Phase 10: Mandantenfaehigkeit

Ein Server, mehrere Wehren. Ein Konto, mehrere Zugehoerigkeiten. Eine
Kreisebene, die zusieht.

Datenmodell und RLS trugen seit Phase 0 mehrere Wehren. Was fehlte, war
alles darueber: bis hierher war die Personenakte zugleich das Anmeldekonto,
und die gehoert genau einer Wehr. Wer in zweien gefuehrt wurde, brauchte
zwei Passwoerter, und die Anmeldung per E-Mail war mehrdeutig.

Neu sind `Benutzer` (das Konto) und `Mitgliedschaft` (die Zugehoerigkeit).
Das Konto traegt bewusst keine Mandantenkennung und kann keine tragen - es
ist der Angelpunkt, an dem ein Mensch zu mehreren Wehren gehoert. Geschuetzt
wird es deshalb ueber Rechte statt ueber RLS, wie `Berechtigung` seit Phase
0. Was es in einer Wehr darf, entscheidet seine Mitgliedschaft.

Die Sitzung behaelt ihre Form und entsteht nur anders - aus der aktiven
Mitgliedschaft statt aus der Person. Von 414 Fundstellen in 61 Dateien
musste dadurch keine angefasst werden. Die eine Ausnahme ist Absicht:
`personId` ist nullbar geworden, weil eine Aufsichtssitzung keine Akte hat,
und der Typechecker hat daraus genau die fuenf Stellen gemacht, an denen
die Kreisaufsicht nichts verloren hat.

Ihre Rechte werden gefiltert statt aufgezaehlt: alles, was `.lesen` heisst,
minus Kasse, Audit-Log, KI-Protokoll und Personenexport. So bekommt sie
neue Leserechte automatisch und neue Schreibrechte nie.

Die Migration ist datenerhaltend und bricht ab, statt einen halben Zustand
zu hinterlassen.

Nebenbei behoben: `db:test-reset` liess die Nachbarwehr stehen, der
Fehlversuch-Test sperrte das gemeinsame Testkonto, ein Testaufbau war
nicht wiederholbar, und die Wartelogik der Bildschirmfotos konnte
ausloesen, bevor eine Seite ueberhaupt geladen war.

581 Unit-Tests und 266 E2E-Tests gruen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Florian Wilde
2026-09-05 13:43:24 +02:00
co-authored by Claude Opus 5
parent 2b53556175
commit ff40437a1a
98 changed files with 3810 additions and 201 deletions
+138 -6
View File
@@ -1,6 +1,6 @@
# Anleitung
Bedienung von FLORIAN, Stand Phase 9 (Version 0.10.0). Die Bilder zeigen die
Bedienung von FLORIAN, Stand Phase 10 (Version 0.11.0). Die Bilder zeigen die
Beispielwehr aus dem Seed und werden mit `npm run screenshots` neu erzeugt.
---
@@ -1986,7 +1986,138 @@ Dezimaltrennzeichen, UTF-8 mit Kennung.
---
## 54. Rollen und was sie dürfen
## 54. Mehrere Wehren auf einem Server
Ein FLORIAN kann mehrere Wehren führen — eine Gemeinde mit drei Ortswehren,
ein Landkreis mit zwanzig. Die Wehren sehen einander dabei **nicht**. Jede
Abfrage ist an eine Wehr gebunden, und zwar in der Datenbank selbst, nicht im
Programm.
### Konto und Personenakte
Zwei verschiedene Dinge, und der Unterschied ist der Kern dieses Kapitels:
| | Was es ist |
|---|---|
| **Konto** | Womit Sie sich anmelden. E-Mail und Passwort. Gehört keiner Wehr. |
| **Personenakte** | Ihr Eintrag in einer Wehr: Dienstgrad, Qualifikationen, Einsätze. |
| **Zuordnung** | Verbindet beides — je Wehr eine. |
Wer nur zu einer Wehr gehört, merkt davon nichts: ein Konto, eine Akte, eine
Zuordnung, und alles sieht aus wie vorher.
Wer zu **zwei** Wehren gehört — aktiv in der einen, Ehrenmitglied in der
anderen —, hat trotzdem nur **ein** Passwort. Zwei Akten, ein Konto.
### Die Wehr wechseln
Steht Ihr Konto bei mehreren Wehren, wird der Name der Wehr in der
Seitenleiste zu einem Auswahlfeld. Ein Klick darauf, und alle Wehren stehen
untereinander — mit dem Hinweis, ob Sie dort Mitglied oder Kreisaufsicht sind.
Nach der Anmeldung sind Sie immer in **Ihrer eigenen** Wehr, nicht in einer
betreuten.
Nach dem Wechsel wird alles neu geladen. Was Sie danach sehen, gehört zur
neuen Wehr — es gibt keinen Zustand, in dem Daten der einen unter dem Namen
der anderen stehen.
---
## 55. Kreisbrandrat und Kreisbrandinspektion
Die Kreisebene bekommt Zugang zu den betreuten Wehren, ohne ihnen anzugehören.
**Sie sieht und ändert nichts.** Das ist keine Einstellung, die jemand
versehentlich anders setzen kann: eine Aufsichtszuordnung bekommt genau die
Leserechte und keines der Schreibrechte, und zwar automatisch auch für Module,
die es noch gar nicht gibt.
Wer als Aufsicht in einer Wehr unterwegs ist, sieht das durchgehend als Zeile
über der Ansicht.
### Was die Aufsicht sieht
Mitglieder, Fahrzeuge, Geräte, Prüfungen, Atemschutz, Einsätze, Übungen,
Qualifikationen, Termine, Wiki, Karte.
Der **Atemschutz** ist dabei der wichtigste Punkt: ob ein Träger tauglich ist,
ist genau die Frage, für die es eine Kreisebene gibt.
### Was sie nicht sieht
| | Warum |
|---|---|
| **Kasse** | Sie gehört dem Verein oder der Kommune, nicht der Kreisaufsicht. |
| **Protokoll** | Wer wann was getan hat, bleibt innerhalb der Wehr. |
| **KI-Protokoll** | Dasselbe. |
| **Personenexport nach DSGVO** | Das Auskunftsrecht erfüllt die Wehr, die die Daten führt. |
### Sie taucht in keiner Mitgliederliste auf
Die Aufsicht hat in der betreuten Wehr **keine Personenakte**. Sie ist also
kein Mitglied, erscheint in keiner Liste, in keiner Stärkemeldung und in
keiner Anwesenheit — und kann als Urheber einer Änderung auch gar nicht
eingetragen werden, weil sie keine macht.
Ist der Kreisbrandinspektor zugleich Kommandant seiner Heimatwehr, hat er dort
ganz normal seine Akte und seine Rollen. Es sind zwei Zuordnungen desselben
Kontos, mehr nicht.
---
## 56. Wehren und Konten verwalten
Unter **Wehren und Konten**. Der Menüpunkt erscheint nur für den, der die
Installation betreibt — nicht für Kommandanten, auch nicht für
Administratoren einer einzelnen Wehr.
> Dieses Merkmal hebt die Trennung zwischen den Wehren auf. Es gehört an so
> wenige Konten wie möglich, im Regelfall an eines.
### Eine Wehr anlegen
Vollständiger Name, Kurzname und eine **Kennung**. Die Kennung steht später
im Terminal und in Dateipfaden und lässt sich nicht mehr ändern — also mit
Bedacht wählen: Kleinbuchstaben, Ziffern, Bindestriche, etwa
`ff-musterhausen`.
Die neue Wehr bekommt sofort ihre Rollen samt Rechten. Ein Konto bekommt sie
nicht: das ist der zweite Schritt.
### Ein Konto anlegen
E-Mail-Adresse und ein erstes Passwort. Die Adresse gilt über alle Wehren
hinweg und ist damit die Anmeldung.
Das Passwort steht im Klartext da, damit Sie es weitergeben können — FLORIAN
verschickt keines. Es gehört nach der ersten Anmeldung geändert.
Gibt es zu der Adresse schon ein Konto, sagt FLORIAN das und legt **kein
zweites** an. Wenn diese Person zu einer weiteren Wehr gehören soll, bekommt
sie eine weitere Zuordnung — genau dafür ist die Trennung da.
### Zuordnen
Konto wählen, **Wehr zuordnen**, dann:
- **Mitglied** — zusätzlich die Personenakte in dieser Wehr wählen. Zur
Auswahl steht, wer noch kein Konto hat: eine Akte gehört zu höchstens einem,
sonst wäre nicht entscheidbar, wer unter ihrem Namen gehandelt hat.
- **Kreisaufsicht** — keine Akte, nur Leserechte.
Jede Zuordnung wird **in der betroffenen Wehr** protokolliert. Dort steht also
nachlesbar, dass jemand von außen Zugang bekommen hat.
### Eine Zuordnung beenden
Über das Papierkorb-Symbol. Die Personenakte in der Wehr bleibt bestehen —
entfernt wird nur der Zugang. Wer ausgetreten ist, wird in der Mitgliederliste
ausgetragen, nicht hier.
---
## 57. 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
@@ -2002,6 +2133,7 @@ kann sie also nachträglich zuschneiden, ohne dass jemand Code ändert.
| **Schriftführer** | Mitglieder pflegen, Einsätze und Berichte erfassen, den Terminkalender führen |
| **Ausbilder** | Übungen und Übungstermine planen, Teilnahme, Anwesenheit und Qualifikationen erfassen |
| **Mitglied** | eigene Daten, Listen lesen, Termine sehen und sich zurückmelden, eigene Benachrichtigungswege einrichten, im Wiki lesen |
| **Kreisebene** | sieht die betreuten Wehren, ändert nichts — siehe [Kapitel 55](#55-kreisbrandrat-und-kreisbrandinspektion) |
| **Terminal** | nur anmelden und erfassen — nie verwalten |
Zwei Dinge sind bewusst so gebaut:
@@ -2020,7 +2152,7 @@ sind nur die Textvorlagen, und die hängen an einem eigenen Recht.
---
## 55. Anmeldung über authentik einrichten
## 58. Anmeldung über authentik einrichten
authentik läuft **getrennt** von FLORIAN und ist nicht Teil dieses Stacks.
@@ -2073,7 +2205,7 @@ ganze Wehr aus.
---
## 56. PIN und Ausweiskarte verwalten
## 59. PIN und Ausweiskarte verwalten
Wie sich am Terminal angemeldet wird, steht in Kapitel 24. Hier geht es darum,
was dahinter liegt.
@@ -2096,7 +2228,7 @@ Huber), PIN `471203`.
---
## 57. Was protokolliert wird
## 60. Was protokolliert wird
Jede schreibende Änderung erzeugt einen Eintrag mit Zeitpunkt, Person,
betroffenem Datensatz und den geänderten Feldern im Vorher-Nachher-Vergleich.
@@ -2121,7 +2253,7 @@ jeweiligen Detailseite sichtbar.
---
## 58. Wenn etwas nicht geht
## 61. Wenn etwas nicht geht
| Beobachtung | Wahrscheinliche Ursache | Was hilft |
|---|---|---|