A WebSocket-driven chat backend using Socket.IO, Express, TypeScript, MongoDB, and Redis.
Designed to handle real-time direct messaging with persistent storage, rate limiting, content moderation, and cached message history.
- Features
- Architecture
- Tech Stack
- Project Structure
- Getting Started
- Socket Events
- REST API Endpoints
- Database Schema
- Usage Examples
- Rate Limiting & Moderation
- Real-time Messaging: Instant bidirectional communication using Socket.IO
- Direct Messaging (DM): Private one-on-one chat rooms
- Message Persistence: All messages stored in MongoDB for chat history
- Online Presence: Track and broadcast online users
- Rate Limiting: Prevent spam with automatic message throttling (3 messages/minute)
- Content Moderation: Automatic filtering of inappropriate content
- Message History API: Retrieve past messages via REST endpoint
- Redis-backed Caching: Reduce repeated MongoDB reads for chat history queries
- Typing Indicators: Real-time visual feedback when a user is composing a message
- Read Receipts: Track and update the delivery and read status of messages
- TypeScript: Full type safety across client, server, and shared types
- CLI Client: Command-line interface for testing and demonstration
βββββββββββββββββββ
β Client A ββββ
β (Socket.IO) β β
βββββββββββββββββββ β
ββββΊ ββββββββββββββββββββ βββββββββββββββ
βββββββββββββββββββ β β Backend Server ββββββββ MongoDB β
β Client B ββββ€ β (Express + β β (Messages) β
β (Socket.IO) β β β Socket.IO) β βββββββββββββββ
βββββββββββββββββββ β ββββββββββββββββββββ
β
βββββββββββββββββββ β
β Client C ββββ
β (Socket.IO) β
βββββββββββββββββββ
Client A
ββ emit("dm-message", text)
β
βΌ
Backend
ββ Validate & Rate Limit
ββ Save to MongoDB
ββ io.to(room).emit("dm-message", message)
β
βΌ
Client A + Client B
ββ on("dm-message") β Display message
- Node.js with TypeScript
- Express - HTTP server and REST API
- Socket.IO - WebSocket communication
- Redis - query caching
- MongoDB with Mongoose(ORM) - Message persistence
- dotenv - Environment configuration
- CORS - Cross-origin resource sharing
- Socket.IO Client - WebSocket client library
- TypeScript - Type-safe client code
- Node.js readline - CLI interface
- TypeScript - Shared type definitions between client and server
.
βββ README.md
βββ client
βΒ Β βββ cli.ts
βΒ Β βββ package-lock.json
βΒ Β βββ package.json
βΒ Β βββ test.ts
βΒ Β βββ tsconfig.json
βΒ Β βββ utils
βββ packages
βΒ Β βββ package-lock.json
βΒ Β βββ shared
βΒ Β βββ dist
βΒ Β βΒ Β βββ index.d.ts
βΒ Β βΒ Β βββ types
βΒ Β βΒ Β βββ historyMessage.d.ts
βΒ Β βΒ Β βββ socket.d.ts
βΒ Β βββ package.json
βΒ Β βββ src
βΒ Β βΒ Β βββ index.ts
βΒ Β βΒ Β βββ types
βΒ Β βΒ Β βββ historyMessage.ts
βΒ Β βΒ Β βββ socket.ts
βΒ Β βββ tsconfig.json
βββ server
βββ package-lock.json
βββ package.json
βββ src
βΒ Β βββ config
βΒ Β βΒ Β βββ dbConnection.ts
βΒ Β βββ controller
βΒ Β βΒ Β βββ msgHistory.controller.ts
βΒ Β βββ index.ts
βΒ Β βββ model
βΒ Β βΒ Β βββ chat.ts
βΒ Β βββ routes
βΒ Β βΒ Β βββ messageHistory.route.ts
βΒ Β βββ service
βΒ Β βΒ Β βββ messageHistory.service.ts
βΒ Β βββ sockets
βΒ Β βΒ Β βββ deliveryMsg.ts
βΒ Β βΒ Β βββ disconnect.ts
βΒ Β βΒ Β βββ dmMessages.ts
βΒ Β βΒ Β βββ index.ts
βΒ Β βΒ Β βββ presence.state.ts
βΒ Β βΒ Β βββ readMsg.ts
βΒ Β βΒ Β βββ setUsername.ts
βΒ Β βΒ Β βββ startDm.ts
βΒ Β βΒ Β βββ typeIndicator.ts
βΒ Β βββ tsconfig.json
βΒ Β βββ utils
βΒ Β βββ roomId.ts
βΒ Β βββ time.ts
βββ test
βββ client-test-1.ts
βββ client-test-2.ts
βββ client-test-3.ts
βββ client-test-4.ts
- Node.js (v16 or higher)
- MongoDB (local or MongoDB Atlas)
- npm or yarn
-
Clone the repository
git clone https://github.com/Amitrajit007/Chat-Backend.git cd Chat-backend -
Install server dependencies
cd server npm install -
Install client dependencies
cd ../client npm install -
Install shared package dependencies
cd ../packages/shared npm install npm run build # Compile TypeScript types
Create a .env file in the server/ directory:
PORT=5000
Atlas_URI=mongodb://localhost:27017/chat-app
# Or use MongoDB Atlas:
# Atlas_URI=mongodb+srv://username:password@cluster.mongodb.net/chat-app-
Start the server
cd server npm run devServer will run on
http://localhost:5000 -
Start client instances (in separate terminals)
# Terminal 1 - User "alice" chatting with "bob" cd client npx ts-node cli.ts alice bob # Terminal 2 - User "bob" chatting with "alice" npx ts-node cli.ts bob alice
| Event | Payload | Description |
|---|---|---|
set-username |
string |
Set the username for the connected socket |
start-dm |
string |
Start a DM session with target user |
dm-message |
string |
Send a message in the current DM room |
| Event | Payload | Description |
|---|---|---|
online-users |
string[] |
Broadcast list of currently online users |
dm-message |
ChatMessage |
Receive a message in the DM room |
dm-error |
string | ChatMessage |
Error notification (rate limit, moderation, etc.) |
type ChatMessage = {
roomId: string; // Sorted usernames (e.g., "alice,bob")
id: string; // Message ID
from: string; // Sender username
text: string; // Message content
to: string; // Recipient username
time: string; // Formatted timestamp
}Retrieve past messages between two users.
Endpoint: GET /lastmessages
Query Parameters:
from(string, required) - First usernameto(string, required) - Second usernamelimit(number, optional) - Number of messages to retrieve (default: 10 and max: 25)
Example Request:
curl "http://localhost:5000/lastmessages?from=alex&to=john&limit=3"Example Response:
[
{
"_id": "45ec5a84-4d0f-4dc4-ae88-f8fe03fe7941",
"roomId": "alex,john",
"id": "45ec5a84-4d0f-4dc4-ae88-f8fe03fe7941",
"from": "alex",
"text": "i love peace",
"to": "john",
"time": "4/1/2026, 10:07:27 pm",
"__v": 0
},
{
"_id": "2cac0dd7-ff7e-4541-94bc-9d2a6659bb16",
"roomId": "alex,john",
"id": "2cac0dd7-ff7e-4541-94bc-9d2a6659bb16",
"from": "john",
"text": "Hello alex",
"to": "alex",
"time": "5/1/2026, 1:09:34 am",
"__v": 0
},
{
"_id": "70a45670-9f03-4e1c-b29f-651964ed53d6",
"roomId": "alex,john",
"id": "70a45670-9f03-4e1c-b29f-651964ed53d6",
"from": "alex",
"text": "hii",
"to": "john",
"time": "5/1/2026, 1:09:54 am",
"__v": 0
}
]Endpoint: GET /health
Response: OK
Endpoint: GET /
Response:
{
"msg": "Active @ 5000"
}{
roomId: String, // Sorted usernames (e.g., "alice,bob")
id: String, // Message ID
from: String, // Sender username
text: String, // Message content
to: String, // Recipient username
time: String, // Formatted timestamp
}Indexes:
{ roomId: 1, createdAt: -1 }- Optimized for message history queries
Server Console:
Listening at 5000
MongoDB connected successfully
Online : [ 'alex' ]
alex is connected in romm : dm:alexjohn
Online : [ 'alex', 'john' ]
john is connected in romm : dm:alexjohn
Client disconnect with id: LkSQBjXklUABPJPaAAAD
Online : [ 'alex' ]
Client disconnect with id: S1JIjaZJXQerzz4PAAAJ
No one is OnlineJohn's Console:
Chatting with alex
Type messages and press Enter...
online: [ 'alex', 'You' ]
online: [ 'You' ]
online: [ 'You', 'alex' ]
alex : hii John 5/1/2026, 3:26:01 am
alex : How are you ? 5/1/2026, 3:26:12 am
> Im fine, thanks
You : Im fine, thanks 5/1/2026, 3:26:38 am
[READ] b9a30bdc-aadc-46b5-ab46-60cb500a8889
[DELIVERED] b9a30bdc-aadc-46b5-ab46-60cb500a8889
alex : Cool π 5/1/2026, 3:27:01 am
Caught Ctrl+C
Closing connection...
DisconnectedAlex's Console:
Chatting with john
Type messages and press Enter...
online: [ 'john', 'You' ]
> hii John
You : hii John 5/1/2026, 3:26:01 am
[DELIVERED] b2a328e8-0034-4635-a3ee-c79db5016afd
[READ] b2a328e8-0034-4635-a3ee-c79db5016afd
> How are you ?
You : How are you ? 5/1/2026, 3:26:12 am
[DELIVERED] 5d54095b-2864-4e5c-837f-533900a64912
[READ] 5d54095b-2864-4e5c-837f-533900a64912J
John : Im fine, thanks 5/1/2026, 3:26:38 am
> Cool π
You : Cool π 5/1/2026, 3:27:01 am
[DELIVERED] e587c3a8-2041-46e3-8676-b37df243faf8
[READ] e587c3a8-2041-46e3-8676-b37df243faf8
online: [ 'You' ]
Caught Ctrl+C
Closing connection...
DisconnectedRun Client 1 Test:
npm run client-test-1Run Client 2 Test:
npm run client-test-2- Limit: 5 messages per minute per user
- Penalty: 5-second mute on exceeding limit
- Error Message:
"Too many messages. Muted for 5s."
Messages containing the following keywords are automatically rejected:
"war""gun"These are just examples, you can add more keywords to theserver\src\sockets\dmMessages.tsfile.
Rejected Message Response:
Error: Message is not accepted
Rate limiting is implemented per socket connection:
socket.data.rate = {
count: 0, // Messages sent in current window
lastReset: Date.now(), // Window start time
mutedUntil: 0 // Timestamp when mute expires
}- socket.id is a temporary identifier assigned per connection, used for debugging and logging
- Room IDs are generated by sorting usernames alphabetically to ensure consistency (e.g.,
"alice,bob"regardless of who initiates) - Timestamps are formatted in local time:
"DD/MM/YYYY, HH:MM:SS am/pm" - All messages are persisted to MongoDB for chat history