# Phase 12: Hardening **Status:** ⬜ Not Started **Parent plan:** [PLAN.md](./PLAN.md) **Domain:** backend ## Objective Production hardening — blue-green deploys, promote flow, dashboard auth, graceful shutdown, structured logging, and config export. ## Tasks - [ ] Task 1: Blue-green deploys — start new container, health check, swap NPM proxy, then stop old container (zero downtime) - [ ] Task 2: Promote flow — enforce `promote_from` for production deploys (only tags running in source stage are eligible) - [ ] Task 3: Local auth — username/password stored in SQLite (bcrypt hashed), login endpoint, session token (JWT or cookie) - [ ] Task 4: OAuth2/OIDC auth — integration with Authentik or any OIDC provider (configurable client ID, client secret, discovery URL) - [ ] Task 5: Auth settings UI — settings page to choose auth mode (local/OIDC), configure OIDC provider, manage local users - [ ] Task 6: Auth middleware — protect all /api/* routes except webhook; check session/JWT/OIDC token - [ ] Task 7: Graceful shutdown — handle SIGTERM/SIGINT, drain in-progress deploys, close DB, stop poller - [ ] Task 8: Structured logging — JSON logs with deploy context (project, stage, tag, instance ID) - [ ] Task 9: Config export — download current SQLite state as YAML (reverse of seed import) - [ ] Task 10: Dockerfile — multi-stage build (build frontend + Go, copy to minimal image) - [ ] Task 11: docker-compose.yml — production-ready compose file with volumes, network, env - [ ] Task 12: Final wiring review — ensure all services are properly initialized and shut down ## Files to Modify/Create - `internal/deployer/bluegreen.go` — blue-green deploy strategy - `internal/deployer/promote.go` — promote flow logic - `internal/auth/local.go` — local auth (bcrypt password hashing, session tokens) - `internal/auth/oidc.go` — OAuth2/OIDC provider integration - `internal/auth/middleware.go` — auth middleware (session/JWT/OIDC token validation) - `internal/auth/models.go` — user model, auth settings, session store - `internal/api/auth.go` — auth API endpoints (login, logout, OIDC callback, user management) - `internal/config/export.go` — config export to YAML - `internal/logging/logger.go` — structured JSON logger - `internal/store/users.go` — user CRUD, auth settings persistence - `web/src/routes/login/+page.svelte` — login page - `web/src/routes/settings/auth/+page.svelte` — auth settings UI - `cmd/server/main.go` — graceful shutdown, structured logging, auth init - `Dockerfile` — multi-stage build - `docker-compose.yml` — production compose file ## Acceptance Criteria - Blue-green: zero downtime during deploy (old container serves until new one is healthy) - Promote: production deploy only accepts tags from the specified source stage - Auth: unauthenticated requests to /api/* (except webhook) return 401 - Graceful shutdown: in-progress deploys complete before exit - Logs are JSON-formatted with contextual fields - Config export produces valid YAML that could be re-imported - Docker image builds and runs correctly ## Notes - Blue-green: keep old container running until new one passes health check, then swap NPM proxy and stop old - Auth has two modes configurable via settings: - **Local auth**: username/password in SQLite (bcrypt hashed), JWT session tokens - **OAuth2/OIDC**: integration with Authentik or any OIDC provider (client ID, secret, discovery URL) - First launch: create default admin user with configurable password via ADMIN_PASSWORD env var - OIDC flow: redirect to provider → callback → create/link local user → issue session - SIGTERM handling: use Go's `os/signal` + `context.WithCancel` - Structured logging: use `log/slog` (Go stdlib since 1.21) - Dockerfile: build stage with Node.js + Go, runtime stage with scratch/alpine - Phase 13 (UI Polish) and Phase 14 (Volumes & Env) follow this phase ## Review Checklist - [ ] All tasks completed - [ ] Blue-green deploy handles rollback if new container fails - [ ] Auth doesn't block webhook endpoint - [ ] Graceful shutdown tested with concurrent deploys - [ ] Dockerfile produces a minimal image - [ ] docker-compose.yml matches the example in PLAN.md ## Handoff to Next Phase