Remove Azure deployment stack; Proxmox 7810 is canonical production.
Delete Static Web Apps workflow, Bicep infra, Azure Functions api/, SWA configs, and Azure-only scripts; document Proxmox deploy path and refresh QuickStart and prerequisites. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -1,768 +1,57 @@
|
||||
# 🚀 Deployment Prerequisites Guide
|
||||
# Deployment prerequisites (Proxmox production)
|
||||
|
||||
Complete guide for setting up MS Azure, MS Entra, Cloudflare, and all other services required for production deployment.
|
||||
> **Azure removed (2026-06):** Static Web Apps, Bicep infra, Azure Functions (`api/`), and Azure CI workflows are no longer part of this repo. Production is **VMID 7810** via Proxmox — see [PROXMOX_DEPLOYMENT.md](./deployment/PROXMOX_DEPLOYMENT.md).
|
||||
|
||||
## 📋 Table of Contents
|
||||
## 1. Operator / LAN access
|
||||
|
||||
1. [Azure Setup](#azure-setup)
|
||||
2. [MS Entra (Azure AD) Configuration](#ms-entra-azure-ad-configuration)
|
||||
3. [Cloudflare Configuration](#cloudflare-configuration)
|
||||
4. [Stripe Configuration](#stripe-configuration)
|
||||
5. [Environment Variables](#environment-variables)
|
||||
6. [Pre-Deployment Checklist](#pre-deployment-checklist)
|
||||
7. [Post-Deployment Verification](#post-deployment-verification)
|
||||
| Requirement | Detail |
|
||||
|-------------|--------|
|
||||
| Proxmox SSH | `[email protected]` (r630-02) |
|
||||
| Web CT | VMID **7810** @ `192.168.11.37` |
|
||||
| API CT | VMID **7811** @ `192.168.11.36` (optional; `/api/` proxy) |
|
||||
| Deploy script | `../proxmox/scripts/mim4u-deploy-to-7810.sh` |
|
||||
|
||||
---
|
||||
|
||||
## 1. Azure Setup
|
||||
|
||||
### 1.1 Prerequisites
|
||||
|
||||
- Azure subscription with Contributor or Owner role
|
||||
- Azure CLI installed and configured
|
||||
- Bicep CLI installed (optional, for local validation)
|
||||
- PowerShell 7+ (for deployment scripts)
|
||||
|
||||
### 1.2 Initial Azure Configuration
|
||||
|
||||
#### Login to Azure
|
||||
## 2. Build toolchain
|
||||
|
||||
```bash
|
||||
# Login to Azure
|
||||
az login
|
||||
|
||||
# Verify subscription
|
||||
az account show
|
||||
|
||||
# Set default subscription (if multiple)
|
||||
az account set --subscription "Your Subscription ID"
|
||||
node -v # 22.x recommended
|
||||
npm -v # 10+
|
||||
convert -version # ImageMagick (brand prebuild)
|
||||
```
|
||||
|
||||
#### Create Resource Group
|
||||
Install deps:
|
||||
|
||||
```bash
|
||||
# Create resource group for production
|
||||
az group create \
|
||||
--name rg-miraclesinmotion-prod \
|
||||
--location eastus2
|
||||
|
||||
# Verify resource group
|
||||
az group show --name rg-miraclesinmotion-prod
|
||||
cd miracles_in_motion
|
||||
npm ci # uses legacy-peer-deps via .npmrc
|
||||
```
|
||||
|
||||
### 1.3 Required Azure Services
|
||||
## 3. Environment variables
|
||||
|
||||
The infrastructure deployment will create:
|
||||
Copy `.env.example` → `.env.local` for local dev. Production frontend is static; secrets belong on **7811** (API) or NPMplus, not in the Vite bundle.
|
||||
|
||||
- **Azure Static Web Apps** (Standard SKU) - Frontend hosting
|
||||
- **Azure Functions** (Premium EP1) - Backend API
|
||||
- **Azure Cosmos DB** - Database
|
||||
- **Azure Key Vault** - Secrets management
|
||||
- **Azure Application Insights** - Monitoring
|
||||
- **Log Analytics Workspace** - Logging
|
||||
- **Azure SignalR** - Real-time communications
|
||||
- **Storage Account** - Function app storage
|
||||
| Variable | Purpose |
|
||||
|----------|---------|
|
||||
| `VITE_STRIPE_PUBLISHABLE_KEY` | Donate page (public key only) |
|
||||
| `VITE_API_BASE_URL` | Override API base (default `/api` via nginx) |
|
||||
| `VITE_GA_MEASUREMENT_ID` | Analytics (optional) |
|
||||
|
||||
### 1.4 Deploy Infrastructure
|
||||
See `env.production.example` for a non-Azure production template.
|
||||
|
||||
```bash
|
||||
# Navigate to infrastructure directory
|
||||
cd infrastructure
|
||||
## 4. Pre-deploy checklist
|
||||
|
||||
# Deploy production infrastructure
|
||||
az deployment group create \
|
||||
--resource-group rg-miraclesinmotion-prod \
|
||||
--template-file main-production.bicep \
|
||||
--parameters main-production.parameters.json \
|
||||
--parameters stripePublicKey="pk_live_YOUR_KEY" \
|
||||
--parameters customDomainName="miraclesinmotion.org" \
|
||||
--parameters enableCustomDomain=true
|
||||
- [ ] `npm run validate:ci` passes (type-check + tests + header WCAG audit)
|
||||
- [ ] `npm run build` succeeds (brand export + Vite)
|
||||
- [ ] NPMplus TLS valid for mim4u.org / www / secure / training
|
||||
- [ ] `./scripts/mim4u-deploy-to-7810.sh` from proxmox repo (or `--dry-run` review)
|
||||
- [ ] Post-deploy: `curl -H 'Host: mim4u.org' http://192.168.11.37/` → 200
|
||||
- [ ] Optional: `npm run a11y:header-audit:live` on production URL
|
||||
|
||||
# Note: Replace pk_live_YOUR_KEY with your actual Stripe public key
|
||||
```
|
||||
## 5. Stripe & DNS (unchanged)
|
||||
|
||||
### 1.5 Get Deployment Outputs
|
||||
- **Stripe:** live keys and webhooks configured on API (7811), not in this static repo.
|
||||
- **Cloudflare / DNS:** A/AAAA or CNAME to public IP per NPMplus; use proxmox `scripts/update-all-dns-to-public-ip.sh --zone-only=mim4u.org --dry-run` before changes.
|
||||
|
||||
```bash
|
||||
# Get deployment outputs
|
||||
az deployment group show \
|
||||
--resource-group rg-miraclesinmotion-prod \
|
||||
--name deployment-name \
|
||||
--query properties.outputs
|
||||
```
|
||||
|
||||
**Important Outputs:**
|
||||
- `staticWebAppName` - Static Web App resource name
|
||||
- `staticWebAppUrl` - Default URL for Static Web App
|
||||
- `functionAppName` - Function App resource name
|
||||
- `keyVaultName` - Key Vault resource name
|
||||
- `appInsightsName` - Application Insights resource name
|
||||
|
||||
---
|
||||
|
||||
## 2. MS Entra (Azure AD) Configuration
|
||||
|
||||
### 2.1 Create App Registration
|
||||
|
||||
#### Using Azure Portal
|
||||
|
||||
1. Navigate to **Azure Portal** → **Microsoft Entra ID** → **App registrations**
|
||||
2. Click **+ New registration**
|
||||
3. Configure:
|
||||
- **Name**: `Miracles In Motion Web App`
|
||||
- **Supported account types**: `Accounts in any organizational directory and personal Microsoft accounts`
|
||||
- **Redirect URI**:
|
||||
- Type: `Single-page application (SPA)`
|
||||
- URI: `https://miraclesinmotion.org` (production)
|
||||
- URI: `https://YOUR_STATIC_WEB_APP.azurestaticapps.net` (staging)
|
||||
|
||||
4. Click **Register**
|
||||
|
||||
#### Using Azure CLI
|
||||
|
||||
```bash
|
||||
# Create app registration
|
||||
az ad app create \
|
||||
--display-name "Miracles In Motion Web App" \
|
||||
--sign-in-audience "AzureADMultipleOrgs" \
|
||||
--web-redirect-uris "https://miraclesinmotion.org" "https://www.miraclesinmotion.org"
|
||||
|
||||
# Get app registration ID
|
||||
APP_ID=$(az ad app list --display-name "Miracles In Motion Web App" --query "[0].appId" -o tsv)
|
||||
echo "App ID: $APP_ID"
|
||||
```
|
||||
|
||||
### 2.2 Configure Authentication
|
||||
|
||||
1. In the app registration, go to **Authentication**
|
||||
2. Enable **ID tokens** (used for implicit and hybrid flows)
|
||||
3. Add redirect URIs:
|
||||
- `https://miraclesinmotion.org`
|
||||
- `https://www.miraclesinmotion.org`
|
||||
- `https://YOUR_STATIC_WEB_APP.azurestaticapps.net`
|
||||
4. Under **Implicit grant and hybrid flows**, enable:
|
||||
- ✅ ID tokens
|
||||
5. Save changes
|
||||
|
||||
### 2.3 Configure API Permissions
|
||||
|
||||
1. Go to **API permissions**
|
||||
2. Click **+ Add a permission**
|
||||
3. Select **Microsoft Graph**
|
||||
4. Add the following **Delegated permissions**:
|
||||
- `User.Read` - Read user profile
|
||||
- `User.ReadBasic.All` - Read all users' basic profiles
|
||||
- `email` - View users' email address
|
||||
- `openid` - Sign users in
|
||||
- `profile` - View users' basic profile
|
||||
5. Click **Add permissions**
|
||||
6. Click **Grant admin consent** (if you have admin rights)
|
||||
|
||||
### 2.4 Create Client Secret (Optional - for server-side flows)
|
||||
|
||||
```bash
|
||||
# Create client secret (valid for 24 months)
|
||||
az ad app credential reset \
|
||||
--id $APP_ID \
|
||||
--display-name "Miracles In Motion Secret" \
|
||||
--years 2
|
||||
|
||||
# Save the secret value immediately - it won't be shown again!
|
||||
```
|
||||
|
||||
### 2.5 Configure App Roles
|
||||
|
||||
1. Go to **App roles** → **+ Create app role**
|
||||
2. Create roles:
|
||||
- **Display name**: `Admin`
|
||||
- **Allowed member types**: `Users/Groups`
|
||||
- **Value**: `Admin`
|
||||
- **Description**: `Administrator access to all features`
|
||||
|
||||
- **Display name**: `Volunteer`
|
||||
- **Allowed member types**: `Users/Groups`
|
||||
- **Value**: `Volunteer`
|
||||
- **Description**: `Volunteer access to assigned tasks`
|
||||
|
||||
- **Display name**: `Resource`
|
||||
- **Allowed member types**: `Users/Groups`
|
||||
- **Value**: `Resource`
|
||||
- **Description**: `Resource provider access`
|
||||
|
||||
3. Save each role
|
||||
|
||||
### 2.6 Assign Users to Roles
|
||||
|
||||
```bash
|
||||
# Get user object ID
|
||||
USER_ID=$(az ad user show --id "[email protected]" --query "id" -o tsv)
|
||||
|
||||
# Get app role ID (Admin role)
|
||||
ROLE_ID=$(az ad app show --id $APP_ID --query "appRoles[?value=='Admin'].id" -o tsv)
|
||||
|
||||
# Assign user to role
|
||||
az ad app assignment create \
|
||||
--app-id $APP_ID \
|
||||
--principal-id $USER_ID \
|
||||
--role-id $ROLE_ID
|
||||
```
|
||||
|
||||
### 2.7 Configure Static Web App Authentication
|
||||
|
||||
1. Navigate to **Static Web App** → **Authentication**
|
||||
2. Click **Add identity provider**
|
||||
3. Select **Microsoft**
|
||||
4. Configure:
|
||||
- **App registration**: Select your app registration
|
||||
- **App ID**: Your app registration ID
|
||||
- **App secret setting name**: `MICROSOFT_CLIENT_SECRET` (optional)
|
||||
5. Save
|
||||
|
||||
#### Using Azure CLI
|
||||
|
||||
```bash
|
||||
# Get Static Web App resource ID
|
||||
SWA_ID=$(az staticwebapp show \
|
||||
--name YOUR_STATIC_WEB_APP_NAME \
|
||||
--resource-group rg-miraclesinmotion-prod \
|
||||
--query "id" -o tsv)
|
||||
|
||||
# Configure Microsoft identity provider
|
||||
az staticwebapp identity assign \
|
||||
--name YOUR_STATIC_WEB_APP_NAME \
|
||||
--resource-group rg-miraclesinmotion-prod
|
||||
|
||||
# Note: Static Web Apps authentication is configured via Azure Portal
|
||||
# or through the staticwebapp.config.json file
|
||||
```
|
||||
|
||||
### 2.8 Update staticwebapp.config.json
|
||||
|
||||
The `staticwebapp.config.json` file should include authentication configuration:
|
||||
|
||||
```json
|
||||
{
|
||||
"routes": [
|
||||
{
|
||||
"route": "/api/*",
|
||||
"allowedRoles": ["anonymous", "authenticated"]
|
||||
},
|
||||
{
|
||||
"route": "/admin/*",
|
||||
"allowedRoles": ["Admin"]
|
||||
},
|
||||
{
|
||||
"route": "/volunteer/*",
|
||||
"allowedRoles": ["Volunteer", "Admin"]
|
||||
},
|
||||
{
|
||||
"route": "/*",
|
||||
"rewrite": "/index.html"
|
||||
}
|
||||
],
|
||||
"auth": {
|
||||
"identityProviders": {
|
||||
"azureActiveDirectory": {
|
||||
"registration": {
|
||||
"openIdIssuer": "https://login.microsoftonline.com/{tenantId}/v2.0",
|
||||
"clientIdSettingName": "AZURE_CLIENT_ID",
|
||||
"clientSecretSettingName": "AZURE_CLIENT_SECRET"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"navigationFallback": {
|
||||
"rewrite": "/index.html",
|
||||
"exclude": ["/api/*", "/admin/*"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.9 Store Configuration in Key Vault
|
||||
|
||||
```bash
|
||||
# Store Azure AD configuration in Key Vault
|
||||
az keyvault secret set \
|
||||
--vault-name YOUR_KEY_VAULT_NAME \
|
||||
--name "azure-client-id" \
|
||||
--value "$APP_ID"
|
||||
|
||||
az keyvault secret set \
|
||||
--vault-name YOUR_KEY_VAULT_NAME \
|
||||
--name "azure-client-secret" \
|
||||
--value "YOUR_CLIENT_SECRET"
|
||||
|
||||
az keyvault secret set \
|
||||
--vault-name YOUR_KEY_VAULT_NAME \
|
||||
--name "azure-tenant-id" \
|
||||
--value "$(az account show --query tenantId -o tsv)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Cloudflare Configuration
|
||||
|
||||
### 3.1 Prerequisites
|
||||
|
||||
- Cloudflare account
|
||||
- Domain registered and added to Cloudflare
|
||||
- DNS management access
|
||||
|
||||
### 3.2 Add Domain to Cloudflare
|
||||
|
||||
1. Log in to **Cloudflare Dashboard**
|
||||
2. Click **Add a site**
|
||||
3. Enter your domain: `miraclesinmotion.org`
|
||||
4. Select a plan (Free plan is sufficient for basic needs)
|
||||
5. Cloudflare will scan your existing DNS records
|
||||
|
||||
### 3.3 Update Nameservers
|
||||
|
||||
1. Copy the nameservers provided by Cloudflare
|
||||
2. Update your domain registrar with these nameservers
|
||||
3. Wait for DNS propagation (24-48 hours)
|
||||
|
||||
### 3.4 Configure DNS Records
|
||||
|
||||
#### Add CNAME Records
|
||||
|
||||
1. Go to **DNS** → **Records**
|
||||
2. Add the following records:
|
||||
|
||||
| Type | Name | Content | Proxy | TTL |
|
||||
|------|------|---------|-------|-----|
|
||||
| CNAME | www | YOUR_STATIC_WEB_APP.azurestaticapps.net | ✅ Proxied | Auto |
|
||||
| CNAME | @ | YOUR_STATIC_WEB_APP.azurestaticapps.net | ✅ Proxied | Auto |
|
||||
|
||||
**Note**: Replace `YOUR_STATIC_WEB_APP` with your actual Static Web App name.
|
||||
|
||||
#### Verify DNS Configuration
|
||||
|
||||
```bash
|
||||
# Check DNS records
|
||||
dig miraclesinmotion.org
|
||||
dig www.miraclesinmotion.org
|
||||
|
||||
# Check Cloudflare proxy status
|
||||
curl -I https://miraclesinmotion.org
|
||||
# Look for "CF-Cache-Status" header
|
||||
```
|
||||
|
||||
### 3.5 Configure SSL/TLS
|
||||
|
||||
1. Go to **SSL/TLS** → **Overview**
|
||||
2. Select **Full (strict)** encryption mode
|
||||
3. Enable **Always Use HTTPS**
|
||||
4. Enable **Automatic HTTPS Rewrites**
|
||||
|
||||
### 3.6 Configure Page Rules
|
||||
|
||||
1. Go to **Rules** → **Page Rules**
|
||||
2. Create rules:
|
||||
|
||||
**Rule 1: Force HTTPS**
|
||||
- URL: `*miraclesinmotion.org/*`
|
||||
- Settings:
|
||||
- Always Use HTTPS: ✅ On
|
||||
- SSL: Full (strict)
|
||||
|
||||
**Rule 2: Cache Static Assets**
|
||||
- URL: `*miraclesinmotion.org/assets/*`
|
||||
- Settings:
|
||||
- Cache Level: Cache Everything
|
||||
- Edge Cache TTL: 1 month
|
||||
|
||||
### 3.7 Configure Security Settings
|
||||
|
||||
1. Go to **Security** → **Settings**
|
||||
2. Configure:
|
||||
- **Security Level**: Medium
|
||||
- **Challenge Passage**: 30 minutes
|
||||
- **Browser Integrity Check**: On
|
||||
- **Privacy Pass Support**: On
|
||||
|
||||
### 3.8 Configure Firewall Rules
|
||||
|
||||
1. Go to **Security** → **WAF** → **Custom rules**
|
||||
2. Create rules to block malicious traffic:
|
||||
|
||||
**Rule: Block Bad Bots**
|
||||
- Expression: `(http.user_agent contains "bot" and not http.user_agent contains "Googlebot")`
|
||||
- Action: Block
|
||||
|
||||
**Rule: Rate Limiting**
|
||||
- Expression: `(http.request.uri.path contains "/api/")`
|
||||
- Action: Challenge
|
||||
- Rate: 100 requests per minute
|
||||
|
||||
### 3.9 Configure Speed Optimization
|
||||
|
||||
1. Go to **Speed** → **Optimization**
|
||||
2. Enable:
|
||||
- ✅ Auto Minify (JavaScript, CSS, HTML)
|
||||
- ✅ Brotli compression
|
||||
- ✅ Rocket Loader (optional)
|
||||
- ✅ Mirage (optional, for mobile)
|
||||
|
||||
### 3.10 Configure Analytics
|
||||
|
||||
1. Go to **Analytics** → **Web Analytics**
|
||||
2. Enable **Web Analytics** for your domain
|
||||
3. Add the tracking script to your application (optional)
|
||||
|
||||
### 3.11 Configure Custom Domain in Azure
|
||||
|
||||
After DNS is configured:
|
||||
|
||||
```bash
|
||||
# Add custom domain to Static Web App
|
||||
az staticwebapp hostname set \
|
||||
--name YOUR_STATIC_WEB_APP_NAME \
|
||||
--resource-group rg-miraclesinmotion-prod \
|
||||
--hostname "miraclesinmotion.org"
|
||||
|
||||
az staticwebapp hostname set \
|
||||
--name YOUR_STATIC_WEB_APP_NAME \
|
||||
--resource-group rg-miraclesinmotion-prod \
|
||||
--hostname "www.miraclesinmotion.org"
|
||||
```
|
||||
|
||||
**Note**: Azure will automatically provision SSL certificates for custom domains.
|
||||
|
||||
### 3.12 Verify Cloudflare Configuration
|
||||
|
||||
```bash
|
||||
# Test DNS resolution
|
||||
nslookup miraclesinmotion.org
|
||||
nslookup www.miraclesinmotion.org
|
||||
|
||||
# Test HTTPS
|
||||
curl -I https://miraclesinmotion.org
|
||||
|
||||
# Test Cloudflare headers
|
||||
curl -I https://miraclesinmotion.org | grep -i "cf-"
|
||||
|
||||
# Expected headers:
|
||||
# CF-Cache-Status: DYNAMIC
|
||||
# CF-Ray: [unique-id]
|
||||
# Server: cloudflare
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Stripe Configuration
|
||||
|
||||
### 4.1 Create Stripe Account
|
||||
|
||||
1. Go to [Stripe Dashboard](https://dashboard.stripe.com)
|
||||
2. Create account or log in
|
||||
3. Complete account verification
|
||||
|
||||
### 4.2 Get API Keys
|
||||
|
||||
1. Go to **Developers** → **API keys**
|
||||
2. Copy:
|
||||
- **Publishable key** (starts with `pk_live_`)
|
||||
- **Secret key** (starts with `sk_live_`) - Keep this secret!
|
||||
|
||||
### 4.3 Configure Webhooks
|
||||
|
||||
1. Go to **Developers** → **Webhooks**
|
||||
2. Click **+ Add endpoint**
|
||||
3. Configure:
|
||||
- **Endpoint URL**: `https://miraclesinmotion.org/api/webhooks/stripe`
|
||||
- **Events to send**: Select relevant events:
|
||||
- `payment_intent.succeeded`
|
||||
- `payment_intent.payment_failed`
|
||||
- `charge.succeeded`
|
||||
- `charge.failed`
|
||||
4. Copy the **Webhook signing secret** (starts with `whsec_`)
|
||||
|
||||
### 4.4 Store Stripe Secrets in Key Vault
|
||||
|
||||
```bash
|
||||
# Store Stripe keys in Key Vault
|
||||
az keyvault secret set \
|
||||
--vault-name YOUR_KEY_VAULT_NAME \
|
||||
--name "stripe-publishable-key" \
|
||||
--value "pk_live_YOUR_KEY"
|
||||
|
||||
az keyvault secret set \
|
||||
--vault-name YOUR_KEY_VAULT_NAME \
|
||||
--name "stripe-secret-key" \
|
||||
--value "sk_live_YOUR_KEY"
|
||||
|
||||
az keyvault secret set \
|
||||
--vault-name YOUR_KEY_VAULT_NAME \
|
||||
--name "stripe-webhook-secret" \
|
||||
--value "whsec_YOUR_SECRET"
|
||||
```
|
||||
|
||||
### 4.5 Update Function App Settings
|
||||
|
||||
```bash
|
||||
# Get secrets from Key Vault
|
||||
STRIPE_SECRET=$(az keyvault secret show \
|
||||
--vault-name YOUR_KEY_VAULT_NAME \
|
||||
--name "stripe-secret-key" \
|
||||
--query "value" -o tsv)
|
||||
|
||||
# Update Function App settings
|
||||
az functionapp config appsettings set \
|
||||
--name YOUR_FUNCTION_APP_NAME \
|
||||
--resource-group rg-miraclesinmotion-prod \
|
||||
--settings "[email protected](SecretUri=https://YOUR_KEY_VAULT_NAME.vault.azure.net/secrets/stripe-secret-key/)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Environment Variables
|
||||
|
||||
### 5.1 Create Environment File Template
|
||||
|
||||
Create `.env.production` file:
|
||||
|
||||
```bash
|
||||
# Azure Configuration
|
||||
AZURE_STATIC_WEB_APP_URL=https://miraclesinmotion.org
|
||||
AZURE_FUNCTION_APP_URL=https://YOUR_FUNCTION_APP.azurewebsites.net
|
||||
AZURE_CLIENT_ID=your-azure-client-id
|
||||
AZURE_TENANT_ID=your-azure-tenant-id
|
||||
|
||||
# Stripe Configuration
|
||||
VITE_STRIPE_PUBLISHABLE_KEY=pk_live_YOUR_KEY
|
||||
STRIPE_SECRET_KEY=sk_live_YOUR_KEY
|
||||
STRIPE_WEBHOOK_SECRET=whsec_YOUR_SECRET
|
||||
|
||||
# Cosmos DB Configuration
|
||||
COSMOS_DATABASE_NAME=MiraclesInMotion
|
||||
COSMOS_ENDPOINT=https://YOUR_COSMOS_ACCOUNT.documents.azure.com:443/
|
||||
|
||||
# Application Insights
|
||||
APPLICATIONINSIGHTS_CONNECTION_STRING=InstrumentationKey=YOUR_KEY
|
||||
|
||||
# Key Vault
|
||||
KEY_VAULT_URL=https://YOUR_KEY_VAULT_NAME.vault.azure.net/
|
||||
|
||||
# SignalR
|
||||
SIGNALR_CONNECTION_STRING=Endpoint=https://YOUR_SIGNALR.service.signalr.net;AccessKey=YOUR_KEY;
|
||||
|
||||
# Custom Domain
|
||||
CUSTOM_DOMAIN=miraclesinmotion.org
|
||||
```
|
||||
|
||||
### 5.2 Update Static Web App Configuration
|
||||
|
||||
```bash
|
||||
# Set environment variables for Static Web App
|
||||
az staticwebapp appsettings set \
|
||||
--name YOUR_STATIC_WEB_APP_NAME \
|
||||
--resource-group rg-miraclesinmotion-prod \
|
||||
--setting-names "VITE_STRIPE_PUBLISHABLE_KEY=pk_live_YOUR_KEY" \
|
||||
"AZURE_CLIENT_ID=your-azure-client-id" \
|
||||
"AZURE_TENANT_ID=your-azure-tenant-id"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Pre-Deployment Checklist
|
||||
|
||||
### 6.1 Azure Checklist
|
||||
|
||||
- [ ] Azure subscription created and active
|
||||
- [ ] Resource group created
|
||||
- [ ] Infrastructure deployed via Bicep
|
||||
- [ ] All Azure resources created successfully
|
||||
- [ ] Key Vault configured with secrets
|
||||
- [ ] Application Insights configured
|
||||
- [ ] Static Web App created
|
||||
- [ ] Function App created and configured
|
||||
- [ ] Cosmos DB database and containers created
|
||||
- [ ] RBAC permissions configured
|
||||
|
||||
### 6.2 MS Entra Checklist
|
||||
|
||||
- [ ] App registration created
|
||||
- [ ] Redirect URIs configured
|
||||
- [ ] API permissions granted
|
||||
- [ ] App roles created (Admin, Volunteer, Resource)
|
||||
- [ ] Users assigned to roles
|
||||
- [ ] Client ID and Tenant ID recorded
|
||||
- [ ] Client secret created (if needed)
|
||||
- [ ] Static Web App authentication configured
|
||||
|
||||
### 6.3 Cloudflare Checklist
|
||||
|
||||
- [ ] Domain added to Cloudflare
|
||||
- [ ] Nameservers updated at registrar
|
||||
- [ ] DNS records configured (CNAME for www and @)
|
||||
- [ ] SSL/TLS set to Full (strict)
|
||||
- [ ] Always Use HTTPS enabled
|
||||
- [ ] Page rules configured
|
||||
- [ ] Firewall rules configured
|
||||
- [ ] Security settings configured
|
||||
- [ ] Speed optimization enabled
|
||||
- [ ] Custom domain added to Azure Static Web App
|
||||
|
||||
### 6.4 Stripe Checklist
|
||||
|
||||
- [ ] Stripe account created and verified
|
||||
- [ ] API keys obtained (publishable and secret)
|
||||
- [ ] Webhook endpoint configured
|
||||
- [ ] Webhook signing secret obtained
|
||||
- [ ] Secrets stored in Key Vault
|
||||
- [ ] Function App configured with Stripe keys
|
||||
|
||||
### 6.5 Application Checklist
|
||||
|
||||
- [ ] Environment variables configured
|
||||
- [ ] staticwebapp.config.json updated
|
||||
- [ ] Authentication flow tested
|
||||
- [ ] API endpoints tested
|
||||
- [ ] Stripe integration tested
|
||||
- [ ] Monitoring configured
|
||||
- [ ] Logging configured
|
||||
|
||||
---
|
||||
|
||||
## 7. Post-Deployment Verification
|
||||
|
||||
### 7.1 Verify Azure Resources
|
||||
|
||||
```bash
|
||||
# Check Static Web App status
|
||||
az staticwebapp show \
|
||||
--name YOUR_STATIC_WEB_APP_NAME \
|
||||
--resource-group rg-miraclesinmotion-prod
|
||||
|
||||
# Check Function App status
|
||||
az functionapp show \
|
||||
--name YOUR_FUNCTION_APP_NAME \
|
||||
--resource-group rg-miraclesinmotion-prod
|
||||
|
||||
# Check Cosmos DB status
|
||||
az cosmosdb show \
|
||||
--name YOUR_COSMOS_ACCOUNT \
|
||||
--resource-group rg-miraclesinmotion-prod
|
||||
```
|
||||
|
||||
### 7.2 Verify Authentication
|
||||
|
||||
1. Navigate to `https://miraclesinmotion.org`
|
||||
2. Click "Sign In"
|
||||
3. Verify Microsoft authentication flow
|
||||
4. Verify user roles are assigned correctly
|
||||
5. Test role-based access control
|
||||
|
||||
### 7.3 Verify Cloudflare
|
||||
|
||||
```bash
|
||||
# Test DNS resolution
|
||||
dig miraclesinmotion.org
|
||||
dig www.miraclesinmotion.org
|
||||
|
||||
# Test HTTPS
|
||||
curl -I https://miraclesinmotion.org
|
||||
|
||||
# Verify Cloudflare headers
|
||||
curl -I https://miraclesinmotion.org | grep -i "cf-"
|
||||
```
|
||||
|
||||
### 7.4 Verify Stripe Integration
|
||||
|
||||
1. Test donation flow on the website
|
||||
2. Verify webhook events are received
|
||||
3. Check Stripe dashboard for transactions
|
||||
4. Verify payment processing
|
||||
|
||||
### 7.5 Verify Monitoring
|
||||
|
||||
1. Check Application Insights for telemetry
|
||||
2. Verify logs are being collected
|
||||
3. Set up alerts for critical issues
|
||||
4. Test error tracking
|
||||
|
||||
### 7.6 Performance Testing
|
||||
|
||||
```bash
|
||||
# Test page load times
|
||||
curl -w "@curl-format.txt" -o /dev/null -s https://miraclesinmotion.org
|
||||
|
||||
# Test API response times
|
||||
curl -w "@curl-format.txt" -o /dev/null -s https://miraclesinmotion.org/api/donations
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Troubleshooting
|
||||
|
||||
### 8.1 Common Issues
|
||||
|
||||
#### Authentication Not Working
|
||||
|
||||
- Verify app registration redirect URIs
|
||||
- Check Static Web App authentication configuration
|
||||
- Verify user roles are assigned
|
||||
- Check browser console for errors
|
||||
|
||||
#### DNS Not Resolving
|
||||
|
||||
- Verify nameservers are updated
|
||||
- Wait for DNS propagation (24-48 hours)
|
||||
- Check Cloudflare DNS records
|
||||
- Verify CNAME records point to correct Azure endpoint
|
||||
|
||||
#### SSL Certificate Issues
|
||||
|
||||
- Verify Cloudflare SSL mode is "Full (strict)"
|
||||
- Check Azure Static Web App custom domain configuration
|
||||
- Wait for SSL certificate provisioning (can take up to 24 hours)
|
||||
|
||||
#### Stripe Webhook Not Working
|
||||
|
||||
- Verify webhook endpoint URL is correct
|
||||
- Check webhook signing secret
|
||||
- Verify Function App is receiving webhook events
|
||||
- Check Function App logs for errors
|
||||
|
||||
### 8.2 Support Resources
|
||||
|
||||
- **Azure Documentation**: https://docs.microsoft.com/azure
|
||||
- **MS Entra Documentation**: https://docs.microsoft.com/azure/active-directory
|
||||
- **Cloudflare Documentation**: https://developers.cloudflare.com
|
||||
- **Stripe Documentation**: https://stripe.com/docs
|
||||
|
||||
---
|
||||
|
||||
## 9. Next Steps
|
||||
|
||||
After completing all prerequisites:
|
||||
|
||||
1. Deploy the application using the deployment script
|
||||
2. Verify all functionality
|
||||
3. Set up monitoring and alerts
|
||||
4. Configure backup and disaster recovery
|
||||
5. Set up CI/CD pipeline
|
||||
6. Schedule regular security audits
|
||||
7. Set up performance monitoring
|
||||
|
||||
---
|
||||
|
||||
## 10. Security Best Practices
|
||||
|
||||
1. **Never commit secrets to source control**
|
||||
2. **Use Key Vault for all secrets**
|
||||
3. **Enable MFA for all Azure accounts**
|
||||
4. **Regularly rotate API keys and secrets**
|
||||
5. **Monitor for suspicious activity**
|
||||
6. **Keep dependencies updated**
|
||||
7. **Use HTTPS everywhere**
|
||||
8. **Implement rate limiting**
|
||||
9. **Regular security audits**
|
||||
10. **Follow principle of least privilege**
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: January 2025
|
||||
**Maintained by**: Miracles In Motion Development Team
|
||||
## 6. Legacy Azure documentation
|
||||
|
||||
Historical docs under `docs/deployment/` and `docs/phases/` may still mention Azure. Treat them as **archived**; do not follow for new deploys.
|
||||
|
||||
+43
-108
@@ -1,139 +1,74 @@
|
||||
# Quick Start Guide
|
||||
|
||||
Fast path to get the Miracles in Motion project running, tested, and deployed.
|
||||
Fast path to run, test, and deploy the Miracles in Motion public site.
|
||||
|
||||
## 1. Prerequisites
|
||||
| Tool | Recommended Version | Notes |
|
||||
|------|---------------------|-------|
|
||||
| Node.js | 20.x / 22.x | Functions runtime Standard supports node:20; local dev can use 22 |
|
||||
| npm | 10+ | Bundled with recent Node |
|
||||
| Azure CLI | >= 2.60 | For infra & Static Web Apps commands |
|
||||
| SWA CLI (@azure/static-web-apps-cli) | latest | Local API + front-end emulation |
|
||||
| Git | latest | Source control |
|
||||
| WSL2 | Enabled | Shell environment (Ubuntu recommended) |
|
||||
|
||||
| Tool | Version | Notes |
|
||||
|------|---------|-------|
|
||||
| Node.js | 22.x | CI and local dev |
|
||||
| npm | 10+ | Use `npm ci` (`.npmrc` sets `legacy-peer-deps`) |
|
||||
| ImageMagick | any recent | Required for `npm run brand:export` / `prebuild` |
|
||||
| Git | latest | |
|
||||
|
||||
Production deploy additionally requires LAN access to Proxmox — see [PROXMOX_DEPLOYMENT.md](./deployment/PROXMOX_DEPLOYMENT.md).
|
||||
|
||||
## 2. Clone & install
|
||||
|
||||
```bash
|
||||
# Verify versions
|
||||
node -v
|
||||
npm -v
|
||||
az version
|
||||
git clone https://github.com/Order-of-Hospitallers/miracles_in_motion.git
|
||||
cd miracles_in_motion
|
||||
npm ci
|
||||
```
|
||||
|
||||
## 2. Clone & Install
|
||||
```bash
|
||||
git clone https://github.com/Miracles-In-Motion/public-web.git
|
||||
cd public-web
|
||||
npm install --legacy-peer-deps
|
||||
cd api && npm install --legacy-peer-deps && cd ..
|
||||
```
|
||||
## 3. Environment
|
||||
|
||||
## 3. Environment Setup
|
||||
Create a `.env.local` (frontend) and `api/local.settings.json` (Azure Functions) as needed.
|
||||
Copy `.env.example` to `.env.local` (do not commit secrets):
|
||||
|
||||
Example `.env.local` (do NOT commit secrets):
|
||||
```
|
||||
```env
|
||||
VITE_API_BASE=/api
|
||||
VITE_STRIPE_PUBLISHABLE_KEY=pk_test_xxx
|
||||
VITE_DEFAULT_LANGUAGE=en
|
||||
VITE_SUPPORTED_LANGUAGES=en,es,fr,de,zh,ar,pt,ru
|
||||
```
|
||||
|
||||
Example `api/local.settings.json`:
|
||||
```json
|
||||
{
|
||||
"IsEncrypted": false,
|
||||
"Values": {
|
||||
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
|
||||
"FUNCTIONS_WORKER_RUNTIME": "node"
|
||||
}
|
||||
}
|
||||
```
|
||||
## 4. Run locally
|
||||
|
||||
## 4. Run Locally (Integrated)
|
||||
Use SWA CLI to serve front-end + Functions together.
|
||||
```bash
|
||||
npm run build:api # Optional: compile API TypeScript
|
||||
swa start http://localhost:5173 --api-location ./api --devserver-run-command "npm run dev" --api-language node
|
||||
npm run dev
|
||||
# http://localhost:5173
|
||||
```
|
||||
If you prefer two terminals:
|
||||
|
||||
## 5. Test & validate
|
||||
|
||||
```bash
|
||||
npm run dev # Front-end (Vite)
|
||||
cd api && npm start # Functions runtime
|
||||
npm test # unit tests (Vitest)
|
||||
npm run type-check # tsc --noEmit
|
||||
npm run a11y:header-audit # WCAG header contrast tokens
|
||||
npm run validate:ci # all three above
|
||||
```
|
||||
|
||||
## 5. Testing
|
||||
## 6. Production build
|
||||
|
||||
```bash
|
||||
npm test # Front-end tests (Vitest / Testing Library)
|
||||
npm run build
|
||||
# output: dist/
|
||||
npm run preview # optional local preview
|
||||
```
|
||||
Add more tests under `src/components/__tests__/` or `src/test`.
|
||||
|
||||
## 6. Build
|
||||
## 7. Deploy to mim4u.org (Proxmox)
|
||||
|
||||
From the **proxmox** repo on operator LAN:
|
||||
|
||||
```bash
|
||||
npm run build # Produces front-end dist/
|
||||
cd api && npm run build # Compiles Functions to dist (if configured)
|
||||
./scripts/mim4u-deploy-to-7810.sh
|
||||
```
|
||||
|
||||
## 7. Azure Deployment (Static Web App Standard)
|
||||
Verify:
|
||||
|
||||
```bash
|
||||
# Login
|
||||
az login
|
||||
|
||||
# Ensure resource group exists
|
||||
az group create --name rg-mim-prod --location eastus2
|
||||
|
||||
# Create Static Web App (front-end + managed functions)
|
||||
az staticwebapp create \
|
||||
--name mim-prod-web-standard \
|
||||
--resource-group rg-mim-prod \
|
||||
--location eastus2 \
|
||||
--source . \
|
||||
--branch main \
|
||||
--app-location / \
|
||||
--output-location dist
|
||||
curl -I -H 'Host: mim4u.org' http://192.168.11.37/
|
||||
```
|
||||
|
||||
To deploy updates without GitHub Actions (manual token):
|
||||
```bash
|
||||
TOKEN=$(az staticwebapp secrets list --name mim-prod-web-standard --resource-group rg-mim-prod --query properties.apiKey -o tsv)
|
||||
swa deploy ./dist --env production --deployment-token $TOKEN
|
||||
```
|
||||
## 8. CI
|
||||
|
||||
## 8. Custom Domain
|
||||
1. Add CNAME `www` → `<defaultHostname>`.
|
||||
2. Set hostname:
|
||||
```bash
|
||||
az staticwebapp hostname set \
|
||||
--name mim-prod-web-standard \
|
||||
--resource-group rg-mim-prod \
|
||||
--hostname miraclesinmotion.org
|
||||
```
|
||||
Azure provisions SSL automatically.
|
||||
|
||||
## 9. Configuration (staticwebapp.config.json)
|
||||
Key elements:
|
||||
- `navigationFallback` ensures SPA routing.
|
||||
- `globalHeaders` for security (CSP, HSTS). Adjust `Content-Security-Policy` as integrations evolve.
|
||||
|
||||
## 10. Useful Scripts
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
| `npm run dev` | Start Vite dev server |
|
||||
| `npm test` | Run tests |
|
||||
| `npm run build` | Build front-end |
|
||||
| `npm run analyze` | (If defined) Bundle analysis |
|
||||
|
||||
## 11. Troubleshooting
|
||||
| Issue | Resolution |
|
||||
|-------|------------|
|
||||
| 404 on portal route | Ensure hash routing `/#/portals` or SPA fallback set |
|
||||
| Functions 500 error | Check `api` logs, run locally with `func start` if using standalone Functions |
|
||||
| CSP blocking script | Update CSP in `staticwebapp.config.json` to allow required domain |
|
||||
| Node version mismatch | Use Node 20 for SWA managed functions, 22 locally if desired |
|
||||
|
||||
## 12. Next Steps
|
||||
- Configure GitHub Actions for CI/CD.
|
||||
- Add monitoring (Application Insights) if using standalone Functions.
|
||||
- Replace test Stripe keys with live keys in production.
|
||||
|
||||
---
|
||||
Last updated: 2025-11-11
|
||||
GitHub Actions runs on PR (`validate.yml`) and main push (`deploy.yml`). See [DEPLOYMENT_PREREQUISITES.md](./DEPLOYMENT_PREREQUISITES.md).
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
# MIM4U production deployment (Proxmox)
|
||||
|
||||
Production for **https://mim4u.org** is served from **VMID 7810** (mim-web-1 @ `192.168.11.37`) behind NPMplus. Azure Static Web Apps and Azure Functions are **not** used.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Node.js 22.x, npm 10+
|
||||
- ImageMagick (`convert`) for `npm run brand:export` (runs on `prebuild`)
|
||||
- LAN SSH to Proxmox host **192.168.11.12** (r630-02)
|
||||
- Sibling repo layout: `../proxmox` beside `miracles_in_motion`, or set `MIM_ROOT`
|
||||
|
||||
## Build and deploy
|
||||
|
||||
From the **proxmox** repo (operator LAN):
|
||||
|
||||
```bash
|
||||
./scripts/mim4u-deploy-to-7810.sh
|
||||
```
|
||||
|
||||
Or manually:
|
||||
|
||||
```bash
|
||||
cd ~/projects/miracles_in_motion
|
||||
npm run build
|
||||
# then tar dist/ into VMID 7810 /var/www/html (see deploy script)
|
||||
```
|
||||
|
||||
The deploy script **wipes** `/var/www/html/*` before extract to avoid stale PWA/JS bundles.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
curl -I -H 'Host: mim4u.org' http://192.168.11.37/
|
||||
curl -I -H 'Host: mim4u.org' http://192.168.11.37/brand/logo-horizontal-nav.svg
|
||||
```
|
||||
|
||||
Public HTTPS: NPMplus proxy hosts for `mim4u.org`, `www.mim4u.org`, `secure.mim4u.org`, `training.mim4u.org` → `192.168.11.37:80`.
|
||||
|
||||
## CI (GitHub Actions)
|
||||
|
||||
| Workflow | Trigger | Purpose |
|
||||
|----------|---------|---------|
|
||||
| `validate.yml` | Pull requests | type-check, tests, header WCAG audit, build |
|
||||
| `deploy.yml` | Push to `main` | validate + GitHub Pages artifact (optional mirror) |
|
||||
| `a11y-live.yml` | Weekly / manual | Lighthouse accessibility on live mim4u.org |
|
||||
|
||||
Canonical production traffic is **Proxmox 7810**, not GitHub Pages.
|
||||
|
||||
## API backend
|
||||
|
||||
`/api/*` on mim4u.org is proxied by nginx on **7810** to **VMID 7811** (mim-api-1 @ `192.168.11.36:3001`). API deployment is separate from this frontend repo.
|
||||
|
||||
## Related proxmox docs
|
||||
|
||||
- `docs/04-configuration/ALL_VMIDS_ENDPOINTS.md` — VMIDs and FQDNs
|
||||
- `docs/04-configuration/E2E_ENDPOINTS_LIST.md` — public routing verification
|
||||
+13
-39
@@ -1,46 +1,20 @@
|
||||
# 📚 Deployment Documentation
|
||||
# Deployment documentation
|
||||
|
||||
This directory contains all deployment-related documentation for the Miracles In Motion project.
|
||||
## Canonical (use this)
|
||||
|
||||
---
|
||||
| Doc | Purpose |
|
||||
|-----|---------|
|
||||
| [PROXMOX_DEPLOYMENT.md](./PROXMOX_DEPLOYMENT.md) | Production deploy to VMID 7810 |
|
||||
| [../DEPLOYMENT_PREREQUISITES.md](../DEPLOYMENT_PREREQUISITES.md) | Checklist and env vars |
|
||||
| [../QuickStart.md](../QuickStart.md) | Local dev, test, build |
|
||||
|
||||
## 📋 Documentation Files
|
||||
Proxmox operator script: `../../proxmox/scripts/mim4u-deploy-to-7810.sh` (sibling repo).
|
||||
|
||||
### Status & Reports
|
||||
- **DEPLOYMENT_STATUS.md** - Current deployment status and checklist
|
||||
- **DEPLOYMENT_STATUS_FINAL.md** - Final deployment status summary
|
||||
- **DEPLOYMENT_VERIFICATION_REPORT.md** - Deployment verification results
|
||||
- **DEPLOYMENT_COMPLETE.md** - Deployment completion summary
|
||||
## Archived (Azure — removed 2026-06)
|
||||
|
||||
### Guides & Instructions
|
||||
- **DEPLOYMENT_SETUP_README.md** - Deployment setup overview
|
||||
- **ALL_NEXT_STEPS.md** - Complete next steps for deployment
|
||||
- **COMPLETE_NEXT_STEPS.md** - Complete deployment steps guide
|
||||
- **DEPLOYMENT_COMPLETE_GUIDE.md** - Quick deployment guide
|
||||
- **FINAL_DEPLOYMENT_STEPS.md** - Final deployment steps
|
||||
The following files describe **deprecated** Azure Static Web Apps / Functions / Bicep flows. Do not use for new deployments:
|
||||
|
||||
### Next Steps & Tasks
|
||||
- **DEPLOYMENT_NEXT_STEPS.md** - Next steps for deployment
|
||||
- **NEXT_STEPS_COMPLETE.md** - Next steps completion summary
|
||||
- **REMAINING_TASKS_COMPLETE.md** - Remaining tasks summary
|
||||
|
||||
### Cloudflare & Domain
|
||||
- **CLOUDFLARE_SETUP.md** - Cloudflare setup instructions
|
||||
- **CLOUDFLARE_AUTOMATION_COMPLETE.md** - Cloudflare automation guide
|
||||
- **CUSTOM_DOMAIN_SETUP.md** - Custom domain configuration
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
1. **Check Current Status:** Start with `DEPLOYMENT_STATUS.md`
|
||||
2. **Follow Next Steps:** See `ALL_NEXT_STEPS.md` for complete guide
|
||||
3. **Cloudflare Setup:** See `CLOUDFLARE_SETUP.md` if using Cloudflare
|
||||
4. **Custom Domain:** See `CUSTOM_DOMAIN_SETUP.md` for domain configuration
|
||||
|
||||
---
|
||||
|
||||
## 📝 Note
|
||||
|
||||
All deployment documentation has been organized here from the project root for better structure and easier access.
|
||||
- `CLOUDFLARE_*.md`, `DEPLOYMENT_*.md`, `FINAL_*.md`, `ALL_NEXT_STEPS.md`, etc. in this folder
|
||||
- `docs/phases/*DEPLOYMENT*`, `PRODUCTION_DEPLOYMENT_SUCCESS.md`
|
||||
|
||||
Production is **https://mim4u.org** on Proxmox **7810** only.
|
||||
|
||||
Reference in New Issue
Block a user