Atemschutzueberwachung nach FwDV 7 ergaenzen

Phase 5: das sicherheitsrelevanteste Modul des Projekts. Ueber jeder Ansicht
steht dauerhaft, dass die analoge Atemschutzueberwachung fuehrend bleibt —
abschaltbar nur zusammen mit der Fundstelle einer Freigabe des Kommandanten.

Es gibt keinen Timer. In der Datenbank stehen Zeitstempel; wie lange ein
Trupp unter Atemschutz ist, rechnet jede Ansicht bei jedem Bild neu aus.
Damit ist die Anforderung "uebersteht Neuladen und Verbindungsabbruch" keine
Funktion, die gelingen muss, sondern eine Eigenschaft, die sich nicht
verlieren laesst. Server und Browser rechnen mit denselben Funktionen.

Der Rueckzugsdruck folgt dem doppelten Anmarschverbrauch: was der Weg hinein
gekostet hat, kostet der Weg zurueck noch einmal. Bis der Trupp das
Einsatzziel meldet, greift die Zwei-Drittel-Regel — sie liegt hoeher und ist
damit die vorsichtigere Annahme.

Das Protokoll ist doppelt gesichert: entzogene Rechte und ein Trigger auf
druckmessung und atemschutz_ereignis. Ein Fehler wird durch einen neuen
Eintrag richtiggestellt, nicht durch Aendern.

Verteilt wird ueber Server-Sent Events statt Socket.IO — es geht nur in eine
Richtung, und so bleibt das Deployment bei "next start".

Behoben: ein abgerissener Ereignisstrom meldete sich nicht. Die Anzeige haette
weiter "Verbunden" behauptet, waehrend der Draht tot war. Jetzt gilt Stille
von acht Sekunden als Abriss. Dazu zwei Altlasten: der Navigationseintrag
"Protokoll" fuehrte ins Leere, und die Startseite stand noch auf Phase 1.

68 neue Tests (51 Unit, 17 gegen eine echte Datenbank, 8 E2E je Browser).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Florian Wilde
2026-09-03 23:19:05 +02:00
co-authored by Claude Opus 5
parent b2b31ed00a
commit 4e2daaafd4
107 changed files with 7214 additions and 40 deletions
+169 -10
View File
@@ -1,10 +1,9 @@
# Anleitung
Bedienung von FLORIAN, Stand Phase 4 (Version 0.5.0). Die Bilder zeigen die
Bedienung von FLORIAN, Stand Phase 5 (Version 0.6.0). Die Bilder zeigen die
Beispielwehr aus dem Seed und werden mit `npm run screenshots` neu erzeugt.
> Atemschutz und Karten kommen in den folgenden Phasen dazu. Siehe
> [ROADMAP.md](ROADMAP.md).
> Die Kartenmodule kommen in Phase 6 dazu. Siehe [ROADMAP.md](ROADMAP.md).
---
@@ -603,7 +602,7 @@ Bericht — wird später nachgetragen. Der Einsatz bekommt sofort eine
fortlaufende Nummer im Format `JJJJ-NNNN`.
**Koordinaten** lassen sich über „Koordinaten suchen" ermitteln, wenn die Wehr
einen eigenen Nominatim betreibt (Kapitel 30). Ohne den bleibt das Feld leer —
einen eigenen Nominatim betreibt (Kapitel 34). Ohne den bleibt das Feld leer —
das ist in Ordnung, die Karte kommt in Phase 6.
---
@@ -945,7 +944,163 @@ nützt eine Minute später nichts mehr.
---
## 30. Adressen zu Koordinaten (Nominatim)
## 30. Atemschutz — was das Modul ist und was nicht
![Atemschutzübersicht](screenshots/31-atemschutz-light.png)
> **Über jeder Ansicht dieses Moduls steht:**
> *Ergänzendes System — die analoge Atemschutzüberwachung bleibt führend.*
Das ist kein Kleingedrucktes. Die Überwachung, die im Ernstfall zählt, hängt am
Fahrzeug und wird mit Stift geführt. FLORIAN schreibt mit, rechnet mit und
druckt am Ende ein Protokoll — aber wenn dieses Tablet ausfällt, läuft der
Einsatz unverändert weiter.
Der Hinweis lässt sich abschalten, aber nur zusammen mit einem Beleg:
```bash
# .env
ATEMSCHUTZ_HINWEIS=false
ATEMSCHUTZ_FREIGABE=Kommandantenbeschluss vom 12.03.2026
```
Fehlt die Fundstelle, bleibt der Hinweis stehen — egal was in
`ATEMSCHUTZ_HINWEIS` steht. Eine Freigabe ohne Beschluss ist keine. Ist er
abgeschaltet, verschwindet er nicht spurlos: dann steht dort, worauf sich die
Freigabe stützt, und dasselbe steht später im Protokoll.
Die Startseite zeigt die Zahl, nach der im Einsatz als Erstes gefragt wird:
**wie viele Atemschutzgeräteträger heute einsetzbar sind** — und wie viele
davon knapp davor stehen, es nicht mehr zu sein.
---
## 31. Eine Überwachung führen
![Überwachungsschirm](screenshots/33-atemschutz-ueberwachung-light.png)
### Eröffnen
Auf `/atemschutz` genügt eine Bezeichnung — „Zimmerbrand Hauptstraße 12". Die
Zuordnung zu einem Einsatz lässt sich nachtragen; im Ernstfall wird zuerst
überwacht und später sortiert.
### Trupp anlegen
Zwei oder drei Personen, für jede der Eingangsdruck vom Manometer, eine davon
Truppführer. Neben jedem Namen steht, ob die Person nach FwDV 7 einsetzbar ist
und was gegebenenfalls fehlt.
> **Verweigert wird nichts.** Im Einsatz entscheidet der Einheitsführer. Ein
> Programm, das ihm im entscheidenden Moment eine Person sperrt, wird umgangen —
> und dann steht am Ende gar nichts im Protokoll. Der Hinweis nützt, die Sperre
> schadet.
### Was auf der Karte steht
| Anzeige | Bedeutung |
|---|---|
| **unter Atemschutz** | Zeit seit dem Einstieg — läuft, solange der Trupp drin ist |
| **niedrigster Druck** | Der ungünstigste Wert im Trupp. Der Trupp geht gemeinsam zurück |
| **Rückzug bei** | Der errechnete Rückzugsdruck |
Die Farbe der Karte ist die Ampel, und daneben steht immer der Text dazu:
„im Rahmen", „Rückzugsdruck bald erreicht", „Rückzugsdruck erreicht — Trupp
zurückziehen". Gelb kommt schon zehn Prozent vor der Grenze — der Trupp soll
losgehen, bevor der Wert erreicht ist.
### Der Rückzugsdruck
Gerechnet wird nach dem **doppelten Anmarschverbrauch**:
```
Rückzug = 2 × (Eingangsdruck − Druck am Einsatzziel) + Warndruck + Zuschlag
```
Dafür meldet der Trupp einmal, wenn er das Einsatzziel erreicht hat — dafür ist
der Knopf **„Einsatzziel erreicht"** da. Bis dahin steht ein vorläufiger Wert
nach der Zwei-Drittel-Regel; er liegt höher und ist damit die vorsichtigere
Annahme. Die Karte sagt das auch dazu.
Beispiel: 300 bar rein, 260 bar am Ziel — 40 bar für den Hinweg, also 80 für
hin und zurück, plus 55 bar Warndruck und 10 bar Zuschlag: **Rückzug bei
145 bar.**
### Druckabfrage
Alle Werte des Trupps in einer Zeile, ein Knopf. Bleibt eine Meldung aus, steht
nach `ATEMSCHUTZ_ABFRAGE_INTERVALL` Sekunden (Vorgabe zehn Minuten) ein
deutlicher Hinweis auf der Karte — gerechnet ab der letzten Meldung, nicht ab
dem Einstieg.
### Mayday
Ein Knopf je Trupp. Er ändert nichts an der Lage: er hält fest, wann es losging,
macht es auf jedem Bildschirm sichtbar und lässt einen Ton hören. Aufgehoben
wird er **ausdrücklich**, nicht durch Wegklicken — und beides steht im
Protokoll.
### Beenden
Geht erst, wenn alle Trupps als draußen gemeldet sind. Das ist keine Schikane:
eine beendete Überwachung mit einem Trupp, der noch drin steht, wäre die
gefährlichste Zeile im ganzen Protokoll.
---
## 32. Was passiert, wenn die Technik streikt
Die wichtigste Eigenschaft dieser Ansicht ist, dass man ihr nichts anhaben
kann. Der Grund dafür ist einfach: **es gibt keinen Timer.** In der Datenbank
steht, wann der Trupp eingestiegen ist; wie lange er drin ist, rechnet der
Bildschirm jede Sekunde neu aus.
| Was passiert | Was Sie sehen |
|---|---|
| Seite neu laden | Dieselbe Zeit läuft weiter |
| Zweites Tablet daneben | Dieselbe Zeit, ohne Abgleich |
| WLAN bricht ab | Die Uhr läuft weiter; oben steht **Verbindung unterbrochen** |
| Server neu gestartet | Nach der ersten Antwort ist alles wieder da |
Oben rechts steht dauerhaft, ob die Verbindung steht. Das ist Absicht: wer
nicht sieht, dass der Draht weg ist, hält einen alten Stand für den aktuellen.
Meldet sich der Server acht Sekunden lang nicht, springt die Anzeige auf
„unterbrochen" — auch dann, wenn der Browser selbst keinen Fehler meldet.
Ist die Verbindung weg, bleibt die Ansicht bedienbar; sie fragt weiter im Takt
nach und holt auf, sobald es wieder geht.
---
## 33. Nachweise und Tauglichkeit
![Nachweise](screenshots/32-atemschutz-nachweise-light.png)
Drei Nachweise müssen **gleichzeitig** gelten, sonst ist jemand nicht
einsetzbar:
| Nachweis | Frist | Wo erfasst |
|---|---|---|
| **G26.3** | drei Jahre, ab 50 Jahren eines | `/atemschutz/nachweise` |
| **Belastungsübung** | jährlich | dort, für die ganze Gruppe auf einmal |
| **Einsatzübung unter Atemschutz** | jährlich | dort — ein echter Einsatz zählt ebenso |
Dazu die Qualifikation als Atemschutzgeräteträger aus Kapitel 9.
Das Ablaufdatum der G26 wird nach dem Alter vorgeschlagen; was auf der
Bescheinigung steht, gilt und lässt sich überschreiben. Eine Untersuchung mit
dem Ergebnis „Nachuntersuchung" oder „nicht tauglich" zählt nicht als Nachweis.
In der Übersicht steht neben jedem Namen **im Klartext**, was fehlt — „G26.3 ist
abgelaufen", „Belastungsübung in diesem Jahr fehlt". Eine rote Ampel ohne
Begründung hilft am Fahrzeug niemandem.
Drei Monate vor Ablauf der G26 wechselt die Ampel auf Gelb: die Person ist
weiter einsetzbar, aber es wird Zeit für einen Termin.
---
## 34. Adressen zu Koordinaten (Nominatim)
FLORIAN löst Einsatzadressen nur auf, wenn die Wehr einen **eigenen** Nominatim
betreibt:
@@ -965,7 +1120,7 @@ GEOCODING_LAENDER=de,at,ch
Ohne Konfiguration bleibt die Suche leer. Koordinaten lassen sich dann von Hand
eintragen oder weglassen.
## 31. Rollen und was sie dürfen
## 35. 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
@@ -994,7 +1149,7 @@ Das Terminal selbst ist nur die Tür.
---
## 32. Anmeldung über authentik einrichten
## 36. Anmeldung über authentik einrichten
authentik läuft **getrennt** von FLORIAN und ist nicht Teil dieses Stacks.
@@ -1047,7 +1202,7 @@ ganze Wehr aus.
---
## 33. PIN und Ausweiskarte verwalten
## 37. PIN und Ausweiskarte verwalten
Wie sich am Terminal angemeldet wird, steht in Kapitel 24. Hier geht es darum,
was dahinter liegt.
@@ -1070,7 +1225,7 @@ Huber), PIN `471203`.
---
## 34. Was protokolliert wird
## 38. Was protokolliert wird
Jede schreibende Änderung erzeugt einen Eintrag mit Zeitpunkt, Person,
betroffenem Datensatz und den geänderten Feldern im Vorher-Nachher-Vergleich.
@@ -1095,7 +1250,7 @@ jeweiligen Detailseite sichtbar.
---
## 35. Wenn etwas nicht geht
## 39. Wenn etwas nicht geht
| Beobachtung | Wahrscheinliche Ursache | Was hilft |
|---|---|---|
@@ -1115,6 +1270,10 @@ jeweiligen Detailseite sichtbar.
| Die Leiste zeigt dauerhaft wartende Änderungen | Server erreichbar, aber der Vorgang wird abgelehnt | Über „anzeigen" den Grund lesen; landet er als Konflikt, steht er unter `/terminal` |
| „Der Code wurde nicht erkannt" beim QR-Login | Marke älter als 60 Sekunden | Auf dem Handy die Seite Anmeldemarke offen halten, sie erneuert den Code selbst |
| Der Monitor zeigt keine Wetterwarnung | `WETTER_ENABLED` aus oder `DWD_WARNCELL` leer | Beides setzen; ohne Warnzelle wird nichts abgerufen |
| Der Sicherheitshinweis im Atemschutz bleibt trotz `ATEMSCHUTZ_HINWEIS=false` | `ATEMSCHUTZ_FREIGABE` ist leer | Fundstelle der Freigabe eintragen — ohne sie bleibt der Hinweis absichtlich stehen |
| Die Überwachung lässt sich nicht beenden | Ein Trupp ist noch nicht als draußen gemeldet | Trupp abmelden, dann beenden. Die Meldung nennt die Anzahl |
| Oben steht „Verbindung unterbrochen", obwohl das Netz da ist | Der Ereignisstrom wurde von einem Proxy gepuffert oder gekappt | Die Ansicht arbeitet weiter; bei einem Reverse Proxy `X-Accel-Buffering: no` durchreichen |
| Das Atemschutzprotokoll fehlt | Die Überwachung ist noch nicht beendet | Ein Protokoll entsteht erst mit dem Ende — vorher wäre es unvollständig und sähe vollständig aus |
Zustand aller Randsysteme auf einen Blick: