michangarrito/docs/97-adr/ADR-0004-notifications-realtime.md
rckrdmrd 2c916e75e5 [SIMCO-V4] feat: Agregar documentación SaaS, ADRs e integraciones
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>
2026-01-13 01:43:15 -06:00

4.0 KiB

id type title status decision_date updated_at simco_version stakeholders tags
ADR-0004 ADR Notificaciones en Tiempo Real Accepted 2026-01-10 2026-01-10 4.0.1
Equipo MiChangarrito
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.

// 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)

@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)

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


Fecha decision: 2026-01-10 Autores: Architecture Team