Skip to content

Latest commit

Β 

History

23 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ’¬ MERN Real-Time Messenger

A production-grade, real-time chat platform built with the MERN stack

MongoDB Express React Node.js Socket.io TypeScript


⚑ Real-time messaging Β β€’Β  πŸ‘₯ Group chats Β β€’Β  🀬 Profanity filter Β β€’Β  πŸ”’ JWT auth Β β€’Β  ☁️ Image uploads Β β€’Β  πŸŒ— Dark/Light mode


πŸ“‹ Table of Contents


✨ Features

πŸ’¬ Core Messaging

  • ⚑ Real-time Messaging β€” Instant message syncing and room broadcasting via Socket.io
  • πŸ‘₯ Group Chats β€” Create and manage group conversations beyond 1-to-1
  • 🟒 Online Presence β€” Live user status tracking across the platform
  • πŸ“Ž Media Sharing β€” Cloudinary-powered image uploads in the chat stream
  • ↩️ Reply Threads β€” Reply to specific messages for contextual conversations

πŸ›‘οΈ Security & Performance

  • πŸ”’ JWT Authentication β€” HTTP-Only cookies with SameSite policies
  • 🀬 Abuse Masker β€” Trie-based profanity filter masks offensive words server-side
  • πŸ›‘οΈ Type-Safe Validation β€” Zod schemas on both client and server
  • πŸš€ Static Splash β€” Zero API calls on landing page for peak SEO & speed
  • πŸ“¦ Zustand State β€” Lightweight, predictable global state management

🎨 UI & Experience

  • Modern responsive UI styled with Tailwind CSS
  • Dedicated Dark / Light mode toggles with glassmorphism tokens
  • Production-ready split-domain deployment (Vercel + Render)

πŸ› οΈ Tech Stack

Frontend β€” /client

Technology Purpose
React UI library
Vite Build tooling
TypeScript Type safety
Tailwind Styling
Zustand State management
Socket.io Real-time client
Axios HTTP client

Backend β€” /backend

Technology Purpose
Node.js Runtime
Express HTTP framework
TypeScript Type safety
MongoDB Database
Socket.io WebSocket engine
Passport JWT authentication
Cloudinary Media storage

πŸ— Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        CLIENT (React + Vite)                    β”‚
β”‚                                                                 β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚   β”‚  Pages   β”‚  β”‚Componentsβ”‚  β”‚  Hooks   β”‚  β”‚ Zustand Storeβ”‚   β”‚
β”‚   β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚        β”‚              β”‚             β”‚               β”‚           β”‚
β”‚        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β”‚
β”‚                    β”‚ Axios (REST)        β”‚ Socket.io-client      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚                    β”‚
                     β–Ό                    β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    SERVER (Node.js + Express)                   β”‚
β”‚                                                                β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚   β”‚  Routes  β”‚β†’ β”‚Controllersβ”‚β†’ β”‚ Services  β”‚β†’ β”‚   Models   β”‚   β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                     β”‚               β”‚          β”‚
β”‚                              β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”        β”‚          β”‚
β”‚                              β”‚AbuseMasker  β”‚        β”‚          β”‚
β”‚                              β”‚(Trie Filter)β”‚        β”‚          β”‚
β”‚                              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β”‚          β”‚
β”‚                                                     β”‚          β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                  β”‚          β”‚
β”‚   β”‚  Socket.io   β”‚  β”‚ Passport   β”‚                  β”‚          β”‚
β”‚   β”‚  (WebSocket) β”‚  β”‚ (JWT Auth) β”‚                  β”‚          β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                  β”‚          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                          β”‚
                                          β–Ό
                                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                β”‚     MongoDB      β”‚
                                β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
                                β”‚  β”‚   Users     β”‚  β”‚
                                β”‚  β”‚   Chats     β”‚  β”‚
                                β”‚  β”‚  Messages   β”‚  β”‚
                                β”‚  β”‚ AbuseWords  β”‚  β”‚
                                β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
                                β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸš€ Getting Started

Prerequisites

Requirement Version
Node.js >= 18.x
MongoDB Atlas cluster or local instance
Cloudinary account Free tier works

1️⃣ Clone the Repository

git clone https://github.com/your-username/MERN-RealTime-Messagers-Platform.git
cd MERN-RealTime-Messagers-Platform

2️⃣ Backend Setup

cd backend
npm install

Create a .env file in the backend/ directory:

PORT=8000
NODE_ENV=development
MONGO_URI=your_mongodb_connection_string
JWT_SECRET=your_super_secret_key
JWT_EXPIRES_IN=1d
FRONTEND_ORIGIN=http://localhost:5173

# Cloudinary (required for image uploads)
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret

Seed the abuse word list (one-time):

npx ts-node src/script/seedAbuseWords.ts

Start the backend:

npm run dev

You should see: Abuse masker loaded 72 words into Trie followed by Server running on port 8000

3️⃣ Frontend Setup

cd client
npm install

Create a .env.local file in client/ (optional β€” defaults to http://localhost:8000/api):

VITE_API_URL=http://localhost:8000/api

Start the frontend:

npm run dev

4️⃣ Open the App

Navigate to http://localhost:5173 β€” you're live! πŸŽ‰


🀬 Abuse Word Masker

A server-side profanity filter that automatically detects and masks abusive language in chat messages before they are stored or broadcast. Zero client-side changes required.

How It Works

User types: "you are a chutiya"
                    β”‚
                    β–Ό
        POST /api/chat/message/send
                    β”‚
                    β–Ό
          sendMessageService()
                    β”‚
                    β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚  abuseMasker.mask(content)    β”‚
    β”‚                               β”‚
    β”‚  Trie lookup per word:        β”‚
    β”‚   "you"     β†’ βœ— (pass)       β”‚
    β”‚   "are"     β†’ βœ— (pass)       β”‚
    β”‚   "a"       β†’ βœ— (pass)       β”‚
    β”‚   "chutiya" β†’ βœ“ (MATCH!)     β”‚
    β”‚                               β”‚
    β”‚  Output: "you are a *******"  β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    β”‚
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
          β–Ό                   β–Ό
   Save to MongoDB    WebSocket broadcast
   (masked content)   (masked content)

Why a Trie?

Approach Time Complexity 1000 words Γ— 50-word message
Brute-force list scan O(n Γ— m) 50,000 comparisons
Regex alternation O(n Γ— m) Regex backtracking overhead
Trie lookup βœ… O(m) per word 50 lookups (word-length only)

The Trie provides constant-time lookups regardless of how many abuse words are in the dictionary.

Architecture

Component File Purpose
🌳 Trie + Masker backend/src/lib/abuseMasker.ts Singleton β€” builds Trie from DB, provides mask(text)
πŸ“„ MongoDB Model backend/src/models/abuseWord.model.ts Stores words with unique lowercase index
🌱 Seed Script backend/src/script/seedAbuseWords.ts Pre-populates ~72 English + Hindi profanity words
πŸ”Œ Admin API backend/src/routes/abuseWord.route.ts REST endpoints to view/add words at runtime
πŸ”— Integration backend/src/services/message.service.ts Hooks masker into the message pipeline

Design Decisions

Decision Rationale
Trie data structure O(m) per-word lookup β€” scales to any dictionary size
Word-boundary splitting \b regex split prevents "class" being flagged by "ass"
Server-side only Masked before DB write β€” all clients always see clean text
Case-insensitive "FUCK", "Fuck", "fuck" are all caught identically
Hot-reload Admin API reloads Trie instantly β€” no server restart needed
Asterisk matching Replacement length matches original word (shit β†’ ****)

Seeding the Word List

cd backend
npx ts-node src/script/seedAbuseWords.ts
βœ“ Database connected for seeding
βœ“ Successfully seeded 72 abuse words
βœ“ Total abuse words in database: 72
βœ“ Database disconnected

Includes English profanity, slurs, and common Hindi/Indian abuse words. Duplicates are automatically skipped on re-runs.


πŸ“‘ API Reference

Authentication

Method Endpoint Description
POST /api/auth/register Register a new user
POST /api/auth/login Log in and receive JWT cookie
POST /api/auth/logout Clear auth cookie

Chat

Method Endpoint Description
POST /api/chat/create Create a new chat (1-to-1 or group)
GET /api/chat/all Get all chats for the authenticated user
GET /api/chat/:id Get a single chat with message history
POST /api/chat/message/send Send a message (auto-masked for profanity)

Abuse Words (Admin)

Method Endpoint Body Description
GET /api/abuse-words β€” List all abuse words
POST /api/abuse-words/add { "words": ["word1", "word2"] } Add words & hot-reload Trie

πŸ”’ All endpoints (except register/login) require JWT authentication via HTTP-Only cookie.

WebSocket Events

Event Direction Payload Description
online:users Server β†’ Client string[] Broadcast online user IDs
chat:join Client β†’ Server chatId Join a chat room
chat:leave Client β†’ Server chatId Leave a chat room
chat:new Server β†’ Client Chat New chat created
chat:update Server β†’ Client { chatId, lastMessage } Chat updated with new message
message:new Server β†’ Client Message New message in chat room

πŸš€ Deployment

This repository is configured for split-domain deployment β€” separating the frontend (static) from the backend (WebSocket-capable).

Backend β†’ Render.com

A render.yaml Blueprint is included at the project root.

  1. Import the repository into Render as a New Blueprint
  2. Render auto-detects the backend service
  3. Set environment variables in the Dashboard
    • Set FRONTEND_ORIGIN to your Vercel URL (no trailing /)

Frontend β†’ Vercel

  1. Import the repository into Vercel
  2. Set Root Directory to client
  3. Set VITE_API_URL to your Render backend URL (e.g., https://your-backend.onrender.com/api)
  4. Deploy πŸš€

A vercel.json rewrite config is included in /client so SPA routes like /chat never 404.


πŸ“ Project Structure

MERN-RealTime-Messagers-Platform/
β”œβ”€β”€ backend/
β”‚   └── src/
β”‚       β”œβ”€β”€ config/            # Database, env, cloudinary, passport configs
β”‚       β”œβ”€β”€ controllers/       # Route handlers (auth, chat, message, abuseWord)
β”‚       β”œβ”€β”€ lib/
β”‚       β”‚   β”œβ”€β”€ socket.ts      # Socket.io server initialization & events
β”‚       β”‚   └── abuseMasker.ts # 🌳 Trie-based profanity filter (singleton)
β”‚       β”œβ”€β”€ middlewares/       # Auth, error handling, async wrapper
β”‚       β”œβ”€β”€ models/            # Mongoose schemas (User, Chat, Message, AbuseWord)
β”‚       β”œβ”€β”€ routes/            # Express route definitions
β”‚       β”œβ”€β”€ script/
β”‚       β”‚   └── seedAbuseWords.ts  # 🌱 Database seeder for abuse words
β”‚       β”œβ”€β”€ services/          # Business logic layer
β”‚       β”œβ”€β”€ utils/             # Helpers (bcrypt, cookies, env)
β”‚       β”œβ”€β”€ validators/        # Zod request schemas
β”‚       └── index.ts           # Server entry point
β”œβ”€β”€ client/
β”‚   └── src/
β”‚       β”œβ”€β”€ components/        # Reusable UI components
β”‚       β”œβ”€β”€ hooks/             # Custom React hooks (auth, chat, socket)
β”‚       β”œβ”€β”€ layouts/           # Page layout wrappers
β”‚       β”œβ”€β”€ lib/               # Axios client, helpers, utils
β”‚       β”œβ”€β”€ pages/             # Route-level page components
β”‚       β”œβ”€β”€ routes/            # React Router configuration
β”‚       β”œβ”€β”€ types/             # TypeScript type definitions
β”‚       └── App.tsx            # Root component
β”œβ”€β”€ render.yaml                # Render deployment blueprint
└── vercel.json                # Vercel deployment config

🀝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Built with ❀️ using the MERN Stack

⭐ Star this repo if you found it useful!

About

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages