feat: notification service
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
# 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`.
|
||||
Reference in New Issue
Block a user