Architecture Overview
2KRIKA is built following Clean Architecture principles, ensuring a modular, testable, and maintainable codebase.
What is Clean Architecture?
Clean Architecture is a software design philosophy that separates concerns into layers, with dependencies flowing inward toward the business logic. This approach ensures:
- Independence from frameworks - Business logic isn't tied to NestJS
- Testability - Core logic can be tested without external dependencies
- Independence from UI - The same backend can serve multiple frontends
- Independence from databases - Easy to swap database implementations
- Independence from external services - External integrations are abstracted
High-Level Architecture
┌─────────────────────────────────────────────────────────┐
│ Web Layer │
│ (NestJS Controllers, Guards, Filters, Gateways) │
└────────────────┬────────────────────────────────────────┘
│
┌────────────────┴────────────────────────────────────────┐
│ Application Layer │
│ (Use Cases, Validators, DTOs, Services) │
└────────────────┬────────────────────────────────────────┘
│
┌────────────────┴────────────────────────────────────────┐
│ Domain Layer │
│ (Entities, Value Objects, Repository Interfaces) │
└────────────────┬────────────────────────────────────────┘
│
┌────────────────┴────────────────────────────────────────┐
│ Adapters Layer │
│ (SQL/NoSQL Repositories, Gateways, External Services) │
└─────────────────────────────────────────────────────────┘
Layer Responsibilities
1. Domain Layer (domain/)
The heart of the application containing:
- Entities - Core business objects (User, Service, Order, Account)
- Value Objects - Immutable values (Permission)
- Repository Interfaces - Contracts for data access
- Domain Exceptions - Business rule violations
Key characteristic: No external dependencies, pure business logic.
2. Application Layer (app/)
Orchestrates the use cases by:
- Use Cases - Application-specific business rules
- Validators - Input validation using Zod
- DTOs - Data transformation objects
- Application Services - Cross-cutting concerns
Key characteristic: Depends on domain, coordinates operations.
3. Adapters Layer (adapters/)
Implements interfaces defined in the domain:
- Repositories - SQL/NoSQL data persistence
- Gateways - External service integrations (Paystack)
- Cache - Redis implementation
- Storage - File system operations
Key characteristic: Implements domain interfaces, bridges external world.
4. Web Layer (web/)
NestJS-specific HTTP and WebSocket handling:
- Controllers - HTTP endpoints
- Guards - Authentication/authorization
- Filters - Exception handling
- Gateways - WebSocket handlers
- Modules - Dependency injection
Key characteristic: Framework-specific, handles requests/responses.
Dependency Flow
- Web depends on Application
- Application depends on Domain
- Adapters implement Domain interfaces
- Domain has no dependencies (pure business logic)
This ensures the domain remains independent and testable.
Core Principles Applied
Dependency Inversion
High-level modules don't depend on low-level modules. Both depend on abstractions.
Example:
// Domain defines the interface
abstract class UserRepository {
abstract get(id: string): Promise<User>;
}
// Adapter implements it
class UserSqlRepository extends UserRepository {
async get(id: string): Promise<User> {
// SQL-specific implementation
}
}
Single Responsibility
Each class/module has one reason to change.
- Entities: Business rules
- Use Cases: Application flow
- Repositories: Data access
- Controllers: HTTP handling
Open/Closed Principle
Open for extension, closed for modification.
Example: Adding a new payment gateway doesn't require changing existing code, just implementing the PaymentGateway interface.
Benefits
✅ Testability - Business logic can be tested without database/HTTP
✅ Flexibility - Easy to change frameworks or databases
✅ Maintainability - Clear separation of concerns
✅ Scalability - Add features without breaking existing code
✅ Team Collaboration - Clear boundaries for parallel development