Co-authored-by: Ulysse Gen <ulysse1704@gmail.com> Co-committed-by: Ulysse Gen <ulysse1704@gmail.com> |
||
|---|---|---|
| docs | ||
| src | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| ControllerDecorator.md | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
Base Backend
🚀 Overview
Base Backend is a production-ready Express.js API server designed to power modern web applications. It leverages TypeScript for type safety and includes enterprise-grade features like authentication, database integration, and comprehensive logging.
Module Architecture
This project follows a modular architecture pattern with clear separation of concerns and dependency injection.
Module Structure
Each module in the codebase follows a standard structure:
@{ModuleType}Module/
├── ModuleType.ts # Main module aggregation file
├── Application/ # Business logic and services
│ └── {Feature}/
│ ├── Services/ # Business logic
│ └── Interfaces/ # Contracts and DTOs
├── Domain/ # Core domain entities
│ └── {Feature}/
│ ├── Entities/ # Domain entities
│ └── Events/ # Domain events
├── Infrastructure/ # External dependencies
│ └── {Feature}/
│ ├── Repositories/ # Data access
│ └── Config/ # Infrastructure config
└── Presentation/ # External interfaces
└── {Feature}/
├── Controllers/ # HTTP controllers
├── Routes/ # Route definitions
└── Middleware/ # HTTP middleware
Current Modules
- @ConfigModule: Handles configuration management and environment variables
- @CoreModule: Provides core application functionality (health checks, etc.)
Module Communication
Modules communicate using dependency injection and event-driven patterns:
- Service Injection: Modules can inject services from other modules
- Event System: Modules can publish and subscribe to events
- Interface Contracts: Communication happens through well-defined interfaces
Dependency Injection Rules
✅ Allowed:
- Injecting services from other modules
- Publishing and subscribing to events
- Using interfaces and types
❌ Not Allowed:
- Direct module-to-module dependencies
- Accessing repositories from other modules
- Bypassing service layer for data access
- Direct database access from other modules
Configuration Management
The ConfigModule provides comprehensive environment variable management:
Basic Usage
import { ReadEnv, MustReadEnv, Config } from '@ConfigModule';
// Read with default value
const port = ReadEnvNumber('PORT', 3000);
const nodeEnv = ReadEnv('NODE_ENV', 'development');
// Read required variables (throws if not set)
const databaseUrl = MustReadEnv('DATABASE_URL', 'default-url-here');
const jwtSecret = MustReadEnv('JWT_SECRET', 'default-secret-here');
// Use the Config helper
const config = Config.get(3000);
console.log(config.port, config.nodeEnv);
Available Functions
| Function | Description | Throws Error |
|---|---|---|
ReadEnv(key, default) |
Read string with default | No |
MustReadEnv(key, default) |
Read required string | Yes (if not set or equals default) |
ReadEnvNumber(key, default) |
Read number with default | Yes (if not a number) |
MustReadEnvNumber(key) |
Read required number | Yes (if not set or not a number) |
ReadEnvBoolean(key, default) |
Read boolean with default | No |
MustReadEnvBoolean(key) |
Read required boolean | Yes (if not set or not boolean) |
Environment Variables
Create a .env file in the project root:
# Application Configuration
PORT=3000
NODE_ENV=development
ENVIRONMENT=development
IS_PRODUCTION=false
IS_DEVELOPMENT=true
# Required Configuration (set these properly)
DATABASE_URL=your-actual-database-url-here
JWT_SECRET=your-actual-jwt-secret-here
TypeScript Path Mapping
The project uses path aliases for cleaner imports:
// Instead of:
import { HealthController } from '../../@CoreModule/Presentation/Health/Controllers/HealthController';
// Use:
import { HealthController } from '@CoreModule/Presentation/Health/Controllers/HealthController';
// Or import the main module:
import { CoreModule } from '@CoreModule';
🛠️ Technology Stack
⚡ Express.js | Fast, unopinionated web framework | 4.18+ | 📝 TypeScript | Type-safe JavaScript with strict mode | 5.0+ | ✅ Zod | Schema validation with first-class TypeScript support | 3.22+ | 🗃️ TypeORM | Object-relational mapping (ORM) for TypeScript | 0.3+ | 🎯 Kysely | Type-safe SQL query builder | 0.26+ | 🔐 JWT | JSON Web Token authentication | 9.0+ | 📊 Winston | Structured logging | 3.11+ | 🧪 Jest | Testing framework | 29.7+ | 🏗️ ESLint & Prettier | Code quality and formatting | Latest |
🎯 Key Features
🔐 Authentication & Security
- JWT-based authentication with refresh tokens
- Role-based access control (RBAC)
- Password hashing with bcrypt
- CORS configuration
- Rate limiting middleware
- Input validation with Zod schemas
🗃️ Database Integration
- Type-safe database operations with TypeORM
- Backup query builder with Kysely
- Database migrations and seeding
- Connection pooling
- Transaction support
📡 API Features
- RESTful API design with OpenAPI documentation
- Request/response logging with Winston
- Comprehensive error handling
- Health check endpoints
- Environment-based configuration
- API versioning support
🧪 Development Experience
- Dockerized development environment
- Hot reload during development
- TypeScript strict mode
- Comprehensive test suite
- Code formatting with Prettier
- Linting with ESLint
- Pre-commit hooks
📋 Project Structure
This project follows Modular Domain-Driven Design (DDD) and Clean Architecture principles with a bounded context approach:
base-backend/
├── 📁 src/
│ ├── 📁 @AuthenticationModule/ # Authentication Bounded Context
│ │ ├── 📁 Domain/ # Core authentication domain logic
│ │ │ ├── 📁 User/ # User Aggregate
│ │ │ │ ├── 📁 Model/
│ │ │ │ │ ├── UserAggregate.ts # Main aggregate root
│ │ │ │ │ ├── UserEmailValueObject.ts # Email value object
│ │ │ │ │ ├── UserPasswordValueObject.ts # Password value object
│ │ │ │ │ └── UserSessionEntity.ts # Session entity
│ │ │ │ ├── 📁 Errors/
│ │ │ │ │ ├── UserAggregateError.ts # User domain errors
│ │ │ │ │ ├── AuthenticationError.ts # Authentication errors
│ │ │ │ │ └── UserEmailError.ts # Email validation errors
│ │ │ │ ├── 📁 Events/
│ │ │ │ │ ├── UserRegisteredEvent.ts # User registration event
│ │ │ │ │ ├── UserLoggedInEvent.ts # User login event
│ │ │ │ │ └── UserLoggedOutEvent.ts # User logout event
│ │ │ │ └── 📁 Repository/
│ │ │ │ └── IUserRepository.ts # User repository interface
│ │ │ │
│ │ │ ├── 📁 Token/ # Token Aggregate
│ │ │ │ ├── 📁 Model/
│ │ │ │ │ ├── TokenAggregate.ts # Token aggregate root
│ │ │ │ │ ├── AccessTokenValueObject.ts # Access token value object
│ │ │ │ │ └── RefreshTokenValueObject.ts # Refresh token value object
│ │ │ │ ├── 📁 Errors/
│ │ │ │ │ └── TokenAggregateError.ts # Token domain errors
│ │ │ │ ├── 📁 Events/
│ │ │ │ │ ├── TokenGeneratedEvent.ts # Token generation event
│ │ │ │ │ └── TokenRefreshedEvent.ts # Token refresh event
│ │ │ │ └── 📁 Repository/
│ │ │ │ └── ITokenRepository.ts # Token repository interface
│ │ │ │
│ │ ├── 📁 Application/ # Authentication use cases
│ │ │ ├── 📁 User/
│ │ │ │ ├── 📁 Commands/
│ │ │ │ │ ├── RegisterUserCommand.ts # Register user command
│ │ │ │ │ ├── LoginUserCommand.ts # Login user command
│ │ │ │ │ └── LogoutUserCommand.ts # Logout user command
│ │ │ │ ├── 📁 Queries/
│ │ │ │ │ ├── GetUserQuery.ts # Get user query
│ │ │ │ │ └── ValidateUserQuery.ts # Validate user query
│ │ │ │ ├── 📁 Listeners/
│ │ │ │ │ ├── UserRegisteredListener.ts # User registration listener
│ │ │ │ │ └── UserLoggedInListener.ts # User login listener
│ │ │ │ └── 📁 Services/
│ │ │ │ ├── AuthenticationService.ts # Auth service
│ │ │ │ └── AuthenticationEventHandler.ts # Auth event handler
│ │ │ │
│ │ ├── 📁 Infrastructure/ # Authentication implementation
│ │ │ ├── 📁 User/
│ │ │ │ ├── 📁 Repositories/
│ │ │ │ │ ├── UserPostgresRepository.ts # PostgreSQL implementation
│ │ │ │ │ ├── UserRedisRepository.ts # Redis implementation
│ │ │ │ │ └── UserSqliteRepository.ts # SQLite implementation
│ │ │ │ └── 📁 Daos/
│ │ │ │ ├── UserPostgresDao.ts # PostgreSQL DAO
│ │ │ │ ├── UserRedisDao.ts # Redis DAO
│ │ │ │ └── UserSqliteDao.ts # SQLite DAO
│ │ │ │
│ │ │ ├── 📁 Token/
│ │ │ │ ├── 📁 Repositories/
│ │ │ │ │ ├── TokenPostgresRepository.ts # PostgreSQL implementation
│ │ │ │ │ ├── TokenRedisRepository.ts # Redis implementation
│ │ │ │ │ └── TokenSqliteRepository.ts # SQLite implementation
│ │ │ │ └── 📁 Daos/
│ │ │ │ ├── TokenPostgresDao.ts # PostgreSQL DAO
│ │ │ │ ├── TokenRedisDao.ts # Redis DAO
│ │ │ │ └── TokenSqliteDao.ts # SQLite DAO
│ │ │ │
│ │ │ └── 📁 External/
│ │ │ ├── 📁 JWT/
│ │ │ │ ├── JWTService.ts # JWT service implementation
│ │ │ │ └── JWTValidator.ts # JWT validator
│ │ │ └── 📁 BCrypt/
│ │ │ ├── PasswordHasher.ts # Password hashing service
│ │ │ └── PasswordValidator.ts # Password validation service
│ │ │
│ │ └── 📁 Presentation/ # Authentication API
│ │ ├── 📁 User/
│ │ │ ├── 📁 Controllers/
│ │ │ │ ├── UserHttpController.ts # User HTTP controller
│ │ │ │ ├── UserController.ts # User controller
│ │ │ │ └── UserController.ts # Alternative user controller
│ │ │ └── 📁 Validators/
│ │ │ ├── UserValidator.ts # User request validator
│ │ │ ├── RegisterUserValidator.ts # Registration validator
│ │ │ └── LoginUserValidator.ts # Login validator
│ │ │
│ │ └── 📁 Token/
│ │ ├── 📁 Controllers/
│ │ │ ├── TokenHttpController.ts # Token HTTP controller
│ │ │ └── TokenController.ts # Token controller
│ │ └── 📁 Validators/
│ │ ├── TokenValidator.ts # Token request validator
│ │ └── RefreshTokenValidator.ts # Refresh token validator
│ │
│ ├── 📁 @AuthorizationModule/ # Authorization Bounded Context
│ │ ├── 📁 Domain/ # Roles, Permissions, Policies
│ │ ├── 📁 Application/ # Permission checking use cases
│ │ ├── 📁 Infrastructure/ # Role management implementation
│ │ └── 📁 Presentation/ # Authorization API endpoints
│ │
│ ├── 📁 @UserModule/ # User Management Bounded Context
│ │ ├── 📁 Domain/ # User profile, settings domain
│ │ ├── 📁 Application/ # User management use cases
│ │ ├── 📁 Infrastructure/ # User storage implementation
│ │ └── 📁 Presentation/ # User CRUD API
│ │
│ └── 📁 @CoreModule/ # Core/Shared Bounded Context
│ ├── 📁 Domain/ # Shared domain entities
│ ├── 📁 Application/ # Shared application services
│ ├── 📁 Infrastructure/ # Database, logging, caching
│ └── 📁 Presentation/ # Shared controllers, middleware
│
│ ├── 📁 @PostgresModule/ # PostgreSQL Infrastructure Module
│ │ ├── 📁 Domain/ # PostgreSQL-specific domain concepts
│ │ │ ├── 📁 Connection/ # Connection aggregates
│ │ │ │ ├── 📁 Model/
│ │ │ │ │ ├── PostgresConnectionAggregate.ts
│ │ │ │ │ ├── ConnectionStringValueObject.ts
│ │ │ │ │ └── DatabaseConfigEntity.ts
│ │ │ │ ├── 📁 Errors/
│ │ │ │ │ ├── ConnectionError.ts
│ │ │ │ │ └── PoolExhaustedError.ts
│ │ │ │ ├── 📁 Events/
│ │ │ │ │ ├── ConnectionEstablishedEvent.ts
│ │ │ │ │ └── ConnectionClosedEvent.ts
│ │ │ │ └── 📁 Repository/
│ │ │ │ └── IPostgresConnectionRepository.ts
│ │ │ ├── 📁 Migration/ # Migration aggregates
│ │ │ │ ├── 📁 Model/
│ │ │ │ │ ├── MigrationAggregate.ts
│ │ │ │ │ ├── MigrationVersionValueObject.ts
│ │ │ │ │ └── MigrationScriptEntity.ts
│ │ │ │ ├── 📁 Errors/
│ │ │ │ │ └── MigrationError.ts
│ │ │ │ ├── 📁 Events/
│ │ │ │ │ ├── MigrationAppliedEvent.ts
│ │ │ │ │ └── MigrationRolledBackEvent.ts
│ │ │ │ └── 📁 Repository/
│ │ │ │ └── IMigrationRepository.ts
│ │ │ └── 📁 Schema/ # Schema aggregates
│ │ │ ├── 📁 Model/
│ │ │ │ ├── SchemaAggregate.ts
│ │ │ │ ├── TableEntity.ts
│ │ │ │ └── IndexEntity.ts
│ │ │ ├── 📁 Errors/
│ │ │ │ └── SchemaError.ts
│ │ │ └── 📁 Events/
│ │ │ ├── SchemaCreatedEvent.ts
│ │ │ └── SchemaUpdatedEvent.ts
│ │ ├── 📁 Application/ # PostgreSQL use cases
│ │ │ ├── 📁 Connection/
│ │ │ │ ├── 📁 Commands/
│ │ │ │ │ ├── CreateConnectionCommand.ts
│ │ │ │ │ ├── TestConnectionCommand.ts
│ │ │ │ │ └── CloseConnectionCommand.ts
│ │ │ │ ├── 📁 Queries/
│ │ │ │ │ ├── GetConnectionStatusQuery.ts
│ │ │ │ │ └── GetConnectionMetricsQuery.ts
│ │ │ │ └── 📁 Services/
│ │ │ │ ├── ConnectionPoolService.ts
│ │ │ │ └── ConnectionHealthService.ts
│ │ │ ├── 📁 Migration/
│ │ │ │ ├── 📁 Commands/
│ │ │ │ │ ├── RunMigrationCommand.ts
│ │ │ │ │ ├── RollbackMigrationCommand.ts
│ │ │ │ │ └── CreateMigrationCommand.ts
│ │ │ │ ├── 📁 Queries/
│ │ │ │ │ ├── GetMigrationStatusQuery.ts
│ │ │ │ │ └── GetMigrationHistoryQuery.ts
│ │ │ │ └── 📁 Services/
│ │ │ │ ├── MigrationService.ts
│ │ │ │ └── SchemaValidationService.ts
│ │ │ └── 📁 Schema/
│ │ │ ├── 📁 Commands/
│ │ │ │ ├── CreateSchemaCommand.ts
│ │ │ │ └── UpdateSchemaCommand.ts
│ │ │ ├── 📁 Queries/
│ │ │ │ ├── GetSchemaInfoQuery.ts
│ │ │ │ └── ValidateSchemaQuery.ts
│ │ │ └── 📁 Services/
│ │ │ ├── SchemaBuilderService.ts
│ │ │ └── SchemaAnalyzerService.ts
│ │ ├── 📁 Infrastructure/ # PostgreSQL implementation
│ │ │ ├── 📁 Connection/
│ │ │ │ ├── 📁 Repositories/
│ │ │ │ │ └── PostgresConnectionRepository.ts
│ │ │ │ └── 📁 Daos/
│ │ │ │ ├── PostgresConnectionDao.ts
│ │ │ │ └── PostgresPoolDao.ts
│ │ │ ├── 📁 Migration/
│ │ │ │ ├── 📁 Repositories/
│ │ │ │ │ └── PostgresMigrationRepository.ts
│ │ │ │ └── 📁 Daos/
│ │ │ │ ├── PostgresMigrationDao.ts
│ │ │ │ └── PostgresSchemaDao.ts
│ │ │ └── 📁 External/
│ │ │ ├── 📁 TypeORM/
│ │ │ │ ├── PostgresTypeORMService.ts
│ │ │ │ └── PostgresTypeORMConfig.ts
│ │ │ ├── 📁 PG/
│ │ │ │ ├── NativePGService.ts
│ │ │ │ └── NativePGConfig.ts
│ │ │ └── 📁 Kysely/
│ │ │ ├── PostgresKyselyService.ts
│ │ │ └── PostgresKyselyConfig.ts
│ │ └── 📁 Presentation/ # PostgreSQL API
│ │ ├── 📁 Controllers/
│ │ │ ├── ConnectionController.ts
│ │ │ ├── MigrationController.ts
│ │ │ └── SchemaController.ts
│ │ └── 📁 Validators/
│ │ ├── ConnectionValidator.ts
│ │ ├── MigrationValidator.ts
│ │ └── SchemaValidator.ts
│ │
│ ├── 📁 @SqliteModule/ # SQLite Infrastructure Module
│ │ ├── 📁 Domain/ # SQLite-specific domain concepts
│ │ │ ├── 📁 Database/ # Database aggregates
│ │ │ │ ├── 📁 Model/
│ │ │ │ │ ├── SQLiteDatabaseAggregate.ts
│ │ │ │ │ ├── DatabasePathValueObject.ts
│ │ │ │ │ └── DatabaseConfigEntity.ts
│ │ │ │ ├── 📁 Errors/
│ │ │ │ │ ├── DatabaseError.ts
│ │ │ │ │ └── DatabaseLockedError.ts
│ │ │ │ ├── 📁 Events/
│ │ │ │ │ ├── DatabaseCreatedEvent.ts
│ │ │ │ │ └── DatabaseBackupEvent.ts
│ │ │ │ └── 📁 Repository/
│ │ │ │ └── ISqliteDatabaseRepository.ts
│ │ │ └── 📁 Query/ # Query aggregates
│ │ │ ├── 📁 Model/
│ │ │ │ ├── SqliteQueryAggregate.ts
│ │ │ │ ├── QueryPlanValueObject.ts
│ │ │ │ └── QueryResultEntity.ts
│ │ │ ├── 📁 Errors/
│ │ │ │ ├── QueryError.ts
│ │ │ │ └── QueryTimeoutError.ts
│ │ │ └── 📁 Events/
│ │ │ ├── QueryExecutedEvent.ts
│ │ │ └── QueryOptimizedEvent.ts
│ │ ├── 📁 Application/ # SQLite use cases
│ │ │ ├── 📁 Database/
│ │ │ │ ├── 📁 Commands/
│ │ │ │ │ ├── CreateDatabaseCommand.ts
│ │ │ │ │ ├── BackupDatabaseCommand.ts
│ │ │ │ │ └── VacuumDatabaseCommand.ts
│ │ │ │ ├── 📁 Queries/
│ │ │ │ │ ├── GetDatabaseInfoQuery.ts
│ │ │ │ │ └── GetDatabaseStatusQuery.ts
│ │ │ │ └── 📁 Services/
│ │ │ │ ├── DatabaseManagementService.ts
│ │ │ │ └── DatabaseBackupService.ts
│ │ │ └── 📁 Query/
│ │ │ ├── 📁 Commands/
│ │ │ │ ├── ExecuteQueryCommand.ts
│ │ │ │ └── OptimizeQueryCommand.ts
│ │ │ ├── 📁 Queries/
│ │ │ │ ├── GetQueryPlanQuery.ts
│ │ │ │ └── GetQueryPerformanceQuery.ts
│ │ │ └── 📁 Services/
│ │ │ ├── QueryOptimizationService.ts
│ │ │ └── QueryAnalysisService.ts
│ │ ├── 📁 Infrastructure/ # SQLite implementation
│ │ │ ├── 📁 Database/
│ │ │ │ ├── 📁 Repositories/
│ │ │ │ │ └── SqliteDatabaseRepository.ts
│ │ │ │ └── 📁 Daos/
│ │ │ │ ├── SqliteDatabaseDao.ts
│ │ │ │ └── SqliteBackupDao.ts
│ │ │ └── 📁 External/
│ │ │ ├── 📁 SQLite3/
│ │ │ │ ├── NativeSQLiteService.ts
│ │ │ │ └── SQLiteConfig.ts
│ │ │ ├── 📁 BetterSQLite/
│ │ │ │ ├── BetterSQLiteService.ts
│ │ │ │ └── BetterSQLiteConfig.ts
│ │ │ └── 📁 Kysely/
│ │ │ ├── SQLiteKyselyService.ts
│ │ │ └── SQLiteKyselyConfig.ts
│ │ └── 📁 Presentation/ # SQLite API
│ │ ├── 📁 Controllers/
│ │ │ ├── DatabaseController.ts
│ │ │ ├── QueryController.ts
│ │ │ └── BackupController.ts
│ │ └── 📁 Validators/
│ │ ├── DatabaseValidator.ts
│ │ ├── QueryValidator.ts
│ │ └── BackupValidator.ts
│ │
│ ├── 📁 @RedisModule/ # Redis Infrastructure Module
│ │ ├── 📁 Domain/ # Redis-specific domain concepts
│ │ │ ├── 📁 Cache/ # Cache aggregates
│ │ │ │ ├── 📁 Model/
│ │ │ │ │ ├── RedisCacheAggregate.ts
│ │ │ │ │ ├── CacheKeyValueObject.ts
│ │ │ │ │ ├── CacheTTLValueObject.ts
│ │ │ │ │ └── CacheEntryEntity.ts
│ │ │ │ ├── 📁 Errors/
│ │ │ │ │ ├── CacheError.ts
│ │ │ │ │ ├── CacheMissError.ts
│ │ │ │ │ └── CacheTimeoutError.ts
│ │ │ │ ├── 📁 Events/
│ │ │ │ │ ├── CacheHitEvent.ts
│ │ │ │ │ ├── CacheMissEvent.ts
│ │ │ │ │ ├── CacheSetEvent.ts
│ │ │ │ │ └── CacheEvictEvent.ts
│ │ │ │ └── 📁 Repository/
│ │ │ │ └── IRedisCacheRepository.ts
│ │ │ ├── 📁 PubSub/ # Pub/Sub aggregates
│ │ │ │ ├── 📁 Model/
│ │ │ │ │ ├── RedisPubSubAggregate.ts
│ │ │ │ │ ├── ChannelValueObject.ts
│ │ │ │ │ ├── MessageEntity.ts
│ │ │ │ │ └── SubscriptionEntity.ts
│ │ │ │ ├── 📁 Errors/
│ │ │ │ │ ├── PubSubError.ts
│ │ │ │ │ └── SubscriptionError.ts
│ │ │ │ ├── 📁 Events/
│ │ │ │ │ ├── MessagePublishedEvent.ts
│ │ │ │ │ ├── MessageReceivedEvent.ts
│ │ │ │ │ └── SubscribedEvent.ts
│ │ │ │ └── 📁 Repository/
│ │ │ │ └── IRedisPubSubRepository.ts
│ │ │ └── 📁 Cluster/ # Cluster aggregates
│ │ │ ├── 📁 Model/
│ │ │ │ ├── RedisClusterAggregate.ts
│ │ │ │ ├── ClusterNodeEntity.ts
│ │ │ │ ├── ClusterSlotValueObject.ts
│ │ │ │ └── ClusterConfigEntity.ts
│ │ │ ├── 📁 Errors/
│ │ │ │ ├── ClusterError.ts
│ │ │ │ └── ClusterNodeError.ts
│ │ │ ├── 📁 Events/
│ │ │ │ ├── ClusterConnectedEvent.ts
│ │ │ │ ├── ClusterFailoverEvent.ts
│ │ │ │ └── ClusterNodeJoinedEvent.ts
│ │ │ └── 📁 Repository/
│ │ │ └── IRedisClusterRepository.ts
│ │ ├── 📁 Application/ # Redis use cases
│ │ │ ├── 📁 Cache/
│ │ │ │ ├── 📁 Commands/
│ │ │ │ │ ├── SetCacheCommand.ts
│ │ │ │ │ ├── GetCacheCommand.ts
│ │ │ │ │ ├── DeleteCacheCommand.ts
│ │ │ │ │ ├── ClearCacheCommand.ts
│ │ │ │ │ └── CacheIncrementCommand.ts
│ │ │ │ ├── 📁 Queries/
│ │ │ │ │ ├── GetCacheInfoQuery.ts
│ │ │ │ │ └── GetCacheStatsQuery.ts
│ │ │ │ └── 📁 Services/
│ │ │ │ ├── CacheManagementService.ts
│ │ │ │ └── CacheEvictionService.ts
│ │ │ ├── 📁 PubSub/
│ │ │ │ ├── 📁 Commands/
│ │ │ │ │ ├── PublishCommand.ts
│ │ │ │ │ ├── SubscribeCommand.ts
│ │ │ │ │ └── UnsubscribeCommand.ts
│ │ │ │ ├── 📁 Queries/
│ │ │ │ │ ├── GetSubscriptionsQuery.ts
│ │ │ │ │ └── GetChannelInfoQuery.ts
│ │ │ │ └── 📁 Services/
│ │ │ │ ├── PubSubService.ts
│ │ │ │ └── MessageHandlerService.ts
│ │ │ └── 📁 Cluster/
│ │ │ ├── 📁 Commands/
│ │ │ │ ├── ConnectClusterCommand.ts
│ │ │ │ ├── AddClusterNodeCommand.ts
│ │ │ │ └── RemoveClusterNodeCommand.ts
│ │ │ ├── 📁 Queries/
│ │ │ │ ├── GetClusterInfoQuery.ts
│ │ │ │ └── GetClusterStatusQuery.ts
│ │ │ └── 📁 Services/
│ │ │ ├── ClusterManagementService.ts
│ │ │ └── ClusterHealthService.ts
│ │ ├── 📁 Infrastructure/ # Redis implementation
│ │ │ ├── 📁 Cache/
│ │ │ │ ├── 📁 Repositories/
│ │ │ │ │ └── RedisCacheRepository.ts
│ │ │ │ └── 📁 Daos/
│ │ │ │ ├── RedisCacheDao.ts
│ │ │ │ └── RedisCacheClusterDao.ts
│ │ │ ├── 📁 PubSub/
│ │ │ │ ├── 📁 Repositories/
│ │ │ │ │ └── RedisPubSubRepository.ts
│ │ │ │ └── 📁 Daos/
│ │ │ │ ├── RedisPubSubDao.ts
│ │ │ │ └── RedisPubSubClusterDao.ts
│ │ │ └── 📁 External/
│ │ │ ├── 📁 ioredis/
│ │ │ │ ├── IoRedisService.ts
│ │ │ │ └── IoRedisConfig.ts
│ │ │ ├── 📁 redis/
│ │ │ │ ├── NodeRedisService.ts
│ │ │ │ └── NodeRedisConfig.ts
│ │ │ └── 📁 upstash/
│ │ │ ├── UpstashRedisService.ts
│ │ │ └── UpstashRedisConfig.ts
│ │ └── 📁 Presentation/ # Redis API
│ │ ├── 📁 Controllers/
│ │ │ ├── CacheController.ts
│ │ │ ├── PubSubController.ts
│ │ │ └── ClusterController.ts
│ │ └── 📁 Validators/
│ │ ├── CacheValidator.ts
│ │ ├── PubSubValidator.ts
│ │ └── ClusterValidator.ts
│
├── 📁 tests/ # Test files organized by module
│ └── Unknown yet
│
├── 📄 package.json
├── 📄 tsconfig.json # TypeScript configuration
├── 📄 jest.config.js # Jest configuration
├── 📄 .env.example # Environment variables template
├── 📄 .env.dev # Environment variables for development
├── 📄 Dockerfile # Dockerfile
├── 📄 Dockerfile.dev # Dockerfile for development
├── 📄 docker-compose.yml # Docker Compose configuration
├── 📄 docker-compose.dev.yml # Docker Compose configuration for development
└── 📄 README.md # This file
Module Architecture Pattern
Each module follows Aggregate-Driven DDD with hexagonal architecture principles:
🔒 Module Structure (per Bounded Context)
@ModuleName/
├── 📁 Domain/ # Domain Layer - Business Logic & Rules
│ ├── 📁 Aggregate1/ # Aggregate 1 (e.g., User)
│ │ ├── 📁 Model/ # Domain model components
│ │ │ ├── Aggregate1Aggregate.ts # Main aggregate root
│ │ │ ├── ValueObject1.ts # Value objects
│ │ │ ├── ValueObject2.ts # Value objects
│ │ │ └── Entity1.ts # Entities within aggregate
│ │ ├── 📁 Errors/ # Domain-specific errors
│ │ │ ├── Aggregate1Error.ts # Aggregate errors
│ │ │ └── Aggregate1DomainError.ts # Domain errors
│ │ ├── 📁 Events/ # Domain events
│ │ │ ├── Aggregate1CreatedEvent.ts # Domain events
│ │ │ └── Aggregate1UpdatedEvent.ts # Domain events
│ │ └── 📁 Repository/ # Repository interfaces
│ │ └── IAggregate1Repository.ts # Repository interface
│ │
│ ├── 📁 Aggregate2/ # Aggregate 2 (e.g., Token)
│ │ ├── 📁 Model/
│ │ ├── 📁 Errors/
│ │ ├── 📁 Events/
│ │ └── 📁 Repository/
│ │
├── 📁 Application/ # Application Layer - Use Cases
│ ├── 📁 Aggregate1/ # Aggregate 1 use cases
│ │ ├── 📁 Commands/ # Commands (CQRS)
│ │ │ ├── CreateAggregate1Command.ts # Create command
│ │ │ ├── UpdateAggregate1Command.ts # Update command
│ │ │ └── DeleteAggregate1Command.ts # Delete command
│ │ ├── 📁 Queries/ # Queries (CQRS)
│ │ │ ├── GetAggregate1Query.ts # Get query
│ │ │ ├── ListAggregate1Query.ts # List query
│ │ │ └── SearchAggregate1Query.ts # Search query
│ │ ├── 📁 Listeners/# Event listeners
│ │ │ ├── Aggregate1CreatedListener.ts # Event listener
│ │ │ └── Aggregate1UpdatedListener.ts # Event listener
│ │ └── 📁 Services/ # Application services
│ │ ├── Aggregate1Service.ts # Application service
│ │ └── Aggregate1EventHandler.ts # Event handler
│ │
│ ├── 📁 Aggregate2/ # Aggregate 2 use cases
│ │ ├── 📁 Commands/
│ │ ├── 📁 Queries/
│ │ ├── 📁 Listeners/
│ │ └── 📁 Services/
│ │
├── 📁 Infrastructure/ # Infrastructure Layer - Implementation
│ ├── 📁 Aggregate1/ # Aggregate 1 implementations
│ │ ├── 📁 Repositories/ # Multiple storage implementations
│ │ │ ├── Aggregate1PostgresRepository.ts # PostgreSQL
│ │ │ ├── Aggregate1RedisRepository.ts # Redis
│ │ │ └── Aggregate1SqliteRepository.ts # SQLite
│ │ └── 📁 Daos/ # Data Access Objects
│ │ ├── Aggregate1PostgresDao.ts # PostgreSQL DAO
│ │ ├── Aggregate1RedisDao.ts # Redis DAO
│ │ └── Aggregate1SqliteDao.ts # SQLite DAO
│ │
│ ├── 📁 Aggregate2/ # Aggregate 2 implementations
│ │ ├── 📁 Repositories/
│ │ └── 📁 Daos/
│ │
│ └── 📁 External/ # External service implementations
│ ├── 📁 Service1/ # External service 1
│ │ ├── Service1Implementation.ts # Implementation
│ │ └── Service1Validator.ts # Validator
│ └── 📁 Service2/ # External service 2
│ ├── Service2Implementation.ts # Implementation
│ └── Service2Validator.ts # Validator
│
└── 📁 Presentation/ # Presentation Layer - API
├── 📁 Aggregate1/ # Aggregate 1 API endpoints
│ ├── 📁 Controllers/
│ │ ├── Aggregate1HttpController.ts # HTTP controller
│ │ ├── Aggregate1Controller.ts # REST controller
│ │ └── Aggregate1GraphQLController.ts # GraphQL controller
│ └── 📁 Validators/
│ ├── Aggregate1Validator.ts # Request validator
│ ├── CreateAggregate1Validator.ts # Create validator
│ └── UpdateAggregate1Validator.ts # Update validator
│
├── 📁 Aggregate2/ # Aggregate 2 API endpoints
│ ├── 📁 Controllers/
│ └── 📁 Validators/
│
└── 📁 Shared/ # Shared presentation components
├── 📁 Middleware/ # Module middleware
├── 📁 Decorators/ # Custom decorators
└── 📁 Types/ # Presentation types
Key Benefits
✅ Bounded Contexts
- Each module represents a specific business domain
- Clear ownership and responsibility boundaries
- Independent development and deployment
🔗 Cross-Module Communication
- Domain events for loose coupling
- Shared kernel for common domain concepts
- Anti-corruption layers where needed
🎯 Separation of Concerns
- Domain purity - no framework dependencies
- Clean interfaces between layers
- Testable components with clear contracts
📦 Modularity
- Feature-flag ready modules
- Independent versioning possible
- Easy replacement of implementations
🚀 Quick Start
Prerequisites
- Node.js 22+
- npm 11+
Installation
# Install dependencies
npm install
# Copy environment variables
cp .env.example .env.dev
# Start development server
npm run dev
Available Scripts
# Development
npm run dev # Start development server with hot reload
npm run dev:debug # Start development server with debug mode
# Testing
npm run test # Run tests
npm run test:coverage # Run tests with coverage report
# Database
npm run migrate # Run database migrations
npm run seed # Seed database with initial data
npm run migrate:undo # Rollback last migration
# Build & Production
npm run build # Build TypeScript files
npm run start # Start production server
npm run start:debug # Start production server with debug mode
# Code Quality
npm run lint # Run ESLint
npm run lint:fix # Fix ESLint issues
npm run format # Format code with Prettier
🔧 Configuration
Environment Variables
# Application
NODE_ENV=development # Environment (development/production/test)
PORT=3001 # Server port
API_VERSION=v1 # API version
BASE_URL=http://localhost:3000/api # Base URL (your domain for production)
# Database
DB_TYPE=postgres # Database type (postgres/mysql/sqlite)
DB_HOST=localhost # Database host
DB_PORT=5432 # Database port
DB_USERNAME=postgres # Database username
DB_PASSWORD=password # Database password
DB_DATABASE=base_backend # Database name
# JWT
JWT_SECRET=your-secret-key # JWT secret key
JWT_EXPIRES_IN=7d # Token expiration
JWT_REFRESH_SECRET=refresh-secret # Refresh token secret
JWT_REFRESH_EXPIRES_IN=30d # Refresh token expiration
# Security
BCRYPT_ROUNDS=12 # Bcrypt salt rounds
RATE_LIMIT_WINDOW=15 # Rate limit window (minutes)
RATE_LIMIT_MAX=100 # Rate limit max requests
# Logging
LOG_LEVEL=info # Log level (debug/info/warn/error)
LOG_DIR=logs # Log directory
📚 API Documentation
Base URL
- Development:
http://localhost:3001/api/v1 - Production:
https://your-api-domain.com/api/v1
Authentication
Most endpoints require authentication. Include the JWT token in the Authorization header:
Authorization: Bearer <your-jwt-token>
Key Endpoints
Authentication
POST /auth/login- User loginPOST /auth/register- User registrationPOST /auth/refresh- Refresh JWT tokenPOST /auth/logout- User logout
Users
GET /users- Get all usersGET /users/:id- Get user by IDPUT /users/:id- Update user profileDELETE /users/:id- Delete user
Health Check
GET /health- Application health status
🧪 Testing
The project uses Jest for testing with comprehensive test coverage:
# Run all tests
npm test
# Run tests with coverage
npm run test:coverage
# Run specific test file
npm test -- auth.test.ts
Test Structure
Not yet defined
🚀 Deployment
Production Setup
-
Environment Configuration
cp .env.example .env # Configure production settings -
Build Application
npm run build -
Database Setup
npm run migrate npm run seed -
Start Production Server
npm run start
Docker Deployment
# Build Docker image
docker build -t base-backend .
Environment Variables for Production
- Set
NODE_ENV=production - Use secure JWT secrets
- Configure production database
- Set appropriate log levels
🔒 Security Best Practices
- Input Validation: All inputs validated with Zod schemas
- SQL Injection Prevention: Parameterized queries with TypeORM
- XSS Protection: Sanitization middleware
- Rate Limiting: API endpoint protection
- CORS: Proper cross-origin configuration
- Helmet: Security headers middleware
- Environment Variables: Sensitive data not hardcoded