Designing a Chat/Messaging App
Real-time delivery and never losing a message pull the design in two directions — the interesting part is reconciling them.
Advanced
| Functional | Non-functional |
|---|---|
| Send and receive messages in near real time | Low latency for delivery to an online recipient |
| Deliver missed messages when a user comes back online | No message loss, even if the recipient is offline for days |
| Show delivery status (sent / delivered / read) | Messages within one conversation must stay in order |
| Component | Role |
|---|---|
| Connection gateway | Holds the open WebSocket connection per online user; maintains a mapping of user ID → which gateway instance holds their connection (since a large user base is spread across many gateway machines). |
| Message service | Receives a send request, persists the message, and looks up whether the recipient is currently online. |
| Message store | The durable record of every message — a natural fit for a database that handles high write volume and mostly-sequential access per conversation. |
| Presence service | Tracks who's currently online and which gateway instance holds their connection — commonly backed by a fast key-value store given the simple, high-frequency read/write pattern. |
1. User A sends a message via their open WebSocket connection
2. Message Service persists it to the Message Store (durability first)
3. Message Service checks Presence Service: is User B online?
4. If yes: forward the message to the gateway instance holding User B's connection, push it immediately
5. If no: leave it durably stored; User B receives it on next connect
| Requirement | How it's met |
|---|---|
| Real-time delivery when online | WebSocket push via the connection gateway holding the recipient's live connection. |
| No message loss when offline | Messages persist to durable storage before any delivery attempt; a reconnect triggers a bounded catch-up query. |
| Correct ordering | Server-assigned, per-conversation monotonic sequence numbers instead of trusting client clocks. |
| Scales with user count | Presence lookups and connection routing are key-value-backed, and the message store scales the same way any high-write dataset does — see Data Partitioning & Sharding Strategies. |