The org's standard furniture for a new repo: licence, code of conduct, security policy, contributing guide, issue and pull-request templates, and the ignore rules. No module yet — that arrives as the first pull request, so this branch exists to open one against. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
154 lines
7.1 KiB
Markdown
154 lines
7.1 KiB
Markdown
# Contributing to Runic Gateway — Module-Rust
|
|
|
|
Thanks for your interest in contributing! This repo is **Module-Rust**: the
|
|
[Rust](https://rust.facepunch.com/) module for the Runic Gateway website.
|
|
Everything the site knows about a Rust server — the server list, identity,
|
|
site-owned permissions, Teams, the live map — lives here rather than in core, so
|
|
that core stays game-agnostic.
|
|
|
|
It is **one repo, one bundle**: the server half (routers, controllers, models, a
|
|
schema fragment) and the client half (SPA screens, nav registrations) version
|
|
together and release as a single artifact.
|
|
|
|
By participating you agree to abide by our
|
|
[Code of Conduct](CODE_OF_CONDUCT.md).
|
|
|
|
## Where the design lives
|
|
|
|
The design of record is
|
|
[`modules/rust/PLAN.md`](https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/modules/rust/PLAN.md)
|
|
in the docs repo — its decisions of record and its phase schedule, which this
|
|
repo is built against one phase at a time. Read it before opening a PR here.
|
|
|
|
If you want to change *what a module can do* — the API surface, the loader, the
|
|
delivery model — propose it against
|
|
[`website/MODULE_API.md`](https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/website/MODULE_API.md)
|
|
first. If you want to change *what this module 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-Rust/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 copy of this tree in core's
|
|
modules directory is the development loop.
|
|
|
|
```bash
|
|
npm ci --prefix server && npm test --prefix server
|
|
npm run check:imports --prefix server
|
|
npm run check:swagger --prefix server
|
|
npm ci --prefix client && npm run build --prefix client
|
|
npm run check:externals --prefix client && npm test --prefix client
|
|
```
|
|
|
|
**Build the client before running its tests.** Two of them read the built chunk
|
|
and skip when there is none, so a run in the other order passes while asking
|
|
nothing about the artifact that ships.
|
|
|
|
To see it running, you also want a
|
|
[rust-link](https://gitea.whitlocktech.com/RunicGateway/Rust-Link) sidecar and a
|
|
Rust server with
|
|
[the bridge plugin](https://gitea.whitlocktech.com/RunicGateway/Rust-Plugins)
|
|
loaded. The module degrades honestly without either — that is the point — so the
|
|
pages render either way, and nothing about a missing game server is an error.
|
|
|
|
The client half builds with Vite **in library mode**. Do not add React to the
|
|
bundle: there is exactly one React instance in the page and core owns it, exposed
|
|
on a `window.__rg` global that the shims in `client/src/shim/` resolve to.
|
|
|
|
### Four rules that are enforced by a check, not by review
|
|
|
|
- **Zero imports escape the module root.** `npm run check:imports` fails a build
|
|
on any relative path that leaves this repo. A module reaches core only through
|
|
the `ctx` it is handed and the `register*` functions it calls; if something you
|
|
need is not on that surface, the surface gets extended rather than reached
|
|
around.
|
|
- **Nothing shared is bundled.** `npm run check:externals` asks the BUILT chunk
|
|
whether a bare import survived.
|
|
- **One file may reach the network.** `test/noGameConnection.test.js` bans every
|
|
networking primitive from the shipped server half except in
|
|
`server/sidecarClient.js`. The website process never opens a connection to a
|
|
game server; it opens one to a sidecar. On a red run here the answer is almost
|
|
always to move the call into `sidecarClient.js`, not to add a second name to
|
|
the allowlist.
|
|
- **The OpenAPI fragment is current.** `npm run check:swagger` fails when
|
|
`swagger-fragment.json` is stale. Regenerate with `npm run swagger --prefix server`
|
|
and commit it.
|
|
|
|
### 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 on every boot,
|
|
exactly like core's own schema. **Changing a table is an ALTER below the CREATE,
|
|
never an edit to the CREATE**, which would reach fresh installs and nothing else.
|
|
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. `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.
|
|
|
|
### The protocol is a contract
|
|
|
|
`PROTOCOL_VERSION` in `server/sidecarClient.js` must agree with the sidecar's own
|
|
constant and with `overlay.toml` in the plugin repo. A bump lands in every repo
|
|
in one change, together with the spec in
|
|
[`rust-link/PROTOCOL.md`](https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/rust-link/PROTOCOL.md).
|
|
|
|
## 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.
|
|
|
|
### 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/rust/` rather than in this repo. A behaviour change here — a new
|
|
route, a changed table, a new nav entry, a different capability — is not complete
|
|
until the matching document reflects it.
|
|
|
|
## 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.
|