Full-stack chat application built for the PLP MERN Stack Week 5 lab. The project combines an Express + MongoDB API with a Vite + React client, Clerk authentication, and Socket.IO for real-time messaging.
- Clerk-backed authentication and profile sync
- REST API for conversations, messages, and user directory data
- Socket.IO rooms that broadcast conversation updates in real time
- Tailwind-driven chat UI with conversation list, message viewport, and composer
- Environment-driven configuration for local dev and deployment
.
├── backend # Express + MongoDB API
└── frontend # Vite + React client
- Node.js 18+ and npm
- MongoDB instance (local or hosted)
- Clerk application with JWT template configured (or integration fallback)
Create backend/.env with the following keys:
| Variable | Description | Example |
|---|---|---|
PORT |
API port (defaults to 5000) | 5000 |
MONGODB_URI |
MongoDB connection string | mongodb://127.0.0.1:27017/meridian-chat |
CLERK_SECRET_KEY |
Clerk secret key for server-side verification | sk_test_... |
CLERK_PUBLISHABLE_KEY |
Clerk publishable key (used to seed profile data) | pk_test_... |
CLERK_JWT_TEMPLATE |
(Optional) custom JWT template name | integration_fallback |
ALLOWED_ORIGINS |
Comma-separated list of allowed front-end origins | http://localhost:5173 |
ALLOWED_ORIGINSis applied to both Express CORS and Socket.IO. If unset, the server allowshttp://localhost:5173andhttp://127.0.0.1:5173.
Create frontend/.env with:
| Variable | Description | Example |
|---|---|---|
VITE_CLERK_PUBLISHABLE_KEY |
Clerk publishable key | pk_test_... |
VITE_CLERK_JWT_TEMPLATE |
(Optional) template request name | integration_fallback |
VITE_API_URL |
Backend base URL | http://localhost:5000 |
VITE_SOCKET_URL |
Socket.IO server URL (defaults to VITE_API_URL) |
http://localhost:5000 |
# install backend dependencies
cd backend
npm install
# install frontend dependencies
cd ../frontend
npm install# terminal 1 - backend API + socket server
cd backend
npm run dev
# terminal 2 - frontend (Vite dev server)
cd frontend
npm run devThe API listens on http://localhost:5000 (unless you override PORT). The Vite dev server runs on http://localhost:5173 by default.
Backend (backend):
npm run dev– start API with Nodemonnpm start– start API without reload
Frontend (frontend):
npm run dev– Vite development servernpm run build– production bundlenpm run preview– preview production buildnpm run lint– run ESLint
All endpoints require a valid Clerk JWT (Bearer token).
GET /api/users– list user directory profilesPOST /api/users/sync– upsert the authenticated user's profileGET /api/conversations– list conversations that include the current userPOST /api/conversations– ensure a one-to-one conversation existsGET /api/conversations/:conversationId– fetch conversation detailGET /api/messages/:conversationId– fetch message historyPOST /api/messages– send a message to a conversation
Health endpoints:
GET /– simple readiness stringGET /healthz– health check payload
Clients authenticate the WebSocket connection with the same Clerk JWT (sent via auth.token).
conversation:join– join a conversation roomconversation:leave– leave a conversation roommessage:new– emit a new message; echoed to conversation membersconversation:update– emitted when unread counts change
Conversation– members, last message metadata, unread counts (Map keyed by Clerk ID)Message– conversation reference, sender info, text, read receipts, statusUserProfile– cached Clerk profile fields for faster display
backend/src/models contains the full schema definitions.
- API guards and Socket.IO middleware verify JWTs via
@clerk/backend. - Set
CLERK_JWT_TEMPLATE/VITE_CLERK_JWT_TEMPLATEif you use a custom template; otherwise the integration fallback is used. - Ensure the template includes the
sub,sid,email, and image claims for profile sync.
- CORS/Socket errors – confirm
ALLOWED_ORIGINS,VITE_API_URL, andVITE_SOCKET_URLpoint to the same host/port. - 401 Unauthorized – verify Clerk keys and JWT template, and ensure the frontend retrieves tokens with
getToken. - MongoDB connection failure – check
MONGODB_URIand that MongoDB is reachable.
- Serve the backend behind HTTPS so Clerk JWTs are transmitted securely.
- Set production
ALLOWED_ORIGINSandVITE_*URLs to the deployed front-end domain. - Provision an Atlas or managed MongoDB instance for production workloads.
Repository: https://github.com/PLP-MERN-Stack-Development/Week5-Chat