Files
opencrm/backend/src/routes/appSetting.routes.ts
T
duffyduckandClaude Opus 4.7 37df8c0c4a 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>
2026-05-19 11:53:04 +02:00

133 lines
3.2 KiB
TypeScript

import { Router } from 'express';
import multer from 'multer';
import * as appSettingController from '../controllers/appSetting.controller.js';
import * as backupController from '../controllers/backup.controller.js';
import * as rateLimitAdminController from '../controllers/rateLimitAdmin.controller.js';
import { authenticate, requirePermission } from '../middleware/auth.js';
// Multer für Backup-Upload (in Memory speichern)
const backupUpload = multer({
storage: multer.memoryStorage(),
limits: { fileSize: 500 * 1024 * 1024 }, // 500MB max
fileFilter: (req, file, cb) => {
if (file.mimetype === 'application/zip' || file.originalname.endsWith('.zip')) {
cb(null, true);
} else {
cb(new Error('Nur ZIP-Dateien sind erlaubt'));
}
},
});
const router = Router();
// Öffentliche Einstellungen (für alle authentifizierten Benutzer, inkl. Kunden)
router.get('/public', authenticate, appSettingController.getPublicSettings);
// Alle Einstellungen (nur Admin)
router.get('/', authenticate, requirePermission('settings:read'), appSettingController.getAllSettings);
// Einzelne Einstellung aktualisieren (nur Admin)
router.put(
'/:key',
authenticate,
requirePermission('settings:update'),
appSettingController.updateSetting
);
// Mehrere Einstellungen aktualisieren (nur Admin)
router.put(
'/',
authenticate,
requirePermission('settings:update'),
appSettingController.updateSettings
);
// ==================== BACKUP & RESTORE ====================
// Liste aller Backups
router.get(
'/backups',
authenticate,
requirePermission('settings:update'),
backupController.listBackups
);
// Neues Backup erstellen
router.post(
'/backup',
authenticate,
requirePermission('settings:update'),
backupController.createBackup
);
// Backup wiederherstellen
router.post(
'/backup/:name/restore',
authenticate,
requirePermission('settings:update'),
backupController.restoreBackup
);
// Backup löschen
router.delete(
'/backup/:name',
authenticate,
requirePermission('settings:update'),
backupController.deleteBackup
);
// Backup als ZIP herunterladen
router.get(
'/backup/:name/download',
authenticate,
requirePermission('settings:update'),
backupController.downloadBackup
);
// Backup-ZIP hochladen
router.post(
'/backup/upload',
authenticate,
requirePermission('settings:update'),
backupUpload.single('backup'),
backupController.uploadBackup
);
// Werkseinstellungen (alles löschen)
router.post(
'/factory-reset',
authenticate,
requirePermission('settings:update'),
backupController.factoryReset
);
// Backup-Operations-Log: Liste (ohne fullLog) + Detail
router.get(
'/backup-logs',
authenticate,
requirePermission('settings:update'),
backupController.listBackupLogs
);
router.get(
'/backup-logs/:id',
authenticate,
requirePermission('settings:update'),
backupController.getBackupLogDetail
);
// Rate-Limit-Verwaltung (Admin)
router.get(
'/rate-limits/active',
authenticate,
requirePermission('settings:read'),
rateLimitAdminController.getActiveRateLimits,
);
router.post(
'/rate-limits/reset',
authenticate,
requirePermission('settings:update'),
rateLimitAdminController.resetRateLimit,
);
export default router;