Skip to content

anasFaleh/Chating-API

Repository files navigation

Chat API

A production-ready real-time chat backend built with NestJS, PostgreSQL, and Socket.io. Supports direct messaging, group chats, file uploads, message delivery tracking, and JWT authentication with refresh token rotation.

Tech Stack

Layer Technology
Framework NestJS 11 (TypeScript)
Database PostgreSQL + Prisma ORM 6
Real-time Socket.io 4 (WebSockets)
Authentication JWT + Passport.js (access + refresh tokens)
Validation class-validator + class-transformer
File Upload Multer
Rate Limiting @nestjs/throttler
Password Hashing bcryptjs (salt 12)

Features

  • Authentication — Register, login, logout, and silent token refresh with rotation
  • Direct Chats — 1-to-1 private conversations
  • Group Chats — Multi-user rooms with admin controls (add/remove members, promote roles)
  • Real-time Messaging — WebSocket gateway for instant message delivery
  • Message Lifecycle — Send, edit, and soft-delete messages
  • Message Status — SENT → DELIVERED → READ tracking per user
  • Typing Indicators — Broadcast typing start/stop events to room members
  • Online Status — Track and broadcast user presence in real time
  • File Uploads — Images and documents up to 10MB, served as static files
  • Cursor Pagination — Efficient infinite-scroll pagination for chats and messages
  • Role-Based Access — USER, MODERATOR, ADMIN roles with route guards
  • Rate Limiting — Per-endpoint throttling to prevent abuse

Project Structure

src/
├── auth/              # JWT authentication (register, login, refresh, logout)
│   ├── dto/           # Request validation DTOs
│   └── strategies/    # Passport JWT & refresh token strategies
├── users/             # User profiles, search, online status
├── chats/             # Direct & group chat management
├── messages/          # Message CRUD + file upload
├── gateway/           # Socket.io WebSocket gateway
├── common/
│   ├── guards/        # JwtAuthGuard, WsAuthGuard, RolesGuard
│   ├── decorators/    # @CurrentUser(), @Roles()
│   ├── filters/       # WebSocket exception filter
│   └── interceptors/  # Response transform interceptor
├── prisma/            # Prisma client service + module
└── uploads/           # Served static files directory

Getting Started

Prerequisites

  • Node.js 18+
  • PostgreSQL 14+
  • npm

Installation

git clone <repo-url>
cd chat-api
npm install

Environment Setup

cp .env.example .env

Edit .env:

PORT=3000
CORS_ORIGIN=http://localhost:5173

DATABASE_URL=postgresql://user:password@localhost:5432/chat_api?schema=public

JWT_ACCESS_SECRET=your-super-secret-access-key-change-in-production
JWT_ACCESS_EXPIRES_IN=15m
JWT_REFRESH_SECRET=your-super-secret-refresh-key-change-in-production
JWT_REFRESH_EXPIRES_IN=30d

Database Setup

# Run migrations
npx prisma migrate dev

# Open Prisma Studio (optional)
npx prisma studio

Running the Server

# Development (watch mode)
npm run start:dev

# Production
npm run build
npm run start:prod

The API will be available at http://localhost:3000/api/v1.

API Reference

Base URL: /api/v1

Authentication

Method Endpoint Auth Description
POST /auth/register Create a new account
POST /auth/login Login and receive tokens
POST /auth/refresh Refresh token Rotate refresh token
POST /auth/logout Bearer Invalidate refresh token

Users

Method Endpoint Auth Description
GET /users/me Bearer Get current user profile
PATCH /users/me Bearer Update username or avatar
GET /users/search?q= Bearer Search users by query
GET /users/:username Bearer Get user by username

Chats

Method Endpoint Auth Description
GET /chats Bearer List user's chats (paginated)
POST /chats/direct Bearer Start a direct chat
POST /chats/groups Bearer Create a group chat
GET /chats/:id Bearer Get chat details
PATCH /chats/:id Bearer (admin) Update group info
DELETE /chats/:id Bearer (admin) Delete group
POST /chats/:id/members Bearer (admin) Add member to group
DELETE /chats/:id/members/:userId Bearer (admin) Remove member
PATCH /chats/:id/members/:userId/role Bearer (admin) Promote/demote member
DELETE /chats/:id/leave Bearer Leave group

Messages

Method Endpoint Auth Description
GET /messages/:chatId Bearer Get messages (cursor paginated)
POST /messages Bearer Send a text message
POST /messages/upload Bearer Upload a file and send
PATCH /messages/:id Bearer Edit a message
DELETE /messages/:id Bearer Soft-delete a message
POST /messages/:chatId/read Bearer Mark messages as read

WebSocket Events

Namespace: /chat
Connection: Pass JWT as auth.token in the Socket.io handshake.

Client → Server

Event Payload Description
message:send { chatId, content, type, fileUrl?, fileName?, fileSize? } Send a message
message:edit { messageId, content } Edit a message
message:delete { messageId } Delete a message
messages:read { chatId, messageIds } Mark messages as read
typing:start { chatId } Notify room of typing
typing:stop { chatId } Stop typing notification

Server → Client

Event Payload Description
message:new Message New message received
message:edited Message Message was edited
message:deleted { messageId, chatId } Message was deleted
messages:read { chatId, userId, messageIds } Read receipt update
typing:start { chatId, userId, username } User started typing
typing:stop { chatId, userId } User stopped typing
user:online { userId } User came online
user:offline { userId, lastSeen } User went offline
chat:member_joined { chatId, member } Member added to group
chat:member_left { chatId, userId } Member left group

Data Models

User ──< ChatMember >── Chat ──< Message
 │                                  │
 └──< RefreshToken       MessageStatus >──┘
Model Key Fields
User id, email, username, passwordHash, role, avatar, isOnline, lastSeen
Chat id, type (DIRECT|GROUP), name, description, avatar
ChatMember chatId, userId, role (MEMBER|ADMIN), joinedAt
Message id, chatId, senderId, content, type (TEXT|IMAGE|FILE), isEdited, isDeleted
MessageStatus messageId, userId, status (SENT|DELIVERED|READ)
RefreshToken token, userId, expiresAt

Authentication Flow

Register / Login
      │
      ▼
Access Token (15m JWT) + Refresh Token (30d UUID, stored in DB)
      │
      ▼
401 Unauthorized  ──►  POST /auth/refresh  ──►  New token pair issued
                                │
                        Old refresh token deleted (rotation prevents reuse)
  • Access tokens are stateless JWTs validated by signature only
  • Refresh tokens are UUIDs stored in the database and deleted on use
  • Logout immediately invalidates the refresh token

Rate Limiting

Endpoint Limit
Global 100 requests / 60s
POST /auth/register 5 requests / 60s
POST /auth/login 10 requests / 60s

File Uploads

Endpoint: POST /messages/upload (multipart/form-data)

  • Max size: 10 MB
  • Allowed types: .jpg, .jpeg, .png, .gif, .webp, .pdf, .doc, .docx, .zip
  • Served at: GET /uploads/<filename>

Validation Rules

Field Rules
Email Valid email format, unique
Username 3–20 chars, alphanumeric + underscore, unique
Password 8–64 chars, requires uppercase, lowercase, and digit
Message content Max 4000 characters
Group name Max 100 characters

Running Tests

# Unit tests
npm run test

# Watch mode
npm run test:watch

# Coverage report
npm run test:cov

# End-to-end tests
npm run test:e2e

Environment Variables

Variable Required Description
PORT No HTTP server port (default: 3000)
CORS_ORIGIN Yes Allowed frontend origin
DATABASE_URL Yes PostgreSQL connection string
JWT_ACCESS_SECRET Yes Secret for signing access tokens
JWT_ACCESS_EXPIRES_IN No Access token TTL (default: 15m)
JWT_REFRESH_SECRET Yes Secret for signing refresh tokens
JWT_REFRESH_EXPIRES_IN No Refresh token TTL (default: 30d)

License

MIT

About

Real-time chat application using websockets and nest.js

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors