# 0004. Use Clean Architecture for the .NET API

- **Status:** Accepted
- **Date:** 2026-05-26
- **Deciders:** Loma Group Platform
- **Related:** [`knowledge/patterns/clean-architecture-dotnet.md`](../../knowledge/patterns/clean-architecture-dotnet.md), [`dotnet/README.md`](../../dotnet/README.md)

## Context

The .NET API is the canonical backend. It must stay testable, evolvable, and resistant to "feature-folder-by-osmosis" decay. Many .NET shops use either layered (Repository pattern, DDD-lite) or Clean Architecture.

## Decision

Use **Clean Architecture** with 5 projects in `dotnet/`:

- `Domain` — entities, value objects, domain events. **Zero external references.**
- `Application` — MediatR commands/queries + FluentValidation + abstractions (`IApplicationDbContext`, `IJwtService`, `IPasswordHasher`, …).
- `Infrastructure` — EF Core, JWT, S3, SMTP. Implements `Application` abstractions.
- `Api` — ASP.NET Core host. Controllers thin; wire DI; middleware (CorrelationId / Exception / Serilog).
- `Shared` — `ApiResponse<T>`, `Result`, `Error`, paging/sorting/filter params.

Dependencies: `Api → Application → Domain ← Infrastructure`. `Domain` depends on nothing but `Shared`.

EF reads use `AsNoTracking().Select(...)` projection directly to response DTOs — no fetch-then-map.

## Alternatives considered

| Option                                       | Why rejected                                                                                         |
| -------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| Vertical slice + Feature folders             | Easier for tiny apps; harder to enforce direction-of-deps at scale; we want strict layer boundaries. |
| N-tier (Controllers → Services → Repos → DB) | The Repository pattern over EF is mostly redundant; `DbContext` already IS the unit of work.         |
| Hexagonal / Onion                            | Same idea as Clean Architecture under different names.                                               |

## Consequences

### Positive

- Domain stays pure → easy to test without spinning up infrastructure.
- Replacing the ORM or storage is mechanical — touches only `Infrastructure`.
- Pipeline behaviors (Logging + Validation) attach cross-cutting concerns once.

### Negative

- More files per feature than a flat structure.
- New devs need an orientation tour.

### Neutral

- Sets a high floor on quality; constrains "quick-and-dirty" patches (by design).

## Compliance

The `Audit` aggregate sits in Domain; persistence is in Infrastructure — keeps the audit contract stable while the storage can evolve.

## References

- Clean Architecture (Robert C. Martin)
- The .NET Clean Architecture template (Jason Taylor) — our structure is similar but not identical
