# AfiS-Aktensystem Fall- und Personalaktenverwaltung für die Abteilung für innere Sicherheit eines SCP-RP-Servers. Anmeldung und Berechtigungen laufen vollständig über Discord. Interne Anwendung für eine geschlossene Gruppe von zehn bis fünfzig Personen, selbst gehostet. Keine Mandantentrennung, keine öffentliche Registrierung. ## Was es kann - **Fallakten** mit Kopfdaten, Abschnitten nach Vorlage und einem Verlauf, der nur wächst - **Personalakten**, überwiegend für Externe, mit Aktenblatt zum Ausdrucken - **Abteilungen** als Ebene darüber: was zu ihnen aktenkundig ist, ergibt sich aus ihren Mitgliedern - **Dokumente** nach Vorlage, an einer Fall- oder Personalakte - **Fünfstufige Klassifizierung** mit feldgenauer Schwärzung - **Volltextsuche** je Freigabestufe, Kommandopalette auf Strg+K - **Chat** in jeder Akte, mit Übernahme einer Nachricht als Vermerk - **Export** als PDF mit Wasserzeichen, jeder Abruf protokolliert - **Zugriffsprotokoll** über jede schreibende Aktion und jeden Lesezugriff ab Stufe 3 ## Zusicherungen Acht Regeln, die im Code und wo möglich in der Datenbank durchgesetzt sind. Sie sind der Grund, warum das System so gebaut ist, wie es gebaut ist - Codekommentare verweisen unter ihrer Nummer hierher. 1. **Berechtigungsprüfung immer serverseitig und immer in der Datenbankabfrage.** Niemals alle Datensätze laden und danach filtern. 2. **Verlaufseinträge dürfen nachträglich geändert werden, aber niemals unsichtbar.** Jede Änderung erzeugt eine Version, jede Zurücknahme lässt einen Grabstein stehen, beides ist für alle sichtbar, die den Eintrag sehen dürfen. Es gibt kein `DELETE` - das steht als Regel in der Datenbank, nicht nur in der Anwendung. 3. **Jede schreibende Aktion und jeder Lesezugriff ab Stufe 3 erzeugt einen Protokolleintrag.** 4. **Keine Dateiendungen als Typprüfung.** Immer Magic Bytes. Kein SVG, kein HTML, keine Archive. 5. **Keine Blockade-Spinner.** Jede Ansicht hat ein Skelett, jede Änderung eine sofortige Rückmeldung. 6. **Existenz ist auch eine Information.** Akten oberhalb der Sichtstufe tauchen weder in Listen noch in Trefferzahlen noch in Rückverweisen auf. Kein Zugriff heisst 404, nicht 403. 7. **Keine Geheimnisse im Repository.** Alles über `.env`, Vorlage in `.env.example`. 8. **Keine Einmal-Container.** Der Betrieb läuft über Dockge, das beendete Container nicht dauerhaft anzeigt. Migrationen gehören ins Startkommando von `web`, wiederkehrende Aufgaben in Dauerläufer mit eigenem Cron. Jeder Dienst braucht einen Healthcheck, weil das in Dockge die Statusanzeige ist. ## Aufbau ``` web/ Next.js 15, App Router, React 19 worker/ discord.js, gleicht Rollen und Mitgliedschaft ab pdf/ Playwright, erzeugt die PDF-Ausdrucke packages/db/ Prisma-Schema, Migrationen, Seed docker/ Dockerfiles für web, worker und pdf compose.yaml Der Dockge-Stack .env.example Vorlage für den .env-Reiter in Dockge ``` Stack: Next.js 15 mit React 19 und TypeScript, Auth.js v5 mit Discord-Provider, Prisma auf PostgreSQL 16, Tailwind ohne Komponentenbibliothek. ClamAV und Playwright laufen als eigene Container. ## Einrichten Discord-Application anlegen, Bot auf den Server einladen und **Server Members Intent aktivieren** - ohne das liefert der Bot keine Rollen. ## Lokal entwickeln Node 22 und pnpm 9. ```bash corepack enable && pnpm install docker run -d --name afis-db -e POSTGRES_DB=afis -e POSTGRES_USER=afis \ -e POSTGRES_PASSWORD=afis -p 5434:5432 postgres:16-alpine cp .env.example .env # DATABASE_URL und DIRECT_DATABASE_URL auf localhost:5434 zeigen lassen pnpm --filter @afis/db run build # erzeugt den Prisma-Client pnpm db:deploy && pnpm db:seed pnpm dev ``` Prüfen wie die CI: ```bash pnpm lint && pnpm typecheck && pnpm test pnpm test:e2e ``` `pnpm test` legt sich eine eigene Datenbank `afis_test` an und lässt die Entwicklungsdatenbank in Ruhe: Verlaufseinträge und Protokollzeilen sind nach Regel 2 nicht löschbar, was ein Test dort anlegt, bliebe für immer stehen. ## Betrieb Gehostet als **ein** Dockge-Stack. Die `.env` wird nicht im Repository gepflegt, sondern im `.env`-Reiter von Dockge. | | | |---|---| | Verwaltung | Dockge, ein Stack namens `afis` unter `/opt/stacks/afis/` | | Erreichbarkeit | Cloudflare Tunnel, kein offener Port am Router | | Aktualisieren | Dockge → Stack → Update, Migration läuft automatisch mit | | Backup | zwei Dauerläufer mit Cron: nächtlicher Dump plus restic offsite | | Wiederherstellung | `scripts/restore-test.sh` spielt einen Dump in eine Wegwerf-Datenbank und vergleicht Zeilenzahlen, Regeln und Trigger |