Run schema migrations on AppOnboard-created databases (listed in prepare-plan.json.services[]) before health checks. The app must be running first — if it’s crashing, fix that before attempting migrations.
⛔ Azure PostgreSQL/MySQL Flexible Server only creates the system postgres/mysql database by default. If the app’s config references a named database (e.g., car_sale_db, myapp_production), create it BEFORE the container starts:
powershell
az postgres flexible-server db create -g {rg} -s {serverName} -d {dbName}
Detect the database name from: (1) prereq-output.json.initCommands[] with type: "db-migrate", (2) app config files (config-docker.yml, .env, database.yml), (3) compose POSTGRES_DB env var. If the container crashes with database "X" does not exist, this step was missed.
Discover the migration command from the codebase (check in order):
Module not found → verify the runtime includes the migration tool
⛔ {pass} MUST be the same password passed to az deployment sub create --parameters pgAdminPassword={value}. See deploy-safety.md § Deploy Checklist — generate each secret ONCE, persist to deploy-secrets.env, reuse everywhere. Mismatched passwords cause silent auth failures on migrations and connectivity checks.
Run BEFORE migrations when services[] includes PostgreSQL Flexible Server:
Firewall connectivity:az postgres flexible-server execute -n {pg} -g {rg} -u {admin} -p {pass} -d postgres --querytext "SELECT 1" — if this fails, the firewall rule is missing or RBAC propagation hasn’t completed. Check AllowAllAzureServicesAndResourcesWithinAzureIps exists, wait 60s, retry
Extension availability:az postgres flexible-server parameter show -g {rg} -n {pg} --name azure.extensions --query value -o tsv — verify the extensions the app needs (e.g., uuid-ossp for Alembic/Django UUID fields) are in the allow-list. If missing, the Bicep module should have set them — check infra/modules/postgresql.bicep
Run BEFORE migrations when services[] includes MySQL Flexible Server:
Firewall connectivity:az mysql flexible-server execute -n {mysql} -u {admin} -p {pass} -d mysql -q "SELECT 1" — if this fails, check the firewall rule and RBAC propagation. Note: execute resolves by server name (no -g needed)
SSL enforcement:az mysql flexible-server parameter show -g {rg} -n {mysql} --name require_secure_transport --query value -o tsv — verify matches the app’s connection string SSL mode