From 931f77ef496055e0e39d4c79fc604247f63baada Mon Sep 17 00:00:00 2001 From: wtclaude Date: Tue, 11 Aug 2026 19:00:43 -0500 Subject: [PATCH] docs(website): record slice 3, and MODULE_API 1.3.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The client half's move: 35 files / 5,332 lines (the table said 51 / ~3,700 and is corrected, not re-derived to match). The seven-kit-members-plus-format claim held exactly, so the kit needed no additions. Contract, 1.2.0 -> 1.3.0, all additive: `icon` on a nav item, a third slot `player.invite.accepted`, and `api.BASE` — which §3.5 specified from the first draft and shared.js had never published, because nothing needed it until a module had to build an EventSource URL. §2.3's narrowing note said game-signup policy was core's business. It was wrong in both directions: the setting's help text names Bridge.cfg, and slice 1 had shipped a controller calling a function the narrowing does not expose, so POST /player/shard/account answered 500 for every caller until this slice. §3.7 gains the rule the invite slot needed: core may ask whether a slot is filled when the answer changes CONTROL FLOW, never when it changes decoration. Decoration goes inside `` — that is the footer-separator bug. §7.7 gains what running it against the real module found, rather than a throwaway: the unguarded portal icon, the relative-MODULES_DIR trap, and the two operational notes (a module needs its own npm ci; copy the directory, never symlink it). Also recorded: the nav-override cost is worse than "a hidden row may reappear" — the review instance had the nine UO rows gathered into a dropdown section, and the whole section is lost. And `api-route-inventory.json` was a slice stale at 228 routes; refreshed to the 158 core actually serves. Co-Authored-By: Claude --- android/PLAN.md | 14 +- website/BACKEND_DESIGN.md | 2 +- website/MODULE_API.md | 88 +++++++++- website/MODULE_SYSTEM.md | 108 +++++++++++- website/api-route-inventory.json | 280 ------------------------------- 5 files changed, 204 insertions(+), 288 deletions(-) diff --git a/android/PLAN.md b/android/PLAN.md index e59689e..3247618 100644 --- a/android/PLAN.md +++ b/android/PLAN.md @@ -85,7 +85,7 @@ change/set password (the SSO-account "no current password" path from `has_passwo list/unlink SSO identities — each mutation folding its `ApiResult` into a section-scoped, localized banner (§7). **Game-account linking** (§6.3) — the in-game `[link` one-time code (`POST /player/shard/link`) plus the hybrid signup (`POST /player/shard/account`, shown only when the public -`gameAccountSignup` flag is set), and the linked-accounts list. **Own game data**, text-only (§6.3): +`gameAccountSignup` flag is set — see the OWED note below), and the linked-accounts list. **Own game data**, text-only (§6.3): per-account character roster → a character sheet (attributes, vitals, resistances, best-first skills, equipment with AOS mods, and guild/governor standing chips — bare cliloc-number titles/item names are skipped, as the app ships no cliloc table, matching the website's `CharacterSheet.jsx`); player @@ -99,6 +99,18 @@ spec-aligned (as recorded for M1); 17 new JVM unit tests cover the account + pla **No backend/API change** — the `/auth/me/*` and `/player/shard/*` surfaces the app consumes were the §8 prerequisites, already landed. +> **OWED — `gameAccountSignup` moved and the app has not followed (2026-08-11).** Phase 3 slice 3 of +> the website's module extraction (`docs/website/MODULE_SYSTEM.md` §2.7.1) moved game-account signup +> policy out of core: the flag is no longer on `GET /public/settings` and is now on module-uo's +> `GET /public/shard/features`, beside the visibility flags. `PublicDto.kt:80` defaults it to +> `false`, so **nothing crashes** — `CharactersViewModel.kt:72` reads `false` and the app simply +> stops offering game-account creation. The fix is one DTO field, one ViewModel line and two tests, +> reading the flag from the features endpoint the app already calls. +> +> Deferred rather than coordinated into the slice (org lead, 2026-08-11): the website work lands on +> `edge` and reaches `main` as one cutover, so there is room. **It must land before that cutover** — +> after it, a shipped app quietly loses a feature. + ✅ **M5 — design pass** (2026-07-20, `RunicGateway/Android-app#10`): the shard-website theme applied across every screen, restyling the working M1–M4 UI with **no architecture, data-flow, endpoint, or DTO change** (§2.1). The design was produced in Claude Design (`Runic Gateway Screens.dc.html`) and diff --git a/website/BACKEND_DESIGN.md b/website/BACKEND_DESIGN.md index 032ab13..2f0726d 100644 --- a/website/BACKEND_DESIGN.md +++ b/website/BACKEND_DESIGN.md @@ -908,7 +908,7 @@ from the per-route **siteMode** middleware (§5), never from an auth gate. | Method | Path | Notes | |---|---|---| -| 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 | `/settings` | whitelisted public keys, the derived `registration` flags (`gameAccountSignup` was one of these until the module extraction moved game-account policy to module-uo — it is on that module's `GET /public/shard/features` now, and the `game_account_signup` settings row is unchanged), 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 `