> ## Documentation Index
> Fetch the complete documentation index at: https://internal.softcrum.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Estándar — Notificaciones (NUEVO)

> email · in_app · webhook · push · sms (adaptador en F1b, tras un ADR de proveedor) · whatsapp (F2) · live_activity (F2). La fila de canal y el NotificationChannelPort existen desde el día 1.

> Traducción. Autoritativo: [`../../standards/notifications.md`](/standards/notifications).

## Catálogo de canales (`core.notification_channels`, paramétrico)

email · in\_app · webhook · push · sms (adaptador en F1b tras el ADR del proveedor) · whatsapp (F2) ·
live\_activity (F2). La fila del canal y el `NotificationChannelPort` existen desde el día 1 aunque el
adaptador llegue después.

## Resolución en cascada (niveles 0–3 + destinatario)

`resolveChannels(evento, tenant, módulo, destinatario)` — función PURA en `packages/core`, con
cobertura unitaria completa:

0. Plataforma: el adaptador existe y está operativo (flag operacional de Vercel Flags, espejado en
   `messaging.platform_channel_status`).
1. Tenant: canal activo para este tenant (entitlement + credenciales o dominio de envío configurados)
   — `messaging.tenant_channel_settings`.
2. Módulo: canal habilitado para el módulo emisor en este tenant —
   `messaging.module_channel_settings`.
3. Tipo de evento: entrada de enrutamiento (canales, plantilla por canal, categoría) —
   `messaging.event_channel_routing`.

Compuertas del destinatario: consentimiento para el canal ∧ no estar en `messaging.suppressions` ∧
centro de preferencias ∧ (solo marketing: quiet hours + frequency caps).

Resultado: un job por canal resuelto en `notif.{canal}.{carril}` (standards/jobs.md).

## Categorías y controles del destinatario

* Categoría por enrutamiento de evento: `transactional | marketing | product`. El transaccional NO es
  opt-out (solo lo detiene una supresión por rebote duro).
* Centro de preferencias del member: por canal Y por categoría. Quiet hours: default por tenant,
  override por campaña. Frequency caps: solo marketing.

## Trazabilidad (end to end)

* Cadena: evento de origen → regla o campaña → job de notificación → `messaging.sends` →
  `messaging.send_status_history` (queued→sent→delivered→opened→clicked / bounced / complained /
  failed) → webhooks salientes. Todo unido por `correlation_id` + `origin_event_id`.
* Ingesta de estados por webhooks del proveedor (hoy Resend); cada canal futuro trae su adaptador de
  estados.
* Los rebotes duros y las quejas escriben automáticamente en `messaging.suppressions`. CADA envío
  verifica supresiones — sin excepciones.

## Carriles y equidad

El carril transaccional siempre gana al de marketing (jobs.md). Token buckets por proveedor (global)
y por tenant. Blasts: solo endpoints batch, con throttling; el blast de un tenant NO DEBE degradar la
latencia de OTP de otro (esta es la mitigación del límite compartido de Resend, generalizada a todos
los canales).
