Phase 1: Stammdatenverwaltung #1

Merged
florian.wilde merged 2 commits from feat/phase-1-stammdaten into main 2026-09-03 06:39:51 +00:00
Owner

Ab hier führt die Wehr ihren Bestand in FLORIAN: Standorte, Fahrzeuge samt
Beladeordnung, Gerätetypen als Vorgabe, Geräte mit QR-Etiketten,
Qualifikationen mit Ablaufwarnung und der Import aus vorhandenen Tabellen.

Enthält zusätzlich den Planungs-Commit, der die Kassenverwaltung als Phase 9
ergänzt (Phase-9.md).

Was zu testen ist

Geräteliste (/geraete)

  • Suche über Inventarnummer, Bezeichnung, Hersteller, Seriennummer
  • Statusfilter, Sortierung per Klick auf die Spaltenüberschrift
  • „Spalten": ein- und ausblenden, die Auswahl bleibt nach dem Neuladen erhalten
  • Mehrere Geräte auswählen → Status setzen, Etiketten drucken

Gerätedetail

  • QR-Code sichtbar, „Etikett drucken" liefert ein PDF
  • Beim Prüfintervall steht „(aus dem Gerätetyp)", wenn am Gerät keines gesetzt ist
  • Verlauf zeigt Einträge aus dem Audit-Log

QR-Route

  • /g/INV-0001 leitet auf das Gerät weiter
  • /g/INV-GIBTESNICHT erklärt verständlich, warum nichts gefunden wurde
  • Abgemeldet aufgerufen: erst Anmeldung, danach das Gerät

Fahrzeuge

  • Detailseite zeigt die Beladung nach Geräteräumen (G1 … G6, Heck, Dach, MR)

Qualifikationen

  • Oben steht, was abläuft — gerechnet mit der Vorwarnzeit des jeweiligen Typs

Import (/geraete/importieren)

  • CSV mit Semikolon und deutschen Datumsangaben hochladen
  • Zuordnung prüfen, eine Spalte von Hand umstellen → Vorschau passt sich an
  • Fehlerhafte Zeilen sind rot markiert und werden nicht übernommen

Scannen (/geraete/scannen)

  • Kamera freigeben und ein Etikett scannen, oder die Nummer eintippen

Behobene Fehler

  • Fristenrechnung war um einen Tag verschoben. startOfDay aus date-fns
    rechnet in der Zeitzone des Servers; ein DATE aus Postgres kommt als
    UTC-Mitternacht und wurde dadurch auf den Vortag geschoben. Jede Prüffrist
    wäre einen Tag zu früh fällig geworden. Jetzt eigene Kalenderarithmetik auf
    UTC-Bestandteilen.
  • ctx.sitzung blieb in tRPC-Prozeduren nullbar, weil t.middleware() die
    Verengung der vorigen Middleware verwirft.
  • CardTitle war ein div und damit keine Überschrift — Karten fehlten in
    der Überschriftennavigation von Sprachausgaben.

Nachweise

Prüfung Ergebnis
npm run typecheck ohne Ausgabe
npm run test 104 grün (vorher 32)
npm run test:e2e 44 grün, Desktop und Tablet (vorher 10)
npm run build 17 Routen, 103 kB gemeinsames JavaScript
Browser-Konsole keine Fehler, keine Hydratationswarnungen

Noch offen

Ein Formular zum einzelnen Anlegen eines Geräts fehlt. Die Router können
anlegen, ändern, umlagern und aussondern; die Oberfläche deckt Liste, Detail,
Massenbearbeitung und Import ab. Geschätzt 0,5 PT, sinnvoll in Phase 2
mitzunehmen — dort entstehen ohnehin Formulare. Steht so in docs/DEVLOG.md.

Ab hier führt die Wehr ihren Bestand in FLORIAN: Standorte, Fahrzeuge samt Beladeordnung, Gerätetypen als Vorgabe, Geräte mit QR-Etiketten, Qualifikationen mit Ablaufwarnung und der Import aus vorhandenen Tabellen. Enthält zusätzlich den Planungs-Commit, der die Kassenverwaltung als Phase 9 ergänzt (`Phase-9.md`). ## Was zu testen ist **Geräteliste** (`/geraete`) - Suche über Inventarnummer, Bezeichnung, Hersteller, Seriennummer - Statusfilter, Sortierung per Klick auf die Spaltenüberschrift - „Spalten": ein- und ausblenden, die Auswahl bleibt nach dem Neuladen erhalten - Mehrere Geräte auswählen → Status setzen, Etiketten drucken **Gerätedetail** - QR-Code sichtbar, „Etikett drucken" liefert ein PDF - Beim Prüfintervall steht „(aus dem Gerätetyp)", wenn am Gerät keines gesetzt ist - Verlauf zeigt Einträge aus dem Audit-Log **QR-Route** - `/g/INV-0001` leitet auf das Gerät weiter - `/g/INV-GIBTESNICHT` erklärt verständlich, warum nichts gefunden wurde - Abgemeldet aufgerufen: erst Anmeldung, danach das Gerät **Fahrzeuge** - Detailseite zeigt die Beladung nach Geräteräumen (G1 … G6, Heck, Dach, MR) **Qualifikationen** - Oben steht, was abläuft — gerechnet mit der Vorwarnzeit des jeweiligen Typs **Import** (`/geraete/importieren`) - CSV mit Semikolon und deutschen Datumsangaben hochladen - Zuordnung prüfen, eine Spalte von Hand umstellen → Vorschau passt sich an - Fehlerhafte Zeilen sind rot markiert und werden nicht übernommen **Scannen** (`/geraete/scannen`) - Kamera freigeben und ein Etikett scannen, oder die Nummer eintippen ## Behobene Fehler - **Fristenrechnung war um einen Tag verschoben.** `startOfDay` aus date-fns rechnet in der Zeitzone des Servers; ein `DATE` aus Postgres kommt als UTC-Mitternacht und wurde dadurch auf den Vortag geschoben. Jede Prüffrist wäre einen Tag zu früh fällig geworden. Jetzt eigene Kalenderarithmetik auf UTC-Bestandteilen. - **`ctx.sitzung` blieb in tRPC-Prozeduren nullbar**, weil `t.middleware()` die Verengung der vorigen Middleware verwirft. - **`CardTitle` war ein `div`** und damit keine Überschrift — Karten fehlten in der Überschriftennavigation von Sprachausgaben. ## Nachweise | Prüfung | Ergebnis | |---|---| | `npm run typecheck` | ohne Ausgabe | | `npm run test` | 104 grün (vorher 32) | | `npm run test:e2e` | 44 grün, Desktop und Tablet (vorher 10) | | `npm run build` | 17 Routen, 103 kB gemeinsames JavaScript | | Browser-Konsole | keine Fehler, keine Hydratationswarnungen | ## Noch offen Ein Formular zum einzelnen Anlegen eines Geräts fehlt. Die Router können anlegen, ändern, umlagern und aussondern; die Oberfläche deckt Liste, Detail, Massenbearbeitung und Import ab. Geschätzt 0,5 PT, sinnvoll in Phase 2 mitzunehmen — dort entstehen ohnehin Formulare. Steht so in `docs/DEVLOG.md`.
florian.wilde added 2 commits 2026-09-03 06:36:27 +00:00
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 <noreply@anthropic.com>
Ab hier fuehrt die Wehr ihren Bestand in FLORIAN.

Datenmodell:
- Standort, Geraeteraum, Geraetetyp, Qualifikationstyp und Qualifikation
- Fahrzeug um Fahrgestellnummer, DIN-Typ, Erstzulassung, Sitzplaetze,
  Tankinhalt und UVV-Frist erweitert
- Geraet um Geraetetyp, Lebensdauerkategorie, errechnetes Lebensdauerende,
  Anschaffungspreis und die Lagerung erweitert
- Ein Geraet steht entweder an einem Standort oder ist auf einem Fahrzeug
  verlastet. Eine Pruefbedingung setzt das durch, ein Trigger stellt zusaetzlich
  sicher, dass ein angegebener Geraeteraum zum angegebenen Fahrzeug gehoert.
- RLS auf allen neuen Tabellen, Trigram-Indizes fuer die Volltextsuche

Fachlogik:
- lib/stammdaten/fristen.ts rechnet Prueftermine, Lebensdauer und den
  abgeleiteten Geraetestatus. Der Geraetetyp gibt vor, das Geraet darf
  abweichen.
- lib/stammdaten/qr.ts und qr-parser.ts erzeugen und lesen die Codes
- lib/stammdaten/etiketten.ts baut den A4-Bogen mit 65 Etiketten
- lib/stammdaten/import.ts liest CSV und Excel, erkennt deutsche Datums- und
  Zahlenformate, Windows-1252 und Dubletten innerhalb der Datei
- lib/pdf.ts spricht Gotenberg an

Oberflaeche:
- Geraeteliste mit Volltextsuche, Statusfilter, serverseitiger Sortierung,
  Blaettern, Spaltenauswahl und Massenbearbeitung
- Geraetedetail mit QR-Code, Pruefvorgabe aus dem Geraetetyp und Verlauf
- Fahrzeugliste und -detail mit Beladung nach Beladeordnung
- Mitgliederliste nach Abteilung, Mitgliedsdetail mit Qualifikationen
- Qualifikationen mit Ablaufwarnung je Vorwarnzeit des Typs
- Import-Assistent mit Zuordnung und Vorschau vor dem Uebernehmen
- QR-Scanner ueber die Kamera, mit Eingabefeld als Rueckfallweg

Behoben:
- Fristenrechnung lief ueber startOfDay aus date-fns und damit in der Zeitzone
  des Servers. Ein DATE aus der Datenbank kommt als UTC-Mitternacht und wurde
  dadurch auf den Vortag geschoben — Fristen waeren einen Tag zu frueh faellig
  geworden. Jetzt eigene Kalenderarithmetik auf UTC-Bestandteilen.
- ctx.sitzung blieb in tRPC-Prozeduren nullbar, weil t.middleware() die
  Verengung der vorigen Middleware verwirft. Middleware jetzt direkt an .use().
- CardTitle war ein div und damit keine Ueberschrift. Wer mit einer
  Sprachausgabe arbeitet, springt von Ueberschrift zu Ueberschrift; Karten
  tauchten in dieser Navigation nicht auf.

Daten und Tests:
- Seed um 3 Standorte, 20 Geraeteraeume, 14 Geraetetypen mit echten
  Pruefvorgaben, 49 Geraete und 107 Qualifikationen erweitert
- 104 Vitest-Tests (vorher 32), 44 Playwright-Tests (vorher 10)
- Anleitung um sieben bebilderte Abschnitte erweitert, Changelog, Devlog,
  Aufwandsschaetzung und Roadmap fortgeschrieben

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
florian.wilde merged commit 47b8e36a38 into main 2026-09-03 06:39:51 +00:00
florian.wilde deleted branch feat/phase-1-stammdaten 2026-09-03 06:39:51 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: florian.wilde/FireAdministration#1