A full-stack real-time multiplayer gaming platform built with React, Node.js, Socket.IO, and MongoDB. Features JWT authentication, live matchmaking, a friends system with private chat, game challenges, leaderboards, and persistent match history.
Games available: Tic Tac Toe · Connect 4
Modes: vs AI · vs Friend (real-time multiplayer)
- Register / Login with email and password
- JWT access tokens (15 min) + refresh tokens (7 days)
- Auto token refresh via Axios interceptor
- Socket.IO connections authenticated via JWT
- Passwords hashed with bcrypt (cost factor 12)
- Tic Tac Toe — Classic 3×3 grid with minimax AI
- Connect 4 — 6×7 grid with alpha-beta pruning AI
- Both games support vs AI and vs Friend multiplayer modes
- Real-time move sync via Socket.IO
- Win detection with highlighted winning cells
- Draw detection
- Search players by username
- Send / accept / reject friend requests
- Real-time online/offline status indicators
- Remove friends
- Challenge friends to either game with a game-picker modal
- Incoming challenges appear as interactive toast notifications (Accept / Decline)
- Real-time messaging between friends via Socket.IO
- Message preview toasts when chat is not open
- Typing indicators
- Win / Loss / Draw tracked per game per user
- Win rate percentage with progress bars
- Global leaderboard filterable by game
- Full match history (opponent, moves, duration, date)
- Player profile pages
helmet.jsHTTP security headersexpress-rate-limiton all API routes (stricter on auth)express-validatorinput sanitization- CORS restricted to client origin
arcade/
├── client/ # React frontend (Vite)
│ ├── src/
│ │ ├── api/
│ │ │ └── axios.js # Axios instance with token interceptors
│ │ ├── context/
│ │ │ └── AuthContext.jsx # Global auth state + login/logout
│ │ ├── socket/
│ │ │ └── socket.js # Socket.IO client (manual connect)
│ │ ├── pages/
│ │ │ ├── AuthPage.jsx # Login + Register (tabbed)
│ │ │ ├── Dashboard.jsx # Home with stats + game cards
│ │ │ ├── ProfilePage.jsx # User profile + match history
│ │ │ └── LeaderboardPage.jsx # Global rankings per game
│ │ ├── components/
│ │ │ └── Friends.jsx # Friends panel with chat + challenges
│ │ └── games/
│ │ ├── tic-tac-toe/
│ │ │ ├── TicTacToe.jsx
│ │ │ ├── ai/minimax.js
│ │ │ └── utils/checkWinner.js
│ │ └── connect4/
│ │ ├── Connect4.jsx
│ │ ├── ai/connect4AI.js
│ │ └── utils/checkWinner.js
│ └── index.html
│
└── server/ # Node.js + Express backend
├── server.js # Entry point — middleware + routes + DB
├── .env
├── config/
│ └── db.js # MongoDB connection
├── models/
│ ├── User.js # Schema: auth, stats, friends, online status
│ └── Match.js # Schema: game results, players, duration
├── middleware/
│ └── auth.js # JWT verify middleware for REST routes
├── routes/
│ ├── auth.js # POST /register, /login, /refresh, GET /me
│ ├── users.js # GET /leaderboard, GET /:id (profile)
│ └── friends.js # Full CRUD for friends + search
├── utils/
│ ├── gameLogic.js # Pure functions: board creation, win checks
│ └── matchUtils.js # saveMatch + stat updates
└── socket/
├── index.js # initSocket() — wires all handlers
├── state.js # Shared rooms{} and socketToUser{} maps
├── authMiddleware.js # JWT verify for socket connections
└── handlers/
├── connectionHandlers.js # connect / disconnect + friend presence
├── gameHandlers.js # createRoom, joinRoom, move, endGame
└── friendHandlers.js # challenge, privateMessage, typing
- Node.js v18+
- MongoDB (local or Atlas)
- npm
git clone https://github.com/Vikram-Kumar-Sahu/ARCADE
cd arcadecd server
npm installStart MongoDB (if running locally):
# macOS
brew services start mongodb-community
# Windows (run as Administrator)
net start MongoDBStart the server:
node server.jsYou should see:
✅ MongoDB connected
🚀 Server running on port 5000
cd client
npm install
npm run devOpen http://localhost:5173 in your browser.
| Method | Endpoint | Body | Description |
|---|---|---|---|
| POST | /register |
{ username, email, password } |
Create new account |
| POST | /login |
{ email, password } |
Login, get tokens |
| POST | /refresh |
{ refreshToken } |
Get new access token |
| GET | /me |
— | Get current user |
| Method | Endpoint | Description |
|---|---|---|
| GET | /leaderboard |
Top 20 users (?game=tictactoe) |
| GET | /:id |
User profile + match history |
| Method | Endpoint | Description |
|---|---|---|
| GET | /list |
Get accepted friends list |
| GET | /requests |
Get incoming friend requests |
| GET | /search/:query |
Search users by username |
| POST | /request/:userId |
Send friend request |
| POST | /accept/:userId |
Accept friend request |
| POST | /reject/:userId |
Reject friend request |
| DELETE | /remove/:friendId |
Remove friend |
| Event | Payload | Description |
|---|---|---|
createRoom |
{ gameType } |
Create a multiplayer room |
joinRoom |
roomId |
Join an existing room |
move |
{ roomId, row, col } |
Make a game move |
challengeFriend |
{ friendId, gameType } |
Send game challenge |
acceptChallenge |
{ roomId, gameType } |
Accept incoming challenge |
privateMessage |
{ toUserId, message } |
Send private message |
typing |
{ toUserId, isTyping } |
Send typing indicator |
| Event | Payload | Description |
|---|---|---|
roomCreated |
{ roomId, symbol } |
Room created confirmation |
startGame |
{ board, players, turn, names } |
Game is starting |
update |
{ board, turn, names } |
Board state after a move |
gameOver |
{ winner, winnerName, board } |
Game ended |
playerLeft |
— | Opponent disconnected |
gameChallenge |
{ from, gameType, roomId } |
Incoming game challenge |
friendOnline |
{ userId, username } |
Friend came online |
friendOffline |
{ userId } |
Friend went offline |
privateMessage |
{ from, message, timestamp } |
Incoming message |
{
username: String, // unique, 2–20 chars
email: String, // unique, lowercase
password: String, // bcrypt hashed
stats: {
tictactoe: { wins, losses, draws },
connect4: { wins, losses, draws },
},
friends: [{
userId: ObjectId,
status: "pending" | "accepted" | "blocked",
}],
friendRequests: [{
from: ObjectId,
status: "pending" | "accepted" | "rejected",
}],
online: Boolean,
lastSeen: Date,
createdAt: Date,
}{
gameType: "tictactoe" | "connect4",
playerX: ObjectId, // ref: User
playerO: ObjectId, // ref: User (null = AI)
winner: "X" | "O" | "Draw",
winnerId: ObjectId, // null = Draw or AI won
moves: Number,
durationSeconds: Number,
playedAt: Date,
}| Layer | Technology |
|---|---|
| Frontend | React 18, Vite, Tailwind CSS, React Router v6 |
| UI/Icons | Lucide React, React Toastify |
| Real-time | Socket.IO (client + server) |
| HTTP Client | Axios (with interceptors) |
| Backend | Node.js, Express.js |
| Database | MongoDB, Mongoose |
| Auth | JWT (access + refresh tokens), bcryptjs |
| Security | Helmet, express-rate-limit, express-validator |
| AI | Minimax with alpha-beta pruning (Connect 4) |
- JWT secrets must be changed before deploying to production
- Set
CLIENT_URLto your actual frontend domain in production - MongoDB URI should use a dedicated database user with least-privilege access
- Consider using MongoDB Atlas for managed hosting
- Spectator mode for live games
- Tournament brackets
- Game replay system
- Push notifications (Web Push API)
- More games (Chess, Checkers)
- Mobile app (React Native)
Vikram Kumar Sahu
GitHub · LinkedIn