Azure Infrastructure
Overview
Impact Pulse is deployed on Microsoft Azure using a combination of managed services optimized for cost efficiency and scalability. The infrastructure is provisioned via Terraform and deployed through GitHub Actions CI/CD pipelines.
Resource Group
All resources live under a single resource group for simplified management.
| Property | Value |
|---|---|
| Name | rg-catalyzeup |
| Region | East US |
| Subscription | CatalyzeUp |
Core Resources
Cosmos DB (MongoDB API)
The primary database, using Azure Cosmos DB with the MongoDB API in serverless mode for cost optimization.
| Property | Value |
|---|---|
| Account Name | cosmos-catalyzeup |
| API | MongoDB |
| Capacity Mode | Serverless |
| Database | impactpulse |
| Consistency | Session |
| Backup | Continuous (7-day retention) |
Collections:
usersorganizationsorganization_membersorganization_invitationssurveysquestionssurvey_sessionssurvey_responsesmaslow_scoresemail_reminders
Why Serverless: For a pet project with unpredictable traffic, serverless billing (per-request) is significantly cheaper than provisioned throughput. Scales to zero when idle.
Redis Cache
Azure Cache for Redis, used for session caching, rate limiting, and Celery task queue.
| Property | Value |
|---|---|
| Name | redis-catalyzeup |
| SKU | Basic C0 |
| Memory | 250 MB |
| TLS | Enabled |
| Port | 6380 (TLS) |
Use Cases:
- JWT token blacklisting
- Session data caching
- Rate limiting counters
- Celery broker for background tasks
- Survey progress auto-save buffer
App Service (Backend API)
The FastAPI backend runs on Azure App Service.
| Property | Value |
|---|---|
| Name | app-impactpulse-api |
| Runtime | Python 3.11 |
| Plan | B1 (Basic) |
| OS | Linux |
| Always On | Yes |
| Custom Domain | impactpulse-api.catalyzeupdev.com |
Configuration:
- Gunicorn with Uvicorn workers
- Health check endpoint:
/api/v1/health - Deployment slots: Production only (B1 tier)
- Managed Identity for Cosmos DB and Redis access
Environment Variables:
MONGODB_URL=<cosmos-connection-string>
MONGODB_DATABASE=impactpulse
REDIS_URL=<redis-connection-string>
SECRET_KEY=<from-key-vault>
FRONTEND_URL=https://impactpulse.catalyzeupdev.com
ENVIRONMENT=production
DEBUG=false
RESEND_API_KEY=<from-key-vault>
Static Web App (Frontend)
The React + Vite frontend is deployed as an Azure Static Web App.
| Property | Value |
|---|---|
| Name | swa-impactpulse |
| SKU | Free |
| Framework | React (Vite) |
| Custom Domain | impactpulse.catalyzeupdev.com |
| API Backend | Proxied to App Service |
Build Configuration:
- App location:
frontend - Output location:
dist - Build command:
npm run build
Cloudflare DNS
DNS management and CDN/security are handled through Cloudflare.
| Record | Type | Value | Proxy |
|---|---|---|---|
impactpulse.catalyzeupdev.com |
CNAME | SWA default hostname | Orange (proxied) |
impactpulse-api.catalyzeupdev.com |
CNAME | App Service hostname | Orange (proxied) |
Cloudflare Features:
- SSL/TLS: Full (strict)
- Always Use HTTPS: On
- Minimum TLS Version: 1.2
- DDoS protection (free tier)
- CDN caching for static assets
CI/CD Pipeline
GitHub Actions
Both frontend and backend have automated deployment pipelines triggered on push to the main branch.
Backend Workflow (.github/workflows/deploy-backend.yml):
- Checkout code
- Set up Python 3.11
- Install dependencies
- Run tests
- Deploy to App Service via
az webapp deploy
Frontend Workflow (.github/workflows/deploy-frontend.yml):
- Checkout code
- Set up Node.js
- Install dependencies
- Build (
npm run build) - Deploy to Static Web App via Azure/static-web-apps-deploy action
Deployment Strategy
- Backend: Direct deployment to App Service (B1 does not support deployment slots)
- Frontend: Atomic deployment via SWA (automatic rollback on failure)
- Database: Schema changes applied through application startup (MongoDB is schemaless)
Security
Key Vault
Sensitive configuration is stored in Azure Key Vault.
| Secret | Description |
|---|---|
cosmos-connection-string |
Cosmos DB MongoDB connection string |
redis-connection-string |
Redis Cache connection string |
jwt-secret-key |
JWT signing key |
resend-api-key |
Resend email API key |
google-oauth-client-id |
Google OAuth client ID |
google-oauth-client-secret |
Google OAuth client secret |
Network Security
- Cosmos DB: IP firewall restricting access to App Service and developer IPs
- Redis: Access only from App Service VNet (when upgraded)
- App Service: HTTPS only, TLS 1.2 minimum
- Static Web App: HTTPS only via Cloudflare
Cost Optimization
Current Monthly Estimate
| Resource | SKU | Estimated Cost |
|---|---|---|
| Cosmos DB (serverless) | Serverless | ~$1-5/month (low traffic) |
| Redis Cache | Basic C0 | ~$16/month |
| App Service | B1 Linux | ~$13/month |
| Static Web App | Free | $0/month |
| Cloudflare | Free | $0/month |
| Total | ~$30-34/month |
Scaling Path
When traffic grows:
- Cosmos DB: Remains serverless until > 1M requests/month, then switch to provisioned autoscale
- Redis: Upgrade to Standard C1 for persistence and replication
- App Service: Scale up to S1/P1v3 for deployment slots and better performance
- Static Web App: Upgrade to Standard for custom auth, larger file sizes
Monitoring
Application Insights
- Connected to App Service for backend monitoring
- Request tracing and performance metrics
- Exception tracking and alerting
- Custom metrics for survey completions, reminder delivery
Health Checks
- App Service: Built-in health check on
/api/v1/health - Cosmos DB: Connection monitoring via Application Insights
- Redis: Connection pool monitoring
Alerts
- Backend 5xx error rate > 5%
- Response time P95 > 2 seconds
- Cosmos DB RU consumption > 80% (if provisioned)
- Redis memory usage > 80%
Disaster Recovery
Backup Strategy
- Cosmos DB: Continuous backup with 7-day point-in-time restore
- Redis: No persistence on Basic tier (cache only, data reconstructed from DB)
- App Service: Source code in GitHub (redeployable)
- Static Web App: Source code in GitHub (redeployable)
Recovery Procedures
- Database corruption: Restore from Cosmos DB continuous backup
- Backend failure: Redeploy from GitHub Actions
- Frontend failure: Redeploy from GitHub Actions
- Redis failure: Restart cache (data is ephemeral, recreated by application)