Files
runicgateway.com/CONTRIBUTING.md
wtclaude f2e59a2426
All checks were successful
PR checks / checks (pull_request) Successful in 9m46s
feat(delivery): phase 12 — the container, and the defect only a proxy could find
PLAN.md §13 phase 12, the last one. Four decisions of record, D54–D57, taking the
count to fifty-seven; recorded in §6, "How phase 12 delivered it".

A two-stage Dockerfile, a pull-only docker-compose.yml carrying both bind mounts,
.env.example, the workflow that publishes and deploys, CONTRIBUTING.md, the
community-health files this was the only repository of the ten to lack, and
DEPLOY.md.

D54 — a merge deploys, amending D6. build-image.yml pushes
runicgateway-site:latest and :sha-<7>, then rolls the container over on the
`rgcom` runner out of /opt/runicgateway.com, and waits for the container's own
healthcheck rather than for `up -d` to return.

D55 — the site runs on its own host behind a generic reverse proxy, so DEPLOY.md
states the four requirements rather than one worked example, and the container
binds 127.0.0.1 so the safe configuration is the default.

D56 — @astrojs/node derives the request protocol from req.socket.encrypted and
never reads x-forwarded-proto, so behind a TLS-terminating proxy the browser sends
Origin: https://… while the container computes http://… and Astro's CSRF check
compares them for equality. Every beta signup, from every visitor, was answered
403. serve.mjs now normalises both forwarded headers, unconditionally — the image
should deploy and work. Two assertions in test/headers.test.mjs hold both halves.

D57 — DEPLOY.md rather than a README section; SECURITY.md and CODE_OF_CONDUCT.md
are pointers to the org's copies rather than copies, because a copy would hard-code
the contact address D13 confines to brand.json.

Verified: npm run verify green (eleven checks, 36 unit tests, 7 served tests,
astro check 0 errors). The image was built and run with both mounts — a mounted
brand reached 51 files and all 50 search pages, /brand/* fell back per file, a
proxy-shaped signup reached the store, and the export CLI wrote both Play files to
the host mount. docker compose config caught a YAML trap in the healthcheck: a
block sequence reads the `: ` in `r.ok ? 0 : 1` as a mapping.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-25 16:54:38 -05:00

6.7 KiB

Contributing to runicgateway.com

Thanks for your interest. This repository is the public marketing and documentation site for Runic Gateway — the platform that puts a private game server's live state on a public website without ever exposing the game to the internet.

It is a site, not a component. Nothing else in the organisation depends on it, and it depends on everything: almost every sentence here describes something that lives in another repository.

By participating you agree to abide by our Code of Conduct.

Read the plan first

PLAN.md is the design of record. It is not a sketch — it carries the verified platform state, the org lead's fifty-odd decisions, the information architecture, the accuracy machinery and the build phases. A change that contradicts a decision recorded there needs the decision changed first, in the same pull request, with the reasoning written down.

Two things it records are worth knowing before you write a line:

  • §1 — the site never re-specifies a contract. docs/ is normative for the protocol, the module API, the backend design and the installer. This site teaches, links out, and quotes versions from data rather than prose. A page that restates a contract is a page that will be wrong later, and nothing will notice.
  • §12 — the checks are the mechanism, and their failure is the feature. When the platform moves, this repository goes red so that somebody updates the site. Do not route around a check; if one is wrong, fix the check and say why in the pull request.

Ways to contribute

  • Report a bug or request a feature through the issue tracker — templates are provided.
  • Improve a page, a check or the build by opening a pull request.
  • Never report a security vulnerability in a public issue. See SECURITY.md.

If you spot a claim on the site that is wrong about the platform — a version, a capability, a command that no longer exists — that is the most valuable report this repository can receive.

Development setup

Prerequisites: Node 22 LTS or newer. Nothing else — no database, no game server, no container runtime for ordinary work.

npm install
npm run dev          # http://localhost:4321
npm run build        # → dist/  (prerendered pages + the Node server entry)
npm start            # serve the built site, exactly as the container does

Two directories are bind mounts at runtime and not in the repository: brand/ overrides the stock branding per file, and data/ holds the beta signup store. Both are optional locally; an absent brand/ produces exactly the stock site, and data/ is created on first write.

The checks

There are eleven, plus two test suites. npm run verify runs all of them in dependency order, and that is what CI does on every pull request.

npm run verify

Three of them read other repositories over the Gitea API and need a token with access to the organisation, not just this repository:

GITEA_TOKEN=<token> npm run check:facts       # every version agrees with its authority
GITEA_TOKEN=<token> npm run check:quickstart  # the install page still matches website's own files
GITEA_TOKEN=<token> npm run check:reference   # every name the Reference lists still exists

Without a token they fail rather than skip, deliberately: a check that silently passes when it could not do its job is worse than no check. CI maps the org-level REGISTRY_TOKEN secret into GITEA_TOKEN for those three steps.

The README's "The checks, and why they are not optional" section explains what each one guards. Read it before adding a page — several of them constrain how a page may be written, particularly check:tokens (no colour literal outside src/styles/tokens.css) and check:links (no commit permalinks into org repositories).

Writing for this site

  • Understated honesty (D8). The site reads as finished. Where something is not built, the absence is stated as data in src/data/notBuilt.mjs and rendered — never implied by silence and never dressed up as a roadmap.
  • No version in prose. Every externally-sourced fact lives in src/data/platform.json and is re-read from its authority by check:facts. If you find yourself typing a version number into a sentence, put it in the data file instead.
  • No email address in src/ or scripts/ (D13). The published contact is a brand.json field so that changing it stays a file copy and a restart. check:facts enforces this.
  • British spelling, in common with the rest of the organisation's prose.

Branch and pull-request workflow

  1. Branch from main with a descriptive name (feature/…, fix/…, docs/…, chore/…).
  2. Keep changes focused; small pull requests are easier to review.
  3. Run npm run verify before opening the pull request.
  4. Push and open a pull request against main. Fill out the template, including the AI-assisted contributions disclosure.
  5. A maintainer will review; address feedback with follow-up commits.

Commit messages

Conventional Commitstype(scope): summary, in common with every repository in the organisation. For example fix(docs): correct the installer flag on the quickstart.

What merging does

Merging to main builds a container image, publishes it to the Gitea registry and deploys it (.gitea/workflows/build-image.yml). There is no separate release step and no manual promotion, so a merge is a publication. DEPLOY.md describes the whole path, including how to roll back to a previous build.

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.

Licence

Runic Gateway is licensed under the GNU General Public License v3.0 or later (see LICENSE). 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.