Adds a Spring @Scheduled job (daily at 03:00) that deletes all events whose expiry_date is before CURRENT_DATE using a native SQL DELETE. RSVPs are cascade-deleted via the existing FK constraint. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4.5 KiB
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:
- Given an event with an
expiryDatein the past, When the scheduled cleanup job runs, Then the event and all its associated data (RSVPs, tokens) are permanently deleted. - Given an event with an
expiryDatein the future, When the scheduled cleanup job runs, Then the event remains untouched. - Given multiple expired events exist, When the cleanup job runs, Then all expired events are deleted in a single run.
- 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
expiryDateis 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
expiryDatefield 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_DATEis sufficient. The existingON DELETE CASCADEon the RSVPs foreign key ensures associated data is removed automatically. The existingidx_events_expiry_dateindex ensures the query is performant.
Assumptions
- The
expiryDatefield already exists on events and is auto-set toeventDate + 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 CASCADEonfk_rsvps_event_id, verified in migration003-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.