fix: Implement tiered backup retention classification (refs #6)
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 6m15s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 28s
Deploy to Staging / Verify Staging (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 6s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
All checks were successful
Deploy to Staging / Build Images (pull_request) Successful in 6m15s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 28s
Deploy to Staging / Verify Staging (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 6s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
Replace per-schedule count-based retention with unified tiered classification. Backups are now classified by timestamp into categories (hourly/daily/weekly/monthly) and are only deleted when they exceed ALL applicable category quotas. Changes: - Add backup-classification.service.ts for timestamp-based classification - Rewrite backup-retention.service.ts with tiered logic - Add categories and expires_at columns to backup_history - Add Expires column to desktop and mobile backup UI - Add unit tests for classification logic (22 tests) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -19,11 +19,12 @@ backup/
|
||||
backup.controller.ts # Request handlers
|
||||
backup.validation.ts # Zod schemas
|
||||
domain/ # Business logic
|
||||
backup.types.ts # TypeScript types
|
||||
backup.types.ts # TypeScript types and constants
|
||||
backup.service.ts # Core backup operations
|
||||
backup-archive.service.ts # Archive creation
|
||||
backup-restore.service.ts # Restore operations
|
||||
backup-retention.service.ts # Retention enforcement
|
||||
backup-archive.service.ts # Archive creation
|
||||
backup-restore.service.ts # Restore operations
|
||||
backup-retention.service.ts # Tiered retention enforcement
|
||||
backup-classification.service.ts # Backup category classification
|
||||
data/ # Data access
|
||||
backup.repository.ts # Database queries
|
||||
jobs/ # Scheduled jobs
|
||||
@@ -31,6 +32,10 @@ backup/
|
||||
backup-cleanup.job.ts # Retention cleanup
|
||||
migrations/ # Database schema
|
||||
001_create_backup_tables.sql
|
||||
002_add_retention_categories.sql # Tiered retention columns
|
||||
tests/ # Test files
|
||||
unit/
|
||||
backup-classification.service.test.ts # Classification tests
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
@@ -122,11 +127,45 @@ Scheduled backups use Redis distributed locking to prevent duplicate backups whe
|
||||
- Lock TTL: 5 minutes (auto-release if container crashes)
|
||||
- Only one container creates the backup; others skip
|
||||
|
||||
**Retention cleanup:**
|
||||
**Retention cleanup (tiered):**
|
||||
- Runs immediately after each successful scheduled backup
|
||||
- Deletes backups exceeding the schedule's retention count
|
||||
- Uses tiered classification: each backup can belong to multiple categories
|
||||
- A backup is only deleted when it exceeds ALL applicable category quotas
|
||||
- Also runs globally at 4 AM daily as a safety net
|
||||
|
||||
## Tiered Retention System
|
||||
|
||||
Backups are classified by their creation timestamp into categories:
|
||||
|
||||
| Category | Qualification | Retention Count |
|
||||
|----------|--------------|-----------------|
|
||||
| hourly | All backups | 8 |
|
||||
| daily | First backup at midnight UTC | 7 |
|
||||
| weekly | First backup on Sunday at midnight UTC | 4 |
|
||||
| monthly | First backup on 1st of month at midnight UTC | 12 |
|
||||
|
||||
**Multi-category classification:**
|
||||
- A backup can belong to multiple categories simultaneously
|
||||
- Example: Backup at midnight on Sunday, January 1st qualifies as: hourly + daily + weekly + monthly
|
||||
|
||||
**Retention logic:**
|
||||
```
|
||||
For each category (hourly, daily, weekly, monthly):
|
||||
1. Get all backups with this category
|
||||
2. Keep top N (sorted by started_at DESC)
|
||||
3. Add to protected set
|
||||
|
||||
A backup is deleted ONLY if it's NOT in the protected set
|
||||
(i.e., exceeds quota for ALL its categories)
|
||||
```
|
||||
|
||||
**Expiration calculation:**
|
||||
- Each backup's `expires_at` is calculated based on its longest retention period
|
||||
- Monthly backup: 12 months from creation
|
||||
- Weekly-only backup: 4 weeks from creation
|
||||
- Daily-only backup: 7 days from creation
|
||||
- Hourly-only backup: 8 hours from creation
|
||||
|
||||
See `backend/src/core/scheduler/README.md` for the distributed locking pattern.
|
||||
|
||||
### Admin Routes
|
||||
|
||||
Reference in New Issue
Block a user