docs(modules): close Phase 4 — de-UO the backend reference, record the acceptance run
Phase 4 slice 4. BACKEND_DESIGN.md had never been de-UO'd: Phase 3 rewrote core's code and README, but §5.2's identifier check reads code, not prose, so nothing ever looked at the design document. It still described 27 shard_* tables, 20 UO route rows and the shard visibility ladder as core's, a phase after core stopped being able to serve any of them. Moved, text unchanged: BACKEND_DESIGN §3 six shard_* schema sections (226 lines) → modules/uo/SCHEMA.md BACKEND_DESIGN §4 13 public + 7 admin UO route rows → modules/uo/API.md BACKEND_DESIGN §6.5 the audience ladder (70 lines) → modules/uo/API.md §4 Core keeps the seam and gains the eight /admin/modules routes it had never documented. §6.5 becomes "Module-owned audience boundaries": core's security boundary ends at authentication, roles and the session, and a module that serves game data brings its own. Also fixed on the way: users.router.js was still listed as 15 routes (it is 9 — six went to the extension slot), and the push section still promised config/shardStreams.js "moves out with it" four slices after it left. The acceptance table now carries results. Criterion 2 was proved for real against module-uo v0.3.0 on an empty database, which turned up the uninstall ordering defect fixed in website#146. AI disclosure: this contribution was AI-assisted (Claude Code). Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,8 @@ these routes *mean* are the ones that already existed and did not move:
|
||||
|
||||
| Doc | What it covers |
|
||||
|---|---|
|
||||
| [`API.md`](API.md) | **This module's 72 URLs** and the audience ladder that gates them — moved out of core's `BACKEND_DESIGN.md` §4/§6.5 |
|
||||
| [`SCHEMA.md`](SCHEMA.md) | **The 27 tables it owns** and why they are shaped that way — moved out of core's `BACKEND_DESIGN.md` §3 |
|
||||
| [`SHARD_VISIBILITY.md`](../../website/SHARD_VISIBILITY.md) | Who sees which shard data — the admin-configurable audience framework |
|
||||
| [`SPAWN_ATLAS.md`](../../website/SPAWN_ATLAS.md) | The bestiary / spawn atlas, parsed from the shard's own ServUO tree |
|
||||
| [`MARKETPLACE.md`](../../website/MARKETPLACE.md) | The player-vendor index |
|
||||
@@ -30,7 +32,8 @@ these routes *mean* are the ones that already existed and did not move:
|
||||
[`routes.manifest.json`](https://gitea.whitlocktech.com/RunicGateway/Module-uo/src/branch/main/routes.manifest.json)
|
||||
and documented in its
|
||||
[`swagger-fragment.json`](https://gitea.whitlocktech.com/RunicGateway/Module-uo/src/branch/main/swagger-fragment.json),
|
||||
which core merges into `/api/docs.json` while the module is running.
|
||||
which core merges into `/api/docs.json` while the module is running. Route counts, gates and the
|
||||
notes that used to sit in core's contract are in [`API.md`](API.md).
|
||||
|
||||
| Mount | Tier | What |
|
||||
|---|---|---|
|
||||
@@ -52,7 +55,8 @@ into core's nav so an operator can reorder, relabel or hide them like any other
|
||||
|
||||
## What it owns
|
||||
|
||||
- **27 database tables** — 26 `shard_*` plus `uo_link_config`. Created by an idempotent
|
||||
- **27 database tables** — 26 `shard_*` plus `uo_link_config`, documented one by one in
|
||||
[`SCHEMA.md`](SCHEMA.md). Created by an idempotent
|
||||
`schema.sql` fragment core replays on every boot, after its own schema. The `shard_`/`uo_link_`
|
||||
prefixes are **grandfathered** ([`MODULE_API.md`](../../website/MODULE_API.md) §6.5): the rule for
|
||||
a new module is `<id>_`, and these predate it.
|
||||
@@ -65,10 +69,35 @@ into core's nav so an operator can reorder, relabel or hide them like any other
|
||||
|
||||
## For an operator
|
||||
|
||||
**Installing.** A release is `module-uo-<version>.tar.gz` plus a manifest carrying its `sha256`.
|
||||
Unpack it as `modules/uo/` on the website's modules volume (or use the admin Modules screen when
|
||||
phase 4 lands) and restart. **You never build anything** — the client chunk is prebuilt and the one
|
||||
runtime dependency ships inside the tarball.
|
||||
**Installing — three ways in, and none of them is a build.** A release publishes
|
||||
`module-uo-<version>.tar.gz`, an install manifest `module-uo-<version>.json` carrying its `sha256`,
|
||||
and a `SHA256SUMS`. **You never build anything**: the client chunk is prebuilt and the one runtime
|
||||
dependency ships inside the tarball.
|
||||
|
||||
| | How | Where it fits |
|
||||
|---|---|---|
|
||||
| **Admin panel** | **Admin → Modules**, paste the URL of the release's `module-uo-<version>.json`, then press Restart when it asks | The click path — no shell on the box. Core downloads the artifact the manifest names, verifies the declared `sha256`, inspects the whole archive before writing anything, and unpacks it as `modules/uo/` |
|
||||
| **`MODULES`** | Declare it in the environment and the container resolves it at every start:<br>`MODULES=uo@0.3.0=https://…/module-uo-0.3.0.json` | The compose-managed host. The running set is a line in a file you version-control. Already at that version ⇒ no network at all, so a restart with the internet down comes up unchanged |
|
||||
| **By hand** | `tar -xf module-uo-0.3.0.tar.gz -C ./modules && mv modules/module-uo-0.3.0 modules/uo`, then restart | Development, and any host where the other two do not fit. The bundle's top-level directory is named after the release, not after the module id — rename it to `uo` |
|
||||
|
||||
The install source must be an `https` host on the allowlist (seeded from `MODULE_SOURCE_HOSTS`,
|
||||
editable in the panel from then on). The `sha256` in the manifest is the trust anchor; the allowlist
|
||||
is what stops a pasted URL from being an SSRF primitive as well.
|
||||
|
||||
**Uninstalling, and the one destructive choice.** Uninstall removes the module's directory and
|
||||
leaves its row `disabled` — **your data is kept**, and reinstalling picks it up exactly where it was.
|
||||
Deleting the data is a separate, opt-in tick box *inside* the uninstall dialog, and it has to be
|
||||
there rather than after: `purge.sql` is a file inside the directory being deleted. There is also a
|
||||
standalone **Purge** action on a module that is still installed but disabled. Purging drops all 27
|
||||
tables; it does **not** touch the two `settings` rows (renaming or deleting
|
||||
`uo_link_protocol_3_migrated` would re-arm a protocol migration against tables that no longer
|
||||
exist), and what the module can re-derive from your ServUO tree — the atlas and the cliloc table — is
|
||||
rebuilt at the next boot. Everything the shard and your players produced is gone.
|
||||
|
||||
**Disabling is a kill switch, not a visibility flag.** Disable runs the module's `onShutdown`
|
||||
immediately: the uo-link WebSocket closes, the SSE streams end, and its routes, nav rows and client
|
||||
chunk answer 404. Re-enabling flips the row and asks for a restart, because there is no `onBoot`
|
||||
re-dispatch — the hooks have never been promised to be re-entrant.
|
||||
|
||||
**Connecting it to a shard.** The module needs the
|
||||
[uo-link sidecar](https://gitea.whitlocktech.com/RunicGateway/link) running next to the ServUO
|
||||
|
||||
Reference in New Issue
Block a user