# Indice de Especificaciones Tecnicas - MGN-008 Notifications

## Identificacion

| Campo | Valor |
|-------|-------|
| **Modulo** | MGN-008 |
| **Epic** | Notifications |
| **Total ET** | 3 |
| **Story Points** | 25 |
| **Fecha** | 2025-12-05 |

---

## Especificaciones Tecnicas

| ID | Titulo | RF Cubiertos | Estado |
|----|--------|--------------|--------|
| [ET-NOTIF-database](./ET-NOTIF-database.md) | Schema core_notifications | RF-001 a RF-004 | Documentado |
| [ET-NOTIF-backend](./ET-NOTIF-backend.md) | Servicios, WebSocket y API REST | RF-001 a RF-004 | Documentado |
| [ET-NOTIF-frontend](./ET-NOTIF-frontend.md) | Componentes React + Socket.io | RF-001 a RF-004 | Documentado |

---

## Resumen de Componentes

### Database (ET-NOTIF-database)

| Tabla | RF | Descripcion |
|-------|-----|-------------|
| notifications | RF-001 | Notificaciones in-app para usuarios |
| email_templates | RF-002 | Templates de email reutilizables |
| email_jobs | RF-002 | Cola de trabajos de email |
| push_subscriptions | RF-003 | Dispositivos registrados para push |
| push_jobs | RF-003 | Cola de trabajos push |
| notification_preferences | RF-004 | Preferencias por usuario y tipo |

**Total:** 6 tablas

**Funciones:**
- `send_notification()` - Envio con aplicacion de preferencias
- `mark_as_read()` - Marcar notificaciones leidas
- `get_unread_count()` - Conteo por tipo
- `cleanup_old_notifications()` - Limpieza automatica
- `cleanup_completed_jobs()` - Limpieza de colas

### Backend (ET-NOTIF-backend)

| Servicio | Responsabilidad | RF |
|----------|-----------------|-----|
| NotificationsService | CRUD in-app + WebSocket | RF-001 |
| EmailService | Cola y envio de emails | RF-002 |
| EmailTemplatesService | Gestion de templates | RF-002 |
| PushService | Subscripciones y envio push | RF-003 |
| PreferencesService | Preferencias de usuario | RF-004 |

**Total:** 18 endpoints REST + WebSocket

**Componentes adicionales:**
- NotificationsGateway (WebSocket)
- EmailProcessor (Bull job processor)
- PushProcessor (Bull job processor)

---

## Matriz de Trazabilidad RF -> ET

| RF | Database | Backend |
|----|----------|---------|
| RF-NOTIF-001 | notifications | NotificationsService, NotificationsGateway |
| RF-NOTIF-002 | email_templates, email_jobs | EmailService, EmailTemplatesService, EmailProcessor |
| RF-NOTIF-003 | push_subscriptions, push_jobs | PushService, PushProcessor |
| RF-NOTIF-004 | notification_preferences | PreferencesService |

---

## Arquitectura de Canales

```
+-------------------+
|   Notification    |
|     Service       |
+--------+----------+
         |
    +----+----+----+
    |    |    |    |
    v    v    v    v
+-----+ +---+ +----+
|In-App| |Email| |Push|
+--+--+ +--+--+ +--+--+
   |       |       |
   v       v       v
WebSocket  SMTP  VAPID
(Socket.io)(Node) (web-push)
```

### Flujo de Envio

1. **Crear notificacion** -> NotificationsService.send()
2. **Verificar preferencias** -> PreferencesService.get()
3. **Filtrar canales** segun preferencias
4. **In-App:** Guardar + WebSocket emit
5. **Email:** Queue job con Bull (respeta frequencia)
6. **Push:** Queue job para cada subscripcion activa

---

## Dependencias Tecnicas

### Externas
- PostgreSQL 15+ (JSONB, arrays)
- Redis (Bull queues, Socket.io adapter)
- TypeORM 0.3+
- NestJS 10+
- Socket.io 4+
- Bull/BullMQ (Job queues)
- Nodemailer (SMTP)
- web-push (VAPID)
- Handlebars (Templates)

### Internas
- core_tenants.tenants (RLS)
- core_users.users (Referencias)
- MGN-001 Auth (JWT para WebSocket)
- MGN-006 Settings (SMTP config)

---

## Configuracion Requerida

### Variables de Entorno

```env
# SMTP
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=user
SMTP_PASS=secret
SMTP_SECURE=false
EMAIL_FROM="App <noreply@example.com>"

# Push Notifications (VAPID)
VAPID_PUBLIC_KEY=BNxxx...
VAPID_PRIVATE_KEY=xxx...
PUSH_SUBJECT=mailto:admin@example.com

# Redis
REDIS_HOST=localhost
REDIS_PORT=6379
```

---

## Service Worker (Push)

```javascript
// public/sw.js
self.addEventListener('push', (event) => {
  const data = event.data.json();

  const options = {
    body: data.body,
    icon: data.icon || '/icon-192.png',
    badge: data.badge || '/badge.png',
    data: {
      url: data.actionUrl,
      ...data.data,
    },
  };

  event.waitUntil(
    self.registration.showNotification(data.title, options)
  );
});

self.addEventListener('notificationclick', (event) => {
  event.notification.close();

  if (event.notification.data?.url) {
    event.waitUntil(
      clients.openWindow(event.notification.data.url)
    );
  }
});
```

---

## Historial

| Version | Fecha | Autor | Cambios |
|---------|-------|-------|---------|
| 1.0 | 2025-12-05 | Requirements-Analyst | Creacion inicial con 2 ET |
| 1.1 | 2025-12-05 | Requirements-Analyst | Agregado ET Frontend |
