Backend Architecture
High-level overview of the Node.js Express backend architecture, design patterns, and directory structure.
Backend Architecture
The SLMS backend is a robust RESTful API built on Node.js, Express.js, and MongoDB. It follows an evolving Modular + Service Layer pattern, transitioning from a classic MVC approach to feature-based modules for better scalability.
Architecture Pattern
Client Request
│
▼
┌─────────┐ ┌─────────────┐ ┌──────────────┐ ┌──────────┐
│ Routes │────▶│ Middleware │────▶│ Controllers │────▶│ Models │
│ │ │ (Auth/Rate) │ │ │ │(Mongoose)│
└─────────┘ └─────────────┘ └──────┬───────┘ └──────────┘
│
▼
┌─────────────┐
│ Services │
│ (Logic/DB) │
└─────────────┘Layer Responsibilities
| Layer | Purpose | Location |
|---|---|---|
| Routes | Define HTTP method + path + middleware chain | routes/ or src/modules/*/ |
| Middleware | Cross-cutting concerns (auth, rate limiting, logging) | middleware/ |
| Controllers | Handle request/response, extract params, call services | controllers/ or src/modules/*/ |
| Services | Core business logic isolated from the HTTP layer | services/ or src/modules/*/ |
| Models | Define Mongoose data schemas and virtuals | models/ |
| Utils | Shared utilities (DB connection, IP extraction, Error class) | utils/ |
| Config | Environment validation and CRON jobs | config/, jobs/ |
Directory Structure
backend/
├── server.js # Main entry point — mounts middleware and routes
├── .env # Environment variables
├── package.json # Dependencies and scripts
│
├── models/ # Mongoose data schemas
│ ├── User.js # User accounts with security fields
│ ├── Role.js # RBAC Roles
│ ├── Permission.js # RBAC Permissions
│ ├── RolePermission.js # RBAC Mapping Table
│ ├── Book.js # Book catalogue metadata
│ ├── BookCopy.js # Physical book copy tracking
│ ├── Category.js # Book category taxonomy
│ ├── Transaction.js # Checkout/return lifecycle
│ ├── Fine.js # Financial penalties
│ ├── Reservation.js # Book hold requests
│ ├── RefreshToken.js # Hashed refresh tokens for sessions
│ ├── BlacklistedToken.js # Revoked access tokens
│ └── SystemConfig.js # Dynamic system settings
│
├── middleware/ # Custom Express middleware
│ ├── authMiddleware.js # JWT verify + RBAC authorization
│ ├── rateLimiter.js # Distributed Redis rate limiters
│ ├── errorHandler.js # Global centralized error handler
│ └── upload.js # Multer configuration
│
├── utils/ # Core utilities
│ ├── db.js # MongoDB connection helper
│ ├── apiError.js # Standardized custom Error class
│ ├── asyncHandler.js # Promise wrapper for controllers
│ ├── getClientIp.js # Cloudflare-aware IP extraction
│ ├── redisClient.js # Redis connection manager
│ ├── auditLogger.js # Security event logging
│ ├── mailer.js # Nodemailer setup
│ └── validators.js # Zod validation schemas
│
├── services/ # Shared business logic
│ ├── emailService.js # Transactional email dispatch
│ └── securityMonitor.js # Security anomaly detection
│
├── config/ # Configuration and Validation
│ ├── envValidator.js # Validates process.env at startup
│ └── dependencyScanner.js # Scans for CVEs in dependencies
│
├── jobs/ # Scheduled CRON jobs
│ └── fineCalculator.js # Daily fine calculation
│
├── src/modules/ # Feature-based modular structure
│ └── auth/ # Auth Module
│ ├── auth.routes.js
│ ├── auth.controller.js
│ └── auth.service.js
│
├── controllers/ # Legacy MVC HTTP request handlers
│ ├── bookController.js
│ ├── circulationController.js
│ ├── userController.js
│ ├── fineController.js
│ ├── notificationController.js
│ ├── systemConfigController.js
│ ├── auditController.js
│ ├── dashboardController.js
│ └── reportController.js
│
└── routes/ # Legacy Express Router definitions
├── books.js
├── circulation.js
├── users.js
├── fines.js
├── notifications.js
├── systemConfig.js
├── audit.js
├── dashboard.js
└── reports.js API Base URL
All API routes are mounted under the /api/v1 namespace:
http://localhost:5000/api/v1/{resource}Error Handling
The backend uses a centralized, predictive error handling model:
asyncHandlerWrapper: Controllers are wrapped inasyncHandler, which automatically catches promise rejections and passes them tonext(err). This eliminates the need for repetitivetry/catchblocks.APIErrorClass: All intentional errors usethrow new APIError('Message', 400, 'ERROR_CODE').- Global Error Handler: The
errorHandlermiddleware catches all errors, normalizes Mongoose validation/duplicate errors into standard API responses, and formats a consistent JSON payload for the frontend.