242 lines
17 KiB
Markdown
242 lines
17 KiB
Markdown
# Administration panel requirements
|
||
|
||
Added to the goal on 22 September 2026 at the user's request. This is required
|
||
product scope. The first access and directory prototype is available at `/admin`;
|
||
the remaining room operations are unfinished. Reuse the existing room, session,
|
||
recovery and persistence systems where suitable.
|
||
|
||
## Required capabilities
|
||
|
||
| Area | Required behavior | Stage |
|
||
| --- | --- | --- |
|
||
| Administrator access | Personal access keys, server-enforced owner/operator/viewer roles, persistent eight-hour sessions and individual/all-session sign-out. [Owner-only account management](ADMIN_ACCOUNTS.md) adds a paginated directory, browser-created one-time keys, role changes, disabling and fresh-key rotation/re-enable with session revocation, live authority and exact retries. A room host is not a site administrator. Failed-attempt history and further operational permissions remain. | Prototyped, partial |
|
||
| Room directory | Search room codes/public player names, filter status/rules/availability, sort and paginate; show host, roster, modules, game change time, pause/join flags and bounded decision ownership. Detailed setup/shared-window ownership remains. | Prototyped |
|
||
| Create and configure | [Create a lobby](ADMIN_ROOM_CREATION.md) with an explicitly owned new host seat, Basic/Advanced preview and initial AI configuration; invite humans and use ordinary lobby controls/voluntary host-seat handover. [Neutral lobby configuration](ADMIN_LOBBY_CONFIGURATION.md) adds rules/modules, AI seats and host assignment to an existing human without private access. Reserved human seats remain. | Prototyped, partial |
|
||
| Lifecycle and removal | [Pause/resume and joining locks](ADMIN_ROOM_CONTROLS.md), [administrative close/reopen](ADMIN_ROOM_CLOSURE.md) and [recoverable removal/restoration](ADMIN_ROOM_REMOVAL.md) have controls, durable audit, exact retries and player/AI enforcement. [Archive/unarchive](ADMIN_ROOM_ARCHIVE.md) has separate directory filters and exact retries. Permanent deletion and bulk actions remain missing. | Prototyped, partial |
|
||
| Participant support | [Participant AI](ADMIN_PARTICIPANT_AI.md) enables an existing difficulty on an eligible human seat in a paused game, retaining access/takeback and private custody. [Discussion controls](ADMIN_DISCUSSION.md) mute/unmute new sends while retaining history and gameplay. Participant removal, access revocation, assisted recovery and further replacement remain. Existing lobby controls can reassign the host. | Prototyped, partial |
|
||
| Saved-game operations | [Owner-only room backups](ADMIN_BACKUPS.md) capture/list/download a size-limited, version-fenced room snapshot without changing play or access; import validation, safe checkpoint restore and interrupted-work diagnosis/resume remain missing. | Prototyped, partial |
|
||
| Operations and audit | [Action history](ADMIN_ACTION_HISTORY.md) searches existing durable operations with safe settings and role-limited reasons. The owner-only [operations page](../app/admin/operations/page.tsx) samples build revision, room/seat flags, JSON syntax failures and backup/export counts without exposing game contents. An explicit owner action runs read-only SQLite quick/foreign-key checks and returns only pass/fail, never corrupt row details. Failed-attempt records, disk capacity, stalled-decision diagnosis and maintenance controls remain. | Prototyped, partial |
|
||
|
||
Track each area through Missing, Prototyped, Integrated, Verified and Polished.
|
||
As implementation begins, link its controls, server actions, persistence,
|
||
documentation and evidence. A working directory alone is not a full admin panel.
|
||
|
||
## Access and directory prototype
|
||
|
||
Use **Administration** in the home-page footer or visit `/admin`. Every directory
|
||
request checks a separate administrator session; seat cookies and forwarded
|
||
identity headers cannot grant access. The standalone NAS runtime has no trusted
|
||
Sites identity dispatcher, so this panel uses separately provisioned personal
|
||
keys. Each key contains a random 256-bit secret. Only its SHA-256 hash is stored;
|
||
sign-in issues a separate random, hashed session with an eight-hour absolute
|
||
expiry. HTTPS uses Secure, HttpOnly, SameSite=Strict cookies scoped to the admin
|
||
API. Mutations require the exact configured origin and bounded JSON requests.
|
||
|
||
All three roles may read the current directory and sign out their own sessions.
|
||
Owners/operators may pause/resume rooms and lock/unlock new joins through
|
||
[Room controls](ADMIN_ROOM_CONTROLS.md). The role is checked from the live
|
||
account, never accepted from a client.
|
||
Owners/operators can also [create a configured lobby](ADMIN_ROOM_CREATION.md),
|
||
with explicit new-host ownership and saved exact retries.
|
||
[Configure lobby](ADMIN_LOBBY_CONFIGURATION.md) changes supported rules, AI seats
|
||
and the host without granting private seat access.
|
||
[Remove or restore](ADMIN_ROOM_REMOVAL.md) blocks ordinary room access while
|
||
preserving the game, seats and access revocations. Use the Directory filter to
|
||
find removed rooms; restoration retains prior pause and joining settings.
|
||
[Close or reopen](ADMIN_ROOM_CLOSURE.md) ends further play without awarding a
|
||
winner and preserves readable private tables and discussion. Reopening retains
|
||
the saved game, pause/join settings and current credentials.
|
||
[Archive or unarchive](ADMIN_ROOM_ARCHIVE.md) organizes closed rooms with separate
|
||
directory filters and exact retries. Unarchiving leaves play closed; restoring
|
||
a removed archive preserves both flags.
|
||
Disabling an account invalidates its sessions; later re-enabling it cannot restore
|
||
them. The database refuses to disable, demote or delete the final enabled owner.
|
||
No default key, public account creation or host-to-administrator promotion exists.
|
||
|
||
[Manage accounts](ADMIN_ACCOUNTS.md) lets a current owner provision a
|
||
personal key, change another administrator’s role, disable access or
|
||
rotate another account’s key. Rotation also re-enables a disabled account
|
||
with a fresh key while invalidating every earlier key and session. The
|
||
exact request and generated key remain tab-scoped through uncertain
|
||
responses; the server never returns a key. The owner reviews the target,
|
||
current state, reason and revocation impact before submitting. No game
|
||
or seat is modified.
|
||
|
||
[Participant AI](ADMIN_PARTICIPANT_AI.md) lets owners/operators support an absent
|
||
human in a paused, started game. The player retains access and takeback controls;
|
||
the administrator receives no private seat. Resume remains a separate action.
|
||
[Discussion controls](ADMIN_DISCUSSION.md) restrict new messages from a human seat,
|
||
including after recovery/handover, without exposing private history.
|
||
|
||
[Private room backups](ADMIN_BACKUPS.md) let an owner capture the current saved
|
||
state and related room-owned records without pausing or editing the room. The
|
||
metadata directory omits private contents; downloaded JSON contains secret
|
||
game state and hashed seat/recovery credentials. Import/restore are not available.
|
||
|
||
The owner-only [operations page](../app/admin/operations/page.tsx) provides
|
||
manual read-only samples of room lifecycle counts, active seat credentials,
|
||
invalid JSON saves, latest room write, backup payload usage and export receipts.
|
||
The database query repeats current owner authority. **Run integrity check** is
|
||
a separate, explicit read-only D1 quick check and foreign-key check. It repeats
|
||
owner authority inside the query batch and returns only pass/fail and sample
|
||
time, never a table name, row ID, private save or SQLite diagnostic text.
|
||
The check can take time; a failed check calls for a protected snapshot and
|
||
private diagnosis, not automatic repair. It does not prove disk capacity,
|
||
backup recoverability, valid game rules or the absence of stalled decisions.
|
||
|
||
The directory uses an explicit field allowlist, independent of any player view.
|
||
It never returns hands, Traitors, predictions, plans, private messages, recovery
|
||
records or raw saved state. Searches inspect only codes and public player names.
|
||
Each page is limited to 25 rooms and repeats authorization in its read transaction
|
||
so concurrent revocation cannot expose a later directory snapshot. Malformed
|
||
saves are marked unreadable without leaking their contents or breaking searches.
|
||
Last game change refers to the room's saved-state timestamp, not private messages.
|
||
Shared windows and setup currently use broad pending labels; these labels do not
|
||
assert that a human is stalled or identify hidden-card-dependent eligibility.
|
||
|
||
Implementation: [panel](../app/admin/page.tsx), [access](../db/admin-access.ts),
|
||
[directory](../db/admin-directory.ts), [HTTP boundary](../lib/admin-http.ts),
|
||
[additive migration](../drizzle/0008_admin_access.sql), and
|
||
[operator CLI](../tools/admin-access.mjs). The migration's explicit SQLite triggers
|
||
enforce final-owner protection and account revocation/provisioning audit; retain
|
||
them when generating future schema changes. [Action history](ADMIN_ACTION_HISTORY.md)
|
||
unifies the existing successful-operation records; broader audit coverage remains.
|
||
|
||
### Initial owner and access recovery
|
||
|
||
The NAS container provisions an **Initial owner** automatically after migrations
|
||
only if `admin_accounts` has no rows. Its newly generated personal access key is
|
||
printed once in that container's startup log (`docker logs <container-name>`).
|
||
Retrieve it privately, save it in a password manager and sign in at `/admin`;
|
||
it is not a chosen password or an environment variable. Anyone able to read
|
||
that log can use the key. Restrict log access and retention; do not paste the
|
||
log into support reports. Restarts,
|
||
container replacements and existing accounts (even disabled ones) never generate
|
||
or print another key. Save the key before replacing the first container, since
|
||
its original log may disappear. Losing it requires manual owner recovery below.
|
||
|
||
The automatic bootstrap applies only to the bundled NAS container startup, not
|
||
`npm run dev` or an external D1 deployment.
|
||
|
||
For manual provisioning or access recovery from the development checkout,
|
||
apply additive migrations, then create a personal owner key in a new private
|
||
directory outside the checkout:
|
||
|
||
```sh
|
||
npm run db:local
|
||
node tools/admin-access.mjs --name 'Owner' --role owner --out /private/dune-owner
|
||
npx wrangler d1 execute DB --local --config tools/wrangler.local.json --persist-to .wrangler/state --file /private/dune-owner/provision.sql
|
||
```
|
||
|
||
The parent directory must already exist. Output files are mode 0600 in a new
|
||
mode-0700 directory. `access-key.txt` contains the sign-in key; `provision.sql`
|
||
contains only its hash. Keep the key in a private password manager or protected
|
||
file, outside Git, logs and chat. The command never connects to a database or
|
||
prints the key. Apply the SQL only to the intended instance. Do not upload a
|
||
development key to production; provision separate accounts there.
|
||
|
||
For the container, run the bundled CLI inside the existing `dune` container
|
||
(using its actual container ID/name), with output such as `/data/admin-owner`.
|
||
Apply the generated SQL using `node node_modules/wrangler/bin/wrangler.js d1
|
||
execute DB --local --config tools/wrangler.local.json --persist-to /data --file
|
||
/data/admin-owner/provision.sql`. A protected volume snapshot should precede
|
||
operational changes. Retrieve the key through an authorized private channel and
|
||
retain the account ID shown by the CLI. No application restart is needed.
|
||
|
||
To revoke an account, generate a new private output directory with
|
||
`node tools/admin-access.mjs --revoke ACCOUNT_UUID --out /private/dune-revoke`
|
||
and apply its `revoke.sql` using the same instance-specific command. To replace
|
||
a lost/compromised owner key, provision a replacement owner first, verify access,
|
||
then revoke the previous account. Existing games and seats are unchanged.
|
||
**Sign out everywhere** revokes browser sessions but keeps the personal key valid.
|
||
|
||
### Focused verification
|
||
|
||
```sh
|
||
npm test -- admin-access admin-directory admin-http
|
||
npm run test:integration -- admin-boundary
|
||
node tools/verify-admin.mjs --url http://localhost:3000 --key-file /private/dune-qa/access-key.txt --qa-account ACCOUNT_UUID --out /private/dune-admin-report
|
||
```
|
||
|
||
The HTTP verifier requires a **dedicated QA administrator account** and explicitly
|
||
checks its ID before proceeding: it creates a named QA room and signs out all
|
||
sessions of that QA account. Never supply a human operator's normal key. It checks
|
||
authentication, cookie properties, ordinary-host denial, directory privacy,
|
||
session revocation and unchanged game/seat continuation. Operator/owner QA keys
|
||
also create dedicated rooms for joining locks, pause/takeback/resume,
|
||
administrator creation, invitations, voluntary host handover and neutral lobby
|
||
configuration with existing-human host assignment and a real game start. They
|
||
also close/reopen, archive/unarchive and remove/restore separate QA games, preserving their paused state, discussion,
|
||
saved seats and revoked credentials. Private reports retain
|
||
room IDs and safe outcomes, never keys/cookies. The container verifier provisions
|
||
its own disposable QA account and checks admin-session continuity across restart
|
||
and replacement, followed by the HTTP flow and HTTPS-proxy cookie behavior.
|
||
Participant checks use another new QA room for paused AI enable, private-seat
|
||
continuity, takeback and durable retries after resuming. Discussion checks use a
|
||
new QA room for mute/unmute, own-only status, incoming messages and saved retries.
|
||
|
||
Local browser checks cover sign-in, directory filters, refresh restoration and
|
||
mobile layout. Final source-bound checks and separately recorded deployed
|
||
acceptance accompany each checkpoint; a local pass is not production evidence.
|
||
|
||
## Behavior and safeguards
|
||
|
||
Every privileged endpoint must authenticate and authorize its caller. Support
|
||
least-privilege roles, secure initial provisioning, safe credential/session
|
||
management, and accessible desktop/mobile controls. Do not ship default shared
|
||
credentials or expose administrator capabilities through ordinary room cookies.
|
||
|
||
Default views must preserve hands, Traitors, predictions, sealed plans, private
|
||
discussion and recovery credentials. Any necessary private support access must
|
||
be separately authorized and audited; it must not reveal information to other
|
||
players or feed an administrator's playing seat or AI strategy. Redact secrets
|
||
and private card contents from routine logs and reports. Backup access needs
|
||
equivalent protection, since backups can contain private state.
|
||
|
||
Pausing must stop human mutations and automatic/AI continuation consistently
|
||
without losing pending decisions. Resuming restores the same turn and pacing.
|
||
Seat removal or reassignment must explain the effect on an active game and
|
||
preserve a legal continuation; do not simply delete a faction's physical pieces.
|
||
Existing consent/recovery boundaries remain applicable to seat access.
|
||
|
||
Use authoritative rules and the existing concurrency model. Reject stale or
|
||
duplicate destructive actions safely. Imports and restoration must validate
|
||
schema, custody, private-information boundaries and session ownership; capture
|
||
a recovery checkpoint before replacing current progress. Never restore old
|
||
credentials in a way that silently reauthorizes a revoked participant.
|
||
|
||
Room removal should be reversible by default. Permanent deletion and bulk
|
||
operations must identify the selected rooms and dependent records, explain
|
||
irreversibility, require deliberate confirmation and retain appropriate audit
|
||
evidence without keeping purged secrets. Protect unrelated games. The existing
|
||
saved-game preservation rules still govern development and maintenance; they
|
||
do not preclude intentional room deletion through the authorized product workflow.
|
||
|
||
Record who acted, when, the affected room/seat, operation, reason, outcome and
|
||
safe before/after metadata. Maintenance controls must warn about interruptions
|
||
to active games and preserve restoration. Do not recreate recurring restarts or
|
||
cleanup schedules. Do not add an arbitrary game-state editor that bypasses rules,
|
||
silently changes outcomes or makes unfinished modes appear complete.
|
||
|
||
## Development order and acceptance
|
||
|
||
Prototype permissions and the room directory first, then room creation and
|
||
reversible lifecycle operations, participant support, backup/restore and
|
||
operational tools. Include functional server actions and saved continuation in
|
||
each slice; continue independent game features in parallel where useful.
|
||
Administration is part of the non-AI completion gate in the
|
||
[AI development plan](AI_DEVELOPMENT_PLAN.md).
|
||
|
||
Acceptance requires working controls and documented setup/recovery procedures,
|
||
with authenticated HTTP and persistence tests for authorization, privacy,
|
||
concurrent actions, exact retries, related-record handling and safe restoration.
|
||
Verify pause/resume with both humans and AI, archive/delete/restore with saved
|
||
rooms, and denied admin actions by ordinary players. Exercise desktop/mobile
|
||
flows and server restart recovery. Use dedicated test rooms and preserve all
|
||
unrelated saved games; complete independent security/privacy/persistence review.
|
||
Verify the panel's relevant deployed flows at
|
||
**https://dune.procrastination.games**, including denied access by ordinary
|
||
players, using the [production verification workflow](VERIFICATION_WORKFLOW.md#verify-the-deployed-application).
|
||
The full goal remains unfinished until this scope and the other completion
|
||
criteria are satisfied.
|