docs(website): record the demo-mode decisions DM1-DM10
The org lead's answers of 2026-10-23: demoLocks in module.json, settings open, the rig open but reset each cycle through Pterodactyl, content open with uploads locked hard, the Oxide rig as the demo's, a stand-in Steam link, every 2 hours, files in website/, latest versions, and every lock at the server route level. Adds the rig reset (§7.1-7.2): the site's first sync imports what is on the rig (D198, D244), so the rig is restored from a baseline archive before the site relinks, and that first import is the reset. Adds the hard upload rule (any multipart body refused). Three follow-ups: F1 console-command steps, F2 "latest" across the bundle, F3 reading of DM2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -37,7 +37,7 @@ sidecar as a service, and hands you the values the website needs.
|
|||||||
| [SHARD_VISIBILITY.md](website/SHARD_VISIBILITY.md) | Who sees which shard data — the admin-configurable audience framework |
|
| [SHARD_VISIBILITY.md](website/SHARD_VISIBILITY.md) | Who sees which shard data — the admin-configurable audience framework |
|
||||||
| [TRUSTED_DEVICES_MFA.md](website/TRUSTED_DEVICES_MFA.md) | TOTP two-factor, trusted devices and recovery codes |
|
| [TRUSTED_DEVICES_MFA.md](website/TRUSTED_DEVICES_MFA.md) | TOTP two-factor, trusted devices and recovery codes |
|
||||||
| [STEAM_SIGNIN.md](website/STEAM_SIGNIN.md) | **Plan, built 2026-10-19** — Sign in with Steam as a built-in provider beside Google and Discord (OpenID 2.0), and a Steam id for modules |
|
| [STEAM_SIGNIN.md](website/STEAM_SIGNIN.md) | **Plan, built 2026-10-19** — Sign in with Steam as a built-in provider beside Google and Discord (OpenID 2.0), and a Steam id for modules |
|
||||||
| [DEMO_MODE.md](website/DEMO_MODE.md) | **Design, awaiting answers** — the public `demo.runicgateway.com`: one flag that locks destructive actions, static logins, and a wipe every couple of hours (website#222) |
|
| [DEMO_MODE.md](website/DEMO_MODE.md) | **Design, decided 2026-10-23 (three follow-ups open)** — the public `demo.runicgateway.com`: one flag that locks destructive actions, static logins, and a wipe every couple of hours (website#222) |
|
||||||
| [MODERATION_APPEALS.md](website/MODERATION_APPEALS.md) | Moderation actions, content reports and the appeals flow |
|
| [MODERATION_APPEALS.md](website/MODERATION_APPEALS.md) | Moderation actions, content reports and the appeals flow |
|
||||||
| [SPAWN_ATLAS.md](website/SPAWN_ATLAS.md) | The bestiary / spawn atlas: what the shard contains, parsed from the shard's own ServUO files — served over the bridge since Protocol 8, so no shared filesystem |
|
| [SPAWN_ATLAS.md](website/SPAWN_ATLAS.md) | The bestiary / spawn atlas: what the shard contains, parsed from the shard's own ServUO files — served over the bridge since Protocol 8, so no shared filesystem |
|
||||||
| [CLILOCS.md](website/CLILOCS.md) | UO's id → name table, so items have names. The shard decompresses and serves it over the bridge; the desktop conversion it replaced is gone |
|
| [CLILOCS.md](website/CLILOCS.md) | UO's id → name table, so items have names. The shard decompresses and serves it over the bridge; the desktop conversion it replaced is gone |
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# Demo mode — `demo.runicgateway.com`
|
# Demo mode — `demo.runicgateway.com`
|
||||||
|
|
||||||
**Status:** design, waiting on the org lead's answers to §9. Nothing is built.
|
**Status:** design. The org lead answered §9 Q1-Q9 on 2026-10-23 (recorded as decisions DM1-DM10
|
||||||
|
in §9); three follow-up questions in §9.2 remain. Nothing is built.
|
||||||
**Issue:** `RunicGateway/website#222`. **Why now:** Google Play (`../android/PLAN.md` item 9,
|
**Issue:** `RunicGateway/website#222`. **Why now:** Google Play (`../android/PLAN.md` item 9,
|
||||||
M8) needs a public HTTPS site with working sign-ins for its reviewers and for the 12 testers who
|
M8) needs a public HTTPS site with working sign-ins for its reviewers and for the 12 testers who
|
||||||
must be opted in for 14 days before the app can apply for production.
|
must be opted in for 14 days before the app can apply for production.
|
||||||
@@ -51,20 +52,43 @@ app maps the code to a new error kind with the same wording; today it would show
|
|||||||
Reads are never locked. Every page can be opened and every form filled in; only the save is
|
Reads are never locked. Every page can be opened and every form filled in; only the save is
|
||||||
refused. That keeps the demo useful as a tour of the admin panel.
|
refused. That keeps the demo useful as a tour of the admin panel.
|
||||||
|
|
||||||
Module routes need their own entries, because they are mounted by core but belong to the module.
|
**The server is the lock, never the UI (DM10).** Every lock is enforced at the route, so a request
|
||||||
§9 Q1 asks how the module declares them.
|
sent with `curl`, an old app build, or a hand-edited page is refused exactly like a click. The UI may
|
||||||
|
explain a lock (the toast, the banner) but never hides or disables a control as the means of
|
||||||
|
locking it, and no client-side check is relied on.
|
||||||
|
|
||||||
### 3.2 What is locked
|
Module routes are mounted by core but belong to the module, so the module declares its own locked
|
||||||
|
routes in `module.json` (DM1, §3.2).
|
||||||
|
|
||||||
Paths are relative to `/api/v1`. Tier A breaks the site for the next visitor and is always locked. Tier B reaches the real game
|
### 3.2 The module's declaration
|
||||||
server, and Tier C is content anyone can see; both are §9 questions.
|
|
||||||
|
`module.json` gains an optional `demoLocks` list, read by core when `DEMO_MODE` is on:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"demoLocks": [
|
||||||
|
{ "method": "PUT", "path": "/admin/rust/servers/:id" },
|
||||||
|
{ "method": "DELETE", "path": "/admin/rust/servers/:id" },
|
||||||
|
{ "method": "POST", "path": "/admin/rust/config/:serverId/file" }
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Paths use the same `:param` syntax as the module's routers and must sit under the module's own
|
||||||
|
mounts, which the loader checks the same way it checks `mounts`. A module without the field is
|
||||||
|
unaffected. It is a new manifest field, so `MODULE_API_VERSION` gets a **minor** bump,
|
||||||
|
`MODULE_API.md` documents it, and the Integration Kit's module chapter gains a paragraph (its
|
||||||
|
`ci/core-ref.json` pin then moves, as for any API bump).
|
||||||
|
|
||||||
|
### 3.3 What is locked
|
||||||
|
|
||||||
|
Paths are relative to `/api/v1`. **Tier A** would break the site for the next visitor and is always
|
||||||
|
locked. **Uploads** are locked hard. **Tier B** (the rig) and **Tier C** (content) stay **open**: the
|
||||||
|
wipe puts them back (§7).
|
||||||
|
|
||||||
**Tier A — always locked (core)**
|
**Tier A — always locked (core)**
|
||||||
|
|
||||||
| Area | Routes | What a visitor could otherwise do |
|
| Area | Routes | What a visitor could otherwise do |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| Site mode | `PUT /admin/site-mode` | Put the site into maintenance; every non-admin is locked out |
|
| Site mode | `PUT /admin/site-mode` | Put the site into maintenance; every non-admin is locked out |
|
||||||
| Settings & branding | `PUT /admin/settings`, `POST /admin/settings/brand-asset/:slot`, `DELETE /admin/settings/:key` | Rename or rebrand the site, swap the logo |
|
|
||||||
| Modules | every write under `/admin/modules` (install, sources, restart, enable, disable, purge, delete) | Disable or purge the Rust module; restart the server |
|
| Modules | every write under `/admin/modules` (install, sources, restart, enable, disable, purge, delete) | Disable or purge the Rust module; restart the server |
|
||||||
| SSO providers | writes under `/admin/auth/providers` | Add a sign-in provider pointing anywhere |
|
| SSO providers | writes under `/admin/auth/providers` | Add a sign-in provider pointing anywhere |
|
||||||
| Email | `PUT /admin/email/config`, `POST /admin/email/test`, `POST /admin/email/disconnect` | Connect a mail account; send mail from the site |
|
| Email | `PUT /admin/email/config`, `POST /admin/email/test`, `POST /admin/email/disconnect` | Connect a mail account; send mail from the site |
|
||||||
@@ -82,13 +106,33 @@ server, and Tier C is content anyone can see; both are §9 questions.
|
|||||||
| The link to the rig | `PUT`/`DELETE /admin/rust/servers/:id` | Repoint or delete the sidecar link; the site goes dark |
|
| The link to the rig | `PUT`/`DELETE /admin/rust/servers/:id` | Repoint or delete the sidecar link; the site goes dark |
|
||||||
| Plugin config files | `POST /admin/rust/config/:serverId/file` | Writes a plugin's config file on the rig's disk |
|
| Plugin config files | `POST /admin/rust/config/:serverId/file` | Writes a plugin's config file on the rig's disk |
|
||||||
|
|
||||||
**Tier B — reaches the rig (§9 Q3).** Permission writes (policy, grant, revoke, groups, members,
|
**Settings stay open (DM2).** Theme, navigation and the other `PUT /admin/settings` values can be
|
||||||
drift actions, sync), RunicNPC writes (factions, profiles, placements, push, respawn), economics and
|
changed and come back at the wipe. Brand images are uploads, so they fall under the upload lock.
|
||||||
permission grants to a linked player, console-command steps and every other world action an event
|
|
||||||
can run, and map fetch/render.
|
|
||||||
|
|
||||||
**Tier C — content anyone can see (§9 Q4).** Posts, wiki, pages, events, teams and team forums,
|
**Uploads — locked hard (DM4)**
|
||||||
moderation actions, invites, uploads, and the public contact form.
|
|
||||||
|
| Route | What it stores |
|
||||||
|
| --- | --- |
|
||||||
|
| `POST /admin/uploads` | The media library |
|
||||||
|
| `POST /admin/posts/upload` | Images in posts |
|
||||||
|
| `POST /admin/settings/brand-asset/:slot` | Logo, hero, favicon |
|
||||||
|
| `POST /player/teams/:slug/forum/uploads` | Images in team forum posts |
|
||||||
|
|
||||||
|
"Hard" means a second rule beside the list: with `DEMO_MODE` on, core refuses **any** request whose
|
||||||
|
body is `multipart/form-data`, before a router sees it. An upload route added later is locked
|
||||||
|
without anyone remembering to list it, and a module cannot open one.
|
||||||
|
|
||||||
|
**Tier B — the rig: open, reset by the wipe (DM3).** Permission writes (policy, grant, revoke,
|
||||||
|
groups, members, drift actions, sync), RunicNPC writes (factions, profiles, placements, push,
|
||||||
|
respawn), economics and permission grants to a linked player, the world actions events run, and map
|
||||||
|
fetch/render all work. The rig starts every cycle from a **demo default set** of permissions, NPCs
|
||||||
|
and events, and the wipe restores it (§7.1). Console-command steps are the exception that needs a
|
||||||
|
rule of their own (§9.2 F1).
|
||||||
|
|
||||||
|
**Tier C — content: open (DM4).** Posts, wiki, pages, events, teams and team forums, moderation
|
||||||
|
actions and invites work. The contact form is locked (`POST /public/contact`), because it sends mail
|
||||||
|
to a person. The demo is served with `X-Robots-Tag: noindex` and a matching `robots.txt`, so nothing
|
||||||
|
a visitor writes reaches a search engine.
|
||||||
|
|
||||||
## 4. Static logins
|
## 4. Static logins
|
||||||
|
|
||||||
@@ -96,7 +140,7 @@ moderation actions, invites, uploads, and the public contact form.
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `demo-admin` | admin | The admin panel, read in full; writes per §3 |
|
| `demo-admin` | admin | The admin panel, read in full; writes per §3 |
|
||||||
| `demo-moderator` | moderator | Moderation queue, appeals |
|
| `demo-moderator` | moderator | Moderation queue, appeals |
|
||||||
| `demo-player` | player | Self-service; a linked Steam account so the Rust player screens have data (§9 Q6) |
|
| `demo-player` | player | Self-service; linked to a stand-in Steam ID that has played on the rig, so the Rust player screens have data (DM6) |
|
||||||
| `play-review` | admin | Google's reviewer. Same powers as `demo-admin`, but a separate account, so a reviewer is never signed out because someone else revoked a session on the shared one |
|
| `play-review` | admin | Google's reviewer. Same powers as `demo-admin`, but a separate account, so a reviewer is never signed out because someone else revoked a session on the shared one |
|
||||||
|
|
||||||
Usernames and passwords are published on the demo's sign-in page and on runicgateway.com `/beta`.
|
Usernames and passwords are published on the demo's sign-in page and on runicgateway.com `/beta`.
|
||||||
@@ -111,7 +155,7 @@ address with (§5), and the static logins cover every role.
|
|||||||
| Email | Not configured. Registration closed, password reset locked, digest and engagement mail never send |
|
| Email | Not configured. Registration closed, password reset locked, digest and engagement mail never send |
|
||||||
| Push (ntfy) | Not deployed. The app's notification settings still save; nothing is delivered |
|
| Push (ntfy) | Not deployed. The app's notification settings still save; nothing is delivered |
|
||||||
| Discord bot | Not deployed |
|
| Discord bot | Not deployed |
|
||||||
| The rig | Per §9 Q3 |
|
| The rig | Open, and restored to the demo default set at every wipe (§7.1) |
|
||||||
|
|
||||||
## 6. The banner
|
## 6. The banner
|
||||||
|
|
||||||
@@ -122,115 +166,158 @@ needs to know the schedule.
|
|||||||
|
|
||||||
## 7. The wipe
|
## 7. The wipe
|
||||||
|
|
||||||
A scheduled workflow on the `demo-site` runner (§9 Q7 for the cadence) runs:
|
A scheduled workflow on the `demo-site` runner runs **every 2 hours on the hour, UTC** (DM7). It
|
||||||
|
resets the rig first and the site second, and the order matters.
|
||||||
|
|
||||||
1. `docker compose down -v` — drops the database **and** the uploads volume, so nothing a visitor
|
### 7.1 Why the rig goes first
|
||||||
made survives.
|
|
||||||
2. `docker compose pull && docker compose up -d` — the app boots, creates the schema, and installs
|
The site's first sync with a server **imports what it finds there**. A new site's first permission
|
||||||
the Rust module from `MODULES=rust@<version>=<manifest>` in `.env`.
|
read adopts every grant and group on the rig (D198), and RunicNPC profiles are adopted before the
|
||||||
|
first push (D244). So wiping only the site would bring back every change a visitor made on the rig,
|
||||||
|
now owned by the fresh site. The rig has to be back at the demo default set **before** the new site
|
||||||
|
first talks to it. Then that first import *is* the reset: the site adopts the default set, and the
|
||||||
|
default set never has to be described twice.
|
||||||
|
|
||||||
|
### 7.2 The rig: restore a baseline through Pterodactyl (DM3)
|
||||||
|
|
||||||
|
The demo rig is the existing `rust-oxide` Pterodactyl server (DM5). On it sits one archive,
|
||||||
|
`demo-baseline.tar.gz`, holding the demo default set:
|
||||||
|
|
||||||
|
- `oxide/data/` — permissions and groups, RunicNPC profiles and placements, Economics balances, the
|
||||||
|
bridge plugin's own data;
|
||||||
|
- `oxide/config/` — plugin configs, so even a config that changed some other way comes back;
|
||||||
|
- `server/<identity>/` — the world save and `cfg/`, so anything an event built or a console command
|
||||||
|
wrote with `server.writecfg` comes back too.
|
||||||
|
|
||||||
|
`oxide/plugins/` is **not** in the baseline. Plugin versions are the deployment's business (§9.2
|
||||||
|
F2), not the wipe's.
|
||||||
|
|
||||||
|
The workflow uses the Pterodactyl **client** API (files and power):
|
||||||
|
|
||||||
|
1. `POST …/power {"signal":"kill"}` — no save, since the world is about to be replaced.
|
||||||
|
2. `POST …/files/delete` the three directories.
|
||||||
|
3. `POST …/files/decompress` `demo-baseline.tar.gz` at the server root.
|
||||||
|
4. `POST …/power {"signal":"start"}`. Rust takes a few minutes to boot; the site does not wait.
|
||||||
|
|
||||||
|
**Capturing the baseline** is a second, hand-run workflow (`workflow_dispatch` only): someone sets up
|
||||||
|
the default set through the demo site (the permission groups, a handful of NPCs, events), then runs
|
||||||
|
it. It saves the world (`server.save` over the console), stops the server, `POST …/files/compress`es
|
||||||
|
the three directories into `demo-baseline.tar.gz`, and starts the server again. Re-run it whenever
|
||||||
|
the default set should change.
|
||||||
|
|
||||||
|
**The key.** Pterodactyl client keys belong to a user and reach every server that user can see. The
|
||||||
|
demo gets its own Pterodactyl **subuser**, with access to `rust-oxide` only and the file and power
|
||||||
|
permissions only, and that subuser's client key is the `demo-site` workflow's secret
|
||||||
|
(`PTERODACTYL_CLIENT_KEY`). The panel URL and server identifier are plain variables.
|
||||||
|
|
||||||
|
### 7.3 The site
|
||||||
|
|
||||||
|
1. `docker compose down -v` — drops the database **and** the uploads volume.
|
||||||
|
2. `docker compose pull && docker compose up -d` — the app boots on the latest `main` image, creates
|
||||||
|
the schema, and installs the Rust module from `MODULES=rust@<version>=<manifest>` (DM9, §9.2 F2).
|
||||||
3. Wait for the app's healthcheck.
|
3. Wait for the app's healthcheck.
|
||||||
4. `docker compose exec app npm run seed:demo` — one core script that, from a fixture file in the
|
4. `docker compose exec app npm run seed:demo` — one core script that, from a fixture file in the
|
||||||
deploy directory:
|
deploy directory:
|
||||||
- creates the four accounts (§4);
|
- creates the four accounts (§4) and `demo-player`'s stand-in Steam link (DM6);
|
||||||
- creates the Rust server row with the rig's sidecar URL and token taken from `.env`, so the
|
- creates the Rust server row with the rig's sidecar URL and token taken from `.env`, so the
|
||||||
link survives every wipe without being stored in the fixture;
|
link survives every wipe without being stored in the fixture;
|
||||||
- writes the seeded content: a few news posts, wiki pages, an upcoming event and a team, enough
|
- writes the seeded site content: news posts, wiki pages, the demo events and a team;
|
||||||
for every screen to have something on it;
|
|
||||||
- stamps `resetsAt` for the banner.
|
- stamps `resetsAt` for the banner.
|
||||||
5. Smoke check: `GET /api/v1/public/status` answers, and the Rust server reports a live connection.
|
5. The module's sync connects when the rig finishes booting, and its first import adopts the
|
||||||
|
baseline's permissions and NPCs (§7.1).
|
||||||
|
6. Smoke check, after a bounded wait: `GET /api/v1/public/status` answers, and the Rust server
|
||||||
|
reports a live connection. A rig that has not come back fails the run, and the site still
|
||||||
|
serves with the server shown offline.
|
||||||
|
|
||||||
A wipe takes the site down for about a minute. Signed-in visitors, including app users, are signed
|
### 7.4 What a visitor sees
|
||||||
out: their sessions and refresh tokens were in the database.
|
|
||||||
|
|
||||||
The same workflow runs on a push that changes the deploy directory and on `workflow_dispatch`, so a
|
The site is down for about a minute; the rig for a few. Signed-in visitors, including app users,
|
||||||
redeploy is the same path as a wipe.
|
are signed out, because their sessions and refresh tokens were in the database.
|
||||||
|
|
||||||
|
The same workflow runs on `workflow_dispatch` and on a push to `main` that changes `deploy/demo/`,
|
||||||
|
so a redeploy is the same path as a wipe.
|
||||||
|
|
||||||
## 8. Where it lives
|
## 8. Where it lives
|
||||||
|
|
||||||
| Piece | Repo |
|
| Piece | Repo |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `DEMO_MODE` lock, banner field, `seed:demo` script | `website` (core) |
|
| `DEMO_MODE` lock, banner field, `seed:demo` script | `website` (core) |
|
||||||
| The Rust module's own lock entries | `Module-Rust` (§9 Q1) |
|
| The Rust module's `demoLocks`, and the console-command rule (§9.2 F1) | `Module-Rust` |
|
||||||
| `DEMO_LOCKED` error kind and the banner in the app | `Android-app` |
|
| `DEMO_LOCKED` error kind and the banner in the app | `Android-app` |
|
||||||
| `docker-compose.yml`, `.env.example`, seed fixture, wipe workflow | §9 Q8 |
|
| `deploy/demo/` (compose file, `.env.example`, seed fixture) and `.gitea/workflows/demo-wipe.yml` + `demo-baseline.yml` | `website` (DM8) |
|
||||||
| `.env` (JWT secret, encryption key, the rig's sidecar token) | On the `demo-site` host only, never in a repo |
|
| `.env` (JWT secret, encryption key, the rig's sidecar token) | On the `demo-site` host only, never in a repo |
|
||||||
|
| `PTERODACTYL_CLIENT_KEY` (the demo subuser's key) | A Gitea Actions secret on `website` |
|
||||||
|
| `demo-baseline.tar.gz` | On the rig, at the Pterodactyl server root |
|
||||||
|
|
||||||
## 9. Questions for the org lead
|
## 9. Decisions and open questions
|
||||||
|
|
||||||
**Q1 — How does the Rust module declare its locked routes?**
|
### 9.1 Decisions (org lead, 2026-10-23)
|
||||||
Example: the demo is up and `demo-admin` opens Rust → Servers → Edit and changes the sidecar URL.
|
|
||||||
Something has to know that route is locked.
|
|
||||||
- **(a) Recommended:** `module.json` gains an optional `demoLocks` list of method + path, read by
|
|
||||||
core's lock. A module with no list is unaffected. It is a new manifest field, so `MODULE_API`
|
|
||||||
gets a minor bump and the Integration Kit documents it.
|
|
||||||
- (b) Core hard-codes the Rust module's paths. No module change, but core then knows one module's
|
|
||||||
routes, which the module system was built to avoid.
|
|
||||||
|
|
||||||
**Q2 — Is the Tier A list (§3.2) complete, and is anything on it you want left open?**
|
| # | Question | Decision |
|
||||||
Example: should `demo-admin` be able to change the site's theme colours, which are under Settings?
|
| --- | --- | --- |
|
||||||
It is harmless and resets at the wipe, but it is also the first thing a visitor would deface.
|
| DM1 | How the module declares its locked routes | A `demoLocks` list in `module.json`; `MODULE_API` minor bump (§3.2) |
|
||||||
|
| DM2 | Is anything on Tier A to stay open? | Settings stay open (theme, navigation and the rest of `PUT /admin/settings`); the rest of Tier A stays locked (§3.3). See F3 |
|
||||||
|
| DM3 | What may a visitor do to the rig? | Permissions, NPCs and events start from a **demo default set**, can be changed through the site, and are put back each cycle by a CI script that restores the rig through Pterodactyl (§7.2) |
|
||||||
|
| DM4 | May visitors publish content? | Yes. **Uploads are locked hard** (§3.3); the contact form is locked; the site is `noindex` |
|
||||||
|
| DM5 | Which rig? | The existing Oxide rig becomes the demo's. A new Oxide server is spun up for testing when a walk needs one |
|
||||||
|
| DM6 | A Steam link for `demo-player`? | Yes, a stand-in Steam ID that has played on the rig |
|
||||||
|
| DM7 | Cadence | Every 2 hours |
|
||||||
|
| DM8 | Where the files live | `website/deploy/demo/` and `website/.gitea/workflows/` |
|
||||||
|
| DM9 | Version | Latest, at every wipe |
|
||||||
|
| DM10 | (the org lead, unprompted) | **Every lock is at the server route level, never the UI level** (§3.1) |
|
||||||
|
|
||||||
**Q3 — What may a visitor do to the rig?**
|
DNS and HTTPS for `demo.runicgateway.com` come from an external reverse proxy, which the org lead is
|
||||||
Example: `demo-admin` grants `demo-player` a kit permission, or starts an event whose step runs
|
setting up. The app sits behind it on plain HTTP; core already trusts one proxy hop for
|
||||||
`server.time 0` on the Oxide rig. The website wipe does not undo either; the rig keeps them.
|
`X-Forwarded-*` by default (`TRUST_PROXY`), and the deploy PR checks secure cookies and client IPs
|
||||||
- **(a) Recommended:** lock everything that writes to the rig (all of Tier B). Visitors see the
|
through that proxy.
|
||||||
live map, feed, players and every admin screen, but saves that would reach the rig are refused.
|
|
||||||
- (b) Allow a short list of harmless, self-healing actions — for example respawning a RunicNPC or
|
|
||||||
rendering the map — and lock the rest.
|
|
||||||
- (c) Allow everything and also reset the rig in the wipe. Much larger: a rig wipe means
|
|
||||||
permissions, NPC placements and plugin state, and a Rust server restart.
|
|
||||||
|
|
||||||
**Q4 — May visitors publish content?**
|
### 9.2 Follow-up questions
|
||||||
Example: someone signs in as `demo-admin` and posts a news item with an offensive image or a
|
|
||||||
phishing link. It is public on `demo.runicgateway.com` until the next wipe.
|
|
||||||
- **(a) Recommended:** allow posts, wiki, pages, events and teams, so the demo shows the real
|
|
||||||
editors. Lock **uploads** (no hosting of arbitrary files on our domain) and the **contact form**.
|
|
||||||
Serve the demo with `noindex`, so nothing a visitor writes reaches search engines.
|
|
||||||
- (b) Lock all publishing as well; the editors open but every save is refused.
|
|
||||||
- (c) Allow uploads too, with the wipe as the only cleanup.
|
|
||||||
|
|
||||||
**Q5 — Which rig does the demo use, and what happens to our walks on it?**
|
**F1 — Console-command steps on the demo.**
|
||||||
Example: next week a walk needs the Oxide rig while the demo is linked to it. The Rust module's
|
Example: `demo-admin` adds a console-command step with `quit` to an event and starts it. The Rust
|
||||||
site-owned permission sync means two sites linked to one rig fight over its permissions.
|
server stops and stays down until the next wipe, up to two hours, for every visitor. Other commands
|
||||||
- **(a) Recommended:** the Oxide rig becomes the demo's rig; walks use the Carbon rig.
|
do the same more quietly: `oxide.unload RunicGateway` cuts the site off from the rig, and
|
||||||
- (b) A third rig for the demo.
|
`kickall` and `ban` affect anyone playing. The command box is free text with no allowlist today
|
||||||
- (c) Share it, with permission sync off on the demo.
|
(Rust §16).
|
||||||
|
- **(a) Recommended:** on the demo, the module accepts a command step or command reward only if its
|
||||||
|
command is on a short allowlist, for example `say`, `env.time`, `weather.*` and `server.time`.
|
||||||
|
The module checks it when the event is saved **and** when the step runs, so it is a server-side
|
||||||
|
rule (DM10). Everything else in events stays open.
|
||||||
|
- (b) Refuse command steps and command rewards entirely on the demo.
|
||||||
|
- (c) Leave them open; the wipe is the cleanup, and the rig may be down until it.
|
||||||
|
|
||||||
**Q6 — Does `demo-player` have a linked Steam account?**
|
**F2 — "Latest" across the website, the module and the rig.**
|
||||||
Example: the player's Rust screens (stats, linked accounts, economics) are empty without one.
|
Example: Module-Rust ships a release that needs protocol 15 while the rig's bridge plugin still
|
||||||
- **(a) Recommended:** the seed links a stand-in Steam ID that has played on the rig, so the screens
|
speaks 14. At the next wipe, the demo pulls the new module, and the site refuses the rig until
|
||||||
have data. It is not anyone's real account.
|
someone updates the plugins.
|
||||||
- (b) Leave it unlinked, and show the empty states.
|
- **(a) Recommended:** the demo follows the latest **Rust bundle**, the protocol-checked set of
|
||||||
|
module, sidecar and plugins that CI already publishes. When the bundle changes, the wipe also
|
||||||
|
puts the bundle's plugins and sidecar onto the rig through the same Pterodactyl file API. The
|
||||||
|
website image always follows `main`.
|
||||||
|
- (b) Latest module at every wipe, and the rig's plugins updated by hand when a release needs it.
|
||||||
|
|
||||||
**Q7 — How often does it wipe?**
|
**F3 — DM2, read correctly?**
|
||||||
- **(a) Recommended:** every 2 hours, on the hour (00:00, 02:00, … UTC). Each wipe signs everyone
|
"Stay open" is read as: the settings (theme, colours, navigation, site texts) stay open, and every
|
||||||
out, which a reviewer in the middle of a review may notice.
|
other Tier A row stays locked, including site mode, modules, SSO, email, Discord, the demo
|
||||||
- (b) Every 6 hours, which leaves visitor changes up for longer.
|
accounts' credentials and 2FA, and the rig link. Is that right?
|
||||||
|
|
||||||
**Q8 — Where do the deployment files live?**
|
**For the org lead to set up (not questions):** a Pterodactyl subuser with access to `rust-oxide`
|
||||||
- **(a) Recommended:** `website/deploy/demo/` (compose file, `.env.example`, seed fixture) and
|
only (file and power permissions), and its client key as the `PTERODACTYL_CLIENT_KEY` secret on
|
||||||
`website/.gitea/workflows/demo-wipe.yml`. The seed script ships in the image, so its fixture sits
|
`website` (§7.2). Also confirm that the `demo-site` host can reach the Pterodactyl panel and the
|
||||||
next to it.
|
rig's sidecar over the network.
|
||||||
- (b) A new repo, `RunicGateway/demo-site`, which keeps the website repo free of one deployment's
|
|
||||||
files.
|
|
||||||
|
|
||||||
**Q9 — Which version does the demo run?**
|
## 10. Build order, once §9.2 is answered
|
||||||
- **(a) Recommended:** whatever `website` `main` and the latest Rust module release are at each
|
|
||||||
wipe, so the demo always shows the current release.
|
|
||||||
- (b) Pinned versions in `.env`, moved by hand.
|
|
||||||
|
|
||||||
**Not asked, assumed:** the host's reverse proxy and DNS for `demo.runicgateway.com`, and that the
|
1. **Core** (`website`): the `DEMO_MODE` lock (deny list, the `multipart/form-data` rule, the
|
||||||
`demo-site` host can reach the Oxide rig's sidecar over the network. These are for the org lead to
|
demo-account and other-session checks), `demoLocks` loading, the banner field, `seed:demo`,
|
||||||
confirm, not to decide.
|
`noindex`, the web banner and toast, `MODULE_API` minor bump, and the OpenAPI note that a route
|
||||||
|
may answer `DEMO_LOCKED`. Tests for every lock. One PR, plus `MODULE_API.md` and this doc.
|
||||||
## 10. Build order, once §9 is answered
|
2. **Module** (`Module-Rust`): `demoLocks` in `module.json`, and the F1 rule with its tests. One PR.
|
||||||
|
3. **Kit** (`Integration-kit`): the `demoLocks` paragraph and the `core-ref.json` re-pin. One PR.
|
||||||
1. **Core** (`website`): the `DEMO_MODE` lock and its tests, the banner field, `seed:demo`, and the
|
4. **App** (`Android-app`): the `DEMO_LOCKED` error kind and the banner on Home. One PR.
|
||||||
OpenAPI note that a route may answer `DEMO_LOCKED`. One PR.
|
5. **Deployment** (`website`): `deploy/demo/`, `demo-wipe.yml` and `demo-baseline.yml`; the first
|
||||||
2. **Module** (`Module-Rust`): its lock entries (Q1), plus a kit note if the manifest changes. One PR.
|
deploy on `demo-site`; setting up the default set and capturing the baseline; then a walk of
|
||||||
3. **Clients**: the web banner and toast (in the core PR), and the `DEMO_LOCKED` error kind and
|
every static login, every Tier A lock and the upload lock, in the browser and the app, plus
|
||||||
banner in `Android-app`. One PR.
|
one full wipe cycle that restores a changed permission, NPC and event. One PR.
|
||||||
4. **Deployment**: compose, fixture and wipe workflow (Q8); first deploy on `demo-site`; a walk of
|
6. **Play**: the sign-in details in the Play Console point at `play-review`;
|
||||||
every static login and every Tier A lock, in the browser and the app. One PR.
|
|
||||||
5. **Play**: the sign-in details in the Play Console point at `play-review`;
|
|
||||||
runicgateway.com `/beta` publishes the logins.
|
runicgateway.com `/beta` publishes the logins.
|
||||||
|
|||||||
Reference in New Issue
Block a user