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>
This commit is contained in:
Florian Wilde
2026-09-03 00:13:53 +02:00
co-authored by Claude Opus 5
commit 845942f36c
84 changed files with 21433 additions and 0 deletions
+237
View File
@@ -0,0 +1,237 @@
# Aufwandsschätzung
Schätzung je Phase, daneben der tatsächliche Aufwand aus dem
[Devlog](DEVLOG.md). Stand: 3. September 2026.
## Wie hier gerechnet wird
Es stehen bewusst **zwei** Größen nebeneinander, weil sie Verschiedenes
aussagen:
| Größe | Bedeutung |
|---|---|
| **Sitzungszeit** | Wie lange Claude tatsächlich gearbeitet hat. Das ist die Zahl, die im Devlog steht, und die Grundlage für die Planung der nächsten Sitzung. |
| **Vergleichsaufwand** | Was eine einzelne Person mit diesem Stack für dasselbe Ergebnis gebraucht hätte, in Personentagen zu 8 Stunden. Das ist die Zahl, die gegenüber der Wehr etwas bedeutet — sie beantwortet „was wäre das sonst wert gewesen". |
Der Vergleichsaufwand ist eine **Schätzung**, keine Messung. Er unterstellt
jemanden, der den Stack kennt, die Feuerwehr-Fachlichkeit aber erst klären
muss — also Recherche zu DGUV-Fristen, FwDV 3 und FwDV 7 einschließt.
Faktoren, die in die Schätzung eingehen:
- **Fachlichkeit** — wie viel muss geklärt werden, bevor gebaut werden kann?
- **Sicherheitsbezug** — Atemschutz und Prüfnachweise brauchen mehr Tests und
mehr Sorgfalt als eine Adressliste.
- **Fremdsysteme** — Gotenberg, Nominatim, tileserver-gl, Ollama, RFID-Leser.
Jedes ist eine eigene Fehlerquelle.
- **Offline und Echtzeit** — die teuersten Anforderungen im ganzen Projekt.
## Übersicht
| Phase | Inhalt | Vergleichsaufwand | Sitzungszeit geschätzt | Sitzungszeit tatsächlich |
|---|---|---:|---:|---:|
| 0 | Fundament | 12–16 PT | — | **1:00 h** |
| 1 | Stammdaten | 10–14 PT | 2,5–3,5 h | offen |
| 2 | Wartung und Prüfung | 18–24 PT | 4,5–6 h | offen |
| 3 | Einsätze und Übungen | 12–16 PT | 3–4 h | offen |
| 4 | Kiosk-PWA mit Offline | 16–22 PT | 4–5,5 h | offen |
| 5 | Atemschutz (FwDV 7) | 14–18 PT | 3,5–4,5 h | offen |
| 6 | Kartenmodule | 14–18 PT | 3,5–4,5 h | offen |
| 7 | Benachrichtigungen und Termine | 10–13 PT | 2,5–3,5 h | offen |
| 8 | Lokale KI | 9–12 PT | 2,5–3 h | offen |
| | **Summe** | **115–153 PT** | **26–34 h** | |
115–153 Personentage entsprechen etwa **6 bis 8 Monaten Vollzeitarbeit** einer
einzelnen Person. Zum Vergleich: eine kommerzielle Feuerwehrverwaltung kostet
je nach Umfang 500 bis 2.500 Euro im Jahr, dauerhaft, mit den Daten beim
Anbieter.
---
## Phase 0 — Fundament
**Vergleichsaufwand: 12–16 PT** · **Tatsächlich: 1:00 h Sitzungszeit**
| Baustein | PT |
|---|---:|
| Monorepo, Werkzeuge, TypeScript, Tailwind, shadcn | 1,5 |
| Docker Compose, Dockerfile, Traefik, Healthchecks | 2,5 |
| Prisma-Schema der Basismodelle | 2,0 |
| Row Level Security samt Rollen- und Rechtekonzept in Postgres | 2,5 |
| Auth.js mit OIDC, lokalem Login und Terminal-Anmeldung | 3,0 |
| storage, audit, warteschlange, Integrationsschnittstellen | 2,0 |
| Basis-Layout, Anmeldeseite, Übersicht, Dark Mode | 1,5 |
| Seed, Vitest, Playwright, Dokumentation | 1,5 |
Das Teuerste war nicht der sichtbare Teil, sondern die Mandantentrennung. RLS
so aufzusetzen, dass Migrationen, Seed und Anmeldung funktionieren und die
Anwendung trotzdem nichts Fremdes sieht, verlangt zwei getrennte
Datenbankzugänge und ein sauberes Verständnis davon, wann welcher greift. Wer
das nachträglich einbaut, zahlt ein Vielfaches.
## Phase 1 — Stammdaten
**Vergleichsaufwand: 10–14 PT**
| Baustein | PT |
|---|---:|
| Modelle: Standort, Geraeteraum, Geraetetyp, Qualifikation | 1,5 |
| Fahrzeug und Geraet um DIN-Typisierung und Lebensdauer erweitern | 1,5 |
| Tabellen mit Sortierung, Filter, Volltextsuche, Spaltenauswahl | 3,0 |
| QR-Code je Gerät, Etikettenbogen als PDF (65 Etiketten, DIN A4) | 1,5 |
| QR-Scan im Browser über die Kamera | 1,0 |
| CSV-/Excel-Import mit Spaltenzuordnung und Vorschau | 2,5 |
| Gerätehistorie aus dem Audit-Log | 1,0 |
| Massenbearbeitung und Tastaturbedienung | 1,0 |
Der Import ist der Posten, der erfahrungsgemäß aus dem Ruder läuft. Jede Wehr
bringt eine andere Excel-Datei mit, und die Vorschau vor dem Übernehmen ist
kein Komfort, sondern die Bedingung dafür, dass die Wehr dem Ergebnis traut.
## Phase 2 — Wartung und Prüfung
**Vergleichsaufwand: 18–24 PT** — die aufwendigste Phase
| Baustein | PT |
|---|---:|
| Modelle: Vorlage, Checklistenpunkt, Termin, Prüfung, Ergebnis, Mangel, Rückruf | 3,0 |
| Fristen-Dashboard mit Gruppierungen | 2,5 |
| Nächtlicher BullMQ-Job: Termine erzeugen, Status setzen, erinnern | 2,5 |
| Prüfungs-Wizard mit Fotoupload je Checklistenpunkt | 3,5 |
| Unterschrift auf Canvas, Touch und Maus | 1,5 |
| PDF-Protokoll über Gotenberg mit Fotos und Signatur | 3,0 |
| Unveränderlichkeit und Korrekturprotokolle mit Verweis | 1,5 |
| Lebensdauerüberwachung und Aussonderungsvorschlag | 1,5 |
| Rückrufe, externe Wartung, Mängel-Workflow | 2,5 |
Hier entsteht der eigentliche Wert: die Software wird zum Nachweis gegenüber
der Unfallkasse. Das heißt aber auch, dass jeder Fehler teuer ist. Die
Unveränderlichkeit abgeschlossener Protokolle ist der Kern — und der Grund,
warum der Audit-Log schon in Phase 0 append-only ist.
## Phase 3 — Einsätze und Übungen
**Vergleichsaufwand: 12–16 PT**
| Baustein | PT |
|---|---:|
| Modelle: Einsatz, Einsatzfahrzeug, Einsatzkraft, Material, Lagemeldung, Übung | 2,0 |
| Schnellerfassung mit Nachtragen | 1,5 |
| Geocoding über self-hosted Nominatim mit Rückfallweg | 1,5 |
| Personalauswahl nach Verfügbarkeit und Qualifikation | 2,0 |
| Stärkeberechnung nach FwDV 3 | 1,0 |
| Einsatzbericht als PDF, Jahresexport für die Gemeinde | 2,0 |
| Statistik: Kategorien, Eintreffzeiten, Beteiligung, Auslastung | 2,5 |
| Externes Portal mit signiertem QR-Link, ohne Login, rate-limited | 2,0 |
Das externe Portal für Fremdwehren ist sicherheitsrelevant: ein Zugang ohne
Anmeldung, der zeitlich begrenzt und mengenbegrenzt sein muss. Der Aufwand
steckt weniger in der Funktion als in der Absicherung.
## Phase 4 — Kiosk-PWA
**Vergleichsaufwand: 16–22 PT**
| Baustein | PT |
|---|---:|
| Eigenes Kiosk-Layout, 64px-Ziele, hoher Kontrast, kein Hover-Zwang | 2,0 |
| Anmeldung per RFID (WebHID), PIN und QR vom Handy | 2,5 |
| Wizards: Wartung, Fahrtenbuch, Mangel, Inventur, Wäsche, Anwesenheit | 4,0 |
| Hallen-Monitor mit DWD-Wetterwarnung | 2,0 |
| Service Worker, App-Shell und Stammdaten offline | 3,0 |
| IndexedDB-Outbox mit Idempotenzschlüssel und Synchronisation | 4,0 |
| Konfliktbehandlung und Konfliktliste für den Administrator | 2,0 |
| Playwright-Tests für den Offline-Fall | 1,5 |
Offline-Fähigkeit mit schreibenden Aktionen ist die technisch schwierigste
Anforderung des ganzen Projekts. Eine Outbox ist schnell gebaut; dass sie
unter Verbindungsabbruch, Doppelklick und parallelem Zugriff von zwei
Terminals nichts verliert und nichts doppelt schreibt, ist die eigentliche
Arbeit. Die Idempotenzschlüssel sind dafür der Schlüssel, nicht die Synchronisation.
## Phase 5 — Atemschutz nach FwDV 7
**Vergleichsaufwand: 14–18 PT**
| Baustein | PT |
|---|---:|
| Modelle: Atemschutzeinsatz, Trupp, Druckmessung, G26, Belastungsübung | 2,0 |
| Truppanlage per RFID, Eingangsdruck | 1,5 |
| Serverseitig autoritative Timer, Socket.IO-Verteilung | 3,5 |
| Rückzugsdruck-Berechnung, Ampel, akustischer Alarm | 2,0 |
| Erinnerung zur Druckabfrage im Intervall | 1,0 |
| Mayday-Knopf mit Protokolleintrag | 1,0 |
| Lückenloses PDF-Protokoll am Einsatz | 1,5 |
| G26.3-Fristen, Belastungsübungen, Tauglichkeitsampel | 2,0 |
| Tests: Reload und Verbindungsabbruch überstehen | 2,0 |
Der Aufwand liegt nicht in der Funktion, sondern im Beweis, dass sie hält. Ein
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.
## Phase 6 — Kartenmodule
**Vergleichsaufwand: 14–18 PT**
| Baustein | PT |
|---|---:|
| MapLibre GL, tileserver-gl, MBTiles fürs Ausrückegebiet | 2,5 |
| Hydranten mit PostGIS, Cluster, Filter, Umkreissuche | 3,0 |
| Import aus GeoJSON und Stadtwerke-CSV | 1,5 |
| Objekte und Feuerwehrpläne nach DIN 14095, Volltextsuche | 3,0 |
| Lagekarte mit taktischen Zeichen nach FwDV 102 als SVG-Set | 3,5 |
| Echtzeit-Sync der Lagekarte zwischen Geräten | 2,0 |
| Wasserförderung: Höhenprofil, Druckverlust, Verstärkerpumpen | 2,5 |
Das SVG-Set für die taktischen Zeichen ist Fleißarbeit, aber unvermeidbar —
fertige Sets sind selten frei verwendbar. Die Wasserförderungsberechnung ist
Physik mit klaren Formeln und deshalb gut testbar.
## Phase 7 — Benachrichtigungen und Termine
**Vergleichsaufwand: 10–13 PT**
| Baustein | PT |
|---|---:|
| Kanalabstraktion: E-Mail, Telegram, ntfy, Web-Push | 2,5 |
| Vorlagen mit Platzhaltern, je Ereignis und Rolle | 2,0 |
| Abonnements je Person | 1,0 |
| Kalender mit Serienterminen und Selbstanmeldung | 3,0 |
| CalDAV-/ICS-Feed je Person mit Token | 1,5 |
| Digitaler Dienstausweis mit signiertem QR und Prüfseite | 2,0 |
Das Grundgerüst der Kanalabstraktion steht bereits aus Phase 0
(`lib/integrations/`), das spart hier etwa einen Personentag.
## Phase 8 — Lokale KI
**Vergleichsaufwand: 9–12 PT**
| Baustein | PT |
|---|---:|
| `lib/ai/` mit OpenAI-kompatiblem Client, abschaltbar | 1,0 |
| Diktat: Aufnahme im Browser, faster-whisper, Transkript | 2,5 |
| Berichtsassistent mit Übernehmen/Verwerfen | 2,0 |
| Wiki mit pgvector, semantische Suche, RAG mit Quellenangabe | 3,5 |
| Belegerfassung über ein Vision-Modell, immer bestätigen | 2,0 |
Der Client aus Phase 0 (`lib/integrations/llm.ts`) ist bereits vorhanden. Die
Kennzeichnungspflicht — jede KI-Ausgabe ist als solche erkennbar und muss
bestätigt werden, bevor sie in ein Dokument mit Nachweischarakter gelangt —
kostet wenig Zeit, ist aber nicht verhandelbar.
---
## Was hier nicht drin ist
**Kassenmodul.** Die Rolle `KASSIER` ist in Phase 0 gefordert und angelegt,
die Rechte `kasse.lesen`, `kasse.bearbeiten` und `kasse.abschluss` stehen
bereit. Ein Kassenmodul kommt in keiner der Phasen 0 bis 8 vor. Geschätzter
Vergleichsaufwand, falls gewünscht: **8–11 PT** für Buchungen, Beiträge,
Rechnungen, Kassenabschluss und Jahresauswertung. Siehe
[ROADMAP.md](ROADMAP.md).
**Betrieb und Einführung.** Datenübernahme aus der Altsoftware, Schulung der
Wehr, Sicherungskonzept, Monitoring: nach Erfahrung noch einmal 15 bis 25
Prozent des Entwicklungsaufwands.