feat(atlas): serve the spawn atlas and give operators a panel for it #113
Reference in New Issue
Block a user
No description provided.
Delete Branch "feat/spawn-atlas-api"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Protocol 3.0 order 3 (Part C), second of two website PRs. #112 built the data pipeline; this makes it reachable. Still website-only: no plugin, no sidecar, no new event kinds, no wire change.
Six public routes, five admin ones, two public pages, and an admin panel.
The API is not under
/shard, and that is the pointNothing here touches the sidecar — the atlas is parsed from the shard's own ServUO tree — so
/api/v1/public/atlas/*stays complete while the shard is down, and a/shardprefix would advertise a dependency it does not have. Unlike/shard/*it issiteMode-gated, like/postsand/wiki: a bestiary is site content and follows site content's rules.GET /atlas/creatures?q=&facet=&limit=&offset=totalGET /atlas/creatures/:slugplaces,spawners,alsoHereGET /atlas/regions·/atlas/landmarksGET /atlas/champions/shard/champs, the live board)GET /atlas/metaEvery route carries
requireFeature('atlas')— 404 disabled, 403 out of rung — and projects its response.atlasdeclares no sensitive fields, so the projection is a no-op today; the call is there because §3.6.1's rule is that the first field needing a gate should be covered by construction rather than by a retrofit nobody remembers.GET /atlas/metareports the game world only. The ServUO path, the source hashes and any pending refresh describe the operator's filesystem and live on the admin route.A facet is never validated against a list — nothing in this codebase names one.
?facet=is length-bounded and matched exactly, and the filter is anEXISTSover the points rather than a JSON path orJSON_SEARCHbuilt from caller input: that function treats%and_as wildcards, so?facet=%would have matched everything.Two bugs the UI surfaced
Respawn delays were being read in the wrong unit — sometimes. XmlSpawner writes
MinDelay/MaxDelayin minutes and switches to seconds only when a delay does not divide into whole minutes, flagging that per record withDelayInSec(XmlSpawner2.cs:7462-7480, read back at:6345-6358). A5therefore means five minutes on one spawner and five seconds on the next — both plausible respawn times, which is exactly what makes it silent. 170 of 6,455 stock spawners are second-flagged. The parser now normalises to seconds and the API and UI carry seconds throughout.That exposed the hash gate as a trap. "Has the tree changed?" is the wrong question on its own: an install whose maps never change would have kept serving the old readings forever, because the only thing compared was the tree.
PARSER_VERSIONnow lives inshard_atlas_metabeside the source hashes and a mismatch counts as drift, so this fix — and any future parse correction — lands on the next boot without an operator knowing it happened.Also renamed the detail route's spawn-point array to
spawners. It waspoints, which is the count on the search route, so one key meant a number in one place and an array in the other.The admin panel
Admin → Spawn Atlas (
adminOnly— it reads a server filesystem path and replaces every atlas table, which is closer to a deploy action than to moderation): status, path, drift, counts, re-import, and the approve/reject decision for a refresh staged because it would remove a facet.Three deliberate behaviours:
status: "unavailable", not a 500.refresh()reports outcomes rather than throwing so boot is never blocked by a bad tree, and that contract is preserved at the API — the admin gets told what is wrong with their path, where a 500 would say only that something broke.activity_log(shard.atlas.import/.approve/.reject/.path).Verification
590 server tests pass (13 new in
atlasController.test.js, plus delay-unit and parser-version cases in the existing suites), 47 client tests (4 new asserting the atlas lives at/public/atlas, not/public/shard).End-to-end against the local MariaDB and the ServUO tree at
C:\Users\colby\Desktop\ServUO:/atlas/meta?limit=9999atlasaudience →staff, anonymousatlasdisabled, anonymousatlasdrops out of/shard/featuresso the nav hides itFacet-loss flow through the API, against a tree copy with
malas.xmlremoved:needsReview, removed["Malas"]; atlas untouched, all 293 Malas points still servedunchanged (refresh previously rejected)Parser-version gate on a restart with an unchanged tree:
spawn atlas refreshed from ServUO tree, and the second-flagged spawners now read 30–59s where they would have read 30–59m.Pages checked in the browser:
/site/atlas(search, facet chips, tabs, paging),/site/atlas/:slug(places, spawner table, "shares a spawner with"), and the admin panel end to end.OpenAPI spec and route manifest regenerated (204 → 215 routes). Docs: RunicGateway/docs#68.
🤖 Generated with Claude Code
https://claude.ai/code/session_01U7CBg11prhLimL9iHSX1bP