A sleek, responsive, and real-time chat application featuring channel isolation, secure cookie-based and message-based WebSocket authentication, custom channel membership, invitations, and creator moderation (kick controls).
The architecture consists of a Node.js Express & PostgreSQL server combined with a React + Tailwind CSS v4 frontend powered by the Vite build tool.
- Robust Authentication: Cookie-based JWT authentication for REST API endpoints and explicit token validation payload for WebSocket handshakes.
- WebSocket Channel Router: Central in-memory message routing system that dynamically binds active client connections to DB-backed room entities.
- Glass orphic UI: High-fidelity dark mode designed using Tailwind CSS v4, featuring Outfit and Inter typography, micro-interactions, and message entry animations.
- Channel Membership: Channels are restricted to their creator and invited members. Non-members are prompted with an interactive Join Channel screen.
- Creator Moderation: Channel creators are designated with a Crown badge and have administrative controls to kick other members.
Quick-chat/
├── server/ # Express REST API & WebSocket Server
│ ├── src/
│ │ ├── controller/ # Auth and Room controllers
│ │ ├── middleware/ # Cookie JWT verification
│ │ ├── utils/ # Prisma client, Swagger, and WebSocket Router
│ │ └── index.ts # App bootstrapper
│ ├── prisma/ # Schema definitions and migrations
│ └── package.json
│
└── client/ # React + Tailwind CSS v4 SPA
├── src/
│ ├── components/ # UI Components (AuthCard, Sidebar, ChatRoom)
│ ├── types.ts # TypeScript models
│ ├── App.tsx # Central layout and state orchestra
│ └── index.css # Tailwind v4 import & custom styles
├── vite.config.ts # Vite configuration & dev proxy
└── package.json
Make sure you have Node.js installed on your machine.
-
Open a terminal and navigate to the
server/directory:cd server -
Install backend dependencies:
npm install
-
Configure your local environment file. Rename or create a
.envfile in theserver/folder and supply your values:PORT=3000 DATABASE_URL="postgresql://username:password@localhost:5432/bobbuilder?schema=public" JWT_SECRET="YOUR_SUPER_SECRET_KEY"
-
Push the Prisma schema to configure your database and generate the Prisma Client:
npx prisma db push
-
Start the backend developer server:
npm run dev
The backend server will list on
http://localhost:3000with WebSockets ready atws://localhost:3000.
-
Open a new terminal and navigate to the
client/directory:cd client -
Install client dependencies:
npm install
-
Launch the Vite developer server:
npm run dev
Open your browser to the local address outputted in the terminal (usually
http://localhost:5173).
The backend includes a Swagger UI interface detailing the REST APIs. Once the server is running, you can explore details at:
http://localhost:3000/api-docs
| Method | Endpoint | Description | Payload |
|---|---|---|---|
POST |
/api/register |
Register new user. Returns Cookie + JWT token | { username, password } |
POST |
/api/login |
Log in existing user. Returns Cookie + JWT token | { username, password } |
POST |
/api/logout |
Clears local session cookie | (None) |
GET |
/api/rooms |
Fetch all channels | (None - Needs cookie) |
POST |
/api/rooms |
Create new channel | { roomName } |
GET |
/api/rooms/:roomname/members |
Get all members of a channel | (None) |
POST |
/api/rooms/:roomname/invite |
Invite/add username to channel members | { username } |
DELETE |
/api/rooms/:roomname/kick |
Kick/remove member from channel (Owner only) | { username } |
WebSocket connections require explicit authentication. After connecting, the server will request authentication. Message payloads follow a { type, payload } format.
-
Client Auth Payload:
{ "type": "auth", "payload": { "token": "<JWT_TOKEN>" } }Server responds with
auth-successorauth-error. -
Join Room Payload:
{ "type": "join-room", "payload": { "roomId": "<ROOM_UUID>" } }Server responds with
room-joinedandroom-history(containing the last 50 messages). -
Send Message Payload:
{ "type": "send-message", "payload": { "content": "Hello world!" } }Server broadcasts the newly saved message to all active clients in the channel under the type
new-message.