This document describes the automatic cleanup feature that removes inactive shopping lists after a configurable retention period.
The system automatically deletes shopping lists that haven't been modified for a specified period (default: 30 days). This helps keep the database clean and prevents accumulation of abandoned lists.
The CleanupService class handles the automatic cleanup logic:
- Location:
backend/src/main/kotlin/com/shoppinglist/service/CleanupService.kt - Runs every: 24 hours
- Default retention: 30 days
- Configurable via:
LIST_RETENTION_DAYSenvironment variable
startCleanupScheduler(): Starts the background cleanup jobperformCleanup(): Performs the actual cleanup and returns count of deleted listsgetListExpirationDate(listId): Returns when a specific list will expiregetRetentionDays(): Returns the configured retention period
- ShoppingList model: Added optional
expiresAtfield - ListRepository: Added
getListWithExpiration()method - API Response: List endpoints now include expiration information
# Set retention period (in days)
LIST_RETENTION_DAYS=30The environment variable is configured in:
docker-compose.yml(development)docker-compose.prod.yml(production).env.prod(production environment)
Displays a visual indicator when a list is approaching expiration:
- Location:
frontend/src/components/ExpirationIndicator.tsx - Shows when: List expires within 7 days
- Color coding:
- 🔴 Red: Expires today or already expired
- 🟠 Orange: Expires within 1-3 days
- 🟡 Yellow: Expires within 4-7 days
New translation keys added for expiration messages:
{
"messages": {
"listExpiredToday": "This list expires today",
"listExpiresTomorrow": "This list expires tomorrow",
"listExpiresInDays": "This list expires in {days} days"
}
}Updated translation function to support parameter interpolation:
t('messages.listExpiresInDays', { days: 5 })
// Returns: "This list expires in 5 days"- Location:
backend/src/test/kotlin/com/shoppinglist/service/CleanupServiceTest.kt - Coverage: All cleanup scenarios including edge cases
- Database: Uses PostgreSQL with Testcontainers
- Location:
frontend/src/components/__tests__/ExpirationIndicator.test.tsx - Coverage: All display states and styling variations
# Set retention to 7 days
export LIST_RETENTION_DAYS=7
# Or in docker-compose.yml
environment:
LIST_RETENTION_DAYS: 7// In application code
val cleanupService = CleanupService()
val deletedCount = cleanupService.performCleanup()
println("Deleted $deletedCount expired lists")// Get expiration date for a specific list
val expirationDate = cleanupService.getListExpirationDate(listId)
if (expirationDate != null) {
println("List expires at: $expirationDate")
}The cleanup service logs its activities:
INFO - Starting cleanup scheduler with retention period of 30 days
INFO - Performing cleanup for lists older than 2024-09-26T10:30:00Z
INFO - Found 5 expired lists to clean up
INFO - Cleaned up 5 expired lists
The cleanup service status can be monitored through application health endpoints.
Existing lists will have their expiration calculated based on their lastModified timestamp plus the retention period.
The expiresAt field is optional, so existing API clients will continue to work without modification.
- Lists are permanently deleted (no soft delete)
- All associated items are also deleted (CASCADE)
- No user notification is sent before deletion
- Consider implementing user notifications for production use
- Cleanup runs once per day during low-traffic hours
- Database queries are optimized with proper indexing
- Minimal impact on application performance
- Cleanup duration scales with number of expired lists
- User Notifications: Email users before list expiration
- Configurable Schedule: Allow custom cleanup intervals
- Soft Delete: Implement recovery period before permanent deletion
- Analytics: Track cleanup statistics and trends
- Admin Interface: Manual cleanup controls for administrators