- Move cross-cutting docs (personas, design system, implementation phases, Ideen.md) to .specify/memory/ - Move cross-cutting research and plans to .specify/memory/research/ and .specify/memory/plans/ - Extract 5 setup tasks from spec/setup-tasks.md into individual specs/001-005/spec.md files with spec-kit template format - Extract 20 user stories from spec/userstories.md into individual specs/006-026/spec.md files with spec-kit template format - Relocate feature-specific research and plan docs into specs/[feature]/ - Add spec-kit constitution, templates, scripts, and slash commands - Slim down CLAUDE.md to Claude-Code-specific config, delegate principles to .specify/memory/constitution.md - Update ralph.sh with stream-json output and per-iteration logging - Delete old spec/ and docs/agents/ directories - Gitignore Ralph iteration JSONL logs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
8.2 KiB
Feature Specification: Cancel an Event as Organizer
Feature: 024-cancel-event
Created: 2026-03-06
Status: Draft
Source: Migrated from spec/userstories.md
User Scenarios & Testing
User Story 1 - Cancel event with optional message (Priority: P1)
The event organizer, from the organizer view, triggers a dedicated "Cancel event" action. A confirmation step is required before finalising. The organizer may optionally enter a cancellation message (reason or explanation). After confirmation, the server sets the event to cancelled state with the provided message. The event page immediately displays a "cancelled" state visible to all visitors. No RSVP submissions are accepted by the server from this point.
Why this priority: Cancellation is a fundamental lifecycle action — guests need to be clearly informed when an event is cancelled rather than discovering it silently. This is the core of US-18.
Independent Test: Can be fully tested by creating an event, triggering cancel (with and without a message), and verifying the event page shows a "cancelled" indicator and the RSVP form is absent.
Acceptance Scenarios:
- Given an organizer with a valid organizer token in localStorage, When they click "Cancel event", Then a confirmation step is shown before any change is made.
- Given the organizer confirms cancellation without entering a message, When the server processes the request, Then the event is marked cancelled and the event page shows a "cancelled" state with no message.
- Given the organizer confirms cancellation with a message, When the server processes the request, Then the event page displays the "cancelled" state along with the cancellation message.
- Given a cancelled event, When a guest attempts to submit an RSVP, Then the server rejects the submission and the RSVP form is not shown on the event page.
- Given a cancelled event that has not yet expired, When any visitor opens the event URL, Then the full event page renders with a clear "cancelled" indicator — no partial data is hidden.
User Story 2 - Adjust expiry date during cancellation (Priority: P2)
When cancelling, the organizer can optionally adjust the event's expiry date to control how long the cancellation notice remains visible before automatic data deletion (US-12). The adjusted date must be in the future, consistent with US-5's expiry date constraint.
Why this priority: The expiry date adjustment is a convenience — organizers may want to keep the cancellation notice visible for a specific period (e.g. one more week) or trigger earlier cleanup. The core cancellation (P1) works without it.
Independent Test: Can be tested by cancelling an event while setting a new expiry date in the future, then verifying the event's expiry date was updated and data persists until that date.
Acceptance Scenarios:
- Given the organizer confirms cancellation with a new expiry date set in the future, When the server processes the request, Then the event is cancelled and its expiry date is updated to the provided value.
- Given the organizer provides an expiry date in the past or set to today during cancellation, When the server processes the request, Then the request is rejected with a clear validation error.
- Given the organizer confirms cancellation without adjusting the expiry date, When the server processes the request, Then the existing expiry date is unchanged.
User Story 3 - Edit cancellation message after cancellation (Priority: P3)
After an event is cancelled, the organizer can update the cancellation message (e.g. to correct a typo or add further explanation). The cancelled state itself cannot be changed.
Why this priority: Editing the message is a refinement capability. The core behaviour (cancellation + message at time of cancellation) is sufficient for P1 and P2.
Independent Test: Can be tested by cancelling an event, then submitting an updated cancellation message via the organizer view, and verifying the new message is displayed on the event page.
Acceptance Scenarios:
- Given a cancelled event with a valid organizer token, When the organizer submits an updated cancellation message, Then the event page displays the new message.
- Given a cancelled event with a valid organizer token, When the organizer attempts to un-cancel (set the event back to active), Then the server rejects the request — cancellation is a one-way state transition.
- Given a cancelled event with an absent or invalid organizer token, When a request is made to edit the cancellation message, Then the server rejects the request.
Edge Cases
- Organizer token absent or invalid: the "Cancel event" action is not shown in the UI and the server rejects any cancel or message-edit request with an appropriate error response.
- RSVP on a cancelled event: the server rejects RSVP submissions with a clear error; the RSVP form is hidden on the client.
- Cancellation message is optional: omitting it is valid — the event still transitions to cancelled state with no message displayed.
- Cancellation + expiry: after the expiry date passes, the event is deleted by the cleanup process (US-12) regardless of cancelled state; the cancellation data is removed as part of the full event deletion.
- Already-expired event at time of cancellation: [NEEDS EXPANSION] — it is unclear whether cancellation should be allowed if the event has already expired but not yet been cleaned up. This edge case should be addressed during implementation.
Requirements
Functional Requirements
- FR-001: The Event entity MUST persist a
is_cancelledboolean (default false) and an optionalcancellation_messagestring, both server-side. - FR-002: The cancel endpoint MUST require a valid organizer token; requests without a valid token are rejected.
- FR-003: The cancel endpoint MUST accept an optional plain-text cancellation message.
- FR-004: The cancel endpoint MUST accept an optional updated expiry date, which MUST be in the future; if provided and not in the future, the request is rejected with a clear validation error.
- FR-005: Cancellation MUST be a one-way state transition: once cancelled, the event cannot be set back to active via any API endpoint.
- FR-006: The event page MUST display a "cancelled" state indicator and the cancellation message (if present) for any visitor once the event is cancelled.
- FR-007: The RSVP endpoint MUST reject submissions for cancelled events; the RSVP form MUST be hidden on the client for cancelled events.
- FR-008: The organizer MUST be able to update the cancellation message after cancellation via a dedicated update action; this action MUST require a valid organizer token.
- FR-009: The UI MUST present a confirmation step before submitting the cancellation request; the cancel action MUST NOT be triggerable in a single click without confirmation.
- FR-010: The "Cancel event" action and organizer-specific cancel UI MUST NOT be rendered when no valid organizer token is present in localStorage.
- FR-011: No personal data, IP addresses, or identifiers MUST be logged during cancellation or cancellation message updates.
Key Entities
- CancellationState: Value type on Event. Fields:
is_cancelled(boolean, persistent),cancellation_message(optional string, persistent). Not a separate entity — stored on the Event record.
Success Criteria
Measurable Outcomes
- SC-001: An organizer with a valid token can cancel an event (with or without a message) in a single confirmed action, and the cancelled state is immediately reflected on the event page.
- SC-002: After cancellation, no guest can successfully submit an RSVP via the API, regardless of client-side state.
- SC-003: The event page correctly renders a "cancelled" indicator (and message if provided) for any visitor after cancellation — no RSVP form, no false "active" state.
- SC-004: Cancellation data (state and message) is removed automatically when the event expires and is deleted by the cleanup process (US-12).
- SC-005: No client or API call can revert a cancelled event to an active state.