# 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 " # 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 |