Files
the-biergarten-app/docs/website/diagrams-src/architecture.puml

147 lines
3.7 KiB
Plaintext

@startuml architecture
!theme plain
skinparam backgroundColor #FFFFFF
skinparam defaultFontName Arial
skinparam packageStyle rectangle
title The Biergarten App - Vertical Slice Architecture
package "API.Core (thin host)" #E3F2FD {
[API.Core\nASP.NET Core Web API host] as API
note right of API
- Program.cs wiring only
- MediatR + AddApplicationPart
per Features.* assembly
- Swagger/OpenAPI, health checks
- JWT auth middleware
- Global exception filter
end note
}
package "Feature Slices" #F3E5F5 {
[Features.Users] as UsersSlice
[Features.Breweries] as BrewerySlice
[Features.Emails] as EmailsSlice
[Features.Locations] as LocationsSlice
note right of UsersSlice
Each slice owns its own:
- Controller (HTTP endpoints)
- Commands/Queries + Handlers
- Validators
- Repository (Dapper)
Features.Users covers auth
(Commands/Authentication),
account management
(Commands/Account), and
profile/avatar (Commands/Profile)
end note
note right of EmailsSlice
No controller - invoked only
via MediatR commands sent
from other slices
end note
note right of LocationsSlice
No controller and no MediatR
handlers - exposes ILocationRepository
directly as a plain DI service.
Not registered by API.Core at all;
only Database.Seed depends on it today
end note
}
package "Shared" #FCE4EC {
[Shared.Contracts] as SharedContracts
[Shared.Application] as SharedApp
note right of SharedApp
- ValidationBehavior
(MediatR pipeline)
- Cross-slice email commands
(SendRegistrationEmailCommand,
SendResendConfirmationEmailCommand)
end note
}
package "Infrastructure Layer" #FFF3E0 {
[Infrastructure.Sql] as Sql
[Infrastructure.Jwt] as JWT
[Infrastructure.PasswordHashing] as PwdHash
[Infrastructure.Email] as Email
[Infrastructure.Email.Templates] as EmailTemplates
}
package "Domain Layer" #E8F5E9 {
[Domain.Entities] as Domain
[Domain.Exceptions] as DomainExceptions
note right of Domain
- UserAccount, UserCredential, UserVerification
- UserProfile, UserAvatar
- BreweryPost, BreweryPostLocation
- City, StateProvince, Country
- BeerPost, BeerStyle
(schema tables exist; no repository yet)
end note
}
database "SQL Server" {
[Tables] as Tables
}
node "Database.Seed\n(separate console app)" as Seed
' Relationships
API ..> UsersSlice : AddApplicationPart\n+ MediatR scan
API ..> BrewerySlice : AddApplicationPart\n+ MediatR scan
API ..> EmailsSlice : MediatR scan only\n(no controller)
Seed ..> UsersSlice : AddFeaturesUsers()\n(DI only, no API/MediatR)
Seed ..> BrewerySlice : AddFeaturesBreweries()
Seed ..> LocationsSlice : AddFeaturesLocations()
UsersSlice --> Sql
UsersSlice --> JWT
UsersSlice --> PwdHash
UsersSlice --> SharedContracts
UsersSlice --> SharedApp
BrewerySlice --> Sql
BrewerySlice --> SharedContracts
BrewerySlice --> SharedApp
LocationsSlice --> Sql
EmailsSlice --> Email
EmailsSlice --> EmailTemplates
EmailsSlice --> SharedApp
' The one cross-slice interaction: a MediatR command contract, not a project reference
UsersSlice ..> SharedApp : sends\nSendRegistrationEmailCommand
EmailsSlice ..> SharedApp : handles\nSendRegistrationEmailCommand
Sql --> Domain
UsersSlice --> Tables : Dapper SQL
BrewerySlice --> Tables : Dapper SQL
LocationsSlice --> Tables : Dapper SQL
UsersSlice --> Domain
BrewerySlice --> Domain
LocationsSlice --> Domain
UsersSlice --> DomainExceptions
' Notes
note left of Sql
SQL-first approach
Each slice's own repository issues
inline SQL via Dapper - no ORM,
no stored procedures
end note
note bottom of UsersSlice
No Features.* project
ever references another
Features.* project directly
end note
@enduml