Chat Application System Design (HLD & LLD)
Functional Requirements
Section titled “Functional Requirements”Core Features
Section titled “Core Features”- 1-to-1 messaging
- Group chat
- Send/receive messages in real-time
- Message delivery status:
- Sent
- Delivered
- Read
- Online/offline presence
- Message history
- Push notifications
Optional Advanced Features
Section titled “Optional Advanced Features”- Media messages
- Message reactions
- Typing indicators
- Message editing/deleting
- End-to-end encryption
Non-Functional Requirements
Section titled “Non-Functional Requirements”- Low latency (<100 ms)
- Highly scalable (millions of users)
- Highly available
- Eventual consistency
- Reliable message delivery
- Horizontal scalability
High-Level Design (HLD)
Section titled “High-Level Design (HLD)”Core Components
Section titled “Core Components”flowchart TD
C[Client Mobile/Web]
G[API Gateway]
CS[Chat Service]
PS[Presence Service]
MS[Message Service]
NS[Notification Service]
R[(Redis)]
K[(Kafka)]
U[(User DB)]
MDB[(Message DB)]
PUSH[Push Service]
C --> G --> CS
CS --> PS
CS --> MS
CS --> NS
PS --> R
MS --> K
MS --> MDB
NS --> PUSH
PS --> U
Component Responsibilities
Section titled “Component Responsibilities”API Gateway
Section titled “API Gateway”- Authentication
- Rate limiting
- Routing
Chat Service
Section titled “Chat Service”Responsible for:
- Sending messages
- Receiving messages
- Routing messages
Technologies:
- WebSocket
- gRPC
- HTTP
Presence Service
Section titled “Presence Service”Tracks:
- Online/offline status
- Last seen
Redis example:
userId -> onlineuserId -> last_seenMessage Service
Section titled “Message Service”Responsible for:
- Message persistence
- Message retrieval
- Delivery status
Notification Service
Section titled “Notification Service”Responsible for:
- Push notifications
- Email/SMS alerts
Used for:
- Decoupling services
- Asynchronous message delivery
Producer -> Chat ServiceConsumer -> Message ServiceConsumer -> Notification ServiceHigh-Level Architecture
Section titled “High-Level Architecture”flowchart LR
A[User A] --> W[WebSocket Gateway]
W --> C[Chat Service]
C --> K[(Kafka)]
K --> M[Message Service]
K --> N[Notification Service]
M --> DB[(Message DB)]
Data Model
Section titled “Data Model”Tables
Section titled “Tables”user_idnamephonestatuscreated_atConversation
Section titled “Conversation”conversation_idtype (DIRECT/GROUP)created_atConversationMember
Section titled “ConversationMember”conversation_iduser_idjoined_atMessage
Section titled “Message”message_idconversation_idsender_idcontenttype (TEXT/IMAGE)timestampstatusMessageStatus
Section titled “MessageStatus”message_iduser_idstatus (sent/delivered/read)timestampER Diagram
Section titled “ER Diagram”erDiagram
USER ||--o{ CONVERSATION_MEMBER : joins
CONVERSATION ||--o{ CONVERSATION_MEMBER : contains
CONVERSATION ||--o{ MESSAGE : has
MESSAGE ||--o{ MESSAGE_STATUS : tracks
Message Flow
Section titled “Message Flow”sequenceDiagram
participant A as User A
participant WS as WebSocket Gateway
participant CS as Chat Service
participant K as Kafka
participant MS as Message Service
participant B as User B
A->>WS: SEND_MESSAGE
WS->>CS: Validate request
CS->>K: Publish MESSAGE_SENT
K->>MS: Consume event
MS->>MS: Persist message
CS->>B: Deliver via WebSocket
B->>CS: Delivered / Read Ack
Send Request
Section titled “Send Request”{ "senderId": "...", "conversationId": "...", "message": "Hello"}Steps:
- Client sends the message over WebSocket.
- Chat Service validates the user.
- Generates a
messageId. - Publishes
MESSAGE_SENTto Kafka. - Message Service stores the message.
- Chat Service delivers it over WebSocket.
- Delivery/read status is updated.
WebSocket Connection Management
Section titled “WebSocket Connection Management”Maintain active sessions:
userId -> websocket sessionDistributed registry:
userId -> serverIdRedis Cluster stores the mapping so any chat server can locate a user’s active connection.
Scaling Strategies
Section titled “Scaling Strategies”Horizontal Scaling
Section titled “Horizontal Scaling”flowchart TD
LB[Load Balancer]
LB --> S1[Chat Server 1]
LB --> S2[Chat Server 2]
Sticky Sessions
Section titled “Sticky Sessions”WebSockets require sticky sessions.
Possible solutions:
- Consistent hashing
- Redis-based connection registry
Database Sharding
Section titled “Database Sharding”Shard messages by:
conversation_idor
user_idRedis Caching
Section titled “Redis Caching”Cache:
recent messagesuser presenceconversation metadataMessage Ordering
Section titled “Message Ordering”Kafka partitions by conversation:
partition = hash(conversationId)This preserves ordering for messages within a conversation.
Offline Users
Section titled “Offline Users”- Persist the message.
- Send a push notification.
- Deliver when the user reconnects.
Reliability
Section titled “Reliability”- Unique
messageId - Idempotent consumers
Low-Level Design (LLD)
Section titled “Low-Level Design (LLD)”Message
Section titled “Message”class Message { String messageId; String conversationId; String senderId; String content; MessageType type; long timestamp;}Conversation
Section titled “Conversation”class Conversation { String conversationId; ConversationType type; List<User> participants;}ChatService
Section titled “ChatService”class ChatService {
MessageRepository messageRepository; WebSocketManager socketManager;
public void sendMessage(Message msg){ messageRepository.save(msg); socketManager.deliver(msg); }}WebSocketManager
Section titled “WebSocketManager”class WebSocketManager {
Map<String, Session> userSessions;
void deliver(Message msg){ Session s = userSessions.get(msg.receiverId); s.send(msg); }}Class Diagram
Section titled “Class Diagram”classDiagram
class Message
class Conversation
class ChatService
class WebSocketManager
ChatService --> WebSocketManager
ChatService --> Message
Conversation --> Message
Bottlenecks and Solutions
Section titled “Bottlenecks and Solutions”| Problem | Solution |
|---|---|
| WebSocket scaling | Connection registry |
| Database growth | Sharding |
| Message ordering | Kafka partitions |
| Offline users | Push notifications |
| Hot conversations | Partitioning |
Send Message
Section titled “Send Message”POST /messagesRequest:
{ "conversationId": "...", "message": "Hello"}Fetch Messages
Section titled “Fetch Messages”GET /messages?conversationId=123&limit=50Mark as Read
Section titled “Mark as Read”POST /messages/readCommon Interview Follow-Up Questions
Section titled “Common Interview Follow-Up Questions”- How does WhatsApp scale to billions of users?
- How would you implement end-to-end encryption?
- How do you maintain message ordering across servers?
- How do typing indicators work?
- How do you support group chats with thousands of users?
- How would you implement full-text message search?
Advanced Topics
Section titled “Advanced Topics”Senior/staff-level interviews often explore:
- WhatsApp-scale architecture
- Fan-out vs. pull messaging models
- Read receipt scaling
- Millions of concurrent WebSocket connections
- Multi-region/global chat architectures
Key Takeaways
Section titled “Key Takeaways”- WebSockets provide low-latency real-time messaging.
- Kafka decouples services and preserves message ordering using conversation-based partitioning.
- Redis enables presence tracking, connection routing, and caching.
- Database sharding and horizontal scaling are essential for handling billions of messages.
- Reliable delivery requires unique message IDs, persistent storage, and idempotent processing.