|
All checks were successful
Sync infra to hosts / sync-beta (push) Has been skipped
Sync infra to hosts / sync-prod (push) Has been skipped
Sync infra to hosts / sync-centralis (push) Has been skipped
Sync infra to hosts / sync-dev (push) Successful in 9s
secrets-guard / encrypted (push) Successful in 5s
Validate observability stack / validate (push) Successful in 12s
shell-lint / shellcheck (push) Successful in 8s
Build + push images (Forgejo registry) / build-push (frontend) (push) Successful in 26s
Build + push images (Forgejo registry) / build-push (backend) (push) Successful in 1m10s
Deploy / deploy (backend) (push) Successful in 1m41s
Deploy / deploy (frontend) (push) Successful in 1m48s
secrets-guard / encrypted (pull_request) Successful in 8s
shell-lint / shellcheck (pull_request) Successful in 9s
PR build (required check) / changes (pull_request) Successful in 20s
PR build (required check) / validate-observability (pull_request) Successful in 15s
PR build (required check) / build-frontend (pull_request) Successful in 17s
PR build (required check) / build-backend (pull_request) Successful in 2m26s
PR build (required check) / gate (pull_request) Successful in 1s
Completes the Forgejo domain migration. ROOT_URL moved to dev.jinemi.com earlier; the registry half was deliberately deferred. Every image name, REGISTRY_HOST default, runner label and --add-host pin now names dev.jinemi.com, so the registry host and the bearer-token realm agree again. Both names address the same Forgejo, so no image needs re-pushing and a rollback to a tag pushed under the old prefix still resolves. git.thermograph.org therefore stays served off the same Caddy site block -- one block, so the /v2/* mesh-only matcher keeps covering both names -- for pre-migration tags and for runners holding it as their registered instance URL. Mesh clients now pin both names in /etc/hosts: the new one as registry host and token realm, the old one for pre-migration tags. runner-vps2/config.yaml carries both --add-host entries for the same reason. Also renames Centralis' endpoint to mcp.jinemi.com in the two places this repo names it; Centralis itself is provisioned outside this repo. Host-side steps this cannot do (documented in deploy/forgejo/README.md, "Host-side steps"): the Forgejo Actions variable REGISTRY_HOST, docker login against the new host, and the /etc/hosts pins. |
||
|---|---|---|
| .. | ||
| 01-orientation.md | ||
| 02-setup.md | ||
| 03-repo-map.md | ||
| 04-backend.md | ||
| 05-frontend.md | ||
| 06-contracts.md | ||
| 07-ci-and-release.md | ||
| 08-infra-secrets.md | ||
| 09-observability.md | ||
| 10-recipes.md | ||
| 11-traps.md | ||
| README.md | ||
Onboarding — becoming a full contributor to Thermograph
This is the developer onboarding path for the Jinemi/thermograph monorepo: what
the product is, how the code is shaped, how to run it, what will break silently
if you get it wrong, and how a change actually travels from your editor to
thermograph.org.
Scope. This covers working in this repo. Cross-cutting architecture
decision records and operator runbooks live in the separate thermograph-docs
repo (reachable through Centralis's docs_search) — this set links out rather
than duplicating them. Where a fact is owned by a CLAUDE.md, that file stays
the source of truth and this set explains the context around it.
Reading order
| # | Doc | Read it when |
|---|---|---|
| 1 | Orientation | First. What the product actually claims, the estate, the four non-negotiable rules. |
| 2 | Local setup | Before you touch anything. Toolchain, verified run/test recipes for every service. |
| 3 | Repo map | To find things. Every domain and directory, and which files matter. |
| 4 | Backend deep dive | Before your first backend change. Data pipeline, grading, caching, roles, daemon. |
| 5 | Frontend deep dive | Before your first frontend change. The Go SSR service, static assets, design system. |
| 6 | Cross-service contracts | Before any change that touches both. These break silently and in production. |
| 7 | CI and release | Before you open a PR. Nine workflows, three branches, three environments. |
| 8 | Infra and secrets | Before you touch deploy, compose, or a secret. |
| 9 | Observability | When something is wrong and you need to see it. |
| 10 | Recipes | Task-shaped walkthroughs for the things you'll actually do. |
| 11 | Traps and stale docs | Skim early, re-read often. Which docs in this repo currently lie, and why. |
The short version
Thermograph grades how unusual today's weather is at any point on Earth against ~45 years of that exact location's own history. Percentiles, never thermometer readings.
backend/— Python 3.12 / FastAPI. Owns all climate data, grading, the API, accounts, notifications, plus a Go daemon (backend/daemon/) that owns the Discord gateway and recurring timers. Ships asjinemi/thermograph/backend.frontend/— Go SSR service (frontend/server/) plus every static asset. No climate data, no database, no compute. Ships asjinemi/thermograph/frontend. (The Python implementation atfrontend/*.pyis the superseded original — see traps.)infra/— compose and Swarm files, deploy scripts, the SOPS secrets vault, Terraform, ops query tooling.observability/— Loki + Grafana on vps1, an Alloy agent per node.
Branches stage environments: PR → dev (vps1, mesh-only) → main (beta, vps2)
→ release (prod, vps2). The two app domains build and deploy
independently — that independence is the whole reason the split-then-reunify
history exists, and contracts is the list of things that
keep it safe.
Your first day
- Read Orientation and Traps.
- Work through Local setup until
make testis green in bothbackend/andfrontend/server/. - Read Repo map with the tree open beside it.
- Pick something small in the domain you're least afraid of, and follow Recipes end to end — including opening the PR.
Your first week
- Read Contracts properly. Every item on that list has already cost someone a production incident somewhere in this project's history; that's why each one is written down.
- Get Centralis wired up (see Local setup) and ask it
fleet_status,logs_overview,deployed_version. You cannot debug this estate blind, and the boxes are not reachable from a laptop off the WireGuard mesh. - Read the
CLAUDE.mdfor each domain. They are terse, current, and binding.