A scalable backend system for a food ordering platform built with NestJS, PostgreSQL, and Docker.
- User Management: Registration and login with email/phone
- Authentication: JWT-based authentication with refresh tokens
- Passwordless Login: OTP-based login via email or phone (5-minute expiration)
- Product Catalog: Food products with variants (sizes, types)
- Shopping Cart: Add, update, remove items with variant support
- Order Management: Place orders with payment type and status tracking
- API Documentation: Swagger/OpenAPI documentation
- Docker Support: Complete Docker Compose setup for all services
- Framework: NestJS 11
- Database: PostgreSQL 16
- ORM: TypeORM
- Authentication: JWT, bcrypt
- Validation: class-validator, class-transformer
- Documentation: Swagger/OpenAPI
- Containerization: Docker & Docker Compose
- Optional: Redis (caching), Kafka (message queue)
src/
├── auth/ # Authentication module (JWT, OTP)
├── users/ # User management
├── products/ # Product catalog with variants
├── cart/ # Shopping cart operations
├── orders/ # Order management
├── entities/ # TypeORM entities
├── dto/ # Data Transfer Objects
├── config/ # Configuration files
├── utils/ # Utility functions
└── main.ts # Application entry point
- Node.js 20+
- Docker & Docker Compose
- npm or yarn
- Clone the repository:
git clone <repository-url>
cd simplex-task- Copy environment file:
cp env.example .env-
Update
.envwith your configuration (optional, defaults work for local development) -
Start all services:
docker compose up -dThis will start:
- PostgreSQL database (port 5432)
- Redis (port 6379)
- Kafka with KRaft (port 9092)
- NestJS API (port 3000)
- Access the API:
- API: http://localhost:3000/api
- Swagger Documentation: http://localhost:3000/api/docs
POST /api/auth/register- Register a new userPOST /api/auth/login- Login with email/phone + passwordPOST /api/auth/otp/request- Request OTP for passwordless loginPOST /api/auth/otp/verify- Verify OTP and loginPOST /api/auth/refresh- Refresh access tokenGET /api/auth/profile- Get current user profile (protected)
GET /api/products- Get all active productsGET /api/products/:id- Get product by IDPOST /api/products- Create product (protected, admin)
GET /api/cart- Get user cart (protected)POST /api/cart/items- Add item to cart (protected)PUT /api/cart/items/:itemId- Update cart item quantity (protected)DELETE /api/cart/items/:itemId- Remove item from cart (protected)DELETE /api/cart/clear- Clear entire cart (protected)
POST /api/orders- Place order from cart (protected)GET /api/orders- Get all user orders (protected)GET /api/orders/:id- Get order by ID (protected)GET /api/orders/order-id/:orderId- Get order by order ID (protected)PUT /api/orders/:id/status- Update order status (protected)
Swagger documentation is available at /api/docs when the application is running.
See env.example for all available environment variables:
NODE_ENV- Environment (development/production)PORT- API port (default: 3000)DB_HOST,DB_PORT,DB_USERNAME,DB_PASSWORD,DB_NAME- Database configurationJWT_SECRET,JWT_EXPIRES_IN- JWT configurationJWT_REFRESH_SECRET,JWT_REFRESH_EXPIRES_IN- Refresh token configurationREDIS_HOST,REDIS_PORT- Redis configuration (optional)KAFKA_BROKER,KAFKA_PORT- Kafka configuration (optional)
The system is designed to handle high concurrency with the following architecture:
- Indexes: Strategic indexes on frequently queried columns:
orders.userId,orders.status,orders.createdAtotps.identifier,otps.expiresAt
- Connection Pooling: TypeORM connection pooling for efficient database connections
- Read Replicas: PostgreSQL read replicas for read-heavy operations
- Partitioning: Order table can be partitioned by date for better performance
- Kafka Integration: Order processing uses Kafka for asynchronous processing
- Order placement publishes to
order-createdtopic - Background workers consume and process orders
- Email notifications, inventory updates handled asynchronously
- Order placement publishes to
- Event-Driven Design: Decoupled services communicate via events
- Node.js Clustering: API can run multiple worker processes
- Docker Swarm/Kubernetes: Container orchestration for auto-scaling
- Load Balancing: Nginx/HAProxy for request distribution
- Stateless API: JWT tokens enable stateless authentication across instances
- Redis Caching:
- Product catalog caching
- User session caching
- Cart data caching (optional)
- Cache Invalidation: Smart cache invalidation on data updates
- Order Processing: Separate worker services and bull processors with kafka as event broker for:
- Order validation
- Payment processing
- Email notifications
- SMS notifications
- Inventory management
- Queue Management: RabbitMQ/Kafka for job queues
- Sharding: Orders can be sharded by userId or date
- Archiving: Old orders archived to separate tables/database
- Connection Pooling: Optimized pool sizes per instance
- Pagination: All list endpoints support pagination
- Response Compression: Gzip compression for API responses
- Rate Limiting: Protect against abuse
- Request Validation: Early validation to reject invalid requests
-
Message Queue Setup:
// Example: Order service publishes to Kafka await kafkaProducer.send({ topic: 'order-created', messages: [{ value: JSON.stringify(orderData) }], });
-
Worker Service:
- Separate NestJS microservice for order processing
- Consumes from Kafka topics
- Handles long-running tasks
-
Redis Caching:
// Cache product catalog await redis.set(`product:${id}`, JSON.stringify(product), 'EX', 3600);
-
Database Read Replicas:
- Configure TypeORM to use read replicas for queries
- Master database for writes
-
Load Testing:
- Use tools like Apache JMeter or artillery
- Test with realistic load patterns
- Monitor database and API performance
- Application Monitoring: Prometheus + Grafana
- Logging: Centralized logging (ELK stack)
- APM: Application Performance Monitoring
- Health Checks:
/healthendpoint for monitoring - Metrics: Track order processing time, error rates, throughput
Currently only basic test case exist
# Unit tests
npm run test
# E2E tests
npm run test:e2e
# Test coverage
npm run test:cov- Set
NODE_ENV=productionin.env - Update database configuration for production
- Use strong JWT secrets (min 32 characters)
- Enable database migrations and add migrations (disable
synchronize) - Set up proper logging and monitoring
- Configure reverse proxy (Nginx)
- Set up SSL/TLS certificates
- Configure backup strategy for database