This is a high-level outline of a complete system design solution that helped a candidate pass the OpenAI system design interview round. It covers requirements gathering, API design, architecture, and key technical decisions for building a Slack-like messaging platform. There's also a link to a video walkthrough below for those that prefer that format to reading.
Design a Slack-like messaging product scoped to a 2-week MVP for corporate teams, focusing on internal company communication with channels, direct messages, threads, file sharing, and real-time delivery.
User Base & Geography:
- Primary users: Corporate teams for internal communication
- Initial deployment: Single region (Europe or North America)
- Multi-tenant product: Multiple independent companies, each with isolated workspaces
- Two role types: workspace members (read/post) and workspace admins (manage channels/users)
Scale Assumptions:
- ~5,000 total users across all workspaces
- Up to 1,000 fully active concurrent users at peak
- 20,000-30,000 messages per hour at peak (~300-500 messages/minute)
- Read-heavy system: ~10:1 read-to-write ratio due to channel broadcast effect
- File uploads: 50 MB cap per file, few thousand uploads daily
- Worst-case file transfer: ~25 GB/minute if every peak message had max-size file
| ID | Tag | Requirement | Description |
|---|---|---|---|
| FR-1 | MUST DO | Workspaces and admin controls | Isolated workspaces. Admins can create/archive channels, invite/remove members, deactivate accounts. |
| FR-2 | MUST DO | Channels | Create, browse, join, leave public channels. Any workspace member can read any public channel. |
| FR-3 | MUST DO | Direct Messages | Private 1-to-1 messages between workspace members. |
| FR-4 | MUST DO | Messaging | Send and read messages in channels and DMs. Fetch history with cursor-based pagination. |
| FR-5 | MUST DO | Threads | Reply to any channel message, creating threads. Many threads per channel. Replies not echoed to main channel. |
| FR-6 | MUST DO | File uploads | Upload/view files in channels, DMs, threads. 50 MB cap. 30-day retention minimum. |
| FR-7 | MUST DO | Near-real-time delivery | Online users receive new messages promptly via push-based delivery to web client. |
| FR-8 | MUST DO | In-app notifications | Web app notifications for @mentions and thread replies. Thread followers: root author + prior repliers. |
| FR-9 | SHOULD DO | Email notifications | Email for mentions/DMs when user inactive (simple heuristic). |
| FR-10 | NICE TO HAVE | Additional chat UX | Reactions, typing indicators, read receipts, presence. All deferred. |
| ID | Tag | Requirement | Details |
|---|---|---|---|
| NFR-1 | MUST DO | Availability | 99.9% monthly (≤43 min downtime/month). Single-region with AZ redundancy. |
| NFR-2 | MUST DO | Latency | Message send p99 ≤200ms, fetch p99 ≤300ms. |
| NFR-3 | MUST DO | Durability | Messages/files/metadata persisted durably. RPO ~1 minute acceptable. |
| NFR-4 | MUST DO | Security | All external traffic TLS encrypted. Every request authenticated. Server-side access control. Rate limiting and payload limits. |
| NFR-5 | SHOULD DO | Observability | Logs, metrics, alerts for latency, errors, file uploads, delivery lag. |
| NFR-6 | MUST DO | Scalability | Handle 5K users, 1K concurrent peak, 300-500 msg/min, associated reads/notifications, few thousand daily file uploads. |
- Full-text search and message indexing
- Voice and video calling
- Bots, third-party integrations, webhooks
- Single Sign-On (SSO)
- Advanced permissions (channel moderators, guest accounts, compliance controls)
- Presence, typing, read receipts
- Native mobile push notifications (APNS/FCM)
- File retention beyond 30 days
- Multi-region active-active deployment
In case you're looking for more handholding see the below video and deep dive tutorial walkthroughs:
- Watch the video walkthrough on YouTube - Visual explanation of the entire design
- Access the complete tutorial with deep dives - Full candidate/interviewer transcript with expert commentary covering:
- Transaction anatomy and idempotency patterns
- Data model design and indexing strategies
- Real-time fanout scaling and WebSocket architecture
- Event-driven reliability and the outbox pattern
| Entity | Description |
|---|---|
Workspace |
Top-level container for a company. Every entity scoped to a workspace. |
User |
Member of one or more workspaces. Has role per workspace: member or admin. |
Channel |
Named group conversation within workspace. Public by default for MVP. |
DmConversation |
Private 1-to-1 conversation between two workspace members. |
Message |
Single message in Channel or DmConversation. Has conversation_id and optional thread_root_id for replies. |
FileRecord |
Metadata for uploaded file: uploader, workspace, storage URL, size, MIME type, expiry. Bytes in object storage. |
Notification |
Persisted in-app notification for mention or thread reply, owned by recipient. |
REST over HTTPS: Stateless, universally supported, fits request-response traffic. All responses JSON. JWT bearer tokens in Authorization header. API Gateway validates JWT signature and extracts user_id; downstream services perform authorization checks against workspace/channel membership.
Pagination: Opaque cursor (not page numbers) encoding position in result set. Stable under concurrent data changes.
Idempotency: Client-generated idempotency_key (UUID) on message sends. Server deduplicates retries.
Workspaces & Admin
POST /workspaces
POST /workspaces/{ws_id}/members
PATCH /workspaces/{ws_id}/members/{user_id}
Channels
GET /workspaces/{ws_id}/channels
POST /workspaces/{ws_id}/channels
Direct Messages
GET /workspaces/{ws_id}/dms
POST /workspaces/{ws_id}/dms
GET /workspaces/{ws_id}/dms/{dm_id}/messages
POST /workspaces/{ws_id}/dms/{dm_id}/messages
Messages & Threads
GET /channels/{channel_id}/messages
POST /channels/{channel_id}/messages
GET /channels/{channel_id}/messages/{root_id}/replies
POST /channels/{channel_id}/messages/{root_id}/replies
Files
POST /files # Request pre-signed upload URL
GET /files/{file_id}
Request:
POST /channels/{channel_id}/messages
Authorization: Bearer eyJ...
Content-Type: application/json
{
"idempotency_key": "550e8400-e29b-41d4-a716-446655440000",
"text": "Has anyone reviewed the spec?",
"file_id": null
}Response (HTTP 201):
{
"message_id": "msg_01abc",
"conversation_id": "ch_xyz",
"sender_user_id": "usr_123",
"text": "Has anyone reviewed the spec?",
"created_at": "2025-03-15T09:41:00Z",
"thread_root_id": null,
"file": null
}Event-driven microservices architecture. Each service owns bounded responsibility, communicates via synchronous REST (user-facing) or asynchronous events (background work). Services are stateless where possible—no in-memory user/session state, all persistence delegated to database/cache/storage. Stateless services scale horizontally without coordination.
Deployment: Single-region with availability zone redundancy. Regional load balancer provides 99.9% availability target without multi-region complexity.
A) Web Client Browser-based UI (React + TypeScript) for channels, DMs, threads, files, notifications. Only client surface for MVP. Speaks REST APIs and WebSocket.
B) Regional Load Balancer Accepts HTTPS traffic, terminates TLS, performs health checks, distributes across API Gateway instances. After TLS termination, traffic stays on provider's private network. Technology: AWS ALB or GCP Load Balancer.
C) API Gateway
Single entry point. Validates JWTs, enforces rate limits (e.g., 1 msg/sec per user, lower on auth endpoints), routes to services. Extracts user_id from token for downstream. Technology: AWS API Gateway or Kong.
D) Auth Service Issues JWT session tokens on login. Provides public key endpoint for gateway verification. No per-request round trip needed. Technology: JWT with RS256 signing.
E) Chat Service
Authoritative backend for channels, DMs, messages, threads. Only service writing messages. On send: (1) check authorization, (2) insert message in transaction with idempotency constraint, (3) commit, (4) publish MessageCreated event, (5) return HTTP 201. Technology: Go or Node.js.
F) File Service
Manages pre-signed upload flow. On POST /files: validates metadata (size ≤50MB, allowed MIME types), creates FileRecord, returns pre-signed upload URL to object storage. Client uploads bytes directly. On GET /files/{file_id}: returns metadata and signed download URL. Technology: Go or Node.js.
G) PostgreSQL: Primary Database
Single durable store for all application data: users, workspaces, memberships, channels, DMs, messages, threads, files, notifications. Fully relational with foreign keys. ACID transactions for idempotency and consistency. WAL + streaming replication to standby in different AZ for durability. Supports native partitioning (by created_at) and horizontal scaling via Citus extension for future growth. Technology: PostgreSQL 15+.
H) Object Storage
Stores raw file bytes. File Service generates pre-signed URLs for direct client upload/download. Lifecycle rules auto-delete files after 30 days based on central FILE_RETENTION_DAYS config. Technology: AWS S3 or GCS.
I) Realtime Delivery Service
Maintains persistent WebSocket connections. Each instance holds in-memory map: connection_id → { user_id, subscribed_conversation_ids }. On MessageCreated event from bus, pushes to local connections subscribed to that conversation. Verifies user access before accepting subscriptions. Technology: Go (goroutine model) or Node.js with ws library.
J) Event Bus: Redis Pub/Sub
Decouples Chat Service write path from consumers. After committing message, Chat Service publishes MessageCreated. Realtime Delivery and Notification Service both subscribe independently. No event durability (acceptable for MVP; messages durable in PostgreSQL). Broadcast to all Realtime instances; each checks local subscribers. Technology: Redis Pub/Sub.
K) Notification Service
Subscribes to event bus. On MessageCreated: (1) identifies recipients (mentioned users + thread followers), (2) writes Notification records, (3) enqueues email jobs if recipients inactive, (4) publishes NotificationCreated for in-app push. Technology: Go or Node.js.
L) Async Queue & Workers: Redis-backed Job Queue Runs background jobs (email sending). Notification Service enqueues jobs; workers pick up, call email provider, retry with exponential backoff. Dead-letter queue for exhausted retries. Technology: Redis-backed job queue library.
M) Observability Prometheus (metrics scraping), Grafana (dashboards + alerts), Sentry (exception tracking), structured logs to CloudWatch/Datadog. Off-the-shelf tools, minimal setup.
Flow A: Send a Channel Message
- Client sends
POST /channels/{channel_id}/messageswith{idempotency_key, text, file_id}+ JWT - Load balancer routes to API Gateway
- API Gateway validates JWT, extracts
user_id, enforces rate limits, forwards to Chat Service - Chat Service checks workspace membership and channel access
- Chat Service begins transaction, inserts message (unique constraint on
(sender_user_id, idempotency_key)), commits - Chat Service publishes
MessageCreatedto event bus (fire-and-forget) - Chat Service returns HTTP 201 with message object
- Realtime Delivery Service receives event, pushes to subscribed WebSocket connections
- Notification Service receives event, writes notifications, enqueues emails if needed
Flow B: Load a Channel Timeline
- Client sends
GET /channels/{channel_id}/messages?limit=50&before=<cursor> - API Gateway validates token, forwards to Chat Service
- Chat Service verifies channel access, runs paginated index scan on messages table, returns 50 messages + cursor
- Client establishes/maintains WebSocket connection, subscribes to channel for future messages
Flow C: Upload File & Attach to Message
- Client sends
POST /fileswith metadata (filename, content_type, size) - File Service validates (size ≤50MB, allowed type), creates
FileRecord, returns pre-signed upload URL +file_id - Client PUTs file bytes directly to pre-signed URL (object storage)
- Client sends
POST /channels/{channel_id}/messageswithfile_idattached - Chat Service writes message referencing
file_id, proceeds through normal send flow (Flow A)
Flow D: Real-time Notification Delivery
- Message committed,
MessageCreatedpublished to event bus - Notification Service receives event. For mention: writes
Notificationper mentioned user. For thread reply: queries messages table for thread root author + prior repliers, writesNotificationper recipient (excluding sender) - Notification Service publishes
NotificationCreatedevent - Realtime Delivery Service receives event, pushes to affected users' WebSocket connections
- Client updates notification badge and inbox without fetch
- If recipient inactive, Notification Service enqueues email job; worker delivers via external provider
| Failure | Result | User Experience |
|---|---|---|
| Realtime Delivery unavailable | Messages persist, readable via fetch API | Users see messages on reconnect; core chat unaffected |
| Notification Service down | Messaging continues | In-app notifications delayed/missed; messages visible via fetch; email delivery paused |
| Redis queue/email worker down | In-app notifications work | Email delivery pauses; jobs in DLQ for replay |
| File Service unavailable | File upload/download fail | Channel/DM messaging continues uninterrupted |
| PostgreSQL unavailable | Core chat stops | Hot standby in separate AZ with automatic failover; must alert immediately |
| Component | Technology | Key Rationale |
|---|---|---|
| Web client | React, TypeScript | Component model suits chat UI; type safety catches API errors |
| Load balancer | AWS ALB / GCP LB | Managed TLS, health checks, AZ redundancy |
| API Gateway | AWS API Gateway / Kong | Auth, rate limiting, routing via config |
| Auth Service | JWT (RS256) | Stateless verification at gateway |
| Chat Service | Go / Node.js | High concurrency, single authoritative writer |
| File Service | Go / Node.js | Independent scaling, pre-signed URLs |
| PostgreSQL | PostgreSQL 15+ | ACID, WAL durability, partitioning, Citus path |
| Object Storage | S3 / GCS | Lifecycle rules, pre-signed URLs |
| Realtime Delivery | WebSockets (Go/Node.js) | Full-duplex, universal support, efficient connections |
| Event Bus | Redis Pub/Sub | Lightweight fanout, pairs with cache/queue |
| Notification Service | Go / Node.js | Isolated failure domain |
| Async Queue | Redis-backed queue | Retries, DLQ, no separate broker |
| Observability | Prometheus, Grafana, Sentry | Off-the-shelf, industry standard |
| Decision | Choice Made | Key Rationale |
|---|---|---|
| Architecture Pattern | Event-driven microservices | Clear service boundaries, independent scaling, isolated failures |
| Database | PostgreSQL | ACID for idempotency, WAL durability, partitioning + Citus for scale |
| Event Bus | Redis Pub/Sub | Lightweight fanout for MVP; also provides cache/queue; swappable for Kafka later |
| Threading Model | Root-anchored (flat) | O(1) pagination, simple notification recipient derivation |
| File Upload | Pre-signed URLs | Keeps bytes off app tier; scales independently |
| Auth | JWT | Stateless verification at gateway; no per-request Auth Service call |
| Pagination | Cursor-based | Stable under concurrent data changes (new messages arriving) |
| Idempotency | Database unique constraint | Safe under concurrent retries; no distributed coordination needed |
| Deployment | Single-region + AZ redundancy | Sufficient for agreed geography; achieves 99.9% without multi-region complexity |
| Real-time Delivery | WebSockets | Full-duplex, universal browser support, efficient for live features |
✅ FR-1 Workspaces/admin: workspaces, workspace_memberships tables; admin role; channel/member management endpoints
✅ FR-2 Channels: channels, channel_memberships tables; Chat Service APIs; timeline index
✅ FR-3 DMs: dm_conversations table; unique constraint prevents duplicates; same message path as channels
✅ FR-4 Messaging: messages table; idempotency constraint; cursor pagination on (created_at, message_id)
✅ FR-5 Threads: Root-anchored via thread_root_id; flat fetch via thread index; multiple threads per channel
✅ FR-6 Files: file_records table; pre-signed URL pattern; 50MB cap; 30-day expiry via lifecycle rules
✅ FR-7 Real-time delivery: Realtime Delivery Service; WebSocket subscriptions; fanout on events; fetch-on-reconnect
✅ FR-8 In-app notifications: Notification Service; notifications table; thread follower derivation; push via WebSocket
✅ FR-9 Email notifications: Background worker; DLQ; enqueued by Notification Service on inactivity
✅ FR-10 Additional UX: Explicitly out of scope
✅ NFR-1 Availability (99.9%): Stateless services + load balancer; AZ redundancy; hot standby PostgreSQL with failover
✅ NFR-2 Latency (send ≤200ms, fetch ≤300ms): Indexed lookups + single insert; post-commit event publish; compound indexes for timeline scans
✅ NFR-3 Durability (RPO ≤1 min): WAL-backed PostgreSQL; streaming replication to standby
✅ NFR-4 Security: JWT auth at gateway; server-side membership checks; rate limiting; payload caps
✅ NFR-5 Observability: Prometheus, Grafana, Sentry, structured logs
✅ NFR-6 Scalability (5K users, 1K concurrent, 300-500 msg/min): Stateless horizontal scaling; PostgreSQL has 1000x headroom over peak; pre-signed URLs for files
messages
message_id UUID PRIMARY KEY
workspace_id UUID NOT NULL REFERENCES workspaces(workspace_id)
conversation_id UUID NOT NULL
conversation_type TEXT CHECK (conversation_type IN ('channel', 'dm'))
sender_user_id UUID NOT NULL REFERENCES users(user_id)
text TEXT NOT NULL
file_id UUID REFERENCES file_records(file_id)
thread_root_id UUID REFERENCES messages(message_id)
idempotency_key UUID NOT NULL
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
UNIQUE (sender_user_id, idempotency_key)workspace_memberships
workspace_id UUID NOT NULL REFERENCES workspaces(workspace_id)
user_id UUID NOT NULL REFERENCES users(user_id)
role TEXT CHECK (role IN ('member', 'admin'))
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
PRIMARY KEY (workspace_id, user_id)dm_conversations
dm_id UUID PRIMARY KEY
workspace_id UUID NOT NULL REFERENCES workspaces(workspace_id)
user_a_id UUID NOT NULL REFERENCES users(user_id)
user_b_id UUID NOT NULL REFERENCES users(user_id)
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
CHECK (user_a_id < user_b_id)
UNIQUE (workspace_id, user_a_id, user_b_id)-- Channel timeline (partial index)
CREATE INDEX idx_messages_channel_timeline
ON messages (conversation_id, created_at DESC, message_id DESC)
WHERE conversation_type = 'channel';
-- Thread fetch (partial index, ascending for top-to-bottom read)
CREATE INDEX idx_messages_thread
ON messages (thread_root_id, created_at ASC, message_id ASC)
WHERE thread_root_id IS NOT NULL;
-- Notification inbox (partial index for unread only)
CREATE INDEX idx_notifications_inbox
ON notifications (recipient_user_id, created_at DESC)
WHERE read_at IS NULL;
-- Thread follower derivation (for Notification Service)
CREATE INDEX idx_messages_thread_root_sender
ON messages (thread_root_id, sender_user_id)
WHERE thread_root_id IS NOT NULL;Root-anchored threads (flat) vs. nested trees
✅ Single index scan for fetch; identical pagination to channels; simple notification recipient query
in_reply_to_message_id later)
Unified message table with polymorphic conversation reference
✅ Channels and DMs share schema, pagination, notification pipeline; extensible to new conversation types
Best-effort event publish (post-commit) with fetch-on-reconnect recovery
✅ Keeps write path simple and fast; missed events recoverable via fetch
Pre-signed URL file upload
✅ File bytes never touch app tier; uploads scale independently
FileRecord created before bytes confirmed uploaded
Redis Pub/Sub as event bus
✅ Single Redis for eventing, queueing, caching; lightweight; sub-millisecond delivery
Single-region deployment with AZ redundancy
✅ Achieves 99.9% target without multi-region complexity; sufficient for agreed geography
For detailed deep dives covering:
- Transaction anatomy and idempotency under concurrent retries
- Data model design, indexes, and partitioning strategy
- Real-time fanout scaling and subscription routing
- Eventing reliability and the outbox pattern
See this tutorial
Problem: Design Slack (Real-time Messaging Platform)
Asked At: OpenAI, Databricks, Meta and other FAANG+ companies
Solution Type: Complete interview-ready answer with requirements, architecture, API design, and data modeling
This system design solution demonstrates how to approach real-time messaging systems in a 45-60 minute interview. The design covers:
- Event-driven microservices architecture for scalable messaging
- WebSocket implementation for real-time delivery
- PostgreSQL data modeling with proper indexing strategies
- Redis Pub/Sub for message fanout and caching
- Idempotency patterns for reliable message delivery
- Multi-tenant architecture for enterprise SaaS
- Pre-signed URL patterns for file uploads at scale
If you're preparing for system design interviews at OpenAI, Meta, Google, or Amazon, you might also encounter:
- Design WhatsApp/Facebook Messenger - Similar real-time messaging with mobile focus
- Design Discord - Voice channels + text, gaming-optimized architecture
- Design Google Docs - Collaborative editing with operational transforms
- Design Twitter/X - Feed generation and real-time updates at massive scale
- Design Zoom - Real-time video/audio with low latency requirements
- Design Notification System - Push notifications across web/mobile/email
If you get "Design Slack" or a similar messaging system in your OpenAI, Meta, or Google system design interview:
- Start with requirements gathering - Don't jump to architecture. Clarify scale, geography, and feature scope.
- Call out the read-heavy pattern - Messaging systems have 10:1 or higher read-to-write ratios due to channel fanout.
- Address real-time delivery explicitly - Explain WebSockets vs. SSE vs. polling trade-offs.
- Show idempotency awareness - Message duplication is a common failure mode; demonstrate you know how to prevent it.
- Think about multi-tenancy - Most enterprise messaging platforms serve multiple companies; show you understand data isolation.
Common follow-up questions interviewers ask:
- "How would you handle message search?" (Full-text indexing, Elasticsearch)
- "What if a user sends 1000 messages/second?" (Rate limiting, backpressure)
- "How do you guarantee message ordering?" (Sequence numbers, vector clocks)
- "What happens if Redis goes down?" (Degraded delivery, fetch-on-reconnect)
Coditioning is your go-to platform for optimizing your chances of landing offers at Big Tech companies like OpenAI, Anthropic, Amazon, Meta, Google, Microsoft, Netflix, OpenAI, and Reddit.
We offer:
✅ Mock interviews (Human & AI) - Practice with engineers who've conducted real interviews at your target companies
✅ Personalized feedback - Get actionable insights on coding, system design, and behavioral interviews
✅ Learning resources - Complete system design solutions with step-by-step breakdowns
✅ Production engineering prep - Cover distributed systems, scalability, and infrastructure design
🎯 Book a mock system design interview - Practice with experienced FAANG+ engineers
📚 Browse complete system design solutions - Real problems from OpenAI, Meta, Google, Amazon
📺 Watch free tutorials on YouTube - System design walkthroughs and interview tips
Core Concepts: system design interview, distributed systems, microservices architecture, event-driven design, real-time messaging, websocket architecture, database design, API design, scalability patterns, high availability systems
Interview Prep: openai interview, openai system design, meta system design interview, google system design interview, amazon system design interview, system design mock interview, faang interview preparation, big tech interviews, senior engineer interview, staff engineer interview
Technical Topics: postgresql optimization, redis pub/sub, cursor pagination, idempotency patterns, multi-tenant saas, message queues, load balancing, horizontal scaling, database sharding, caching strategies, rate limiting, jwt authentication
Problem Variations: design slack, design messaging app, design chat application, design real-time collaboration tool, design team communication platform, slack architecture, slack system design, messaging system architecture
Target Companies: openai interview questions, meta interview prep, google interview preparation, amazon system design, microsoft interview, netflix system design, reddit engineering interview, faang+ system design
Questions or feedback? Drop a comment on the YouTube video or reach out via Coditioning.com
Last updated: April 2025 | Based on real OpenAI interview experience | Free resource for interview preparation
If you found this system design solution helpful:
- ⭐ Star this gist
- 🔗 Share with friends preparing for FAANG+ interviews
- 📺 Subscribe to Coditioning on YouTube for more content