CloudBlocks — Deployment Guide¶
Audience: Contributors / DevOps | Status: Partially stale — backend deployment references (PostgreSQL, Redis, Azure Container Apps) describe planned infrastructure not yet implemented. Frontend deployment via GitHub Pages is current. | Verified against: v0.43.0
Overview¶
CloudBlocks is designed for lightweight deployment with minimal infrastructure. The frontend is a static SPA, and the backend is a thin orchestration layer. Production deployments use PostgreSQL for metadata and Redis for session caching, enabling horizontal scaling with multiple container replicas.
~~For the canonical multi-environment cloud strategy (local/staging/production, promotion model, and cost targets), see ENVIRONMENT_STRATEGY.md.~~ (Removed — ENVIRONMENT_STRATEGY.md was deleted as speculative future infrastructure.)
⚠️ Stale backend references: Sections on PostgreSQL, Redis, Azure Container Apps, and multi-environment promotion describe planned infrastructure. The frontend is a static SPA deployed to GitHub Pages; the backend currently runs only on local development setups. The deleted
ENVIRONMENT_STRATEGY.mdwas a companion to this future infrastructure plan.
Terminology¶
CloudBlocks uses four distinct terms for its deployment lifecycle. Every document, workflow, and UI label must use these definitions consistently.
| Term | Definition | Example |
|---|---|---|
| Deploy | Push code or infrastructure to a specific environment. Triggered by a CI/CD pipeline. | "Deploy to staging" — deploy.yml runs on push to main. |
| Promote | Move a tested version from staging to production. A controlled, deliberate action with pre-checks (tests passed, cost reviewed, diff approved). |
"Promote to production" — promote.yml runs after manual approval. |
| Rollback | Revert an environment to a previous known-good version. Used for emergency or planned recovery. | "Rollback production to v0.17.0" — restores the last stable release. |
| Release | Tag a version as a user-facing milestone. A labeling action, not a deployment action. Releases are created after a milestone closes. | "Release v0.18.0" — git tag + GitHub Release. |
| Pipeline | An automated CI/CD workflow (GitHub Actions). | "The CI pipeline passed." |
| Revision | A specific deployed instance of the application (Azure Container Apps concept). | "New revision is active." |
| Image Tag | The unique identifier for a container image (git SHA). | "Promote image tag abc123..." |
Usage Guidelines¶
- Deploy ≠ Release. A deploy pushes code to an environment; a release tags a version for users. They happen at different times.
- Promote ≠ Deploy. A promotion is a specific kind of deployment that moves a validated staging build to production. Use "promote" when the source is staging and the target is production.
- Rollback ≠ Redeploy. A rollback reverts to a previous version. A redeploy pushes the same version again. Use "rollback" only when reverting.
- Workflow naming convention:
deploy.yml(staging),promote.yml(staging → production). Never name a promote workflow "deploy-production."
Local Development¶
Prerequisites¶
- Node.js >= 20
- Python >= 3.10
- pnpm >= 9
- Docker & Docker Compose (optional, for backend services)
Quick Start¶
# Clone and install
git clone https://github.com/yeongseon/cloudblocks.git
cd cloudblocks
make install
# Start frontend dev server (no backend needed for Milestone 1)
cd apps/web && pnpm dev
# Or use Makefile
make dev
Development URLs¶
| Service | URL |
|---|---|
| Frontend | http://localhost:5173 |
| Backend API (Milestone 5+) | http://localhost:8000 |
| API Docs (Swagger) | http://localhost:8000/docs |
Architecture¶
Single-Replica (Development / Staging)¶
Static Frontend (SPA)
↓
Backend API (Single Container)
↓
┌─────────────┬──────────────┐
│ PostgreSQL │ GitHub API │
│ (metadata) │ (data store) │
├─────────────┤ │
│ Redis │ │
│ (sessions) │ │
└─────────────┴──────────────┘
Multi-Replica (Production)¶
Azure Static Web App (SPA)
↓ (HTTPS)
Azure Container Apps
┌─────────┬─────────┬─────────┐
│Replica 1│Replica 2│Replica N│ ← HTTP auto-scaling
└────┬────┴────┬────┴────┬────┘
│ │ │
├─────────┼─────────┤
↓ ↓ ↓
┌──────────────────────────────┐
│ Azure Database for PostgreSQL│ ← Shared metadata
│ (Flexible Server) │
├──────────────────────────────┤
│ Azure Cache for Redis │ ← Shared sessions
│ (Basic C0) │
└──────────────────────────────┘
Multi-replica prerequisites (all met since Phase 8):
- ✅ All persistent data in PostgreSQL (not SQLite)
- ✅ Sessions in Redis (not SQLite)
- ✅ OAuth state is stateless (cookie-based)
- ✅ No in-memory state in application code
Deployment Options¶
Option 1: Frontend Only (Milestone 1)¶
Deploy the frontend as a static site. No backend needed.
# Build
cd apps/web && pnpm build
# Output in apps/web/dist/
# Deploy to any static host:
# - Vercel
# - Netlify
# - GitHub Pages
# - Cloudflare Pages
# - S3 + CloudFront
Option 2: Full Stack with Docker Compose (Local)¶
Docker Compose (Full Stack)¶
The docker-compose.yml starts all services: PostgreSQL, Redis, API, and Web frontend.
# Copy and fill in environment variables
cp .env.example .env
# Start all services
docker compose up -d
# Check service health
docker compose ps
docker-compose.yml Services¶
| Service | Image / Build | Purpose |
|---|---|---|
postgres |
postgres:16-alpine |
Relational metadata store |
redis |
redis:7-alpine |
Session cache & revocation (sliding TTL) |
api |
infra/docker/api.Dockerfile |
FastAPI backend |
web |
infra/docker/web.Dockerfile |
Nginx-served SPA frontend |
Development with Hot-Reload¶
Use the dev override to mount the API source and enable --reload:
This mounts apps/api/ into the container so code changes restart the server automatically.
Tip: Set
COMPOSE_FILE=docker-compose.yml:docker-compose.dev.ymlin your shell to avoid typing the-fflags every time.
Option 3: Azure Container Apps (Cloud)¶
Cloud deployment note:
infra/terraform/environments/dev/is the current implementation baseline. The planned direction is staged environments (staging→production). ~~SeeENVIRONMENT_STRATEGY.md.~~ (Removed — deleted as speculative future infrastructure.) Use this section for current dev-stack provisioning details until the multi-environment Terraform wrappers land.
Managed Azure Stack¶
| Component | Azure Service | SKU / Tier | Est. Cost |
|---|---|---|---|
| Frontend | Azure Static Web Apps | Free | $0/mo |
| Backend API | Azure Container Apps | Consumption | ~$5/mo |
| Metadata DB | Azure Database for PostgreSQL | B_Standard_B1ms | ~$13/mo |
| Session Cache | Azure Cache for Redis | Basic C0 (250MB) | ~$16/mo |
| Container Registry | Azure Container Registry | Basic | ~$5/mo |
| Data Store | GitHub (user repos) | — | Free |
Total estimated cost: ~$39/month (dev environment)
Terraform Provisioning¶
All Azure infrastructure is defined in infra/terraform/environments/dev/.
cd infra/terraform/environments/dev
# Copy and fill in variables
cp terraform.tfvars.example terraform.tfvars
# Edit terraform.tfvars with your values
# Initialize
terraform init
# Plan (review changes)
terraform plan -var-file="terraform.tfvars"
# Apply
terraform apply -var-file="terraform.tfvars"
Resources Provisioned by Terraform¶
| Resource | Name Pattern | Purpose |
|---|---|---|
| Resource Group | rg-cloudblocks-{env} |
Logical grouping |
| Log Analytics | law-cloudblocks-{env} |
Container logs & metrics |
| Container App Environment | cae-cloudblocks-{env} |
Container Apps hosting |
| Container Registry | cloudblocks{env}acr |
Docker image storage |
| PostgreSQL Flexible Server | psql-cloudblocks-{env} |
Metadata database |
| Azure Cache for Redis | redis-cloudblocks-{env} |
Session cache |
| Container App (API) | ca-cloudblocks-api-{env} |
Backend API |
| Static Web App | swa-cloudblocks-{env} |
Frontend SPA |
Scaling Configuration¶
The Container App scales horizontally based on HTTP concurrent requests:
| Parameter | Default | Description |
|---|---|---|
container_min_replicas |
1 | Minimum replicas (0 = scale to zero) |
container_max_replicas |
3 | Maximum replicas |
scaling_concurrent_requests |
50 | Requests/replica before scaling out |
container_cpu |
0.5 | CPU cores per replica |
container_memory |
1Gi | Memory per replica |
To adjust scaling, update terraform.tfvars:
Health Probes¶
The Container App configures three probe types:
| Probe | Path | Interval | Purpose |
|---|---|---|---|
| Startup | /health |
5s | Wait for app to start (up to 50s) |
| Liveness | /health |
30s | Restart unhealthy containers |
| Readiness | /health/ready |
15s | Remove from load balancer if DB unavailable |
CI/CD Pipeline¶
GitHub Actions¶
The deploy workflow (.github/workflows/deploy.yml) runs on manual dispatch (or push to main when configured):
Required GitHub Secrets:
| Secret | Description |
|---|---|
AZURE_CLIENT_ID |
Azure AD service principal client ID (OIDC) |
AZURE_TENANT_ID |
Azure AD tenant ID |
AZURE_SUBSCRIPTION_ID |
Azure subscription ID |
ACR_NAME |
Container Registry name |
ACR_LOGIN_SERVER |
Container Registry login server URL |
AZURE_RESOURCE_GROUP |
Target resource group name |
CONTAINER_APP_NAME |
Container App name (from Terraform output) |
AZURE_SWA_TOKEN |
Static Web Apps deployment token |
Pipeline jobs:
- build-api — Builds Docker image via
az acr buildand pushes to ACR (tagged with git SHA +latest) - deploy-api — Updates Container App with new image, waits for healthy revision, verifies
/healthendpoint - deploy-web — Builds frontend SPA and deploys to Azure Static Web Apps
To enable automatic deployment on push to main, uncomment the push trigger in .github/workflows/deploy.yml.
Environment Variables¶
Frontend (.env)¶
Backend (.env)¶
All backend variables use the CLOUDBLOCKS_ prefix. See .env.example for a complete template.
# Application
CLOUDBLOCKS_APP_ENV=development
CLOUDBLOCKS_APP_PORT=8000
CLOUDBLOCKS_APP_DEBUG=true
# Database (SQLite or PostgreSQL)
CLOUDBLOCKS_DATABASE_URL=sqlite+aiosqlite:///cloudblocks.db
# CLOUDBLOCKS_DATABASE_URL=postgresql+asyncpg://user:pass@localhost:5432/cloudblocks
# Session backend (sqlite | redis)
CLOUDBLOCKS_SESSION_BACKEND=sqlite
CLOUDBLOCKS_REDIS_URL=redis://localhost:6379/0
# GitHub OAuth
CLOUDBLOCKS_GITHUB_CLIENT_ID=your_github_client_id
CLOUDBLOCKS_GITHUB_CLIENT_SECRET=your_github_client_secret
CLOUDBLOCKS_GITHUB_REDIRECT_URI=http://localhost:8000/api/v1/auth/github/callback
# Session encryption (Fernet key derivation)
CLOUDBLOCKS_JWT_SECRET=your-32-plus-char-random-string
# CORS
CLOUDBLOCKS_CORS_ORIGINS=["http://localhost:5173"]
Important: Session auth uses httpOnly cookies (
cb_oauth,cb_session) and server-side sessions. Frontend API calls must usecredentials: 'include'.
Production Secrets (set via secret manager)¶
| Secret | Description |
|---|---|
CLOUDBLOCKS_JWT_SECRET |
Strong random string (≥32 chars) for session encryption key derivation (Fernet) |
CLOUDBLOCKS_TOKEN_ENCRYPTION_SALT |
Strong random string (≥16 chars) for PBKDF2 key derivation (with JWT_SECRET) to encrypt OAuth state cookies and stored OAuth tokens via Fernet |
CLOUDBLOCKS_GITHUB_CLIENT_SECRET |
GitHub App OAuth secret |
CLOUDBLOCKS_GITHUB_CLIENT_ID |
GitHub OAuth client ID |
CLOUDBLOCKS_CORS_ORIGINS |
JSON array of allowed browser origins |
Health Checks¶
| Endpoint | Description |
|---|---|
GET /health |
Basic health check (liveness) |
GET /health/ready |
Readiness check (verifies database connectivity) |
Monitoring¶
Application logs are written to stdout/stderr in JSON format and collected by:
- Azure Container Apps: Log Analytics workspace (auto-configured by Terraform)
- Docker Compose: Container logging driver
Recommended monitoring:
- Uptime: Better Uptime / UptimeRobot (free tier)
- Errors: Sentry (free tier: 5K events/month)
- Metrics: Azure Monitor metrics + Log Analytics queries
- Scaling: Azure Portal → Container App → Metrics → Replica Count
Phase 8 Infrastructure (Complete)¶
- ✅ PostgreSQL for production-scale relational metadata (
CLOUDBLOCKS_DATABASE_URL) - ✅ Redis for session caching with sliding TTL and logout-all support (
CLOUDBLOCKS_SESSION_BACKEND=redis) - ✅ Docker Compose stack with healthchecks and dev hot-reload
- ✅ Azure Container Apps multi-replica deployment with auto-scaling
- ✅ Azure Cache for Redis (Basic C0) for shared session state
- ✅ CI/CD pipeline with image build, deploy, and health verification
- ✅ Health probes (startup, liveness, readiness) for container orchestration