This guide prepares you to explain the SocketChat architecture during a technical interview. It covers the most common "deep-dive" questions and provides high-signal answers based on your implementation.
Interviewer: "Tell me about the architecture of your chat system."
Your Answer:
"I built SocketChat as a distributed real-time messaging platform. It uses Node.js/Express and Socket.io for persistent connections, with a Nginx reverse proxy for load balancing. To handle horizontal scaling, I integrated a Redis Pub/Sub adapter so that users on different server instances can communicate seamlessly. For data durability and reliability, I used PostgreSQL with a write-through pattern and implemented idempotency keys to prevent message duplication during network retries."
Technical Implementation:
- You use Cookie-based Handshake Auth.
- The JWT is stored in an
httpOnly,Secure,SameSite=Laxcookie. - Why this matters: Unlike sending the token in a
payloadorquery string(which can be logged by proxies), the cookie is sent automatically during the HTTP Upgrade request. - The Code: In
backend/src/socket/index.ts, you parse the cookie header before the socket is even fully connected (io.use).
Technical Implementation:
- Sticky Sessions: Nginx uses
ip_hashto ensure a client stays on the same server for the initial handshake. - Redis Adapter: You use
@socket.io/redis-adapter. - Scenario: If User A is on Server 1 and User B is on Server 2:
- User A sends a message to Server 1.
- Server 1 saves it to the DB and publishes it to Redis.
- Server 2 is "listening" to Redis; it sees the message and pushes it via WebSocket to User B.
Technical Implementation:
- Client-Side: The frontend generates a unique
client_message_id(UUID) for every message before sending it. - Database-Side: The
messagestable has aUNIQUE (client_message_id)constraint. - Logic: You use
INSERT ... ON CONFLICT DO NOTHING. - Interview Signal: This demonstrates you understand Idempotency and the "At-Least-Once" delivery challenges of distributed systems.
Technical Implementation:
- The Problem: A user might have 3 tabs open across 2 different servers. You don't want them to show as 'Offline' if they just close one tab.
- The Solution: You used a Redis Hash with
HINCRBY.- Connect: Increment the counter in Redis. If the result is
1, they just went online. - Disconnect: Decrement the counter. If the result is
0, they are officially offline.
- Connect: Increment the counter in Redis. If the result is
- Why Redis? Server memory is isolated. Redis provides a Global Shared State that all server instances can see.
| Choice | Trade-off |
|---|---|
| PostgreSQL vs. MongoDB | I chose Postgres for ACID compliance and strict schemas for user/auth data. For extreme scale (billions of messages), I would look at partitioning Postgres or moving to a NoSQL store like Cassandra/ScyllaDB. |
| Redis vs. Kafka | Redis is perfect for sub-millisecond low-latency fan-out needed for chat. I would add Kafka later if I needed a durable "event stream" for analytics or complex search indexing. |
| HTTP Handshake Auth | Using cookies simplifies the code and is more secure against XSS, but it requires the frontend and backend to share a domain (or properly configured CORS/Cookies). |
If they ask how you'd improve the system, mention these:
- Message Ordering (Sequence Numbers): Use a per-channel sequence number to ensure that if packets arrive out of order, the UI can re-sort them correctly.
- Media Sharding: Move file uploads to an S3-compatible object store and use a CDN (CloudFront) for delivery instead of serving them from the local backend.
- Read Receipts: Implement a "Last Read Message" pointer in the database per user per channel to handle unread counts efficiently.
Tip for your interview: Have a tab open with your README.md and the backend/src/socket/index.ts file. These are your strongest "evidence" files!