# Contributing to Runic Gateway — module-uo Thanks for your interest in contributing! This repo is **module-uo**: the Ultima Online module for the Runic Gateway website. Everything the site knows about a *shard* — shard status, the spawn atlas, the marketplace, governors, clilocs, the town crier and the uo-link integration — lives here rather than in core, so that core stays game-agnostic and a second game can be a second module. It is **one repo, one bundle**: the server half (routers, controllers, models, a schema fragment) and the client half (SPA screens, nav registrations, a feature provider) version together and release as a single artifact. By participating you agree to abide by our [Code of Conduct](CODE_OF_CONDUCT.md). ## Status: planning **No module code exists yet.** 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 layout, the state machine, the install/uninstall/purge model, and the phases. **Phase 1 has to settle the contract (`docs/website/MODULE_API.md`) before module code can be written against it**, and Phase 3 is what fills this repo by extracting the UO half of `website/`. If you want to change *what a module can do* — the API surface, the loader, the delivery model — propose it against the plan in the docs repo first. If you want to change *what module-uo does with that API*, a PR here is the right place. ## Ways to contribute - **Report a bug** or **request a feature** through the [issue tracker](https://gitea.whitlocktech.com/RunicGateway/Module-uo/issues) (issue templates are provided). - **Improve the code or docs** by opening a pull request (see below). - **Never** report a security vulnerability in a public issue — see [SECURITY.md](SECURITY.md). ## Development setup **Prerequisites:** Node 20+, and a checkout of [`RunicGateway/website`](https://gitea.whitlocktech.com/RunicGateway/website) to run the module against — a module is not runnable on its own. Core loads modules synchronously from the filesystem at boot, so a working tree of this repo placed in core's modules directory is the development loop. Once the code exists, both halves are plain npm packages: ```bash npm ci --prefix server && npm test --prefix server npm ci --prefix client && npm run build --prefix client ``` The client half builds with Vite **in library mode**, declaring `react`, `react-dom` and `react-router-dom` as externals. Do not add React to the module's bundle: there is exactly one React instance in the page and core owns it, exposed on a `window.__rg` global that the module's externals resolve to. ### Two rules that are enforced in CI, not by review - **Zero internal-file imports into core.** A module reaches core only through the documented API surface — the `ctx` it is handed and the `register*` functions it calls. If something you need is not on that surface, the surface gets extended (a docs PR and a core PR) rather than reached around. Any `require`/`import` that resolves outside this repo is a build failure. - **The module owns one path segment.** Server routes keep the API paths core already publishes; SPA pages live under `/uo/*`, `/admin/uo/*` and `/player/uo/*`. A route that escapes the module's segment is a bug. ### Schema fragments, not migrations There is no migration runner anywhere in this project, and modules do not get one. `server/db/schema.sql` is an **idempotent** fragment — `CREATE TABLE IF NOT EXISTS`, `ALTER TABLE … ADD COLUMN IF NOT EXISTS` — replayed by core's `ensureSchema()` on every boot, exactly like core's own schema. Anything destructive belongs in `server/db/purge.sql`, which only ever runs on an explicit operator purge. ### The operator never builds anything Installing a module is an admin-panel action or a mounted directory, never a build step: production runs a prebuilt, pull-only image. `client/dist/` is produced by this repo's CI and published in the release artifact. A change that only works when someone builds on the server is not shippable. ## Branch & PR workflow 1. Branch from `main` with a descriptive name (`feature/…`, `fix/…`, `docs/…`, `chore/…`). 2. Keep changes focused; small PRs are easier to review. 3. Push and open a pull request against `main`. Fill out the PR template, including the **AI-assisted contributions** disclosure. 4. A maintainer will review; address feedback with follow-up commits. `Module-uo` develops on its own `main` from its first commit — it has no `edge` branch and no cutover, unlike `website`, whose module work accumulates on `edge` and reaches `main` once. ### Commit messages We use [Conventional Commits](https://www.conventionalcommits.org/) — `type(scope): summary`. ## Keep the docs in sync `RunicGateway/docs` is canonical, and this module's documentation lives there under `modules/uo/` rather than in this repo. A behavior change here — a new route, a changed table, a new nav entry, a different capability — is not complete until the matching document reflects it. Changes to the module *system* itself belong in `website/MODULE_SYSTEM.md` and `website/MODULE_API.md`. ## AI-assisted contributions (disclosure required) This project is developed openly with AI assistance, and we ask the same transparency of everyone. **If you used an AI tool** (Claude, Copilot, ChatGPT, Cursor, etc.) to help produce a contribution, you must disclose it: - Tick the AI-usage box in the pull-request template and name the tool(s). - Mark AI-authored commits with a trailer, e.g. `Co-Authored-By: Claude ` or `Assisted-By: `. - You remain responsible for every line you submit: review it, understand it, and make sure it is correct and that you have the right to contribute it. Disclosed AI assistance is welcome. Undisclosed AI-generated contributions are not, and may be closed. ## License Runic Gateway is licensed under the **GNU General Public License v3.0 or later** (see [LICENSE.md](LICENSE.md)). By submitting a contribution you agree that it is licensed under the same terms (inbound = outbound) and that you have the right to contribute it.