docs(website): settle what core publishes about an installed module
Phase 2, PR 6 of MODULE_SYSTEM.md 2.7 — GET /api/v1/public/modules. MODULE_API.md gains 2.9, the normative shape: four fields (id, name, version, capabilities) in scan order, and what is deliberately absent. Only started modules appear, so a disabled or failed one is absent exactly as 4.4 already leaves its routes and nav; no state, failure_stage or failure_reason reaches an anonymous caller; no client chunk URL, because htmlShell hands the browser the tag; an empty array is a real answer, but the 7.6 guard is a 500 and never []. Also records why it owns the /modules prefix rather than sitting in the root-mounted site router, where the loader's collision probe could not see it. 6.7 amends MODULE_SYSTEM 2.6 step 4, which said the SPA reads the endpoint "to learn what to load" — step 3 of the same list had already answered loading a different way, and 3.1.3 is the normative version. The endpoint feature-detects. 2.6 step 4 now says so, and Part 6's intro no longer claims a fixed count of amendments. MODULE_SYSTEM.md 2.7 records PR 6 and restates the phase exit criterion honestly: no EXISTING URL moves, and PR 6 is the single deliberate addition in Phase 2. Status line updated — the design is in implementation, not unimplemented. BACKEND_DESIGN.md documents the route in the /public table and the router in the folder map, and the published api-route-inventory.json mirror is refreshed to 228 public routes (the prose count was stale at 226). Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -105,6 +105,12 @@ server/
|
||||
NOT under /shard: nothing here
|
||||
touches the sidecar, and unlike
|
||||
/shard it IS site-mode gated
|
||||
modules.router.js (1) /public/modules — the installed-module
|
||||
list a client feature-detects against.
|
||||
A real prefix and not a fifth singleton
|
||||
below, so the module loader's
|
||||
collision probe (which skips
|
||||
root-mounted layers) sees it
|
||||
site.router.js (4) /settings /status /version /contact —
|
||||
the group-root singletons; declares no
|
||||
router-level middleware
|
||||
@@ -715,7 +721,7 @@ are authoritative, and they answer different questions:
|
||||
|
||||
| Artifact | Source of truth for | Generated by |
|
||||
|---|---|---|
|
||||
| `server/routes.manifest.json` — mirrored as [api-route-inventory.json](./api-route-inventory.json) | **What URLs exist.** 226 public routes + 2 on the internal listener, sorted, method + path only. | `npm run routes:manifest`, by walking the live Express stack |
|
||||
| `server/routes.manifest.json` — mirrored as [api-route-inventory.json](./api-route-inventory.json) | **What URLs exist.** 228 public routes + 2 on the internal listener, sorted, method + path only. | `npm run routes:manifest`, by walking the live Express stack |
|
||||
| `server/swagger/swagger-output.json` — served at `/api/docs` | **What each route means.** Parameters, bodies, response codes, security. | `npm run swagger`, from `#swagger.*` annotations |
|
||||
|
||||
The split is deliberate: Swagger is annotation-derived, so an unannotated route is invisible in it and
|
||||
@@ -898,6 +904,7 @@ from the per-route **siteMode** middleware (§5), never from an auth gate.
|
||||
| GET | `/settings` | whitelisted public keys, derived `registration`/`gameAccountSignup` flags, the per-shard **`brand`** block (name, `accent` color, logo/hero/favicon) a client themes itself from — one image runs as any shard, asset fields may be site-relative paths (resolve against the base URL); these are **effective** values, so an admin theme (`theme_visual`) beats `BRAND_ACCENT_COLOR` and an uploaded `brand_assets` asset beats its `BRAND_*` path — an optional **`theme`** block, the resolved CSS custom properties for that admin theme (absent when the instance was never themed, which is what makes it render from the shipped stylesheet unchanged) — and a **`push`** block `{ ntfyUrl }` (M7): the client-facing ntfy relay URL the app's embedded distributor registers its device topic against, from `NTFY_PUBLIC_URL` / first `NTFY_ALLOWED_ORIGINS` (never the internal `NTFY_BASE_URL`); `null` when push isn't configured for the shard. |
|
||||
| GET | `/status` | status message + current mode, **plus a `version` block** (`{ service:'runic-gateway', api, server }`) so a client first-run probe recognizes the backend and can run a version-mismatch guard |
|
||||
| GET | `/version` | lightweight, **DB-free** backend identity/version (`{ service, api, server }`) — the canonical target for the version guard and a cheap liveness check |
|
||||
| GET | `/modules` | `{ modules: [{ id, name, version, capabilities }] }` — the modules this backend is currently **serving**, in scan order (module system, `MODULE_API.md` §2.9). A module that is disabled or failed to load is **absent**, not listed with a state: its routes and nav are absent too, so the client renders a site without that capability rather than advertising one that 503s. The recorded failure stage and reason are admin-panel detail and are never published here. `capabilities` are opaque strings the module declares — feature-detect against them and treat an unknown one as absent. Like `/status` and `/version` it is **DB-free and not site-mode gated**, so a client can still feature-detect during maintenance. It is *not* how a module's client chunk loads — `htmlShell` injects a `<script type="module">` per started module. |
|
||||
| GET | `/posts/:category` | published only; `category` ∈ news\|five-on-friday\|newsletter\|screenshots |
|
||||
| GET | `/posts/:category/:idOrSlug` | single published post |
|
||||
| GET | `/wiki` | list of pages (slug + title) |
|
||||
|
||||
Reference in New Issue
Block a user