Auto-delete expired events via daily scheduled cleanup job
All checks were successful
CI / backend-test (push) Successful in 58s
CI / frontend-test (push) Successful in 23s
CI / frontend-e2e (push) Successful in 1m10s
CI / build-and-publish (push) Has been skipped

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>
This commit is contained in:
2026-03-09 21:58:35 +01:00
parent 2a6a658df9
commit 4bfaee685c
14 changed files with 499 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
# 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.