2.9 KiB
TrakQR Architecture Guidelines
Core Principles
1. Modular Monolith
The application is structured as a modular monolith where each feature/domain is self-contained but runs in a single deployable unit.
This provides:
- Clear boundaries between features
- Easy refactoring to microservices if needed later
- Simplified deployment and operations
2. Vertical Slice Architecture
Code is organized by feature (vertical slices), not by technical layer (horizontal).
Each feature contains everything it needs:
- Endpoint definitions
- Request/Response models
- Business logic
- Validators
/Features
/Auth
/Endpoints
SmallEndpoint.cs (contains Request, Response, Validator and Endpoint)
/Register
Endpoint.cs
Request.cs
Response.cs
Validator.cs
/Login
...
/Links
/Create
...
/List
...
/QRCodes
...
3. Minimal API with FastEndpoints
We use FastEndpoints instead of traditional MVC Controllers because:
- Better performance (no reflection-based model binding)
- Cleaner, more focused endpoint classes
- Built-in validation with FluentValidation
- Request/Response DTOs are co-located with endpoints
- Easier testing
4. No Traditional Controllers
DO NOT use [ApiController] or ControllerBase. All HTTP endpoints must be FastEndpoints.
Module Structure
Each feature module should be fully self-contained. All code related to a feature lives within that feature's folder:
/Features/{Module}/
- {Module}Responses.cs # Shared response DTOs for this module
- {Module}Settings.cs # Configuration classes for this module
/{Operation}/
- Endpoint.cs # The FastEndpoint class
- Request.cs # Input DTO
- Validator.cs # FluentValidation rules
Example - Auth module:
/Features/Auth/
- AuthResponses.cs # AuthResponse, UserInfo, MessageResponse
- JwtSettings.cs # JWT configuration
/Register/
- Endpoint.cs
- Request.cs
- Validator.cs
/Login/
- Endpoint.cs
- Request.cs
- Validator.cs
For simple operations, business logic lives directly in the Endpoint class. For complex logic, add a Handler.cs or Service.cs within the same feature folder.
Shared Infrastructure
Only truly cross-cutting infrastructure goes outside Features:
/Data- DbContext, migrations (shared database access)/Models- EF Core entities (shared domain model)
Dependency Injection
- Use constructor injection
- Register services in
Program.csor feature-specific extension methods - Prefer scoped services for request-specific work
Validation
- Use FluentValidation via FastEndpoints' built-in support
- Validate at the endpoint level, not in services
- Return 400 Bad Request with structured error responses
Authentication
- JWT Bearer tokens for API authentication
- Claims-based authorization
- User ID extracted from JWT
subclaim