# Feature Specification: Cancel Event

**Feature Branch**: `016-cancel-event`
**Created**: 2026-03-12
**Status**: Draft
**Input**: User description: "As an organizer, I want to cancel an event so that attendees know the event will not take place"

## User Scenarios & Testing *(mandatory)*

### User Story 1 - Organizer Cancels an Event (Priority: P1)

An organizer navigates to their event page (identified by having the organizer token). They decide to cancel the event. They tap a "Cancel Event" button, which opens a bottom sheet (visually similar to the attend/RSVP flow). The bottom sheet contains a text area for an optional cancellation reason and a confirm button. After confirming, the event is permanently marked as cancelled. This action is irreversible.

**Why this priority**: This is the core action of the feature. Without it, nothing else matters.

**Independent Test**: Can be fully tested by viewing the event with the organizer token, tapping cancel, optionally entering a reason, and confirming. The event's cancelled state persists on reload.

**Acceptance Scenarios**:

1. **Given** an active event viewed by someone who has the organizer token, **When** the organizer taps "Cancel Event", **Then** a bottom sheet opens with a text area and a confirm button.
2. **Given** the cancel bottom sheet is open, **When** the organizer enters a cancellation reason and taps the confirm button, **Then** the event is marked as cancelled with the provided reason.
3. **Given** the cancel bottom sheet is open, **When** the organizer taps confirm without entering a reason, **Then** the event is marked as cancelled without a reason.
4. **Given** a cancelled event, **When** the organizer revisits the event page, **Then** the event remains cancelled (irreversible).
5. **Given** the cancel bottom sheet is open, **When** the organizer taps confirm and the API call fails, **Then** an error message is displayed in the bottom sheet, the sheet remains open, and the confirm button is re-enabled for retry.

---

### User Story 2 - Attendee Sees Cancelled Event (Priority: P1)

An attendee (or any visitor) opens the event detail page for a cancelled event. A prominent red banner is displayed at the top of the page, clearly communicating that the event has been cancelled. If the organizer provided a cancellation reason, it is shown within the banner. The RSVP buttons are hidden — no new RSVPs can be submitted.

**Why this priority**: Equal to P1 because the cancellation must be visible to attendees for the feature to deliver value. Without this, cancelling has no effect from the attendee's perspective.

**Independent Test**: Can be tested by viewing a cancelled event's detail page and verifying the banner appears, the reason is displayed (if provided), and RSVP buttons are hidden.

**Acceptance Scenarios**:

1. **Given** a cancelled event with a cancellation reason, **When** a visitor opens the event detail page, **Then** a prominent red banner is displayed showing that the event is cancelled along with the reason.
2. **Given** a cancelled event without a cancellation reason, **When** a visitor opens the event detail page, **Then** a prominent red banner is displayed showing that the event is cancelled, without a reason text.
3. **Given** a cancelled event, **When** a visitor opens the event detail page, **Then** the RSVP buttons are not visible.
4. **Given** a cancelled event, **When** a visitor opens the event detail page, **Then** all other event details (title, date, location, description) remain visible.

---

### Edge Cases

- What happens when the organizer tries to cancel an already cancelled event? The cancel button is not available on an already cancelled event.
- What happens to existing RSVPs when an event is cancelled? They are preserved as-is but no new RSVPs can be submitted.
- What happens when the event is both cancelled and expired? The auto-delete mechanism (feature 013) continues to apply normally — cancelled events are deleted on the same schedule as non-cancelled events.
- What happens when the cancellation API call fails (network error, server error)? The bottom sheet remains open, a visible error message is displayed within the sheet, and the confirm button is re-enabled so the organizer can retry.
- How are cancelled events displayed in the event list? Out of scope for this feature — the event list view is not affected.

## Requirements *(mandatory)*

### Functional Requirements

- **FR-001**: System MUST allow the organizer to cancel an event via the organizer view.
- **FR-002**: The cancellation interaction MUST use a bottom sheet pattern consistent with the existing RSVP/attend flow.
- **FR-003**: The bottom sheet MUST contain a text area for an optional cancellation reason and a confirm button.
- **FR-004**: Cancellation MUST be irreversible — once cancelled, there is no way to undo it.
- **FR-005**: System MUST store a cancelled flag and an optional cancellation reason for the event.
- **FR-006**: System MUST NOT allow new RSVPs for a cancelled event.
- **FR-007**: System MUST preserve existing RSVPs when an event is cancelled.
- **FR-008**: The event detail page MUST display a prominent red banner for cancelled events.
- **FR-009**: The banner MUST include the cancellation reason when one was provided.
- **FR-010**: The RSVP buttons MUST be hidden on a cancelled event's detail page.
- **FR-011**: All other event information MUST remain visible on a cancelled event's detail page.
- **FR-012**: The cancel button MUST NOT be shown on an already cancelled event.
- **FR-013**: There MUST be no push notifications, emails, or any active notification mechanism for cancellations.
- **FR-014**: If the cancellation API call fails, the bottom sheet MUST remain open, display an error message, and allow the organizer to retry.
- **FR-015**: Changes to the event list view for cancelled events are explicitly OUT OF SCOPE for this feature.

### Key Entities

- **Event** (extended): Gains a cancelled state (boolean) and an optional cancellation reason (free text). An event can transition from active to cancelled, but not back.

## Success Criteria *(mandatory)*

### Measurable Outcomes

- **SC-001**: Organizer can cancel an event in under 30 seconds (open bottom sheet, optionally type reason, confirm).
- **SC-002**: 100% of visitors to a cancelled event's detail page see the cancellation banner without scrolling.
- **SC-003**: 0% of cancelled events accept new RSVPs.
- **SC-004**: Existing RSVPs are fully preserved after cancellation (no data loss).

## Clarifications

### Session 2026-03-12

- Q: How should cancelled events appear in the event list view? → A: Out of scope for this feature — event list view is not affected.
- Q: What should happen when the cancellation API call fails? → A: Error message displayed in the bottom sheet, sheet remains open, confirm button re-enabled for retry.

## Assumptions

- The bottom sheet component pattern already exists from the RSVP/attend flow and can be reused.
- The cancellation reason has a maximum length of 2000 characters (consistent with the event description field).
- The cancellation reason is plain text (no formatting or markup).
