- Add audit_logs table with categories, severities, and indexes - Create AuditLogService and AuditLogRepository - Add REST API endpoints for viewing and exporting logs - Wire audit logging into auth, vehicles, admin, and backup features - Add desktop AdminLogsPage with filters and CSV export - Add mobile AdminLogsMobileScreen with card layout - Implement 90-day retention cleanup job - Remove old AuditLogPanel from AdminCatalogPage Security fixes: - Escape LIKE special characters to prevent pattern injection - Limit CSV export to 5000 records to prevent memory exhaustion - Add truncation warning headers for large exports 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Backup Feature
Complete backup and restore system for MotoVaultPro.
Overview
This feature provides:
- Manual and scheduled backups of the PostgreSQL database and document files
- Multiple backup schedules with individual retention policies
- Restore functionality with safety backup creation
- Email notifications on backup success/failure
Architecture
backup/
api/ # HTTP endpoints
backup.routes.ts # Route definitions
backup.controller.ts # Request handlers
backup.validation.ts # Zod schemas
domain/ # Business logic
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 # Tiered retention enforcement
backup-classification.service.ts # Backup category classification
data/ # Data access
backup.repository.ts # Database queries
jobs/ # Scheduled jobs
backup-scheduled.job.ts # Scheduled backup execution
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
All endpoints require admin authentication.
Backup Operations
| Method | Path | Description |
|---|---|---|
| GET | /api/admin/backups |
List backups with pagination |
| POST | /api/admin/backups |
Create manual backup |
| GET | /api/admin/backups/:id |
Get backup details |
| GET | /api/admin/backups/:id/download |
Download backup file |
| DELETE | /api/admin/backups/:id |
Delete backup |
| POST | /api/admin/backups/upload |
Upload backup file |
Restore Operations
| Method | Path | Description |
|---|---|---|
| POST | /api/admin/backups/:id/restore/preview |
Preview restore |
| POST | /api/admin/backups/:id/restore |
Execute restore |
| GET | /api/admin/backups/restore/status |
Get restore status |
Schedule Operations
| Method | Path | Description |
|---|---|---|
| GET | /api/admin/backups/schedules |
List schedules |
| POST | /api/admin/backups/schedules |
Create schedule |
| PUT | /api/admin/backups/schedules/:id |
Update schedule |
| DELETE | /api/admin/backups/schedules/:id |
Delete schedule |
| PATCH | /api/admin/backups/schedules/:id/toggle |
Enable/disable |
Settings
| Method | Path | Description |
|---|---|---|
| GET | /api/admin/backups/settings |
Get settings |
| PUT | /api/admin/backups/settings |
Update settings |
Backup Archive Format
Backups are .tar.gz archives containing:
motovaultpro_backup_YYYYMMDD_HHMMSS.tar.gz
manifest.json # Backup metadata
database/
motovaultpro.sql.gz # Compressed PostgreSQL dump
documents/
<user_id>/ # User document files
Schedule Frequencies
| Frequency | Cron | Default Time |
|---|---|---|
| hourly | 0 * * * * |
Every hour |
| daily | 0 3 * * * |
3:00 AM |
| weekly | 0 3 * * 0 |
Sunday 3:00 AM |
| monthly | 0 3 1 * * |
1st of month 3:00 AM |
Database Tables
backup_schedules- Schedule configurationsbackup_history- Backup operation recordsbackup_settings- Global settings
Storage
Backups are stored in /app/data/backups/ (mapped to ./data/backups/ on host).
Integration
Scheduler
Jobs are registered in backend/src/core/scheduler/index.ts:
- Backup check: Every minute
- Retention cleanup: Daily at 4 AM (also runs after each scheduled backup)
Distributed Locking
Scheduled backups use Redis distributed locking to prevent duplicate backups when multiple backend containers are running (blue-green deployments).
Lock behavior:
- Lock key:
backup:schedule:{schedule_id} - Lock TTL: 5 minutes (auto-release if container crashes)
- Only one container creates the backup; others skip
Retention cleanup (tiered):
- Runs immediately after each successful scheduled backup
- 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_atis 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
Routes are registered in backend/src/features/admin/api/admin.routes.ts.