Docs

Communication Workflows

Documento tecnico que describe el sistema de workflows automatizados para comunicaciones en Nvito. Los workflows permiten configurar envios automaticos de mensajes (email, WhatsApp, SMS, push) en respuesta a eventos del dominio o en momentos programados relativos a la fecha del evento.

CampoValor
Version1.0
FechaMarzo 2026
EstadoEn revision
AudienciaEquipo de desarrollo, arquitectos, stakeholders

Tabla de Contenidos

  1. Modelo CommunicationWorkflow
  2. Controller y Servicio
  3. Tipos de Triggers
  4. Flujo de Ejecucion
  5. Filtrado de Destinatarios
  6. Integracion con Sistema de Notificaciones
  7. Retry Policy y Ciclo de Vida de Mensajes
  8. Limites y Restricciones
  9. Testing
  10. Referencias

Modelo CommunicationWorkflow

El modelo CommunicationWorkflow representa una regla de automatizacion que define cuando, a quien y que mensaje enviar. Cada workflow pertenece a un evento especifico y se ejecuta automaticamente cuando se cumple su condicion de trigger.

Campos del Modelo

CampoTipoDescripcion
idUUIDIdentificador unico del workflow
eventIdUUIDEvento al que pertenece el workflow
namestringNombre descriptivo del workflow (ej: "Recordatorio 7 dias antes")
triggerenumEvento que dispara la ejecucion
triggerConfigJSONConfiguracion del trigger (ej: { daysOffset: 7 })
campaignTypeenumTipo de campana que se crea al ejecutarse
channelstringCanal de comunicacion (email, whatsapp, sms, push)
subjectstringAsunto del mensaje (para email)
bodystringCuerpo del mensaje con variables de template
templateIdUUID (opcional)Referencia a un template de comunicacion predefinido
recipientFilterJSONFiltros para seleccionar destinatarios (estado RSVP, grupo, tags)
statusenumEstado actual del workflow
executionCountnumberVeces que se ha ejecutado exitosamente
lastExecutedAtdatetimeFecha y hora de la ultima ejecucion
createdAtdatetimeFecha de creacion
updatedAtdatetimeUltima modificacion

CommunicationWorkflowStatus

EstadoDescripcion
ACTIVEEl workflow se ejecutara cuando ocurra su trigger
PAUSEDEl workflow esta temporalmente deshabilitado; no se ejecutara aunque ocurra el trigger
COMPLETEDEl workflow ha terminado su ciclo (aplica a triggers que solo se ejecutan una vez, como EVENT_DAY)

CommunicationWorkflowTrigger

TriggerCategoriaDescripcion
GUEST_ADDEDEvento de dominioSe dispara al agregar un invitado nuevo al evento
RSVP_CONFIRMEDEvento de dominioSe dispara cuando un invitado confirma asistencia
RSVP_DECLINEDEvento de dominioSe dispara cuando un invitado declina la invitacion
DAYS_BEFORE_EVENTProgramadoSe ejecuta N dias antes de la fecha del evento
EVENT_DAYProgramadoSe ejecuta el dia del evento
POST_EVENTProgramadoSe ejecuta despues del evento (agradecimiento, encuestas, etc.)

Controller y Servicio

CommunicationWorkflowsController

El controller expone endpoints CRUD protegidos por la cadena estandar de guards (ClerkAuthGuard + UserThrottlerGuard + RoleGuard) y requiere acceso al evento (@RequireEventAccess()).

MetodoRutaDescripcionValidaciones
GET/communication-workflows?eventId=xxxListar workflows del eventoeventId requerido, acceso al evento
POST/communication-workflowsCrear workflowMaximo 10 por evento, trigger valido, channel valido
PATCH/communication-workflows/:idActualizar workflowSolo si status es ACTIVE o PAUSED
DELETE/communication-workflows/:idEliminar workflowSolo si no tiene ejecuciones en progreso
PATCH/communication-workflows/:id/toggleAlternar entre ACTIVE y PAUSEDNo aplica a COMPLETED

CommunicationWorkflowsService

El servicio implementa la logica de negocio para la gestion de workflows:

  • create() — Valida que no se exceda el limite de 10 workflows por evento, verifica que el trigger y canal sean validos, y crea el registro en base de datos. Si el trigger es programado (DAYS_BEFORE_EVENT, EVENT_DAY, POST_EVENT), registra el cron job correspondiente en Bull.
  • update() — Permite modificar nombre, trigger, canal, template, filtros y cuerpo del mensaje. Si cambia el trigger, actualiza o recrea el cron job.
  • toggle() — Alterna el status entre ACTIVE y PAUSED. Un workflow pausado no se ejecuta aunque ocurra su trigger. No se puede alternar un workflow COMPLETED.
  • delete() — Elimina el workflow y cancela cualquier cron job asociado. Si hay una campana en progreso generada por este workflow, la ejecucion actual se completa pero no se generaran nuevas.

Tipos de Triggers

Los triggers se dividen en dos categorias fundamentales segun su mecanismo de activacion: triggers basados en eventos de dominio y triggers basados en tiempo.

Triggers de Evento de Dominio

Estos triggers reaccionan a acciones que ocurren en el sistema en tiempo real. Cuando un evento de dominio se emite (por ejemplo, un invitado confirma asistencia), el WorkflowEventListenerService evalua todos los workflows activos del evento correspondiente para determinar cuales deben ejecutarse.

GUEST_ADDED: Se ejecuta inmediatamente cuando se agrega un nuevo invitado al evento. Es util para enviar automaticamente la invitacion o un mensaje de bienvenida al invitado recien agregado. El destinatario es siempre el invitado que acaba de ser agregado (no requiere filtro).

RSVP_CONFIRMED: Se ejecuta cuando un invitado confirma su asistencia via el formulario RSVP de la invitacion. Permite enviar automaticamente un mensaje de confirmacion con detalles del evento (ubicacion, horario, dress code). El destinatario es el invitado que confirmo.

RSVP_DECLINED: Se ejecuta cuando un invitado declina la invitacion. Puede usarse para enviar un mensaje de agradecimiento o solicitar feedback. El destinatario es el invitado que declino.

Triggers Programados (Time-based)

Estos triggers se ejecutan en momentos especificos relativos a la fecha del evento. Utilizan un scheduler basado en Bull/Redis que ejecuta un cron job a medianoche en la zona horaria del evento. El cron job evalua si algun workflow programado debe dispararse ese dia.

DAYS_BEFORE_EVENT: Requiere triggerConfig.daysOffset (numero entero positivo). El workflow se ejecuta N dias antes de la fecha del evento. Ejemplo: con daysOffset: 7, si el evento es el 15 de abril, el workflow se ejecuta el 8 de abril. Es el trigger mas comun para recordatorios.

EVENT_DAY: Se ejecuta el mismo dia del evento. No requiere configuracion adicional. Es util para enviar un mensaje de "nos vemos hoy" con los ultimos detalles logisticos (direccion, estacionamiento, etc.). Despues de ejecutarse, el workflow transiciona automaticamente a COMPLETED.

POST_EVENT: Se ejecuta despues del evento. Puede configurarse con triggerConfig.daysOffset para especificar cuantos dias despues. Es util para mensajes de agradecimiento, encuestas de satisfaccion o compartir fotos de la galeria. Despues de ejecutarse, transiciona a COMPLETED.

Condiciones Adicionales por Trigger

Cada trigger puede tener condiciones adicionales definidas en el campo recipientFilter del workflow:

CondicionAplica aDescripcion
rsvpStatusDAYS_BEFORE_EVENT, EVENT_DAY, POST_EVENTFiltrar por estado RSVP (confirmed, pending, declined)
guestGroupTodosFiltrar por grupo de invitados
tagsTodosFiltrar por tags asignados al invitado
hasPhoneWhatsApp, SMSSolo invitados con numero de telefono
hasEmailEmailSolo invitados con email
hasPushTokenPushSolo invitados con token de push registrado

Flujo de Ejecucion

El flujo de ejecucion de un workflow sigue una cadena de servicios con responsabilidades bien definidas. El flujo varia segun el tipo de trigger.

Flujo para Triggers de Evento de Dominio

Flujo para Triggers Programados

Componentes del Flujo

ComponenteResponsabilidad
WorkflowEventListenerServiceEscucha eventos de dominio (NestJS EventEmitter). Filtra workflows activos del evento correspondiente que coinciden con el trigger emitido.
WorkflowSchedulerServiceCron job que se ejecuta diariamente. Calcula que workflows programados deben dispararse basandose en la fecha del evento y el daysOffset. Respeta la timezone del evento.
WorkflowExecutorServiceOrquesta la ejecucion de un workflow: obtiene destinatarios, invoca el dispatcher, actualiza contadores. Es la pieza central que conecta la deteccion del trigger con el envio real.
RecipientFilterServiceAplica los filtros del recipientFilter del workflow sobre la lista de invitados del evento. Valida que cada destinatario tenga los datos de contacto necesarios para el canal elegido.
MessageDispatcherServiceCrea la CommunicationCampaign, renderiza el template con los datos de cada invitado, crea los registros CommunicationMessage y encola los jobs en Bull.

Filtrado de Destinatarios

El RecipientFilterService es responsable de determinar que invitados reciben el mensaje de un workflow. Combina multiples criterios de filtrado con logica AND (todos los filtros deben cumplirse).

Criterios de Filtrado

Por estado RSVP: El filtro rsvpStatus acepta uno o varios estados: CONFIRMED, PENDING, DECLINED, NO_RESPONSE. Esto permite, por ejemplo, enviar un recordatorio solo a invitados que aun no han respondido (PENDING + NO_RESPONSE).

Por grupo de invitados: El filtro guestGroup acepta uno o varios IDs de grupo. Los grupos son categorias definidas por el organizador (familia del novio, amigos de la novia, companeros de trabajo, etc.).

Por tags: El filtro tags acepta uno o varios tags. Los tags son etiquetas libres asignadas a invitados para segmentacion flexible.

Por datos de contacto: El servicio valida automaticamente que el destinatario tenga el dato de contacto necesario para el canal del workflow:

  • Email: requiere campo email no vacio
  • WhatsApp/SMS: requiere campo phone no vacio
  • Push: requiere al menos un pushToken registrado en el dispositivo

Los invitados que no tienen el dato de contacto requerido se excluyen silenciosamente (no generan error, simplemente no reciben el mensaje).

Ejemplo de recipientFilter

{
  "rsvpStatus": ["PENDING", "NO_RESPONSE"],
  "guestGroup": ["family-bride"],
  "tags": ["vip"]
}

Este filtro selecciona invitados que: (1) no han respondido al RSVP, (2) pertenecen al grupo "familia de la novia", y (3) tienen el tag "vip". Los tres criterios deben cumplirse simultaneamente.


Integracion con Sistema de Notificaciones

Los workflows reutilizan la arquitectura de 3 capas de notificaciones existente en Nvito. No implementan su propio sistema de envio, sino que generan campanas y mensajes que fluyen a traves de la infraestructura ya probada.

Arquitectura de 3 Capas

Capa 1 — NotificationChannelsModule (canales puros): Servicios de envio sin logica de negocio. Cada servicio sabe como enviar un mensaje por su canal especifico. No tienen dependencia a Bull ni a la base de datos.

  • EmailService — Envio via SMTP (nodemailer). Soporta HTML templates con variables.
  • WhatsAppService — Envio via Twilio API. Soporta templates aprobados de WhatsApp Business.
  • SmsService — Envio via Twilio API. Mensajes de texto plano.
  • PushSenderService — Envio via Expo Push API. Notificaciones push a iOS y Android.

Capa 2 — QueueModule (colas Bull/Redis): Maneja el encolamiento y procesamiento asincrono de jobs. Cada canal tiene su propia cola con concurrencia y reintentos configurables.

  • EmailProcessor — Procesa jobs de email. Concurrencia configurable.
  • WhatsAppProcessor — Procesa jobs de WhatsApp. Concurrencia limitada por rate limits de Twilio.
  • PushProcessor — Procesa jobs de push. Batch de hasta 100 notificaciones por request a Expo.

Capa 3 — NotificationsModule (API de alto nivel): Expone la API publica que los workflows (y otros modulos) consumen. Maneja la logica de creacion de campanas, mensajes, templates y metricas.

Vinculacion Workflow-Campana

Cada vez que un workflow se ejecuta, crea una nueva CommunicationCampaign con el campo workflowId vinculado. Esto permite:

  • Rastrear cuantas campanas ha generado un workflow
  • Ver el historial de envios por workflow en el panel admin
  • Distinguir campanas manuales (sin workflowId) de campanas automatizadas

Retry Policy y Ciclo de Vida de Mensajes

Ciclo de Vida del CommunicationMessage

Cada mensaje individual creado por un workflow sigue un ciclo de vida con estados bien definidos:

Estados del Mensaje

EstadoDescripcionSiguiente paso
PENDINGMensaje creado, aun no encoladoSe encola en Bull
QUEUEDJob activo en la cola BullProcesador lo toma y envia
SENTEl proveedor (SMTP, Twilio, Expo) acepto el mensajeEspera webhook de confirmacion
DELIVEREDWebhook confirma que el destinatario recibio el mensajePara email, puede transicionar a OPENED
OPENEDEl destinatario abrio el email (tracking pixel)Estado terminal exitoso
FAILEDError irrecuperable despues de agotar reintentosEstado terminal de error
BOUNCEDEl email reboto (direccion invalida, buzon lleno, etc.)Estado terminal, se registra para exclusion

Politica de Reintentos

Los workflows utilizan la misma politica de reintentos que el sistema de colas general:

ParametroValorDescripcion
Intentos maximos3Numero total de intentos (1 original + 2 reintentos)
BackoffExponencialEl delay se duplica en cada reintento
Delay base5,000msPrimer reintento a los 5 segundos
Delay maximo60,000msTope de 1 minuto entre reintentos

La secuencia de reintentos es: intento 1 (inmediato) -> fallo -> espera 5s -> intento 2 -> fallo -> espera 10s -> intento 3 -> fallo -> dead letter.

Dead letter: Cuando un mensaje agota sus 3 intentos, su status se actualiza a FAILED y se registra el error completo en el campo errorDetails del CommunicationMessage. No se reintenta mas. El contador failedCount de la campana padre se incrementa.

Webhooks de Estado

Para email y WhatsApp, los proveedores notifican cambios de estado via webhooks:

  • Email (SMTP): Los servidores SMTP con soporte de DSN (Delivery Status Notification) envian bounces. Los emails con tracking pixel reportan apertura via webhook a /api/communications/webhook/email.
  • WhatsApp (Twilio): Twilio envia callbacks de estado (sent, delivered, read, failed) al webhook configurado en /api/communications/webhook/whatsapp.
  • Push (Expo): Expo retorna tickets de recibo que se verifican periodicamente. Los tokens invalidos se marcan para exclusion.

Limites y Restricciones

Limites por Evento

LimiteValorMotivo
Workflows maximos por evento10Evitar complejidad excesiva y conflictos entre workflows
Ejecuciones simultaneas1 por workflowUn workflow no puede ejecutarse si ya tiene una ejecucion en progreso
Destinatarios por ejecucionSin limite explicitoLimitado indirectamente por la capacidad de las colas Bull

Restricciones de Negocio

  • Un workflow solo puede pertenecer a un evento. No existe el concepto de workflow global o de organizacion.
  • Los workflows programados (DAYS_BEFORE_EVENT, EVENT_DAY, POST_EVENT) se calculan en la timezone del evento, no UTC.
  • Un workflow PAUSED no se ejecuta, pero no pierde su posicion en el scheduler. Al reactivarlo, se ejecutara en la proxima ventana valida.
  • Los workflows COMPLETED no pueden reactivarse. Para repetir un workflow completado, el usuario debe crear uno nuevo.
  • Los triggers GUEST_ADDED, RSVP_CONFIRMED y RSVP_DECLINED pueden ejecutarse multiples veces (una por cada invitado que dispare el evento). Los triggers EVENT_DAY y POST_EVENT se ejecutan una sola vez.

Testing

El sistema de workflows cuenta con tests unitarios que cubren el servicio, controller, listener, executor, filtro y dispatcher.

Areas Cubiertas

CommunicationWorkflowsService:

  • CRUD completo (crear, listar, actualizar, eliminar)
  • Validacion de limite de 10 workflows por evento
  • Toggle entre ACTIVE y PAUSED
  • Rechazo de toggle en workflows COMPLETED

CommunicationWorkflowsController:

  • Autorizacion: requiere token valido y acceso al evento
  • Validacion de DTOs con class-validator
  • Respuestas correctas para cada endpoint

WorkflowEventListenerService:

  • Deteccion correcta de triggers por tipo de evento de dominio
  • Filtrado de workflows ACTIVE (ignora PAUSED y COMPLETED)
  • Manejo de multiples workflows para el mismo trigger

WorkflowExecutorService:

  • Ejecucion completa del flujo (filtrado -> dispatch -> contadores)
  • Incremento de executionCount y lastExecutedAt
  • Transicion a COMPLETED para triggers de ejecucion unica

RecipientFilterService:

  • Filtrado por rsvpStatus, guestGroup, tags
  • Exclusion de destinatarios sin datos de contacto
  • Combinacion AND de multiples filtros

MessageDispatcherService:

  • Creacion de CommunicationCampaign con workflowId
  • Renderizado de template con variables de invitado
  • Encolamiento correcto en el canal correspondiente

Referencias

Modulo de Workflows

  • CommunicationWorkflowsController: src/modules/communications/controllers/communication-workflows.controller.ts
  • CommunicationWorkflowsService: src/modules/communications/services/communication-workflows.service.ts
  • WorkflowEventListenerService: src/modules/communications/services/workflow-event-listener.service.ts
  • WorkflowExecutorService: src/modules/communications/services/workflow-executor.service.ts
  • WorkflowSchedulerService: src/modules/communications/services/workflow-scheduler.service.ts

Servicios Compartidos

  • RecipientFilterService: src/modules/communications/services/recipient-filter.service.ts
  • MessageDispatcherService: src/modules/communications/services/message-dispatcher.service.ts
  • CommunicationTemplateService: src/modules/communications/services/communication-template.service.ts

Modelo Prisma

  • CommunicationWorkflow: prisma/schema.prisma (modelo CommunicationWorkflow)
  • CommunicationCampaign: prisma/schema.prisma (modelo CommunicationCampaign)
  • CommunicationMessage: prisma/schema.prisma (modelo CommunicationMessage)

Documentacion Relacionada

Esta pagina fue util?