~12 min
A chat system's functional list adds one thing the systems so far haven't needed: a live push to a connected client, not just a request-response. Send a message, deliver it to a recipient who's online right now, deliver it the next time they connect if they're not, load message history for a conversation — and the non-functional targets worth pinning down are a delivery SLO (messages should arrive in under a second when the recipient is online) and an ordering requirement (messages within one conversation must display in the order they were sent, even if delivery timing varies).
Delivering to an online recipient needs a connection the server can push through rather than one the client has to keep re-polling — a long-lived, bidirectional connection (commonly WebSocket) held open between client and server for exactly this purpose. But "push it down the open connection" only covers the recipient who's actually connected right now; the same at-least-once delivery problem this course covered for queues shows up here directly: a message sent while the recipient is offline has to be held somewhere and delivered once they reconnect, which is exactly a per-recipient queue — durable storage that survives a disconnect, delivered and acknowledged the same way any queued message is, with the same requirement that a client's message-handling logic tolerate a duplicate delivery rather than assume exactly-once.
The ordering requirement maps directly onto a concept this course already covered for streams: Kafka guarantees order only within a partition, and a chat conversation needs exactly that same scoped guarantee — order within one conversation, not globally across every conversation on the platform. A messages table keyed by (conversation_id, sent_at, message_id) gives that ordering for free from a single index, and sharding that table by conversation_id (not by a global auto-increment) keeps every write and every history read scoped to one shard, the same way a stream's per-key ordering only holds when related events share a partition key. Loading history is a straightforward range query on that index; nothing about it needs a cache as urgently as the URL shortener's redirect path did, since chat history is read far less often relative to how much of it accumulates.
It mirrors Kafka's per-partition ordering guarantee: scoping both the shard and the sort order to conversation_id means every message in one conversation lands together and reads back in order, the same way a stream only guarantees order for events sharing a partition key.