Thermograph monorepo: graded-climate API + SSR frontend + infra, domain-specific containerized deploys
Find a file
Emi Griffith b2b56bdc1a frontend: fix the three inconsistencies the onboarding guide found
1. CLAUDE.md and README.md described the superseded Python service. Both now
   describe server/ (Go), say plainly that the Python files at that level are
   the original the port was made from, and drop CLAUDE.md's claim that
   `make test-unit` is "the tier CI runs" — CI's only frontend check is the
   Dockerfile builder stage's gofmt + vet + go test.

2. static/units.js's F_REGIONS was guarded by nothing, despite three source
   comments claiming "a test asserts all three stay identical": the only check
   compared the Go set against the backend's Python. TestFCountriesMatchesUnitsJS
   now diffs the browser copy both directions.

   That backend cross-check also skips in CI — the image build context is
   frontend/, so backend/ is unreachable from the builder stage, which is the
   only place CI runs these tests. static/ IS in the context, so the Dockerfile
   copies units.js into the builder and the new assertion runs during the image
   build. Verified by mutating units.js and confirming the build fails.

3. Both docker-compose.test.yml files defaulted to the retired
   emi/thermograph-backend/app path, and the frontend harness pinned the
   split-era v0.0.2-split-ci tag. Path corrected in both. Rather than swap one
   hardcoded pin for another, backend-for-tests.sh now derives the tag from the
   checkout — sha-<12hex of `git log -1 -- backend/`>, the same domain-keyed
   rule build-push.yml and deploy.yml use — and compose requires the variable
   so a stale pin cannot creep back in.

Verified: backend 429 passed/8 skipped; frontend go vet clean and all packages
ok; frontend image builds; `make backend-up` pulls and serves on the derived
tag; shellcheck zero findings across the tree.

Unrelated pre-existing issue noted in the docs, not fixed here:
`make test-integration` fails 7/16 with 503 against a cold throwaway backend
(empty database, nothing warm). Reproduced identically on the old image, so it
predates this change.

Claude-Session: https://claude.ai/code/session_01AfXqHrxCJLs2D7hpQkiUiJ
2026-07-25 11:43:22 -07:00
.claude guardrails: enforce live-host and secrets policy with hooks (#82) 2026-07-25 07:09:11 +00:00
.forgejo/workflows ci: collapse the eight deploy and build-push workflows into two (#87) 2026-07-25 07:48:49 +00:00
backend frontend: fix the three inconsistencies the onboarding guide found 2026-07-25 11:43:22 -07:00
docs/onboarding frontend: fix the three inconsistencies the onboarding guide found 2026-07-25 11:43:22 -07:00
frontend frontend: fix the three inconsistencies the onboarding guide found 2026-07-25 11:43:22 -07:00
infra ci: collapse the eight deploy and build-push workflows into two (#87) 2026-07-25 07:48:49 +00:00
observability alerting: don't print a bare "value:" when ValueString is empty (#96) 2026-07-25 18:17:37 +00:00
.gitignore Drop accidentally-committed worktrees; ignore .claude/worktrees 2026-07-24 15:57:34 -07:00
CLAUDE.md ci: collapse the eight deploy and build-push workflows into two (#87) 2026-07-25 07:48:49 +00:00
CUTOVER-NOTES.md ci: collapse the eight deploy and build-push workflows into two (#87) 2026-07-25 07:48:49 +00:00
README.md docs: add a developer onboarding guide for the monorepo 2026-07-25 18:34:44 +00:00

thermograph

The Thermograph monorepo — the split repos reunified (2026-07-22) with full history via subtree merges, while keeping everything the split was actually for: per-domain images, per-domain deploys, and an async FE/BE contract.

Domains

Dir What CI
backend/ FastAPI graded-climate API, accounts, notifications (Discord bot, push, mail), data pipeline build-push → image emi/thermograph/backend; deploy
frontend/ Public client: static JS/CSS + SSR pages same build-push / deploy workflows, matrixed by domain; image emi/thermograph/frontend
infra/ Compose (beta, LAN dev) + the Swarm stack (prod), deploy scripts, terraform, SOPS secrets vault, ops cron infra-sync (host checkout + secrets render), secrets-guard, ops-cron
observability/ Loki + Grafana + Alloy stack observability-validate

thermograph-docs deliberately stays its own repo (ADRs + runbooks, no build artifacts, different change cadence).

New here?

docs/onboarding/ is the developer onboarding path: orientation, verified local-setup recipes, a per-domain deep dive, the cross-service contracts that break silently, the release flow, and a list of which docs in this repo are currently stale.

How CI stays decoupled

Every workflow in .forgejo/workflows/ is path-filtered to its domain: a push touching only frontend/** builds/deploys nothing else. Images stay separate (emi/thermograph/backend, emi/thermograph/frontend, each tagged sha-<12hex>), deploys stay per-service (infra/deploy/deploy.sh SERVICE=backend|frontend|all), and the API version contract (GET /api/version, PAYLOAD_VER) still lets FE and BE ship out of lockstep. The one intentionally coupled piece is pr-build.yml: a single always-running gate required check that builds only the domains a PR touches (a path-filtered required check would deadlock auto-merge).

Branch model (unchanged from the split era): PRs → dev, main → beta, release → prod; infra tracked via main on all hosts.

Before pointing anything live at this repo, read CUTOVER-NOTES.md.