/** * Produce a full disaster-recovery bundle (db.dump + every blob + manifest.json) * to a local file. Same code path as the admin "Download full backup" button * (`createFullBackupTar`), minus the HTTP layer — for headless/ops use and for * rehearsing the restore runbook (docs/backup-restore-runbook.md). * * pnpm tsx scripts/create-full-backup.ts [outfile.tar] * * Defaults the output name to ./pn-crm-backup-.tar in the CWD. */ import 'dotenv/config'; import { copyFile } from 'node:fs/promises'; import path from 'node:path'; import { createFullBackupTar } from '@/lib/services/backup-export.service'; import { logger } from '@/lib/logger'; async function main(): Promise { const { tarPath, filename, manifest, cleanup } = await createFullBackupTar(); try { const dest = path.resolve(process.argv[2] ?? filename); await copyFile(tarPath, dest); logger.info( { dest, storageBackend: manifest.storageBackend, dbDumpBytes: manifest.database.sizeBytes, blobs: manifest.counts.blobs, blobBytes: manifest.counts.blobBytes, skipped: manifest.counts.skipped, }, 'Full backup written', ); if (manifest.skipped.length) { logger.warn({ skipped: manifest.skipped }, 'Some referenced blobs were missing in storage'); } } finally { await cleanup(); } } main() .then(() => process.stdout.write('', () => process.exit(0))) .catch((err) => { logger.error({ err }, 'Full backup failed'); process.stderr.write('', () => process.exit(1)); });