[Frontend] Add missing self-service controls: un-reveal a spoiler, delete an XP entry, and .ics calendar export #389

Closed
opened 2026-08-25 20:42:26 +00:00 by claude-bot · 2 comments
Contributor

Impact: MEDIUM

Found in the August 2026 session lifecycle review (#319).

What the user experiences

Three backend capabilities exist with no UI control to reach them. A GM who reveals a spoiler card to the table during a live session has no way to retract it — the backend supports un-revealing, but no button calls it. XP entries appear to be permanently un-deletable from the UI once created. And the calendar-add control only offers Google Calendar; Apple/Outlook users, a substantial share of any hosted audience, have no path to add a session to their calendar at all.

Evidence

  • webapp/frontend/src/api/shelf.jsrevokeSessionReveal is exported and never called anywhere in the frontend.
  • webapp/frontend/src/api/loot.jsfetchXp/deleteXp are exported and never called anywhere in the frontend.
  • webapp/frontend/src/pages/SessionDetail.jsx:1414-1428 — "Add to Calendar" offers Google Calendar only, no .ics download.

Why it matters for a hosted product

Each of these is a real backend capability with zero UI cost to expose, and each closes a specific "I can't undo/manage this" complaint a hosted customer would otherwise have no way to self-serve.

Proposed fix

Add an un-reveal button to the reveal list on SessionShelf, calling the existing revokeSessionReveal. Add a delete control to XP entries on the loot ledger, calling the existing deleteXp. Add an .ics download option alongside the existing Google Calendar link on SessionDetail. This is the audit's M4, M5, and the fetchXp/deleteXp orphan noted in §2.3.

Acceptance criteria

  • SessionShelf has an un-reveal control for previously-revealed cards.
  • The loot ledger has a delete control for individual XP entries.
  • SessionDetail's calendar control offers an .ics download in addition to Google Calendar.
**Impact: MEDIUM** Found in the August 2026 session lifecycle review (#319). ## What the user experiences Three backend capabilities exist with no UI control to reach them. A GM who reveals a spoiler card to the table during a live session has no way to retract it — the backend supports un-revealing, but no button calls it. XP entries appear to be permanently un-deletable from the UI once created. And the calendar-add control only offers Google Calendar; Apple/Outlook users, a substantial share of any hosted audience, have no path to add a session to their calendar at all. ## Evidence - `webapp/frontend/src/api/shelf.js` — `revokeSessionReveal` is exported and never called anywhere in the frontend. - `webapp/frontend/src/api/loot.js` — `fetchXp`/`deleteXp` are exported and never called anywhere in the frontend. - `webapp/frontend/src/pages/SessionDetail.jsx:1414-1428` — "Add to Calendar" offers Google Calendar only, no `.ics` download. ## Why it matters for a hosted product Each of these is a real backend capability with zero UI cost to expose, and each closes a specific "I can't undo/manage this" complaint a hosted customer would otherwise have no way to self-serve. ## Proposed fix Add an un-reveal button to the reveal list on `SessionShelf`, calling the existing `revokeSessionReveal`. Add a delete control to XP entries on the loot ledger, calling the existing `deleteXp`. Add an `.ics` download option alongside the existing Google Calendar link on `SessionDetail`. This is the audit's M4, M5, and the `fetchXp`/`deleteXp` orphan noted in §2.3. ## Acceptance criteria - [ ] `SessionShelf` has an un-reveal control for previously-revealed cards. - [ ] The loot ledger has a delete control for individual XP entries. - [ ] `SessionDetail`'s calendar control offers an `.ics` download in addition to Google Calendar.
Author
Contributor

Picking this up as v4.3.0 phase 7 (#514). Un-reveal on the shelf's reveal list and delete on XP entries call the endpoints that already exist. For the calendar export the decision is a small server-side GET /api/sessions/{id}/calendar.ics (members only, one VEVENT in UTC from the same fields the Google link uses) rather than a browser-built file, so times are computed once and tested once; the page links it as a download beside Google Calendar.

Picking this up as v4.3.0 phase 7 (#514). Un-reveal on the shelf's reveal list and delete on XP entries call the endpoints that already exist. For the calendar export the decision is a small server-side `GET /api/sessions/{id}/calendar.ics` (members only, one VEVENT in UTC from the same fields the Google link uses) rather than a browser-built file, so times are computed once and tested once; the page links it as a download beside Google Calendar.
Author
Contributor

Done in the phase 7b PR (auto-merging on green); ships with v4.3.0.

Un-reveal is a "Shown to the table" strip on the shelf, not a button on each card: ShelfRevealOut.shelf_card_id is nullable, so a reveal can outlive its card, and a card-attached control would leave orphans permanently up with no way down. It calls the existing revokeSessionReveal; the player table picks the change up on its own poll, as it already does for reveals.

fetchXp and deleteXp were both unused for one underlying reason: the ledger rendered XP totals only, so an individual award was never on screen to act on. Awards are now listed like loot and gold, each with a delete whose confirm names it.

On the .ics: the backend endpoint already existed, GET /api/sessions/{id}/calendar.ics, member-gated, text/calendar, built by calendar_service.build_single_session_ics, which shares its event, escaping and date code with the subscribable feed and the emailed invites. It had tests and no caller, so this is a download link, not a new endpoint. One change was needed there: eligibility was "status is confirmed", but the "Add to Calendar" section renders on confirmed_time, so a completed session would have offered a download that answered 400. Widened to "has a scheduled time", which matches both the UI's condition and the feed's statuses. A session with no scheduled time stays 400, not 404: it exists, there is just nothing to put in a calendar yet; documented in the endpoint and asserted in a test.

Tests: 5 new backend (member 200, non-member 403, exact DTSTART/DTEND/UID/SUMMARY, past-confirmed still 200 with the right STATUS, unscheduled 400); frontend covers un-reveal, delete-XP-with-confirm, and the .ics link beside Google Calendar.

Done in the phase 7b PR (auto-merging on green); ships with v4.3.0. Un-reveal is a "Shown to the table" strip on the shelf, not a button on each card: `ShelfRevealOut.shelf_card_id` is nullable, so a reveal can outlive its card, and a card-attached control would leave orphans permanently up with no way down. It calls the existing `revokeSessionReveal`; the player table picks the change up on its own poll, as it already does for reveals. `fetchXp` and `deleteXp` were both unused for one underlying reason: the ledger rendered XP totals only, so an individual award was never on screen to act on. Awards are now listed like loot and gold, each with a delete whose confirm names it. On the `.ics`: **the backend endpoint already existed**, `GET /api/sessions/{id}/calendar.ics`, member-gated, `text/calendar`, built by `calendar_service.build_single_session_ics`, which shares its event, escaping and date code with the subscribable feed and the emailed invites. It had tests and no caller, so this is a download link, not a new endpoint. One change was needed there: eligibility was "status is confirmed", but the "Add to Calendar" section renders on `confirmed_time`, so a completed session would have offered a download that answered 400. Widened to "has a scheduled time", which matches both the UI's condition and the feed's statuses. A session with no scheduled time stays 400, not 404: it exists, there is just nothing to put in a calendar yet; documented in the endpoint and asserted in a test. Tests: 5 new backend (member 200, non-member 403, exact DTSTART/DTEND/UID/SUMMARY, past-confirmed still 200 with the right STATUS, unscheduled 400); frontend covers un-reveal, delete-XP-with-confirm, and the `.ics` link beside Google Calendar.
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rbrooks/Quest-Board#389
No description provided.