AI Implementation feature(918): Admin Area System: Database Backup/Restore and Danger Zone 1.01 (#63)
This commit was merged in pull request #63.
This commit is contained in:
@@ -4,7 +4,7 @@ title: Admin System Endpoints
|
||||
description: Admin-only destructive System operations: backup download, restore validate/commit, re-authenticated confirmation tokens, reset-scores, and wipe-challenges.
|
||||
resource: backend/src/modules/admin/system/admin-system.controller.ts
|
||||
tags: [api, admin, system, backup, restore, danger-zone, confirmation-tokens]
|
||||
timestamp: 2026-07-23T12:04:50Z
|
||||
timestamp: 2026-07-23T13:27:25Z
|
||||
---
|
||||
|
||||
# Overview
|
||||
@@ -130,6 +130,31 @@ Flow:
|
||||
database + uploads are swapped atomically via
|
||||
`FilesystemTransactionService.stageSwap()` (with a `restore-backup`
|
||||
rollback handle).
|
||||
|
||||
The offline clone rebuild begins by capturing the exact SQL of the
|
||||
deployment-wide `trg_user_last_admin_update` and
|
||||
`trg_user_last_admin_delete` triggers from `sqlite_master`,
|
||||
dropping them in the candidate database, then clearing the
|
||||
application tables and re-inserting the archived rows. SQLite
|
||||
triggers fire regardless of `PRAGMA foreign_keys = OFF`, so
|
||||
clearing the sole admin row before the archive's admin is inserted
|
||||
would otherwise abort the rebuild with `LAST_ADMIN`. The suspension
|
||||
is confined to the offline candidate file. Before the candidate is
|
||||
eligible to swap, the rebuild:
|
||||
|
||||
- asserts at least one `user.role = 'admin'` row exists in the
|
||||
rebuilt data (zero-admin archives fail with
|
||||
`SYSTEM_RESTORE_ROLLED_BACK` so the live system never lands in a
|
||||
no-admin state, even momentarily),
|
||||
- re-creates both captured triggers via `db.exec(sql)` so the
|
||||
`LAST_ADMIN` invariant is restored on the candidate, and
|
||||
- re-enables `PRAGMA foreign_keys` and runs `PRAGMA foreign_key_check`.
|
||||
|
||||
On any rebuild, integrity, swap, or verification error the capture
|
||||
loop is wrapped in a `try/catch` that best-effort re-creates any
|
||||
missing trigger before rethrowing, so a rolled-back candidate never
|
||||
leaks to disk missing the `LAST_ADMIN` safety net. The original
|
||||
failure is then rethrown unchanged.
|
||||
4. On any failure the swap is rolled back, the staged tree is removed,
|
||||
and the error is mapped to `SYSTEM_RESTORE_ROLLED_BACK` (500).
|
||||
5. On success, every refresh token belonging to the current admin is
|
||||
@@ -288,4 +313,4 @@ curl -sS ... -d '{"operation":"reset-scores","token":"<raw>"}'
|
||||
| Front-end route | `frontend/src/app/app.routes.ts` (admin child `system`) |
|
||||
| Cross-store invalidation | `frontend/src/app/core/services/system-data-change.service.ts` |
|
||||
| Forced logout helper | `frontend/src/app/core/services/auth.service.ts` (`forceServerInvalidation`) |
|
||||
| Tests | `tests/backend/admin-system-authorization.spec.ts`, `admin-system-backup.spec.ts`, `admin-system-confirmation-token.spec.ts`, `admin-system-danger.spec.ts`, `admin-system-restore-validation.spec.ts`; `tests/frontend/admin-system.pure.spec.ts` |
|
||||
| Tests | `tests/backend/admin-system-authorization.spec.ts`, `admin-system-backup.spec.ts`, `admin-system-confirmation-token.spec.ts`, `admin-system-danger.spec.ts`, `admin-system-restore-validation.spec.ts`, `admin-system-restore-commit.spec.ts`; `tests/frontend/admin-system.pure.spec.ts` |
|
||||
|
||||
Reference in New Issue
Block a user