This project follows a modular architecture pattern with clean separation of concerns, implementing industry best practices for maintainability, scalability, and testability.
erDiagram
User ||--o{ Order : "assigned"
User ||--o{ Shipment : "assigned"
Vendor ||--o{ Order : "places"
Fare ||--o{ Order : "priced_by"
Warehouse ||--o{ Shipment : "handles"
Order ||--o{ Shipment : "generates"
User {
string id PK
string email
string password
string name
enum role "ADMIN|MANAGER|USER"
datetime createdAt
datetime updatedAt
}
Vendor {
string id PK
string name
string email
string phone
string address
string city
string state
string country
string postalCode
boolean isActive
datetime createdAt
datetime updatedAt
}
Warehouse {
string id PK
string name
string address
string city
string state
string country
string postalCode
int capacity
boolean isActive
datetime createdAt
datetime updatedAt
}
Fare {
string id PK
string fromCity
string toCity
float branchDelivery
float codBranch
float doorDelivery
boolean isActive
datetime createdAt
datetime updatedAt
}
Order {
string id PK
string orderNumber UNIQUE
string vendorId FK
string userId FK "nullable"
enum status "PENDING|CONFIRMED|PROCESSING|SHIPPED|DELIVERED|CANCELLED|RETURNED"
string deliveryCity
string deliveryAddress
string contactNumber
string name
string alternateContactNumber "nullable"
float amountToBeCollected "nullable"
enum deliveryType "BRANCH_DELIVERY|COD_BRANCH|DOOR_DELIVERY"
string fareId FK
float productWeight
string productType
float totalAmount
string notes "nullable"
datetime createdAt
datetime updatedAt
}
Shipment {
string id PK
string trackingNumber UNIQUE
string orderId FK
string warehouseId FK
string userId FK "nullable"
enum status "PREPARING|PICKED_UP|IN_TRANSIT|OUT_FOR_DELIVERY|DELIVERED|FAILED_DELIVERY|RETURNED"
string carrier "nullable"
string trackingUrl "nullable"
datetime estimatedDelivery "nullable"
datetime actualDelivery "nullable"
float weight "nullable"
json dimensions "nullable"
string notes "nullable"
datetime createdAt
datetime updatedAt
}
flowchart LR
subgraph Client
FE[Frontend / API Consumers]
end
FE -->|HTTP| GW[Express App]
subgraph Middleware
SEC[Security: Helmet/CORS/CSP]
AUTH[Auth: JWT, RBAC]
RATE[Rate & Speed Limits]
VAL[Validation: Joi]
end
GW --> SEC --> AUTH --> RATE --> VAL --> RT[Routes]
subgraph Routes
RAuth[/auth/*/]
ROrders[/orders/*/]
RShipments[/shipments/*/]
RFares[/fares/*/]
RVendors[/vendors/*/]
RWarehouses[/warehouses/*/]
RSecurity[/security/*/]
RQueue[/queue/*/]
RReports[/reports/*/]
RDashboard[/dashboard/*/]
end
RT --> CTRL[Controllers]
CTRL --> SRV[Services]
subgraph Services
SAuth[AuthService]
SOrder[OrderService]
SShipment[ShipmentService]
SFare[FareService]
SVendor[VendorService]
SWarehouse[WarehouseService]
SCache[CacheService]
SEmail[EmailService]
SQueue[QueueService]
SReport[ReportService]
SDash[DashboardService]
end
SRV --> REPO[Repositories]
REPO --> DB[(PostgreSQL via Prisma)]
SRV --> REDIS[(Redis)]
SQueue -->|Bull Jobs| REDIS
SQueue -->|ReportExport| FILES[(reports/ CSV files)]
SEmail --> SMTP[(SMTP Provider)]
subgraph Docs
SWAG[Swagger UI]
end
GW --> SWAG
src/
├── config/ # Configuration files
│ ├── database.js # Database configuration
│ ├── index.js # Main configuration
│ └── swagger.js # Swagger documentation config
├── constants/ # Application constants and enums
│ └── index.js # All constants and enums
├── controllers/ # Request/Response handling
│ ├── AuthController.js
│ ├── OrderController.js
│ └── ...
├── dtos/ # Data Transfer Objects
│ ├── BaseDTO.js
│ ├── UserDTO.js
│ ├── OrderDTO.js
│ └── ...
├── errors/ # Custom error classes
│ ├── AppError.js
│ └── index.js
├── interfaces/ # TypeScript interfaces (if using TS)
├── middleware/ # Express middleware
│ ├── auth.js
│ ├── errorHandler.js
│ └── validation.js
├── repositories/ # Data access layer
│ ├── BaseRepository.js
│ ├── UserRepository.js
│ ├── OrderRepository.js
│ └── ...
├── routes/ # API routes
│ ├── auth.js
│ ├── orders.js
│ ├── vendors.js
│ └── ...
├── services/ # Business logic layer
│ ├── BaseService.js
│ ├── AuthService.js
│ ├── OrderService.js
│ └── ...
├── types/ # TypeScript type definitions
├── utils/ # Utility functions
│ ├── logger.js
│ ├── response.js
│ └── validation.js
├── validators/ # Input validation schemas
│ ├── authValidator.js
│ ├── orderValidator.js
│ └── ...
├── server.js # Application entry point
└── seed.js # Database seeding
- Purpose: Handle HTTP requests and responses
- Responsibilities:
- Extract data from requests
- Call appropriate service methods
- Format responses
- Handle errors
- Purpose: Implement business logic
- Responsibilities:
- Business rule validation
- Data processing and transformation
- Orchestrating multiple repository calls
- Complex business operations
- Purpose: Data access abstraction
- Responsibilities:
- Database operations
- Query building
- Data mapping
- Database-specific logic
- Purpose: Data structure definition and validation
- Responsibilities:
- Define data contracts
- Data transformation
- Input/output validation
- API response formatting
class BaseRepository {
async create(data) { /* ... */ }
async findById(id) { /* ... */ }
async findMany(where, options) { /* ... */ }
async update(id, data) { /* ... */ }
async delete(id) { /* ... */ }
}class BaseService {
constructor(repository) {
this.repository = repository;
}
async create(data) { /* ... */ }
async findById(id) { /* ... */ }
// ... other methods
}class UserDTO extends BaseDTO {
static createUser(data) { /* ... */ }
static response(user) { /* ... */ }
static authResponse(user, token) { /* ... */ }
}class AppError extends Error {
constructor(message, statusCode, isOperational = true) {
super(message);
this.statusCode = statusCode;
this.isOperational = isOperational;
}
}- Custom error classes with proper HTTP status codes
- Centralized error handling middleware
- Operational vs programming error distinction
- Detailed error logging
- Joi-based input validation
- Centralized validation schemas
- Custom validation helpers
- Detailed error messages
- Winston-based structured logging
- Different log levels (error, warn, info, debug)
- File and console logging
- Request/response logging
- Consistent API response structure
- Success/error response helpers
- Pagination support
- Standardized error messages
- JWT-based authentication
- Role-based access control
- Middleware-based protection
- Token validation and refresh
- Each layer has a single responsibility
- Clear boundaries between layers
- Loose coupling between components
- Services depend on abstractions (repositories)
- Easy to mock for testing
- Flexible and maintainable
- Custom error classes
- Proper HTTP status codes
- Detailed error messages
- Error logging and monitoring
- Input validation at controller level
- Business rule validation in services
- Database constraint validation
- Comprehensive error messages
- Structured logging with Winston
- Different log levels
- Request/response logging
- Error tracking
- Environment-based configuration
- Centralized config files
- Type-safe configuration
- Default values and validation
- Swagger/OpenAPI documentation
- Interactive API explorer
- Comprehensive schemas
- Example requests/responses
- Clear code organization
- Easy to locate and modify code
- Consistent patterns throughout
- Well-documented code
- Modular architecture
- Easy to add new features
- Horizontal scaling support
- Performance optimization
- Dependency injection
- Mockable components
- Unit test friendly
- Integration test support
- Input validation
- Authentication/authorization
- Error handling
- Security headers
- Clear project structure
- Comprehensive documentation
- Interactive API docs
- Consistent patterns
-
Install Dependencies
npm install
-
Setup Environment
cp env.example .env # Edit .env with your configuration -
Setup Database
npm run db:push npm run db:seed
-
Start Development Server
npm run dev
-
Access API Documentation
- Swagger UI: http://localhost:3000/api-docs
- Health Check: http://localhost:3000/api/health
When adding new features:
- Create DTOs for data structures
- Implement repository for data access
- Create service for business logic
- Add controller for HTTP handling
- Create routes and validation
- Add comprehensive tests
- Update documentation
The architecture supports:
- Unit testing (services, repositories)
- Integration testing (API endpoints)
- End-to-end testing (full workflows)
- Mock testing (external dependencies)
- Structured logging with Winston
- Error tracking and reporting
- Performance monitoring
- Health check endpoints