A production-ready RESTful e-commerce backend built with NestJS, Prisma, and PostgreSQL. Supports full e-commerce workflows with JWT authentication, role-based access control, and Swagger documentation.
- Overview
- Features
- Tech Stack
- Project Structure
- Getting Started
- API Documentation
- API Endpoints
- Authentication & Authorization
- Database Schema
- Scripts
- License
This project is a fully-featured e-commerce REST API designed for real-world use. It covers the complete shopping flow — from user registration and product browsing, to cart management, checkout, and order tracking.
Built on a modular NestJS architecture, it emphasizes security, maintainability, and developer experience, making it a solid foundation for any e-commerce product.
- Authentication — JWT access tokens (15 min) + HTTP-only refresh token cookies (7 days) with rotation and reuse detection
- Role-Based Access Control —
USERandADMINroles enforced via guards and decorators - Product Catalog — Full CRUD with category filtering, price range filtering, and full-text search
- Shopping Cart — Persistent per-user cart with add/update/remove operations
- Checkout & Orders — Atomic checkout with stock decrement; order history and cancellation
- Product Reviews — One review per user per product; filterable by rating, product, and user
- Image Uploads — Secure file uploads (JPEG, PNG, WebP, GIF; max 5 MB) with static serving
- Global Validation —
ValidationPipewith whitelist stripping and type transformation - Centralized Error Handling — Global exception filter with Prisma error code mapping
- Request Logging — Winston logger with per-request timing via an interceptor
- Rate Limiting — Global throttle (100 req/60s) + stricter limits on auth endpoints (5 req/60s)
- API Documentation — Interactive Swagger UI at
/api/docs
| Category | Technology |
|---|---|
| Framework | NestJS v11, Node.js |
| Language | TypeScript v5 |
| Database | PostgreSQL |
| ORM | Prisma v6 |
| Auth | Passport.js, JWT, bcrypt |
| Validation | class-validator, class-transformer, Joi |
| Logging | Winston, nest-winston |
| Documentation | Swagger / OpenAPI |
| File Uploads | Multer |
| Security | Helmet, CORS, express-rate-limit |
| Caching | @nestjs/cache-manager |
src/
├── auth/ # Authentication (signup, login, logout, token refresh)
│ ├── dto/
│ ├── guards/
│ └── strategies/
├── product/ # Product catalog (CRUD, search, filtering)
│ └── dto/
├── category/ # Product categories (CRUD)
│ └── dto/
├── cart/ # Shopping cart (add, update, remove items)
│ └── dto/
├── order/ # Checkout and order management
│ └── dto/
├── review/ # Product reviews and ratings
│ └── dto/
├── user/ # User profile management
│ └── dto/
├── uploads/ # Product image uploads
├── prisma/ # Prisma service and module
├── common/ # Shared utilities
│ ├── decorators/ # @Public, @Roles, @GetUser, @GetRefreshToken
│ ├── guards/ # RolesGuard
│ ├── filters/ # AllExceptionsFilter
│ └── logger/ # LoggerInterceptor, Winston config
├── config/ # App and auth configuration factories
├── app.module.ts
└── main.ts
prisma/
├── schema.prisma # Database schema
└── migrations/
uploads/
└── images/ # Stored product images (static served)
- Node.js >= 18
- PostgreSQL >= 14
- npm >= 9
# Clone the repository
git clone https://github.com/anasFaleh/Simple-E-commerce-App.git
cd Simple-E-commerce-App
# Install dependencies (also auto-generates Prisma client via postinstall)
npm installCreate a .env file in the project root:
# Database
DATABASE_URL=postgresql://username:password@localhost:5432/ecommerce_db
# JWT Secrets — use long, random strings (minimum 32 characters)
JWT_SECRET=your-super-secret-jwt-access-key-here
JWT_REFRESH_SECRET=your-super-secret-jwt-refresh-key-here
# Application
NODE_ENV=development
PORT=3000
# CORS — comma-separated list of allowed origins
ALLOWED_ORIGINS=http://localhost:4200,http://localhost:3000Security Note: Never commit your
.envfile. Use strong, unique secrets forJWT_SECRETandJWT_REFRESH_SECRETin production.
# Apply all migrations to your database
npx prisma migrate deploy
# (Optional) Open Prisma Studio to browse data
npx prisma studio# Development (watch mode)
npm run start:dev
# Production
npm run build
npm run start:prodThe API will be available at http://localhost:3000/api/v1/.
Interactive Swagger UI is available at:
http://localhost:3000/api/docs
All endpoints, request bodies, and response schemas are documented there.
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST |
/api/v1/auth/signup |
Public | Register a new user account |
POST |
/api/v1/auth/login |
Public | Login and receive tokens |
POST |
/api/v1/auth/Refresh |
Refresh Cookie | Rotate access + refresh tokens |
POST |
/api/v1/auth/Logout |
Bearer JWT | Revoke session and clear cookie |
Auth endpoints (signup/login) are throttled to 5 requests per minute.
| Method | Endpoint | Auth | Role | Description |
|---|---|---|---|---|
GET |
/api/v1/products |
Public | — | List products (filter by category, price range, pagination) |
GET |
/api/v1/products/search |
Public | — | Full-text search by name/description (?q=, ?page=, ?limit=) |
GET |
/api/v1/products/:id |
Public | — | Get a single product by ID |
POST |
/api/v1/products |
JWT | ADMIN |
Create a new product |
PUT |
/api/v1/products/:id |
JWT | ADMIN |
Update a product |
DELETE |
/api/v1/products/:id |
JWT | ADMIN |
Delete a product |
| Method | Endpoint | Auth | Role | Description |
|---|---|---|---|---|
GET |
/api/v1/categories |
Public | — | List all categories |
GET |
/api/v1/categories/:id |
Public | — | Get a single category |
POST |
/api/v1/categories |
JWT | ADMIN |
Create a category |
PATCH |
/api/v1/categories/:id |
JWT | ADMIN |
Update a category |
DELETE |
/api/v1/categories/:id |
JWT | ADMIN |
Delete a category |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/v1/carts |
JWT | Get the current user's cart with totals |
POST |
/api/v1/carts/add |
JWT | Add a product to the cart |
PUT |
/api/v1/carts/item/:itemId |
JWT | Update cart item quantity |
DELETE |
/api/v1/carts/item/:itemId |
JWT | Remove an item from the cart |
| Method | Endpoint | Auth | Role | Description |
|---|---|---|---|---|
POST |
/api/v1/orders/checkout |
JWT | — | Checkout: convert cart to order (atomic) |
GET |
/api/v1/orders |
JWT | — | List the current user's orders |
GET |
/api/v1/orders/:id |
JWT | — | Get a single order |
PATCH |
/api/v1/orders/:id/cancel |
JWT | — | Cancel a PENDING order (restores stock) |
PATCH |
/api/v1/orders/:id/status |
JWT | ADMIN |
Update order status |
Order status flow: PENDING → CONFIRMED → SHIPPED → DELIVERED
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/v1/reviews |
Public | List reviews (filter by productId, userId, rating, pagination) |
GET |
/api/v1/reviews/:id |
Public | Get a single review |
POST |
/api/v1/reviews |
JWT | Create a review (one per user per product) |
PUT |
/api/v1/reviews/:id |
JWT | Update your own review |
DELETE |
/api/v1/reviews/:id |
JWT | Delete your own review |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/v1/users/:id |
JWT | Get a user's profile |
PATCH |
/api/v1/users/:id |
JWT | Update your own profile |
DELETE |
/api/v1/users/:id |
JWT | Delete your own account |
| Method | Endpoint | Auth | Role | Description |
|---|---|---|---|---|
POST |
/api/v1/uploads/products/:productId |
JWT | ADMIN |
Upload a product image (multipart/form-data) |
GET |
/api/v1/uploads/products/:productId |
Public | — | Get a product's image URL |
DELETE |
/api/v1/uploads/products/:productId |
JWT | ADMIN |
Delete a product's image |
Uploaded images are served statically at:
http://localhost:3000/static/images/:filename
This API uses a dual-token authentication strategy:
| Token | Type | TTL | Location |
|---|---|---|---|
| Access Token | JWT | 15 minutes | Authorization: Bearer <token> |
| Refresh Token | JWT | 7 days | HTTP-only cookie (refresh_token) |
How it works:
- On login, the server returns an access token in the response body and sets a refresh token as an HTTP-only cookie.
- When the access token expires, call
POST /auth/Refresh— the server validates the refresh token cookie, checks the storedjti, and issues a new token pair. - If a refresh token is reused after it has already been rotated, the session is fully revoked (reuse detection).
- On logout, the server clears the refresh token from the database and expires the cookie.
Role-based access is enforced using the @Roles() decorator and RolesGuard. Public routes are marked with the @Public() decorator, which bypasses the global JwtGuard.
User — id, email, name, role, hash, RT (refresh token jti)
Product — id, name, description, price, stock, imageUrl, categoryId, userId
Category — id, name
Cart — id, userId (1-to-1 with User)
CartItem — id, cartId, productId, quantity
Order — id, userId, status, totalAmount
OrderItem — id, orderId, productId, quantity, unitPrice (price snapshot at checkout)
Review — id, userId, productId, rating, comment
Each user has exactly one persistent cart.
OrderItemstores a price snapshot at checkout time so historical order totals remain accurate even if product prices change later.
npm run start:dev # Start in watch mode (development)
npm run start:prod # Start compiled app (production)
npm run build # Compile TypeScript and generate Prisma client
npm run lint # Run ESLint with auto-fix
npm run format # Format code with Prettier
npm test # Run unit tests
npm run test:cov # Run tests with coverage report
npm run test:e2e # Run end-to-end testsThis project is licensed under the MIT License.