Skip to main content
The service runs as a single Azure Container App plus a scheduled job. The entire footprint is one Bicep file — infra/main.bicep:
Why scale-to-zero? Traffic is a handful of calls per day plus a cheap orchestrator ping; the orchestrator only acts when input changed, so idle runs are no-ops. Max one replica keeps the file-based state single-writer.

Bootstrap

The ACR doesn’t exist until the template runs, so the first deployment uses a placeholder image and then swaps in the real one:
1

Deploy the infrastructure

2

Build the image in ACR (no local Docker needed)

3

Point the app at the real image

The public URL is in the deployment output appFqdn.
Re-running step 1 is idempotent; code redeploys only need steps 2–3.

Continuous deployment

The manual GitHub Actions workflow deploy.yml runs the same ACR build + app update. It needs:
  • repository secret AZURE_CREDENTIALS (service principal with contributor on the resource group),
  • repository variables AZURE_RESOURCE_GROUP and AZURE_NAME_PREFIX.

Security posture

  • Two scoped API keys: EXTERNAL_API_KEY (hand to the customer; forecast ingestion only) and PROCESS_API_KEY (internal pipeline + orchestrator timer). /health stays open for probes.
  • Secrets live as Container Apps secrets — move to Key Vault references when the team standardizes on it.
  • Before live Engrate submissions, set the real balancing-group EICs (AREA_MARKET_IDS) and the ECC counterparty EIC; use ENGRATE_TEST_MODE=true to exercise the integration without gate-closure validation.
  • If the customer calls from fixed egress IPs, add ingress IP restrictions on the Container App.