High‑Level Architecture
HTTP for stateless CRUD and history. WebSocket for low‑latency, push‑based updates across clusters.
Infrastructure Diagram

Compute & Routing
- HTTP LB distributes REST traffic across HTTP EC2 clusters.
- WebSocket LB manages long‑lived connections for realtime.
- HTTP EC2 handles user creation and message history.
- WS EC2 keeps persistent sessions for low latency.
Data Storage
- DynamoDB: fast, scalable reads/writes for users, rooms, messages, and relations.
Realtime Fan‑out
- Redis stores WS connection IDs and broadcasts across WS nodes for cross‑server delivery.
Dual entry points
HTTP for REST, WS for push. Best of both worlds for UX and scalability.
Separation of duties
Stateless APIs on HTTP nodes. Stateful connections on WS nodes.
Resilient broadcast
Redis enables cross‑node delivery even when users land on different WS hosts.
Data Structures
Client-side state for different components
User basic data
type User = {
id: string, // unique identifier of the user
name: string, // a name of the user shown on the UI
avatar?: string, // the image representation of the user
}
Interfaces
HTTP API endpoints and WebSocket actions.
RESTGet users, create users, fetch room messages.
GET/users
Get users you can create a room with.
Response
[
{ "id": "user_123", "name": "Alice", "avatar": "https://example.com/avatar/alice.png" },
{ "id": "user_456", "name": "Bob", "avatar": "https://example.com/avatar/bob.png" }
]
POST/users
Create a new user.
Payload
{
"name": "Alice",
"avatar": "https://example.com/avatar/alice.png"
}
Response
{
"id": "user_123",
"name": "Alice",
"avatar": "https://example.com/avatar/alice.png"
}
GET/rooms/{room_id}/messages
Get message history of a room.
Response
[
{
"roomId": "room_456",
"messageId": "msg_001",
"content": "Hello!",
"senderId": "user_123",
"createdAt": "2024-06-16T12:34:56.789Z",
"status": "success"
},
{
"roomId": "room_456",
"messageId": "msg_002",
"content": "Hi!",
"senderId": "user_456",
"createdAt": "2024-06-16T12:35:12.000Z",
"status": "success"
}
]
WebSocketCreate rooms and messages, broadcast to online users.
WSaction: create_room
Create a room via WebSocket and notify participants.
Can also be modeled as HTTP + SSE if WS is not preferred.
Payload
{
"action": "create_room",
"participants": ["user_123", "user_456"]
}
Response
{
"type": "room_created",
"room": {
"id": "room_456",
"participants": [
{ "id": "user_123", "name": "Alice" },
{ "id": "user_456", "name": "Bob" }
],
"createdAt": "2024-06-16T12:36:00.000Z"
}
}
WSaction: create_message
Create a message and broadcast to the room.
Payload
{
"action": "create_message",
"roomId": "room_456",
"messageId": "msg_003", // client-generated UUID
"content": "How are you?",
"senderId": "user_123",
"createdAt": "2024-06-16T12:36:10.000Z"
}
Response
{
"type": "message_created",
"message": {
"roomId": "room_456",
"messageId": "msg_003",
"content": "How are you?",
"senderId": "user_123",
"createdAt": "2024-06-16T12:36:10.000Z",
"status": "success"
}
}
Tip
Room creation can also be modeled as HTTP + SSE if WebSocket is not preferred for that flow.