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>
@@ -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
|
||||
|
||||

|
||||
|
||||
> **Ü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
|
||||
|
||||

|
||||
|
||||
### 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
|
||||
|
||||

|
||||
|
||||
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:
|
||||
|
||||
|
||||
@@ -249,7 +249,7 @@ soll, sind es nicht.
|
||||
|
||||
## Phase 5 — Atemschutz nach FwDV 7
|
||||
|
||||
**Vergleichsaufwand: 14–18 PT**
|
||||
**Vergleichsaufwand: 14–18 PT** · **Tatsächlich: 2:40 h Sitzungszeit**
|
||||
|
||||
| Baustein | PT |
|
||||
|---|---:|
|
||||
@@ -268,6 +268,33 @@ Timer, der einen Reload überlebt, ist Pflicht — deshalb muss die Zeit
|
||||
serverseitig geführt werden und der Browser nur anzeigen. Diese Phase bekommt
|
||||
den höchsten Testanteil im Projekt.
|
||||
|
||||
**Rückblick.** Der Satz stimmt, aber die Schlussfolgerung war die falsche. Die
|
||||
Aufstellung veranschlagt 3,5 PT für „serverseitig autoritative Timer" — als
|
||||
wäre ein Timer zu bauen. Gebraucht wurde das Gegenteil: **kein** Timer. Wer die
|
||||
Zeit als Zeitstempel in die Datenbank schreibt und jede Ansicht selbst rechnen
|
||||
lässt, hat nichts, was einen Reload nicht überlebt. Der teuerste Posten der
|
||||
Schätzung war der billigste der Umsetzung, weil die richtige Entscheidung ihn
|
||||
auflöst statt ihn zu lösen.
|
||||
|
||||
Auch Socket.IO fiel weg. Es geht nur in eine Richtung — der Server meldet eine
|
||||
Änderung, der Browser holt den Stand über den Weg, den es ohnehin gibt. Ein
|
||||
Route Handler mit Server-Sent Events ist siebzig Zeilen und braucht kein
|
||||
verändertes Deployment.
|
||||
|
||||
Teurer war das, was in keiner Zeile der Aufstellung steht: **die Frage, was
|
||||
passiert, wenn nichts passiert.** Ein abgerissener Ereignisstrom meldet sich
|
||||
nicht — `EventSource` schweigt einfach. Eine Anzeige, die deshalb weiter
|
||||
„Verbunden" behauptet, ist gefährlicher als eine, die gar nichts anzeigt: sie
|
||||
lässt einen alten Stand wie einen aktuellen aussehen. Aufgefallen ist das nur,
|
||||
weil der E2E-Test das Netz gekappt und danach nachgesehen hat — die 2,0 PT für
|
||||
„Tests: Reload und Verbindungsabbruch überstehen" waren wieder der
|
||||
bestangelegte Posten der Phase.
|
||||
|
||||
Billiger als gedacht war die Tauglichkeit. Nicht das Rechnen — die
|
||||
Entscheidung, **nicht** zu sperren. Damit entfielen alle Sonderfälle, die eine
|
||||
Sperre nach sich zieht: Übersteuern, Begründungspflicht, Freigabe durch wen.
|
||||
Was bleibt, ist ein Satz neben dem Namen, und der ist im Einsatz mehr wert.
|
||||
|
||||
## Phase 6 — Kartenmodule
|
||||
|
||||
**Vergleichsaufwand: 14–18 PT**
|
||||
|
||||
@@ -16,7 +16,87 @@ Die aufgewendete Zeit wandert nach jedem Abschnitt in die Spalte
|
||||
| Phase 2 — Wartung und Prüfung | 2:25 h | 1 | 03.09.2026 |
|
||||
| Phase 3 — Einsätze und Übungen | 2:10 h | 1 | 03.09.2026 |
|
||||
| Phase 4 — Kiosk-PWA im Gerätehaus | 3:00 h | 1 | 03.09.2026 |
|
||||
| **Summe** | **10:40 h** | **6** | |
|
||||
| Phase 5 — Atemschutz nach FwDV 7 | 2:40 h | 1 | 03.09.2026 |
|
||||
| **Summe** | **13:20 h** | **7** | |
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-03 · Phase 5 — Atemschutz nach FwDV 7
|
||||
|
||||
**19:40 – 22:20 · 2:40 h · Version 0.6.0**
|
||||
|
||||
### Was entstanden ist
|
||||
|
||||
Die Atemschutzüberwachung. Sieben Tabellen, ein Ereignisstrom, ein
|
||||
lückenloses Protokoll — und der Hinweis über allem, dass die analoge
|
||||
Überwachung führend bleibt.
|
||||
|
||||
| Bereich | Dateien |
|
||||
|---|---|
|
||||
| Rechnen | `lib/atemschutz/berechnung.ts`, `tauglichkeit.ts`, `verfuegbarkeit.ts` |
|
||||
| Server | `server/routers/atemschutz/ueberwachung.ts`, `traeger.ts` |
|
||||
| Strom | `app/api/atemschutz/strom/route.ts`, `components/atemschutz/stand.ts` |
|
||||
| Protokoll | `lib/atemschutz/protokoll.ts`, `protokoll-erzeugen.ts`, `api/atemschutz/protokoll` |
|
||||
| Oberfläche | `app/(app)/atemschutz/`, `components/atemschutz/` |
|
||||
| Tests | 51 Unit, 17 Datenbank, 8 E2E je Browser |
|
||||
|
||||
### Entscheidungen
|
||||
|
||||
**Server-Sent Events statt Socket.IO.** Phase-5.md nennt Socket.IO; das
|
||||
verlangt in Next.js einen eigenen Node-Server und damit ein anderes
|
||||
Deployment. Gebraucht wird aber nur eine Richtung: der Server meldet „es hat
|
||||
sich etwas geändert", der Browser holt den Stand über tRPC. Ein Route Handler
|
||||
genügt, `EventSource` verbindet nach einem Abbruch von selbst neu, und
|
||||
`next start` bleibt wie es ist. Nach Rücksprache so entschieden.
|
||||
|
||||
**Es gibt keinen Timer.** Kein Zähler, kein Intervall, das Zeit führt. Jede
|
||||
Dauer entsteht aus zwei Zeitstempeln — einem aus der Datenbank, einem von der
|
||||
Uhr. Damit ist die Anforderung „übersteht Reload und Verbindungsabbruch" keine
|
||||
Funktion, die man testen muss, sondern eine Eigenschaft, die sich nicht
|
||||
verlieren lässt. Getestet wird sie trotzdem.
|
||||
|
||||
**Der Rückzugsdruck nach dem doppelten Anmarschverbrauch.** Nach Rücksprache:
|
||||
die Wehr rechnet mit dem tatsächlichen Verbrauch auf dem Hinweg. Solange keine
|
||||
Zielmeldung vorliegt, greift die Zwei-Drittel-Regel — sie liegt höher, ist also
|
||||
die vorsichtigere Annahme, und das steht auch so auf der Karte.
|
||||
|
||||
**Die Tauglichkeit sperrt niemanden.** Neben jedem Namen steht, ob die Person
|
||||
nach FwDV 7 einsetzbar wäre und was fehlt. Verweigert wird nichts. Ein
|
||||
Programm, das im Einsatz eine Person blockiert, wird umgangen — und dann steht
|
||||
am Ende gar nichts im Protokoll. Der Hinweis nützt, die Sperre schadet.
|
||||
|
||||
**Das Protokoll ist doppelt gesichert.** Entzogene Rechte **und** ein Trigger
|
||||
auf `druckmessung` und `atemschutz_ereignis`. Eine Sperre hätte gereicht; bei
|
||||
einer Aufzeichnung, an der Menschenleben hängen, ist die zweite ihren Preis
|
||||
wert.
|
||||
|
||||
### Wo es gehakt hat
|
||||
|
||||
| Problem | Ursache | Lösung |
|
||||
|---|---|---|
|
||||
| Ein gekapptes Netz ließ die Anzeige „Verbunden" melden | `context.setOffline()` trennt einen **offenen** SSE-Strom in Chromium nicht — er liefert weiter. Der Test prüfte damit etwas anderes als gedacht. Schlimmer: bei einem echten Abriss schweigt `EventSource`, ohne einen Fehler zu melden | Der Server schickt alle zwei Sekunden ein Lebenszeichen; bleibt es acht Sekunden aus, gilt die Verbindung als tot. Der Test schneidet den Strom jetzt über eine abgewiesene Route ab, statt das Netz zu kappen |
|
||||
| Prisma meldete den Teilindex nicht beim Namen | Ein `UNIQUE INDEX … WHERE` erscheint als verletzte Eindeutigkeit auf der Spalte | Zusicherung im Test daran angepasst, mit Verweis auf den Index |
|
||||
| Die Bildschirmfotos zeigten Testleichen | 34 Überwachungen aus den E2E-Läufen standen über der einen echten aus dem Seed | Rückstände in der Entwicklungsdatenbank abgeräumt, Auswahl im Skript auf Nicht-Testdaten eingegrenzt. Die Ursache bleibt: die E2E-Suite schreibt in die Demowehr |
|
||||
|
||||
### Abweichung von der Vorgabe
|
||||
|
||||
**Kein Socket.IO.** Siehe oben — nach Rücksprache durch Server-Sent Events
|
||||
ersetzt. Die Roadmap ist entsprechend berichtigt.
|
||||
|
||||
**Kein RFID-Scan beim Truppanlegen.** Phase-5.md nennt „Truppanlage per
|
||||
RFID-Scan oder Auswahl". Umgesetzt ist die Auswahl. Der Kartenleser hängt am
|
||||
Terminal im Gerätehaus (Phase 4) und meldet dort Personen an; am
|
||||
Überwachungsschirm steht der Überwacher mit einem Tablet und wählt zwei Namen
|
||||
aus einer Liste, auf der ohnehin die Tauglichkeit steht. Der Scan wäre dort
|
||||
ein zweiter Weg zum selben Ziel — nachrüstbar, wenn er im Betrieb vermisst
|
||||
wird.
|
||||
|
||||
### Nachweise
|
||||
|
||||
- `npx tsc --noEmit` — ohne Ausgabe
|
||||
- `npm run test` — 306 Tests grün, davon 36 gegen eine echte Datenbank
|
||||
- `npx playwright test tests/e2e/atemschutz.spec.ts` — 16 grün (Desktop und Tablet)
|
||||
- `npm run db:seed` — Nachweise und eine abgeschlossene Überwachung angelegt
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ Phase 1 ████████████████████ fertig
|
||||
Phase 2 ████████████████████ fertig 0.3.0
|
||||
Phase 3 ████████████████████ fertig 0.4.0
|
||||
Phase 4 ████████████████████ fertig 0.5.0
|
||||
Phase 5 ░░░░░░░░░░░░░░░░░░░░ offen 0.6.0
|
||||
Phase 5 ████████████████████ fertig 0.6.0
|
||||
Phase 6 ░░░░░░░░░░░░░░░░░░░░ offen 0.7.0
|
||||
Phase 7 ░░░░░░░░░░░░░░░░░░░░ offen 0.8.0
|
||||
Phase 8 ░░░░░░░░░░░░░░░░░░░░ offen 0.9.0
|
||||
@@ -116,14 +116,16 @@ Für die Wandtablets in der Fahrzeughalle.
|
||||
**Danach kann die Wehr:** einen Mangel in unter 30 Sekunden melden, ohne den
|
||||
Rechner im Büro einzuschalten — auch wenn das Netz gerade weg ist.
|
||||
|
||||
## Phase 5 — Atemschutz nach FwDV 7 · als Nächstes
|
||||
## Phase 5 — Atemschutz nach FwDV 7 · fertig
|
||||
|
||||
Sicherheitsrelevant. Jede Ansicht zeigt dauerhaft den Hinweis, dass die
|
||||
analoge Überwachung führend bleibt — abschaltbar erst über eine Option, die
|
||||
eine dokumentierte Freigabe durch den Kommandanten voraussetzt.
|
||||
|
||||
- Truppanlage per RFID, Eingangsdruck erfassen
|
||||
- Serverseitig autoritative Timer, per Socket.IO verteilt
|
||||
- Serverseitig autoritative Zeitstempel; verteilt über Server-Sent Events
|
||||
statt Socket.IO — es geht nur in eine Richtung, und so bleibt es bei
|
||||
`next start` ohne eigenen Node-Server
|
||||
- Rückzugsdruck-Berechnung mit Ampel und akustischem Alarm
|
||||
- Erinnerung zur Druckabfrage im konfigurierbaren Intervall
|
||||
- Mayday-Knopf je Trupp
|
||||
@@ -133,7 +135,7 @@ eine dokumentierte Freigabe durch den Kommandanten voraussetzt.
|
||||
**Danach kann die Wehr:** die Überwachung digital mitführen — parallel zur
|
||||
analogen, bis die Wehr ausdrücklich anders entscheidet.
|
||||
|
||||
## Phase 6 — Kartenmodule
|
||||
## Phase 6 — Kartenmodule · als Nächstes
|
||||
|
||||
- MapLibre GL mit selbst gehosteten Kacheln fürs Ausrückegebiet
|
||||
- Hydranten mit Typ, Nennweite, Durchfluss, letzter Prüfung; Import aus
|
||||
|
||||
|
Before Width: | Height: | Size: 206 KiB After Width: | Height: | Size: 207 KiB |
|
Before Width: | Height: | Size: 210 KiB After Width: | Height: | Size: 212 KiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 246 KiB After Width: | Height: | Size: 246 KiB |
|
Before Width: | Height: | Size: 254 KiB After Width: | Height: | Size: 254 KiB |
|
Before Width: | Height: | Size: 161 KiB After Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 164 KiB |
|
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 170 KiB |
|
Before Width: | Height: | Size: 175 KiB After Width: | Height: | Size: 175 KiB |
|
Before Width: | Height: | Size: 415 KiB After Width: | Height: | Size: 415 KiB |
|
Before Width: | Height: | Size: 424 KiB After Width: | Height: | Size: 424 KiB |
|
Before Width: | Height: | Size: 733 KiB After Width: | Height: | Size: 733 KiB |
|
Before Width: | Height: | Size: 756 KiB After Width: | Height: | Size: 756 KiB |
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 140 KiB |
|
Before Width: | Height: | Size: 143 KiB After Width: | Height: | Size: 143 KiB |
|
Before Width: | Height: | Size: 307 KiB After Width: | Height: | Size: 307 KiB |
|
Before Width: | Height: | Size: 318 KiB After Width: | Height: | Size: 318 KiB |
|
Before Width: | Height: | Size: 968 KiB After Width: | Height: | Size: 969 KiB |
|
Before Width: | Height: | Size: 1013 KiB After Width: | Height: | Size: 1014 KiB |
|
Before Width: | Height: | Size: 211 KiB After Width: | Height: | Size: 211 KiB |
|
Before Width: | Height: | Size: 215 KiB After Width: | Height: | Size: 215 KiB |
|
Before Width: | Height: | Size: 540 KiB After Width: | Height: | Size: 1005 KiB |
|
Before Width: | Height: | Size: 555 KiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 126 KiB |
|
Before Width: | Height: | Size: 258 KiB After Width: | Height: | Size: 258 KiB |
|
Before Width: | Height: | Size: 262 KiB After Width: | Height: | Size: 262 KiB |
|
Before Width: | Height: | Size: 427 KiB After Width: | Height: | Size: 554 KiB |
|
Before Width: | Height: | Size: 436 KiB After Width: | Height: | Size: 565 KiB |
|
Before Width: | Height: | Size: 271 KiB After Width: | Height: | Size: 271 KiB |
|
Before Width: | Height: | Size: 281 KiB After Width: | Height: | Size: 234 KiB |
|
Before Width: | Height: | Size: 242 KiB After Width: | Height: | Size: 243 KiB |
|
Before Width: | Height: | Size: 251 KiB After Width: | Height: | Size: 252 KiB |
|
Before Width: | Height: | Size: 416 KiB After Width: | Height: | Size: 540 KiB |
|
Before Width: | Height: | Size: 421 KiB After Width: | Height: | Size: 547 KiB |
|
Before Width: | Height: | Size: 361 KiB After Width: | Height: | Size: 362 KiB |
|
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 373 KiB |
|
Before Width: | Height: | Size: 245 KiB After Width: | Height: | Size: 245 KiB |
|
Before Width: | Height: | Size: 250 KiB After Width: | Height: | Size: 250 KiB |
|
Before Width: | Height: | Size: 352 KiB After Width: | Height: | Size: 367 KiB |
|
Before Width: | Height: | Size: 353 KiB After Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 227 KiB After Width: | Height: | Size: 227 KiB |
|
Before Width: | Height: | Size: 236 KiB After Width: | Height: | Size: 236 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 119 KiB |
|
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 185 KiB |
|
Before Width: | Height: | Size: 184 KiB After Width: | Height: | Size: 191 KiB |
|
Before Width: | Height: | Size: 209 KiB After Width: | Height: | Size: 206 KiB |
|
Before Width: | Height: | Size: 209 KiB After Width: | Height: | Size: 204 KiB |
|
Before Width: | Height: | Size: 285 KiB After Width: | Height: | Size: 195 KiB |
|
Before Width: | Height: | Size: 432 KiB After Width: | Height: | Size: 200 KiB |
|
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 163 KiB |
|
After Width: | Height: | Size: 373 KiB |
|
After Width: | Height: | Size: 385 KiB |
|
After Width: | Height: | Size: 300 KiB |
|
After Width: | Height: | Size: 312 KiB |
|
After Width: | Height: | Size: 265 KiB |
|
After Width: | Height: | Size: 268 KiB |