From 4b3021bb50a5e022ab78cacf6e3f688aa71ed247 Mon Sep 17 00:00:00 2001 From: Florian Wilde Date: Thu, 3 Sep 2026 07:11:37 +0200 Subject: [PATCH] Kassenverwaltung als Phase 9 ergaenzen, Festlegungen dokumentieren Die Rolle KASSIER war seit Phase 0 angelegt, ein Kassenmodul fehlte in der Planung. Phase-9.md beschreibt es jetzt: Konten, Buchungen mit Beleg, Beitragslauf mit Mahnstufen, Rechnungen, Kassenabschluss und Auswertungen. Geschaetzt 8-11 PT, Version 0.10.0. Zwei Festlegungen aus der Spezifikation, weil sie den Rest bestimmen: eine festgeschriebene Buchung ist unveraenderbar und wird nur ueber eine Gegenbuchung korrigiert; der Kassenabschluss friert seinen Zeitraum ein. Ausserdem als entschieden festgehalten: - Berechtigung bleibt ohne organisationId. Die Tabelle ist der systemweite Katalog dessen, was die Software kann; mandantenbezogen wird es erst ueber RolleBerechtigung. - Die Loeschausnahme im Audit-Log bleibt. UPDATE ist dauerhaft gesperrt, DELETE nur im gekennzeichneten Aufbewahrungslauf des Workers. Roadmap, Aufwandsschaetzung, Versionierung, README und die Seitenleiste sind entsprechend ergaenzt. Co-Authored-By: Claude Opus 5 --- Phase-9.md | 38 ++++++++++++++++++++ README.md | 1 + docs/AUFWANDSSCHAETZUNG.md | 33 +++++++++++++----- docs/ROADMAP.md | 48 +++++++++++++++++--------- docs/VERSIONIERUNG.md | 6 +++- src/components/layout/seitenleiste.tsx | 4 ++- src/lib/authz.ts | 4 +-- 7 files changed, 103 insertions(+), 31 deletions(-) create mode 100644 Phase-9.md diff --git a/Phase-9.md b/Phase-9.md new file mode 100644 index 0000000..00bdcc7 --- /dev/null +++ b/Phase-9.md @@ -0,0 +1,38 @@ +Phase 9: Kassenverwaltung. + +Ergänzt am 03.09.2026. Die Rolle KASSIER ist seit Phase 0 angelegt, ein Modul +dazu fehlte in der ursprünglichen Planung. + +Modelle: Kassenkonto (Bezeichnung, Art: bar | bank | ruecklage, IBAN, +Anfangsbestand, aktiv), Buchungskategorie (Name, Art: einnahme | ausgabe, +Oberkategorie, Konto im Kontenrahmen), Buchung (Konto, Kategorie, Datum, +Betrag, Verwendungszweck, Belegnummer, Gegenkonto, Person ODER +Lieferant, Beleg als Datei, festgeschrieben), Beitragssatz (Bezeichnung, +Betrag je Jahr, gilt für Abteilung), Beitrag (Person, Jahr, Satz, Betrag, +Status: offen | bezahlt | erlassen | gemahnt, bezahlt_am), +Rechnung (Empfänger, Positionen, Betrag, Datum, faellig_am, Status), +Kassenabschluss (Zeitraum, Kassenbestand laut Buch, gezählter Bestand, +Differenz, Prüfer, geprueft_am, Bericht als PDF). + +Funktionen: +- Buchungsmaske mit Kategorievorschlag aus dem Verwendungszweck +- Beleg als Foto oder PDF anhängen, Ablage in MinIO +- Beitragslauf: erzeugt für ein Jahr alle Beiträge nach Abteilung, + Mahnstufen mit Vorlage, Zahlungseingang manuell oder per CSV-Abgleich + aus dem Bankkonto (CAMT.053 oder MT940) +- Rechnungen an Dritte (Fehlalarm, Öleinsatz, Vereinsveranstaltung) mit + Nummernkreis und PDF über Gotenberg +- Kassenabschluss: Zeitraum wählen, Bestand zählen, Differenz erklären, + Kassenprüfbericht als PDF mit Unterschriftsfeldern +- Auswertungen: Einnahmen/Ausgaben nach Kategorie und Monat, + Jahresvergleich, offene Posten, Beitragsrückstände +- Export für den Steuerberater und für die Kassenprüfung der Gemeinde + +Wichtig: +- Eine festgeschriebene Buchung ist unveränderbar. Korrekturen erfolgen über + eine Gegenbuchung mit Verweis, nie durch Ändern. +- Der Kassenabschluss friert den Zeitraum ein: danach sind Buchungen mit + Datum in diesem Zeitraum nicht mehr möglich. +- Beträge als DECIMAL(12,2), niemals als Fließkommazahl. +- Der Kassier sieht keine Geräte- oder Atemschutzdaten, der Gerätewart keine + Buchungen. Die Trennung ist in lib/authz.ts bereits angelegt. diff --git a/README.md b/README.md index fe94a53..2c173f0 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ Anmelden mit `SEED_ADMIN_EMAIL` und `SEED_ADMIN_PASSWORT` aus der `.env` | Phase 6 — Kartenmodule | offen | | Phase 7 — Benachrichtigungen und Termine | offen | | Phase 8 — Lokale KI | offen | +| Phase 9 — Kassenverwaltung | offen | Vollständige Planung mit Aufwänden: [docs/ROADMAP.md](docs/ROADMAP.md) und [docs/AUFWANDSSCHAETZUNG.md](docs/AUFWANDSSCHAETZUNG.md). diff --git a/docs/AUFWANDSSCHAETZUNG.md b/docs/AUFWANDSSCHAETZUNG.md index aa36ea5..a48ad8d 100644 --- a/docs/AUFWANDSSCHAETZUNG.md +++ b/docs/AUFWANDSSCHAETZUNG.md @@ -39,9 +39,10 @@ Faktoren, die in die Schätzung eingehen: | 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** | | +| 9 | Kassenverwaltung | 8–11 PT | 2–3 h | offen | +| | **Summe** | **123–164 PT** | **28–37 h** | | -115–153 Personentage entsprechen etwa **6 bis 8 Monaten Vollzeitarbeit** einer +123–164 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. @@ -221,17 +222,31 @@ 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. +## Phase 9 — Kassenverwaltung + +**Vergleichsaufwand: 8–11 PT** — am 03.09.2026 ergänzt + +| Baustein | PT | +|---|---:| +| Modelle: Konto, Kategorie, Buchung, Beitragssatz, Beitrag, Rechnung, Abschluss | 2,0 | +| Buchungsmaske mit Kategorievorschlag, Beleg als Datei | 1,5 | +| Beitragslauf, Mahnstufen, Zahlungsabgleich aus CAMT.053 oder MT940 | 2,5 | +| Rechnungen mit Nummernkreis und PDF | 1,0 | +| Kassenabschluss mit Zeitraumsperre und Prüfbericht | 1,5 | +| Auswertungen und Exporte | 1,5 | + +Der Zahlungsabgleich ist der unsichere Posten: CAMT.053 ist gut spezifiziert, +MT940 dagegen je nach Bank unterschiedlich ausgelegt. Falls die Hausbank nur +MT940 liefert, kommt ein halber bis ganzer Tag für die Eigenheiten dazu. + +Die Unveränderlichkeit festgeschriebener Buchungen kostet hier fast nichts — +das Muster steht seit Phase 0 mit dem Audit-Log-Trigger und lässt sich +übernehmen. + --- ## 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. diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index fe0c5a6..a802431 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -18,6 +18,7 @@ Phase 5 ░░░░░░░░░░░░░░░░░░░░ offen Phase 6 ░░░░░░░░░░░░░░░░░░░░ offen 0.7.0 Phase 7 ░░░░░░░░░░░░░░░░░░░░ offen 0.8.0 Phase 8 ░░░░░░░░░░░░░░░░░░░░ offen 0.9.0 +Phase 9 ░░░░░░░░░░░░░░░░░░░░ offen 0.10.0 Freigabe ░░░░░░░░░░░░░░░░░░░░ offen 1.0.0 ``` @@ -159,6 +160,28 @@ Alles gegen Ollama, kein externer Anbieter, komplett abschaltbar. Jede KI-Ausgabe ist gekennzeichnet und muss bestätigt werden, bevor sie in ein Dokument mit Nachweischarakter gelangt. +## Phase 9 — Kassenverwaltung + +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. + +**Danach kann die Wehr:** 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 @@ -173,26 +196,17 @@ Echtbetrieb ein. Voraussetzungen: --- -## Offene Punkte +## Getroffene Festlegungen -### Kassenmodul fehlt in der Phasenplanung +Am 03.09.2026 entschieden: -Phase 0 verlangt die Rolle `KASSIER`, und sie ist angelegt — mit den Rechten -`kasse.lesen`, `kasse.bearbeiten` und `kasse.abschluss`. Ein Kassenmodul kommt -in keiner der Phasen 0 bis 8 vor. Die Rolle hätte also dauerhaft Rechte ohne -zugehörige Oberfläche. +| Punkt | Entscheidung | +|---|---| +| Kassenmodul | Wird als **Phase 9** ergänzt. Spezifikation in `Phase-9.md`, Aufwand 8–11 PT. | +| `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. | -Zwei Wege: - -1. **Phase 9 ergänzen** — Buchungen, Beiträge, Rechnungen, Kassenabschluss, - Jahresauswertung. Geschätzt 8–11 PT. -2. **Rolle belassen, Modul streichen** — der Kassier nutzt weiterhin seine - bisherige Lösung, die Rechte bleiben als Platzhalter stehen. - -Solange das nicht entschieden ist, bleiben die Rechte im Katalog, aber es gibt -keinen Navigationseintrag dafür. - -### Weitere Kandidaten für später +## Weitere Kandidaten für später | Idee | Nutzen | grob | |---|---|---:| diff --git a/docs/VERSIONIERUNG.md b/docs/VERSIONIERUNG.md index db1c3a5..b374092 100644 --- a/docs/VERSIONIERUNG.md +++ b/docs/VERSIONIERUNG.md @@ -30,9 +30,13 @@ Versionsnummer eine Aussage über den Funktionsumfang. | `0.7.0` | Phase 6 — Kartenmodule | | `0.8.0` | Phase 7 — Benachrichtigungen und Termine | | `0.9.0` | Phase 8 — Lokale KI | +| `0.10.0` | Phase 9 — Kassenverwaltung | | `1.0.0` | Freigabe für den Wirkbetrieb durch die Wehr | -`1.0.0` ist bewusst an die **Freigabe** gebunden, nicht an Phase 8. Erst wenn +`0.10.0` ist nach SemVer korrekt größer als `0.9.0` — die Stellen werden als +Zahlen verglichen, nicht als Text. + +`1.0.0` ist bewusst an die **Freigabe** gebunden, nicht an die letzte Phase. Erst wenn eine Wehr die Software im Echtbetrieb einsetzt, darf die analoge Überwachung zurücktreten — und erst dann ist eine Zusage über Stabilität ehrlich. diff --git a/src/components/layout/seitenleiste.tsx b/src/components/layout/seitenleiste.tsx index c622fa8..f0c52be 100644 --- a/src/components/layout/seitenleiste.tsx +++ b/src/components/layout/seitenleiste.tsx @@ -15,6 +15,7 @@ import { MonitorSmartphone, Siren, Truck, + Wallet, Users, Wrench, X, @@ -31,7 +32,7 @@ import type { Recht, Rolle } from "@/lib/authz"; * bleibt in lib/authz.ts, wie es die Projektregeln verlangen. Ein ausgeblendeter * Eintrag ist Bequemlichkeit, kein Schutz; der Schutz sitzt in der tRPC-Schicht. * - * Die Phasenangaben entsprechen den Dateien Phase-0.md bis Phase-8.md. + * Die Phasenangaben entsprechen den Dateien Phase-0.md bis Phase-9.md. */ interface Eintrag { @@ -86,6 +87,7 @@ const EINTRAEGE: Eintrag[] = [ rechte: ["ausbildung.lesen"], abPhase: 7, }, + { titel: "Kasse", pfad: "/kasse", symbol: Wallet, rechte: ["kasse.lesen"], abPhase: 9 }, { titel: "Protokoll", pfad: "/protokoll", diff --git a/src/lib/authz.ts b/src/lib/authz.ts index 7eb99a1..47eb72b 100644 --- a/src/lib/authz.ts +++ b/src/lib/authz.ts @@ -114,9 +114,7 @@ export const RECHTE = { "qualifikation.lesen": { bereich: "Ausbildung", bezeichnung: "Qualifikationen ansehen" }, "qualifikation.bearbeiten": { bereich: "Ausbildung", bezeichnung: "Qualifikationen pflegen" }, - // Kasse — die Rolle KASSIER ist in Phase 0 gefordert, ein Kassenmodul ist - // in Phase-0.md bis Phase-8.md aber nicht vorgesehen. Die Rechte stehen hier - // bereits bereit, damit die Rolle nicht leer bleibt. Siehe docs/ROADMAP.md. + // Kasse (Phase 9) "kasse.lesen": { bereich: "Kasse", bezeichnung: "Buchungen und Auswertungen ansehen" }, "kasse.bearbeiten": { bereich: "Kasse", bezeichnung: "Buchungen erfassen" }, "kasse.abschluss": { bereich: "Kasse", bezeichnung: "Kassenabschluss durchführen" },