Files
AfiS-Aktensystem/packages/db/prisma/seed.ts
T
HarlekinandClaude Opus 5 51984f17d4 Workspace und Datenmodell
pnpm-Workspace mit web/, worker/, pdf/ und packages/db. Das Datenbankpaket ist
eigenständig, weil Web-App und Worker denselben Prisma-Client brauchen.

Schema nach docs/04-datenmodell.md, mit drei Abweichungen, die dort begründet
sind: CaseParticipant bekommt einen eigenen Schlüssel statt eines
zusammengesetzten mit NULL-Spalten, die Aktenzeichen laufen über CaseCounter
statt über eine Sequenz pro Jahr, und ServiceHeartbeat kommt dazu, damit
/api/health den Gateway-Zustand kennt, ohne Discord zu fragen.

Die zweite Migration enthält, was Prisma nicht ausdrücken kann:
- kein DELETE auf CaseEntry, CaseEntryVersion und AuditLog
- authorId, createdAt, caseId und type eines Eintrags sind unveränderlich
- an einer Eintragsversion darf nur minClearance angehoben werden
- Volltextsuche mit deutscher Konfiguration; geschwärzte Bereiche werden vor
  dem Indizieren entfernt, sonst verrät ein Treffer den Inhalt
- pg_notify bei Rollen- und Mapping-Änderungen

Acht Tests prüfen diese Regeln gegen eine echte Postgres-Instanz, nicht gegen
die Anwendungslogik.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 00:01:29 +02:00

70 lines
2.5 KiB
TypeScript

import { createPrismaClient } from '../src/index.js'
/**
* Grundzustand der Anwendung. Alles hier ist Konfiguration, ohne die die App
* nicht sinnvoll läuft, kein Testinhalt.
*
* Die vier Startvorlagen (Korruptionsverdacht, Dienstvergehen,
* Sicherheitsvorfall, Routineprüfung) kommen in Phase 3 dazu, zusammen mit dem
* Vorlagen-Editor. Siehe TASKS.md.
*/
const db = createPrismaClient()
/**
* Auslieferungszustand nach docs/01-produkt.md. Ab Stufe 3 ist die Existenz
* einer Akte für niedrigere Stufen verborgen, darunter nur der Inhalt gesperrt.
* Der Leiter kann das im Adminbereich ändern.
*/
const CLEARANCE_LEVELS = [
{ level: 0, name: 'Offen', hiddenBelow: false, colorToken: 'stamp-0' },
{ level: 1, name: 'Intern', hiddenBelow: false, colorToken: 'stamp-1' },
{ level: 2, name: 'Vertraulich', hiddenBelow: false, colorToken: 'stamp-2' },
{ level: 3, name: 'Geheim', hiddenBelow: true, colorToken: 'stamp-3' },
{ level: 4, name: 'Streng geheim', hiddenBelow: true, colorToken: 'stamp-4' },
{ level: 5, name: 'Leitungssache', hiddenBelow: true, colorToken: 'stamp-5' },
]
async function main(): Promise<void> {
for (const config of CLEARANCE_LEVELS) {
await db.clearanceLevelConfig.upsert({
where: { level: config.level },
create: config,
update: { name: config.name, colorToken: config.colorToken },
})
}
console.log(`[seed] ${CLEARANCE_LEVELS.length} Freigabestufen`)
// Änderungsrichtlinie im Auslieferungszustand: eigene Einträge sind 15 Minuten
// frei änderbar, danach nur mit Recht. Eine Änderung in dieser Karenzzeit wird
// versioniert und protokolliert, aber nicht sichtbar markiert.
// Siehe docs/05-akten-und-vorlagen.md.
await db.appSetting.upsert({
where: { id: 1 },
create: { id: 1 },
update: {},
})
console.log('[seed] Änderungsrichtlinie GRACE_WINDOW, 15 Minuten')
const year = new Date().getFullYear()
await db.caseCounter.upsert({
where: { year },
create: { year, lastNumber: 0 },
update: {},
})
console.log(`[seed] Aktenzeichen-Zähler für ${year}`)
// entry.edit_own, entry.edit_any und entry.retract sind bewusst keiner Rolle
// zugeordnet. Der Leiter schaltet sie frei, wenn er sie will.
// Siehe docs/03-auth-und-rechte.md.
const mappings = await db.roleMapping.count()
console.log(`[seed] ${mappings} Rollen-Zuordnungen vorhanden, keine angelegt`)
}
main()
.then(() => db.$disconnect())
.catch(async (error: unknown) => {
console.error('[seed] fehlgeschlagen', error)
await db.$disconnect()
process.exit(1)
})