docs(website): record the uo-link client config-decrypt contract and the dashboard mixed tier #61
@@ -100,7 +100,13 @@ flowchart TB
|
|||||||
talks to it. Every backend→sidecar call carries `Authorization: Bearer <token>` and an
|
talks to it. Every backend→sidecar call carries `Authorization: Bearer <token>` and an
|
||||||
`X-UOLink-Version` header (a protocol mismatch fails fast with `409`). The REST client
|
`X-UOLink-Version` header (a protocol mismatch fails fast with `409`). The REST client
|
||||||
(`uoLinkClient.js`) never throws — every call returns `{ ok, data, status }` — so the site degrades
|
(`uoLinkClient.js`) never throws — every call returns `{ ok, data, status }` — so the site degrades
|
||||||
gracefully when the shard is down.
|
gracefully when the shard is down. That guarantee covers **reading the config too**: resolving the
|
||||||
|
admin-managed config decrypts the stored auth token, which throws when the ciphertext can't be
|
||||||
|
authenticated (`SECRET_ENC_KEY` rotated, or a DB dump restored under a different key). This is
|
||||||
|
handled inside the client and reported as `{ ok: false, status: 0, error: 'uo-link config
|
||||||
|
unreadable' }` plus a distinct `ERROR`-level log, so a wrong key degrades the shard surface to
|
||||||
|
"unavailable" instead of 500ing it — and `GET /admin/uo-link/config` keeps working, which is the
|
||||||
|
screen an admin needs to re-enter the token and recover.
|
||||||
- **Two ways in from the sidecar.** Live game events arrive over an outbound **WebSocket** and are
|
- **Two ways in from the sidecar.** Live game events arrive over an outbound **WebSocket** and are
|
||||||
routed by the `shardIngest.js` dispatcher (state-changing kinds update `shard_*` tables, notable
|
routed by the `shardIngest.js` dispatcher (state-changing kinds update `shard_*` tables, notable
|
||||||
kinds append to `shard_events`, high-frequency kinds only update state). Point-in-time reads and
|
kinds append to `shard_events`, high-frequency kinds only update state). Point-in-time reads and
|
||||||
|
|||||||
@@ -561,7 +561,13 @@ Public content GETs pass through the **siteMode** gate (§5).
|
|||||||
the whole gate. The ops/config capabilities — `uo-link`, `email`, `discord-bot`, `settings`, and
|
the whole gate. The ops/config capabilities — `uo-link`, `email`, `discord-bot`, `settings`, and
|
||||||
`PUT /site-mode` — are `adminOnly`; `shard` is the one mixed prefix, where self-service account
|
`PUT /site-mode` — are `adminOnly`; `shard` is the one mixed prefix, where self-service account
|
||||||
linking carries no extra gate and the in-game staff operations carry `modAccess`. There is no residual
|
linking carries no extra gate and the in-game staff operations carry `modAccess`. There is no residual
|
||||||
file: every admin route is declared in a capability router. The URLs below are unaffected by which
|
file: every admin route is declared in a capability router.
|
||||||
|
|
||||||
|
`GET /dashboard` and `PUT /site-mode` are the one place where a **single screen spans two tiers**: the
|
||||||
|
dashboard is staff-wide, but the site-mode toggle on it is `adminOnly`. The client must therefore gate
|
||||||
|
that control on its own (`Dashboard.jsx` renders it only for `role === 'admin'`) rather than relying on
|
||||||
|
the route gate that admitted them to the page — the same rule the sidebar follows, so a non-admin is
|
||||||
|
never shown a control that would 403. The URLs below are unaffected by which
|
||||||
file a route sits in — that is the property the route manifest freezes.
|
file a route sits in — that is the property the route manifest freezes.
|
||||||
| Method | Path | Purpose |
|
| Method | Path | Purpose |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|
|||||||
Reference in New Issue
Block a user