Files
FireAdministration/docs/ANLEITUNG.md
T
Florian WildeandClaude Opus 5 845942f36c Phase 0: Fundament der Feuerwehr-Verwaltungsplattform
Legt den kompletten Unterbau an, auf dem die Fachmodule aufsetzen.

Betrieb:
- docker-compose.yml mit Traefik, App, Worker, PostgreSQL 17 + PostGIS,
  Redis, MinIO und Gotenberg; Entwicklungs-Override ohne Traefik, dafuer
  mit Mailpit und Adminer
- Mehrstufiges Dockerfile: eigener Benutzer, tini als PID 1, Healthcheck
- .env.example mit einem Kommentar zu jeder Variable

Mandantentrennung:
- Row Level Security auf allen mandantenpflichtigen Tabellen
- Zwei getrennte Datenbankverbindungen: florian_app mit aktiver RLS fuer
  die Anwendung, Eigentuemer-Zugang nur fuer Migration, Seed und Anmeldung
- fuerOrganisation() als einziger Weg zu Fachdaten

Nachvollziehbarkeit:
- AuditLog append-only per Trigger; UPDATE ist dauerhaft gesperrt, DELETE
  nur im gekennzeichneten Aufbewahrungslauf
- Geheimnisse werden vor dem Schreiben entfernt

Anmeldung:
- OIDC gegen ein extern betriebenes authentik, Rollen aus Gruppen nur als
  Vorbelegung beim ersten Login
- Lokaler E-Mail/Passwort-Login als Rueckfallweg
- Terminal per PIN und RFID mit zwei Schranken (Geraet, dann Person)

Weiteres:
- lib/authz.ts mit 9 Rollen und 38 Einzelrechten
- lib/storage.ts (MinIO), lib/audit.ts, lib/warteschlange.ts (BullMQ)
- Integrationen fuer Mail, Telegram und LLM hinter abschaltbaren Interfaces
- tRPC v11, Basis-Layout mit Seitenleiste und dunkler Darstellung
- Seed mit einer Beispielwehr: 16 Personen, 3 Fahrzeuge, 40 Geraete
- 32 Vitest-Tests (davon 8 gegen eine echte Datenbank), 10 Playwright-Tests
- README, Anleitung mit Screenshots, Roadmap, Aufwandsschaetzung, Devlog,
  Versionierungsregeln und Changelog

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

9.8 KiB

Anleitung

Bedienung von FLORIAN, Stand Phase 0 (Version 0.1.0). Die Bilder zeigen die Beispielwehr aus dem Seed und werden mit npm run screenshots neu erzeugt.

Was hier noch fehlt — Mitglieder, Geräte, Prüfungen — kommt in den folgenden Phasen dazu. Der Stand ist bewusst schmal: Phase 0 baut das Fundament, nicht die Fachmodule. Siehe ROADMAP.md.


1. Anmelden

Aufgerufen wird FLORIAN im Browser unter der Adresse, die der Administrator eingerichtet hat — in der Entwicklung http://localhost:3100.

Anmeldeseite

Die Anmeldeseite zeigt genau die Wege, die in dieser Installation eingerichtet sind:

Weg Wann
Anmeldung über authentik Der Regelweg, sobald authentik eingerichtet ist. Ein Klick, keine Passworteingabe in FLORIAN.
E-Mail und Passwort Beim Erststart, und wenn authentik gerade nicht erreichbar ist.
Terminal im Gerätehaus Am Wandtablet, mit PIN oder Ausweiskarte. Eigene Oberfläche, kommt in Phase 4.

Beim allerersten Start gibt es genau ein Konto: das aus SEED_ADMIN_EMAIL und SEED_ADMIN_PASSWORT in der .env. Vorgabe:

admin@beispielwehr.de
Feuerwehr2026

Dieses Passwort gehört nach dem ersten Login geändert.

Wenn die Anmeldung nicht klappt

Nach mehreren Fehlversuchen wird das Konto vorübergehend gesperrt — voreingestellt nach fünf Versuchen für fünf Minuten (KIOSK_MAX_FEHLVERSUCHE, KIOSK_SPERRDAUER). Die Meldung nennt nicht, ob die E-Mail-Adresse oder das Passwort falsch war; das ist Absicht und verhindert, dass sich vorhandene Konten erraten lassen.


2. Die Übersicht

Nach der Anmeldung steht die Übersicht der eigenen Wehr.

Übersicht

Von oben nach unten:

Kopfzeile. Name der Wehr und darunter, wer angemeldet ist und mit welchen Rollen. Wer mehrere Rollen trägt — der Gerätewart ist oft auch Ausbilder — sieht alle.

Sicherheitshinweis. Der gelbe Kasten bleibt stehen, solange die Wehr die Anwendung nicht ausdrücklich freigegeben hat. Er ist keine Formalität: Atemschutzüberwachung und Alarmmonitor sind sicherheitsrelevant, und bis zur Freigabe bleibt die analoge Überwachung führend.

Kennzahlen. Vier Kacheln mit aktiven Mitgliedern, Fahrzeugen, Geräten und fälligen Prüfungen. Sie zählen nur die eigene Wehr — was eine andere Wehr auf derselben Installation hat, ist nicht sichtbar und nicht abfragbar.

Stand des Aufbaus. Welche Phasen fertig sind und was als Nächstes kommt.

Die Seitenleiste

Links stehen alle Module. Was noch nicht existiert, ist ausgegraut und trägt rechts sein Phasenkürzel — P2 heißt „kommt in Phase 2".

Was jemand überhaupt sieht, hängt an seinen Rechten. Ein einfaches Mitglied sieht die Mitgliederliste, aber nicht das Protokoll. Wichtig zum Verständnis: das Ausblenden ist nur Bequemlichkeit. Der eigentliche Schutz sitzt auf dem Server — wer eine Adresse direkt aufruft, für die ihm das Recht fehlt, bekommt trotzdem nichts.


3. Helle und dunkle Darstellung

Oben rechts wird zwischen hell und dunkel umgeschaltet. Voreingestellt ist die Einstellung des Betriebssystems.

Übersicht in dunkler Darstellung

Die dunkle Darstellung ist bewusst kein invertiertes Schwarz, sondern ein warmes Grau. Wer abends vom Fahrzeug hereinkommt und ans Terminal tritt, soll nicht geblendet werden.


4. Rollen und was sie dürfen

Neun Rollen, jede mit einem festen Satz Rechte. Die Zuordnung steht zentral in src/lib/authz.ts und wird beim Seed in die Datenbank gespiegelt — eine Wehr kann sie also nachträglich zuschneiden, ohne dass jemand Code ändert.

Rolle Darf im Kern
Administrator alles, auch über Wehren hinweg
Kommandant alles innerhalb der eigenen Wehr, einschließlich Rollen vergeben und Protokoll einsehen
Gerätewart Fahrzeuge und Geräte anlegen, ändern, aussondern; Prüfungen planen und durchführen
Atemschutzgerätewart zusätzlich Atemschutzgeräte, Träger und die Überwachung nach FwDV 7
Kassier Buchungen und Kassenabschluss (Modul noch nicht geplant, siehe Roadmap)
Schriftführer Mitglieder pflegen, Einsätze und Berichte erfassen
Ausbilder Übungen planen, Teilnahme und Qualifikationen erfassen
Mitglied eigene Daten, Listen lesen
Terminal nur anmelden und erfassen — nie verwalten

Zwei Dinge sind bewusst so gebaut:

Der Gerätewart kommt nicht an die Kasse, der Kassier nicht an die Geräte. Trennung nach Verantwortung, nicht nach Bequemlichkeit.

Das Terminal darf fast nichts. Wer am Wandtablet arbeitet, meldet sich zusätzlich mit PIN oder Karte an und handelt dann unter seiner eigenen Person. Das Terminal selbst ist nur die Tür.


5. Anmeldung über authentik einrichten

authentik läuft getrennt von FLORIAN und ist nicht Teil dieses Stacks.

In authentik

  1. Neuen Provider anlegen, Typ OAuth2/OpenID Provider
  2. Client-Typ: Confidential
  3. Redirect-URI genau so eintragen:
    https://<ihre-florian-adresse>/api/auth/callback/authentik
    
  4. Scopes: openid, profile, email
  5. Für die Rollenvorbelegung zusätzlich ein Scope-Mapping, das die Gruppen des Benutzers als Claim groups ausliefert
  6. Eine Application anlegen und mit dem Provider verbinden. Der Slug der Application ist der letzte Teil der Issuer-URL.

In der .env

AUTH_OIDC_ENABLED=true
AUTH_OIDC_ISSUER=https://auth.beispiel.de/application/o/florian/
AUTH_OIDC_CLIENT_ID=<aus authentik>
AUTH_OIDC_CLIENT_SECRET=<aus authentik>
AUTH_OIDC_GROUP_CLAIM=groups
AUTH_OIDC_GROUP_MAPPING=feuerwehr-kommandant:KOMMANDANT,feuerwehr-geraetewart:GERAETEWART
AUTH_OIDC_AUTO_PROVISION=true
AUTH_OIDC_STANDARD_ORGANISATION=ff-musterhausen

Danach die Anwendung neu starten. Auf der Anmeldeseite erscheint der Knopf für authentik.

Wie die Rollenvorbelegung wirkt

Die Zuordnung greift nur beim allerersten Login einer Person. Danach ist die in FLORIAN gepflegte Rolle führend, und authentik überschreibt sie nicht mehr. Wer also einem Mitglied in FLORIAN die Rolle „Gerätewart" gibt, behält sie — auch wenn die authentik-Gruppe etwas anderes sagt.

Steht AUTH_OIDC_AUTO_PROVISION=false, muss die Person vorher in FLORIAN angelegt sein. Verknüpft wird über die E-Mail-Adresse.

Wenn authentik ausfällt

Solange AUTH_LOCAL_ENABLED=true steht, bleibt der Passwort-Login als Rückfallweg erreichbar. Für den Wirkbetrieb ist es sinnvoll, mindestens ein Konto mit Passwort zu behalten — sonst sperrt ein Ausfall von authentik die ganze Wehr aus.


6. Terminal-Anmeldung im Gerätehaus

Die Oberfläche dazu kommt in Phase 4; der Anmeldeweg steht bereits.

Am Terminal wird zweifach geprüft:

  1. Das Gerät weist sich mit KIOSK_DEVICE_SECRET aus. Ohne diesen Wert nimmt der Server keine PIN und keine Karte an.
  2. Die Person meldet sich mit einer sechsstelligen PIN (zusammen mit ihrer Mitgliedsnummer) oder mit einer RFID-Karte an.

Beides wird nur als Hash gespeichert — weder die PIN noch die Kartenkennung liegen im Klartext in der Datenbank.

PINs, die sich zu leicht raten lassen, weist FLORIAN ab: lauter gleiche Ziffern und fortlaufende Folgen wie 123456.

Aus dem Seed lässt sich das ausprobieren: Mitgliedsnummer 0001 (Andreas Huber), PIN 471203.


7. Was protokolliert wird

Jede schreibende Änderung erzeugt einen Eintrag mit Zeitpunkt, Person, betroffenem Datensatz und den geänderten Feldern im Vorher-Nachher-Vergleich. Auch jede Anmeldung — erfolgreich wie gescheitert.

Zwei Eigenschaften sind wichtig:

Der Log lässt sich nicht ändern. Nicht über die Oberfläche, nicht über die Datenbank, auch nicht vom Administrator. Die Datenbank selbst verhindert es.

Er lässt sich nur im Aufbewahrungslauf kürzen. Nach der eingestellten Frist (AUDIT_AUFBEWAHRUNG_TAGE, Vorgabe 10 Jahre) sichert der Hintergrundprozess die alten Einträge und entfernt sie danach. Das ist der einzige Weg, auf dem etwas aus dem Log verschwindet.

Passwörter, PINs und Kartenkennungen stehen nie im Log — sie werden vor dem Schreiben herausgenommen.

Einsehbar ist der Log mit dem Recht system.auditlog, das Kommandant und Administrator haben. Die Ansicht dazu kommt in Phase 1.


8. Wenn etwas nicht geht

Beobachtung Wahrscheinliche Ursache Was hilft
Die Anwendung startet nicht und meldet fehlende Variablen .env unvollständig Die Meldung nennt jede fehlende Variable. Erklärungen dazu stehen in .env.example.
Anmeldung schlägt immer fehl, obwohl das Passwort stimmt Konto nach Fehlversuchen gesperrt Fünf Minuten warten, oder gesperrtBis in der Datenbank zurücksetzen
Listen sind leer, obwohl Daten da sind Kein Mandantenkontext gesetzt Das ist der Schutzmechanismus. Der Zugriff muss über fuerOrganisation() laufen.
Dateien lassen sich nicht hochladen MinIO nicht erreichbar oder Bucket fehlt http://localhost:9011 öffnen; docker compose logs minio-init
Der Knopf für authentik fehlt Issuer, Client-ID oder Secret nicht gesetzt Alle drei sind nötig, sonst wird der Weg ausgeblendet
docker compose up startet Traefik mit Override-Datei wurde nicht mitgeladen In Produktion -f docker-compose.yml angeben

Zustand aller Randsysteme auf einen Blick:

http://localhost:3100/api/health

Antwortet mit 200 und "status": "ok", wenn Datenbank, Objektspeicher und Warteschlange erreichbar sind — sonst mit 503 und der Angabe, welcher Dienst fehlt.


Bilder erneuern

docker compose up -d
npm run dev
npm run screenshots

Die Bilder entstehen in docs/screenshots/, jeweils in heller und dunkler Darstellung, und werden mit eingecheckt — die Anleitung soll auch dann lesbar sein, wenn gerade kein Stack läuft.