Backup-Operations-Log + EBUSY-Fix beim Restore
Backup-Seite zeigt zwei neue Log-Panels: links Backup-Erstellung, rechts Backup-Wiederherstellung. Jeder Eintrag mit ✓/✗-Status, Summary, Timestamp + User. Klick öffnet Modal mit vollständigem Verlauf – alle console.log/error/warn/info-Zeilen werden während der Operation in einen Puffer mitgefangen und im fullLog-Feld persistiert. Auto-Refresh alle 5s. Persistenz: neue Tabelle BackupLog mit Migration 20260519100000_backup_log (CREATE TABLE IF NOT EXISTS für Re-Deploys auf DBs mit Vorab-db-push). fullLog auf 1 MB gecappt. Endpoints (settings:update): - GET /api/settings/backup-logs?operation=CREATE|RESTORE&limit=50 - GET /api/settings/backup-logs/:id EBUSY-Fix: Der neue Log-Verlauf hat sofort einen alten Bug sichtbar gemacht. backup.service.restoreBackup rief deleteDirectory(UPLOADS_DIR) auf, dessen finales rmdirSync auf /app/uploads ein EBUSY warf – das Verzeichnis ist im Container ein Bind-Mount und lässt sich nicht aushängen. Fix: neuer Helper emptyDirectory() löscht nur die Inhalte, das Verzeichnis bleibt stehen. Live-verifiziert: 4867 Datensätze + 1 Datei in 13.2s wiederhergestellt; Log-Modal zeigt den vollständigen Verlauf. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
-- BackupLog: persistierte Historie aller Backup-/Restore-Vorgänge mit
|
||||
-- Status + Volltext-Log. UI zeigt in zwei Listen (je CREATE und RESTORE).
|
||||
--
|
||||
-- IF NOT EXISTS damit Re-Deploys auf bestehende DBs nicht crashen, falls
|
||||
-- jemand vorher manuell `prisma db push` gefahren hat.
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `BackupLog` (
|
||||
`id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`operation` ENUM('CREATE', 'RESTORE') NOT NULL,
|
||||
`backupName` VARCHAR(191) NULL,
|
||||
`success` BOOLEAN NOT NULL,
|
||||
`durationMs` INTEGER NOT NULL DEFAULT 0,
|
||||
`summary` TEXT NOT NULL,
|
||||
`fullLog` LONGTEXT NOT NULL,
|
||||
`userId` INTEGER NULL,
|
||||
`userEmail` VARCHAR(191) NULL,
|
||||
`ipAddress` VARCHAR(191) NULL,
|
||||
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
INDEX `BackupLog_operation_createdAt_idx`(`operation`, `createdAt`),
|
||||
INDEX `BackupLog_createdAt_idx`(`createdAt`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
@@ -1146,6 +1146,33 @@ enum SecuritySeverity {
|
||||
CRITICAL // Threshold überschritten (>10 failed login/h, >5 403/min)
|
||||
}
|
||||
|
||||
enum BackupOperation {
|
||||
CREATE
|
||||
RESTORE
|
||||
}
|
||||
|
||||
// Persistiertes Log für Backup-Vorgänge.
|
||||
// `summary` ist die einzeilige Anzeige in der Liste (z.B. "4859 Datensätze
|
||||
// wiederhergestellt"), `fullLog` der detaillierte Output inkl. Stack-Trace
|
||||
// für das Modal. Wird beim Build/Restore in `backup.controller.ts`
|
||||
// geschrieben.
|
||||
model BackupLog {
|
||||
id Int @id @default(autoincrement())
|
||||
operation BackupOperation
|
||||
backupName String?
|
||||
success Boolean
|
||||
durationMs Int @default(0)
|
||||
summary String @db.Text
|
||||
fullLog String @db.LongText
|
||||
userId Int?
|
||||
userEmail String?
|
||||
ipAddress String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([operation, createdAt])
|
||||
@@index([createdAt])
|
||||
}
|
||||
|
||||
model SecurityEvent {
|
||||
id Int @id @default(autoincrement())
|
||||
type SecurityEventType
|
||||
|
||||
Reference in New Issue
Block a user