Skip to main content

Architecture Overview

Karma Ecommerce is built using Clean Architecture principles combined with Domain-Driven Design (DDD) and CQRS patterns. This architecture creates a scalable, maintainable, and testable Angular application.

Architectural Layers

The application is organized into three distinct layers, each with specific responsibilities:
┌─────────────────────────────────────────────┐
│         Infrastructure Layer                │
│  (UI Components, HTTP Services, External)   │
│                                             │
│  • Angular Components                       │
│  • HTTP Client Services                     │
│  • External API Integrations                │
└──────────────────┬──────────────────────────┘
                   │ depends on

┌─────────────────────────────────────────────┐
│         Application Layer                   │
│    (Commands, Queries, Handlers)            │
│                                             │
│  • Commands (Write Operations)              │
│  • Queries (Read Operations)                │
│  • Use Case Handlers                        │
└──────────────────┬──────────────────────────┘
                   │ depends on

┌─────────────────────────────────────────────┐
│            Domain Layer                     │
│    (Business Logic, Models, Rules)          │
│                                             │
│  • Domain Models (Entities)                 │
│  • Repository Interfaces                    │
│  • Business Rules                           │
└─────────────────────────────────────────────┘

Domain Layer (Core)

The innermost layer containing:
  • Domain Models: Pure TypeScript interfaces representing business entities
  • Repository Interfaces: Abstract contracts for data access
  • Business Rules: Core business logic independent of frameworks
Example: src/app/usuario/domain/models/usuario.ts
The Domain layer has zero dependencies on external frameworks or libraries. It’s pure business logic.

Application Layer (Use Cases)

Orchestrates the flow of data and implements use cases through:
  • Commands: Represent write operations (mutations)
  • Queries: Represent read operations
  • Handlers: Execute commands and queries using domain repositories
Example: src/app/usuario/application/usecases/commandHandlers/register-user.handler.ts

Infrastructure Layer (External Concerns)

Handles all external dependencies:
  • UI Components: Angular components for presentation
  • Services: Concrete implementations of repository interfaces
  • HTTP Clients: Communication with backend APIs
  • Routing: Navigation and page management
Example: src/app/usuario/infrastructure/services/auth-service.ts

How Layers Interact

1

User Interaction

User interacts with a UI component (Infrastructure Layer)
// register-page.ts
registrar(usuario: string, contrasena: string) {
  this.authService.registrarUsuario(usuario, contrasena)
}
2

Service Call

Component calls a service that implements the repository interface
// auth-service.ts implements UsuarioRepository
registrarUsuario(usuario: string, contrasena: string): Observable<Usuario>
3

Handler Execution

Handler receives a Command/Query and executes the use case
// register-user.handler.ts
handle(command: RegisterUserCommand): Observable<Usuario>
4

Domain Logic

Repository interface (defined in Domain) is used by the handler
// usuario.repository.ts (interface)
abstract registrarUsuario(usuario: string, contrasena: string)

Dependency Flow

The key principle is Dependency Inversion:

Traditional Architecture

Higher layers depend on lower layersUI → Business Logic → Database

Clean Architecture

All layers depend on the DomainInfrastructure → Domain ← Application
This means:
  • Infrastructure implements interfaces defined in Domain
  • Application uses interfaces, not concrete implementations
  • Domain has no dependencies on outer layers

Benefits of This Architecture

Testability

Each layer can be tested independently. Mock repositories easily for unit tests.

Maintainability

Clear separation of concerns makes code easier to understand and modify.

Scalability

Add new features without affecting existing code. Modular structure supports growth.

Framework Independence

Business logic doesn’t depend on Angular. Can migrate UI framework without rewriting logic.

Framework Independence

Your business logic lives in the Domain layer, which doesn’t import Angular. You could theoretically:
  • Replace Angular with React/Vue
  • Use the same logic in a Node.js backend
  • Share code between web and mobile apps

Testability

With dependency injection and interfaces, you can:
  • Mock repositories in tests
  • Test handlers without HTTP calls
  • Test components with fake services

Clear Boundaries

Each layer has a specific purpose:
  • Domain: What the business does
  • Application: How use cases are orchestrated
  • Infrastructure: How we interact with the outside world

Module Structure

The application is organized into feature modules (e.g., usuario), each containing all three layers:
usuario/
├── domain/          # Business entities and interfaces
├── application/     # Use cases (commands, queries, handlers)
└── infrastructure/  # UI and external services
This modular approach supports:
  • Feature-based organization
  • Team autonomy (teams can own entire features)
  • Code reusability
  • Clear boundaries between features

Learn More

Clean Architecture

Deep dive into clean architecture and DDD principles

Folder Structure

Detailed breakdown of the project structure

Getting Started

Set up and run the project locally

Build docs developers (and LLMs) love