@startuml architecture_v6 skinparam linetype ortho skinparam nodesep 90 skinparam ranksep 110 title The Biergarten App - Vertical Slice Architecture package "API.Core (thin host)" #F1F3EA { [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" #DBEEDD { [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" #E4E6D8 { [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" #EBECE3 { [Infrastructure.Sql] as Sql [Infrastructure.Jwt] as JWT [Infrastructure.PasswordHashing] as PwdHash [Infrastructure.Email] as Email [Infrastructure.Email.Templates] as EmailTemplates } package "Domain Layer" #CBD2B5 { [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 note right of Seed Seed calls each slice's AddFeatures*() DI extension directly - no API host, no MediatR pipeline end note ' Relationships API ..> UsersSlice : AddApplicationPart API ..> BrewerySlice : AddApplicationPart API ..> EmailsSlice : MediatR scan only Seed ..> UsersSlice : AddFeaturesUsers() 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 LocationsSlice --> Tables 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