Skip to content

Notifications flow

One pipeline handles every notification. See the Notifications concept for the model and defaults.

flowchart TD
    EV["Event emitted<br/>(e.g. booking.confirmed)"] --> AUD["Resolve audience<br/>(recipients)"]
    AUD --> PREF{"Per-recipient preference<br/>(recipient, event_type, channel)<br/>active?"}
    PREF -->|no| DROP["Skip channel"]
    PREF -->|yes| Q["BullMQ enqueue"]
    Q --> EMAIL["Email channel"]
    Q --> SMS["SMS channel"]
    Q --> INAPP["in_app (inbox + bell)"]
    Q -.planned.-> PUSH["push (slot, not built)"]
    EMAIL --> LOG["Audit log"]
    SMS --> LOG
    INAPP --> LOG

Delivery is opt-in: absent a preference row (or active=false) the channel does not fire. The in-app channel surfaces in the notification inbox/bell; the stream is authorized with a short-lived stoken.