mhd.io — Real-Time Chat Application
A full-stack real-time chat app built with Node.js / Express / Socket.io / Prisma / PostgreSQL on the backend and React Native (Expo) on the frontend.
mhd.io/
├── backend/ # Node.js API + Socket.io server
│ ├── prisma/
│ │ └── schema.prisma # User & Message models
│ ├── src/
│ │ ├── auth.js # JWT auth helpers + middleware
│ │ └── validation.js # Zod schemas + Express validate() middleware
│ ├── server.js # Express app + Socket.io server
│ ├── .env.example
│ └── package.json
└── frontend/ # React Native (Expo) app
├── src/
│ ├── api/
│ │ └── client.js # Axios instance with auth interceptor
│ ├── context/
│ │ └── SocketContext.js # Socket.io provider + useSocket hook
│ └── screens/
│ ├── LoginScreen.js
│ ├── ChatListScreen.js # User list with online indicators
│ └── ChatScreen.js # Message history + real-time chat
├── App.js # Root navigator + session bootstrap
├── app.json
└── package.json
Node.js >= 18
PostgreSQL database running locally (or a connection string)
3 — Configure environment
cp .env.example .env
# Edit .env and fill in DATABASE_URL and JWT_SECRET
4 — Run migrations & generate Prisma client
npx prisma migrate dev --name init
npm run dev # development (nodemon)
npm start # production
The server starts on http://localhost:4000 by default.
2 — Configure environment
cp .env.example .env
# Set EXPO_PUBLIC_API_URL to your backend URL
3 — Start the Expo dev server
Method
Path
Auth
Description
POST
/api/auth/register
—
Register a new user
POST
/api/auth/login
—
Login; returns JWT
GET
/api/users
yes
List all other users
GET
/api/messages/:userId
yes
Fetch message history with a user
Client -> Server
Payload
Description
send_message
{ receiverId, content }
Send a message
Server -> Client
Payload
Description
new_message
Message object
A message was received
user_status
{ userId, isOnline }
A user's online status changed
JWT authentication — register/login with bcrypt-hashed passwords
Real-time messaging — Socket.io delivers messages instantly to the recipient
Message history — cursor-based paginated REST endpoint
Online/offline presence — DB flag + broadcast on connect/disconnect
Input validation — Zod schemas on all auth and message inputs
Rate limiting — 10 login attempts / 15 min; 5 registrations / hour per IP
React Native UI — sent/received bubble styles, keyboard-avoiding, FlatList pagination