feat: notification service
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
# Configuration and Contract Examples
|
||||
|
||||
The examples below are illustrative. IDs, timestamps, and stream keys are
|
||||
placeholders unless explicitly stated otherwise.
|
||||
|
||||
## Example Environment
|
||||
|
||||
Minimal local runtime:
|
||||
|
||||
```dotenv
|
||||
NOTIFICATION_REDIS_ADDR=127.0.0.1:6379
|
||||
NOTIFICATION_INTERNAL_HTTP_ADDR=:8092
|
||||
NOTIFICATION_USER_SERVICE_BASE_URL=http://127.0.0.1:8091
|
||||
|
||||
NOTIFICATION_GATEWAY_CLIENT_EVENTS_STREAM=gateway:client-events
|
||||
NOTIFICATION_MAIL_DELIVERY_COMMANDS_STREAM=mail:delivery_commands
|
||||
|
||||
NOTIFICATION_ADMIN_EMAILS_GEO_REVIEW_RECOMMENDED=geo-admin@example.com
|
||||
NOTIFICATION_ADMIN_EMAILS_GAME_GENERATION_FAILED=ops@example.com
|
||||
NOTIFICATION_ADMIN_EMAILS_LOBBY_RUNTIME_PAUSED_AFTER_START=ops@example.com
|
||||
NOTIFICATION_ADMIN_EMAILS_LOBBY_APPLICATION_SUBMITTED=admins@example.com
|
||||
|
||||
OTEL_TRACES_EXPORTER=none
|
||||
OTEL_METRICS_EXPORTER=none
|
||||
```
|
||||
|
||||
## Probe HTTP Examples
|
||||
|
||||
Liveness:
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:8092/healthz
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok"
|
||||
}
|
||||
```
|
||||
|
||||
Readiness:
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:8092/readyz
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ready"
|
||||
}
|
||||
```
|
||||
|
||||
## User-Targeted Intent Example
|
||||
|
||||
```bash
|
||||
redis-cli XADD notification:intents '*' \
|
||||
notification_type game.turn.ready \
|
||||
producer game_master \
|
||||
audience_kind user \
|
||||
recipient_user_ids_json '["user-1","user-2"]' \
|
||||
idempotency_key game-master:game-123:turn-54 \
|
||||
occurred_at_ms 1775121700000 \
|
||||
request_id request-123 \
|
||||
trace_id trace-123 \
|
||||
payload_json '{"game_id":"game-123","game_name":"Nebula Clash","turn_number":54}'
|
||||
```
|
||||
|
||||
Expected effects:
|
||||
|
||||
- `Notification Service` resolves both users through `User Service`
|
||||
- one `push` route and one `email` route are materialized per user
|
||||
- `Gateway` receives user-wide client events without `device_session_id`
|
||||
- `Mail Service` receives template-mode commands with
|
||||
`template_id=game.turn.ready`
|
||||
|
||||
## Administrator Intent Example
|
||||
|
||||
```bash
|
||||
redis-cli XADD notification:intents '*' \
|
||||
notification_type geo.review_recommended \
|
||||
producer geoprofile \
|
||||
audience_kind admin_email \
|
||||
idempotency_key geoprofile:user-123:review-true:1775121700001 \
|
||||
occurred_at_ms 1775121700001 \
|
||||
payload_json '{"user_id":"user-123","user_email":"pilot@example.com","observed_country":"DE","usual_connection_country":"PL","review_reason":"country_mismatch"}'
|
||||
```
|
||||
|
||||
Expected effects:
|
||||
|
||||
- `Notification Service` does not call `User Service`
|
||||
- recipients are read from `NOTIFICATION_ADMIN_EMAILS_GEO_REVIEW_RECOMMENDED`
|
||||
- only email routes are publishable; push route slots are skipped
|
||||
|
||||
## Gateway Client Event Shape
|
||||
|
||||
Example stream entry appended by `Notification Service`:
|
||||
|
||||
```bash
|
||||
redis-cli XADD gateway:client-events MAXLEN '~' 1024 '*' \
|
||||
user_id user-1 \
|
||||
event_type game.turn.ready \
|
||||
event_id '1775121700000-0/push:user:user-1' \
|
||||
payload_bytes '<flatbuffers-bytes>' \
|
||||
request_id request-123 \
|
||||
trace_id trace-123
|
||||
```
|
||||
|
||||
`Gateway` derives `timestamp_ms`, computes `payload_hash`, signs the outgoing
|
||||
event, and delivers it to every active stream for `user-1`.
|
||||
|
||||
## Mail Command Shape
|
||||
|
||||
Example stream entry appended by `Notification Service`:
|
||||
|
||||
```bash
|
||||
redis-cli XADD mail:delivery_commands '*' \
|
||||
delivery_id '1775121700000-0/email:user:user-1' \
|
||||
source notification \
|
||||
payload_mode template \
|
||||
idempotency_key 'notification:1775121700000-0/email:user:user-1' \
|
||||
requested_at_ms 1775121700000 \
|
||||
request_id request-123 \
|
||||
trace_id trace-123 \
|
||||
payload_json '{"to":["pilot@example.com"],"cc":[],"bcc":[],"reply_to":[],"template_id":"game.turn.ready","locale":"en","variables":{"game_id":"game-123","game_name":"Nebula Clash","turn_number":54},"attachments":[]}'
|
||||
```
|
||||
|
||||
## Dead-Letter Replay
|
||||
|
||||
Replay a dead-lettered route by publishing a new compatible intent with a new
|
||||
producer-owned `idempotency_key`.
|
||||
|
||||
```bash
|
||||
redis-cli XADD notification:intents '*' \
|
||||
notification_type game.turn.ready \
|
||||
producer game_master \
|
||||
audience_kind user \
|
||||
recipient_user_ids_json '["user-1"]' \
|
||||
idempotency_key game-master:game-123:turn-54:manual-replay-1 \
|
||||
occurred_at_ms 1775121700000 \
|
||||
payload_json '{"game_id":"game-123","game_name":"Nebula Clash","turn_number":54}'
|
||||
```
|
||||
|
||||
Do not mutate existing `notification_route`,
|
||||
`notification_dead_letter_entry`, or `notification:route_schedule` records as a
|
||||
replay workflow.
|
||||
Reference in New Issue
Block a user