Skip to content

System overview

BAM is one global product. It is deployed once, not once per customer. The one deployment today is staging. Everything hosted is created by ba-infrastructure, except where this page says “by hand”.

State as of 2026-11-05.

flowchart LR
  user([Browser]) -->|HTTPS| cf[Cloudflare Pages<br/>ba-client]
  user -->|login| ory[Ory Network<br/>auth.businessaffairs.com]
  cf -->|GraphQL| api[ca-ba-staging-api<br/>Container App, port 4000]
  api -->|HTTP, internal| doc[ca-ba-staging-docbuilder<br/>Container App, port 8080]
  api -->|TLS| atlas[(MongoDB Atlas Flex<br/>ba-staging, db ba-api)]
  doc --> atlas
  api -->|signed URLs| s3[(S3 ba-staging-documents<br/>AWS account bam-staging)]
  user -->|PUT/GET via signed URL| s3
  api -->|secrets at boot| kv[Key Vault<br/>kv-ba-staging-app]
  doc -->|secret references| kv
  api --> mail[Postmark]
  api & doc -->|logs| law[Log Analytics<br/>law-ba-staging]
  law --> mon[Azure Monitor alerts] -->|email| alerts[alerts@businessaffairs.com]
Part Name Notes
Web client hosting Cloudflare Pages project ba-client Production branch main. Custom domains app, app.demo and app.staging.businessaffairs.com all serve the production deployment. Build settings are in the Cloudflare dashboard and ba-client/wrangler.toml.
API Container App ca-ba-staging-api Public ingress on port 4000 at api.staging.businessaffairs.com, managed certificate, HSTS. Runs with NODE_ENV=production and runs database migrations at boot.
Document builder Container App ca-ba-staging-docbuilder Internal ingress only, port 8080. The API calls it to produce Word documents.
Container Apps environment cae-ba-staging Consumption plan, public ingress, no virtual network. Apps scale to zero.
Images Azure Container Registry acrbastaging Tags sha-<short commit>; main-latest is a moving pointer. Pulled with a managed identity.
Application secrets Key Vault kv-ba-staging-app Every runtime secret and the master key for encrypting fields. See Secrets and identity.
Logs Log Analytics workspace law-ba-staging 30-day retention, 1 GB per day quota. Console and system logs from both apps.
Alerts Azure Monitor, action group ag-ba-staging-email Restarts, CPU, memory, vault authentication failures, container exits, log quota. Email to alerts@businessaffairs.com. See the alerts runbook.
Database MongoDB Atlas Flex cluster ba-staging, database ba-api In AWS Sydney, not Azure, because Atlas Flex is not offered in Azure Australia East (ADR 002). Both apps use it.
Uploaded documents S3 bucket ba-staging-documents, region ap-southeast-2 In the AWS account bam-staging, a member of the Sii organisation under the BAM organisational unit. Versioned, encrypted, public access blocked, TLS only. The browser uploads straight to signed URLs.
Login Ory Network project at auth.businessaffairs.com Existing BA project, kept. The API trusts Ory sessions and keys users on their Ory identity.
Mail Postmark, configured through the API’s vault secrets Delivery from staging is not yet verified: a share email sent on 2026-11-04 did not arrive. Open item.
DNS Cloudflare zone businessaffairs.com api.staging and its asuid ownership record are Terraform. The app* records were made by hand and are to be imported.
  • Azure subscription ba-staging, region Australia East. Resource groups rg-ba-staging (everything above) and rg-terraform (state storage and the Terraform vault).
  • Terragrunt layers, in apply order: devops, log-analytics, security, database, environment, compute, cloudflare, monitoring, aws. One folder per layer under environments/staging/, pointing at modules/<layer>.
  • CI signs in to Azure and AWS with GitHub OIDC. It holds no secret of its own.
  • No virtual network, private endpoints, Application Gateway or bastion. BA takes public ingress with TLS and no fixed egress; that is most of the cost difference from TEP (ADR 001).
  • No production deployment yet, and no PR environments for the API. ba-client PR previews build on Cloudflare Pages and point at the staging API.
  • No local development stack yet (planned as area env-01).