import { db } from '@/lib/db' import { writeAudit } from '@/lib/audit/write' import { AccessError } from '@/lib/errors' import type { EffectivePermissions } from '@/lib/auth/permissions' /** * Vollständiger JSON-Abzug als Umzugs- und Notfallformat. * * **Ohne Stufenfilterung**, nur mit Recht `admin`, immer protokolliert - so * steht es in docs/08-suche-und-export.md. Das ist die eine Stelle im System, * an der die Klassifizierung nicht greift, und sie ist deshalb absichtlich * unbequem: kein Knopf an einer Akte, sondern eine eigene Seite im * Adminbereich. * * Ausgelassen wird, was Zugang verschafft statt ihn zu dokumentieren: * Sitzungen. Sie gehören niemandem ausser dem Browser, aus dem sie stammen. */ export async function exportDatabase(p: EffectivePermissions): Promise { if (!p.isAdmin) throw new AccessError('no-permission') const [ users, roleMappings, clearanceLevels, foundationClearances, statusTags, templates, cases, caseSections, caseSectionVersions, caseEntries, caseEntryVersions, participants, exclusions, links, personnel, assignments, documents, documentSections, documentSectionVersions, attachments, messages, reactions, auditLog, ] = await Promise.all([ db.user.findMany(), db.roleMapping.findMany(), db.clearanceLevelConfig.findMany(), db.foundationClearance.findMany(), db.personnelStatusTag.findMany(), db.documentTemplate.findMany(), db.case.findMany(), db.caseSection.findMany(), db.caseSectionVersion.findMany(), db.caseEntry.findMany(), db.caseEntryVersion.findMany(), db.caseParticipant.findMany(), db.caseExclusion.findMany(), db.caseLink.findMany(), db.personnelFile.findMany(), db.personnelAssignment.findMany(), db.document.findMany(), db.documentSection.findMany(), db.documentSectionVersion.findMany(), db.attachment.findMany(), db.chatMessage.findMany(), db.chatReaction.findMany(), // Das Protokoll gehört dazu: ein Abzug ohne die Zugriffsspur wäre als // Notfallformat wertlos. db.auditLog.findMany({ orderBy: { id: 'desc' }, take: 50_000 }), ]) const abzug = { exportedAt: new Date().toISOString(), exportedBy: p.userId, note: 'Vollstaendiger Abzug ohne Stufenfilterung. Vertraulich behandeln.', users, roleMappings, clearanceLevels, foundationClearances, statusTags, templates, cases, caseSections, caseSectionVersions, caseEntries, caseEntryVersions, participants, exclusions, links, personnel, assignments, documents, documentSections, documentSectionVersions, attachments, messages, reactions, auditLog, } await db.$transaction(async (tx) => { await writeAudit(tx, { actorId: p.userId, action: 'export.database', targetType: 'Database', targetId: 'all', clearanceAtTime: p.clearanceLevel, meta: { cases: cases.length, entries: caseEntries.length, users: users.length }, }) }) // `BigInt` kommt in AuditLog.id vor und ist in JSON nicht vorgesehen. return new TextEncoder().encode( JSON.stringify(abzug, (_key, wert: unknown) => typeof wert === 'bigint' ? wert.toString() : wert, 2), ) }