Skip to Content
Design DecisionsAzure, Not Vercel

Azure Container Apps as the sole deployment target

Status: Accepted · Date: 2026-07-02 (Vercel retirement; recorded as decision D0 in the auto-deploy design) · Area: Deployment

Context

The platform needs two deployment shapes: the singleton Aurora control plane, and a per-solution Orbit stack (reader webapp + writer agent + Mission Control) that Aurora provisions automatically on solution creation. Historically Aurora had a Vercel deployment path (infrastructure/vercel/, including a release.sh drive tool with cut/deploy/promote/rollback), while the per-solution stacks — which need persistent file shares for the cloned solution repositories — were always Azure-shaped. By July 2026 the Vercel project itself no longer existed, and keeping two targets meant carrying Vercel-shaped constraints into Azure work.

Decision

  • Aurora’s production home is Azure Container Apps (decision D0). Azure is the sole deployment target for the whole platform.
  • infrastructure/vercel/ was fully retired and deleted on 2026-07-02 (a user decision; the Vercel project no longer existed).
  • Provisioning runs under the container’s managed identity (DefaultAzureCredential / az login --identity) — no service-principal secret is stored anywhere. A user-assigned identity (id-aurora) carries AcrPull on the registry and Contributor on the solutions resource group.
  • Container images live in ACR and are pulled via the UAMI with the registry admin user disabled (D7). Azure Files env-storage links are the one exception to identity-first: ACA Files linking has no identity path, so the links use the storage account key (D8).
  • The front door is Cloudflare (proxied CNAME + ACA managed-cert custom domain binding), scripted end-to-end in the provisioners.

Consequences

  • One infrastructure scenario (infrastructure/azure/) covers the singleton and the per-solution stacks, sharing one lib.sh foundation and one deploy.sh dispatcher; earlier Vercel-shaped constraints are gone.
  • Historical aurora-webapp release records with target: vercel remain valid history — releases/release.schema.json keeps the vercel enum value alongside the newer container target.
  • ACA’s rough edges had to be learned and scripted around: az containerapp create --yaml silently drops identity/registries/secrets/scale (the reliable pattern is create-on-public-placeholder, then imperative identity → registry → secrets → real image); a proxied Cloudflare CNAME alone returns HTTP 525 until the custom domain is explicitly bound with a managed cert. Both recipes are now live-proven and encoded in the provisioning scripts.
  • A recovery convenience died with Vercel: lost GitHub App private keys can no longer be re-pulled via vercel env pull — they must be regenerated in the GitHub App settings.
  • Aurora is live at https://aurora.maxqlabs-orbit.com on the ACA environment orbit-aca-wcus.

Evidence

  • infrastructure/azure/lib.sh, bootstrap.sh, provision-aurora.sh, provision-solution.sh, build-images.sh, deploy.sh
  • implementation/aurora-webapp/codebase/src/lib/solutions/deploy-azure.ts — the in-product SDK provisioning path
  • releases/release.schema.jsoncontainer and legacy vercel targets
  • memory/orbit-auto-deploy.md (D0, D7, D8 and the ACA gotchas), memory/release-registry.md (the Vercel-era retirement), designs/orbit-auto-deploy.md