# module-uo — the Ultima Online module for Runic Gateway The Runic Gateway website is becoming **game-agnostic**: core keeps accounts, sessions, the wiki, posts, branding, theming and the admin panel, and everything that knows what a *shard* is moves out into an installable module. This repo is that module — the first one, and the reference for every module that follows. ``` RunicGateway/website (core — game-agnostic) │ loads modules at boot, synchronously, from the filesystem ▼ ┌───────────────────────────────────────────┐ │ module-uo (>>> HERE <<<) │ │ shard status · spawn atlas · marketplace │ │ governors · cliloc · town crier · uo-link│ └───────────────────────────────────────────┘ │ server half: routers, models, schema fragment │ client half: prebuilt ESM chunk, SPA routes + nav ▼ the shard bridge (RunicGateway/link → RunicGateway/servuo-plugins) ``` The module's **id** is `uo` — that is what appears in `module.json`, in the `installed_modules` table, in the `modules//` path on disk and in the URL segment (`/uo/*`, `/admin/uo/*`, `/player/uo/*`). `Module-uo` is the repository; `module-uo` is the module and its release artifact. ## Status: planning — no module code exists yet This repo currently holds governance scaffolding only. The design of record is [`website/MODULE_SYSTEM.md`](https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/website/MODULE_SYSTEM.md) in the docs repo — **read it before opening a PR here.** It defines the module API surface, the packaging, the state machine, the install/uninstall/purge model, and the phases. | Phase | Where it happens | State | |---|---|---| | 0 — CI trigger fix, cut `website` `edge`, bootstrap this repo | `website`, here | 🟡 in progress | | 1 — module API contract (`docs/website/MODULE_API.md`) + the atlas spike | `docs`, `website` | ⬜ blocking | | 2 — core scaffolding: loader, `installed_modules`, registries, client registry | `website` | ⬜ | | 3 — extract the UO half of the site into this repo | `website`, here | ⬜ | | 4 — delivery: the admin Modules screen + the Docker path | `website` | ⬜ | Nothing lands here until Phase 1 has settled the contract this module is written against. Phase 3 is what fills the repo. ## What it will contain One repo, one bundle: the server half and the client half live side by side and version together, so a route and the screen that calls it can never be mismatched. ``` module.json id, version, coreApi range, mounts, extensions server/ routers, controllers, models, utils server/db/schema.sql idempotent fragment, replayed by core's ensureSchema() server/db/purge.sql destructive; only ever run by an explicit purge client/src/ route components, nav registrations, feature provider client/dist/ PREBUILT ESM chunk, built by CI — never by an operator ``` Release artifact: `module-uo-.tar.gz`, plus a manifest carrying its `sha256`. ## How it reaches an operator **An operator never builds anything.** Installing a module is the WordPress-plugin experience: an admin-panel action, or a directory mounted into the Docker container — never a build step, because production runs a prebuilt, pull-only image. That constraint is why the client half ships as a prebuilt ESM chunk that resolves React from a `window.__rg` global rather than an import map (an import map must be inline, and the site's CSP is `script-src 'self'`). The [installer](https://gitea.whitlocktech.com/RunicGateway/installer) is **not** the delivery path. It deploys the *shard* side — the plugin overlay and the uo-link sidecar — and never contacts the website. Module delivery is website-side only. ## Compatibility `module.json` declares a `coreApi` semver range, checked at boot against core's `MODULE_API_VERSION`. A mismatch fails **loudly** — the module is marked `startup_failed` and the site comes up without it, rather than mis-loading. This is a separate number from `PROTOCOL_VERSION`, which versions the shard wire protocol and says nothing about a website module. A module that fails to load must never take the site down. ## Related repos | Repo | What | |------|------| | **this** — `RunicGateway/Module-uo` | The UO module: the game-specific half of the website. | | [RunicGateway/website](https://gitea.whitlocktech.com/RunicGateway/website) | Core — the site, admin panel and API that loads this module. | | [RunicGateway/link](https://gitea.whitlocktech.com/RunicGateway/link) | The **uo-link sidecar** — the network-facing half of the game bridge this module talks to. | | [RunicGateway/servuo-plugins](https://gitea.whitlocktech.com/RunicGateway/servuo-plugins) | The **C# ServUO plugin** that feeds the sidecar. | | [RunicGateway/installer](https://gitea.whitlocktech.com/RunicGateway/installer) | Deploys the shard side. Not the module delivery path. | | [RunicGateway/docs](https://gitea.whitlocktech.com/RunicGateway/docs) | All project documentation, including the module system design and this module's docs under `modules/uo/`. | ## Contributing See [CONTRIBUTING.md](CONTRIBUTING.md). Contributions are welcome, AI assistance must be disclosed, and security problems go to [SECURITY.md](SECURITY.md) rather than a public issue. ## License **GNU General Public License v3.0 or later** — see [LICENSE.md](LICENSE.md).