# Feature Specification: Auto-Delete Expired Events **Feature Branch**: `013-auto-delete-expired` **Created**: 2026-03-09 **Status**: Draft **Input**: User description: "Delete events automatically after they expired" ## User Scenarios & Testing *(mandatory)* ### User Story 1 - Automatic Cleanup of Expired Events (Priority: P1) As a self-hoster, I want expired events to be automatically deleted from the database so that personal data is removed without manual intervention and storage stays clean. A scheduled background job periodically checks all events. Any event whose `expiryDate` is in the past gets permanently deleted — including all associated data (RSVPs, tokens). No user action is required; the system handles this autonomously. **Why this priority**: This is the core and only feature — automated, hands-off cleanup of expired events. It directly supports the privacy promise of fete. **Independent Test**: Can be fully tested by creating events with past expiry dates, triggering the cleanup job, and verifying the events are gone from the database. **Acceptance Scenarios**: 1. **Given** an event with an `expiryDate` in the past, **When** the scheduled cleanup job runs, **Then** the event and all its associated data (RSVPs, tokens) are permanently deleted. 2. **Given** an event with an `expiryDate` in the future, **When** the scheduled cleanup job runs, **Then** the event remains untouched. 3. **Given** multiple expired events exist, **When** the cleanup job runs, **Then** all expired events are deleted in a single run. 4. **Given** no expired events exist, **When** the cleanup job runs, **Then** nothing is deleted and the job completes without error. --- ### Edge Cases - What happens if the cleanup job fails mid-deletion (e.g., database connection lost)? Events that were not yet deleted remain and will be picked up in the next run. No partial state. - What happens if the server was offline for an extended period? On the next run, all accumulated expired events are deleted — no special catch-up logic needed. - What happens if an organizer is viewing their event page while it gets deleted? The page shows a "not found" state on next interaction. This is acceptable because the event has expired. ## Requirements *(mandatory)* ### Functional Requirements - **FR-001**: System MUST automatically delete events whose `expiryDate` is before the current date/time. - **FR-002**: When an event is deleted, all associated data (RSVPs, organizer tokens, event tokens) MUST be deleted as well (cascade delete). - **FR-003**: The cleanup job MUST run on a recurring schedule (default: once daily). - **FR-004**: The cleanup job MUST be idempotent — running it multiple times produces the same result. - **FR-005**: The cleanup job MUST log how many events were deleted per run. - **FR-006**: Events that have not yet expired MUST NOT be affected by the cleanup job. ### Key Entities - **Event**: The primary entity being cleaned up. Has an `expiryDate` field that determines when it becomes eligible for deletion. - **RSVP**: Associated guest responses linked to an event. Deleted when the parent event is deleted. ## Success Criteria *(mandatory)* ### Measurable Outcomes - **SC-001**: Expired events are deleted within 24 hours of their expiry date without manual intervention. - **SC-002**: Zero data residue — when an event is deleted, no orphaned RSVPs or tokens remain in the system. - **SC-003**: The cleanup process completes without errors under normal operating conditions. - **SC-004**: Non-expired events are never affected by the cleanup process. ## Clarifications ### Session 2026-03-09 - Q: How should deletion be implemented — application code (JPA) or direct database query? → A: Direct database query. A single native `DELETE FROM events WHERE expiry_date < CURRENT_DATE` is sufficient. The existing `ON DELETE CASCADE` on the RSVPs foreign key ensures associated data is removed automatically. The existing `idx_events_expiry_date` index ensures the query is performant. ## Assumptions - The `expiryDate` field already exists on events and is auto-set to `eventDate + 7 days` (implemented in the previous feature). - Cascade deletion of associated data (RSVPs, tokens) is handled at the database level via foreign key constraints (`ON DELETE CASCADE` on `fk_rsvps_event_id`, verified in migration `003-create-rsvps-table.xml`). - The daily schedule is sufficient — there is no requirement for near-real-time deletion. - No "grace period" or "soft delete" is needed — events are permanently removed once expired.