A scalable Node.js application built with Domain-Driven Design (DDD) principles using Express, MySQL, Redis, and BullMQ for asynchronous job processing.
- Overview
- Technology Stack
- Project Structure
- Getting Started
- Development
- Docker Deployment
- Database Migrations
- API Documentation
- Architecture
- Troubleshooting
This project demonstrates enterprise-grade Node.js development using Domain-Driven Design, featuring:
β
Modular Architecture - Independent, testable business domains
β
DDD Patterns - Aggregate Roots, Value Objects, Domain Events
β
Async Processing - BullMQ for background jobs (email, reports, etc.)
β
Security - Helmet, CORS, Rate Limiting, JWT
β
Logging - Winston with daily rotation
β
Database - MySQL with Knex migrations
β
Docker Ready - Containerized for production
| Layer | Technology |
|---|---|
| Runtime | Node.js |
| Framework | Express 5.x |
| Database | MySQL 8 + Knex (Query Builder + Migrations) |
| ORM/Query | Knex.js |
| Cache/Queue | Redis + BullMQ |
| Nodemailer | |
| Security | Helmet, CORS, Rate Limiting, bcrypt, JWT |
| Logging | Winston |
| Testing | Jest + Supertest |
| HTTP Templates | Handlebars (for email templates) |
| Validation | Zod |
ddd/
βββ src/
β βββ config/ # Configuration files
β β βββ database.js # Database connection setup
β β
β βββ modules/ # Business Domains (Bounded Contexts)
β β βββ order/ # Order Management Domain
β β β βββ domain/ # Business rules (Order entity, events)
β β β βββ application/ # Use cases (CreateOrderService)
β β β βββ infrastructure/ # Data access (repositories, DB queries)
β β β βββ interface/ # API endpoints (HTTP routes, DTOs)
β β β βββ workers/ # Background jobs (email, notifications)
β β β
β β βββ catalog/ # Product Catalog Domain
β β β βββ domain/ # Catalog aggregate, value objects
β β β βββ application/ # Queries and use-cases (GetCatalogList, CreateCatalog)
β β β βββ infrastructure/ # Persistence adapters (MySQLCatalogRepository)
β β β βββ interface/ # HTTP routes, DTOs, controllers
β β β βββ mapper/ # Mapping between domain and DTOs
β β β
β β βββ partner/ # Partner/Vendor Domain
β β βββ domain/
β β βββ application/
β β βββ infrastructure/
β β βββ interface/
β β
β βββ shared/ # Shared utilities & infrastructure
β βββ core/ # Base classes & error handling
β β βββ AggregateRoot.js
β β βββ AppError.js
β β βββ Guard.js
β β βββ ValueObject.js
β β
β βββ infra/ # Shared infrastructure
β β βββ database/ # MySQL connection (Singleton)
β β βββ email/ # Email service + templates
β β βββ http/ # Middleware, error handler
β β βββ logging/ # Winston logger
β β βββ queue/ # BullMQ queue factory
β β
β βββ utils/ # Helper functions
β βββ DateUtils.js
β βββ ObjectUtils.js
β βββ PaginationUtils.js
β βββ TextUtils.js
β
βββ migrations/ # Database migration files (Knex)
βββ docker-compose.yml # Multi-container setup (App, MySQL, Redis)
βββ Dockerfile # Container image definition
βββ Makefile # Development commands
βββ knexfile.js # Knex configuration
βββ server.js # Application entry point
βββ package.json # Dependencies
- Node.js 16+ (or higher)
- npm or yarn
- MySQL 8+ (or Docker)
- Redis (or Docker)
-
Clone the repository
git clone <repository> cd ddd
-
Install dependencies
npm install # or use Makefile make install -
Create environment file
cp .env.example .env
-
Configure
.envfileNODE_ENV=development PORT=3000 # Database DB_HOST=localhost DB_USER=root DB_PASSWORD=password DB_NAME=ddd_db DB_PORT=3306 # Redis REDIS_HOST=localhost REDIS_PORT=6379 # Email SMTP_HOST=smtp.gmail.com SMTP_PORT=587 SMTP_USER=your-email@gmail.com SMTP_PASS=your-app-password # JWT JWT_SECRET=your-secret-key JWT_EXPIRY=7d
-
Run database migrations
npm run migrate:latest # or make migrate-up -
Start the server
npm run dev # or make devServer will run on
http://localhost:3000
| Command | Purpose |
|---|---|
make dev |
Run server in watch mode (Nodemon) |
make start |
Run server in production mode |
make test |
Run test suite (Jest) |
make module name=payment |
Generate new DDD module scaffold |
make migrate-make name=create_users |
Create new database migration |
make migrate-up |
Run pending migrations |
make migrate-down |
Rollback last migration |
make help |
Show all available commands |
The project uses module-alias for clean imports:
// Instead of: require('../../../shared/core')
// You write:
const { AggregateRoot, Guard } = require("@shared/core");
const orderModule = require("@modules/order");Alias mapping (in package.json):
{
"_moduleAliases": {
"@shared": "src/shared",
"@modules": "src/modules",
"@config": "src/config"
}
}# Build and start all services (App, MySQL, Redis)
make docker-up
# Stop services
make docker-down
# Rebuild and restart
make docker-update
# Scale app to 3 instances
make docker-scale n=3docker-compose.yml includes:
- app - Node.js application (Port 3000)
- mysql - MySQL database (Port 3306)
- redis - Redis cache (Port 6379)
All database changes go through migrations for version control and reproducibility.
make migrate-make name=create_orders_tableThis creates a file in migrations/ like:
exports.up = function (knex) {
return knex.schema.createTable("orders", (table) => {
table.uuid("id").primary();
table.uuid("customer_id").notNullable();
table.decimal("total", 10, 2);
table.enum("status", ["PENDING", "PAID", "CANCELLED"]);
table.timestamps(true, true);
});
};
exports.down = function (knex) {
return knex.schema.dropTableIfExists("orders");
};# Run all pending migrations
make migrate-up
# Rollback last batch
make migrate-down
# Rollback all migrations
make migrate-rollback
# Check status
make db-statusDetailed API endpoints are documented in API_DOCUMENTATION.md.
curl http://localhost:3000/healthResponse:
{
"status": "OK",
"uptime": 123.456,
"db": "Connected"
}# Create order
POST /api/orders
Content-Type: application/json
{
"customerId": "uuid-here",
"items": [
{ "productId": "prod-1", "quantity": 2, "price": 50.00 }
],
"email": "customer@example.com"
}This project follows Domain-Driven Design (DDD) principles. See ARCHITECTURE.md for detailed explanation of:
- Bounded Contexts - Isolated business domains
- Aggregates - Consistency boundaries
- Domain Events - Domain-driven communication
- Repository Pattern - Data access abstraction
- Service Layer - Business logic orchestration
- Value Objects - Immutable concepts
- DTOs - Data transfer objects
β
Helmet - HTTP security headers
β
CORS - Cross-origin resource sharing control
β
Rate Limiting - Anti-DDoS protection (100 req/15min per IP)
β
bcrypt - Password hashing
β
JWT - Token-based authentication
β
Input Validation - Zod schema validation
β
Error Handling - No stack traces exposed to clients
Winston logger configured with:
- Console output (development)
- File rotation (daily logs in
logs/directory) - Request tracking (HTTP method, URL, duration)
- Error logging (stack traces in files, messages to client)
# Run tests
make test
# Watch mode
make test-watchUses Jest + Supertest for unit and integration tests.
Solution: Ensure module-alias/register is loaded first in server.js
Solution: Check DB_HOST, DB_USER, DB_PASSWORD in .env
# Test MySQL connection
mysql -h localhost -u root -pSolution: Start Redis service
# macOS
brew services start redis
# Linux
sudo systemctl start redis-server
# Docker
docker-compose up -d redisSolution: Ensure Redis is running and BullMQ workers are initialized in server.js
- README.md - Project overview & setup (you are here)
- ARCHITECTURE.md - DDD patterns & design decisions
- API_DOCUMENTATION.md - API endpoints & examples
- CODE_DOCUMENTATION.md - JSDoc code comments
- Create a new branch:
git checkout -b feature/my-feature - Follow DDD structure when adding features
- Write tests for business logic
- Submit a pull request
ISC License
For issues or questions, please check:
- Troubleshooting section
- ARCHITECTURE.md for design patterns
- API_DOCUMENTATION.md for API usage
Last Updated: December 28, 2025
Version: 1.0.0