Files
florian.wilde 3b20abcb23
Pruefung / pruefung (push) Canceled after 0s
Pruefung / oberflaeche (push) Canceled after 0s
Version 1.0.0 — Freigabe für den Echtbetrieb (#17)
2026-09-06 20:08:16 +00:00

373 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Roadmap
Was FLORIAN wann kann. Die Phasen kommen aus `Phase-0.md` bis `Phase-8.md` und
werden **einzeln** abgearbeitet — nie zwei in einem Schritt.
Aufwände je Phase: [AUFWANDSSCHAETZUNG.md](AUFWANDSSCHAETZUNG.md).
Versionszuordnung: [VERSIONIERUNG.md](VERSIONIERUNG.md).
## Stand
```
Phase 0 ████████████████████ fertig 0.1.0
Phase 1 ████████████████████ fertig 0.2.0
Phase 2 ████████████████████ fertig 0.3.0
Phase 3 ████████████████████ fertig 0.4.0
Phase 4 ████████████████████ fertig 0.5.0
Phase 5 ████████████████████ fertig 0.6.0
Phase 6 ████████████████████ fertig 0.7.0
Phase 7 ████████████████████ fertig 0.8.0
Phase 8 ████████████████████ fertig 0.9.0
Phase 9 ████████████████████ fertig 0.10.0
Phase 10 ████████████████████ fertig 0.11.0
Phase 11 ████████████████████ fertig 0.12.0
Freigabe ████████████████████ fertig 1.0.0
```
---
## Phase 0 — Fundament · fertig
Alles, worauf der Rest aufsetzt.
- Monorepo, Docker Compose mit Traefik, PostgreSQL 17 + PostGIS, Redis, MinIO,
Gotenberg
- Mandantentrennung über Row Level Security, geprüft gegen eine echte Datenbank
- Append-only-Audit-Log mit kontrolliertem Aufbewahrungslauf
- Anmeldung: OIDC gegen authentik, lokaler Passwort-Login, Terminal per
PIN und RFID
- 9 Rollen, 38 Einzelrechte, zentral in `lib/authz.ts`
- Dateiablage in MinIO, Zugriff nur über `lib/storage.ts`
- Basis-Layout mit Seitenleiste und dunkler Darstellung
- Seed mit einer vollständigen Beispielwehr
## Phase 1 — Stammdaten · fertig
Die Wehr trägt ein, was sie hat.
- Standort, Geraeteraum, Geraetetyp, Qualifikationstyp, Qualifikation
- Fahrzeug um Fahrgestellnummer, DIN-Typ und TÜV-Termin erweitern
- Geraet um Lebensdauerkategorie und die Zuordnung
„Standort ODER Fahrzeug + Geräteraum" erweitern
- Tabellen mit Sortierung, Filter, Volltextsuche und Spaltenauswahl
- QR-Code je Gerät, Etikettenbogen als PDF (DIN A4, 65 Etiketten)
- QR-Scan über die Kamera öffnet direkt die Gerätedetailseite
- CSV-/Excel-Import mit Spaltenzuordnung und Vorschau
- Gerätehistorie aus dem Audit-Log
- Qualifikationen mit Ablaufwarnung auf der Übersicht
- Formular zum Anlegen und Bearbeiten eines einzelnen Geräts, mit
Fristenvorschau beim Ausfüllen
**Danach kann die Wehr:** ihren Bestand vollständig führen und jedes Gerät per
QR-Code am Regal wiederfinden.
## Phase 2 — Wartung und Prüfung · fertig
Das wichtigste Modul. Ab hier ersetzt FLORIAN den Ordner.
- Wartungsvorlagen mit Checklisten, Intervall und Vorwarnzeit
- Fristen-Dashboard: überfällig / diese Woche / diesen Monat / nächste 90 Tage,
gebündelt nach Fahrzeug, Standort, Gerätetyp oder Zuständigem
- Nächtlicher Lauf erzeugt Termine, zieht den Gerätestatus nach und erinnert bei
T-30, T-7, T-0 und einmal bei Überfälligkeit
- Prüfwizard mit Foto je Checklistenpunkt, Zeiterfassung und Unterschrift auf
dem Zeichenfeld
- PDF-Prüfprotokoll über Gotenberg, unveränderlich in MinIO — die Sperre setzt
ein Datenbanktrigger durch, nicht der Anwendungscode
- Korrekturen erzeugen ein neues Protokoll mit Verweis auf das alte
- Lebensdauerüberwachung mit Aussonderungsvorschlag
- Rückrufe suchen betroffene Geräte über Bauart, Modell, Seriennummernbereich
und Herstellungszeitraum
- Mängel-Workflow: melden → zugewiesen → in Arbeit → behoben, mit
Gerätesperre bei kritischen Mängeln
- Externe Wartung: Fachfirma, Kosten und Fremdprotokoll als PDF
**Danach kann die Wehr:** einen DGUV-Nachweis führen, der einer Prüfung durch
die Unfallkasse standhält.
## Phase 3 — Einsätze und Übungen · fertig
- Einsatz mit allen Zeitstempeln: alarmiert, ausgerückt, eingetroffen,
Einsatzende, eingerückt, einsatzbereit
- Schnellerfassung: Stichwort, Adresse, Fahrzeuge — Rest später
- Geocoding über self-hosted Nominatim
- Personalauswahl mit Vorschlag nach Verfügbarkeit und Qualifikation
- Stärkeberechnung nach FwDV 3
- Einsatzbericht als PDF, Jahresexport für die Gemeinde
- Statistik: Kategorien, Eintreffzeiten, Beteiligung, Fahrzeugauslastung
- Externes Portal für Fremdwehren über signierten QR-Link, ohne Anmeldung
**Danach kann die Wehr:** ihre Jahresstatistik auf Knopfdruck erzeugen.
## Phase 4 — Kiosk-PWA · fertig
Für die Wandtablets in der Fahrzeughalle.
- Eigenes Layout: große Kacheln, mindestens 64px, mit Handschuhen bedienbar
- Anmeldung per RFID, PIN oder QR vom Handy, Abmeldung nach Untätigkeit
(`KIOSK_IDLE_TIMEOUT`, Vorgabe 120 Sekunden)
- Wizards: Fahrtenbuch, Mangel melden, Inventur, Wäsche, Anwesenheit. Die
Prüfung bleibt beim Wizard aus Phase 2 — Checkliste, Fotos und Unterschrift
lassen sich nicht sinnvoll in eine Warteschlange legen; die Kachel sagt
„braucht Netz"
- Hallen-Monitor: Vollbild mit Terminen, überfälligen Prüfungen,
Fahrzeugstatus, Wetterwarnung
- Offline-Betrieb mit IndexedDB-Outbox, Idempotenzschlüssel und
Konfliktliste für alles, was sich beim Nachtragen nicht anwenden lässt
**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 · 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 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
- Lückenloses PDF-Protokoll am Einsatz
- G26.3-Fristen, Belastungsübungen, Tauglichkeitsübersicht
**Danach kann die Wehr:** die Überwachung digital mitführen — parallel zur
analogen, bis die Wehr ausdrücklich anders entscheidet.
## Phase 6 — Kartenmodule · fertig
- MapLibre GL mit selbst gehosteten Kacheln fürs Ausrückegebiet
- Hydranten mit Typ, Nennweite, Durchfluss, letzter Prüfung; Import aus
GeoJSON und Stadtwerke-CSV
- Objekte und Feuerwehrpläne nach DIN 14095, vom Einsatz aus erreichbar
- Lagekarte mit taktischen Zeichen nach FwDV 102, Abgleich über denselben
Ereignisstrom wie der Atemschutz
- Wasserförderung: Druckverlust, Verstärkerpumpen, druckbares Schema
**Danach kann die Wehr:** auf der Anfahrt sehen, wo der nächste Hydrant liegt
und was ihn hergibt.
## Phase 7 — Benachrichtigungen und Termine · fertig
Die Wehr weiß, wann der nächste Dienst ist — ohne dass jemand eine Rundmail
tippt.
- Terminkalender mit Dienst, Übung, Lehrgang, Arbeitsdienst, Veranstaltung und
Sitzung. Serientermine werden ausgeschrieben, nicht als Regel gespeichert.
- Selbstanmeldung mit Platzbegrenzung und einer Warteliste, die von selbst
nachrückt. Absage mit Grund, wahlweise für alle folgenden Termine einer Serie.
- Anwesenheitsliste über alle aktiven Mitglieder — zum Abhaken am Tablet oder
zum Ausdrucken. Zusage und Anwesenheit sind getrennt.
- Vier Kanäle hinter Schnittstellen: E-Mail (echtes SMTP statt Platzhalter),
ntfy (selbst gehostet), Telegram, Web-Push. Was das Netz der Wehr verlässt,
bekommt nur die Kurzfassung.
- Vorlagen je Ereignis und Kanal mit Platzhaltern, Vorschau und eingebautem
Standardtext für alles.
- ICS-Abonnement je Person, Token nur als Hash gespeichert, einzeln widerrufbar.
- Digitaler Dienstausweis: signierter QR, fünf Minuten gültig, Prüfseite ohne
Anmeldung.
**Danach kann die Wehr:** ihren Jahresplan führen, Rückmeldungen einsammeln,
Anwesenheit nachweisen und jedes Mitglied auf dem Weg erreichen, den es selbst
gewählt hat.
### Kein CalDAV
CalDAV ist ein Schreib-Lese-Protokoll mit Rechteverwaltung und
Konfliktauflösung. Gebraucht wird hier nur Lesen — die Termine entstehen in
FLORIAN, nicht im Kalender des Anwenders. Dafür genügt eine Adresse, die eine
ICS-Datei ausliefert; jeder Kalender kann das. CalDAV wäre ein Vielfaches an
Aufwand für dieselbe Wirkung.
### Warum kein WhatsApp
Die WhatsApp Business API kostet je Konversation und verlangt einen
zugelassenen Anbieter dazwischen — laufende Kosten für eine Wehr, die keinen
Etat dafür hat. Der schwerere Grund ist der Datenschutz: die Nachrichten liefen
über Server von Meta, die Wehr müsste einen Vertrag zur Auftragsverarbeitung
schließen, und die gewöhnliche App gleicht zusätzlich das Telefonbuch ab. Das
verträgt sich nicht mit einer Anwendung, die bewusst im Gerätehaus steht.
Telegram, ntfy und Web-Push decken denselben Bedarf ab, ntfy sogar vollständig
selbst gehostet.
Wer seine Wehr trotzdem über WhatsApp erreichen will, hat den Weg schon: die
Gruppe, die es ohnehin gibt. Ein Link zum Termin hineinkopiert kostet nichts.
## Phase 8 — Lokale KI · fertig
Alles gegen selbst betriebene Modelle, kein externer Anbieter, komplett
abschaltbar.
- Wiki mit pgvector: Dienstvorschriften und Ausbildungsunterlagen als Markdown,
Wortsuche und semantische Suche nebeneinander, Antwort mit Fundstellenangabe
- Diktat: Aufnahme im Browser, faster-whisper, Transkript als Vorschlag
- Berichtsassistent: aus Stichpunkten ein Einsatzberichtsentwurf, immer mit
Übernehmen/Verwerfen
- Belegerfassung: Foto einer Quittung, Vorschlag für Betrag, Datum, Händler —
nicht Erkanntes bleibt leer statt geraten zu werden
- KI-Protokoll und Audit-Log-Ansicht nebeneinander
- Eigenes Postgres-Image mit PostGIS **und** pgvector
**Danach kann die Wehr:** ihr Wissen ablegen und befragen, Berichte diktieren
statt tippen und Belege fotografieren statt abzuschreiben — ohne dass eine
Zeile Text das Gerätehaus verlässt.
### Die Regel, die den Aufbau bestimmt
Jede KI-Ausgabe ist zuerst ein eigener Datensatz und nicht ein Feld im
Zieldokument. Sie ist gekennzeichnet, sie steht daneben statt mittendrin, und
sie braucht eine Entscheidung, bevor etwas mit ihr geschieht. Die Datenbank
hält gegen: Eingabe, Ausgabe und Modell sind unveränderlich, gelöscht wird
nicht, und über einen Vorschlag wird genau einmal entschieden.
Ohne das ließe sich in einem Jahr nicht mehr sagen, welcher Satz in einem
Einsatzbericht von einem Menschen stammt.
### Kein Rückfall auf einen Anbieter
Fehlen die Container, fehlt die Funktion — sie wird nicht durch einen fremden
Dienst ersetzt. Das ist die einzige Bauart, bei der der Satz „die Daten bleiben
im Haus" auch dann noch stimmt, wenn der eigene Server aus ist.
Dafür bleibt **alles andere ohne Modell vollständig benutzbar**: Wiki lesen und
schreiben, Wortsuche, Belege ablegen, beide Protokolle. Wo etwas fehlt, steht
ein Satz, der sagt was fehlt und wie es ohne geht.
## Phase 9 — Kassenverwaltung · fertig
Am 03.09.2026 ergänzt. Die Rolle `KASSIER` war seit Phase 0 angelegt, ein Modul
dazu fehlte in der ursprünglichen Planung. Spezifikation: `Phase-9.md`.
- Kassenkonten (Bar, Bank, Rücklage), Buchungskategorien, Buchungen mit Beleg
- Beitragslauf je Jahr nach Abteilung, Mahnstufen, Zahlungsabgleich aus
CAMT.053 oder MT940
- Rechnungen an Dritte mit Nummernkreis und PDF
- Kassenabschluss mit gezähltem Bestand, Differenz und Kassenprüfbericht
- Auswertungen nach Kategorie und Monat, offene Posten, Beitragsrückstände
- Export für Steuerberater und Kassenprüfung der Gemeinde
Zwei Festlegungen, die den Rest bestimmen: eine festgeschriebene Buchung ist
unveränderbar — Korrekturen laufen über eine Gegenbuchung mit Verweis. Und der
Kassenabschluss friert seinen Zeitraum ein, danach nimmt die Buchungsmaske
kein Datum daraus mehr an. Beträge durchgängig als `DECIMAL(12,2)`, nie als
Fließkommazahl.
Beides sitzt in Triggern und nicht im Router: ein vergessener Zustandscheck,
ein Skript oder ein Import würden sonst reichen, um den geprüften Bestand zu
ändern, ohne dass irgendwo etwas auffällt.
**Die Wehr kann jetzt:** ihre Kasse führen und den Kassenprüfbericht auf
Knopfdruck erzeugen.
## Phase 10 — Mandantenfähigkeit · fertig
Am 05.09.2026 ergänzt. Datenmodell und RLS trugen seit Phase 0 mehrere Wehren;
was fehlte, war alles darüber.
- `Benutzer` und `Mitgliedschaft`: das Anmeldekonto ist von der Personenakte
gelöst. Ein Mensch, ein Passwort, beliebig viele Wehren.
- Wehrwähler in der Seitenleiste — er erscheint nur, wenn es etwas zu wählen
gibt.
- Die Rolle `AUFSICHT` für die Kreisebene: Kreisbrandrat und
Kreisbrandinspektion sehen die betreuten Wehren und ändern nichts.
- Verwaltung der Installation unter `/wehren`: Wehren anlegen, Konten führen,
Zuordnungen vergeben.
Die Entscheidung, die alles andere bestimmt: **das Konto trägt keine
Mandantenkennung.** Es kann keine tragen — es ist ja der Angelpunkt, an dem
ein Mensch zu mehreren Wehren gehört. Geschützt wird es deshalb wie
`Berechtigung` über Rechte statt über Row Level Security, und was ein Konto in
einer Wehr darf, entscheidet nicht es selbst, sondern seine `Mitgliedschaft` —
und die trägt `organisationId` wie jede andere Tabelle.
**Bewusst nicht dabei:** wehrübergreifende Auswertungen. Eine Zahl über
mehrere Wehren hinweg braucht eine abgestimmte Definition, und ohne die ist
sie schlimmer als keine. Die Aufsicht sieht jede Wehr einzeln.
**Die Wehr kann jetzt:** sich einen Server mit anderen teilen, ohne dass
jemand über die Grenze sieht — und die Kreisebene kann hineinschauen, ohne
etwas anfassen zu können.
## Phase 11 — Freigabereife · fertig
Am 05.09.2026 umgesetzt. Kein Modul, sondern die drei Software-Voraussetzungen
für die Freigabe.
- **Auskunft nach Art. 15 DSGVO.** Das Recht `person.export` stand seit Phase 0
im Katalog und war zugewiesen — umgesetzt war nichts. Ohne Auskunftsseite ist
ein Löschkonzept nicht abnehmbar.
- **Sicherung und Wiederherstellung** mit einer durchgeführten Rückspielprobe.
- **Pipeline** in Gitea Actions: typecheck, lint, Migrationen, Seed und Tests.
Die Rückspielprobe hat sich sofort bezahlt gemacht: der erste Versuch lief
sauber durch und hatte dabei sämtliche Unveränderlichkeitsgarantien der
Datenbank entfernt. Gefunden haben es die Datenbanktests unmittelbar danach —
also genau die Probe, wegen der 1.0.0 sie verlangt.
**Die Wehr kann jetzt:** eine Selbstauskunft erteilen, ihren Bestand sichern
und ihn nachweislich zurückholen.
## 1.0.0 — Freigabe · am 06.09.2026 erteilt
Kein neues Modul, sondern eine Entscheidung: die Wehr setzt FLORIAN im
Echtbetrieb ein.
**Damit das nicht zur Formalie wird, hier der Stand jeder Voraussetzung — auch
der offenen.** Eine Freigabe, die alles abhakt, was ohnehin nicht geprüft
wurde, ist keine.
| Voraussetzung | Stand |
|---|---|
| Datenübernahme aus der bisherigen Verwaltung | **entfällt.** Die Wehr pflegt den Bestand von Hand ein; es gibt kein Altsystem, aus dem übernommen würde. Für Mitglieder, Fahrzeuge und Geräte steht der Import-Assistent bereit, falls sich das ändert. |
| Sicherungskonzept steht und ist einmal wiederhergestellt worden | **erledigt** mit Phase 11. Die Probe hat dabei einen Fehler gefunden, der sonst erst im Notfall aufgefallen wäre. |
| Löschkonzept nach DSGVO | **technisch vollständig** seit Phase 11: Auskunft nach Art. 15, Anonymisierung im Aufbewahrungslauf, konfigurierbare Fristen. Die Abnahme durch die Wehr ist ein organisatorischer Schritt und steht aus. |
| Schulung von Kommandant, Gerätewart und Atemschutzgerätewart | **steht aus.** Sie läuft nach der Freigabe; Grundlage ist die [Kurzanleitung](KURZANLEITUNG.md). |
| Hinweis zur analogen Atemschutzüberwachung | **bewusst stehen gelassen.** `ATEMSCHUTZ_HINWEIS=true`. FLORIAN bleibt damit ergänzend; die Tafel am Fahrzeug ist führend. Das Abschalten verlangt ohnehin einen Kommandantenbeschluss samt Fundstelle. |
Die beiden offenen Punkte sind **organisatorisch, nicht technisch**: an der
Software hängt nichts davon ab. Sie stehen hier, damit später nachlesbar ist,
was zum Zeitpunkt der Freigabe erledigt war und was nicht.
### Was 1.0.0 bedeutet — und was nicht
**Bedeutet:** Der Funktionsumfang ist vollständig, die Datenbank ist stabil,
Migrationen sind aufwärtskompatibel, und ab hier gilt semantische
Versionierung. Ein Update bricht nichts, ohne dass es in der Hauptnummer
steht.
**Bedeutet nicht:** dass keine Fehler mehr da sind. Es bedeutet, dass die
Wehr echte Daten hineingeben kann, ohne befürchten zu müssen, sie beim
nächsten Update zu verlieren.
---
## Getroffene Festlegungen
Am 03.09.2026 entschieden:
| Punkt | Entscheidung |
|---|---|
| Kassenmodul | Als **Phase 9** ergänzt und mit 0.10.0 umgesetzt. Spezifikation in `Phase-9.md`. |
| `Berechtigung` ohne `organisationId` | Bleibt so. Die Tabelle ist der systemweite Katalog dessen, was die Software kann, für alle Wehren identisch — mandantenbezogen wird es erst über `RolleBerechtigung`. Für die Anwendungsrolle nur lesbar. |
| `Benutzer` ohne `organisationId` | Notwendige Ausnahme, seit Phase 10. Die Tabelle ist der Angelpunkt der Doppelmitgliedschaft — mit Mandantenkennung könnte sie das nicht sein. Geschützt über Rechte statt RLS, wie `Berechtigung`: die Anwendungsrolle darf lesen und die Anmeldefelder fortschreiben, mehr nicht. |
| `AUFSICHT` nicht im Prisma-Enum | Die Kreisebene ergibt sich aus der Mitgliedschaftsart, nicht aus einer Rollenzuweisung. Vergebbar zu machen hiesse, dass jemand innerhalb einer Wehr Rechte an einer anderen verteilen könnte. |
| `istVerwalter` als Kontomerkmal | Kein Recht. Rechte gelten je Wehr; wer Wehren anlegt, steht über allen. Ein Recht, das in Wehr A vergeben wird und in Wehr B wirkt, wäre die Hintertür, die Phase 10 vermeiden soll. |
| Löschausnahme im Audit-Log | Bleibt so. `UPDATE` ist dauerhaft gesperrt, `DELETE` nur mit `SET LOCAL app.audit_bereinigung = 'an'` im Aufbewahrungslauf des Workers. Ohne diese Ausnahme wäre das Löschkonzept nach DSGVO nicht umsetzbar. |
## Weitere Kandidaten für später
| Idee | Nutzen | grob |
|---|---|---:|
| Fahrtenbuch als eigenes Modul | derzeit nur als Kiosk-Wizard in Phase 4 vorgesehen | 3–4 PT |
| Kleiderkammer und Wäscheverwaltung | in Phase 4 nur als Wizard, ohne Bestandsführung | 4–6 PT |
| Jugendfeuerwehr mit eigener Abzeichenverwaltung | eigene Fachlichkeit | 5–7 PT |
| Schnittstelle zur Integrierten Leitstelle | Alarmdaten automatisch übernehmen | 6–10 PT, stark abhängig von der ILS |
Die Mandantenfähigkeit ist mit **Phase 10** umgesetzt: umschalten, Kreisebene,
Doppelmitgliedschaft, Verwaltung. Offen geblieben sind bewusst die
gemeindeübergreifenden Auswertungen — dafür braucht es zuerst eine abgestimmte
Definition dessen, was verglichen werden soll.