46 lines
7.0 KiB
Markdown
46 lines
7.0 KiB
Markdown
# Arrowstack Character
|
|
|
|
Mobile-first Vue 3 / TypeScript character-sheet PWA. Pinia manages state, Dexie stores characters in IndexedDB, Zod validates saves and JSON imports. A small Express gateway protects the application with a confidential Keycloak OIDC client using authorization code flow, PKCE, state and nonce verification.
|
|
|
|
## v0.3
|
|
|
|
Create/edit multiple characters, abilities, skill/expertise and save proficiency, HP/temp HP, armour class, speed, manually entered attacks, spellbook/preparation, generic resources, rest preview, inventory, notes, d20 rolls, account-separated local saves, JSON import/export. No copyrighted spell or rule compendium is bundled. Account-backed PostgreSQL storage and offline-first sync are available. Existing local characters upload after sign-in; conflicts retain offline edits as a new local copy instead of overwriting remote changes.
|
|
|
|
Short rest resets declared short-rest resources. Long rest also resets long-rest resources, restores HP and clears temporary HP. Hit dice and class-specific rest rules are manual. These are configurable sheet operations, not a complete edition-specific rules engine.
|
|
|
|
## Authentication and offline behavior
|
|
|
|
Use existing Arrowstack accounts in the dev realm. Any authenticated realm user can use the app; no control-plane role is required. Keycloak tokens and the confidential client secret stay server-side. The encrypted 12-hour session uses a Secure, HttpOnly, SameSite=Lax, host-only cookie. Protected HTML requires a session; unauthenticated /api/session returns 401. Static JS/CSS and PWA metadata are public, but contain no character data or secrets.
|
|
|
|
After successful sign-in, the worker caches the app shell and immutable build assets for offline use. The browser retains only the last subject/name/expiry, not OIDC tokens. Browser offline access expires with the session after at most 12 hours. Revocation cannot be checked while offline; reconnecting rechecks the gateway session. Character storage is namespaced by Keycloak subject, not encrypted at rest. Treat the device as trusted. Sign-out removes offline identity and cached shell while preserving per-account character backups. Sign-out ends the app session; the Arrowstack SSO session may still exist.
|
|
|
|
Clearing site data removes unsynced device saves. Account-synced sheets download after sign-in. Export JSON backups before clearing browser storage.
|
|
|
|
## Build and deploy
|
|
|
|
`npm ci`, `npm test`, `npm run build`. Docker executes tests and type-check/build, then runs as an unprivileged node user on 8080. No Gitea Actions builder is required.
|
|
|
|
Runtime configuration: DATABASE_URL (injected by Arrowstack tenant provisioning), APP_ORIGIN=https://dnd.arrowstack.dev, KEYCLOAK_ISSUER, KEYCLOAK_CLIENT_ID, KEYCLOAK_CLIENT_SECRET. Provision confidential client `dnd-character` with standard authorization code flow only, exact redirect `https://dnd.arrowstack.dev/auth/callback`, PKCE S256. Use Arrowstack's secret handoff to inject credentials directly into Coolify. /health exposes status/version/revision, never secrets. Canonical source is private in Admin/dnd-character-pwa. For now Coolify builds the public Admin/dnd-character-deploy mirror main branch over HTTPS; runtime secrets are never committed. See deployment.md for resource IDs and release steps. Redeploy a prior mirror commit through Coolify to roll back; database tables initialize additively at startup. Keep the database when rolling back; old app versions cannot expose synced sheets.
|
|
|
|
Local production smoke test needs the same HTTPS origin and Keycloak configuration. Do not add an authentication bypass to production. Vite development uses its proxy for /auth and /api.
|
|
|
|
## MCP
|
|
|
|
Connect a Streamable HTTP client to `https://dnd.arrowstack.dev/mcp`. Discovery is at `/.well-known/oauth-protected-resource/mcp` and `/.well-known/oauth-authorization-server`. Public/confidential OAuth client registration is supported at `/register`; authorization code with mandatory S256 PKCE, resource binding and exact registered redirects is handled by the MCP SDK. Keycloak sign-in uses the existing confidential app client, followed by a per-client consent screen. HTTPS redirects or HTTP loopback redirects only.
|
|
|
|
Scopes: `characters:read` (default) and `characters:write` (explicit consent). Tokens are encrypted, audience-bound, short-lived and checked against persisted grants. Refresh tokens rotate; authorization codes and refresh tokens are one-time use. Grants expire with the 12-hour browser sign-in period. `/revoke` revokes a client grant; browser sign-out ends the browser session and does not revoke previously approved MCP grants. MCP access tokens cannot act as browser sessions.
|
|
|
|
Tools: list_characters, get_character, create_character, update_character, change_hit_points, apply_rest, set_resource, delete_character, roll_dice. Resource: `character://collection`. Writes require an expected revision. Read a sheet again after a conflict; do not retry stale writes. Character rules remain manually configured, without a bundled spell/rule compendium.
|
|
|
|
PWA sync runs after sign-in, after edits, on reconnect and every 30 seconds. Local IndexedDB remains available offline; server data is account-scoped by Keycloak subject. Sync stores deletion tombstones to prevent another device reviving deleted sheets. Stale offline modifications are preserved as a new local copy; deleting a stale sheet retains the newer account version. Database initialization is additive; do not remove tables or character data during rollback.
|
|
|
|
## Campaigns and roles
|
|
|
|
Choose Campaigns to create a table or redeem a single-use invitation (valid seven days). Every campaign has at least one DM; memberships and player/DM roles are campaign-specific. DMs can invite players/co-DMs, manage members, save NPCs/monsters and secrets, plan party-visible sessions, and run initiative encounters.
|
|
|
|
Owners explicitly assign saved PCs and can revoke optional DM HP delegation. Party views share name, class, species, level, abilities and combat stats; personal notes, inventory, spellbook and resources remain private. Private campaign notes are author-only, party notes are member-visible, and DM notes/hidden NPCs require a current DM role. Visible NPC notes remain DM-only. Removed members lose access and their PCs are unassigned. Role changes take effect server-side, including MCP access.
|
|
|
|
Encounter participants and HP are party-visible snapshots; snapshot damage does not alter saved PC sheets. Actual party HP editing needs current DM membership, explicit owner delegation and the latest sheet revision. Campaign writes use optimistic revisions; stale writes require a refresh. Campaigns are online-only; existing personal sheets retain offline support.
|
|
|
|
Sixteen additional MCP tools cover campaigns, invites, membership, PC assignment, notes, NPCs, sessions, encounters and delegated HP. Existing characters:read / characters:write scopes also gate campaign operations, with membership and role checks on every call. Consent discloses both characters and campaigns. The private plugin retains its identity and endpoint.
|