Files
Module-Rust/CONTRIBUTING.md
wtclaude 883438009d chore: repository scaffolding
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
2026-09-15 19:53:44 -05:00

7.1 KiB

Contributing to Runic Gateway — Module-Rust

Thanks for your interest in contributing! This repo is Module-Rust: the Rust 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.

Where the design lives

The design of record is 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 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 (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.

Development setup

Prerequisites: Node 20+, and a checkout of 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.

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 sidecar and a Rust server with the bridge plugin 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.

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 Commitstype(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). 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.