Production
Topology
Production runs in a dedicated Azure subscription, separate from development.App Gateway
Application Gateway WAF v2 as the single public entry point. Everything behind it is private.
Routing is path-based:
/api/* to the backend, /inspect/* to the inspector PWA, and
everything else to the frontend SPA.
Network isolation
The Container Apps environment is created with internal ingress — its load balancer is private and no public endpoint exists. App FQDNs resolve, through a private DNS zone, to an address inside the VNet. Three subnets, each with its own NSG: the gateway subnet, the private-endpoint subnet, and the Container Apps subnet. The gateway subnet can reach the apps on 443 and nothing else.Data platform
PostgreSQL Flexible Server sits behind a private endpoint withpublicNetworkAccess
disabled. There are no firewall rules because there is no public listener to firewall.
- Geo-redundant backups with 35-day retention, committed at first provisioning — this setting is immutable after creation, so it was not deferred.
- RPO ≈ minutes from continuous backup. RTO ≈ tens of minutes for a point-in-time restore; geo-restore covers a regional disaster.
- TLS required on all connections.
- A zone-redundant HA standby is not enabled — recovery is restore-based. Unlike the backup setting this one is mutable, so HA can be switched on later without recreating the server.
Storage and the ingestion contract
The storage account keeps a public endpoint by deliberate decision, because both of its workloads require one: inspection photos are uploaded and read directly from the browser via SAS URLs, and producers drop ingestion files into landing containers. Authorisation is by SAS with stored access policies rather than by network position:- Producer tokens are create, write and list only — no read, no delete. A leaked token
cannot read ingestion history from
archive/or tamper with processed files. - Policy expiry is 12 months, with rotation built into project onboarding.
- Anonymous blob access is disabled; HTTPS-only, TLS 1.2.
landing/ container with the issued SAS, and
the pipeline takes them from there. The landing zone is the interface, and it is
producer-agnostic by design.
Data Factory reaches the private database through a Managed VNet integration runtime
with a managed private endpoint — pipeline definitions, staging schema and stored
procedures are unchanged from development.
Development
The development environment is public by design and unchanged — Container Apps with external ingress, a PostgreSQL server reachable on its public endpoint, and public Key Vault, registry and OpenAI. It is the reference for what production would look like without hardening, which is precisely why the two are kept separate. Both environments run the same application images. The differences are build arguments and environment variables, not code branches — the production frontend build points at a relative/api path since it is same-origin behind the gateway, and the inspector PWA is
mounted under /inspect/.