Kassenbuch, Mitgliedsbeitraege, Rechnungen an Dritte, Kassenpruefung und die Auswertungen fuer die Jahreshauptversammlung. Die drei Festlegungen aus Phase-9.md sitzen in der Datenbank, nicht im Router: eine festgeschriebene Buchung ist unveraenderbar, ein geprueftes Jahr nimmt kein Datum mehr an, und gerechnet wird mit Prisma.Decimal. Korrigiert wird ueber eine Gegenbuchung mit Verweis - beide Buchungen bleiben stehen, damit im Kassenbuch zu sehen ist, dass etwas berichtigt wurde. Neun Modelle, drei Trigger, zwoelf CHECKs, sechs Router, fuenf Ansichten. Dazu der Bankimport fuer CAMT.053 und MT940 ohne Fremdbibliothek, der Kategorievorschlag aus dem eigenen Buchungsbestand und die Bruecke von Phase 8: aus einem gegengezeichneten Beleg wird eine Buchung, das Foto haengt danach an ihr. Nebenbei behoben: die Rechnungsnummer war ein Wettlauf, und eine Organisation liess sich nicht mehr loeschen, sobald sie eine festgeschriebene Buchung hatte - der Trigger kannte den Aufbewahrungsschalter nicht. 562 Unit-Tests und 239 E2E-Tests gruen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
302 lines
14 KiB
Markdown
302 lines
14 KiB
Markdown
# 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
|
||
Freigabe ░░░░░░░░░░░░░░░░░░░░ offen 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.
|
||
|
||
## 1.0.0 — Freigabe
|
||
|
||
Kein neues Modul, sondern eine Entscheidung: die Wehr setzt FLORIAN im
|
||
Echtbetrieb ein. Voraussetzungen:
|
||
|
||
- Datenübernahme aus der bisherigen Verwaltung abgeschlossen und abgeglichen
|
||
- Sicherungskonzept steht und ist einmal wiederhergestellt worden
|
||
- Schulung von Kommandant, Gerätewart und Atemschutzgerätewart erfolgt
|
||
- Löschkonzept nach DSGVO abgenommen
|
||
- Der Hinweis zur analogen Atemschutzüberwachung wird bewusst und
|
||
dokumentiert abgeschaltet — oder bewusst stehen gelassen
|
||
|
||
---
|
||
|
||
## 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. |
|
||
| 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 |
|
||
| Mehrere Wehren je Installation | technisch bereits möglich, Oberfläche fehlt | 4–6 PT |
|
||
|
||
Die Mandantenfähigkeit ist der Punkt, der ohne Zusatzaufwand am weitesten
|
||
trägt: das Datenmodell und RLS können bereits mehrere Wehren. Was fehlt, ist
|
||
eine Oberfläche zum Umschalten und ein Konzept für gemeindeübergreifende
|
||
Auswertungen. Für einen Landkreis, der mehrere Wehren betreiben will, wäre das
|
||
der nächste sinnvolle Schritt.
|