feat(backup): формат бэкапа v2 — audit/уведомления/баны, counts и одноразовый тикет

Валидация и нормализация restore вынесены из server.js в backup-restore.js,
покрыты юнит-тестами backup.selftest.js (30+ проверок, без стенда).

В бэкап добавлены audit_log, notifications, notification_reads, banned_ips,
счётчики counts, метаданные приложения и версия формата (принимаются 1..2).
Тикет бэкапа стал одноразовым: файл удаляется сразу после отдачи,
uploadBackup фильтрует расширения. sessions в бэкап не входит намеренно.

sweepOrphanedUploads учитывает аватары, обложки, оригиналы фото и photo_jobs —
иначе restore сносил файлы сразу после восстановления.
storage.getStream при STORAGE_LOCAL_FALLBACK читает локальный файл, а не S3.
This commit is contained in:
dev
2026-10-04 01:36:58 +03:00
parent 32aabe9a80
commit 76d36e5c35
5 changed files with 698 additions and 396 deletions
+4
View File
@@ -250,6 +250,10 @@ function createStorage(options = {}) {
if (!fp || !fs.existsSync(fp)) return null;
return { stream: fs.createReadStream(fp), contentLength: fs.statSync(fp).size, contentType: mimeFor(key) };
}
if (localFallback && localExists(key)) {
const fp = localFile(key);
return { stream: fs.createReadStream(fp), contentLength: fs.statSync(fp).size, contentType: mimeFor(key) };
}
try {
const out = await client.send(new GetObjectCommand({ Bucket: bucket, Key: objKey }));
return { stream: out.Body, contentLength: out.ContentLength || 0, contentType: out.ContentType || mimeFor(key) };