# Main Flows ## Producer -> Notification ```mermaid sequenceDiagram participant Producer participant Stream as Redis Stream notification:intents participant Consumer as Intent consumer participant Notify as Notification Service participant Redis Producer->>Stream: XADD normalized intent Consumer->>Stream: XREAD from stored offset Consumer->>Notify: decode and validate envelope alt malformed intent Notify->>Redis: record malformed-intent entry Consumer->>Redis: save stream offset else duplicate with same normalized content Notify->>Redis: load accepted notification Consumer->>Redis: save stream offset else idempotency conflict Notify->>Redis: record malformed-intent entry Consumer->>Redis: save stream offset else new valid intent Notify->>Redis: store notification, routes, and idempotency record Consumer->>Redis: save stream offset end ``` Duplicate handling is scoped by `(producer, idempotency_key)`. `request_id` and `trace_id` are observability-only metadata and do not participate in the idempotency fingerprint. ## User-Targeted Enrichment ```mermaid sequenceDiagram participant Consumer as Intent consumer participant Notify as Notification Service participant User as User Service participant Redis Consumer->>Notify: accepted user-targeted intent loop each recipient_user_id Notify->>User: GET /api/v1/internal/users/{user_id} alt user exists User-->>Notify: email + preferred_language else subject_not_found Notify->>Redis: record malformed intent recipient_not_found Consumer->>Redis: save stream offset else temporary failure Notify-->>Consumer: service unavailable Consumer-->>Consumer: stop before stream-offset advance end end Notify->>Redis: persist enriched routes ``` User-targeted routes are enriched before durable route write. The currently supported resolved locale is exactly `en`; unsupported or empty values fall back to `en`. ## Notification -> Gateway ```mermaid sequenceDiagram participant Push as Push publisher participant Redis participant Gateway as Edge Gateway participant Client Push->>Redis: load due push route Push->>Redis: acquire temporary route lease Push->>Push: encode FlatBuffers notification payload Push->>Redis: XADD MAXLEN ~ gateway client-event stream Push->>Redis: mark route published and remove from schedule Gateway->>Redis: XREAD client-event stream Gateway->>Gateway: sign outgoing GatewayEvent Gateway-->>Client: fan out to all active user streams ``` `Notification Service` publishes `user_id`, `event_type`, `event_id`, `payload_bytes`, and optional `request_id` / `trace_id`. It intentionally omits `device_session_id`. ## Notification -> Mail ```mermaid sequenceDiagram participant Email as Email publisher participant Redis participant Mail as Mail Service Email->>Redis: load due email route Email->>Redis: acquire temporary route lease Email->>Email: encode template-mode command Email->>Redis: XADD mail:delivery_commands Email->>Redis: mark route published and remove from schedule Mail->>Redis: XREAD mail:delivery_commands Mail->>Mail: accept template delivery command ``` Notification-generated mail always uses `source=notification`, `payload_mode=template`, and `template_id == notification_type`. Auth-code mail is not part of this flow and remains a direct `Auth / Session Service -> Mail Service` request. ## Retry and Dead Letter ```mermaid sequenceDiagram participant Publisher participant Redis participant Downstream as Gateway or Mail Service Publisher->>Redis: load due route Publisher->>Redis: acquire temporary route lease Publisher->>Downstream: append downstream stream entry alt publication succeeds Publisher->>Redis: mark published and remove schedule member else retry budget remains Publisher->>Redis: mark failed and schedule next attempt else retry budget exhausted Publisher->>Redis: mark dead_letter and write dead-letter entry end ``` `push` and `email` retry independently. A dead-lettered route never rolls back or invalidates a sibling route that already reached `published`.