Files
flights_web/docs/superpowers/plans/2026-04-14-phase-1i-deploy.md
T

3.8 KiB

Phase 1I — Deploy pipeline + runbook contracts

Parent plan: 2026-04-14-phase-1-foundation-master.md, section "1I — Deploy pipeline + runbook contracts" Date: 2026-04-14


Overview

This sub-plan delivers the deploy pipeline contracts: Docker images for both build targets (standalone SSR and remote static), health endpoint, graceful shutdown handler, CI workflow template, and an operational runbook.

Constraints

  • Do NOT modify modern.config.ts (middleware registration is a future integration step)
  • Health and shutdown modules export factory functions, not auto-registered middleware
  • Coexist with the existing ASP.NET Dockerfile and Dockerfile.local (write Dockerfile.react and Dockerfile.remote)
  • Do NOT touch ClientApp/, ASP.NET files, or wwwroot/

Tasks

Task 1 — Dockerfile.react (standalone SSR image)

File: Dockerfile.react (repo root)

Multi-stage build:

  1. Stage 1 (deps): Node 24 base, enable corepack pnpm, copy package.json + pnpm-lock.yaml, run pnpm install --frozen-lockfile
  2. Stage 2 (build): copy src/, config files, run pnpm build:standalone
  3. Stage 3 (runtime): Node 24 slim, copy dist/standalone/, entrypoint node dist/standalone/index.js

Exit gate: File exists, valid Dockerfile syntax.

Task 2 — Dockerfile.remote (nginx static image)

File: Dockerfile.remote (repo root)

Multi-stage build:

  1. Stage 1 (deps): same as Task 1
  2. Stage 2 (build): copy source, run pnpm build:remote
  3. Stage 3 (runtime): nginx:alpine, copy dist/remote/ to /usr/share/nginx/html, expose port 80

Exit gate: File exists, valid Dockerfile syntax.

Task 3 — Health endpoint (src/server/routes/health.ts)

Files: src/server/routes/health.ts, src/server/routes/health.test.ts

Export healthMiddleware(options) factory function that returns an Express-style (req, res, next) handler. The middleware:

  • Pings the upstream API client on each request (with configurable timeout, default 5000ms)
  • Tracks last successful ping timestamp
  • Returns 200 { status: "ok" } if last success < 60s ago
  • Returns 503 { status: "degraded", reason: "upstream_unreachable" } otherwise

TDD: Tests mock ApiClient, verify 200/503 responses, verify timeout behavior.

Exit gate: pnpm test passes health tests.

Task 4 — Graceful shutdown (src/server/shutdown.ts)

Files: src/server/shutdown.ts, src/server/shutdown.test.ts

Export registerGracefulShutdown(options) factory function that:

  • Registers a SIGTERM handler
  • On SIGTERM: calls server.close(), waits up to drainTimeoutMs (default 30000), flushes logger transport, exits with code 0
  • If drain times out, force-exits with code 1

TDD: Tests mock process.on, server.close, logger flush; verify shutdown sequence.

Exit gate: pnpm test passes shutdown tests.

Task 5 — CI deploy workflow (.github/workflows/deploy.yml)

File: .github/workflows/deploy.yml

Template workflow triggered on push to main:

  • Checkout, setup Node 24, install pnpm, pnpm install --frozen-lockfile
  • Build both targets (pnpm build:both)
  • Build Docker images (Dockerfile.react, Dockerfile.remote)
  • Push to registry (placeholder)
  • Deploy to testing environment (placeholder)

Exit gate: File exists, valid YAML syntax.

Task 6 — Operational runbook (docs/superpowers/phase-1/runbook.md)

File: docs/superpowers/phase-1/runbook.md

Covers:

  1. Incident response decision tree
  2. Canary rollout procedure
  3. Rollback procedure (auto + manual)
  4. Health-check interpretation
  5. Log query cookbook
  6. Known-failure playbooks (6 scenarios)

Exit gate: File exists, covers all required sections.


Verification

After all tasks:

pnpm typecheck && pnpm lint && pnpm test