Allows guests to cancel their RSVP via a DELETE endpoint using their guestToken. Frontend shows cancel button in RsvpBar and clears local storage on success. Includes unit tests, integration tests, and E2E spec. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
9.3 KiB
Feature Specification: Cancel RSVP
Feature Branch: 014-cancel-rsvp
Created: 2026-03-09
Status: Draft
Input: User description: "A guest can cancel their attendance if they still have their RSVP token in localStorage. The event detail view should offer this functionality (design proposals needed). The RSVP is permanently deleted from the database by RSVP token. When a guest removes an entry from their event list, attendance is automatically cancelled. The confirmation dialog informs the guest about this behavior."
User Scenarios & Testing (mandatory)
User Story 1 - Cancel RSVP from Event Detail View (Priority: P1)
A guest who previously RSVP'd to an event visits the event detail page. The sticky bottom bar shows their attendance status ("You're attending!"). The guest can cancel their attendance directly from this view. After cancellation, their RSVP is permanently removed from the server and from localStorage. The attendee count decreases by one, and the RSVP bar returns to the initial "I'm attending" call-to-action state, allowing the guest to re-RSVP if desired.
Why this priority: This is the core feature — the explicit, intentional cancellation flow. It gives guests direct control over their attendance and is the primary interaction point.
Independent Test: Can be fully tested by navigating to an event detail page as an RSVP'd guest, cancelling, and verifying the RSVP is deleted server-side and the UI resets.
Acceptance Scenarios:
- Given a guest has an RSVP token stored in localStorage for an event, When they view the event detail page, Then they see a way to cancel their attendance alongside their attendance status.
- Given the guest initiates cancellation, When the system presents a confirmation prompt, Then the prompt clearly states that attendance will be permanently cancelled.
- Given the guest confirms cancellation, When the server successfully deletes the RSVP, Then the RSVP token and name are removed from localStorage, the attendee count decreases by one, and the RSVP bar returns to the initial call-to-action state.
- Given the guest confirms cancellation, When the server returns an error, Then the guest sees an error message and their attendance status remains unchanged.
- Given the guest cancels and the RSVP bar resets, When the guest taps the call-to-action, Then they can submit a new RSVP as normal.
User Story 2 - Auto-Cancel on Event List Removal (Priority: P2)
A guest removes an event from their personal event list (via delete button or swipe gesture on the event card). If the guest has an RSVP token for that event, the confirmation dialog informs them that removing the event will also cancel their attendance on the server. Upon confirmation, the RSVP is deleted from the server before the event is removed from localStorage.
Why this priority: This ensures data consistency between client and server. Without it, a guest could believe they cancelled but their name would remain on the attendee list.
Independent Test: Can be fully tested by adding an RSVP'd event to the list, removing it via the event list, and verifying the RSVP is deleted server-side.
Acceptance Scenarios:
- Given a guest has an event in their list with an RSVP token, When they initiate removal (delete button or swipe), Then the confirmation dialog explicitly mentions that their attendance will also be cancelled.
- Given a guest has an event in their list without an RSVP token (organizer-only or link-only), When they initiate removal, Then the confirmation dialog does not mention attendance cancellation (existing behavior unchanged).
- Given the guest confirms removal of an RSVP'd event, When the server successfully deletes the RSVP, Then the event is removed from localStorage (including RSVP token) and disappears from the list.
- Given the guest confirms removal of an RSVP'd event, When the server fails to delete the RSVP, Then the guest sees an error message and the event remains in the list unchanged.
- Given the guest dismisses the confirmation dialog, When no action is taken, Then the event and RSVP remain unchanged.
User Story 3 - Cancel RSVP with Expired/Invalid Token (Priority: P3)
A guest attempts to cancel their RSVP, but the token is no longer valid on the server (e.g., the event was deleted, or the RSVP was already removed by another means). The system handles this gracefully.
Why this priority: Edge case handling — less common but important for a smooth user experience.
Independent Test: Can be tested by manipulating localStorage to contain a stale RSVP token and attempting cancellation.
Acceptance Scenarios:
- Given a guest has a stale RSVP token in localStorage, When they attempt to cancel from the event detail view, Then the system treats a "not found" server response as a successful cancellation (the RSVP is already gone), cleans up localStorage, and resets the UI.
- Given a guest has a stale RSVP token in localStorage, When they remove the event from their list, Then the system treats a "not found" server response as success and removes the event from localStorage.
Edge Cases
- What happens when the guest has no internet connection during cancellation? → Show an error message; do not modify localStorage or UI state.
- What happens if the event itself has been deleted? → The event detail view already handles the "not found" state. For list removal, treat the 404 as success and clean up localStorage.
- What happens if multiple browser tabs are open? → localStorage changes propagate across tabs; the RSVP bar should reflect the current localStorage state on visibility/focus.
Requirements (mandatory)
Functional Requirements
- FR-001: System MUST provide a cancellation endpoint that permanently deletes an RSVP record identified by event token and RSVP token.
- FR-002: System MUST return a success response when the RSVP is deleted, including when the RSVP does not exist (idempotent delete).
- FR-003: The event detail view MUST display a cancel option when the guest has an RSVP token in localStorage for the current event.
- FR-004: The cancel option MUST require explicit confirmation before proceeding.
- FR-005: After successful cancellation, the system MUST remove the RSVP token and RSVP name from localStorage for that event.
- FR-006: After successful cancellation on the event detail view, the attendee count MUST decrease by one and the RSVP bar MUST return to its initial call-to-action state.
- FR-007: When a guest removes an RSVP'd event from their event list, the system MUST attempt to delete the RSVP on the server before removing it from localStorage.
- FR-008: The event list removal confirmation dialog MUST inform the guest that their attendance will be cancelled when an RSVP token is present.
- FR-009: If the server returns an error (other than "not found") during cancellation, the system MUST show an error message and leave the local state unchanged.
- FR-010: The cancellation endpoint MUST only delete the RSVP matching the provided RSVP token — no other RSVPs or event data may be affected.
Key Entities
- RSVP: An attendance record linking a guest name to an event. Identified by a unique RSVP token (UUID). Existence indicates attendance; deletion indicates cancellation.
- Stored Event (client-side): A localStorage entry containing event metadata, and optionally an RSVP token and name if the guest has RSVP'd.
Success Criteria (mandatory)
Measurable Outcomes
- SC-001: A guest can cancel their RSVP from the event detail view in under 5 seconds (two taps: cancel + confirm).
- SC-002: After cancellation, the guest's name no longer appears in the attendee list when viewed by the organizer.
- SC-003: Removing an RSVP'd event from the event list results in server-side RSVP deletion 100% of the time when the server is reachable.
- SC-004: The confirmation dialog clearly communicates the consequence (attendance cancellation) — no guest should be surprised by the side effect.
- SC-005: A guest can re-RSVP after cancellation without any issues.
Design Decision: Cancel UI on Event Detail View
Chosen: Tap-to-Reveal Pattern
The current RSVP bar (sticky bottom) shows "You're attending!" after an RSVP. The status bar becomes tappable. Tapping it reveals a slide-out or expand animation with a "Cancel attendance" button. Tapping outside collapses it back. A subtle visual hint (chevron or icon) indicates the bar is interactive.
Assumptions
- The existing
findByRsvpToken()repository method can be leveraged for the delete operation. - The RSVP token alone (combined with the event token in the URL) is sufficient authorization for deletion — consistent with the project's token-based privacy model.
- The delete operation is idempotent: deleting an already-deleted RSVP returns success (not an error).
- The event list confirmation dialog already exists and can be extended with conditional messaging.
Dependencies
- 008-rsvp: The RSVP creation flow and localStorage storage pattern (completed).
- 007-view-event: The event detail view and RSVP bar component (completed).
- 009-list-events: The event list with delete functionality (completed).