Skip to main content
Traducción. Autoritativo: fs-msg-0001-channel-cascade.md.
Cuando esto se entregue, cualquier módulo podrá preguntar “¿puedo notificar a esta persona sobre esto, y cómo?” y recibir una respuesta que ya considera nuestro estado operativo, la configuración del tenant y las decisiones de la propia persona.

Contexto

Todo módulo necesita notificar a alguien, y sin una respuesta única cada uno inventa la suya — uno verifica consentimiento, otro olvida quiet hours, un tercero envía igual porque su mensaje le pareció importante. Así termina una plataforma con cuatro caminos de entrega y un reclamo. ADR-019 lo convierte en una función pura sobre cuatro niveles de configuración y un conjunto de compuertas del destinatario. Que sea pura importa: resolveChannels no hace I/O, así que se puede testear exhaustivamente, y un cambio de reglas es un cambio en una función probada y no en cuatro lugares. La fila del canal y el puerto existen desde el día uno aunque el adaptador llegue después (DEC-E1).

Alcance (normativo)

  • Los cuatro niveles: plataforma, tenant, módulo, enrutamiento de evento.
  • resolveChannels(evento, tenant, módulo, destinatario) como función pura en packages/core.
  • Compuertas del destinatario: consentimiento, supresión, centro de preferencias, y para marketing quiet hours y frequency caps.
  • Categoría por entrada de enrutamiento: transactional | marketing | product.
  • Una razón tipada para cada exclusión, registrada cuando un mensaje no se envía.
  • Endpoints de gestión para cada nivel.

Fuera de alcance (normativo)

  • Renderizar — FS-MSG-0002. La resolución decide si y dónde, no qué.
  • Encolar y entregar — FS-MSG-0005 y FS-MSG-0006.
  • El almacenamiento del consentimiento, que es de core y acá se lee, nunca se escribe.
  • Fallback entre canales (push falla → email), que es F2 y queda anotado (DEC-E4).

Comportamiento (normativo)

  1. La resolución corre los niveles en orden, y cualquiera que diga no la termina: plataforma operativa → tenant habilitado y configurado → módulo habilitado → existe enrutamiento del evento.
  2. Luego las compuertas del destinatario: consentimiento para ese canalno suprimido ∧ el centro de preferencias lo permite ∧ (solo marketing) quiet hours y frequency caps.
  3. Transaccional no es opt-out (DEC-E3). Pasa el centro de preferencias, quiet hours y caps, pero nunca pasa la supresión: un rebote duro significa que la dirección no funciona, y la categoría no cambia eso.
  4. Cada “no” devuelve una razón tipada, y la razón se registra. “No enviado” sin razón hace imposible el soporte e imposible responder una pregunta de cumplimiento.
  5. La función es pura: sin base de datos, sin caché, sin leer el reloj. Sus entradas son el evento, la configuración ya cargada y el snapshot del destinatario.
  6. Las quiet hours se evalúan en la zona horaria del destinatario cuando se conoce, cayendo a la del tenant. Una regla de quiet hours en la zona equivocada es peor que ninguna.
  7. El resultado es una lista de canales, no uno. Un evento puede ir legítimamente a in-app y email.
  8. PROHIBIDO: cualquier camino de envío que no llame a esta función · una configuración de tenant que desactive la verificación de supresión o de consentimiento · una categoría que salte la cascada.

Datos (normativo)

API (normativo)

simulate responde “si este evento ocurriera para este contacto ahora, qué enviaríamos y por qué no el resto” — la herramienta de soporte más útil del módulo.

Eventos (normativo)

Ninguno emitido. Esta feature consume los eventos de todos los módulos y decide qué sigue.

Criterios de aceptación (normativo)

  1. 100% de cobertura de ramas en resolveChannels, con un fixture por nivel y por compuerta.
  2. Un destinatario suprimido no recibe nada, incluido transaccional.
  3. Quien optó por salir de marketing sigue recibiendo transaccional.
  4. Las quiet hours se evalúan en la zona del destinatario, verificado cruzando la línea de cambio de fecha.
  5. Cada exclusión devuelve una razón tipada distinta, y la razón queda registrada.
  6. Desactivar un canal a nivel de módulo detiene los envíos de ese módulo sin afectar a otros.
  7. simulate no escribe nada y devuelve tanto los canales resueltos como las razones del resto.
  8. Negativo: ninguna configuración desactiva la compuerta de consentimiento ni la de supresión.

Ejecución

Un solo slice, comando síncrono. La función pura vive en packages/core junto al evaluador de acumulación; las tablas y endpoints en backend/api. Parte de TS-002.

Preguntas abiertas

Changelog

Registro de entrega

Aún no implementado.