Azure Backend Setup

Select this backend with npm run init:backend -- --provider azure. This maps the current AWS-oriented prototype to Microsoft Entra identity, Azure Functions, Azure Cosmos DB, Azure Blob Storage, Event Grid, and Azure Communication Services Email.

Azure can be the only cloud backend for a local workspace, or it can be connected alongside AWS. In both cases the application model remains provider-neutral: Blob Storage stores object bytes and workspace envelopes, Cosmos DB stores sync indexes and application records, and the coordinating node handles push/pull sync.

This page covers private Azure backend resources. Public Azure static-site publishing and approval guidance are covered in Frontend Deployment. A short record of the first Azure static-site deployment is kept at the end of this page.

Access Model

Do not share Microsoft account passwords, recovery codes, storage account keys, or connection strings in chat. For AI-assisted provisioning, authenticate locally with Azure CLI and grant only the needed RBAC roles to the signed-in user, a temporary collaborator, or a service principal.

Minimum setup flow:

az login
az account set --subscription "<subscription-id-or-name>"
az account show --output table

The setup script assigns Storage Blob Data Contributor to the signed-in user at the storage-account scope so az storage container create --auth-mode login can create the private container after RBAC propagates.

Service Mapping

Concern Azure service
User identity and app roles Microsoft Entra External ID
API boundary Azure Functions or Container Apps behind API Management
Project/account/team records Azure Cosmos DB for NoSQL
Raw and processed files/document artifacts Azure Blob Storage
Administrative events Event Grid
Email notifications Azure Communication Services Email
Runtime configuration App Configuration or Key Vault

Cosmos DB Containers

Use one SQL API database with a single item container for the first implementation:

Use /pk as the partition key for the baseline script, with item values mirroring the AWS single-table partition groups such as ACCOUNT#account_id, TEAM#team_id, USER#user_id, and PROJECT#project_id.

Blob Storage

Store raw and processed files under private blob names:

accounts/{account_id}/projects/{project_id}/documents/{document_id}/raw/{filename}
accounts/{account_id}/projects/{project_id}/documents/{document_id}/processed/{artifact_name}.json
workspaces/{workspace_id}/projects/{project_id}/documents/{document_id}/raw/{filename}

Uploads should use short-lived delegated upload URLs returned by POST /api/uploads/presign. Azure Functions should create the artifact record before issuing the delegated upload URL, then confirm blob existence after upload.

Bootstrap Script

npm run init:backend -- --provider azure --environment dev --prefix workspace-management --location eastus

export AZURE_RESOURCE_GROUP=wm-dev-rg
export AZURE_LOCATION=eastus
export AZURE_STORAGE_ACCOUNT=<globally-unique-lowercase-name>
export AZURE_STORAGE_CONTAINER=workspace-documents
export AZURE_COSMOS_ACCOUNT=<globally-unique-cosmos-name>
export AZURE_COSMOS_DATABASE=workspace
export AZURE_COSMOS_CONTAINER=workspace_items
npm run setup:azure

The Azure CLI commands used by the setup script follow Microsoft Learn command groups for resource groups, storage accounts and containers, Cosmos DB accounts, Cosmos DB SQL databases and containers, and role assignments.

Guardrails

Tenant or subscription administration does not imply file-content access. File download and delegated upload APIs must require effective project permission, not just Entra role membership or Azure subscription access.

Keep Blob containers private. Use RBAC or managed identity for backend workers, and issue user-scoped delegated upload/download URLs only after the API computes project permissions.

Historical Azure Frontend Deployment Record

This is a historical record of the first Azure static frontend deployment, not the current deployment runbook. Use Frontend Deployment for the current Azure static-site command, approval notes, and frontend/backend separation audit.

The first Azure frontend was published as an Azure Storage static website:

https://wme97ea6bcsite.z13.web.core.windows.net/

Resources created or updated:

Resource Value
Subscription context Selected through az login --use-device-code
Resource group wm-site-rg
Region eastus
Static website storage account wme97ea6bcsite
Static website container $web
Index document index.html
Error document index.html

What was needed:

  1. Install Azure CLI and verify az version.
  2. Authenticate with az login --use-device-code.
  3. Select the intended subscription and confirm it with az account show.
  4. Create the static-site resource group.
  5. Register Microsoft.Storage because the fresh subscription reported it as NotRegistered.
  6. Create or update the StorageV2 account for the public frontend.
  7. Enable Azure Storage static website hosting.
  8. Upload dist/ into the $web container.
  9. Upload extensionless HTML route aliases so routes such as /docs/deployment work without .html.
  10. Verify the public Azure endpoint and /docs/deployment returned HTTP 200.

Reusable command pattern:

az login
az account set --subscription "<subscription-id-or-name>"
az provider register --namespace Microsoft.Storage --wait

export AZURE_RESOURCE_GROUP=wm-site-rg
export AZURE_LOCATION=eastus
export AZURE_SITE_STORAGE_ACCOUNT=wme97ea6bcsite
npm run deploy:azure

Use a different globally unique AZURE_SITE_STORAGE_ACCOUNT when deploying another Azure environment.

The reusable deployment script is scripts/deploy-azure-site.sh, exposed through npm run deploy:azure. It owns only Azure frontend deployment concerns: resource group creation, static website account creation, $web upload, extensionless route aliases, and endpoint reporting.

The script defaults to AZURE_STORAGE_AUTH_MODE=key so a prototype deployment can upload immediately after creating the storage account. Set AZURE_STORAGE_AUTH_MODE=login after the deploying identity has Storage Blob Data Contributor on the storage account or $web container.

References