Skip to content

feat: fort map-data consumer — gyms (stations/pokestops/DNF to follow)#1228

Draft
jfberry wants to merge 15 commits into
WatWowMap:developfrom
jfberry:feat/fort-consumer
Draft

feat: fort map-data consumer — gyms (stations/pokestops/DNF to follow)#1228
jfberry wants to merge 15 commits into
WatWowMap:developfrom
jfberry:feat/fort-consumer

Conversation

@jfberry

@jfberry jfberry commented Jul 16, 2026

Copy link
Copy Markdown

Summary

Routes ReactMap's fort map-data (markers, popups, filter lists) through Golbat's in-memory fort endpoints instead of SQL, with automatic SQL fallback — the Phase‑2 ReactMap consumer for the Golbat fort-scan work (Golbat draft UnownHash/Golbat#385). Stacks on #1227 (the pokestop-available consumer) and reuses its dual endpoint+DB source plumbing.

This PR is built in slices on one branch; the branch is a draft until all slices land and it's validated against a Golbat deploy.

Landed so far: gyms (match-all)

  • server/src/utils/evalScannerQuery.js (new) — shared endpoint-or-knex fetch helper (secret / HTTP-Basic auth, queryDebug), so gym/station consumers don't each re-copy Pokemon.evalQuery.
  • server/src/models/gymAvailableMapper.js (new) — pure mapper: Golbat /api/gym/available {teams,raids} → the t/g/e/r + raid-boss filter keys, reproducing the SQL Gym.getAvailable output exactly.
  • Gym.getAvailableGET /api/gym/available, with SQL fallthrough on 503/error (dual source).
  • Gym.getAllPOST /api/gym/scan match-all (filters: []); endpoint rows feed the existing secondaryFilter unchanged (ApiGymResult field names already match ReactMap's), with client-side enabled/!deleted, hideOldGyms, power_up_level, and filterRTree area filtering; SQL fallback on any endpoint failure.
  • Gym.getOneGET /api/gym/id/{id}, with SQL fallback.

Coming on this branch (follow-on slices)

Stations (match-all), pokestops (match-all, needs Golbat with_incidents), then DNF filtering for all three (a fort filter Backend mirroring PkmnBackend) — the payoff phase that replaces filters: [] with translated ApiFortDnfFilter[] so Golbat does the narrowing.

Design notes

  • No row mapper for gym getAll. Golbat's ApiGymResult uses ReactMap's own field names, so scan rows go straight into secondaryFilter; only the aggregate getAvailable needs a mapper.
  • Area restriction moved to app code. getAreaSql is SQL-only, and (notably) the Pokemon.getAll endpoint path applies no area filter — this consumer deliberately adds filterRTree on the fort endpoint path so area restrictions are enforced.
  • Dual-source fallback. Every mem branch returns only on endpoint success and otherwise falls through to the existing SQL — a dual (endpoint + DB) source keeps working through a Golbat outage; a pure-endpoint source is dropped upstream. A Golbat network/timeout returns undefined (distinguishable from an empty result) so getAll falls back rather than silently blanking markers.
  • Badges stay on the ReactMap-local Badge table, merged unchanged.

Testing

Per repo convention there is no test framework and the maintainer opted out of TDD. Verified via eslint + prettier (clean on all changed files), a throwaway node golden check on the mapper (exact key parity with the SQL path), reasoning against each SQL branch, and per-task + whole-branch subagent code review (two Important findings — getAll net-error fallback and the power_up_level filter — found and fixed).

Live end-to-end validation is deferred until Golbat #385 is deployed (fort_in_memory on): confirm gym/raid markers, popups, and the gym filter list match the DB path, and area restrictions hold.

Depends on

🤖 Generated with Claude Code

jfberry and others added 15 commits July 14, 2026 17:32
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pure, dependency-free mapper that reproduces Pokestop.js's SQL-derived
{ available, conditions } filter-key shape from the structured tuples
returned by Golbat's GET /api/pokestop/available, so a future endpoint
consumer can replace the SQL block key-for-key.
…tardust

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wires Pokestop.getAvailable() to Golbat's GET /api/pokestop/available
when a source has `mem` set (an endpoint source), using the Task 2
mapper to build the same {available, conditions} shape the SQL path
produces. Falls back to the existing SQL block unchanged on a
non-2xx response, a network/timeout error, or any thrown error;
MAD/DB sources (mem: '') skip the branch entirely and always run SQL.

Extracts the config-gated `fallbackRocketPokemonFiltering` a${id}-${form}
backfill (previously inline in the SQL rocketPokemon case) into a shared
applyRocketPokemonFallback() helper so both the endpoint and SQL paths
stay byte-identical. Adds a Pokestop.evalQuery static mirroring
Pokemon.evalQuery, since Pokestop extends Model directly and had no
endpoint-fetch helper of its own.
… SQL fallback path)

Endpoint sources (mem truthy) have no bound knex, so on
/api/pokestop/available failure the previous fallthrough to the SQL
block threw on this.query(), was swallowed by Promise.allSettled, and
silently contributed zero filter keys. Endpoint sources are now
endpoint-authoritative: on failure they return a clean empty
{ available: [], conditions: {} } instead of falling through, matching
Pokemon.getAvailable. The SQL block is reached only for mem:'' (DB/MAD)
sources.
A source with both a Golbat endpoint and DB creds now registers the
endpoint AND builds a knex connection: migrated queries (Pokestop
getAvailable) use the endpoint, un-migrated ones (getAll/getOne/search/
submissions) fall back to this.query() on the bound DB — so a Golbat
pokestop endpoint no longer breaks map markers/popups/search.

- DbManager: keep the knex connection for endpoint schemas that also
  carry DB creds; overlay mem/secret/httpAuth onto the schemaChecked
  context so isMad/has* flags survive.
- Pokestop.getAvailable: on endpoint failure fall through to the SQL block
  (a dual source runs it on the bound knex; a pure-endpoint source throws
  and is dropped by allSettled) instead of returning empty.
- types: ApiEndpoint.httpAuth typed; DbConnection gains optional
  endpoint/secret/httpAuth for the dual shape.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…the Golbat endpoint

The DbManager fan-out logs "[DB] Querying available for Pokestop" before any
source picks endpoint-vs-SQL, so it can't confirm the endpoint path ran. Add
an [POKESTOPS] info line on the endpoint success path with the endpoint URL and
per-category counts, so operators can positively confirm the pokestop available
list came from Golbat (and by its absence, that it fell back to SQL).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
First slice of the reactmap fort-scan consumer: route Gym.getAll/getOne/
getAvailable through Golbat's fort endpoints with SQL fallback. Adds a shared
evalScannerQuery util + gymAvailableMapper; getAll reuses secondaryFilter (no
row mapper — ApiGymResult keys match) and adds filterRTree area handling.
Stations/pokestops/DNF are follow-on plans on this branch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant