What changed, and why
The last workload leaves the cluster. This PR carries the infra half of Everwhen's move to Vercel: the DNS flip, the retirement of infra/k8s/everwhen, and the point where the docs admit what the cluster has become, which is plumbing with nothing left to plumb. CLAUDE.md now calls it a decommission candidate in so many words. Actually decommissioning is a separate decision, and this PR deliberately does not make it.
The app half is mseeks/everwhen#356 (Dockerfile out, CI slimmed, Sentry server init moved to serverless injection). Terraform's footprint stays what it has been through all four migrations: the DNS zone it already owned. No vercel provider. No token.
dns.tf: apex in place, www replaced, redirect moved
Mechanically this is the 2ls.tech flip again. The apex stays an A record. Re-pointing it is an in-place update, no gap, since a CNAME is illegal at a zone apex and Vercel hands out an anycast address for exactly that case. www changes type, and a type change forces replacement. The www 301 needs a new home too. A dedicated everwhen-www-redirect Ingress used to serve it on the cluster; after the flip, the dashboard's domain-redirect setting serves it from Vercel's edge instead.
The rewritten zone tail: one comment block, the apex A, the www CNAME. Mail records above are untouched.
infra/dns.tf · 367 lines
⋯ 337 lines hidden (lines 1–337)
The stack retired: 399 lines, seven files
Seven files, 399 lines. The everwhen stack was the biggest thing on the cluster, and its census explains the extra care this round gets:
| file | what it did | replaced by |
|---|---|---|
manifests/10-deployment.yaml | two replicas of the Nitro server (RollingUpdate with maxSurge 0 for the tight node, /favicon.ico probes, 256Mi requests) plus its Service | Vercel Functions — scale, memory, and health are platform concerns now |
manifests/20-ingress.yaml | routed the apex through the DO LB with a cert-manager cert | Vercel's edge terminates TLS |
manifests/21-www-redirect.yaml | the www→apex 301 | the dashboard's domain redirect |
secrets.example.env | the production env-var inventory — the infra/.env template install.sh turned into the everwhen-secrets Secret | the same vars, set in the Vercel dashboard |
install.sh | preflight, apply, secret checks, rollout | git push — the integration deploys |
00-namespace.yaml + README.md | the namespace and its wiring story | nothing to isolate; the app README's Hosting section |
The docs stop pretending
Zero app Ingresses remain, and three docs needed to stop pretending otherwise. cert-manager's README now sends readers to git log for its worked example. ingress-nginx's README says plainly that no app routes remain. The ynab hairpin keeps its record but loses its host list; nothing depends on it today, and it becomes load-bearing again the moment any app Ingress returns. CLAUDE.md's infrastructure section ends the workload story:
The infrastructure section: cluster plumbing only, decommission candidate.
CLAUDE.md · 85 lines
⋯ 77 lines hidden (lines 1–77)
⋯ 1 line hidden (lines 85–85)
Verification, and the careful cutover
terraform fmt -check, init, and validate pass, and the targeted plan shows exactly the two intended record changes:
playeverwhen_com_apexwill be updated in-place —value: "174.138.116.75" -> "216.198.79.1",ttl: 300 -> 3600.playeverwhen_com_wwwmust be replaced —type: "A" -> "CNAME"(forces replacement, value739dd9fe1c5c2ea6.vercel-dns-017.com.). Plan: 1 to add, 1 to change, 1 to destroy.
The app-side gate (1458 unit tests, typecheck, lint, production build) ran from a clean path and is quoted in mseeks/everwhen#356.
The cutover order is stricter than the static rounds, because this is the product:
1. Import mseeks/everwhen in the Vercel dashboard and set every production env var (bulk-pasted from the k8s secret, never printed), then let it deploy. 2. Verify the deployment end-to-end on its .vercel.app URL before DNS moves: / and /play return 200, a real turn streams, the OG card renders, checkout-session creation answers. 3. Attach both domains (www set to redirect). The dashboard issued the per-project values at that moment; the committed ones are what it issued. Merge both PRs, apply the two targeted records. 4. Verify production, then soak: the namespace stays up as instant rollback. Deleting it — and deciding the now-empty cluster's fate — are later, separate steps.