First commit for the UO module — the game-specific half of the Runic Gateway
website, extracted from core so that core can become game-agnostic. Phase 0 of
the module system plan (docs/website/MODULE_SYSTEM.md §2.7) calls for this repo
to get its initial commit before any module work starts.
Governance scaffolding only; no module code. The design of record settles the
API surface in Phase 1 and Phase 3 is what fills the repo, so writing module
code now would be writing against a contract that does not exist yet.
- README.md what module-uo is, the phase table, the packaging layout,
and why an operator never builds anything
- CONTRIBUTING.md planning status, the dev loop (a module is not runnable on
its own), the zero-internal-imports and one-path-segment
rules, schema fragments instead of migrations
- SECURITY.md private reporting, plus the module-specific notes: the
module boundary is not a security boundary, access control
lives in core, and the uo-link token stays write-only
- CODE_OF_CONDUCT.md, CONTRIBUTORS.md, LICENSE.md (GPL-3.0-or-later),
PR + issue templates — the same set every repo in the org carries
- .gitignore Node-shaped; client/dist/ is ignored deliberately, since it
is a release artifact built by CI, not a source artifact
CI lands next, in a PR, mirroring how the installer repo was bootstrapped: an
empty repo cannot take a pull request, but everything after it can.
Co-Authored-By: Claude <noreply@anthropic.com>
133 lines
6.2 KiB
Markdown
133 lines
6.2 KiB
Markdown
# 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 <noreply@anthropic.com>` or `Assisted-By: <tool>`.
|
|
- 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.
|