A full-stack real-time messaging platform built with a microservices architecture. Users can send friend requests, chat one-on-one or in groups, and receive messages instantly via WebSockets. Messages are persisted asynchronously through a Redis-backed queue for high throughput and scalability.
┌───────────┐ ┌──────────────┐ ┌──────────────┐
│ Frontend │◄─────►│ HTTP Server │◄─────►│ PostgreSQL │
│ (React) │ │ (Express) │ │ │
└─────┬──────┘ └──────────────┘ └──────▲───────┘
│ │
│ WebSocket │
│ │
┌─────▼──────┐ ┌──────────────┐ ┌──────┴───────┐
│ WS Server │◄─────►│ Redis │◄─────►│ DB Service │
│ (ws) │ │ (Pub/Sub + │ │ (Queue Worker)│
└────────────┘ │ Queue) │ └──────────────┘
└──────────────┘
How it works:
- The HTTP Server handles authentication, friend requests, chat CRUD, and serves the REST API.
- The WebSocket Server manages real-time connections. When a user sends a message, it publishes to Redis Pub/Sub for instant delivery to all participants and pushes the message onto a Redis queue.
- The DB Service (queue consumer) picks messages off the Redis queue and persists them to PostgreSQL, decoupling real-time delivery from database writes.
- Redis Pub/Sub enables horizontal scaling — multiple WS server instances can share messages across connections.
| Layer | Technology |
|---|---|
| Frontend | React, TypeScript, Vite, Tailwind CSS, Radix UI, React Query, React Router |
| HTTP Server | Node.js, Express, TypeScript, JWT, bcrypt |
| WebSocket Server | Node.js, ws library, Redis Pub/Sub |
| Database | PostgreSQL 15, Prisma ORM |
| Message Queue | Redis (List-based queue + Pub/Sub) |
| Queue Consumer | Node.js worker service |
| Monorepo | Turborepo, pnpm workspaces |
| Containerization | Docker, Docker Compose, Kubernetes |
- Real-Time Messaging — Instant message delivery via WebSocket connections with Redis Pub/Sub
- Friend System — Send, accept, or reject friend requests; private chats auto-created on acceptance
- Private & Group Chats — One-on-one conversations and group chats with role-based permissions (Owner, Admin, Member)
- Group Invites — Invite friends to groups with 48-hour expiring invitations
- Typing Indicators — See when someone is typing in real-time
- Async Message Persistence — Messages are queued in Redis and batch-written to the database by a separate worker, keeping the WS server fast
- Cursor-Based Pagination — Efficient infinite-scroll message history
- User Profiles — Customizable profiles with bio, avatar, social links, interests, and location
- JWT Authentication — Stateless auth shared across HTTP and WebSocket services
- Responsive UI — Clean interface built with Tailwind CSS and Radix UI primitives
socket-talk/
├── apps/
│ ├── frontend/ # React + Vite SPA
│ ├── http-server/ # Express REST API
│ ├── ws-server/ # WebSocket server
│ └── db-service/ # Redis queue consumer worker
├── packages/
│ ├── prisma/ # Shared Prisma schema & client
│ ├── ui/ # Shared UI component library
│ ├── eslint-config/ # Shared ESLint config
│ └── typescript-config/ # Shared TypeScript config
├── k8s/ # Kubernetes manifests
├── docker-compose.yml
└── turbo.json
User ─────┬──── Profile (1:1)
├──── Friend (many-to-many, bidirectional)
├──── FriendRequest (sender/receiver)
├──── ChatParticipant ──── Chat
├──── Message
└──── GroupInvite
Chat ─────┬──── ChatParticipant (with roles: OWNER, ADMIN, MEMBER, GUEST)
├──── Message
└──── GroupInvite (48hr expiry)
- Node.js >= 18
- pnpm 9+
- PostgreSQL 15
- Redis
git clone https://github.com/<your-username>/socket-talk.git
cd socket-talk
pnpm installCopy the example env files and configure them:
# Database connection
cp packages/prisma/.env.example packages/prisma/.env
# HTTP server
cp apps/http-server/.env.example apps/http-server/.env
# WebSocket server
cp apps/ws-server/.env.example apps/ws-server/.env
# DB service (queue consumer)
cp apps/db-service/.env.example apps/db-service/.env
# Frontend
cp apps/frontend/.env.example apps/frontend/.envEnvironment variables:
| Service | Variable | Default |
|---|---|---|
| Prisma | DATABASE_URL |
postgresql://postgres:password@localhost:5432/postgres |
| HTTP Server | PORT |
3000 |
| HTTP Server | JWT_SECRET |
secret |
| WS Server | JWT_SECRET |
secret |
| DB Service | REDIS_URL |
redis://localhost:6379 |
| Frontend | VITE_BACKEND_URL |
http://localhost:3000/api/v1 |
| Frontend | VITE_WS_URL |
ws://localhost:3001 |
cd packages/prisma
npx prisma migrate dev# From the root directory
pnpm devThis starts the HTTP server (:3000), WebSocket server (:3001), DB service worker, and frontend (:5173) concurrently via Turborepo.
docker compose up --buildThis spins up PostgreSQL, Redis, all backend services, and the frontend in containers with health checks and persistent volumes.
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/v1/auth/register |
Register a new user |
POST |
/api/v1/auth/login |
Login and receive JWT |
GET |
/api/v1/users/profile |
Get current user profile |
PUT |
/api/v1/users/profile |
Update profile |
GET |
/api/v1/users/search/:username |
Search users by username |
GET |
/api/v1/friends |
Get friend list |
POST |
/api/v1/friends/requests/send/:userId |
Send friend request |
GET |
/api/v1/friends/requests |
Get sent & received requests |
PUT |
/api/v1/friends/requests/:requestId |
Accept or reject request |
POST |
/api/v1/chats |
Create a chat (private or group) |
GET |
/api/v1/chats |
Get user's chats |
GET |
/api/v1/chats/:chatId/messages |
Get messages (cursor paginated) |
POST |
/api/v1/chats/:chatId/invites |
Send group invite |
GET |
/api/v1/invites |
Get pending group invites |
PUT |
/api/v1/invites/:inviteId |
Accept or reject group invite |
| Event | Direction | Description |
|---|---|---|
join_chat |
Client → Server | Join a chat room |
send_message |
Client → Server | Send a message to a chat |
typing_start |
Client → Server | Notify others you're typing |
leave_chat |
Client → Server | Leave a chat room |
receive_message |
Server → Client | Receive a new message |
typing |
Server → Client | Someone is typing indicator |
User sends message
│
▼
WS Server receives it
│
├──► Redis Pub/Sub ──► All connected clients in the chat receive it instantly
│
└──► Redis Queue (db_update_message)
│
▼
DB Service (worker)
│
▼
PostgreSQL (message persisted + chat.lastMessageAt updated)
The k8s/ directory contains manifests for deploying to a Kubernetes cluster:
- PostgreSQL & Redis with persistent volume claims
- HTTP Server (2 replicas) and Frontend (2 replicas) for high availability
- DB Service (1 replica) as a queue consumer
- Traefik Ingress routing
/to frontend,/apito HTTP server,/socketto WS server - Secrets management via Kubernetes Secrets