FC-3h + FC-3k: backup first-class + admin destructive actions #10

Merged
bvandeusen merged 0 commits from dev into main 2026-05-25 01:41:53 -04:00
bvandeusen commented 2026-05-25 01:41:30 -04:00 (Migrated from git.fabledsword.com)

Cuts together two roadmap stages built up on dev since v26.05.24.3 (FC-3i).

FC-3h — Backup as first-class service

Promotes backup out of the migration tooling into a permanent FC feature, split into independent DB and image backup components.

Backend:

  • BackupRun model + alembic 0017 (composite + partial-tag indexes)
  • 4 backup_* knobs on import_settings + alembic 0018 (nightly-enabled, hour, keep-N per kind)
  • backend/app/services/backup_service.py — pg_dump (DB) + tar+zstd (images) + restore + unlink
  • 6 Celery tasks on maintenance queue: backup_db_task, backup_images_task, restore_db_task, restore_images_task, prune_backups, backup_db_nightly (all with autoretry + soft/hard time limits)
  • Beat: hourly nightly tick (settings-gated, default OFF) + daily prune
  • /api/system/backup/* blueprint (9 endpoints) with typed-token confirmation for restore + delete
  • Retired backup + rollback from migrate.py _VALID_KINDS; deleted services/migrators/backup.py + rollback.py

Frontend:

  • Pinia useBackupStore
  • BackupConfirmModal.vue typed-token modal
  • BackupCard.vue + BackupRunsTable.vue (combined card, DB + Images sub-sections)
  • Slotted into MaintenancePanel.vue above LegacyMigrationCard

FC-3k — Admin destructive actions

Five first-class admin actions, surviving FC-3j: delete-artist-cascade, prune-unused-tags, delete-single-tag, merge-tag, bulk-delete-images.

Backend:

  • cleanup_service.py — projections + mutations + file-unlink primitive (lifted from migrators/cleanup.py)
  • Celery tasks on maintenance queue: delete_artist_cascade_task (30/40 min limits), bulk_delete_images_task (15/20 min)
  • 6 endpoints under /api/admin/* with graduated confirmation friction (Tier A single-click after preview / Tier B yes/no with count / Tier C typed-token)
  • Reuses TagService.merge() as-is for tag-merge endpoint

Frontend:

  • BackupConfirmModal renamed/relocated to modal/DestructiveConfirmModal.vue (added tier + projectedCounts props; BackupCard wire-compatible)
  • Pinia useAdminStore with pollTaskUntilDone tailing FC-3i's activity dashboard
  • ArtistDangerZone.vue slotted at bottom of ArtistView
  • BulkEditorPanel.vue "Delete selected" with browser-side sha8 sha256 token matching server
  • TagCard.vue dots-menu with Merge picker + Tier-B delete modal
  • TagMaintenanceCard.vue (prune-unused preview-then-commit) slotted into MaintenancePanel

Test coverage

  • FC-3h: test_backup_service.py, test_tasks_backup.py, test_api_system_backup.py
  • FC-3k: test_cleanup_service.py, test_tasks_admin.py, test_api_admin.py
  • All CI-green on dev

Inheritance

Both stages inherit FC-3i's task_run lifecycle (recovery sweep, daily prune, soft/hard time limits, duration tracking) for the long-running Celery tasks. No new lifecycle plumbing required.

What's not in this PR

  • IR migration verification (operator-driven manual check before FC-3j)
  • FC-3j (remove migration tooling) — depends on verification
  • FC-3g extension verification

🤖 Generated with Claude Code

Cuts together two roadmap stages built up on dev since v26.05.24.3 (FC-3i). ## FC-3h — Backup as first-class service Promotes backup out of the migration tooling into a permanent FC feature, split into independent DB and image backup components. **Backend:** - `BackupRun` model + alembic 0017 (composite + partial-tag indexes) - 4 `backup_*` knobs on `import_settings` + alembic 0018 (nightly-enabled, hour, keep-N per kind) - `backend/app/services/backup_service.py` — pg_dump (DB) + tar+zstd (images) + restore + unlink - 6 Celery tasks on `maintenance` queue: `backup_db_task`, `backup_images_task`, `restore_db_task`, `restore_images_task`, `prune_backups`, `backup_db_nightly` (all with autoretry + soft/hard time limits) - Beat: hourly nightly tick (settings-gated, default OFF) + daily prune - `/api/system/backup/*` blueprint (9 endpoints) with typed-token confirmation for restore + delete - Retired `backup` + `rollback` from `migrate.py` `_VALID_KINDS`; deleted `services/migrators/backup.py` + `rollback.py` **Frontend:** - Pinia `useBackupStore` - `BackupConfirmModal.vue` typed-token modal - `BackupCard.vue` + `BackupRunsTable.vue` (combined card, DB + Images sub-sections) - Slotted into `MaintenancePanel.vue` above LegacyMigrationCard ## FC-3k — Admin destructive actions Five first-class admin actions, surviving FC-3j: delete-artist-cascade, prune-unused-tags, delete-single-tag, merge-tag, bulk-delete-images. **Backend:** - `cleanup_service.py` — projections + mutations + file-unlink primitive (lifted from `migrators/cleanup.py`) - Celery tasks on `maintenance` queue: `delete_artist_cascade_task` (30/40 min limits), `bulk_delete_images_task` (15/20 min) - 6 endpoints under `/api/admin/*` with graduated confirmation friction (Tier A single-click after preview / Tier B yes/no with count / Tier C typed-token) - Reuses `TagService.merge()` as-is for tag-merge endpoint **Frontend:** - `BackupConfirmModal` renamed/relocated to `modal/DestructiveConfirmModal.vue` (added `tier` + `projectedCounts` props; BackupCard wire-compatible) - Pinia `useAdminStore` with `pollTaskUntilDone` tailing FC-3i's activity dashboard - `ArtistDangerZone.vue` slotted at bottom of `ArtistView` - `BulkEditorPanel.vue` "Delete selected" with browser-side sha8 sha256 token matching server - `TagCard.vue` dots-menu with Merge picker + Tier-B delete modal - `TagMaintenanceCard.vue` (prune-unused preview-then-commit) slotted into `MaintenancePanel` ## Test coverage - FC-3h: `test_backup_service.py`, `test_tasks_backup.py`, `test_api_system_backup.py` - FC-3k: `test_cleanup_service.py`, `test_tasks_admin.py`, `test_api_admin.py` - All CI-green on dev ## Inheritance Both stages inherit FC-3i's `task_run` lifecycle (recovery sweep, daily prune, soft/hard time limits, duration tracking) for the long-running Celery tasks. No new lifecycle plumbing required. ## What's not in this PR - IR migration verification (operator-driven manual check before FC-3j) - FC-3j (remove migration tooling) — depends on verification - FC-3g extension verification 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bvandeusen/FabledCurator#10