Initial commit
This commit is contained in:
+171
@@ -0,0 +1,171 @@
|
||||
# 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=<your-server>.database.windows.net;Database=PowderCoatingDb;User Id=<user>;Password=<password>;MultipleActiveResultSets=true;TrustServerCertificate=true;Encrypt=true` |
|
||||
|
||||
### Required — Azure Storage
|
||||
|
||||
| Name | Value |
|
||||
|---|---|
|
||||
| `Storage__ConnectionString` | `DefaultEndpointsProtocol=https;AccountName=<account>;AccountKey=<key>;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://<your-domain>/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 <rg> \
|
||||
--name <app-service-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**.
|
||||
Reference in New Issue
Block a user