thermograph/infra
Emi Griffith c98512cfcc
All checks were successful
secrets-guard / encrypted (pull_request) Successful in 10s
PR build (required check) / changes (pull_request) Successful in 17s
shell-lint / shellcheck (pull_request) Successful in 14s
PR build (required check) / validate-observability (pull_request) Successful in 44s
PR build (required check) / build-frontend (pull_request) Successful in 2m13s
PR build (required check) / build-backend (pull_request) Successful in 2m31s
PR build (required check) / gate (pull_request) Successful in 3s
docs: rewrite the agent context layer to match the live system
The four domain CLAUDE.md files still described the pre-monorepo split-repo
topology, and several statements were the exact inverse of current reality:
infra/CLAUDE.md told a reader that emi/thermograph is archived and must not be
pointed at, when that is the live repo; backend/ and frontend/ both claimed
there is no Makefile and no requirements-dev.txt when all four files exist;
frontend/ described itself as one of four sibling repos; observability/ claimed
a single unprotected main branch.

These files are read before every change, so a stale one is a correctness
problem rather than a documentation one. Rewritten against the tree:

- Root CLAUDE.md now owns the cross-cutting truth once — branch model, the
  SERVICE + *_IMAGE_TAG deploy contract, image names, which orchestrator each
  environment runs, and that everything is a PR. Domain files carry only what
  differs and are capped at ~70 lines.
- Records that prod runs Swarm from deploy/stack/thermograph-stack.yml while
  beta and LAN dev run compose, routed by /etc/thermograph/deploy-mode.
- Documents the *-deploy-dev.yml workflows as inert rather than leaving a
  reader to discover it.

Deletes infra/docker-stack.yml. It defined db/app/worker, matched nothing that
deploys, and was referenced only by prose describing it as a future design
record — while the real 8-service prod stack lives under deploy/stack/. A file
that looks authoritative and affects nothing is the worst case for a reader
asked to change the prod stack.

infra/README.md claimed "compose in production today" and that Swarm was "not
currently live"; corrected, and infra-sync.yml's existence is now recorded
instead of "there is no separate infra deploy trigger". The compose file's
timescale-pin comment now points at how deploy-stack.sh actually resolves the
digest from the running container.
2026-07-24 20:59:44 -07:00
..
.claude/skills/key-gaps key-gaps: the key regex was blind to digits, inventing missing secrets 2026-07-24 15:57:15 -07:00
deploy secrets: silence two SC2016s that are the intended behaviour 2026-07-24 18:13:08 -07:00
lake-iceberg Iceberg conversion container for the ERA5 lake (infra/lake-iceberg) (#24) 2026-07-23 22:56:27 +00:00
ops ops/iceberg.sh: read-only Iceberg lake queries across all environments (#23) 2026-07-24 19:34:30 +00:00
terraform Log hygiene: Alloy CPU, Loki chunks/limits, Caddy field-stripping (#36) 2026-07-24 04:37:41 +00:00
.env.example daemon: move the Discord gateway and scheduler out of the web process into Go (#21) 2026-07-23 22:49:54 +00:00
.gitignore Iceberg conversion container for the ERA5 lake (infra/lake-iceberg) (#24) 2026-07-23 22:56:27 +00:00
.sops.yaml Subtree-merge thermograph-infra (origin/main) into infra/ 2026-07-22 22:01:11 -07:00
ACCESS.md Subtree-merge thermograph-infra (origin/main) into infra/ 2026-07-22 22:01:11 -07:00
CLAUDE.md docs: rewrite the agent context layer to match the live system 2026-07-24 20:59:44 -07:00
DEPLOY-DEV.md secrets: vault dev and Centralis; render dev without common.yaml 2026-07-24 18:10:51 -07:00
DEPLOY.md observability: add the estate's first alerting; supervise Postfix 2026-07-24 13:19:19 -07:00
docker-compose.dev.yml Reconcile: merge main (shellcheck guard, Go daemon) into dev 2026-07-23 17:06:52 -07:00
docker-compose.openmeteo.yml Subtree-merge thermograph-infra (origin/main) into infra/ 2026-07-22 22:01:11 -07:00
docker-compose.yml docs: rewrite the agent context layer to match the live system 2026-07-24 20:59:44 -07:00
Makefile Subtree-merge thermograph-infra (origin/main) into infra/ 2026-07-22 22:01:11 -07:00
README.md docs: rewrite the agent context layer to match the live system 2026-07-24 20:59:44 -07:00

infra/

Infrastructure for Thermograph: Terraform host provisioning, the SOPS+age secrets vault, WireGuard/Swarm networking, Forgejo, Caddy, mail, and the deploy scripts that run the already-built app images on each host. This is a domain of the emi/thermograph monorepo — hosts' /opt/thermograph is a checkout of the whole monorepo, and infra/ never builds app source; it only runs published images.

  • terraform/ — provisions/configures hosts (SSH-driven by default; an optional GCP-creating module is scaffolded, no live resources yet). See terraform/README.md. No tfstate is persisted anywhere — treat apply as executable documentation, not a routine operation.
  • deploy/secrets/ — the git-native SOPS+age secrets vault (every app secret, encrypted at rest, rendered at deploy time). See deploy/secrets/README.md.
  • deploy/swarm/, deploy/forgejo/ — the WireGuard/Swarm cluster hosting Forgejo (git + CI + registry). See ACCESS.md.
  • deploy/deploy.sh — the single deploy entry point for beta and prod. Takes SERVICE=backend|frontend|all plus BACKEND_IMAGE_TAG/FRONTEND_IMAGE_TAG, resets the host checkout, renders secrets, and routes to the right orchestrator.
  • deploy/stack/ — the Swarm path, live on prod: thermograph-stack.yml (db, web, worker, lake, daemon, frontend, autoscaler, autoscaler-lake), deploy-stack.sh, autoscale.sh, and the LB. Rolling updates are start-first, health-gated, with auto-rollback. STACK_TEST=1 rehearses the whole stack on throwaway volumes and ports.
  • docker-compose*.yml — the compose path, live on beta and LAN dev (db, backend, lake, daemon, frontend). docker-compose.dev.yml is the LAN overlay; docker-compose.openmeteo.yml is the self-hosted Open-Meteo overlay.

Which path a host takes is decided by /etc/thermograph/deploy-mode: the string stack makes deploy.sh exec deploy/stack/deploy-stack.sh; anything else is compose. The workflows never need to know which mode a host runs.

Branches & how changes reach each environment

  • main — what prod and beta run. infra-sync.yml fires on a push to main touching infra/**, fast-forwards each host's /opt/thermograph checkout and re-renders /etc/thermograph.env from the vault. It deliberately does not roll any service: image tags are the app domains' axis, not infra's. A compose or stack change that must recreate containers takes effect on the next app deploy, or a by-hand SERVICE=all … deploy/deploy.sh.
  • dev — what LAN dev would run via deploy/deploy-dev.sh. The CI trigger for this is currently inert (the LAN box still holds a split-era checkout); use make dev-up locally.
  • release — consumed by app deploys only. Both hosts track infra via main; prod's app images are staged by release, but its checkout follows main.

Note the asymmetry with the app domains: app code IS environment-staged (devmainrelease maps to LAN→beta→prod via image tags); infra is not.