Overview
Live state of this server.
Lobbies
Every live engagement, with its occupants.
Players
Live connections. Identity is a self-declared display name — there are no accounts yet, so this is presence, not a user list.
Campaigns
The loaded campaign, as the engine sees it.
Campaign builder
Not built. Campaigns are authored as packs/<id>/campaign.json
and validated at boot — a malformed campaign crashes startup rather
than surfacing as a broken room.
A builder must write pack files, and this container runs with a read-only filesystem, so authoring needs a writable content volume first. Until then editing the JSON directly is the supported path and this tab would only be a worse text editor.
- Scene sequencing across acts, with
kind(battle / story / rest) - Location graph and route validation
- Threat budget preview per scene
- Prologue slide ordering and art binding
Content
Portrait coverage. Served from ART_DIR, outside the web root,
so art can be added to a read-only container through a mounted volume.
Config
Any OpenAI-compatible server. One code path covers Ollama and LM Studio.
Full guide: docs/LLM-CONFIG.md
/v1. Trailing slashes are normalised./v1/models from the server above.
Enter a model name manually
/v1/models. The name
must match exactly, including any :tag.
Generation & auth
Optional text-to-speech server. Narration and the prologue are read aloud by a local synthesiser — nothing is sent to the wider network, and the voice never touches a single roll.
/v1. Any OpenAI-compatible speech endpoint.API key
Browser playback
Lifetimes and ceilings. Every value is bounded server-side; out-of-range input is clamped and the applied value is shown back.
Event management
No event system exists yet. Nothing to configure.
An event is a time-boxed rule override — a modified threat budget, a bonus reward, a themed card pool. Every one of those reaches into resolution, so events depend on the balance multipliers being wired first. Building the UI before the mechanism would be configuring nothing.
- Window (start / end), with an explicit timezone
- Rule overrides, drawn from the same schema as Balance
- Scoped card pool additions — never deletions, per the pack rule
- Participation record, so a completed event survives its window
Season management
No season system exists yet.
A season needs durable per-character progression to reset or carry, and progression currently commits to an in-memory character on campaign completion. Seasons are meaningless without storage that outlives the process.
- Season window and label
- What resets and what is retained — marks and scars are earned history
- Leaderboard snapshot at close
- Pack version pinning, so a season replays on the rules it was played under
Logs
Administrative acts. Separate buffer from the action log so routine dice traffic cannot evict the record of a room being closed.
Runtime verbosity. Changed live, because raising the level during an incident must not require a restart — a restart destroys every in-memory session, which is the state you were trying to inspect.
trace logs every action. Bounded ring buffer, so it cannot
exhaust memory, but it will evict history faster.
Accounts
User management
There is no user database. Access is a single shared passphrase
(EA_PASSPHRASE), and a display name is whatever a player types.
So there is nothing to administer: no per-person record to edit, no credential to reset, no role to grant. A user-management screen over this model would be a UI that lies. Live presence is under Players, which is the honest version of this view.
What real accounts require
- Durable identity store — the same storage gap that blocks seasons
- Per-account credentials and a reset path
- Roles: operator versus player, so this panel can be exposed safely
- Character ownership bound to an account rather than a browser
- Ban and suspension records, which must outlive a session
Compliance
What this server holds, why, and for how long. Served from the code rather than transcribed, so the panel and the docs cannot drift.
A subject access request returns everything held about one display name.
- No durable audit sink — the trail is in memory and lost on restart
- No retention timer — buffers evict by volume, not by age
- No consent record, because no data leaves the process
- Admin endpoints share the game's passphrase; they need their own role
- No transport encryption on the container itself — terminate TLS ahead of it