Real-time chat built for developers. Share code with syntax highlighting, stream AI explanations in-line, collaborate faster — without alt-tabbing to ChatGPT.
- 💬 Real-time messaging via WebSockets (Socket.io) — with optimistic send and an automatic reconnect banner
- 🖥️ Syntax-highlighted code with Shiki (the same engine that powers VS Code's docs), 20+ languages
- ✨ AI explanations — click "Explain" on any code block, get a streamed GPT-4o-mini response (you bring your own OpenAI key, encrypted at rest)
- ⚡ AI cache — explanations are saved to the message, so the second time is instant (and free)
- 🏢 Workspaces & Channels — create teams, organize conversations by topic
- 🟢 Presence indicators — see who's online in real-time
- ⌠ Typing indicators — "Alice is typing..."
- 🔗 Invite codes — share a code to invite teammates
- 🔒 Google OAuth + email/password
- 🚀 Try-the-demo mode — no signup, full workspace pre-seeded with code samples and cached AI explanations
- 📱 Mobile-friendly — sidebar becomes a slide-out drawer on small screens
- 🛡️ React error boundary — a single component crash never blanks the whole UI
- 🌙 Dark-mode first — built for developers who live in the terminal
| Layer | Technology |
|---|---|
| Frontend | Next.js 15 (App Router) + React 19 |
| Styling | Tailwind CSS 4 + custom design tokens |
| Code highlighting | Shiki (lazy-loaded, client-side) |
| Real-time | Socket.io 4.x |
| Backend | Node.js + Express 4 |
| Database | MongoDB 8.x + Mongoose |
| Auth | JWT (email/password) + Google OAuth |
| AI | OpenAI GPT-4o-mini, streaming via SSE |
| Security | Helmet, Zod input validation, AES-256-GCM at-rest encryption for user OpenAI keys, per-route authorization, rate limiting |
- Node.js 18+
- MongoDB (local install or Atlas free tier)
git clone https://github.com/shihabcodes/DevChat.git
cd DevChat
# Server
cd server && npm install
# Client (new terminal)
cd ../client && npm install# Server
cp server/.env.example server/.env
# Edit server/.env — set MONGODB_URI and a real JWT_SECRET (>= 32 chars)
# Client
cp client/.env.example client/.env.local
# Edit client/.env.local — leave NEXT_PUBLIC_API_URL pointing at the local backend# Terminal 1 — backend
cd server && npm run dev
# → http://localhost:5001
# Terminal 2 — frontend
cd client && npm run dev
# → http://localhost:3000Visit http://localhost:3000 → click 🚀 Try the demo to land in a fully seeded workspace in 2 seconds.
With the server running on :5001, run an end-to-end smoke test (no test framework needed):
cd server && node smoke.jsYou should see 22 passing checks covering health, validation, disposable email block, auth flows, demo seed, AI explain cache hit + 412, IDOR protection, and OpenAI key CRUD.
DevChat/
├── client/ # Next.js frontend (App Router)
│ └── src/
│ ├── app/ # Pages: / and /workspace/[id]
│ ├── components/ # UI: Sidebar, ChatArea, MessageBubble, CodeBlock, AISettings
│ └── lib/ # api client, socket client, Shiki highlighter
├── server/ # Express backend
│ └── src/
│ ├── config/ # env, db, logger
│ ├── models/ # Mongoose schemas: User, Workspace, Channel, Message
│ ├── routes/ # REST API: auth, workspaces, channels, messages, ai, keys, demo
│ ├── socket/ # Socket.io handlers with membership checks
│ ├── middleware/ # auth, authorization, validation, rate limiting
│ └── utils/ # AES-256-GCM crypto helper
├── DEPLOYMENT.md # Production deploy walkthrough
└── README.md
All routes (except /api/auth/*, /api/demo, /api/health) require a JWT in the Authorization: Bearer <token> header.
| Method | Path | Purpose |
|---|---|---|
POST |
/api/auth/register |
Email + password signup |
POST |
/api/auth/login |
Email + password login |
POST |
/api/auth/google |
Google OAuth ID token sign-in |
GET |
/api/auth/me |
Current user + workspaces + hasOpenaiKey |
POST |
/api/demo |
Create an ephemeral demo workspace (auto-expires) |
GET /POST |
/api/workspaces |
List / create workspaces |
GET |
/api/workspaces/:id |
Get a workspace (membership-checked) |
POST |
/api/workspaces/join |
Join via invite code |
GET /POST /PATCH /DELETE |
/api/channels[/...] |
Channel CRUD, membership-checked |
GET |
/api/messages/channel/:id |
List messages (membership-checked) |
POST |
/api/ai/explain |
Streamed AI explanation (SSE) |
GET POST DELETE |
/api/keys |
Manage user's OpenAI key |
POST |
/api/keys/test |
Verify the stored key against OpenAI |
GET |
/api/health |
Health + Mongo status |
DevChat is built with the assumption that a hostile user is poking at every endpoint. Highlights:
- Helmet security headers (Helmet's default CSP in prod)
- CORS allowlist from
ALLOWED_ORIGINSenv - Request body size capped at 64 KB
- Zod input validation on every route + socket payload
- JWT_SECRET runtime check: server refuses to boot in production with a placeholder secret
- Per-route authorization middleware — no IDOR, no implicit cross-tenant access
- Per-route + global rate limiting (express-rate-limit)
- Disposable email blocklist on signup
- OpenAI keys encrypted at rest with AES-256-GCM (random IV per write, auth tag verified on read)
- Socket.io membership checks on
joinChannelandsendMessage - Graceful shutdown on SIGTERM (drain sockets, close server, disconnect Mongo)
- Structured logging with request IDs (Pino-style in prod, single-line in dev)
POST /api/ai/explain returns Server-Sent Events. Each delta event carries one chunk of the streamed response. The final done event carries the full explanation, which the server also persists to Message.aiExplanation so the same request is free the second time.
const stream = api.explainCodeStream({ messageId, code, language, onDelta });
const { text } = await stream.result;Developers context-switch to ChatGPT to ask about code shared in chat. DevChat embeds the AI in the chat so the switch goes away. The bet is that the chat is where the code is, so the AI should be there too.
MIT — see LICENSE.