Nuevas Épicas (MCH-029 a MCH-033): - Infraestructura SaaS multi-tenant - Auth Social (OAuth2) - Auditoría Empresarial - Feature Flags - Onboarding Wizard Nuevas Integraciones (INT-010 a INT-014): - Email Providers (SendGrid, Mailgun, SES) - Storage Cloud (S3, GCS, Azure) - OAuth Social - Redis Cache - Webhooks Outbound Nuevos ADRs (0004 a 0011): - Notifications Realtime - Feature Flags Strategy - Storage Abstraction - Webhook Retry Strategy - Audit Log Retention - Rate Limiting - OAuth Social Implementation - Email Multi-provider Actualizados: - MASTER_INVENTORY.yml - CONTEXT-MAP.yml - HERENCIA-SIMCO.md - Mapas de documentación Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
182 lines
4.0 KiB
Markdown
182 lines
4.0 KiB
Markdown
---
|
|
id: ADR-0004
|
|
type: ADR
|
|
title: "Notificaciones en Tiempo Real"
|
|
status: Accepted
|
|
decision_date: 2026-01-10
|
|
updated_at: 2026-01-10
|
|
simco_version: "4.0.1"
|
|
stakeholders:
|
|
- "Equipo MiChangarrito"
|
|
tags:
|
|
- notifications
|
|
- websocket
|
|
- sse
|
|
- realtime
|
|
---
|
|
|
|
# ADR-0004: Notificaciones en Tiempo Real
|
|
|
|
## Metadata
|
|
|
|
| Campo | Valor |
|
|
|-------|-------|
|
|
| **ID** | ADR-0004 |
|
|
| **Estado** | Accepted |
|
|
| **Fecha** | 2026-01-10 |
|
|
| **Autor** | Architecture Team |
|
|
| **Supersede** | - |
|
|
|
|
---
|
|
|
|
## Contexto
|
|
|
|
MiChangarrito necesita notificar a los usuarios en tiempo real sobre eventos como nuevos pedidos, pagos recibidos, alertas de inventario y actualizaciones de estado. Se requiere una solucion que funcione tanto en web como en mobile.
|
|
|
|
---
|
|
|
|
## Decision
|
|
|
|
**Adoptamos Server-Sent Events (SSE) para notificaciones web y push notifications nativas para mobile.**
|
|
|
|
SSE es unidireccional (servidor -> cliente), suficiente para notificaciones, mas simple de implementar que WebSockets, y funciona mejor con proxies y load balancers.
|
|
|
|
```typescript
|
|
// Endpoint SSE
|
|
@Get('notifications/stream')
|
|
@Sse()
|
|
notificationStream(@Req() req: Request): Observable<MessageEvent> {
|
|
const userId = req.user.id;
|
|
return this.notificationService.getUserStream(userId);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Alternativas Consideradas
|
|
|
|
### Opcion 1: WebSockets (Socket.io)
|
|
- **Pros:**
|
|
- Bidireccional
|
|
- Ampliamente soportado
|
|
- Buena libreria (Socket.io)
|
|
- **Cons:**
|
|
- Mas complejo de escalar
|
|
- Requiere sticky sessions
|
|
- Overhead para notificaciones unidireccionales
|
|
|
|
### Opcion 2: Server-Sent Events (Elegida)
|
|
- **Pros:**
|
|
- Simple de implementar
|
|
- Unidireccional (perfecto para notificaciones)
|
|
- Reconexion automatica
|
|
- Funciona sobre HTTP/2
|
|
- No requiere sticky sessions
|
|
- **Cons:**
|
|
- Solo unidireccional
|
|
- Limite de conexiones por dominio
|
|
- No soportado en IE
|
|
|
|
### Opcion 3: Polling
|
|
- **Pros:**
|
|
- Muy simple
|
|
- Funciona en cualquier navegador
|
|
- **Cons:**
|
|
- Ineficiente
|
|
- Latencia alta
|
|
- Carga innecesaria al servidor
|
|
|
|
---
|
|
|
|
## Consecuencias
|
|
|
|
### Positivas
|
|
|
|
1. **Simplicidad:** SSE es nativo del navegador
|
|
2. **Escalabilidad:** Funciona con load balancers
|
|
3. **Eficiencia:** Conexion persistente sin overhead
|
|
4. **Resiliencia:** Reconexion automatica
|
|
|
|
### Negativas
|
|
|
|
1. **Limite conexiones:** 6 por dominio en HTTP/1.1
|
|
2. **Solo unidireccional:** Si necesitamos bidireccional, agregar WebSocket
|
|
3. **IE no soportado:** Usar polyfill si es necesario
|
|
|
|
---
|
|
|
|
## Implementacion
|
|
|
|
### Backend (NestJS)
|
|
|
|
```typescript
|
|
@Controller('notifications')
|
|
export class NotificationController {
|
|
constructor(
|
|
private readonly notificationService: NotificationService,
|
|
) {}
|
|
|
|
@Get('stream')
|
|
@UseGuards(JwtAuthGuard)
|
|
@Sse()
|
|
stream(@Req() req: Request): Observable<MessageEvent> {
|
|
const userId = req.user.id;
|
|
const tenantId = req.user.tenantId;
|
|
|
|
return this.notificationService
|
|
.createStream(userId, tenantId)
|
|
.pipe(
|
|
map(notification => ({
|
|
data: notification,
|
|
type: notification.type,
|
|
id: notification.id,
|
|
})),
|
|
);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Frontend (React)
|
|
|
|
```typescript
|
|
function useNotifications() {
|
|
const [notifications, setNotifications] = useState([]);
|
|
|
|
useEffect(() => {
|
|
const eventSource = new EventSource('/api/notifications/stream', {
|
|
withCredentials: true,
|
|
});
|
|
|
|
eventSource.onmessage = (event) => {
|
|
const notification = JSON.parse(event.data);
|
|
setNotifications(prev => [notification, ...prev]);
|
|
toast.info(notification.message);
|
|
};
|
|
|
|
eventSource.onerror = () => {
|
|
// Reconexion automatica
|
|
};
|
|
|
|
return () => eventSource.close();
|
|
}, []);
|
|
|
|
return notifications;
|
|
}
|
|
```
|
|
|
|
### Mobile (Push Notifications)
|
|
|
|
Para mobile, usamos push notifications nativas en lugar de SSE para mejor experiencia cuando la app esta en background.
|
|
|
|
---
|
|
|
|
## Referencias
|
|
|
|
- [MDN Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)
|
|
- [NestJS SSE](https://docs.nestjs.com/techniques/server-sent-events)
|
|
|
|
---
|
|
|
|
**Fecha decision:** 2026-01-10
|
|
**Autores:** Architecture Team
|