feat: player-visible quest log (#115) #193

Merged
claude-bot merged 2 commits from feat/115-quest-log into main 2026-07-18 01:23:47 +00:00
Contributor

Closes #115. Second feature of v3.7.0 Table Tools.

Extends the existing PlotThread (GM plot threads) so it doubles as the player-facing quest log — no parallel model, player_visible gates who sees what.

Backend (6d4a0d1)

  • New QuestStatus enum (rumored/active/completed/failed/abandoned) + player_visible / player_summary columns. Drops the old resolved bool, data-migrating resolved=true → completed (migration f2a3b4c5d6e7, verified upgrade→downgrade→upgrade round-trip on a reset test DB).
  • GM thread endpoints gain the new fields (require_gm; GM view keeps private notes). list_threads now orders open statuses before closed.
  • New member-readable GET /campaigns/{id}/quests returning a separate QuestResponse built by explicit field mapping — structurally cannot leak notes or other GM-only columns. Filters player_visible=true.
  • Bot: GET /api/bot/guilds/{guild_id}/quests (active + visible, safe fields) + api_client.get_guild_quests() + a /quests slash command with a friendly zero-quest message. Purely additive → no BOT_CONTRACT_VERSION bump.

Frontend (<this PR head>)

  • ThreadTracker migrated from resolved to status (badge + status select; "closed" = completed/failed/abandoned drives show/hide + counts + dimming). Per-row player_visible quick-toggle and a player_summary field, clearly distinct from GM-private notes.
  • New read-only QuestLog on the campaign page (all members): grouped Active / Rumored, resolved statuses under a collapsed section, links to sessions + wiki entries, never shows notes.

Tests

  • Backend: +10 in test_quests.py, incl. a raw-JSON-keys assertion that notes never appears in the player or bot response, plus visibility-filter coverage. Full suite 466 pass; migration round-trip verified.
  • Frontend: +4 QuestLog; 206 pass, eslint clean, vite build green.

Notes

  • One fix applied during review: two backend tests originally combined the gm_client + player_client fixtures, which share app.dependency_overrides (last wins → GM requests ran as the player → spurious 403). Rewrote them to seed the other user's rows via db and use one client per test (matching the #112 convention), and added a GM-only PATCH-wiring test.
  • Dropping resolved is a deliberate single-source-of-truth call; all references (backend endpoints + frontend ThreadTracker) were updated in the same branch, so no half-migrated state ships.

🤖 Generated with Claude Code

Closes #115. Second feature of **v3.7.0 Table Tools**. Extends the existing `PlotThread` (GM plot threads) so it doubles as the player-facing quest log — no parallel model, `player_visible` gates who sees what. ## Backend (`6d4a0d1`) - New `QuestStatus` enum (`rumored/active/completed/failed/abandoned`) + `player_visible` / `player_summary` columns. **Drops the old `resolved` bool**, data-migrating `resolved=true → completed` (migration `f2a3b4c5d6e7`, verified upgrade→downgrade→upgrade round-trip on a reset test DB). - GM thread endpoints gain the new fields (`require_gm`; GM view keeps private `notes`). `list_threads` now orders open statuses before closed. - **New member-readable `GET /campaigns/{id}/quests`** returning a *separate* `QuestResponse` built by explicit field mapping — structurally cannot leak `notes` or other GM-only columns. Filters `player_visible=true`. - Bot: `GET /api/bot/guilds/{guild_id}/quests` (active + visible, safe fields) + `api_client.get_guild_quests()` + a `/quests` slash command with a friendly zero-quest message. **Purely additive → no `BOT_CONTRACT_VERSION` bump.** ## Frontend (`<this PR head>`) - `ThreadTracker` migrated from `resolved` to `status` (badge + status select; "closed" = completed/failed/abandoned drives show/hide + counts + dimming). Per-row `player_visible` quick-toggle and a `player_summary` field, clearly distinct from GM-private notes. - New read-only `QuestLog` on the campaign page (all members): grouped Active / Rumored, resolved statuses under a collapsed section, links to sessions + wiki entries, never shows notes. ## Tests - Backend: +10 in `test_quests.py`, incl. a **raw-JSON-keys assertion** that `notes` never appears in the player or bot response, plus visibility-filter coverage. Full suite **466 pass**; migration round-trip verified. - Frontend: +4 `QuestLog`; **206 pass**, eslint clean, vite build green. ## Notes - One fix applied during review: two backend tests originally combined the `gm_client` + `player_client` fixtures, which share `app.dependency_overrides` (last wins → GM requests ran as the player → spurious 403). Rewrote them to seed the other user's rows via `db` and use one client per test (matching the #112 convention), and added a GM-only PATCH-wiring test. - Dropping `resolved` is a deliberate single-source-of-truth call; all references (backend endpoints + frontend ThreadTracker) were updated in the same branch, so no half-migrated state ships. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Extends PlotThread so GM plot threads double as player-facing quests,
rather than adding a parallel model.

Backend:
- New QuestStatus enum (rumored/active/completed/failed/abandoned) +
  player_visible / player_summary columns; drops the old `resolved` bool,
  migrating resolved=true -> completed (migration f2a3b4c5d6e7, round-trips).
- GM thread endpoints gain the new fields (still require_gm; ThreadResponse
  keeps GM `notes`).
- New member-readable GET /campaigns/{id}/quests returning a separate
  QuestResponse built by explicit field mapping — structurally cannot leak
  GM `notes` or other private columns. Filters player_visible=true.
- list_threads ordering now surfaces open statuses before closed ones.

Bot (additive — no BOT_CONTRACT_VERSION bump):
- GET /api/bot/guilds/{guild_id}/quests (active + player_visible only,
  safe fields).
- api_client.get_guild_quests() + /quests slash command listing active
  quests, with a friendly zero-quest message.

Tests: +10 in test_quests.py incl. a raw-JSON-keys assertion that `notes`
never appears in the player or bot response, and visibility-filter coverage.
Full backend suite 466 pass; migration upgrade/downgrade/upgrade verified.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(frontend): quest log — status rework + player quest view (#115)
All checks were successful
CI / Docker image build (pull_request) Successful in 41s
CI / Backend lint (ruff) (pull_request) Successful in 47s
CI / Frontend tests, audit, and build (pull_request) Successful in 1m30s
CI / Bot tests and audit (pull_request) Successful in 2m2s
CI / Backend migration, tests, and audit (pull_request) Successful in 4m5s
ba5a714d46
- ThreadTracker (CampaignPlanning): migrate from the dropped `resolved`
  bool to the `status` enum (rumored/active/completed/failed/abandoned).
  Per-row status badge + status <select> in the editor; "closed" =
  completed/failed/abandoned drives the show/hide toggle, counts, and
  dimmed styling. Adds a per-row `player_visible` quick-toggle and a
  `player_summary` field (labelled distinct from GM-private notes).
- QuestLog (new, CampaignDetail): read-only player-facing quest log via
  GET /campaigns/{id}/quests — grouped Active / Rumored, with
  completed/failed/abandoned under a collapsed "Resolved quests" section.
  Links to introduced/resolved sessions and linked wiki entries. Never
  shows notes. Visible to all members.
- api/planning.js: add fetchQuests.

Tests: +4 QuestLog; CampaignDetail test mocks fetchQuests. 206 pass,
eslint clean, vite build succeeds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
claude-bot deleted branch feat/115-quest-log 2026-07-18 01:23:48 +00:00
Sign in to join this conversation.
No description provided.