Commit graph

4 commits

Author SHA1 Message Date
Emi Griffith
083d3bd0f8 Approximate-location fallback from the client IP (feature-flagged off)
All checks were successful
PR build (required check) / changes (pull_request) Successful in 6s
secrets-guard / encrypted (pull_request) Successful in 5s
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Successful in 1m8s
PR build (required check) / build-backend (pull_request) Successful in 1m36s
PR build (required check) / gate (pull_request) Successful in 2s
A visitor who declines browser geolocation currently has no location at all —
the copy sends them to the map picker. This adds an opt-in fallback that
suggests a coarse city from the request's own IP, presented as a guess with a
one-tap correction, so the dead end has a way out.

backend/data/geoip.py does the lookup against a local MMDB file (DB-IP IP to
City Lite or GeoLite2 City — same format, either works, attribution derived
from the file's metadata). Off unless THERMOGRAPH_GEOIP is truthy AND the
database exists AND maxminddb imports; every degraded case — private/reserved/
CGNAT/IPv6-ULA addresses, unparseable input, no record, a country-centroid
record with no city, a record wider than the accuracy limit, a corrupt file —
returns None, which the route answers as 204 and the client treats exactly as
today.

The IP is read in memory and dropped. GET /api/v2/geoip runs no RunAudit,
records no metric dimension, and is excluded from the access log (its own
"geoip" traffic category) so no stored, joinable (IP, location) pair is ever
written. The response is no-store/Vary:* and takes no parameters.

Client-side rather than server-rendered on purpose: the homepage's HTML and
weak ETag must stay byte-identical for every visitor, or any cache added in
front of it can serve one visitor's city to another. The suggestion is fetched
only after a declined/unavailable prompt, and only when nothing is remembered.

A guess is never persisted — no localStorage write, no URL hash — and the hero
and results headings say "roughly near"/"near … approximate" rather than
letting the reverse-geocoded cell name a neighbourhood the lookup never knew.

The /privacy page's "never looks up your location from your IP address"
paragraph now follows the same flag out of the same env file, so the published
statement and the behaviour flip together.

Database lifecycle is a host-side systemd timer (infra/deploy/geoip-refresh.*)
that verifies a download opens and answers before swapping it in atomically,
bind-mounted read-only; geoip.py re-opens on mtime change, so a refresh needs
no restart. GEOIP-APPROX-LOCATION.md carries the database comparison, the
SSR-vs-client argument, the privacy analysis, and the open decisions.
2026-07-23 16:22:37 -07:00
emi
8e09155aaf Run the ERA5 lake service in every environment (#20)
All checks were successful
secrets-guard / encrypted (push) Successful in 6s
2026-07-23 22:32:13 +00:00
Emi Griffith
2e753f2c6f deploy: adapt scripts + compose to the monorepo host checkout
/opt/thermograph becomes a monorepo checkout: deploy.sh gains INFRA_DIR (git
ops at the root, compose work cd'd into infra/), lock/tags/render paths move
under infra/deploy/, image-path defaults become emi/thermograph/backend|
frontend across compose, stack, and the tag-prune. docker-compose.yml pins
name: thermograph -- without it compose run from .../infra derives project
"infra" and recreates the whole stack beside the running one;
deploy-dev.sh pins COMPOSE_PROJECT_NAME=thermograph-dev (env wins over the
file key) to keep LAN dev's separate project.
2026-07-22 22:11:33 -07:00
Emi Griffith
ae1d9bb534 Subtree-merge thermograph-infra (origin/main) into infra/
git-subtree-dir: infra
git-subtree-mainline: d6df04eab2
git-subtree-split: 99b4b3f78d
2026-07-22 22:01:11 -07:00