A real-time one-to-one chat application built with React (frontend), Express + Node.js (backend), MongoDB (database), and Ably (for real-time messaging). Users can sign up, log in, chat with others in real time, mark messages as seen, and view shared media.
- User authentication (signup / login) using JWT
- Real-time messaging between users via Ably
- Mark messages as "seen"
- View conversation list / recent chats
- Fetch and display unseen message counts
- Upload images in chat (via Cloudinary)
- Search users
- Profile update
- Shared media retrieval
https://chat-app-frontend-tenzins-projects-246f77e7.vercel.app/
| Layer | Technology |
|---|---|
| Frontend | React, Vite, Tailwind CSS, Axios |
| Backend | Node.js, Express |
| Real-time | Ably Realtime (for message events) |
| Database | MongoDB |
| File Storage | Cloudinary (for image uploads) |
| Authentication | JWT + Protected Routes |
| Vercel | A cloud platform for deploying web apps |
| and APIs. |
/client # frontend React app
├─ src
├─ pages/
├─ components/
├─ context/
└─ ...
/server # backend Express app
├─ controllers/
├─ routes/
├─ middleware/
├─ lib/ # e.g., database connection, cloudinary setup
├─ models/
└─ app.js / index.js
.env (server only)
README.md
- Node.js (>= 14 or 16)
- MongoDB (local or a cloud instance)
- An Ably account with API key
- Cloudinary account (for image uploads)
-
Clone the repo and navigate to backend folder:
cd server -
Install dependencies:
npm install
-
Create
.envfile with environment variables: -
Server env variables
PORT=5000
MONGO_URI=your_mongo_connection_string
JWT_SECRET=your_jwt_secret
ABLY_API_KEY=your_ably_root_key
CLOUDINARY_CLOUD_NAME=...
CLOUDINARY_API_KEY=...
CLOUDINARY_API_SECRET=...-
Client env variables VITE_BACKEND_URL=http://localhost:5000
-
Start the backend:
npm run dev
-
Verify backend is running by visiting:
http://localhost:5000/api/status
-
Open another terminal, go to client folder:
cd client -
Install dependencies:
npm install
-
Create a
.envfile (React / Vite) with frontend environment variables:VITE_BACKEND_URL=http://localhost:5000
-
Start the frontend:
npm run dev
-
Open browser at
http://localhost:5173(or whichever port Vite uses)
-
The frontend initializes an Ably
Realtimeclient with:new Realtime({ authUrl: `${VITE_BACKEND_URL}/api/ably/auth?userId=${authUser._id}` });
-
The backend provides a route at
/api/ably/authwhich uses Ably’s server SDK to generate a token request:const ably = new Ably.Rest({ key: process.env.ABLY_API_KEY }); const tokenRequest = await ably.auth.createTokenRequest({ clientId: userId }); res.json(tokenRequest);
-
Once authenticated, clients subscribe to channels (e.g.
user:{userId}) to receive events likenewMessageormessagesSeen. -
To send a message, you publish to the appropriate Ably channel and also persist it in MongoDB.
| Method | Path | Description |
|---|---|---|
POST /api/auth/signup |
Sign up a new user | |
POST /api/auth/login |
Log in and receive JWT | |
PUT /api/auth/update-profile |
Update user profile (protected) | |
GET /api/auth/check-auth |
Return current user if JWT valid | |
GET /api/auth/all-users |
List all users (protected) | |
GET /api/auth/searchUser/:search |
Search users by text (protected) |
| Method | Path | Description |
|---|---|---|
GET /api/messages/recent-chats/:id |
Get list of recent chats (protected) | |
GET /api/messages/unseen-count |
Get unseen message counts per user (protected) | |
GET /api/messages/all-messages/:id |
Get message history with user id (protected) |
|
PUT /api/messages/mark-seen/:id |
Mark messages from user id as seen |
|
POST /api/messages/send-message/:id |
Send message (text + optional image) to user id |
|
GET /api/ably/auth?userId=... |
Get Ably token request |
- The backend is deployed as serverless functions (no
app.listen()in production). - Ensure environment variables are set in Vercel for
ABLY_API_KEY,MONGO_URI,JWT_SECRET,CLOUDINARY_*. - The React frontend is deployed via Vercel as well, pointing to backend routes.
- Confirm
/api/statusworks after deployment to check the function is live.
-
Create a vercel.json at the Server folder of your repo:
{"version": 2, "builds": [ { "src": "server.js", "use": "@vercel/node", "config": { "includeFiles": [ "dist/**" ] } } ], "rewrites": [ { "source": "/(.)", "destination": "/server.js" } ], "headers": [ { "source": "/api/(.)", "headers": [ { "key": "Access-Control-Allow-Origin", "value": "https://app.example" }, { "key": "Access-Control-Allow-Methods", "value": "GET, POST, OPTIONS" }, { "key": "Access-Control-Allow-Headers", "value": "Content-Type, Authorization" }, { "key": "Access-Control-Allow-Credentials", "value": "true" } ] } ] }
-
Create a vercel.json at the Client folder of your repo: { "rewrites":[ { "source":"/(.*)", "destination":"/" } ] }
- 500 / INTERNAL_SERVER_ERROR on
/api/status→ check logs, ensure.envis loaded and noapp.listen()in production. - Ably Error “No key specified” (40101) → ensure
process.env.ABLY_API_KEYis valid and loaded properly before creatingAbly.Rest. - 404 on
/api/ably/auth→ check routing:app.use("/api/ably", ablyRouter), and inablyRouterroute should berouter.get("/auth"). - CORS / network issues → make sure backend allows your frontend origin.
- Add error handling and validation on endpoints
- Support group chats / rooms
- Support file attachments beyond images (videos, docs)
- Add read receipts and typing indicators
- Better UI/UX, notifications
- Unit tests / integration tests
- Logging and monitoring