System Architecture
SGRH follows a layered architecture (modular monolith) pattern with strict separation of concerns and dependency inversion. The system is built as a centralized backend exposing a REST API, consumed by decoupled Web and Desktop clients.
Architecture Overview
Architecture Type
Modular Monolith - Single deployable unit with clear module boundaries
Layered Architecture - Strict layer separation with dependency rules
Centralized Backend - Single REST API serving multiple clients
Decoupled Clients - Web and Desktop applications consuming the API
Contract-Based Infrastructure - Infrastructure implements domain contracts
Solution Structure
The SGRH solution consists of 7 main projects:
SGRH
├── SGRH.Domain # Core business logic and entities
├── SGRH.Application # Use cases and application logic
├── SGRH.Infrastructure # External integrations (AWS S3, SES)
├── SGRH.Persistence # Database access with EF Core
├── SGRH.Auth # Authentication and authorization
├── SGRH.Api # REST API endpoints
├── SGRH.Web # Blazor web client
└── SGRH.Desktop # .NET MAUI desktop client
Layer Details
1. Domain Layer (SGRH.Domain)
The core of the business - contains all business logic, entities, and contracts.
Key Characteristics
Zero external dependencies - Does not depend on any other project
Rich domain models - Entities with encapsulated business logic
Contract definitions - Interfaces for infrastructure implementations
Business rules - Invariants and validation logic
Structure:
SGRH.Domain/
├── Entities/
│ ├── Clientes/
│ │ └── Cliente.cs
│ ├── Reservas/
│ │ ├── Reserva.cs
│ │ ├── DetalleReserva.cs
│ │ └── ReservaServicioAdicional.cs
│ ├── Habitaciones/
│ │ ├── Habitacion.cs
│ │ ├── HabitacionHistorial.cs
│ │ └── CategoriaHabitacion.cs
│ └── Auditoria/
│ ├── AuditoriaEvento.cs
│ └── AuditoriaEventoDetalle.cs
├── Abstractions/
│ ├── Repositories/
│ │ ├── IAuditoriaRepository.cs
│ │ └── ...
│ ├── Email/
│ │ ├── IEmailSender.cs
│ │ └── IAdminNotifier.cs
│ └── Policies/
│ └── IReservaDomainPolicy.cs
├── Base/
│ └── EntityBase.cs
├── Common/
│ └── Guard.cs
├── Enums/
├── Exceptions/
└── Contracts/
Example: Customer Entity
SGRH.Domain/Entities/Clientes/Cliente.cs
public sealed class Cliente : EntityBase
{
public int ClienteId { get ; private set ; }
public string NationalId { get ; private set ; } = default ! ;
public string NombreCliente { get ; private set ; } = default ! ;
public string ApellidoCliente { get ; private set ; } = default ! ;
public string Email { get ; private set ; } = default ! ;
public string Telefono { get ; private set ; } = default ! ;
public Cliente (
string nationalId ,
string nombreCliente ,
string apellidoCliente ,
string email ,
string telefono )
{
Guard . AgainstNullOrWhiteSpace ( nationalId , nameof ( nationalId ), 20 );
Guard . AgainstNullOrWhiteSpace ( nombreCliente , nameof ( nombreCliente ), 100 );
Guard . AgainstNullOrWhiteSpace ( apellidoCliente , nameof ( apellidoCliente ), 100 );
Guard . AgainstNullOrWhiteSpace ( email , nameof ( email ), 100 );
Guard . AgainstNullOrWhiteSpace ( telefono , nameof ( telefono ), 20 );
NationalId = nationalId ;
NombreCliente = nombreCliente ;
ApellidoCliente = apellidoCliente ;
Email = email ;
Telefono = telefono ;
}
public void ActualizarDatos (
string nombreCliente ,
string apellidoCliente ,
string email ,
string telefono )
{
// Validation and update logic
}
}
Notice how the entity validates all inputs and exposes behavior through methods rather than exposing setters. This is a key principle of domain-driven design.
2. Application Layer (SGRH.Application)
Orchestrates use cases and application workflows.
Responsibilities
Defines application use cases
Orchestrates domain objects
Contains DTOs for data transfer
Validates application-level concerns
No direct database access
No external SDK dependencies
Dependencies: Only depends on SGRH.Domain
Structure:
SGRH.Application/
├── UseCases/
│ ├── Clientes/
│ ├── Reservas/
│ ├── Habitaciones/
│ └── Reportes/
├── DTOs/
│ ├── Requests/
│ └── Responses/
└── Validators/
3. Infrastructure Layer (SGRH.Infrastructure)
Implements domain contracts for external services.
Implementations
Amazon S3 integration for file storage
Amazon SES integration for email notifications
External service adapters
Cloud service clients
Dependencies: SGRH.Domain
Structure:
SGRH.Infrastructure/
├── StorageS3/
│ └── S3StorageService.cs
├── EmailSES/
│ └── SESEmailService.cs
└── DependencyInjection/
└── InfrastructureServiceRegistration.cs
4. Persistence Layer (SGRH.Persistence)
Handles database access using Entity Framework Core.
Data Access
Entity Framework Core 8.0
MySQL provider (note: configured for SQL Server in code)
Repository implementations
Database context configuration
Migrations management
Dependencies: SGRH.Domain
Key Component:
SGRH.Persistence/Context/SGRHDbContext.cs
public class SGRHDbContext : DbContext
{
public SGRHDbContext ( DbContextOptions < SGRHDbContext > options )
: base ( options )
{
}
// DbSets for all entities
public DbSet < Cliente > Clientes { get ; set ; }
public DbSet < Reserva > Reservas { get ; set ; }
public DbSet < Habitacion > Habitaciones { get ; set ; }
// ... more entities
}
5. Auth Module (SGRH.Auth)
Handles authentication and authorization .
Security Features
JWT token generation and validation
Authorization policies
Authentication services
Role-based access control
Structure:
SGRH.Auth/
├── Services/
│ └── TokenService.cs
├── Policies/
└── Extensions/
6. API Layer (SGRH.Api)
The entry point exposing REST endpoints.
API Features
REST controllers
Swagger/OpenAPI documentation
Security configuration
Dependency injection setup
Request/response handling
Dependencies: SGRH.Application, SGRH.Infrastructure, SGRH.Persistence, SGRH.Auth
Project Configuration:
< Project Sdk = "Microsoft.NET.Sdk.Web" >
< PropertyGroup >
< TargetFramework > net8.0 </ TargetFramework >
< Nullable > enable </ Nullable >
< ImplicitUsings > enable </ ImplicitUsings >
</ PropertyGroup >
< ItemGroup >
< PackageReference Include = "Microsoft.AspNetCore.Authentication.JwtBearer" Version = "8.0.0" />
< PackageReference Include = "Microsoft.EntityFrameworkCore.Design" Version = "8.0.0" />
< PackageReference Include = "Swashbuckle.AspNetCore" Version = "8.0.0" />
</ ItemGroup >
< ItemGroup >
< ProjectReference Include = "..\SGRH.Application\SGRH.Application.csproj" />
< ProjectReference Include = "..\SGRH.Auth\SGRH.Auth.csproj" />
< ProjectReference Include = "..\SGRH.Infrastructure\SGRH.Infrastructure.csproj" />
< ProjectReference Include = "..\SGRH.Persistence\SGRH.Persistence.csproj" />
</ ItemGroup >
</ Project >
Controllers:
SGRH.Api/Controllers/
├── ClientesController.cs
├── ReservasController.cs
├── HabitacionesController.cs
├── ReportesController.cs
└── AuditoriaController.cs
Program.cs Bootstrap:
var builder = WebApplication . CreateBuilder ( args );
// Add services to the container
builder . Services . AddControllers ();
builder . Services . AddEndpointsApiExplorer ();
builder . Services . AddSwaggerGen ();
// Database configuration
builder . Services . AddDbContext < SGRHDbContext >( options =>
options . UseSqlServer ( builder . Configuration . GetConnectionString ( "Default" )));
var app = builder . Build ();
// Configure middleware pipeline
if ( ! app . Environment . IsDevelopment ())
{
app . UseHttpsRedirection ();
}
if ( app . Environment . IsDevelopment ())
{
app . UseSwagger ();
app . UseSwaggerUI ();
}
app . UseAuthorization ();
app . MapControllers ();
app . Run ();
7. Client Applications
Web Client (SGRH.Web)
Blazor Server
Server-side Blazor application
Consumes REST API via HTTP
No business logic - pure presentation
Real-time UI updates
Desktop Client (SGRH.Desktop)
.NET MAUI Blazor Hybrid
Cross-platform desktop application
Blazor UI in native container
Role-based interfaces (Admin/Receptionist)
Consumes REST API via HTTP
No business logic - pure presentation
Dependency Flow
The architecture enforces strict dependency rules:
Critical Rule: The Domain layer has zero dependencies . All other layers depend on the domain, never the reverse. This is the essence of dependency inversion.
Key Architectural Patterns
Dependency Inversion
The domain defines interfaces, infrastructure implements them:
SGRH.Domain/Abstractions/Email/IEmailSender.cs
public interface IEmailSender
{
Task < EmailSendResult > SendEmailAsync ( EmailMessage message );
}
SGRH.Infrastructure/EmailSES/SESEmailService.cs
public class SESEmailService : IEmailSender
{
public async Task < EmailSendResult > SendEmailAsync ( EmailMessage message )
{
// AWS SES implementation
}
}
Domain Policies
Complex business rules are encapsulated in policy objects:
SGRH.Domain/Abstractions/Policies/IReservaDomainPolicy.cs
public interface IReservaDomainPolicy
{
void EnsureHabitacionDisponible ( int habitacionId , DateTime entrada ,
DateTime salida , int ? excludeReservaId );
void EnsureHabitacionNoEnMantenimiento ( int habitacionId ,
DateTime entrada , DateTime salida );
decimal GetTarifaAplicada ( int habitacionId , DateTime fechaEntrada );
int GetTemporadaId ( DateTime fecha );
}
Policies are injected into domain entities to enforce complex rules:
SGRH.Domain/Entities/Reservas/Reserva.cs
public void AgregarHabitacion ( int habitacionId , IReservaDomainPolicy policy )
{
Guard . AgainstNull ( policy , nameof ( policy ));
EnsureEditable ();
policy . EnsureHabitacionDisponible (
habitacionId , FechaEntrada , FechaSalida ,
ReservaId == 0 ? null : ReservaId );
policy . EnsureHabitacionNoEnMantenimiento (
habitacionId , FechaEntrada , FechaSalida );
var tarifa = policy . GetTarifaAplicada ( habitacionId , FechaEntrada );
_habitaciones . Add ( new DetalleReserva ( ReservaId , habitacionId , tarifa ));
}
Benefits of This Architecture
Testability Each layer can be tested in isolation with mocked dependencies
Maintainability Clear boundaries make changes predictable and contained
Flexibility Easy to swap implementations (e.g., change from SQL Server to MySQL)
Domain Focus Business logic is isolated and independent of technical concerns
Next Steps
Quick Start Set up and run SGRH on your local machine
API Reference Explore the REST API endpoints