Update documentation to reflect new architecture and previous refactors

This commit is contained in:
Aaron Po
2026-06-20 01:33:05 -04:00
parent fd341e332c
commit 07aedcb866
10 changed files with 543 additions and 346 deletions

View File

@@ -4,41 +4,67 @@ skinparam backgroundColor #FFFFFF
skinparam defaultFontName Arial
skinparam packageStyle rectangle
title The Biergarten App - Layered Architecture
title The Biergarten App - Vertical Slice Architecture
package "API Layer" #E3F2FD {
[API.Core\nASP.NET Core Web API] as API
package "API.Core (thin host)" #E3F2FD {
[API.Core\nASP.NET Core Web API host] as API
note right of API
- Controllers (Auth, User)
- Swagger/OpenAPI
- Middleware
- Health Checks
- Program.cs wiring only
- MediatR + AddApplicationPart
per Features.* assembly
- Swagger/OpenAPI, health checks
- JWT auth middleware
- Global exception filter
end note
}
package "Service Layer" #F3E5F5 {
[Service.Auth] as AuthSvc
[Service.UserManagement] as UserSvc
note right of AuthSvc
- Business Logic
- Validation
- Orchestration
package "Feature Slices" #F3E5F5 {
[Features.Auth] as AuthSlice
[Features.Breweries] as BrewerySlice
[Features.UserManagement] as UserSlice
[Features.Emails] as EmailsSlice
note right of AuthSlice
Each slice owns its own:
- Controller (HTTP endpoints)
- Commands/Queries + Handlers
- Validators
- Repository
end note
note right of EmailsSlice
No controller - invoked only
via MediatR commands sent
from other slices
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.Repository] as Repo
[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
- BreweryPost
end note
}
@@ -48,28 +74,53 @@ database "SQL Server" {
}
' Relationships
API --> AuthSvc
API --> UserSvc
API ..> AuthSlice : AddApplicationPart\n+ MediatR scan
API ..> BrewerySlice : AddApplicationPart\n+ MediatR scan
API ..> UserSlice : AddApplicationPart\n+ MediatR scan
API ..> EmailsSlice : MediatR scan only\n(no controller)
AuthSvc --> Repo
AuthSvc --> JWT
AuthSvc --> PwdHash
AuthSvc --> Email
AuthSlice --> Sql
AuthSlice --> JWT
AuthSlice --> PwdHash
AuthSlice --> SharedContracts
AuthSlice --> SharedApp
UserSvc --> Repo
BrewerySlice --> Sql
BrewerySlice --> SharedContracts
BrewerySlice --> SharedApp
Repo --> SP
Repo --> Domain
UserSlice --> Sql
UserSlice --> SharedContracts
UserSlice --> SharedApp
EmailsSlice --> Email
EmailsSlice --> EmailTemplates
EmailsSlice --> SharedApp
' The one cross-slice interaction: a MediatR command contract, not a project reference
AuthSlice ..> SharedApp : sends\nSendRegistrationEmailCommand
EmailsSlice ..> SharedApp : handles\nSendRegistrationEmailCommand
Sql --> SP
Sql --> Domain
SP --> Tables
AuthSvc --> Domain
UserSvc --> Domain
AuthSlice --> Domain
BrewerySlice --> Domain
UserSlice --> Domain
AuthSlice --> DomainExceptions
' Notes
note left of Repo
note left of Sql
SQL-first approach
All queries via
stored procedures
end note
note bottom of AuthSlice
No Features.* project
ever references another
Features.* project directly
end note
@enduml

View File

@@ -112,38 +112,32 @@ package "Test Environment\n(docker-compose.test.yaml)" #FFF3E0 {
end note
}
node "Infrastructure.Repository.Tests\n(Unit Tests)" as RepoTests {
component "xUnit + DbMocker" as RepoComp
node "unit.tests\n(Features.*.Tests, one container)" as UnitTests {
component "xUnit + Moq + DbMocker" as UnitComp
note right
Tests:
- AuthRepository
- UserAccountRepository
- SQL command building
Builds Dockerfile.tests, which
restores/builds against Core.slnx
then runs `dotnet test` for every
Features/*.Tests project in turn:
- Features.Auth.Tests
- Features.Breweries.Tests
- Features.UserManagement.Tests
- Features.Emails.Tests
Uses: Mock connections
Uses: Moq for handlers,
DbMocker for repositories
No real database needed
end note
}
node "Service.Auth.Tests\n(Unit Tests)" as SvcTests {
component "xUnit + Moq" as SvcComp
note right
Tests:
- RegisterService
- LoginService
- Token generation
Uses: Mocked dependencies
No database or infrastructure
end note
}
}
folder "test-results/\n(mounted volume)" as Results {
file "api-specs/\n results.trx" as Result1
file "repository-tests/\n results.trx" as Result2
file "service-auth-tests/\n results.trx" as Result3
file "Features.Auth.Tests.trx" as Result2
file "Features.Breweries.Tests.trx" as Result3
file "Features.UserManagement.Tests.trx" as Result4
file "Features.Emails.Tests.trx" as Result5
note bottom
TRX format
@@ -170,17 +164,16 @@ DevAPI .up.> DevSeed : depends_on
TestMig --> TestDB : 1. Migrate
TestSeed --> TestDB : 2. Seed
Specs --> TestDB : 3. Integration test
RepoTests ..> TestDB : Mock (no connection)
SvcTests ..> TestDB : Mock (no connection)
UnitTests ..> TestDB : depends_on for startup\nordering only (Moq/DbMocker,\nno real connection)
TestMig .up.> TestDB : depends_on
TestSeed .up.> TestMig : depends_on
Specs .up.> TestSeed : depends_on
UnitTests .up.> TestSeed : depends_on
' Test results export
Specs --> Results : Export TRX
RepoTests --> Results : Export TRX
SvcTests --> Results : Export TRX
UnitTests --> Results : Export TRX (one .trx per slice)
' Network notes
note bottom of DevDB