The supported deployment path uses the Azure Developer CLI (azd) and Bicep. It provisions a new resource group per azd environment, remotely builds three images in Azure Container Registry, deploys Container Apps, and runs database migrations as a one-shot Container Apps Job.
No Azure resource is shared or expected to exist before deployment.
- Azure Developer CLI 1.25 or later
- Azure CLI
- Git
- Node.js 22 or later for hooks and local validation
- Docker only for local image builds
- access to an External ID tenant and the council workforce tenant when
AUTHENTICATION_MODEisentraorhybrid
Verify:
azd version
az version
node --versionThe deployment creates resources and Azure role assignments. The deploying principal normally needs:
- Contributor on the subscription or target scope; and
- User Access Administrator for role assignments.
An Owner assignment includes both capabilities but is broader than necessary. Follow the organisation's privileged-access process rather than granting standing access solely for this sample.
Ensure these providers can be registered:
Microsoft.AppMicrosoft.ContainerRegistryMicrosoft.DBforPostgreSQLMicrosoft.CacheMicrosoft.StorageMicrosoft.KeyVaultMicrosoft.CognitiveServiceswhen AI is enabledMicrosoft.OperationalInsightsMicrosoft.InsightsMicrosoft.ManagedIdentityMicrosoft.Network
The deploying principal can check registration with:
az provider show --namespace Microsoft.App --query registrationState -o tsvBefore azd up, confirm:
- the intended region is allowed by Azure Policy;
- PostgreSQL
Standard_B1msand Azure Managed RedisBalanced_B0are available; - Container Apps environment and managed-environment quota is available;
- required tags and naming policies are understood;
- public-endpoint or private-network policies do not conflict with the development profile;
- when AI is enabled,
gpt-4.1-miniversion2025-04-14supports Global Standard in the selected AI region and sufficient token quota exists.
Model availability changes independently of the application region. Keep AZURE_OPENAI_LOCATION separate from AZURE_LOCATION.
Authenticate and run:
azd auth login
azd upazd prompts for:
- environment name;
- subscription;
- primary location.
Use a short environment name such as dev, test01, or pilot. It becomes part of resource names and tags.
The standalone customer installer produces one ZIP containing the validated deployment project, a secret-free council package, and local launchers.
On Windows, extract the ZIP and double-click:
Install-DigitalPermitPlatform.cmd
The launcher checks/installs Microsoft prerequisites with permission, validates the package, signs the deployment owner in locally, configures non-secret azd values, runs azd provision --preview, and asks for explicit confirmation before deployment. It writes a non-secret deployment-result.json receipt when complete.
Technical operators can still run npm run setup:deploy -- --package "/path/to/council-setup.zip". Pass --plan for no-change validation or --subscription <guid> to pin the target subscription.
See Hosted installer and council setup for the complete three-phase journey and identity boundaries.
The preprovision hook creates missing values once per environment:
DATABASE_PASSWORDNEXTAUTH_SECRETDEMO_PASSWORD- default AI, branding, and seed settings
- default
demoauthentication mode and disabled Entra placeholders
Existing values are never changed by the hook. Secret values are not printed.
For entra and hybrid, the hook fails unless all External ID and workforce tenant, client, and secret values are configured.
The postdeploy hook starts the migration job, overrides SEED_DEMO_DATA for that execution, and waits for Succeeded. Deployment fails if migrations fail or exceed 30 minutes.
Set bootstrap values after azd env new and before azd up, or update them and rerun azd up.
azd env set NEXT_PUBLIC_APP_NAME "Example Council Permit Platform"
azd env set NEXT_PUBLIC_SUPPORT_EMAIL "permits@example.gov.uk"
azd env set NEXT_PUBLIC_SUPPORT_PHONE "0300 123 4567"
azd env set NEXT_PUBLIC_DEMO_MODE true
azd env set NEXT_PUBLIC_SHOW_SAMPLE_BANNER true
azd env set SEED_DEMO_DATA trueUse SEED_DEMO_DATA=false outside demonstration environments. Demo mode is a UI flag; it is not a security boundary.
After migrations and the web application are healthy, open <SERVICE_WEB_URI>/setup. Public bootstrap values are used only until an administrator applies a council profile.
The browser keeps an unfinished draft locally. In-app Setup controls only the presentation and resident-service configuration:
- council and service identity;
- landscape logo, branding and support contacts;
- an explicit public-impact publication gate with an atomic audit record.
Azure resources, region, identity, AI and deployment settings are not shown or editable in the main application. For those changes, use the separate customer installer or controlled azd and identity workflows. Module availability is managed separately through Admin > Modules. Retain the setup ZIP as a reviewed configuration record; it contains no secrets.
After the first application deployment, a manager or administrator uses Licensing policy to upload the authority's approved local Statement of Licensing Policy. The application accepts PDF, DOCX, Markdown and text files up to 50MB, preserves the complete source file, and creates an inactive draft. PDFs are reviewed in the original embedded document viewer and can also be opened or downloaded. Activating the reviewed version switches Policy Copilot and application insight together without a redeployment and without a policy-length gate. Add each later adopted edition or revision as a new draft; previously active versions are retained for audit and rollback.
Text extraction is an internal search aid, not a replacement copy of the policy. Policy Copilot retrieves a bounded set of relevant excerpts for each request rather than sending the complete statement to the model. Scanned/image-only PDFs remain valid official records but need a text-based replacement or OCR before AI features can use them.
Do not enable policy-grounded AI for service users until the authority has tested representative retrieval and citations against the retained original. Scanned/image-only PDFs can be used as official records immediately, but require OCR or a text-based replacement before enabling AI grounding.
The default azd up path uses synthetic demo credentials for evaluation. For a new production-intent environment, use one guided command instead:
npm run setup:identity -- --external-tenant <tenant-id-or-domain> --deployWhen necessary, it creates/selects the azd environment and runs azd provision in demo-disabled placeholder mode to derive SERVICE_WEB_URI without deploying or seeding the application. It then derives the workforce tenant, creates both app registrations and service principals, creates and associates the applicant user flow, configures workforce roles and assignment enforcement, stores credentials in azd, switches to entra, disables demo data and performs the first azd up. Follow Identity for required directory roles, a no-change preview and manual fallback.
Do not enable entra until both client credentials are set. Bicep stores them in Key Vault; only the web Container App receives versionless secret references.
azd env set ENABLE_AI true
azd env set AZURE_OPENAI_LOCATION uksouth
azd env set AZURE_OPENAI_CAPACITY 10
azd upIf deployment reports unavailable model, SKU, or quota, select a supported region or update the model definition in infra/modules/platform.bicep after validating application compatibility.
Inspect the environment:
azd env get-valuesImportant non-secret outputs include:
| Output | Meaning |
|---|---|
AZURE_RESOURCE_GROUP |
Environment resource group |
SERVICE_WEB_URI |
Public application URL |
WEB_APP_NAME |
Web Container App |
WORKER_APP_NAME |
Worker Container App |
MIGRATIONS_JOB_NAME |
Manual migration job |
AZURE_CONTAINER_REGISTRY_NAME |
ACR name |
AZURE_STORAGE_ACCOUNT_NAME |
Storage account |
AZURE_KEY_VAULT_NAME |
Key Vault |
AZURE_OPENAI_ENDPOINT |
Empty when AI is disabled |
Never share azd env get-values output without reviewing it; an azd environment also contains generated secrets.
azd deployThis rebuilds and deploys all three services and runs the postdeploy migration job.
Deploy one service only when no schema or shared configuration changed:
azd deploy webazd provision
azd deployRun Bicep validation and review the planned cost/security impact before provisioning shared environments.
Add a checked-in Prisma migration; do not use prisma db push for managed environments.
npm run db:migrate -- --name describe_change
azd deployThe migration image contains Prisma CLI and the checked-in migration directory. The job applies prisma migrate deploy before optional seed commands.
npm ci
npm run db:generate
npm run lint
npm run typecheck
npm test
npm run build
npm audit --audit-level=low
az bicep restore --file infra/main.bicep
az bicep build --file infra/main.bicep
azd show --no-promptSubscription-aware az deployment sub validate requires concrete values in place of the azd substitutions in infra/main.parameters.json.
The included validation workflow does not deploy Azure resources. For environment deployment:
- use workload identity federation instead of a client secret;
- scope the deployment identity to the target subscription or resource group;
- protect production with GitHub environments and required reviewers;
- run validation before
azd provisionorazd deploy; - keep environment secrets in the CI environment, not repository variables;
- retain deployment and migration evidence.
Use azd pipeline config only after reviewing the generated permissions and workflow against organisational policy.
Delete an environment with:
azd down --purgeConfirm that no required data or backups remain only in the environment. Key Vault purge protection intentionally prevents immediate permanent deletion until its retention window expires.
Remove local azd environment metadata separately when it is no longer needed:
azd env delete <environment-name>- The default is a development topology, not a multi-region production topology.
- PostgreSQL uses password authentication, with the password held in Key Vault. Evaluate Microsoft Entra-only database authentication for production.
- Redis uses access-key authentication held in Key Vault. Evaluate Microsoft Entra authentication and disable keys where the client/runtime design supports token refresh.
- Redis, Storage, Key Vault, ACR, and optional OpenAI retain public service endpoints in the default profile.
- Synthetic demo users and data are enabled by default for accelerator exploration.
- Migration seeding is idempotent but should be disabled for production datasets.
See Security and Operations before adapting the template for production.