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:
co-authored by
Claude Opus 5
parent
b2b31ed00a
commit
4e2daaafd4
+81
-1
@@ -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
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user