The specification the other three repositories are held against, plus the phase record. `PROTOCOL.md` §8 is the new contract. Its centre is one field: every frame now carries `type` — `event`, `snapshot`, `reply`, `control` — and the sidecar files on that and nothing else. That is the dumb-forwarder property made structural rather than intended: ten new event kinds are zero change in Rust-Link, and only a version adding an indexed column touches it at all. Also in §8: the fifteen-kind catalogue and what each frame carries; `wipeId` derived by the plugin, which REVERSES §3.2's "deriving one is the website's job" and says why; boards re-sent on connect and on a cadence; the aggregate rule (a hook that can fire more than once a second per player is a counter, not an event); the void rule that stops a read-path hook vetoing a death or a login; and `GET /feed`, a cursor route separate from `/events` because one route with two orderings serves the wrong one to every caller that forgets the parameter. §8.5 is the part to read twice. The classification of a kind as public or staff is NOT on the wire, deliberately: a boundary declared by the sender is one a compromised or out-of-date game host can widen, so the module holds a default-deny allowlist and this table is what its test holds it against. §8.8 corrects a catalogue rather than a defect: PLAN.md §10 sources `rust.login.denied` from `CanUserLogin`, and that hook fires on every attempt — the only way to learn of a denial from it is to be the denier. A denial is the absence of an approval, and protocol 2 emits both facts so phase 10 can pair them. `PLAYER_WALK.md` is new, and it exists because half this catalogue cannot fire without somebody holding a mouse. Ten steps, what each one should produce, and what counts as a pass — written so the walk can be run without watching the output live, and so the answer afterwards is readable as a transcript. PLAN.md §16 is phase 3 as built: the four decisions, the two defects only a server that BOOTED with the plugin could find (a wipe id that was null for every real session, and a two-second main-thread stall on unload), what was proven and how, and — stated plainly rather than implied — the three measurements still queued on the org lead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
141 lines
10 KiB
Markdown
141 lines
10 KiB
Markdown
# Runic Gateway — Documentation
|
|
|
|
Central documentation for the Runic Gateway platform. The docs here were
|
|
extracted from the two code repositories (with full commit history preserved)
|
|
so they live in one place, independent of either codebase.
|
|
|
|
## Layout
|
|
|
|
```
|
|
website/ docs from the website core (Node/Express + MariaDB + React/Vite)
|
|
modules/ docs for installable game modules — one directory per module id
|
|
link/ docs from the ServUO bridge (C# plugin + Rust sidecar + Node WS)
|
|
rust-link/ docs from the Rust bridge (Oxide plugin + Rust sidecar)
|
|
android/ docs from the native Android client (Kotlin + Jetpack Compose)
|
|
installer/ docs for the installer that deploys a shard's bridge components
|
|
ci/ cross-cutting CI/quality notes
|
|
```
|
|
|
|
**Setting up a shard?** [`installer/INSTALL.md`](installer/INSTALL.md) is the operator guide, and
|
|
the installer is the supported path: one binary deploys the plugin overlay, installs the uo-link
|
|
sidecar as a service, and hands you the values the website needs.
|
|
|
|
### `website/`
|
|
| Doc | What it covers |
|
|
|---|---|
|
|
| [BACKEND_DESIGN.md](website/BACKEND_DESIGN.md) | API contract, DB schema, security model |
|
|
| [ARCHITECTURE.md](website/ARCHITECTURE.md) | The system diagram — how core, an installed module, the sidecar and the clients fit together |
|
|
| [TEAMS.md](website/TEAMS.md) | Teams as a platform primitive: roster, forums, notifications, Discord slash commands and voice — design of record |
|
|
| [ENGAGEMENT.md](website/ENGAGEMENT.md) | The engagement system: module-declared event triggers, rules, cooldowns, templates and the email / push / in-app delivery channels — design of record |
|
|
| [HERO_EDITOR.md](website/HERO_EDITOR.md) | Hero canvas editor feature spec |
|
|
| [THEMING_AND_NAV.md](website/THEMING_AND_NAV.md) | Admin-configurable theme, brand assets and navigation — build contract |
|
|
| [MODULE_SYSTEM.md](website/MODULE_SYSTEM.md) | Making the site game-agnostic: game logic becomes an installable module — design of record |
|
|
| [MODULE_API.md](website/MODULE_API.md) | The module ↔ core contract: `ctx`, the `register*` calls, the client registry and the loader's obligations |
|
|
| [UPGRADE_NOTES.md](website/UPGRADE_NOTES.md) | **Operator-facing, newest first** — the upgrades that need an operator to do something, or that change behaviour quietly enough to be discovered by accident |
|
|
| [WIKI_UPGRADE.md](website/WIKI_UPGRADE.md) | Wiki subsystem upgrade notes |
|
|
| [SHARD_VISIBILITY.md](website/SHARD_VISIBILITY.md) | Who sees which shard data — the admin-configurable audience framework |
|
|
| [TRUSTED_DEVICES_MFA.md](website/TRUSTED_DEVICES_MFA.md) | TOTP two-factor, trusted devices and recovery codes |
|
|
| [MODERATION_APPEALS.md](website/MODERATION_APPEALS.md) | Moderation actions, content reports and the appeals flow |
|
|
| [SPAWN_ATLAS.md](website/SPAWN_ATLAS.md) | The bestiary / spawn atlas: what the shard contains, parsed from the shard's own ServUO files — served over the bridge since Protocol 8, so no shared filesystem |
|
|
| [CLILOCS.md](website/CLILOCS.md) | UO's id → name table, so items have names. The shard decompresses and serves it over the bridge; the desktop conversion it replaced is gone |
|
|
| [MARKETPLACE.md](website/MARKETPLACE.md) | The player-vendor index: how it is gathered, what it costs, how to tune it |
|
|
| [website-README.md](website/website-README.md) | Snapshot of the website repo's README (setup/run reference) |
|
|
| [test-plan.md](website/test-plan.md) | The website's test strategy and harness |
|
|
| [API_V2_PLAN.md](website/API_V2_PLAN.md) | Router domain split + CSP hardening. The split is complete; only the CSP enforce step remains |
|
|
| [API_V2_SKELETON.md](website/API_V2_SKELETON.md) | **Superseded** — the `/api/v2` scaffold that was never built. Kept as the record of why the split was done in place instead |
|
|
| [PROJECT_TREE.md](website/PROJECT_TREE.md) | Auto-generated snapshot of the repo's tracked file layout |
|
|
|
|
### `modules/`
|
|
|
|
Documentation for installable game modules aggregates here rather than in each module's repo
|
|
([MODULE_SYSTEM.md](website/MODULE_SYSTEM.md) §2.10). The website core knows nothing about any
|
|
particular game; a module is what makes it a site *for* one.
|
|
|
|
| Doc | What it covers |
|
|
|---|---|
|
|
| [uo/](modules/uo/README.md) | **module-uo** — the Ultima Online module: what it serves, what it owns, and what an operator needs |
|
|
| [uo/API.md](modules/uo/API.md) · [uo/SCHEMA.md](modules/uo/SCHEMA.md) | module-uo's own route surface and the tables it owns |
|
|
| [kit-acceptance.md](modules/kit-acceptance.md) | The Integration Kit acceptance run — building a module by following the kit alone, and what it found |
|
|
| [rust-dryrun.md](modules/rust-dryrun.md) | A written, deliberately unimplemented `module-rust` — the test that the module contract generalises past the game it was extracted from |
|
|
| [rust/](modules/rust/README.md) | **Reference for the upcoming `module-rust`** — a mirror of the uMod/Oxide ecosystem, scraped from upstream: [HOOKS.md](modules/rust/HOOKS.md) (477 Rust hooks), [OXIDE_API.md](modules/rust/OXIDE_API.md) (the plugin framework), [DEFINITIONS.md](modules/rust/DEFINITIONS.md) (678 items, 2,590 skins), [OPERATING.md](modules/rust/OPERATING.md) (the operator's side), and [agent/](modules/rust/agent/README.md) — the same facts as TSV/JSONL at ~46% of the tokens |
|
|
|
|
### `link/`
|
|
| Doc | What it covers |
|
|
|---|---|
|
|
| [INTEGRATION.md](link/INTEGRATION.md) | How the website integrates with the uo-link sidecar |
|
|
| [PROTOCOL_2.md](link/PROTOCOL_2.md) | Protocol 2.0 / 2.1 design |
|
|
| [v3.md](link/v3.md) | Protocol 3.0 design — shard content/standings streams + the visibility framework |
|
|
| [v4.md](link/v4.md) | Protocol 4.0 — guild membership on the wire (`guild.roster`, `guild.leave`) |
|
|
| [v5.md](link/v5.md) | Protocol 5 — three enrichments in one bump: `house.decay`'s decay schedule, `vendor.listing`'s fee state, and `account.login.result`. Shipped 2026-09-01 as bundle 2026.09.01 (sidecar v2.1.0 + overlay v1.1.0) |
|
|
| [v6.md](link/v6.md) | Protocol 6 — idempotent commands, config leases with a shard-side deadline, and the run-scoped participation ledger |
|
|
| [v7.md](link/v7.md) | Protocol 7 — the world verbs an event OWNS: creatures, bosses, oracle NPCs, temporary gates, decoration, and the persisted ownership registry behind them. **The released protocol**, bundle 2026.09.10 (sidecar v2.2.0 + overlay v1.2.0) |
|
|
| [v8.md](link/v8.md) | Protocol 8 — the Asset Bridge: the shard reads its own UO client and serves creature art, item and land pictures, the cliloc table and its own spawn files, so nothing is converted on a desktop and the website needs no shared filesystem. On `edge` |
|
|
| [ADMIN_CONTROLS.md](link/ADMIN_CONTROLS.md) | Staff write-plane (kick/ban/broadcast, page queue) |
|
|
| [SHARD_PREREQS.md](link/SHARD_PREREQS.md) | Shard-side prerequisites for the bridge |
|
|
| [PLAN.md](link/PLAN.md) | uo-link build plan |
|
|
| [RESEARCH.md](link/RESEARCH.md) | Research notes |
|
|
| [link-README.md](link/link-README.md) | Snapshot of the link repo's README |
|
|
| [PROJECT_TREE.md](link/PROJECT_TREE.md) | Auto-generated snapshot of the repo's tracked file layout |
|
|
|
|
### `rust-link/`
|
|
|
|
The same pair of contracts as `link/`, for Rust rather than Ultima Online: an Oxide plugin that
|
|
dials out to a sidecar, and a sidecar the website reads. The two bridges are **independent** — they
|
|
share a shape and nothing else, so neither document is a fallback for the other.
|
|
|
|
| Doc | What it covers |
|
|
|---|---|
|
|
| [PROTOCOL.md](rust-link/PROTOCOL.md) | **Canonical** — the game link and the website API, the four declaration sites of the wire version, and what each protocol version defines: 1 the transport, 2 the read path |
|
|
| [INTEGRATION.md](rust-link/INTEGRATION.md) | Standing the bridge up by hand, and which of the three components is wrong when it does not work |
|
|
| [PLAYER_WALK.md](rust-link/PLAYER_WALK.md) | The half of the read path a console cannot reach: ten minutes on a rig with a player, step by step, with what each hook should produce |
|
|
|
|
### `android/`
|
|
| Doc | What it covers |
|
|
|---|---|
|
|
| [PLAN.md](android/PLAN.md) | Android client build plan / milestones |
|
|
| [COVERAGE_PLAN.md](android/COVERAGE_PLAN.md) | Test-coverage rollout plan |
|
|
| [APP_LINKS.md](android/APP_LINKS.md) | Android App Links / deep-link setup |
|
|
| [theme-plan.md](android/theme-plan.md) | Theming plan |
|
|
| [THEMING_AND_NAV.md](android/THEMING_AND_NAV.md) | The app's half of admin-configurable theming and navigation — build contract |
|
|
| [TRUSTED_DEVICES_APP_HANDOFF.md](android/TRUSTED_DEVICES_APP_HANDOFF.md) | Trusted-devices app handoff notes |
|
|
| [PROJECT_TREE.md](android/PROJECT_TREE.md) | Auto-generated snapshot of the repo's tracked file layout |
|
|
|
|
### `installer/`
|
|
| Doc | What it covers |
|
|
|---|---|
|
|
| [INSTALL.md](installer/INSTALL.md) | **Start here to set up a shard** — the installer deploys the plugin overlay and the uo-link sidecar, registers the service, and connects it to the website. Appendix A is the same thing by hand, still supported |
|
|
| [PLAN.md](installer/PLAN.md) | Installer design of record — phases, locked decisions, the bundle/compat-matrix model |
|
|
| [PROJECT_TREE.md](installer/PROJECT_TREE.md) | Auto-generated snapshot of the repo's tracked file layout |
|
|
|
|
### `ci/`
|
|
| Doc | What it covers |
|
|
|---|---|
|
|
| [SONARQUBE.md](ci/SONARQUBE.md) | The SonarQube setup: project keys, how analysis runs, and how to read a report |
|
|
|
|
## Provenance
|
|
|
|
- `website/*` was extracted from `RunicGateway/website` via `git filter-repo`.
|
|
- `link/*` was extracted from `RunicGateway/link` via `git filter-repo`.
|
|
|
|
Commit history and authorship for each doc are preserved. The two source repos
|
|
retain a short pointer to this repo in their own READMEs; the authoritative copy
|
|
of each document now lives here.
|
|
|
|
---
|
|
|
|
## License
|
|
|
|
Runic Gateway's documentation is free: licensed under the **GNU General Public
|
|
License v3.0 or later** — see [LICENSE.md](LICENSE.md).
|
|
|
|
Copyright (C) 2026 Runic Gateway
|
|
|
|
This documentation is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY. You may redistribute and/or modify it under the terms of
|
|
the GNU General Public License as published by the Free Software Foundation,
|
|
either version 3 of the License, or (at your option) any later version.
|
|
|
|
Contributions are welcome — please read [CONTRIBUTING.md](CONTRIBUTING.md) (note
|
|
the **AI-usage disclosure** requirement) and our
|
|
[Code of Conduct](CODE_OF_CONDUCT.md).
|