Skip to content

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 → Application → Domain ← Adapters
  • 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

Next Steps