# Bauplan Phasen in Reihenfolge abarbeiten. Am Ende jeder Phase muss `pnpm lint && pnpm typecheck && pnpm test` durchlaufen und die Anwendung startbar sein. ## Phase 0 — Gerüst - [x] Next.js 15 mit TypeScript strict, Tailwind, pnpm-Workspace mit `web/` und `worker/` - [x] Prisma, Postgres im Compose, erste Migration - [x] Design-Tokens aus `docs/10-design-system.md` als CSS-Variablen, IBM Plex selbst gehostet - [x] `lib/i18n/de.ts` mit den ersten Texten, Konvention: keine deutschen Strings im JSX - [x] Vitest und Playwright eingerichtet, ein rauchender Test je Ebene - [x] `.env.example` gefüllt, `compose.yaml` aus `docs/11-betrieb.md` als Dockge-Stack lauffähig (zunächst nur `web`, `db`, `pgbouncer`) - [x] Dockerfiles für `web`, `worker` und `pdf`, GitHub-Actions-Workflow schiebt die Images in die GitHub Container Registry - [x] `/api/health` prüft Datenbank, Discord-Gateway und ClamAV, wird vom Healthcheck genutzt ## Phase 1 — Anmeldung und Rechte Das ist der schwierigste Teil. Wenn er steht, ist der Rest Formularbau. - [x] Auth.js mit Discord-Provider, Scope `identify`, state und PKCE - [x] Bot-Client mit Bot-Token, Guild-Mitgliedschaftsprüfung im Callback - [x] Eigene Session in der Datenbank, Cookie-Einstellungen wie in `docs/03-auth-und-rechte.md` - [x] `worker/`: discord.js am Gateway, Ereignisse plus Voll-Abgleich alle 5 Minuten - [x] `pg_notify` bei Rollenänderung, Cache-Invalidierung in der Web-App - [x] `EffectivePermissions` mit prozesslokalem Cache - [x] `BOOTSTRAP_ADMIN_IDS` als Notfallzugang - [x] Adminseite Rollen-Mapping: Tabelle der Discord-Rollen, Stufe per Auswahl, Rechte per Kästchen, Vorschau „Was sieht Stufe 2?" - [x] Sessions werden bei Rollenverlust oder Serveraustritt beendet - [x] Zwischenstand: eingeloggte Seite zeigt Name, Rollen, errechnete Stufe und Rechte - [x] Negativtests aus `docs/03-auth-und-rechte.md` grün, soweit sie ohne Akten prüfbar sind. Die vier zu nachträglichen Änderungen an Verlaufseinträgen gehören zu Phase 2 - [x] `entry.edit_own`, `entry.edit_any`, `entry.retract` und `case.edit_closed` als Rechte angelegt, im Auslieferungszustand keiner Rolle zugeordnet ## Phase 2 — Akten - [x] Datenmodell für `Case`, `CaseSection`, `CaseEntry`, Beteiligte, Ausschlüsse - [x] `lib/access/` mit Where-Fragmenten, überall verwendet, nirgends Nachfilterung - [x] Aktenzeichen-Vergabe kollisionsfrei über `CaseCounter` - [x] Fallliste mit Filtern, cursorbasiert, `loading.tsx` mit Skelett - [x] Aktenansicht: Kopfdaten sofort, Verlauf in eigener Suspense-Grenze (Chat: Phase 6) - [x] Vermerk anlegen, optimistisch, mit clientseitiger UUIDv7 - [x] Statusübergänge mit Rechteprüfung und automatischem Systemeintrag - [x] Schreibgrenzen nach `docs/03-auth-und-rechte.md`: keine Akte über der eigenen Stufe anlegen, Ändern nur mit Lesezugriff, Klassifizierung nachträglich änderbar bis zur eigenen Stufe. Kein Löschen von Akten, nur `ARCHIVED` und `SEALED` - [x] Umklassifizierung erzeugt `SYSTEM`-Eintrag und `AuditLog` mit alter und neuer Stufe - [x] Negativtests dazu: Stufe 2 kann keine Stufe-4-Akte anlegen, nicht ändern, nicht hochstufen, auch nicht über einen direkten Aufruf der Server Action - [x] Audit-Log für alle schreibenden Aktionen und Lesezugriffe ab Stufe 3 - [x] Nachträgliche Änderungen an Verlaufseinträgen nach `docs/05-akten-und-vorlagen.md`: `CaseEntryVersion`, Karenzzeit, Pflichtbegründung, `bearbeitet · vN` mit Diff-Historie - [x] Zurückziehen mit Grabstein und Pflichtbegründung, kein hartes Löschen - [x] Postgres-Regeln gegen `DELETE` auf `CaseEntry` und `CaseEntryVersion` - [x] Änderungsübersicht als Reiter an der Akte - [x] Adminseite für `AppSetting`: Änderungsrichtlinie, Karenzzeit, Markierungsverhalten ## Phase 3 — Vorlagen und Abschnitte - [x] Entschieden: jede Akte trägt Kurzvermerke und Dokumente, die Fallakte zusätzlich Abschnitte. Siehe `docs/13-entscheidungen.md` - [x] Feldtypen für Textkörper-Vorlagen ergänzen: fester Fließtext, Überschrift, Platzhalter, Unterschriftenzeile — der Sonderarbeitsvertrag ist kein Formular - [x] `CaseTemplate` mit Feldtypen aus `docs/05-akten-und-vorlagen.md` - [x] Aktenzeichen-Muster je Vorlage: Präfix und Stellenzahl, Nummernkreis je Präfix und Jahr - [x] Feld „Foundation-Freigabe" als gewöhnliches Vorlagenfeld, ohne Wirkung auf den Zugriff - [x] Vorlagen-Editor im Adminbereich, versioniert, mit Vorschau - [x] Abschnitte rendern und bearbeiten, Autosave lokal alle 2 Sekunden - [x] Versionierung mit Diff-Ansicht - [x] Konflikterkennung über mitgesendete Version, 409 mit Vergleichsansicht - [x] `minClearance` pro Feld, serverseitige Ersetzung durch Platzhalter - [x] Schwärzungs-Auszeichnung im Freitext, Parser in `lib/redaction.ts` - [x] Seed mit vier Startvorlagen ## Phase 4 — Personalakten und Verknüpfungen - [x] `PersonnelFile`, auch für Personen ohne Discord-Konto - [x] Dokumente an der Personalakte aus Vorlagen, z. B. Sonderarbeitsvertrag - [x] Beteiligte einer Akte mit Rolle - [x] Rückverweise auf der Personalakte, durch die Sichtbarkeitsprüfung gefiltert - [x] Verknüpfungen zwischen Akten - [x] Test: Stufe-1-Nutzer sieht auf einer Personalakte keinen Hinweis auf Stufe-3-Fälle - [x] Aktenblatt der Personalabteilung als Vorlage, Aufbau und Aussehen übernommen - [x] Status als mehrere Etiketten, im Adminbereich pflegbar - [x] AfiS-Mitglieder an einer Personalakte, mit ausnahmsweisem Zugang - [x] Fall und Person von beiden Seiten verknüpfbar, auch beim Anlegen ## Phase 5 — Dateien - [x] Upload-Endpunkt mit Quarantäne, Limits, Kontingent - [x] Typprüfung über Magic Bytes, Whitelist - [x] ClamAV-Container angebunden - [x] Neu-Kodierung mit sharp und qpdf, Vorschaubild und Blurhash - [x] Auslieferung über `/api/files/[id]` mit Rechteprüfung und harten Headern - [x] Upload-UI: lokale Vorschau, Fortschrittsbalken, Zustand „Wird geprüft" - [x] SSE-Ereignis `attachment.scanned` aktualisiert die Anzeige - [x] Lichtbild im Aktenblatt: Feldtyp `photo` füllen, Wert ist die Kennung eines geprüften Anhangs — das Feld und sein Platz stehen seit Phase 4 ## Phase 6 — Chat und Echtzeit - [x] SSE-Endpunkt mit `LISTEN/NOTIFY`, Heartbeat, Reconnect mit `Last-Event-ID` - [x] Aktenchat mit Antworten, Reaktionen, Bearbeiten, Zurückziehen - [x] Optimistisches Senden mit Dedupe über Client-ID - [x] Aktenzeichen-Erkennung mit serverseitig aufgelöster Vorschaukarte - [x] Ungelesen-Markierung und Trennlinie - [x] Freie Kanäle mit eigener Mindeststufe - [x] „Als Vermerk übernehmen" - [x] Discord-Benachrichtigungen über den Worker, ohne Inhalte - [x] Benachrichtigungseinstellung je Nutzer: alles / meine Fälle / Erwähnungen / aus ## Phase 7 — Suche - [x] `search_vector` mit Trigger und Gewichtung, GIN-Index — je Freigabestufe einer - [x] Suchseite mit Filtern, Debounce, AbortController, gedimmte alte Treffer - [x] Sichtbarkeitsprüfung in derselben Abfrage, auch für Facettenzähler - [x] Kommandopalette auf Strg+K - [x] Gespeicherte Ansichten - [x] „Zuletzt geöffnet" als Sprungliste — eigene Spur ohne Verlauf, siehe docs/13 ## Phase 8 — Export - [x] Druckansicht `/faelle/[caseNumber]/druck` mit `@media print` - [x] Playwright-Container erzeugt PDF, Ergebnis gecacht - [x] Schwärzung und Wasserzeichen im Export - [x] Freigabeverfahren ab Stufe 3 - [x] Einzeldokument als PDF, ohne Verlauf, Aussehen aus der Vorlage - [x] ZIP-Sammelexport und JSON-Vollexport für Admins - [x] Fallakte in Reiter geteilt, Bündelbudget wieder eingehalten (116,2 statt 119,8 von 120 kB) ## Phase 9 — Schliff - [x] Dashboard: meine Fälle, Fristen, ungelesene Chats, letzte Aktivität - [x] Beobachtungsliste - [x] Helles Thema - [x] Mobile Ansicht durchgehen, besonders Akte und Chat - [x] Web-Vitals-Erfassung und Anzeige im Adminbereich - [x] Bundle-Analyse, Budget aus `docs/09-performance-und-ux.md` einhalten - [x] Backup-Wiederherstellung einmal von Hand testen (`scripts/restore-test.sh`)