# Code Migration Phase Migrate source platform web application code to Azure App Service. ## Prerequisites - Assessment report completed - Best practices loaded via `mcp_azure_mcp_get_azure_bestpractices` tool ## Rules - Create all output in `-azure/` — never modify the source directory - Use latest GA runtime stack for the target language - Prefer managed identity over connection strings or API keys - Use App Configuration for shared settings, Key Vault for secrets - Always configure health check endpoint ## Steps 1. **Load Best Practices** — Use `mcp_azure_mcp_get_azure_bestpractices` tool for App Service guidance 2. **Create Project Structure** — Set up the project inside the output directory 3. **Migrate Application Code** — Adapt source code for App Service runtime 4. **Update Dependencies** — Replace platform-specific SDKs with Azure equivalents 5. **Configure Startup** — Set startup command or create Dockerfile 6. **Migrate Environment Variables** — Map to App Settings / App Configuration / Key Vault 7. **Configure Database Connections** — Switch to Azure database services with managed identity 8. **Add Health Check** — Implement `/healthz` endpoint for App Service health monitoring 9. **Set Up Logging** — Integrate Application Insights SDK ## Key Configuration Files ### Startup Command For non-Docker deployments, configure the startup command in App Service: | Runtime | Default Start | Custom Start | |---------|--------------|--------------| | Node.js | `npm start` | Set in Configuration → General Settings | | Python | `gunicorn app:app` | `gunicorn --bind=0.0.0.0 --timeout 600 app:app` | | Java | Auto-detected | `-Dserver.port=80` | | .NET | Auto-detected | `dotnet myapp.dll` | ### Dockerfile (When Needed) Use a Dockerfile when the app requires custom system dependencies or multi-process setups: ```dockerfile FROM node:20-slim WORKDIR /app COPY package*.json ./ RUN npm ci --omit=dev COPY . . EXPOSE 8080 CMD ["node", "server.js"] ``` > ⚠️ **Port**: App Service injects `PORT` env var. Always bind to `process.env.PORT || 8080`. ### Application Insights Integration ```javascript // Add as FIRST import in entry point const appInsights = require('applicationinsights'); appInsights.setup(process.env.APPLICATIONINSIGHTS_CONNECTION_STRING) .setAutoCollectRequests(true) .setAutoCollectExceptions(true) .start(); ``` ## Database Migration Patterns | Source | Azure Target | Connection Pattern | |--------|--------------|--------------------| | RDS PostgreSQL | Azure Database for PostgreSQL Flexible Server | Managed identity + `@azure/identity` | | RDS MySQL | Azure Database for MySQL Flexible Server | Managed identity + `@azure/identity` | | RDS SQL Server | Azure SQL Database | Managed identity + `@azure/identity` | | Heroku Postgres | Azure Database for PostgreSQL Flexible Server | Managed identity | | Cloud SQL | Azure SQL / PostgreSQL Flexible Server | Managed identity | | MongoDB Atlas | Azure Cosmos DB for MongoDB | Connection string → managed identity | ### Managed Identity Database Connection (Node.js) ```javascript const { DefaultAzureCredential } = require('@azure/identity'); const { Client } = require('pg'); async function main() { const credential = new DefaultAzureCredential({ managedIdentityClientId: process.env.AZURE_CLIENT_ID }); const token = await credential.getToken('https://ossrdbms-aad.database.windows.net/.default'); const client = new Client({ host: process.env.PGHOST, database: process.env.PGDATABASE, user: process.env.PGUSER, password: token.token, ssl: { rejectUnauthorized: true }, port: 5432 }); await client.connect(); // ... use client } main().catch(console.error); ``` > ⚠️ Wrap in `async function main()` — top-level `await` is not supported in CommonJS or many Node.js entrypoints. For ESM, top-level await works only with `"type": "module"` in `package.json`. ## Static Assets & CDN If the source app serves static assets, consider: 1. **Azure Blob Storage + CDN** for static files 2. **Azure Front Door** for global distribution 3. **App Service built-in static file serving** for simple cases ## Background Workers | Source Pattern | Azure Equivalent | |---------------|------------------| | Heroku Worker dyno | WebJobs (continuous) or separate Container App | | Beanstalk Worker tier | WebJobs or Azure Functions | | App Engine service (worker) | WebJobs or Azure Functions | | Cron jobs | WebJobs (triggered) or Azure Functions Timer trigger | ## Handoff to azure-prepare After code migration is complete: 1. Update `migration-status.md` — mark Code Migration as ✅ Complete 2. Invoke **azure-prepare** — pass the assessment report context so it can: - Use the service mapping as requirements input - Generate IaC (Bicep/Terraform) for the mapped Azure services - Create `azure.yaml` and `.azure/preparation-manifest.md` - Apply security hardening 3. azure-prepare will then chain to **azure-validate** → **azure-deploy**