# DEPLOYMENT_SPEC.md ## 1. Environments | Env | Where | Purpose | URL | |---|---|---|---| | **dev** | Local (Docker compose dev stack) | Inner loop, HMR | localhost:4321 | | **staging** | Same server, separate compose project | Pre-release verification on real infra (headers, proxy, relay SMTP against a mailbox test) | `staging.cesnimda.co.uk` (basic-auth gated at the proxy, `noindex` everywhere) | | **prod** | Server, compose stack `resumesite` | Live | `cesnimda.co.uk` | Staging exists chiefly for the **cutover** and for occasional risky changes; day-to-day content edits may go dev → prod (single-owner pragmatism, gates make it safe). ## 2. Pipeline (Gitea Actions, all self-hosted) ``` push / PR to main ├─ lint + typecheck + astro check ├─ unit (vitest: i18n parity, slug-map bijection, JSON-LD builders) ├─ build site (static) ──► Playwright e2e vs built output + relay container │ ──► axe a11y scan (both locales, both themes) │ ──► Lighthouse CI budgets (fail = red) ├─ build + push images :sha and :latest → Gitea registry (main only) └─ deploy job (main only, manual approval toggle): ssh to server → compose pull → compose up -d → smoke check (curl /, /no/, /api/contact healthz, spot-check headers) → notify ``` - **Rollback:** redeploy previous `:sha` tag (one command, documented runbook); HTML no-cache means rollback is immediate. Registry retains last N images. - **Content-only changes** ride the same pipeline — content errors are build errors by design (schema + parity tests), which is the safety that replaces CMS preview. - Scheduled workflow (weekly): external link check (DATA_MODEL §8.6) + Lighthouse drift report + Renovate PRs. ## 3. Cutover plan (WordPress → new site) 1. Pre-launch: staging fully verified (both locales, CV downloads, form → real mailbox, redirects incl. `/Linkedin`, 410 map, OG previews via LinkedIn/Slack debuggers, Search Console fetch). 2. URL inventory + redirect/410 map finalised (SEO_SPEC §6). 3. Cutover = move the `cesnimda.co.uk` Traefik Host router from the WordPress container to the `site` container (a label change + `compose up -d`; WP left running dark for 2 weeks as instant rollback). 4. Post-launch checklist: submit sitemaps, watch Search Console coverage + relay logs for form spam patterns, then decommission WP + its PHP/MySQL surface (attack-surface win worth noting on the colophon). ## 4. Operational guardrails - **Uptime:** monitored by existing homelab monitoring (add checks: `/` 200 + content match, `/no/` 200, relay healthz); alerting via his current channel. - **TLS:** unchanged at the existing edge proxy (already terminating for Gitea etc.). - **Logs:** site-nginx access logs minimal (no query bodies, standard rotation); relay logs metadata only (timestamp, IP hash, outcome) — privacy stance documented on colophon. - **CV updates:** replace PDF in repo → pipeline redeploys; stable URLs mean previously shared links always fetch the newest CV — an explicit product decision. - **Secrets rotation:** SMTP credential rotation runbook (env file update + `compose up -d relay`), noted in deploy README. ## 5. Definition of Done for Phase 3 (deployment perspective) 1. All CI gates green on main; images in registry. 2. Staging sign-off checklist complete (incl. native-Norwegian content review — I18N_SPEC §6). 3. Cutover executed; WP dark-standby; monitoring green 48h. 4. Search Console: sitemaps accepted, no coverage regressions after 4 weeks (watch item, not blocker). 5. Colophon page published describing the stack honestly (the P2 hook).