115 lines
4.5 KiB
TypeScript
115 lines
4.5 KiB
TypeScript
/**
|
|
* Datenbank-Backup Script
|
|
*
|
|
* Exportiert alle Daten als JSON-Dateien für die Wiederherstellung nach Migrationen.
|
|
*
|
|
* Verwendung:
|
|
* npx ts-node prisma/backup-data.ts
|
|
*
|
|
* Erstellt einen Ordner 'backups/YYYY-MM-DD_HH-mm-ss/' mit JSON-Dateien pro Tabelle.
|
|
*/
|
|
|
|
import { PrismaClient } from '@prisma/client';
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
async function main() {
|
|
// Backup-Ordner mit Zeitstempel erstellen
|
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
const backupDir = path.join(__dirname, 'backups', timestamp);
|
|
|
|
if (!fs.existsSync(backupDir)) {
|
|
fs.mkdirSync(backupDir, { recursive: true });
|
|
}
|
|
|
|
console.log(`\n📦 Starte Datenbank-Backup nach: ${backupDir}\n`);
|
|
|
|
// Tabellen in Abhängigkeitsreihenfolge (unabhängige zuerst)
|
|
const tables = [
|
|
// Level 0: Keine Abhängigkeiten
|
|
{ name: 'Permission', query: () => prisma.permission.findMany() },
|
|
{ name: 'Role', query: () => prisma.role.findMany() },
|
|
{ name: 'SalesPlatform', query: () => prisma.salesPlatform.findMany() },
|
|
{ name: 'ContractCategory', query: () => prisma.contractCategory.findMany() },
|
|
{ name: 'CancellationPeriod', query: () => prisma.cancellationPeriod.findMany() },
|
|
{ name: 'ContractDuration', query: () => prisma.contractDuration.findMany() },
|
|
{ name: 'AppSetting', query: () => prisma.appSetting.findMany() },
|
|
{ name: 'EmailProviderConfig', query: () => prisma.emailProviderConfig.findMany() },
|
|
{ name: 'EnergyProvider', query: () => prisma.energyProvider.findMany() },
|
|
{ name: 'TelecomProvider', query: () => prisma.telecomProvider.findMany() },
|
|
|
|
// Level 1: Abhängig von Level 0
|
|
{ name: 'RolePermission', query: () => prisma.rolePermission.findMany() },
|
|
{ name: 'User', query: () => prisma.user.findMany() },
|
|
{ name: 'Customer', query: () => prisma.customer.findMany() },
|
|
{ name: 'Tariff', query: () => prisma.tariff.findMany() },
|
|
|
|
// Level 2: Abhängig von Level 1
|
|
{ name: 'UserRole', query: () => prisma.userRole.findMany() },
|
|
{ name: 'CustomerRepresentative', query: () => prisma.customerRepresentative.findMany() },
|
|
{ name: 'StressfreiEmail', query: () => prisma.stressfreiEmail.findMany() },
|
|
{ name: 'Contract', query: () => prisma.contract.findMany() },
|
|
{ name: 'Meter', query: () => prisma.meter.findMany() },
|
|
|
|
// Level 3: Abhängig von Level 2
|
|
{ name: 'CachedEmail', query: () => prisma.cachedEmail.findMany() },
|
|
{ name: 'ContractTask', query: () => prisma.contractTask.findMany() },
|
|
{ name: 'MeterReading', query: () => prisma.meterReading.findMany() },
|
|
{ name: 'ContractNote', query: () => prisma.contractNote.findMany() },
|
|
{ name: 'ContractDocument', query: () => prisma.contractDocument.findMany() },
|
|
|
|
// Level 4: Abhängig von Level 3
|
|
{ name: 'ContractTaskSubtask', query: () => prisma.contractTaskSubtask.findMany() },
|
|
|
|
// Vertragstyp-spezifische Details
|
|
{ name: 'EnergyContractDetails', query: () => prisma.energyContractDetails.findMany() },
|
|
{ name: 'TelecomContractDetails', query: () => prisma.telecomContractDetails.findMany() },
|
|
{ name: 'CarInsuranceDetails', query: () => prisma.carInsuranceDetails.findMany() },
|
|
];
|
|
|
|
let totalRecords = 0;
|
|
const stats: { table: string; count: number }[] = [];
|
|
|
|
for (const table of tables) {
|
|
try {
|
|
const data = await table.query();
|
|
const count = data.length;
|
|
totalRecords += count;
|
|
stats.push({ table: table.name, count });
|
|
|
|
// JSON-Datei schreiben
|
|
const filePath = path.join(backupDir, `${table.name}.json`);
|
|
fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
|
|
|
|
const status = count > 0 ? '✅' : '⚪';
|
|
console.log(`${status} ${table.name}: ${count} Einträge`);
|
|
} catch (error: any) {
|
|
// Tabelle existiert möglicherweise nicht (bei älteren Schema-Versionen)
|
|
console.log(`⚠️ ${table.name}: Übersprungen (${error.message?.slice(0, 50)}...)`);
|
|
}
|
|
}
|
|
|
|
// Backup-Info speichern
|
|
const backupInfo = {
|
|
timestamp: new Date().toISOString(),
|
|
totalRecords,
|
|
tables: stats,
|
|
};
|
|
fs.writeFileSync(path.join(backupDir, '_backup-info.json'), JSON.stringify(backupInfo, null, 2));
|
|
|
|
console.log(`\n✅ Backup abgeschlossen!`);
|
|
console.log(` 📊 ${totalRecords} Datensätze in ${stats.filter(s => s.count > 0).length} Tabellen`);
|
|
console.log(` 📁 Gespeichert in: ${backupDir}\n`);
|
|
}
|
|
|
|
main()
|
|
.catch((e) => {
|
|
console.error('❌ Backup fehlgeschlagen:', e);
|
|
process.exit(1);
|
|
})
|
|
.finally(async () => {
|
|
await prisma.$disconnect();
|
|
});
|