# 42. Deployment — Update Docker, CI/CD, and Environment Configuration meta: id: shieldai-unified-restructure-42 feature: shieldai-unified-restructure priority: P0 depends_on: [shieldai-unified-restructure-41] tags: [deployment, docker, ci-cd, infrastructure] objective: - Create production-ready deployment configuration for the unified monolith. Update Docker containers, CI/CD pipelines, and environment configuration to support the new single-app architecture plus native mobile builds. deliverables: - `web/Dockerfile` — Production container for the web app: - Multi-stage build: Node.js builder → runtime - Installs pnpm, dependencies, builds app - Exposes port 3000 - Health check endpoint - Non-root user for security - `docker-compose.yml` — Local development orchestration: - `web` service: builds from `web/Dockerfile`, ports `3000:3000` - `postgres` service: PostgreSQL 16 with volume for data persistence - `redis` service: Redis 7 for job queues and caching - `nginx` service: reverse proxy with SSL termination (optional) - Environment variables from `.env` file - `docker-compose.prod.yml` — Production orchestration: - Similar to dev but with production-optimized settings - Volume mounts for uploads/logs - Restart policies - Resource limits - `.github/workflows/ci.yml` — GitHub Actions CI pipeline: - Lint and type check (TypeScript) - Unit tests for web app - Build verification - Dependency audit (`pnpm audit`) - `.github/workflows/deploy.yml` — GitHub Actions CD pipeline: - Build Docker image on release tag - Push to container registry (GitHub Packages, Docker Hub, or ECR) - Deploy to staging on push to `main` - Deploy to production on release tag - Run database migrations before deployment - Health check after deployment - `web/.env.example` — Complete environment variable documentation: - Database: `DATABASE_URL` - Redis: `REDIS_URL` - Auth: `JWT_SECRET`, `NEXTAUTH_SECRET` - Stripe: `STRIPE_SECRET_KEY`, `STRIPE_WEBHOOK_SECRET`, `STRIPE_PRICE_*` - Notifications: `RESEND_API_KEY`, `FIREBASE_SERVICE_ACCOUNT_PATH`, `TWILIO_*` - External APIs: `HIBP_API_KEY`, `SECURITYTRAILS_API_KEY`, etc. - Monitoring: `SENTRY_DSN`, `DATADOG_API_KEY` (optional) - App: `NODE_ENV`, `PORT`, `API_URL`, `APP_URL` - `scripts/deploy.sh` — Deployment helper script: - Database backup before migration - Migration runner - Health check verification - Rollback on failure - `scripts/backup.sh` — Database backup script: - `pg_dump` to timestamped file - Upload to S3 or similar storage steps: 1. Create `web/Dockerfile`: ```dockerfile # Build stage FROM node:20-alpine AS builder WORKDIR /app RUN npm install -g pnpm COPY web/package.json web/pnpm-lock.yaml ./ RUN pnpm install --frozen-lockfile COPY web/ . RUN pnpm build # Runtime stage FROM node:20-alpine WORKDIR /app RUN npm install -g pnpm COPY --from=builder /app/package.json /app/pnpm-lock.yaml ./ COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/.output ./.output COPY --from=builder /app/drizzle ./drizzle ENV NODE_ENV=production EXPOSE 3000 HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD curl -f http://localhost:3000/health || exit 1 USER node CMD ["node", ".output/server/index.mjs"] ``` 2. Create `docker-compose.yml`: - Define services with appropriate environment variables - PostgreSQL with `volumes: postgres_data:/var/lib/postgresql/data` - Redis with `volumes: redis_data:/data` - Network configuration 3. Create `docker-compose.prod.yml`: - Add restart policies: `unless-stopped` - Add resource limits: `mem_limit`, `cpus` - Add logging driver configuration - Remove port bindings for internal services (postgres, redis) 4. Create `.github/workflows/ci.yml`: - Trigger: push to any branch, pull requests - Jobs: - `lint`: `pnpm lint` - `typecheck`: `tsc --noEmit` - `test`: `pnpm test` - `build`: `pnpm build` - `audit`: `pnpm audit --audit-level=high` 5. Create `.github/workflows/deploy.yml`: - Trigger: release tags (`v*`), manual dispatch - Jobs: - `build`: build Docker image, tag with version - `push`: push to registry - `migrate`: SSH into server, run `pnpm db:migrate` - `deploy`: update Docker Compose stack - `healthcheck`: verify `/health` endpoint responds 200 - Use GitHub secrets for SSH keys, registry credentials 6. Update `web/.env.example`: - Document every environment variable used by the app - Include description, example value, and whether required - Group by category (Database, Auth, Payments, APIs, etc.) 7. Create `scripts/deploy.sh`: - `#!/bin/bash` with error handling (`set -euo pipefail`) - Backup database: `docker exec postgres pg_dump ...` - Run migrations: `docker compose exec web pnpm db:migrate` - Deploy: `docker compose -f docker-compose.prod.yml up -d` - Health check: `curl -f http://localhost:3000/health` - Rollback on failure: `docker compose rollback` or restore backup 8. Create `scripts/backup.sh`: - Generate timestamped dump - Compress with gzip - Upload to S3 using AWS CLI or rclone - Retain last 30 backups 9. Test deployment locally: - `docker compose up --build` - Verify app accessible at `http://localhost:3000` - Verify database migrations run - Verify health check passes 10. Document deployment process in `docs/DEPLOYMENT.md`. steps: - Integration: `docker compose up --build` starts all services successfully - Integration: App is accessible and functional inside Docker - Integration: CI pipeline passes on GitHub Actions - Integration: Deployment script completes without errors - Security: Dockerfile uses non-root user - Security: No secrets committed to repository acceptance_criteria: - [ ] `web/Dockerfile` builds a production-ready container - [ ] `docker-compose.yml` orchestrates web, postgres, and redis for local dev - [ ] `docker-compose.prod.yml` is optimized for production with restart policies and resource limits - [ ] CI pipeline runs lint, type check, tests, build, and audit on every PR - [ ] CD pipeline builds and deploys on release tags - [ ] Database migrations run automatically before deployment - [ ] Health check endpoint verifies app is ready - [ ] Rollback script restores previous version on deployment failure - [ ] Backup script creates and stores database dumps - [ ] `.env.example` documents all required environment variables - [ ] No secrets are present in repository (verified by `git-secrets` or manual audit) validation: - `docker compose up --build -d` → verify `docker ps` shows all containers running - `curl http://localhost:3000/health` → returns `{"status":"ok"}` - `docker logs shieldai-web` → no startup errors - Push to a test branch and verify GitHub Actions CI pipeline runs - Create a test release tag and verify CD pipeline triggers - Run `scripts/backup.sh` and verify dump file created - Run `scripts/deploy.sh` and verify deployment succeeds notes: - The unified monolith simplifies deployment significantly: one container instead of 5+ microservices. - For high availability, run multiple web container instances behind a load balancer (nginx, AWS ALB, etc.). - Consider using a managed database (RDS, Supabase, Neon) instead of self-hosted PostgreSQL for production. - For Redis, consider Upstash or ElastiCache for managed service. - The web app uses SolidStart with Nitro, which can run as a standalone server. Ensure the `.output/server/index.mjs` entry point is correct. - For SSL, use Let's Encrypt with nginx or a managed load balancer. Document certificate renewal. - Monitor disk space for logs and uploads. Configure log rotation in Docker. - For mobile app deployment (iOS/Android), set up separate CI workflows for building and signing apps. This is outside the scope of the web deployment but should be documented. - Consider using Terraform or Pulumi for infrastructure as code if managing cloud resources.