hardSenior Backend EngineerSocial Media
How would you design a real-time chat system supporting group chats, typing indicators, and message history?
Posted 18/04/2026
by Mehedy Hasan Ador
Question Details
At a messaging company:
"Design a chat system that supports: private messages, group chats (up to 200 members), typing indicators, online status, and message history. 1M daily active users."
Suggested Solution
Architecture
Client → WebSocket Gateway → Message Service → Message DB (MongoDB)
↓ ↓
Presence Service Push Notification Service
↓
Redis (online status)
WebSocket Connection
// Server
const connections = new Map<string, WebSocket>(); // userId → socket
wss.on("connection", (ws, req) => {
const userId = authenticate(req);
connections.set(userId, ws);
// Set online status
await redis.set(`online:${userId}`, "1", "EX", 300);
ws.on("message", async (data) => {
const msg = JSON.parse(data);
switch (msg.type) {
case "chat":
// Save to DB
await db.message.create({ data: msg.payload });
// Deliver to recipients
for (const recipientId of msg.payload.recipientIds) {
const recipientWs = connections.get(recipientId);
if (recipientWs) {
recipientWs.send(JSON.stringify(msg));
} else {
// Offline → push notification
await sendPushNotification(recipientId, msg.payload);
}
}
break;
case "typing":
// Broadcast to chat members (don't persist)
broadcastToChat(msg.chatId, { type: "typing", userId });
break;
}
});
});
Key Design Decisions
| Feature | Approach |
|---|---|
| Message delivery | WebSocket with push notification fallback |
| Typing indicators | Don't persist — broadcast only, debounce 3s |
| Online status | Redis with 5min TTL, heartbeat every 2min |
| Message history | MongoDB with pagination, index on { chatId, createdAt } |
| Group chats | Fan-out on write (send to each member's connection) |
| Read receipts | Store per-message, batch update |
Scaling
| Component | Strategy |
|---|---|
| WebSocket servers | Horizontal + Redis pub/sub for cross-server messaging |
| Message storage | MongoDB sharded by chatId |
| Presence | Redis cluster |
| File attachments | Pre-signed S3 URLs, not through WebSocket |