Write apps/backend/docs/concepts-replay-protection.md covering services/replay-protection.service.ts and the dispatcher's idempotency path: how an eventId is recorded, the device-scoped key, the configurable TTL, and the dispatch_ack carrying duplicate: true/false.
Acceptance criteria:
- Explains the two distinct layers — transport-level
eventId dedup and message-level messageId idempotency — and why both exist
- Documents that the dedup key is device-scoped, so one device's replayed id cannot block another device's legitimate event
- Documents the TTL, that it is env-configurable, and the fail-open behaviour when Redis is unavailable
- Notes that handlers are reachable only through the enveloped
dispatch path, so every event gets this check
Write
apps/backend/docs/concepts-replay-protection.mdcoveringservices/replay-protection.service.tsand the dispatcher's idempotency path: how aneventIdis recorded, the device-scoped key, the configurable TTL, and thedispatch_ackcarryingduplicate: true/false.Acceptance criteria:
eventIddedup and message-levelmessageIdidempotency — and why both existdispatchpath, so every event gets this check