diff --git a/docs/website/diagrams-md/architecture.md b/docs/website/diagrams-md/architecture.md
index f466b2b7..f4e91347 100644
--- a/docs/website/diagrams-md/architecture.md
+++ b/docs/website/diagrams-md/architecture.md
@@ -12,34 +12,64 @@ doesn't wire up any slice; it applies schema directly.
```mermaid
---
+
config:
- flowchart:
- curve: stepAfter
+
+flowchart:
+
+curve: stepAfter
+
+layout: elk
+
---
+
flowchart TB
- API["API.Core
(ASP.NET Core Web API)"]
- Seed["Database.Seed
(console app)"]
- Migrations["Database.Migrations
(console app)"]
- subgraph SLICES["Feature Slices"]
- direction LR
- UsersSlice["Features.Users
(controller)"]
- BrewerySlice["Features.Breweries
(controller)"]
- PhotoSlice["Features.PhotoUpload
(MediatR only)"]
- EmailsSlice["Features.Emails
(MediatR only)"]
- LocationsSlice["Features.Locations
(plain DI service)"]
- BeersSlice["Features.Beers
(scaffolded, no code yet)"]
- end
+API["API.Core
(ASP.NET Core Web API)"]
- API -->|AddApplicationPart + MediatR scan| UsersSlice
- API -->|AddApplicationPart + MediatR scan| BrewerySlice
- API -->|MediatR scan only| PhotoSlice
- API -->|MediatR scan only| EmailsSlice
+Seed["Database.Seed
(console app)"]
- Seed -->|AddFeaturesUsers| UsersSlice
- Seed -->|AddFeaturesBreweries| BrewerySlice
- Seed -->|AddFeaturesPhotoUpload| PhotoSlice
- Seed -->|AddFeaturesLocations| LocationsSlice
+Migrations["Database.Migrations
(console app)"]
+
+
+
+subgraph SLICES["Feature Slices"]
+
+direction LR
+
+UsersSlice["Features.Users
(controller)"]
+
+BrewerySlice["Features.Breweries
(controller)"]
+
+PhotoSlice["Features.PhotoUpload
(MediatR only)"]
+
+EmailsSlice["Features.Emails
(MediatR only)"]
+
+LocationsSlice["Features.Locations
(plain DI service)"]
+
+BeersSlice["Features.Beers
(scaffolded, no code yet)"]
+
+end
+
+
+
+API -->|AddApplicationPart + MediatR scan| UsersSlice
+
+API -->|AddApplicationPart + MediatR scan| BrewerySlice
+
+API -->|MediatR scan only| PhotoSlice
+
+API -->|MediatR scan only| EmailsSlice
+
+
+
+Seed -->|AddFeaturesUsers| UsersSlice
+
+Seed -->|AddFeaturesBreweries| BrewerySlice
+
+Seed -->|AddFeaturesPhotoUpload| PhotoSlice
+
+Seed -->|AddFeaturesLocations| LocationsSlice
```
## Project reference dependencies
@@ -54,67 +84,132 @@ see the notes for what else each of those foundation projects pulls in.
```mermaid
---
+
config:
- flowchart:
- curve: stepAfter
+
+flowchart: {}
+
+layout: fixed
+
---
+
flowchart TB
- subgraph SLICES["Feature Slices"]
- direction LR
- BrewerySlice["Features.Breweries"]
- LocationsSlice["Features.Locations"]
- BeersSlice["Features.Beers
(scaffolded)"]
- PhotoSlice["Features.PhotoUpload"]
- UsersSlice["Features.Users"]
- EmailsSlice["Features.Emails"]
- end
- subgraph FOUNDATION["Foundation (every DB-backed slice depends on all three)"]
- direction LR
- SharedContracts["Shared.Contracts"]
- Domain["Domain.Entities"]
- DBConn["Database.Connection"]
- end
+subgraph SLICES["Feature Slices"]
- SharedApp["Shared.Application
(email command contract)"]
+direction LR
- subgraph INFRA["Slice-specific Infrastructure"]
- direction LR
- JWT["Infrastructure.Jwt"]
- PwdHash["Infrastructure.PasswordHashing"]
- FileUpload["Infrastructure.FileUpload"]
- Email["Infrastructure.Email"]
- EmailTemplates["Infrastructure.Email.Templates"]
- end
+BrewerySlice["Features.Breweries"]
- Tables[("SQL Server
Tables")]
+LocationsSlice["Features.Locations"]
- %% the one feature-to-feature reference, breaking slice isolation
- UsersSlice ==>|"project ref, sends UploadPhotoCommand"| PhotoSlice
+BeersSlice["Features.Beers
(scaffolded)"]
- %% cross-slice MediatR contract, routed through Shared.Application instead
- UsersSlice -.->|sends email commands| SharedApp
- EmailsSlice -.->|handles email commands| SharedApp
+PhotoSlice["Features.PhotoUpload"]
- %% every DB-backed slice depends on the same foundation
- BrewerySlice & LocationsSlice & BeersSlice & PhotoSlice & UsersSlice --> FOUNDATION
+UsersSlice["Features.Users"]
- %% slice-specific infra, one edge per slice
- UsersSlice --> JWT & PwdHash
- PhotoSlice --> FileUpload
- EmailsSlice --> Email & EmailTemplates
+EmailsSlice["Features.Emails"]
- DBConn -->|Dapper SQL, no ORM| Tables
+end
+
+subgraph FOUNDATION["Foundation (every DB-backed slice depends on all three)"]
+
+direction LR
+
+SharedContracts["Shared.Contracts"]
+
+Domain["Domain.Entities"]
+
+DBConn["Database.Connection"]
+
+end
+
+subgraph INFRA["Slice-specific Infrastructure"]
+
+direction LR
+
+JWT["Infrastructure.Jwt"]
+
+PwdHash["Infrastructure.PasswordHashing"]
+
+FileUpload["Infrastructure.FileUpload"]
+
+Email["Infrastructure.Email"]
+
+EmailTemplates["Infrastructure.Email.Templates"]
+
+end
+
+UsersSlice == project ref, sends UploadPhotoCommand ==> PhotoSlice
+
+UsersSlice -. sends email commands .-> SharedApp["Shared.Application
(email command contract)"]
+
+EmailsSlice -. handles email commands .-> SharedApp
+
+BrewerySlice --> FOUNDATION
+
+LocationsSlice --> FOUNDATION
+
+BeersSlice --> FOUNDATION
+
+PhotoSlice --> FOUNDATION & FileUpload
+
+UsersSlice --> FOUNDATION & JWT & PwdHash
+
+EmailsSlice --> Email & EmailTemplates
+
+DBConn -- Dapper SQL, no ORM --> Tables[("SQL Server
Tables")]
```
## Notes
-- **API.Core**: Program.cs wiring only — MediatR + `AddApplicationPart` per HTTP-exposed `Features.*` assembly, Swagger/OpenAPI, health checks, JWT auth middleware, global exception filter. Only `Features.Users` and `Features.Breweries` get `AddApplicationPart` (controllers); `Features.PhotoUpload` and `Features.Emails` are scanned for MediatR handlers only. `Features.Locations` and `Features.Beers` aren't referenced by `API.Core` at all.
-- **Feature slices**: each owns its own controller (where present), commands/queries + handlers, validators, and Dapper repository. `Features.Users` covers auth (`Commands/Authentication`), account management (`Commands/Account`), and profile/avatar (`Commands/Profile`) — internally namespaced `Features.Auth`, despite the project being named `Features.Users`. `Features.Emails` and `Features.PhotoUpload` have no controller — invoked only via MediatR commands sent from other slices. `Features.Locations` has no controller either; it now has one MediatR handler (`GetOrCreateCityHandler`), but that's only registered by `Database.Seed`'s own MediatR pipeline — `API.Core` never scans it. `Features.Beers` is scaffolded (project + references only, no source files yet).
-- **The one exception to slice isolation**: `Features.Users` takes a direct project reference to `Features.PhotoUpload` and sends its `UploadPhotoCommand` via MediatR from `UploadAvatarHandler` — unlike the email flow, the command type lives in the target slice itself, not in `Shared.Application`.
-- **Shared.Application**: `ValidationBehavior` (MediatR pipeline) plus the cross-slice email commands (`SendRegistrationEmailCommand`, `SendResendConfirmationEmailCommand`) — that interaction is a MediatR command contract, not a project reference, and every slice (including `Features.Emails`) references it for the pipeline behavior alone.
-- **Domain.Entities**: `UserAccount`, `UserCredential`, `UserVerification`, `UserProfile`, `UserAvatar`, `BreweryPost`, `BreweryPostLocation`, `City`, `StateProvince`, `Country`, `BeerPost`, `BeerStyle`, `Photo` (schema tables exist for `BeerPost`/`BeerStyle`; no repository yet since `Features.Beers` has no code).
-- **Database.Connection**: the shared connection-factory project — each slice's own repository issues inline SQL via Dapper against it, no ORM, no stored procedures. Replaces the old `Infrastructure.Sql` project.
-- **Database.Migrations**: separate console app (`schema.dbml` + SQL scripts) that applies DDL directly — distinct from `Database.Seed`, which loads data through the feature slices' own DI extensions.
-- **Database.Seed**: calls each slice's `AddFeatures*()` DI extension directly and builds its own MediatR registration — no API host, no shared pipeline with `API.Core`.
-- **Omitted from the diagram**: `Domain.Exceptions` (referenced by nearly every project directly, including all of `Shared.Contracts`, `Infrastructure.Jwt`, and each feature slice) and `Infrastructure.Configuration` (the shared options-binding project referenced by `Database.Connection`, `Infrastructure.Email`, `Infrastructure.FileUpload`, and `Features.Emails` directly) — both are plumbing-level dependencies of nearly everything above, and drawing them would just add a second copy of the same fan-in.
+- **API.Core**: Program.cs wiring only
+ - MediatR + `AddApplicationPart` per HTTP-exposed `Features.*` assembly
+ - Swagger/OpenAPI, health checks, JWT auth middleware, global exception filter
+ - Only `Features.Users` and `Features.Breweries` get `AddApplicationPart` (controllers)
+ - `Features.PhotoUpload` and `Features.Emails` scanned for MediatR handlers only
+ - `Features.Locations` and `Features.Beers` not referenced by `API.Core` at all
+
+- **Feature slices**: each owns its own controller (where present), commands/queries + handlers, validators, and Dapper repository
+ - `Features.Users` covers auth (`Commands/Authentication`), account management (`Commands/Account`), and profile/avatar (`Commands/Profile`)
+ - internally namespaced `Features.Auth`, despite project name `Features.Users`
+ - `Features.Emails` and `Features.PhotoUpload` have no controller — invoked only via MediatR commands sent from other slices
+ - `Features.Locations` has no controller; one MediatR handler (`GetOrCreateCityHandler`) registered by `Database.Seed` only — `API.Core` never scans it
+ - `Features.Beers` is scaffolded (project + references only, no source files yet)
+
+- **The one exception to slice isolation**: `Features.Users` takes a direct project reference to `Features.PhotoUpload`
+ - sends its `UploadPhotoCommand` via MediatR from `UploadAvatarHandler`
+ - unlike the email flow, the command type lives in the target slice itself, not in `Shared.Application`
+
+- **Shared.Application**:
+ - `ValidationBehavior` (MediatR pipeline)
+ - Cross-slice email commands (`SendRegistrationEmailCommand`, `SendResendConfirmationEmailCommand`)
+ - MediatR command contract (not project reference)
+ - Every slice (including `Features.Emails`) references it for the pipeline behavior alone
+
+- **Domain.Entities**:
+ - `UserAccount`, `UserCredential`, `UserVerification`, `UserProfile`, `UserAvatar`
+ - `BreweryPost`, `BreweryPostLocation`
+ - `City`, `StateProvince`, `Country`
+ - `BeerPost`, `BeerStyle`, `Photo` (schema tables exist for `BeerPost`/`BeerStyle`; no repository yet since `Features.Beers` has no code)
+
+- **Database.Connection**: the shared connection-factory project
+ - each slice's own repository issues inline SQL via Dapper against it
+ - no ORM, no stored procedures
+ - Replaces the old `Infrastructure.Sql` project
+
+- **Database.Migrations**: separate console app
+ - `schema.dbml` + SQL scripts
+ - applies DDL directly
+ - distinct from `Database.Seed`, which loads data through the feature slices' own DI extensions
+
+- **Database.Seed**:
+ - calls each slice's `AddFeatures*()` DI extension directly
+ - builds its own MediatR registration
+ - no API host, no shared pipeline with `API.Core`
+
+- **Omitted from the diagram**:
+ - `Domain.Exceptions` (referenced by nearly every project directly, including all of `Shared.Contracts`, `Infrastructure.Jwt`, and each feature slice)
+ - `Infrastructure.Configuration` (the shared options-binding project referenced by `Database.Connection`, `Infrastructure.Email`, `Infrastructure.FileUpload`, and `Features.Emails` directly)
+ - both are plumbing-level dependencies of nearly everything above, and drawing them would just add a second copy of the same fan-in