Compare commits

..

1 Commits

Author SHA1 Message Date
runic-docs-bot
cbcce6f27a docs(tree): sync website/PROJECT_TREE.md from RunicGateway/website@69998ec [skip ci] 2026-10-26 10:52:31 +00:00
3 changed files with 8 additions and 37 deletions

View File

@@ -776,11 +776,6 @@ Mirrors the website's "degrade gracefully" invariant:
shard as **offline**, keep the rest of the app usable.
- **Site maintenance** (`/public/status` = maintenance) → show the maintenance page; public shard
widgets may still render (they're not maintenance-gated server-side).
- **The public demo's refusal** (`403` with `code: "DEMO_LOCKED"`, `../website/DEMO_MODE.md` §3.1) →
one app-wide snackbar with the server's sentence, spotted by an interceptor on the main client;
`HttpError` carries the body's `code`, `ErrorKind.DEMO_LOCKED` covers load screens (no Retry), and
a screen whose `403` line blames the role says the demo sentence instead (DM19). Home shows the
demo's strip from `/public/settings`' `demo` block (DM20).
- **Offline caching is not a v1 requirement** (decided). The app assumes connectivity and shows clean
loading/error/retry states; it does **not** ship a Room cache in v1. Cached read-only content can be
added later without reworking the repository layer (its typed results already isolate the UI from the

View File

@@ -1825,8 +1825,7 @@ it.
- the target of `/admin/users/:id…` is a demo account;
- the caller of `/auth/me/…` is signed in as one;
- the `PUT /admin/settings` body names a protected key (`site_mode*`, `module_source_hosts`,
`teams_voice_*`, `demo_*`, `hero_layout`). `hero_layout_draft` stays open, so the hero
editor previews but cannot publish (DM21).
`teams_voice_*`, `demo_*`).
A condition that cannot decide refuses.
- **Event steps** (`MODULE_API` 1.19.0, DM18). `POST /admin/events`, `PUT /admin/events/:id` and

View File

@@ -47,11 +47,8 @@ answers:
```
The web client shows the message as a toast wherever an action fails with that code. The Android
app does the same with a snackbar (DM19): an interceptor on its one HTTP client spots the code on
any `403` and reports the server's sentence, so a module's own wording (a refused console command)
reaches the screen as written. The screen still shows its own failure line, except where that line
blames the role ("You don't have permission for that action", on the admin screens), which says the
demo sentence instead. Load screens get a `DEMO_LOCKED` error kind, with no Retry button.
app maps the code to a new error kind with the same wording; today it would show the generic
"Something went wrong", which is misleading for a reviewer.
Reads are never locked, with one exception: the bridge's config (§3.5). 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.
@@ -106,7 +103,7 @@ wipe puts them back (§7).
| Other people's sessions | `DELETE /auth/me/sessions/:id` **on a demo account**, whichever session it names (DM17) | Sign every other visitor out of the shared account |
| Password reset | `POST /auth/password/forgot`, `POST /auth/password/reset/:token` | Reset a demo account's password |
| Registration | `POST /auth/register` (DM16) | Settings are open, so a visitor could switch `player_registration` on. The route is what keeps registration closed (§4) |
| Settings that reach a lock | `PUT /admin/settings` when the body names `site_mode*`, `module_source_hosts`, `teams_voice_*`, `demo_*` or `hero_layout` | That route writes arbitrary keys, so these would get around the site-mode, Modules and team-voice rows above, rewrite the banner and the published logins, or publish the homepage hero (DM21). The answer names the keys (`keys: [...]`) |
| Settings that reach a lock | `PUT /admin/settings` when the body names `site_mode*`, `module_source_hosts`, `teams_voice_*` or `demo_*` | That route writes arbitrary keys, so these would get around the site-mode, Modules and team-voice rows above, or rewrite the banner and the published logins. The answer names the keys (`keys: [...]`) |
**Why DM17 locks the whole route.** A mobile access token carries no id for its refresh-token row,
so the server cannot tell which row in `GET /auth/me/sessions` is the caller's own. Signing out is
@@ -123,12 +120,6 @@ so the server cannot tell which row in `GET /auth/me/sessions` is the caller's o
changed and come back at the wipe, except the keys in the "Settings that reach a lock" row above.
Brand images are uploads, so they fall under the upload lock.
**The hero editor previews but does not publish (DM21).** Admin → Hero autosaves to
`hero_layout_draft`, and its Preview opens the homepage with that draft, so both keep working. Its
Publish writes `hero_layout`, the hero every visitor sees, and is refused; the editor's status line
and the toast give the demo sentence. Its image uploads fall under the upload lock. The demo admins
share one login, so they share one draft, and the wipe resets it.
**Which accounts are demo accounts.** The four usernames in §4 are fixed in core
(`server/src/demo/mode.js`), not read from the seed fixture: the lock checks them on every request,
and a fixture that dropped one would unlock the account everybody shares. The lock decides by the
@@ -265,8 +256,7 @@ address with (§5), and the static logins cover every role.
The seed writes both into one settings row, `demo_state`, which `PUT /admin/settings` cannot touch
(§3.3). The web client shows a thin strip on every page: "Demo site — anything you change is wiped at
14:00 UTC. Sign-ins: demo-admin / demo-player … — passwords on the sign-in page". The app shows the same
strip on Home, but it does not list the passwords: its strip names the site's sign-in page instead
("passwords at demo.runicgateway.com/account/login"), DM20. Both read `resetsAt`, so neither needs to know the schedule. The time is said in UTC,
strip on Home. Both read `resetsAt`, so neither needs to know the schedule. The time is said in UTC,
not converted, so it matches the schedule published on `/beta`.
**The toast.** Every web request goes through one request primitive (`client/src/api/client.js`),
@@ -432,9 +422,6 @@ down.
| DM16 | (build) Settings are open, so `player_registration` can be switched on. Lock registration? | Yes: **`POST /auth/register`** is a Tier A lock. Invites stay open (§3.3) |
| DM17 | (build) The server cannot tell which mobile session is the caller's own. What does the other-sessions lock do? | **`DELETE /auth/me/sessions/:id` is locked outright on a demo account**; `POST /auth/mobile/logout` stays open (§3.3) |
| DM18 | (build, step 2) Saving an event is core's route, and core never asks a module about a step's params. How is a denied command refused at save? | **A new core hook:** an event action's optional `demoRefuses(params)`, asked at create, save and publish on the demo, refusing `403 DEMO_LOCKED` (§3.4). `MODULE_API` 1.19.0; Module-Rust then needs `^1.19.0` |
| DM19 | (build, step 4) Each app screen writes its own failure line, and the admin screens turn every `403` into "You don't have permission for that action". How does the app show a refusal? | **One app-wide snackbar** with the server's sentence, like the web's toast, and the screens whose `403` line blames the role say the demo sentence instead. `ErrorKind.DEMO_LOCKED` for load screens (§3.1) |
| DM20 | (build, step 4) Should the app's sign-in screen list the logins, as the web's does? | **No, the banner only.** The Home strip names the site's sign-in page for the passwords; Google's reviewer gets `play-review`'s from the Play Console (§6) |
| DM21 | (amendment, 2026-10-26) Settings are open, so the hero editor's Publish changes the homepage every visitor sees. What may a visitor do in the hero editor? | **Edit and preview, never publish.** `hero_layout` joins the protected settings keys; the draft and Preview stay open; uploads were already locked. Server lock only: Publish stays clickable and answers the demo sentence (§3.3) |
DNS and HTTPS for `demo.runicgateway.com` come from an external reverse proxy, which the org lead is
setting up. The app sits behind it on plain HTTP; core already trusts one proxy hop for
@@ -473,24 +460,14 @@ through that proxy.
that cannot be read never unlocks the file. A config that does not parse is withheld whole on the
demo, because its secrets cannot be found to redact.
3. **Kit** (`Integration-kit`): a paragraph on `demoLocks` and `ctx.demoMode`, and the
`core-ref.json` re-pin. One PR. **Built 2026-10-26** as `Integration-kit#17`, pinned to the
sha `website#224` merged as (1.19.0). Chapter 2 gains a section on a public demo site, which
also covers `onDemoSeed` (DM15), and chapter 5 covers `demoRefuses` (DM18). Both hooks were
decided after this list was written. Module-Rust's own pin moved to the same sha in
`Module-Rust#63`.
4. **App** (`Android-app`): the `DEMO_LOCKED` error kind and the banner on Home. One PR. **Built
2026-10-26** as `Android-app#61`, into `edge`, with the snackbar (DM19) and the banner only (DM20).
The refusal is read in `core/result/DemoLocked.kt` and spotted by `core/net/DemoLockInterceptor`;
the strip is `ui/demo/DemoBanner`. Checked on an emulator against `website` `main` with
`DEMO_MODE=true` and `seed:demo`: the strip, a shared login's username change refused, and the
admin site-mode switch refused with the demo sentence in place of the permission line.
`core-ref.json` re-pin. One PR.
4. **App** (`Android-app`): the `DEMO_LOCKED` error kind and the banner on Home. One PR.
5. **Deployment** (`website`): `deploy/demo/`, `demo-wipe.yml` (with §7.5's bundle step) and
`demo-baseline.yml`; the first deploy on `demo-site`; setting up the default set and capturing
the baseline. Then a walk of every static login, every Tier A lock and the upload lock, in the
browser and the app, plus one full wipe cycle that restores a changed permission, NPC and
event; a denied console command refused at save and at run; and a plugin config changed and
reloaded through the editor, with the bridge's config refused for reading and another plugin's
secret field redacted; and the hero editor's draft previewed while its Publish is refused
(DM21). One PR.
secret field redacted. One PR.
6. **Play**: the sign-in details in the Play Console point at `play-review`;
runicgateway.com `/beta` publishes the logins.