1. Arquitectura de 3 Capas
El sistema de comunicaciones está dividido en 3 módulos NestJS con responsabilidades claras y sin dependencias circulares:
Arquitectura de 3 Capas — Comunicaciones
Capa 3: NotificationsModule
Capa 3: NotificationsModule
Capa 2: QueueModule
Capa 2: QueueModule
Capa 2: QueueModule
Capa 1: NotificationChannelsModule
1.1 Responsabilidades por Capa
| Capa | Modulo | Responsabilidad | Dependencias |
|---|---|---|---|
| 3 - Alto nivel | NotificationsModule | API de dominio, campanas, workflows | Importa Capa 2 y Capa 1 |
| 2 - Colas | QueueModule | Encolamiento, procesamiento, reintentos | Importa Capa 1 |
| 1 - Canales | NotificationChannelsModule | Envio puro (email, WhatsApp, SMS, push) | Sin dependencias internas |
1.2 Regla de Arquitectura
La Capa 1 nunca importa a la Capa 2 ni la Capa 3. La Capa 2 nunca importa la Capa 3. Las dependencias fluyen de arriba hacia abajo exclusivamente.
2. Templates de Comunicación
Los templates usan sintaxis Handlebars para insertar variables dinámicas del invitado y el evento.
2.1 Variables Disponibles
| Variable | Tipo | Ejemplo |
|---|---|---|
{{guest.firstName}} | string | "Maria" |
{{guest.lastName}} | string | "Garcia" |
{{guest.fullName}} | string | "Maria Garcia" |
{{guest.groupSize}} | number | 3 |
{{event.name}} | string | "Boda de Ana y Carlos" |
{{event.date}} | string | "15 de marzo de 2026" |
{{event.time}} | string | "18:00" |
{{event.venue}} | string | "Hacienda Los Olivos" |
{{event.location}} | string | "Queretaro, Mexico" |
{{invitation.url}} | string | "https://nvito.mx/i/ana-carlos-2026" |
{{rsvp.url}} | string | URL directa al formulario RSVP |
{{organization.name}} | string | "Wedding Planner XYZ" |
2.2 Estados del Template
Estados del Template
start→draftCrear templatedraft→activeActivaractive→archivedArchivararchived→activeReactivardraft→draftEditaractive→activeEditar contenido| Estado | Descripción | Puede usarse en campanas? |
|---|---|---|
| DRAFT | Template en construcción, no disponible para envio | No |
| ACTIVE | Template listo para usar en campanas y workflows | Si |
| ARCHIVED | Template descontinuado, no aparece en la lista | No |
2.3 Tipos de Template
| Tipo | Canal | Contenido |
|---|---|---|
| SMTP | HTML con layout responsive, sujeto, preheader | |
| Twilio | Texto plano con variables (requiere template aprobado por Meta) | |
| SMS | Twilio | Texto plano, max 160 chars (concatenable) |
| Push | Firebase/Expo | Titulo + body + data payload |
3. Workflows Automatizados
Los workflows permiten configurar acciones automáticas que se disparan por eventos del sistema.
3.1 Triggers Disponibles
| Trigger | Cuando se dispara | Datos disponibles | Caso de uso tipico |
|---|---|---|---|
| GUEST_ADDED | Al agregar un invitado al evento | Guest, Event | Enviar invitación automáticamente |
| RSVP_CONFIRMED | Al confirmar asistencia via RSVP | Guest, Event, RSVP | Enviar confirmación y detalles |
| RSVP_DECLINED | Al rechazar via RSVP | Guest, Event, RSVP | Enviar agradecimiento por responder |
| DAYS_BEFORE_EVENT | N días antes del evento (configurable) | Event, Guests | Recordatorio de asistencia |
| EVENT_DAY | El día del evento | Event, Guests | Detalles logisticos, horarios |
| POST_EVENT | Después del evento | Event, Guests | Agradecimiento, galería, encuestá |
3.2 Configuración del Workflow
Cada workflow define:
| Campo | Tipo | Descripción |
|---|---|---|
trigger | enum | Evento que lo dispara |
channel | enum | Canal de envio (EMAIL, WHATSAPP, SMS, PUSH) |
templateId | UUID | Template a usar |
isActive | boolean | Si está habilitado |
delayMinutes | number | Retraso antes de ejecutar (0 = inmediato) |
filterCondition | JSON? | Filtro opcional (ej: solo invitados confirmados) |
daysBeforeEvent | number? | Solo para trigger DAYS_BEFORE_EVENT |
3.3 Flujo de Ejecución del Workflow
Ejecucion del Workflow
4. Canales de Envio
4.1 Email (SMTP)
| Aspecto | Detalle |
|---|---|
| Libreria | Nodemailer |
| Transporte | SMTP configurable por ambiente |
| Dev | MailDev (localhost:1080) |
| Staging | Mailtrap |
| Producción | SMTP empresarial |
| Features | HTML responsive, adjuntos, reply-to, tracking headers |
4.2 WhatsApp (Twilio)
| Aspecto | Detalle |
|---|---|
| Proveedor | Twilio WhatsApp Business API |
| Templates | Pre-aprobados por Meta (HSM) |
| Sesiones | 24h window para respuestas libres |
| Chatbot RSVP | Respuestá conversacional via WhatsApp |
| Webhooks | Status callbacks (sent, delivered, read, failed) |
4.3 SMS (Twilio)
| Aspecto | Detalle |
|---|---|
| Proveedor | Twilio Programmable SMS |
| Uso | Fallback cuando WhatsApp no disponible |
| Limite | 160 chars por segmento (auto-concatenacion) |
| Paises | Mexico, USA, Colombia (configurables) |
4.4 Push Notifications
| Aspecto | Detalle |
|---|---|
| Proveedor | Expo Push API → Firebase (Android) / APNs (iOS) |
| Libreria | PushSenderService via expo-server-sdk |
| Registro | Token almacenado al instalar la app |
| Payload | title, body, data (deep link) |
| Silenciosa | Soportada para actualizar datos en background |
5. Colas Bull (Redis)
5.1 Configuración de Colas
| Cola | Nombre | Concurrencia | Reintentos | Backoff |
|---|---|---|---|---|
email-queue | 5 | 3 | Exponencial (1s, 2s, 4s) | |
whatsapp-queue | 3 | 3 | Exponencial (2s, 4s, 8s) | |
| SMS | sms-queue | 3 | 3 | Exponencial (1s, 2s, 4s) |
| Push | push-queue | 10 | 2 | Exponencial (1s, 2s) |
5.2 Estructura del Job
interface QueueJob {
id: string; // UUID del mensaje
channel: Channel; // EMAIL | WHATSAPP | SMS | PUSH
to: string; // Destinatario (email, phone, pushToken)
subject?: string; // Solo email
body: string; // Contenido renderizado
htmlBody?: string; // Solo email (HTML)
metadata: {
eventId: string;
guestId: string;
campaignId?: string;
workflowId?: string;
templateId: string;
};
attempts: number;
priority: number; // 1 (alta) a 10 (baja)
}
5.3 Politica de Reintentos
- Intento 1: Inmediato
- Intento 2: Después de
backoff * 1segundos - Intento 3: Después de
backoff * 2segundos - Fallo definitivo: Marcar mensaje como
FAILED, registrar error
6. Ciclo de Vida del Mensaje
Cada mensaje individual tiene un ciclo de vida rastreable:
Ciclo de Vida del Mensaje
start→pendingMensaje creadopending→queuedEncolado en Bullqueued→sentEnviado al proveedorsent→deliveredConfirmacion de entregadelivered→openedAbierto por destinatariosent→bouncedRebotadosent→failedError de envioqueued→failedError al procesarpending→cancelledCampana cancelada| Estado | Descripción | Final? |
|---|---|---|
| PENDING | Mensaje creado, pendiente de encolar | No |
| QUEUED | En la cola Bull, esperando procesamiento | No |
| SENT | Enviado exitosamente al proveedor (SMTP, Twilio, Expo) | No |
| DELIVERED | Confirmación de entrega al destinatario | No |
| OPENED | El destinatario abrio el mensaje (tracking pixel o read receipt) | Si |
| BOUNCED | El mensaje reboto (email invalido, teléfono no existe) | Si |
| FAILED | Error definitivo después de agotar reintentos | Si |
| CANCELLED | Campana cancelada antes del envio | Si |
7. Campanas Masivas
Las campanas permiten enviar comunicaciones a múltiples invitados.
7.1 Estados de la Campana
Estados de la Campana
start→draftCrear campanadraft→scheduledProgramar envioscheduled→sendingHora de envio alcanzadasending→completedTodos los mensajes procesadossending→failedError criticodraft→cancelledCancelarscheduled→cancelledCancelar7.2 Flujo de Campana
Flujo de Campana Masiva
7.3 Prevencion de Spam
| Regla | Descripción |
|---|---|
| Deduplicacion 24h | No enviar al mismo destinatario el mismo template en 24 horas |
| Rate limit por evento | Max 1000 mensajes por hora por evento |
| Opt-out | Respetar preferencias de comunicación del invitado |
| Horario | No enviar entre 22:00 y 08:00 hora local del destinatario |
8. Webhooks de Estado
Los proveedores externos notifican cambios de estado via webhooks:
| Proveedor | Webhook URL | Eventos |
|---|---|---|
| Twilio (WhatsApp/SMS) | POST /webhooks/twilio/status | sent, delivered, read, failed, undelivered |
| Email (tracking) | Pixel tracking en HTML | opened |
| Email (bounces) | SMTP bounce processing | bounced, complained |
8.1 Procesamiento de Webhooks
Procesamiento de Webhooks
9. Archivos Clave
| Archivo | Ubicación | Responsabilidad |
|---|---|---|
communications.service.ts | src/modules/communications/ | Campanas masivas, despacho de mensajes |
communication-template.service.ts | src/modules/communications/services/ | CRUD de templates, renderizado Handlebars |
workflow.service.ts | src/modules/communications/services/ | Motor de workflows automatizados |
queue.service.ts | src/modules/queue/ | Encolamiento de jobs en Bull/Redis |
email.processor.ts | src/modules/queue/processors/ | Procesador de jobs de email |
whatsapp.processor.ts | src/modules/queue/processors/ | Procesador de jobs de WhatsApp |
push.processor.ts | src/modules/queue/processors/ | Procesador de jobs de push |
email.service.ts | src/modules/notification-channels/ | Envio SMTP via Nodemailer |
whatsapp.service.ts | src/modules/notification-channels/ | Envio via Twilio WhatsApp API |
push-sender.service.ts | src/modules/notification-channels/ | Envio via Expo Push API |
template.service.ts | src/modules/notification-channels/ | Renderizado de templates de email |
notification-helper.service.ts | src/modules/notifications/ | Notificaciones de dominio (RSVP, recordatorios) |
10. Relación con Otros Flujos
| Flujo relacionado | Relación |
|---|---|
| Flujo del Invitado | Los triggers RSVP_CONFIRMED/DECLINED disparan workflows |
| Ciclo de Vida del Evento | DAYS_BEFORE_EVENT, EVENT_DAY y POST_EVENT se calculan desde las fechas del evento |
| Ciclo de Vida de la Invitación | Los templates incluyen {{invitation.url}} de la invitación publicada |
| Flujo de Pagos | Los recibos de pago se envian via el sistema de comunicaciones |