- HERENCIA-SIMCO.md actualizado con directivas v3.7 y v3.8 - Actualizaciones de configuracion Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
239 lines
5.8 KiB
Markdown
239 lines
5.8 KiB
Markdown
---
|
|
id: "ADR-004"
|
|
title: "Sistema de Notificaciones Real-time"
|
|
type: "ADR"
|
|
status: "Accepted"
|
|
priority: "P0"
|
|
supersedes: "N/A"
|
|
superseded_by: "N/A"
|
|
version: "1.0.0"
|
|
created_date: "2026-01-07"
|
|
updated_date: "2026-01-10"
|
|
---
|
|
|
|
# ADR-004: Sistema de Notificaciones Real-time
|
|
|
|
## Metadata
|
|
| Campo | Valor |
|
|
|-------|-------|
|
|
| ID | ADR-004 |
|
|
| Estado | Accepted |
|
|
| Fecha | 2026-01-10 |
|
|
| Supersede | N/A |
|
|
|
|
## Contexto
|
|
|
|
Template SaaS necesita un sistema de notificaciones que soporte:
|
|
- Múltiples canales (email, push, in-app, SMS)
|
|
- Entrega en tiempo real
|
|
- Preferencias de usuario
|
|
- Templates reutilizables
|
|
- Cola para procesamiento asíncrono
|
|
- Tracking de entrega
|
|
|
|
## Opciones Consideradas
|
|
|
|
### Opción 1: Polling
|
|
**Descripción:** Cliente hace requests periódicos para verificar nuevas notificaciones.
|
|
|
|
**Pros:**
|
|
- Simple de implementar
|
|
- Sin infraestructura adicional
|
|
|
|
**Contras:**
|
|
- Latencia alta
|
|
- Desperdicio de recursos
|
|
- Mala experiencia de usuario
|
|
|
|
### Opción 2: Server-Sent Events (SSE)
|
|
**Descripción:** Conexión unidireccional server→client.
|
|
|
|
**Pros:**
|
|
- Simple
|
|
- Reconexión automática
|
|
- Soportado nativamente
|
|
|
|
**Contras:**
|
|
- Solo unidireccional
|
|
- Límite de conexiones por dominio
|
|
- No ideal para bidireccional
|
|
|
|
### Opción 3: WebSocket + BullMQ ✓
|
|
**Descripción:** WebSocket para real-time + cola para procesamiento.
|
|
|
|
**Pros:**
|
|
- Bidireccional
|
|
- Baja latencia
|
|
- Cola confiable
|
|
- Escalable horizontalmente
|
|
- Retry automático
|
|
|
|
**Contras:**
|
|
- Más complejo
|
|
- Requiere Redis
|
|
- Manejo de reconexiones
|
|
|
|
## Decisión
|
|
|
|
**Elegimos WebSocket (Socket.io) + BullMQ** porque:
|
|
|
|
1. **Real-time:** WebSocket para entrega instantánea
|
|
2. **Confiabilidad:** BullMQ para procesamiento garantizado
|
|
3. **Escalabilidad:** Redis permite múltiples instancias
|
|
4. **Multi-canal:** Cola maneja diferentes canales
|
|
|
|
## Implementación
|
|
|
|
### Arquitectura
|
|
|
|
```
|
|
┌─────────────┐ ┌─────────────┐
|
|
│ Client │◀───▶│ WebSocket │
|
|
│ (React) │ │ Gateway │
|
|
└─────────────┘ └─────────────┘
|
|
│
|
|
┌──────▼──────┐
|
|
│ Redis │
|
|
│ (Pub/Sub) │
|
|
└──────┬──────┘
|
|
│
|
|
┌─────────────┐ ┌──────▼──────┐
|
|
│ BullMQ │◀───▶│ Workers │
|
|
│ Queues │ │ │
|
|
└─────────────┘ └─────────────┘
|
|
│ │
|
|
│ ┌──────▼──────┐
|
|
│ │ Email │
|
|
│ │ Push │
|
|
│ │ SMS │
|
|
└───────────▶└─────────────┘
|
|
```
|
|
|
|
### Canales Soportados
|
|
|
|
| Canal | Provider | Uso |
|
|
|-------|----------|-----|
|
|
| Email | SendGrid/SES | Transaccional, marketing |
|
|
| Push | Web Push API | Alertas importantes |
|
|
| In-app | WebSocket | Notificaciones UI |
|
|
| SMS | Twilio | (Futuro) |
|
|
| WhatsApp | Meta API | (Sprint 5) |
|
|
|
|
### WebSocket Gateway
|
|
|
|
```typescript
|
|
@WebSocketGateway({
|
|
namespace: '/notifications',
|
|
cors: { origin: '*' },
|
|
})
|
|
export class NotificationsGateway {
|
|
@SubscribeMessage('subscribe')
|
|
handleSubscribe(client: Socket, payload: { tenantId: string }) {
|
|
client.join(`tenant:${payload.tenantId}`);
|
|
}
|
|
|
|
async sendToUser(userId: string, notification: Notification) {
|
|
this.server.to(`user:${userId}`).emit('notification', notification);
|
|
}
|
|
|
|
async sendToTenant(tenantId: string, notification: Notification) {
|
|
this.server.to(`tenant:${tenantId}`).emit('notification', notification);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Queue Processing
|
|
|
|
```typescript
|
|
@Processor('notifications')
|
|
export class NotificationProcessor {
|
|
@Process('send')
|
|
async handleSend(job: Job<NotificationJob>) {
|
|
const { notification, channels } = job.data;
|
|
|
|
for (const channel of channels) {
|
|
switch (channel) {
|
|
case 'email':
|
|
await this.emailService.send(notification);
|
|
break;
|
|
case 'push':
|
|
await this.pushService.send(notification);
|
|
break;
|
|
case 'in_app':
|
|
await this.gateway.sendToUser(notification.userId, notification);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Push Notifications (VAPID)
|
|
|
|
```typescript
|
|
// Generar VAPID keys
|
|
const vapidKeys = webPush.generateVAPIDKeys();
|
|
|
|
// Enviar push
|
|
await webPush.sendNotification(subscription, JSON.stringify({
|
|
title: notification.title,
|
|
body: notification.body,
|
|
icon: '/icon.png',
|
|
data: { url: notification.actionUrl },
|
|
}));
|
|
```
|
|
|
|
### Preferencias de Usuario
|
|
|
|
```typescript
|
|
interface NotificationPreferences {
|
|
email: {
|
|
marketing: boolean;
|
|
transactional: boolean;
|
|
digest: 'none' | 'daily' | 'weekly';
|
|
};
|
|
push: {
|
|
enabled: boolean;
|
|
alerts: boolean;
|
|
updates: boolean;
|
|
};
|
|
inApp: {
|
|
enabled: boolean;
|
|
sound: boolean;
|
|
};
|
|
}
|
|
```
|
|
|
|
## Consecuencias
|
|
|
|
### Positivas
|
|
- Entrega instantánea con WebSocket
|
|
- Confiabilidad con colas
|
|
- Multi-canal flexible
|
|
- Escalable horizontalmente
|
|
- User preferences respetadas
|
|
|
|
### Negativas
|
|
- Complejidad adicional
|
|
- Dependencia de Redis
|
|
- Costos de proveedores externos
|
|
- Manejo de estados de conexión
|
|
|
|
### Monitoreo
|
|
- Queue metrics (jobs pending, failed)
|
|
- WebSocket connections activas
|
|
- Delivery rates por canal
|
|
- Error rates
|
|
|
|
## Referencias
|
|
|
|
- [Socket.io Documentation](https://socket.io/docs/v4/)
|
|
- [BullMQ Documentation](https://docs.bullmq.io/)
|
|
- [Web Push Protocol](https://tools.ietf.org/html/rfc8030)
|
|
- Implementación: `apps/backend/src/modules/notifications/`
|
|
|
|
---
|
|
|
|
**Fecha decision:** 2026-01-10
|
|
**Autores:** Claude Code (Arquitectura)
|