131 lines
4.3 KiB
Markdown
131 lines
4.3 KiB
Markdown
# 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`.
|