Nearmap basemap option for Nidus Reveal (issue #184) #185

Closed
ned wants to merge 2 commits from issue-184-nearmap-tiles into main
Member

Closes #184 — exposes Nearmap (and future external tile vendors) as a basemap option in the main Nidus Reveal UI.

What

  • nearmap/ package: minimal resty client for https://api.nearmap.com/tiles/v3/Vert/{z}/{x}/{y}.img (256×256 JPEG, CORS-enabled — verified against the live API with the Delta key). Rejects non-JPEG responses; parses {"error": ...} bodies like "No tile found for this request" (out-of-coverage areas).
  • Per-organization gating (migration 00239): the Nearmap key lives in public.organization.nearmap_api_key (nullable), NOT an env var. Districts share one production instance, so a global NEARMAP_API_KEY would have exposed Delta's paid Nearmap subscription to every district — the licensing violation Benjamin flagged on #184. The key is set via org update or sudo org update; the sudo org summary exposes a nearmapEnabled flag without leaking the key value.
  • GET /api/vision/tile/nearmap/{z}/{x}/{y}: reuses the existing Stadia tile-proxy path (serveVisionTile) — worker/session auth, disk cache under {FilesDirectory}/nearmap-cache/{orgID}/ (namespaced per org). The key is resolved from the authenticated user's org and the gate is checked BEFORE the cache read, so a district without a key can neither fetch nor read cached Nearmap imagery. Worker-token requests pass no user and never see Nearmap.
  • GET /api/vision/basemaps: reports nearmap only for orgs with a key, so the UI button is hidden for non-subscribers.
  • UI: MapStyleSwitcher generalized from a 2-state toggle to an option list (default unchanged: Map/Satellite); the Reveal map gains a Nearmap option rendering /api/vision/tile/nearmap/{z}/{x}/{y} as a 256 raster overlay, same as satellite. Options are filtered on mount by /api/vision/basemaps.
  • README: documents per-org key setup; the env var entry is removed.

Also fixes (pre-existing, blocks CI on main)

Commit f98b9485 declared maskSource/confirmedOnly inside the for loop in postTrainManifest but the manifest INSERT references them after the loop — go build ./api/ failed on main. Hoisted the computation above the loop (no behavior change).

Verification

  • go build ./..., go vet ./api ./nearmap ./config clean; go test ./nearmap 3/3 pass, plus a regression test for Organization.NearmapAPIKey().
  • pnpm typecheck clean; pnpm build-sync clean.
  • Nearmap tile fetch verified live: HTTP 200 JPEG at z12/z16/z18 (Phoenix + Denver), access-control-allow-origin: * with Origin header.
  • CI run 1020 green (golint ✅ pnpm-build ✅) on the branch head.

Deploy note

Apply migration 00239 (goose up), then set Delta's key per org via org update / sudo org update (nearmap_api_key). No env var needed.

Closes #184 — exposes Nearmap (and future external tile vendors) as a basemap option in the main Nidus Reveal UI. ## What - **`nearmap/` package**: minimal resty client for `https://api.nearmap.com/tiles/v3/Vert/{z}/{x}/{y}.img` (256×256 JPEG, CORS-enabled — verified against the live API with the Delta key). Rejects non-JPEG responses; parses `{"error": ...}` bodies like "No tile found for this request" (out-of-coverage areas). - **Per-organization gating** (migration 00239): the Nearmap key lives in `public.organization.nearmap_api_key` (nullable), NOT an env var. Districts share one production instance, so a global `NEARMAP_API_KEY` would have exposed Delta's paid Nearmap subscription to every district — the licensing violation Benjamin flagged on #184. The key is set via org update or sudo org update; the sudo org summary exposes a `nearmapEnabled` flag without leaking the key value. - **`GET /api/vision/tile/nearmap/{z}/{x}/{y}`**: reuses the existing Stadia tile-proxy path (`serveVisionTile`) — worker/session auth, disk cache under `{FilesDirectory}/nearmap-cache/{orgID}/` (namespaced per org). The key is resolved from the authenticated user's org and the gate is checked BEFORE the cache read, so a district without a key can neither fetch nor read cached Nearmap imagery. Worker-token requests pass no user and never see Nearmap. - **`GET /api/vision/basemaps`**: reports `nearmap` only for orgs with a key, so the UI button is hidden for non-subscribers. - **UI**: `MapStyleSwitcher` generalized from a 2-state toggle to an option list (default unchanged: Map/Satellite); the Reveal map gains a Nearmap option rendering `/api/vision/tile/nearmap/{z}/{x}/{y}` as a 256 raster overlay, same as satellite. Options are filtered on mount by `/api/vision/basemaps`. - **README**: documents per-org key setup; the env var entry is removed. ## Also fixes (pre-existing, blocks CI on main) Commit f98b9485 declared `maskSource`/`confirmedOnly` inside the `for` loop in `postTrainManifest` but the manifest INSERT references them after the loop — `go build ./api/` failed on main. Hoisted the computation above the loop (no behavior change). ## Verification - `go build ./...`, `go vet ./api ./nearmap ./config` clean; `go test ./nearmap` 3/3 pass, plus a regression test for `Organization.NearmapAPIKey()`. - `pnpm typecheck` clean; `pnpm build-sync` clean. - Nearmap tile fetch verified live: HTTP 200 JPEG at z12/z16/z18 (Phoenix + Denver), `access-control-allow-origin: *` with Origin header. - CI run 1020 green (golint ✅ pnpm-build ✅) on the branch head. ## Deploy note Apply migration 00239 (`goose up`), then set Delta's key per org via `org update` / `sudo org update` (`nearmap_api_key`). No env var needed.
Author
Member

CI is green on the PR head (commit 86a20c7f) — run 1295 success. go build/vet, tests, and pnpm typecheck/build all pass, so the branch is mergeable as-is. Note for reviewers: the postTrainManifest compile fix included here is the only thing un-breaking go build ./api/ on main (f98b9485 broke it), so main stays red until this merges. Ready for review/merge — shout if you want anything changed.

CI is green on the PR head (commit 86a20c7f) — run 1295 success. `go build`/vet, tests, and pnpm typecheck/build all pass, so the branch is mergeable as-is. Note for reviewers: the postTrainManifest compile fix included here is the only thing un-breaking `go build ./api/` on main (f98b9485 broke it), so main stays red until this merges. Ready for review/merge — shout if you want anything changed.
Author
Member

Follow-up push (42cd58db) with the per-organization gating refactor, now folded into this PR — CI run 1020 is green on the branch head.

Why: districts share one production instance, so the original global NEARMAP_API_KEY env var would have exposed Delta's paid Nearmap subscription to every district on the deployment (the licensing concern from #184). The key now lives in the DB instead:

  • public.organization.nearmap_api_key (nullable) — migration 00239; set via org update / sudo org update; sudo summary exposes a nearmapEnabled flag without leaking the key
  • /api/vision/basemaps reports nearmap only for orgs with a key (UI button hidden otherwise)
  • the tile proxy resolves the key from the authenticated user's org and gates BEFORE reading the cache — no key, no fetch, no cached reads
  • disk cache namespaced per org (nearmap-cache/{orgID}/...) so tiles cached for one district are never served to another
  • worker-token requests pass no user → never see Nearmap

The env var and its README entry are removed. PR description updated with the new deploy steps (goose up 00239 + per-org key, no env var).

Follow-up push (42cd58db) with the per-organization gating refactor, now folded into this PR — CI run 1020 is green on the branch head. Why: districts share one production instance, so the original global `NEARMAP_API_KEY` env var would have exposed Delta's paid Nearmap subscription to every district on the deployment (the licensing concern from #184). The key now lives in the DB instead: - `public.organization.nearmap_api_key` (nullable) — migration 00239; set via org update / sudo org update; sudo summary exposes a `nearmapEnabled` flag without leaking the key - `/api/vision/basemaps` reports nearmap only for orgs with a key (UI button hidden otherwise) - the tile proxy resolves the key from the authenticated user's org and gates BEFORE reading the cache — no key, no fetch, no cached reads - disk cache namespaced per org (`nearmap-cache/{orgID}/...`) so tiles cached for one district are never served to another - worker-token requests pass no user → never see Nearmap The env var and its README entry are removed. PR description updated with the new deploy steps (goose up 00239 + per-org key, no env var).
eliribble force-pushed issue-184-nearmap-tiles from 42cd58db01
All checks were successful
/ golint (push) Successful in 21s
/ pnpm-build (push) Successful in 1m16s
to 23cbba601b
All checks were successful
/ golint (push) Successful in 21s
/ pnpm-build (push) Successful in 1m46s
2026-08-29 22:18:25 +00:00
Compare
Owner

Nearmap has since been added in later commits.

Nearmap has since been added in later commits.
eliribble closed this pull request 2026-09-04 21:37:52 +00:00
All checks were successful
/ golint (push) Successful in 21s
/ pnpm-build (push) Successful in 1m46s

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Gleipnir/nidus-sync!185
No description provided.