Documento tecnico que describe el sistema completo de comunicaciones de Nvito: la arquitectura de 3 capas, los templates con variables Handlebars, los workflows automatizados con 6 triggers, los 4 canales de envio, las colas Bull con reintentos y el ciclo de vida de mensajes y campanas.
| Campo | Valor |
|---|
| Version | 1.0 |
| Fecha | Marzo 2026 |
| Estado | Publicado |
| Audiencia | Equipo de desarrollo, arquitectos |
El sistema de comunicaciones esta dividido en 3 modulos NestJS con responsabilidades claras y sin dependencias circulares:
| 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 |
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.
Los templates usan sintaxis Handlebars para insertar variables dinamicas del invitado y el evento.
| 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" |
| Estado | Descripcion | Puede usarse en campanas? |
|---|
| DRAFT | Template en construccion, no disponible para envio | No |
| ACTIVE | Template listo para usar en campanas y workflows | Si |
| ARCHIVED | Template descontinuado, no aparece en la lista | No |
| Tipo | Canal | Contenido |
|---|
| Email | SMTP | HTML con layout responsive, sujeto, preheader |
| WhatsApp | 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 |
Los workflows permiten configurar acciones automaticas que se disparan por eventos del sistema.
| Trigger | Cuando se dispara | Datos disponibles | Caso de uso tipico |
|---|
| GUEST_ADDED | Al agregar un invitado al evento | Guest, Event | Enviar invitacion automaticamente |
| RSVP_CONFIRMED | Al confirmar asistencia via RSVP | Guest, Event, RSVP | Enviar confirmacion y detalles |
| RSVP_DECLINED | Al rechazar via RSVP | Guest, Event, RSVP | Enviar agradecimiento por responder |
| DAYS_BEFORE_EVENT | N dias antes del evento (configurable) | Event, Guests | Recordatorio de asistencia |
| EVENT_DAY | El dia del evento | Event, Guests | Detalles logisticos, horarios |
| POST_EVENT | Despues del evento | Event, Guests | Agradecimiento, galeria, encuesta |
Cada workflow define:
| Campo | Tipo | Descripcion |
|---|
trigger | enum | Evento que lo dispara |
channel | enum | Canal de envio (EMAIL, WHATSAPP, SMS, PUSH) |
templateId | UUID | Template a usar |
isActive | boolean | Si esta 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 |
| Aspecto | Detalle |
|---|
| Libreria | Nodemailer |
| Transporte | SMTP configurable por ambiente |
| Dev | MailDev (localhost:1080) |
| Staging | Mailtrap |
| Produccion | SMTP empresarial |
| Features | HTML responsive, adjuntos, reply-to, tracking headers |
| Aspecto | Detalle |
|---|
| Proveedor | Twilio WhatsApp Business API |
| Templates | Pre-aprobados por Meta (HSM) |
| Sesiones | 24h window para respuestas libres |
| Chatbot RSVP | Respuesta conversacional via WhatsApp |
| Webhooks | Status callbacks (sent, delivered, read, failed) |
| Aspecto | Detalle |
|---|
| Proveedor | Twilio Programmable SMS |
| Uso | Fallback cuando WhatsApp no disponible |
| Limite | 160 chars por segmento (auto-concatenacion) |
| Paises | Mexico, USA, Colombia (configurables) |
| 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 |
| Cola | Nombre | Concurrencia | Reintentos | Backoff |
|---|
| Email | email-queue | 5 | 3 | Exponencial (1s, 2s, 4s) |
| WhatsApp | 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) |
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)
}
- Intento 1: Inmediato
- Intento 2: Despues de
backoff * 1 segundos
- Intento 3: Despues de
backoff * 2 segundos
- Fallo definitivo: Marcar mensaje como
FAILED, registrar error
Cada mensaje individual tiene un ciclo de vida rastreable:
| Estado | Descripcion | 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 | Confirmacion de entrega al destinatario | No |
| OPENED | El destinatario abrio el mensaje (tracking pixel o read receipt) | Si |
| BOUNCED | El mensaje reboto (email invalido, telefono no existe) | Si |
| FAILED | Error definitivo despues de agotar reintentos | Si |
| CANCELLED | Campana cancelada antes del envio | Si |
Las campanas permiten enviar comunicaciones a multiples invitados.
| Regla | Descripcion |
|---|
| 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 comunicacion del invitado |
| Horario | No enviar entre 22:00 y 08:00 hora local del destinatario |
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 |
| Archivo | Ubicacion | 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) |