El sistema de notificaciones debe ser escalable, confiable y asíncrono para no afectar la latencia de las transacciones principales. La arquitectura propuesta utiliza un modelo basado en eventos con procesamiento paralelo mediante Worker Threads.
graph TB
MICRO[MICROSERVICIOS EMISORES
MS-Pagos,
MS-Autenticación
MS-Datos-Cliente, etc.]
KAFKA[KAFKA EVENT BUS
Topic: notifications]
MS_NOT[MS-NOTIFICACIONES
Node.js + Worker Threads]
MAIN[Main Thread
• Consume Kafka
• Enqueue jobs
• Coordina workers]
WORKERS[Worker Thread Pool
• Email Workers
• SMS Workers
• Push Workers]
subgraph "REDIS QUEUES"
Q1[Redis Queue
Email]
Q2[Redis Queue
SMS]
Q3[Redis Queue
Push]
end
subgraph "SERVICIOS EXTERNOS"
EMAIL[Mailpit Dev /
Nodemailer Prod]
SMS[Firebase Cloud
Messaging SMS]
PUSH[Firebase Cloud
Messaging Push]
end
MICRO -->|Emit Event| KAFKA
KAFKA -->|Consume Events| MS_NOT
MS_NOT --> MAIN
MAIN --> WORKERS
WORKERS --> Q1
WORKERS --> Q2
WORKERS --> Q3
Q1 --> EMAIL
Q2 --> SMS
Q3 --> PUSH
style MICRO fill:#667eea,stroke:#333,color:#fff
style KAFKA fill:#764ba2,stroke:#333,color:#fff
style MS_NOT fill:#4caf50,stroke:#333,color:#fff
style MAIN fill:#2196F3,stroke:#333,color:#fff
style WORKERS fill:#ff9800,stroke:#333,color:#fff
Bull es una librería robusta de gestión de colas basada en Redis que proporciona:
| Característica | Bull Queue | Alternativa (RabbitMQ) |
|---|---|---|
| Configuración | Simple (solo Redis) | Compleja (broker separado) |
| Performance | 10K+ jobs/segundo | 15K+ jobs/segundo |
| Persistencia | Redis AOF/RDB | Disk persistence |
| Monitoreo | Bull Board (web UI) | Requiere plugin |
| Costo operativo | Bajo (reutiliza Redis) | Medio (infraestructura adicional) |
Node.js Worker Threads permite procesamiento paralelo de notificaciones:
graph TB
MAIN[MS-NOTIFICACIONES
Main Thread
Consume Kafka → Enqueue jobs → Coordina workers]
subgraph "WORKER THREAD POOL"
W1[Worker 1
Email Thread]
W2[Worker 2
Email Thread]
W3[Worker 3
SMS Thread]
W4[Worker 4
Push Thread]
end
PROCESS[Procesa 1000+ notificaciones/segundo]
MAIN --> W1
MAIN --> W2
MAIN --> W3
MAIN --> W4
W1 --> PROCESS
W2 --> PROCESS
W3 --> PROCESS
W4 --> PROCESS
style MAIN fill:#667eea,stroke:#333,color:#fff
style W1 fill:#4caf50,stroke:#333,color:#fff
style W2 fill:#4caf50,stroke:#333,color:#fff
style W3 fill:#ff9800,stroke:#333,color:#fff
style W4 fill:#2196F3,stroke:#333,color:#fff
style PROCESS fill:#764ba2,stroke:#333,color:#fff
| Ventaja | Descripción |
|---|---|
| Económico | Hasta 10,000 SMS gratis/mes. Push notifications ilimitadas gratis. |
| Alta tasa de entrega | 99%+ de entrega exitosa para SMS y Push |
| API simple | SDK de Node.js bien documentado y fácil de integrar |
| Multi-país | Soporte para 200+ países sin configuración adicional |
| Integración directa | SDK en apps móviles para push notifications nativas |
| Ambiente | Tecnología | Justificación |
|---|---|---|
| Desarrollo | Mailpit en contenedor Docker |
|
| Producción | Nodemailer con SMTP propio |
|
| Evento | SMS | Push | Prioridad | Tiempo Máximo | |
|---|---|---|---|---|---|
| Transferencia realizada | ✔ | ✔ | ✔ | Alta | < 30 segundos |
| Login desde nuevo dispositivo | ✔ | ✔ | ✔ | Crítica | < 10 segundos |
| Cambio de contraseña | ✔ | ✔ | - | Crítica | < 10 segundos |
| Saldo bajo (alerta) | ✔ | - | ✔ | Media | < 5 minutos |
| Recordatorio de pago | ✔ | - | ✔ | Baja | < 1 hora |
| Promociones | ✔ | - | ✔ | Baja | Best-effort |
| Transferencia fallida | ✔ | ✔ | ✔ | Alta | < 1 minuto |
| Actualización de app disponible | - | - | ✔ | Baja | Best-effort |
Bull Queue permite asignar prioridades numéricas a los jobs (menor número = mayor prioridad):
graph TB
QUEUE[REDIS QUEUE - Bull]
P1[Priority 1 - CRITICAL
Security Events
• Login nuevo dispositivo
• Cambio contraseña
• Intento login fallido]
P2[Priority 2 - HIGH
Transactional Events
• Transferencia exitosa
• Transferencia fallida
• Recepción de dinero]
P3[Priority 3 - NORMAL
Informational
• Saldo bajo
• Recordatorio pago]
P4[Priority 4 - LOW
Marketing
• Promociones
• Newsletter]
QUEUE --> P1
P1 -->|Procesado primero| P2
P2 --> P3
P3 -->|Procesado último| P4
style QUEUE fill:#667eea,stroke:#333,color:#fff,stroke-width:3px
style P1 fill:#f44336,stroke:#333,color:#fff
style P2 fill:#ff9800,stroke:#333,color:#fff
style P3 fill:#2196F3,stroke:#333,color:#fff
style P4 fill:#9e9e9e,stroke:#333,color:#fff
| Prioridad | Workers Asignados | SLA de Procesamiento | Reintentos |
|---|---|---|---|
| CRITICAL (1) | 6 workers | < 10 segundos | 5 intentos, exponential backoff |
| HIGH (2) | 4 workers | < 30 segundos | 3 intentos, exponential backoff |
| NORMAL (3) | 2 workers | < 5 minutos | 2 intentos, exponential backoff |
| LOW (4) | 1 worker | Best-effort | 1 intento, sin retry |
sequenceDiagram
participant U as Usuario
participant PAG as MS-Pagos
participant K as Kafka
Topic: notifications
participant NOT as MS-Notificaciones
participant DB as Database/Cache
participant BULL as Bull Queue
participant W as Workers
Email/SMS/Push
participant EXT as Servicios Externos
Nodemailer/Firebase
participant ES as Elasticsearch
Audit Logs
U->>PAG: Completa transferencia
PAG->>K: POST Event TRANSFER_COMPLETED
{userId, amount, recipient, priority: HIGH}
K->>NOT: Consumer Group notification-service
NOT->>NOT: Valida estructura del evento
NOT->>DB: Consulta preferencias del usuario
DB-->>NOT: Preferencias (respeta excepto seguridad)
NOT->>BULL: Enqueue job: email-notifications
{template, to, data, priority: 2}
NOT->>BULL: Enqueue job: sms-notifications
{to, message, priority: 2}
NOT->>BULL: Enqueue job: push-notifications
{token, title, body, priority: 2}
par Workers procesan en paralelo
BULL->>W: Email Worker (Worker Thread)
W->>W: Renderiza plantilla HTML (Handlebars)
W->>EXT: Envía vía Nodemailer SMTP
EXT-->>W: ✓ Enviado
W->>DB: Registra resultado en DB
W->>ES: Log para auditoría
and
BULL->>W: SMS Worker (Worker Thread)
W->>EXT: Envía vía Firebase Cloud Messaging
EXT-->>W: ✓ Enviado
W->>DB: Registra resultado en DB
W->>ES: Log para auditoría
and
BULL->>W: Push Worker (Worker Thread)
W->>EXT: Envía vía Firebase Cloud Messaging
EXT-->>W: ✓ Enviado
W->>DB: Registra resultado en DB
W->>ES: Log para auditoría
end
W->>BULL: Marca jobs como completed
BULL->>NOT: Actualiza métricas en Prometheus
Note over U,ES: Usuario recibe notificación
Tiempo total: < 30 segundos
| Intento | Espera | Acción |
|---|---|---|
| 1 | Inmediato | Primer intento de envío |
| 2 | 30 segundos | Retry con backoff |
| 3 | 2 minutos | Retry con backoff |
| 4 | 5 minutos | Retry con backoff |
| 5 | 15 minutos | Último intento |
| Failed | - | Job marcado como fallido, alerta a operaciones |
| Canal | Error Común | Acción de Recuperación |
|---|---|---|
| SMTP timeout | Retry con otro servidor SMTP de backup | |
| Email inválido | No retry, marcar email para validación | |
| SMS | Firebase rate limit | Delay + retry, activar rate limiting local |
| SMS | Número inválido | No retry, marcar teléfono para validación |
| Push | Token expirado | Solicitar nuevo token al dispositivo |
| Push | Dispositivo offline | Queue notification, entregar cuando vuelva online |
Jobs que fallan después de todos los reintentos se mueven a una Dead Letter Queue para revisión manual:
Las plantillas de email se gestionan con Handlebars para facilitar la personalización:
templates/
├── emails/
│ ├── transfer-completed.hbs
│ ├── login-new-device.hbs
│ ├── password-changed.hbs
│ ├── low-balance-alert.hbs
│ └── payment-reminder.hbs
│
├── sms/
│ ├── transfer-completed.txt
│ ├── login-new-device.txt
│ └── otp-code.txt
│
└── layouts/
├── base-email.hbs (Header + Footer común)
└── transactional.hbs
Ejemplo: transfer-completed.hbs
<h1>Transferencia Exitosa</h1>
<p>Hola {{customerName}},</p>
<p>Tu transferencia de <strong>{{amount}}</strong> a
<strong>{{recipientName}}</strong> fue exitosa.</p>
<p>Detalles:</p>
<ul>
<li>Monto: {{amount}}</li>
<li>Destinatario: {{recipientName}}</li>
<li>Cuenta: {{accountNumber}}</li>
<li>Fecha: {{date}}</li>
</ul>
| Idioma | Plantillas | Prioridad |
|---|---|---|
| Español (es) | templates/es/ | Principal |
| Inglés (en) | templates/en/ | Secundario |
El idioma se determina según las preferencias del usuario almacenadas en su perfil.
| Métrica | Descripción | Umbral de Alerta |
|---|---|---|
| Notification Rate | Notificaciones procesadas por segundo | < 100/segundo (capacidad baja) |
| Success Rate Email | % de emails enviados exitosamente | < 95% |
| Success Rate SMS | % de SMS enviados exitosamente | < 90% |
| Success Rate Push | % de push enviados exitosamente | < 85% (normal por tokens expirados) |
| Queue Latency | Tiempo desde enqueue hasta procesamiento | > 60 segundos |
| DLQ Size | Jobs en Dead Letter Queue | > 50 jobs |
| Worker Health | Workers activos vs total esperado | < 80% de workers activos |
| Normativa | Requisito | Implementación |
|---|---|---|
| Normativas Bancarias | Mínimo 2 canales de notificación para movimientos | Email + SMS o Email + Push para todas las transacciones |
| GDPR | Consentimiento para comunicaciones de marketing | Opt-in explícito, fácil opt-out en cada email |
| GDPR | Derecho al olvido | Eliminar datos de contacto al cerrar cuenta |
| ISO 27001 | Logs de todas las notificaciones | Registro en Elasticsearch con retención de 2 años |
| PCI DSS | No enviar datos sensibles por email/SMS | Solo enviar últimos 4 dígitos de cuentas, nunca CVV |
Cada notificación enviada se registra con:
| Componente | Capacidad | Configuración |
|---|---|---|
| Kafka Topic | 10,000+ mensajes/segundo | 5 particiones, replication factor 3 |
| Redis Queue | 15,000+ jobs/segundo | Cluster de 3 nodos, AOF enabled |
| Worker Pool | 1,000+ notificaciones/segundo | 12 workers por pod (4 email, 4 sms, 4 push) |
| Email SMTP | 300+ emails/minuto | Rate limit del proveedor SMTP |
| Firebase SMS | 500+ SMS/minuto | Firebase free tier + paid |
| Firebase Push | Ilimitado | Sin rate limit en Firebase FCM |
graph TB
subgraph "Carga Baja < 100 notif/s"
P1[Pod 1
12 workers]
end
subgraph "Carga Media 100-500 notif/s"
P2A[Pod 1
12 workers]
P2B[Pod 2
12 workers]
end
subgraph "Carga Alta 500-1500 notif/s"
P3A[Pod 1
12 workers]
P3B[Pod 2
12 workers]
P3C[Pod 3
12 workers]
end
HPA["HPA (Horizontal Pod Autoscaler)"
• Métrica: Queue length en Redis
• Scale-up: > 1000 jobs pendientes
• Scale-down: < 100 jobs pendientes
• Min replicas: 2
• Max replicas: 5]
style P1 fill:#4caf50,stroke:#333,color:#fff
style P2A fill:#ff9800,stroke:#333,color:#fff
style P2B fill:#ff9800,stroke:#333,color:#fff
style P3A fill:#f44336,stroke:#333,color:#fff
style P3B fill:#f44336,stroke:#333,color:#fff
style P3C fill:#f44336,stroke:#333,color:#fff
style HPA fill:#667eea,stroke:#333,color:#fff
| Protección | Implementación |
|---|---|
| Rate Limiting por Usuario | Máximo 10 notificaciones del mismo tipo por hora por usuario |
| Deduplicación | No enviar notificación duplicada en ventana de 5 minutos |
| Email Authentication | SPF, DKIM y DMARC configurados en dominio |
| Unsubscribe Link | Link para darse de baja en cada email de marketing (GDPR) |
| Validación de Destinatarios | Verificar formato de email/teléfono antes de enviar |
| Tipo de Test | Objetivo | Herramienta |
|---|---|---|
| Unit Tests | Lógica de enqueue, prioridades, formateo de plantillas | Jest |
| Integration Tests | Flujo completo Kafka → Queue → Worker → SMTP | Jest + Testcontainers |
| Template Tests | Renderizado correcto de plantillas con datos de prueba | Jest + Handlebars |
| Load Tests | Procesar 5,000 notificaciones/segundo sin degradación | k6 |
| Email Rendering | Visualización correcta en Gmail, Outlook, Apple Mail | Litmus o Email on Acid |
| Servicio | Volumen Mensual | Costo Mensual (USD) |
|---|---|---|
| Firebase SMS | 50,000 SMS | $0 (10K gratis) + $40 (40K × $0.001) |
| Firebase Push | Ilimitado | $0 (gratis) |
| SMTP Propio (Nodemailer) | 100,000 emails | $0 (infraestructura propia) |
| Redis (ElastiCache) | cache.t3.medium | $50 |
| Mailpit (Dev) | Desarrollo | $0 (self-hosted) |
Ahorro versus alternativas como SendGrid ($300+/mes) o Twilio SMS ($500+/mes para 50K SMS)
graph TB
MICRO[MICROSERVICIOS
MS-Pagos,
MS-Auth,
MS-Datos-Cliente,
MS-Auditoría]
KAFKA[KAFKA CLUSTER
Topic: notifications
5 partitions
RF: 3]
MS_NOT[MS-NOTIFICACIONES
Node.js + Worker Threads]
MAIN[Main Thread
• Kafka Consumer
• Job Enqueue
• Worker Coordination]
WORKERS[Worker Thread Pool
12 Workers Total
• 4 Email Workers
• 4 SMS Workers
• 4 Push Workers]
subgraph "REDIS QUEUES - Bull"
Q1[Redis Queue
Email
Bull Queue]
Q2[Redis Queue
SMS
Bull Queue]
Q3[Redis Queue
Push
Bull Queue]
end
subgraph "SERVICIOS EXTERNOS"
EMAIL[Mailpit Dev /
Nodemailer Prod]
SMS[Firebase Cloud
Messaging SMS]
PUSH[Firebase Cloud
Messaging Push]
end
ES[ELASTICSEARCH
Audit Logs
Retention: 2 años]
MICRO -->|Publish Events| KAFKA
KAFKA -->|Consumer Group| MS_NOT
MS_NOT --> MAIN
MAIN --> WORKERS
WORKERS --> Q1
WORKERS --> Q2
WORKERS --> Q3
Q1 --> EMAIL
Q2 --> SMS
Q3 --> PUSH
EMAIL --> ES
SMS --> ES
PUSH --> ES
style MICRO fill:#667eea,stroke:#333,color:#fff
style KAFKA fill:#764ba2,stroke:#333,color:#fff
style MS_NOT fill:#4caf50,stroke:#333,color:#fff
style MAIN fill:#2196F3,stroke:#333,color:#fff
style WORKERS fill:#ff9800,stroke:#333,color:#fff
style ES fill:#9c27b0,stroke:#333,color:#fff
El sistema de notificaciones propuesto ofrece:
Beneficio clave: Notificaciones confiables en menos de 30 segundos sin afectar el rendimiento de las transacciones principales.