Skip to main content

Introduction

ApiTickets is built using Clean Architecture principles, ensuring separation of concerns, maintainability, and testability. The architecture is organized into four distinct layers, each with specific responsibilities and dependencies flowing inward toward the domain.
Clean Architecture keeps business logic independent of frameworks, databases, and external agencies. This makes the codebase more maintainable, testable, and adaptable to change.

Architecture Principles

The ApiTickets project follows these core Clean Architecture principles:

Dependency Rule

Dependencies point inward. Outer layers depend on inner layers, never the reverse.

Domain Independence

Business logic is independent of frameworks, UI, databases, and external services.

Separation of Concerns

Each layer has a distinct responsibility and clear boundaries.

Testability

Business logic can be tested without UI, database, or external dependencies.

Four-Layer Structure

Layer Hierarchy

1

Domain Layer (Core)

Contains business entities, DTOs, and domain logic. Has no dependencies on other layers.Location: /Domain
  • Entity models (TicketE, UsuarioE, CatalogoE)
  • DTOs for data transfer
  • Domain utilities (Password hashing)
2

Application Layer

Orchestrates the application flow and dependency injection setup.Location: /API/Application
  • Dependency injection configuration
  • JWT authentication setup
  • Service registrations
3

Infrastructure Layer

Implements external concerns like database context and security.Location: /Infrastructure
  • DBContext (Entity Framework)
  • JWT token generation
  • PostgreSQL configuration
4

Persistence Layer

Handles data access through queries and commands (CQRS pattern).Location: /Persistence
  • Query classes (read operations)
  • Command classes (write operations)
  • Repository implementations

Dependency Flow

The dependency flow ensures that the Domain layer remains pure and independent:
// Domain Layer - No dependencies
namespace Domain.Entities.TicketE
{
    [Table("tickets")]
    public class TicketE
    {
        [Key]
        [Column("id_ticket")]
        public Guid? IdTicket { get; set; } = Guid.NewGuid();
        
        [Column("titulo")]
        public required string Titulo { get; set; }
        
        [Column("descripcion")]
        public required string Descripcion { get; set; }
        // ... more properties
    }
}
// Persistence Layer - Depends on Domain and Infrastructure
using Domain.DTOs.TicketD;
using Domain.Entities.TicketE;
using Infrastructure;

namespace Persistence.Queries
{
    public class TicketQueries : ITicketQueries
    {
        private readonly DBContext _contexto;
        
        public async Task<List<TicketDto>> ObtenerTicketsAsync()
        {
            var tickets = await _contexto.TicketEs
                .AsNoTracking()
                .Select(a => TicketDto.CrearDTO(a))
                .ToListAsync();
            return tickets;
        }
    }
}

Benefits of This Architecture

Clear separation makes it easy to locate and modify code. Changes in one layer don’t cascade to others.
Business logic in the Domain layer can be tested independently without databases or external services.
Easy to swap implementations (e.g., change from PostgreSQL to SQL Server) without touching business logic.
CQRS pattern in Persistence layer allows independent scaling of read and write operations.
Different teams can work on different layers simultaneously with minimal conflicts.

Project Structure

ApiTickets/
├── API/                          # Presentation Layer
│   ├── Controllers/              # REST API endpoints
│   ├── Application/              # DI & configuration
│   └── Program.cs                # Application entry point
├── Domain/                       # Core business layer
│   ├── Entities/                 # Business entities
│   ├── DTOs/                     # Data transfer objects
│   └── Utilidades/               # Domain utilities
├── Infrastructure/               # External services
│   ├── DBContext.cs              # EF Core context
│   └── Seguridad/                # JWT security
└── Persistence/                  # Data access
    ├── Queries/                  # Read operations (CQRS)
    └── Commands/                 # Write operations (CQRS)

CQRS Pattern Implementation

The Persistence layer implements the CQRS (Command Query Responsibility Segregation) pattern:
  • Queries: Handle read operations (GET requests)
  • Commands: Handle write operations (POST, PUT, DELETE requests)
This separation allows for:
  • Optimized read and write models
  • Independent scaling
  • Clearer code organization
  • Better performance tuning
For detailed information about each layer, see the Layers documentation.To learn about the entity models, visit Entities documentation.

Next Steps

Layer Details

Explore each layer’s responsibilities and implementation

Entity Models

Learn about domain entities and their relationships

Build docs developers (and LLMs) love