# Azure Deployment Setup Guide ## Overview The app uses environment-specific config layering: - `appsettings.json` — base defaults (checked into source) - `appsettings.Production.json` — production log levels (checked into source) - **Azure App Service Configuration** — secrets and environment-specific values (overrides everything, never in source) Azure App Service flattens nested JSON keys using `__` (double underscore). For example, `Stripe:SecretKey` in JSON becomes `Stripe__SecretKey` in Azure. --- ## Step 1 — Create Azure Resources You will need the following Azure resources: | Resource | Purpose | |---|---| | App Service (Windows or Linux, .NET 8) | Hosts the web application | | Azure SQL Database | Production database | | Azure Storage Account (`powdercoatingappdev` or prod equivalent) | Blob storage for files + Data Protection keys | ### Storage containers to create (or they auto-create on first run): | Container Name | Purpose | |---|---| | `profileimages` | User profile photos | | `jobimages` | Job photos | | `companylogos` | Company logo images | | `manuals` | Equipment PDF manuals | | `dataprotection` | ASP.NET Data Protection keys (auto-created on startup) | --- ## Step 2 — App Service Configuration (Application Settings) Navigate to: **App Service → Configuration → Application Settings** Add each of the following as individual Application Settings entries. ### Required — Environment | Name | Value | |---|---| | `ASPNETCORE_ENVIRONMENT` | `Production` | ### Required — Database | Name | Value | |---|---| | `ConnectionStrings__DefaultConnection` | `Server=.database.windows.net;Database=PowderCoatingDb;User Id=;Password=;MultipleActiveResultSets=true;TrustServerCertificate=true;Encrypt=true` | ### Required — Azure Storage | Name | Value | |---|---| | `Storage__ConnectionString` | `DefaultEndpointsProtocol=https;AccountName=;AccountKey=;EndpointSuffix=core.windows.net` | The container names default to the values below and only need to be set here if you want to override them: | Name | Default Value | |---|---| | `Storage__Containers__ProfileImages` | `profileimages` | | `Storage__Containers__JobImages` | `jobimages` | | `Storage__Containers__Manuals` | `manuals` | | `Storage__Containers__CompanyLogos` | `companylogos` | ### Required — Stripe Replace with your **live** keys (not test keys) for production. | Name | Value | |---|---| | `Stripe__SecretKey` | `sk_live_...` | | `Stripe__PublishableKey` | `pk_live_...` | | `Stripe__WebhookSecret` | `whsec_...` | | `Stripe__Prices__Basic` | `price_...` (your live Stripe price ID) | | `Stripe__Prices__Pro` | `price_...` (your live Stripe price ID) | | `Stripe__Prices__Enterprise` | `price_...` (your live Stripe price ID) | ### Required — SendGrid | Name | Value | |---|---| | `SendGrid__ApiKey` | `SG....` | | `SendGrid__FromEmail` | `noreply@yourdomain.com` | | `SendGrid__FromName` | `Your Company Name` | ### Optional — Twilio (SMS) Only needed if SMS notifications are enabled. | Name | Value | |---|---| | `Twilio__AccountSid` | `AC...` | | `Twilio__AuthToken` | `...` | | `Twilio__FromNumber` | `+1XXXXXXXXXX` | ### Optional — App Settings Overrides | Name | Value | |---|---| | `AppSettings__CompanyName` | `Your Powder Coating Company` | | `AppSettings__BaseUrl` | `https://yourdomain.azurewebsites.net` | | `AppSettings__TaxRate` | `0.0` | | `AppSettings__Currency` | `USD` | --- ## Step 3 — Stripe Webhook (if using billing) 1. In the Stripe Dashboard, add a webhook endpoint pointing to: `https:///stripe/webhook` 2. Select events: `customer.subscription.created`, `customer.subscription.updated`, `customer.subscription.deleted`, `invoice.payment_succeeded`, `invoice.payment_failed` 3. Copy the webhook signing secret into `Stripe__WebhookSecret` above. --- ## Step 4 — Database EF Core migrations run **automatically on startup** in Production. No manual `dotnet ef database update` step is needed after the first deployment. For the very first deployment only, ensure the Azure SQL firewall allows connections from your App Service (or enable "Allow Azure services to access this server"). --- ## Step 5 — Deploy ```bash # Publish to a local folder dotnet publish src/PowderCoating.Web -c Release -o ./publish # Or use Azure CLI to deploy directly az webapp deployment source config-zip \ --resource-group \ --name \ --src publish.zip ``` Or connect the App Service to your git repo/GitHub Actions for CI/CD. --- ## Step 6 — First Run Checklist After deploying and before handing off to users: - [ ] App loads at the Azure URL without errors - [ ] Log in with SuperAdmin credentials (`superadmin@powdercoating.com` / `SuperAdmin123!`) or company admin (`admin@demo.com` / `CompanyAdmin123!`) - [ ] Platform Management → Seed Data → seed System Data - [ ] Platform Management → Storage Migration → migrate any existing local files to Azure - [ ] Verify a profile photo and job photo load correctly - [ ] Verify Stripe webhook is receiving events (check Stripe Dashboard → Webhooks) - [ ] Update SuperAdmin password to something strong --- ## Notes - **Data Protection keys** are stored in the `dataprotection` Azure Blob container as `keys.xml`. This allows auth cookies to survive app restarts and work across multiple instances. - **Local development** is unaffected — it uses `appsettings.Development.json` and a local filesystem key store. No Azure credentials are required for local dev (though the dev storage account is already configured in `appsettings.Development.json`). - **Logs** write to both console (captured by Azure Log Stream) and the `logs/` folder on the App Service filesystem. View live logs via: **App Service → Log stream**.