Skip to main content

Overview

The domain layer is the heart of your application. It contains the core business logic, entities, and rules that define your application’s purpose. This layer is completely independent of any framework, library, or external dependency.
The domain layer should never depend on Angular, HttpClient, or any other infrastructure concern. It defines what your application does, not how it does it.

What Belongs in the Domain Layer

The domain layer typically contains:
  • Entities/Models: Core business objects that represent your domain concepts
  • Repository Interfaces: Contracts that define how to interact with data, without implementation details
  • Business Rules: Domain-specific validation and logic
  • Value Objects: Immutable objects that represent domain concepts

Why Framework-Agnostic?

Keeping the domain layer framework-agnostic provides several benefits:
  1. Portability: Your business logic can be moved to different frameworks or platforms
  2. Testability: Easy to unit test without mocking framework dependencies
  3. Clarity: Clear separation of business concerns from technical implementation
  4. Longevity: Business logic survives framework changes and upgrades

Domain Models

Domain models represent the core entities in your business domain. They should be simple, focusing on the data structure without any behavior that depends on external systems.

Usuario Model

Here’s the Usuario entity from the authentication domain: Location: ~/workspace/source/src/app/usuario/domain/models/usuario.ts:1
usuario.ts
export interface Usuario {
    id: number,
    usuario: string,
    contrasena: string
}
id
number
required
Unique identifier for the user
usuario
string
required
Username for authentication
contrasena
string
required
User’s password (encrypted in practice)
In a production application, you would never store or return plain-text passwords. This model would typically only contain the hashed password for storage, and authentication flows would handle password comparison securely.

Repository Interfaces

Repository interfaces define the contract for data access without specifying the implementation. They use Observable (from RxJS) to handle asynchronous operations, but this is purely for type safety - the domain layer doesn’t implement these Observables.

UsuarioRepository Interface

Location: ~/workspace/source/src/app/usuario/domain/repositories/usuario.repository.ts:1
usuario.repository.ts
import { Observable } from "rxjs";
import { Usuario } from "../models/usuario";

export abstract class UsuarioRepository {
    abstract loginUsuario(usuario: string, contrasena: string): Observable<Usuario>;
    abstract registrarUsuario(usuario: string, contrasena: string): Observable<Usuario>;
}
loginUsuario
(usuario: string, contrasena: string) => Observable<Usuario>
Authenticates a user and returns their information
usuario
string
required
Username to authenticate
contrasena
string
required
Password for authentication
registrarUsuario
(usuario: string, contrasena: string) => Observable<Usuario>
Registers a new user in the system
usuario
string
required
Desired username
contrasena
string
required
User’s chosen password

Why Abstract Classes?

The repository is defined as an abstract class rather than an interface because:
  1. Dependency Injection: Angular’s DI system works better with abstract classes as tokens
  2. Future Extension: You can add non-abstract helper methods later
  3. Type Safety: Provides better type checking in some scenarios
The domain layer defines the repository interface, but never implements it. Implementation happens in the infrastructure layer.

Business Rules

While the current Usuario domain is relatively simple, business rules would typically include:
  • Password complexity requirements
  • Username format validation
  • Account status checks (active, suspended, etc.)
  • Role-based access control
These rules should be implemented in the domain layer as pure functions or methods that don’t depend on external systems.

Domain Layer Structure

src/app/usuario/domain/
├── models/
│   └── usuario.ts          # Domain entities
└── repositories/
    └── usuario.repository.ts  # Repository contracts

Key Principles

The domain layer has no dependencies on:
  • Angular framework (@angular/core, @angular/common)
  • HTTP clients
  • Routing
  • UI components
It only depends on minimal libraries like RxJS for type definitions.

Build docs developers (and LLMs) love