@startuml deployment !theme plain skinparam backgroundColor #FFFFFF skinparam defaultFontName Arial skinparam linetype ortho title Docker Deployment Architecture ' External systems actor Developer cloud "Docker Host" as Host package "Development Environment\n(docker-compose.dev.yaml)" #E3F2FD { node "SQL Server\n(mcr.microsoft.com/mssql/server:2022-latest)" as DevDB { database "Biergarten\nDatabase" as DevDBInner { portin "1433" } note right Environment: - ACCEPT_EULA=Y - SA_PASSWORD=*** - MSSQL_PID=Developer Volumes: - biergarten-dev-data end note } node "API Container\n(API.Core)" as DevAPI { component "ASP.NET Core 10" as API1 portin "8080:8080 (HTTP)" as DevPort1 portin "8081:8081 (HTTPS)" as DevPort2 note right Environment: - ASPNETCORE_ENVIRONMENT=Development - DB_SERVER=sql-server - DB_NAME=Biergarten - DB_USER/PASSWORD - JWT_SECRET - SMTP_* (10+ variables) Health Check: /health endpoint end note } node "Migrations\n(run-once)" as DevMig { component "Database.Migrations" as Mig1 note bottom Runs: DbUp migrations Environment: - CLEAR_DATABASE=false Depends on: sql-server end note } node "Seed\n(run-once)" as DevSeed { component "Database.Seed" as Seed1 note bottom Creates: - 100 test users - Location data (US/CA/MX) - test.user account Depends on: migrations end note } node "Mailpit\n(axllent/mailpit)" as DevMailpit { portin "8025 (Web UI)" as DevMailpitWeb portin "1025 (SMTP)" as DevMailpitSmtp note right Local SMTP catcher for dev email testing. Environment: - MP_SMTP_AUTH_ACCEPT_ANY=1 - MP_SMTP_AUTH_ALLOW_INSECURE=1 end note } } package "Test Environment\n(docker-compose.test.yaml)" #FFF3E0 { node "SQL Server\n(isolated instance)" as TestDB { database "Biergarten\nTest Database" as TestDBInner { portin "1434" } note right Fresh instance each run CLEAR_DATABASE=true Volumes: - biergarten-test-data (ephemeral) end note } node "Migrations\n(test)" as TestMig { component "Database.Migrations" } node "Seed\n(test)" as TestSeed { component "Database.Seed" note bottom Minimal seed: - test.user only - Essential data end note } node "API.Specs\n(Integration Tests)" as Specs { component "Reqnroll + xUnit" as SpecsComp note right Tests: - Registration flow - Login flow - Validation rules - 404 handling Uses: TestApiFactory Mocks: Email services end note } node "unit.tests\n(Features.*.Tests, one container)" as UnitTests { component "xUnit + Moq" as UnitComp note right Builds Dockerfile.tests, which restores/builds against Core.slnx then runs `dotnet test` for every Features/*.Tests project in turn: - Features.Users.Tests - Features.Breweries.Tests - Features.Emails.Tests Uses: Moq to mock each handler's repository/service dependencies No real database needed end note } } package "Production Environment\n(docker-compose.prod.yaml)" #FCE4EC { node "SQL Server\n(mcr.microsoft.com/mssql/server:2022-latest)" as ProdDB { database "Biergarten\nDatabase" as ProdDBInner note right Environment: - ACCEPT_EULA=Y - SA_PASSWORD=*** - MSSQL_PID=Express Volumes: - sqlserverdata-prod No host port published. end note } node "Migrations\n(run-once)" as ProdMig { component "Database.Migrations" as ProdMig1 note bottom Depends on: sql-server (healthy) No seed step in production. end note } node "API Container\n(API.Core)" as ProdAPI { component "ASP.NET Core 10" as ProdAPI1 portin "8080:8080 (HTTP)" as ProdPort1 portin "8081:8081 (HTTPS)" as ProdPort2 note right Environment: - ASPNETCORE_ENVIRONMENT=Production - DB_SERVER/NAME/USER/PASSWORD - ACCESS/REFRESH/CONFIRMATION_TOKEN_SECRET - WEBSITE_BASE_URL Depends on: sql-server (healthy) - does not wait on migrations/seed. end note } ProdMig --> ProdDB : 1. Run migrations ProdAPI --> ProdDB : 2. Connect & serve ProdMig .up.> ProdDB : depends_on ProdAPI .up.> ProdDB : depends_on note bottom of ProdDB Prod Network (bridge: prodnet) Isolated from dev/test networks. Volumes: sqlserverdata-prod, nuget-cache-prod end note } package "Database-only Environment\n(docker-compose.db.yaml)" #EDE7F6 { node "SQL Server" as DbOnlyDB { database "Biergarten\nDatabase" as DbOnlyDBInner { portin "1434" } } node "Migrations\n(run-once)" as DbOnlyMig { component "Database.Migrations" } node "Seed\n(run-once)" as DbOnlySeed { component "Database.Seed" } note bottom of DbOnlyDB Same devnet volumes/images as docker-compose.dev.yaml, minus api.core and mailpit - for working against the database without running the API. end note DbOnlyMig --> DbOnlyDB : 1. Run migrations DbOnlySeed --> DbOnlyDB : 2. Seed data DbOnlyMig .up.> DbOnlyDB : depends_on DbOnlySeed .up.> DbOnlyMig : depends_on } package "Minimal Environment\n(docker-compose.min.yaml)" #FFF9C4 { node "SQL Server" as MinDB { database "Biergarten\nDatabase" as MinDBInner { portin "1433" } } node "Migrations\n(run-once)" as MinMig { component "Database.Migrations" } node "Mailpit" as MinMailpit { portin "8025 / 1025" } node "Seed\n(run-once)" as MinSeed { component "Database.Seed" } note bottom of MinDB Database + mailpit only, no API container - for frontend development against an API.Core process run outside Docker. end note MinMig --> MinDB : 1. Run migrations MinSeed --> MinDB : 2. Seed data MinMig .up.> MinDB : depends_on MinSeed .up.> MinMig : depends_on } folder "test-results/\n(mounted volume)" as Results { file "api-specs/\n results.trx" as Result1 file "Features.Users.Tests.trx" as Result2 file "Features.Breweries.Tests.trx" as Result3 file "Features.Emails.Tests.trx" as Result5 note bottom TRX format Readable by: - Visual Studio - Azure DevOps - GitHub Actions end note } ' External access Developer --> Host : docker compose up Host --> DevAPI : http://localhost:8080 ' Development dependencies DevMig --> DevDB : 1. Run migrations DevSeed --> DevDB : 2. Seed data DevAPI --> DevDB : 3. Connect & serve DevAPI ..> DevMailpit : 4. SMTP_HOST/PORT DevMig .up.> DevDB : depends_on DevSeed .up.> DevMig : depends_on DevAPI .up.> DevSeed : depends_on ' Test dependencies TestMig --> TestDB : 1. Migrate TestSeed --> TestDB : 2. Seed Specs --> TestDB : 3. Integration test UnitTests ..> TestDB : depends_on for startup\nordering only (Moq mocks,\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 UnitTests --> Results : Export TRX (one .trx per slice) ' Network notes note bottom of DevDB Dev Network (bridge: biergarten-dev) Internal DNS: - sql-server (resolves to SQL container) - api (resolves to API container) end note note bottom of TestDB Test Network (bridge: biergarten-test) All test components isolated end note ' Startup sequence notes note top of DevMig Startup Order: 1. SQL Server (health check) 2. Migrations (run-once) 3. Seed (run-once) 4. API (long-running) end note note top of Specs Test Execution: All tests run in parallel Results aggregated end note @enduml