5-Layer Clean Architecture
Dependency Rule
Dependencies point inward — outer layers depend on inner layers, never the reverse.
Presentation (CLI/API)
↓ depends on
Application (Services)
↓ depends on
Domain (Entities, Traits)
↑ implemented by
Infrastructure (SQL Server)
The Domain layer has zero external dependencies. Repository traits are defined in the domain and implemented in infrastructure.
Layer Details
1. Domain Layer
The innermost layer. Contains business entities, DTOs, and repository trait definitions.
Entities (crates/core/src/domain/entities/):
- Data model structs with
serdederives - Mirror the SQL Server table structure
- DB column abbreviations preserved (e.g.,
pNO,pStatus,pwDia,boID)
Repository Traits (crates/core/src/domain/repositories/):
- Async traits using
#[async_trait] - Define the operations each domain supports
- No knowledge of SQL Server or any specific database
2. Service Layer
Business logic that orchestrates domain operations.
#![allow(unused)]
fn main() {
pub struct WheelService<R: WheelRepository> {
repo: R,
}
impl<R: WheelRepository> WheelService<R> {
pub async fn count(&mut self, filters: &WheelFilters) -> Result<i32> {
self.repo.count(filters).await
}
}
}
Key patterns:
- Generic over
R: Repository— database-agnostic - Takes
&mut selffor mutable repository access - Uses
anyhow::Resultwith.context()for error chaining
3. Infrastructure Layer
SQL Server implementations of the repository traits.
Location: crates/core/src/infrastructure/sqlserver/
- Uses Tiberius (pure Rust TDS driver) for SQL Server connectivity
- Hand-written SQL queries (no ORM)
- Parameterized queries for SQL injection prevention
- All operations are async
4. Application Layer
Currently thin — the CLI commands serve as the application layer, orchestrating service calls.
As the project evolves (Phase 2: REST API), this layer will include:
- Use cases (application services)
- Input validation
- Authorization checks
- DTO transformations
5. Presentation Layer
CLI (crates/cli/src/commands/):
- Clap derive macros for argument parsing
dialoguerfor interactive promptsowo-colorsfor colored terminal outputcomfy-tablefor table formattingindicatiffor progress bars
Error Handling Strategy
| Layer | Approach |
|---|---|
| Domain | thiserror custom error types |
| Service | anyhow::Context for error chaining |
| Infrastructure | Map Tiberius/SQL errors to domain errors |
| CLI | Display user-friendly messages, exit with appropriate codes |