Skip to main content

7. Deployment View

7.1 Production Deployment (Azure)

7.2 Infrastructure Components

ComponentAzure ServicePurpose
Frontend hostingAzure Static Web AppServes React SPA. Global CDN distribution.
API hostingAzure Container AppsServerless container hosting. Auto-scaling. Managed ingress.
Background workersAzure Container AppsLong-running jobs (BestEx batch, pooling, report generation).
DatabaseAzure SQL Managed InstanceDatabase-per-tenant. Enterprise SQL Server features.
CacheAzure Cache for RedisSession state, rate sheet cache, tenant config cache.
Message busAzure Service BusAsync processing (batch BestEx, pool creation, notifications).
MonitoringApplication Insights + Log AnalyticsOpenTelemetry-based. Traces, metrics, logs.
Container registryAzure Container RegistryDocker image storage for API and worker containers.
IdentityTBD (Keycloak / Azure AD)Authentication and authorization. See ADR-013.

7.3 Local Development (Docker Compose)

All local services are accessed through a single Nginx reverse proxy at http://pssaas.powerseller.local/ (port 80), eliminating port sprawl. A hosts file entry maps pssaas.powerseller.local to 127.0.0.1. See ADR-016 for the rationale.

Docker Compose Profiles

Services are organized into profiles so only what's needed runs at any given time:

docker compose up # proxy + docs (default)
docker compose --profile dev up # + api, web, cache
docker compose --profile dev --profile full up # + identity, bus, mail

Docker Compose Services

ServiceContainerImageProfilePurpose
proxypssaas-proxynginx:alpinedefaultReverse proxy — single entry point at http://pssaas.powerseller.local/ (port 80)
docspssaas-docsCustom Node.jsdefaultDocusaurus documentation site at /docs/
apipssaas-apimcr.microsoft.com/dotnet/sdk:8.0devPSSaaS API with hot reload at /api/
webpssaas-webnode:20-alpinedevReact dev server with HMR at /
cachepssaas-cacheredis:7-alpinedevPrice cache (BestEx, rate sheets)
identitypssaas-identityquay.io/keycloak/keycloakfullIdentity provider at /auth/ (TBD — ADR-013)
buspssaas-busrabbitmq:3-management-alpinefullMessage bus for async operations
mailpssaas-mailaxllent/mailpitfullLocal email capture at /mail/

Key Design Decisions

  • No local SQL Server. The API connects directly to Azure SQL MI. Only MWFI and test databases are there today. See ADR-005.
  • No host port mappings on individual services. Only the proxy exposes port 8080. Services communicate internally via the Docker network.
  • Unavailable routes return 502. When a profile's services aren't running, the proxy returns HTTP 502 gracefully — Nginx does not crash.

7.4 CI/CD Pipeline

Git Push → Azure DevOps Pipeline
├── Build: dotnet build + npm build
├── Test: dotnet test + npm test
├── Analyze: static analysis + security scan
├── Docker: build + push to ACR
└── Deploy:
├── Staging: deploy to staging Container App
├── Validate: smoke tests against staging
└── Production: promote to production Container App

7.5 Database Deployment

Each tenant database follows the same schema. Schema changes are applied via EF Core migrations, rolled out tenant-by-tenant with the ability to pause if issues are detected.

Schema Migration Pipeline:
1. EF Core migration generated
2. Migration reviewed and approved
3. Applied to internal test database
4. Applied to MWFI staging database
5. Applied to MWFI production database
6. Rolled out to remaining tenants