[Table Tools] Player-visible quest log #115
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context / Motivation
GM-side plot threads exist in the planning workspace:
PlotThread(webapp/backend/app/models/plot_thread.py) withtitle,notes,resolvedbool,introduced_session_id,resolved_session_id,linked_lore_entry_id; CRUD lives inline inwebapp/backend/app/routers/campaigns.py:3322-3390(GET/POST /{campaign_id}/planning/threads,PATCH/DELETE .../threads/{thread_id}); siblingCampaignArcmodel has a real status enum (planned/active/concluded). The player-facing half — "active quests, leads, promises" — is what groups keep in a shared doc today.Spec
Model choice — extend
PlotThread, don't add a parallel model. It already carries session links and a lore link, which is exactly the quest shape; a parallelQuestmodel would immediately drift. Migration adds:status: enumrumored | active | completed | failed | abandoned(replaces the semantics ofresolved; migrateresolved=True→completed,False→active; keep or drop the bool per migration reviewer's call — document it)player_visible: bool, defaultfalse(existing threads stay GM-private)player_summary: nullable Text — the player-facing description;notesremains GM-private alwaysintroduced_session_id/resolved_session_id/linked_lore_entry_idcover the linking requirements)API:
campaigns.py:3322-3390) with the new fields (GM-only, as today).GET /campaigns/{campaign_id}/quests(any member): returns onlyplayer_visible=truethreads and only public fields (title,status,player_summary, session/lore links) — the serializer must never includenotes. Do not reuse the GMThreadResponseschema; define a separateQuestResponse.UI:
Bot (small): extend
/nextor add/questsinbot/questboard_bot/cogs/sessions.py(command group precedent at:42for/next) listing active player-visible quests via a new backend endpoint on the bot contract (webapp/backend/app/routers/bot.py+bot/questboard_bot/api_client.py, same commit).Out of scope (flagged follow-up)
Acceptance criteria
/questsreceives visible quests withoutnotesin any response shape; GM notes never leak (assert on raw JSON keys).References
webapp/backend/app/models/plot_thread.py(current columns incl.resolvedat line 22, session/lore FKs at 23-31)webapp/backend/app/models/campaign_arc.py(ArcStatusenum precedent)webapp/backend/app/routers/campaigns.py:3322-3390(thread endpoints,ThreadResponse)bot/questboard_bot/cogs/sessions.py:42(/next)webapp/backend/app/routers/bot.py,bot/questboard_bot/api_client.py(contract pair)Filed from the July 2026 full-project review.
Done — merged in PR #193 (backend+bot
6d4a0d1, frontendba5a714). CI green.Shipped:
PlotThread(no parallel model): newQuestStatusenum (rumored/active/completed/failed/abandoned),player_visible,player_summary; droppedresolved, data-migratedresolved=true → completed(migrationf2a3b4c5d6e7, upgrade/downgrade/upgrade verified on a reset test DB).notesstays GM-only. New member-readableGET /campaigns/{id}/questswith a separateQuestResponsebuilt by explicit field mapping — structurally can't leaknotes.GET /api/bot/guilds/{guild_id}/quests+/questsslash command (active + player-visible only). Additive → noBOT_CONTRACT_VERSIONbump.ThreadTrackermigratedresolved→statuswith a per-row visibility toggle + player-summary field; new read-onlyQuestLogon the campaign page (grouped Active/Rumored, resolved collapsed), never shows notes.Tests: backend 466 pass (+10
test_quests.py, incl. a raw-JSON-keys check thatnotesnever reaches players/bot); frontend 206 (+4QuestLog).Acceptance criteria all met: player token gets visible quests without
notes; GM CRUD covers status/visibility/summary and toggling visibility immediately affects the player view; player view renders all five statuses with session/lore links; bot command handles the zero-quest case.Closing.