Commit Graph
68 Commits
Author SHA1 Message Date
patrickandClaude Sonnet 5 30e2db63ae feat(ui): UI-007 Aktionsleiste auf der Objektakte
CI / backend-tests (push) Successful in 2m1s
CI / frontend-build (push) Successful in 18s
Kontrolle starten/Mangel melden direkt unter Status statt nur ein
Button am Seitenende - nach dem QR-Scan (MOBILE-002 landet auf der
Akte) sofort erreichbar. Mangel melden springt mit ?objekt_id=X in
MangelListePage und wählt das Objekt direkt vor.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-06 21:41:36 +02:00
patrickandClaude Sonnet 5 fbc3b2223b feat(ui): UI-006 Abweichungen in der Kontrolle dauerhaft hervorheben
CI / backend-tests (push) Successful in 2m2s
CI / frontend-build (push) Successful in 18s
PositionCard bekommt eine farbige linke Randlinie je Zustand (grün
passt, gelb Abweichung/Fehlbestand, rot Übertragungsfehler) - eine
Abweichung war bisher nur während des kurz offenen Nachfüll-Dialogs
sichtbar, danach nicht mehr von einer normalen Bestätigung zu
unterscheiden. Fortschrittsanzeige existierte bereits. Nebenbei
hartkodierte Hex-Fallbackfarben durch Token-Referenzen ersetzt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-06 21:39:13 +02:00
patrickandClaude Sonnet 5 209b541220 feat(ui): UI-005 begründete Einsatzbereitschaft + Dokumente in der Akte
CI / backend-tests (push) Successful in 2m2s
CI / frontend-build (push) Successful in 19s
Backend: objekt_readiness() in dashboard.py liefert Status+Gründe für
ein einzelnes Objekt, Fallunterscheidung aus einsatzbereitschaft()
extrahiert (_kategorie_und_gruende, keine Duplizierung). Neue Felder
an /akte/objekt/{id}. Frontend: ReadinessBadge + Gründeliste ersetzt
den rohen objekt.status-Badge (Objekt-Lebenszyklus-Status bleibt
separat sichtbar). Dokumente waren in der Akte bisher nur Text ohne
Interaktion - jetzt DokumentePanel eingebunden plus neuer "Ansehen"-
Klick (PDF/Bild im neuen Tab statt Zwangs-Download).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-06 21:35:52 +02:00
patrickandClaude Sonnet 5 21ea63a69a feat(ui): Dashboard als Startseite für Verantwortliche + einstellbar
CI / backend-tests (push) Successful in 2m0s
CI / frontend-build (push) Successful in 19s
Root-Route "/" und Catch-all landeten bisher immer auf /objekte,
Login-Weiterleitung (Verantwortliche -> Dashboard) war der einzige
Pfad dorthin. Jetzt zentrale startseitenPfad()-Logik überall genutzt,
zusätzlich per Dropdown in der Sidebar einstellbar (automatisch/
Dashboard/Objekte), Präferenz in localStorage.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-06 13:37:02 +02:00
patrickandClaude Sonnet 5 ed9ba29581 feat(ui): UI-004 Dashboard "Was ist jetzt zu tun?"-Karte
CI / backend-tests (push) Successful in 2m0s
CI / frontend-build (push) Successful in 18s
Neue Karte ganz oben fasst offene Fehlbestände, kritische Mängel,
überfällige Prüfungen, abgelaufene Chargen und nie kontrollierte
Objekte zusammen (bereits geladene Daten, keine neuen Endpunkte),
mit Direktlinks - "5-Sekunden-Antwort" auf "was muss ich jetzt tun".
Nebenbei: fehlende .text-success/.text-danger in global.css ergänzt
(waren in AktePage.tsx bereits referenziert, aber nie definiert).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-06 13:33:08 +02:00
patrickandClaude Sonnet 5 79ddb37a36 feat(ui): UI-003 zentrale Statuskomponenten + SyncStatus-Lücke geschlossen
CI / backend-tests (push) Successful in 2m3s
CI / frontend-build (push) Successful in 19s
ReadinessBadge (ready/limited/not-ready/unknown, "unbekannt" nie wie
"einsatzbereit"), FristBadge als Basis für InspectionStatus/
InventoryStatus, SyncStatus neu in AppShell verdrahtet - Online/
Offline/Sync-Queue-Status war zuvor nirgends sichtbar, obwohl die
Offline-Infrastruktur seit Prompt 17 existiert. Dashboard nutzt die
neuen Komponenten statt Ad-hoc-Inline-Farben.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-06 13:30:45 +02:00
patrickandClaude Sonnet 5 b6ada2b5a1 feat(inventory): INV-007 Ausgabe/Rückgabe von Material und Leihgeräten
CI / backend-tests (push) Successful in 2m1s
CI / frontend-build (push) Successful in 18s
Personenbezogene Ausgabe ergänzt die reine Standort-/Lagerplatz-Sicht
um "wer hat das Ding gerade": neues Modell ausgabe (Material +
optional geraet_instanz_id), POST /ausgaben, GET /ausgaben (Filter
status/empfaenger), POST /ausgaben/{id}/rueckgabe mit Schutz vor
Doppel-Rueckgabe. Frontend als Admin-Tab "Ausgabe/Rückgabe" +
Command-Palette-Eintrag.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-06 13:19:31 +02:00
patrickandClaude Sonnet 5 16a42c6b85 feat(ui): UI-002 Command Palette und Deep-Links statt Nav-Umbau
CI / backend-tests (push) Successful in 2m0s
CI / frontend-build (push) Successful in 18s
Globale Suche/Quick Actions per Strg/Cmd+K (CommandPalette): Objekt-
Suche nach Name/Code, Sprung zu QR-Scan/Material/Lager/Personal/
Verwaltung. AdminPage-Tab jetzt im URL-Query (?tab=...) statt nur
lokalem State, damit die Palette gezielt verlinken kann, ohne Routen
zu duplizieren. Bewusst keine neuen Sidebar-Punkte fuer Fahrzeuge/
Kontrollen/Pruefungen - dafuer gibt es keine eigenstaendigen Listen-
Seiten in MABEA.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-06 13:09:56 +02:00
patrickandClaude Sonnet 5 bccb8d1933 feat(ui): UI-001 Designsystem-Grundlage - Dark Mode + Readiness-Farbtokens
CI / backend-tests (push) Successful in 2m1s
CI / frontend-build (push) Successful in 18s
Epic 20 (UI-Redesign) angelegt, Stufe 1: CSS-Variablen für Dark Mode
(System-Präferenz + manueller Schalter via ThemeToggle, localStorage-
persistiert) und eigene Farbtokens für Einsatzbereitschaft (ready/
limited/not-ready/unknown), Basis für ReadinessBadge in UI-003.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-06 09:57:49 +02:00
patrickandClaude Sonnet 5 01263753bf fix(mobile): MOBILE-002 Scan routet zur Akte statt zur Kontrolle
CI / backend-tests (push) Successful in 2m2s
CI / frontend-build (push) Successful in 18s
Scan-Ziel war noch auf den alten Kontroll-Direktsprung eingestellt,
obwohl die Akte (FILE-006) seit 2026-09-05 existiert. Kurzweg-Button
"Kontrolle starten" auf der Akte deckt den alten Ablauf weiter ab.
Frontend-Anzeigen-Audit über alle Epics ergab keine weiteren echten
Backend-fertig/Anzeige-fehlt-Lücken.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-06 09:42:26 +02:00
patrickandClaude Sonnet 5 a6f0c51842 fix(beladungsplaner): Klick-zum-Zuordnen statt HTML5-Drag&Drop
CI / backend-tests (push) Successful in 1m58s
CI / frontend-build (push) Successful in 18s
Nutzer-Fund 2026-09-05: natives Drag&Drop funktionierte auf Desktop mit Maus
nicht zuverlässig und wäre auf Touch-Geräten ohnehin gar nicht nutzbar
(HTML5-DnD-API unterstützt keine Touch-Eingabe) - genau die Geräteklasse, die
dieses Projekt im Feld primär anspricht. Ersetzt durch Klick-zum-Zuordnen:
Material im Pool antippen (markiert es), dann Ziel-Fach antippen ordnet zu.
Funktioniert identisch auf Desktop und Touch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-05 23:33:36 +02:00
patrickandClaude Sonnet 5 4fa7ace6d9 feat(vorlage): Beladungsplanung per Drag&Drop (Shelf-inspiriert)
CI / backend-tests (push) Successful in 1m56s
CI / frontend-build (push) Successful in 17s
Nutzer-Vorgabe: gute Inhalte aus Vergleichsprojekten übernehmen. Ersetzt die
Zeile-für-Zeile-Formular-Bearbeitung beim "Positionen bearbeiten" durch ein
Drag&Drop-Board: Material-Pool links, Fach-Spalten rechts (+ "Ohne Fach").
Material reinziehen ordnet zu, zwischen Spalten ziehen verschiebt das Fach,
"×" oder zurück in den Pool ziehen entfernt die Zuordnung. Sollmenge bleibt
inline editierbar. Nutzt weiterhin PUT /vorlagen/{id}/positionen, keine
Backend-Änderung nötig.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-05 23:25:10 +02:00
patrickandClaude Sonnet 5 0249921bd5 feat(vorlage): Vorlage direkt editierbar ohne Versionszwang (Nutzer-Vorgabe)
CI / backend-tests (push) Successful in 2m0s
CI / frontend-build (push) Successful in 18s
Bisher wurde die Sollmenge einer Objektposition live aus der Vorlagenposition
gelesen (objekt.vorlage_id -> vorlagenposition.sollmenge), Bearbeiten der
Vorlage erzeugte deshalb zwingend eine neue Version - sonst hätte sich jede
Änderung rückwirkend auf alle Objekte ausgewirkt, die diese Vorlage nutzen.

- Neue Spalte objektposition.sollmenge_vorlage (Migration 0020): kopiert die
  Sollmenge fest bei Anlage/Duplizieren statt live nachzuschlagen
- sollmenge_effektiv(position) liest jetzt nur noch override/sollmenge_vorlage,
  kein DB-Lookup mehr nötig (sollmenge_map() entfernt)
- Neuer Endpoint PUT /vorlagen/{id}/positionen: ersetzt Positionen direkt,
  ohne neue Version. Bestehende Objekte unbetroffen, nur neu angelegte nutzen
  die aktualisierten Werte (Test: test_aktualisiere_positionen_wirkt_nicht_
  rueckwirkend_auf_bestehendes_objekt)
- POST /vorlagen/{id}/neue-version bleibt zusätzlich bestehen (nicht entfernt)
- Frontend: "Neue Version speichern" -> "Positionen speichern" (PUT statt POST)
- 140 Tests grün

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-05 22:33:08 +02:00
patrickandClaude Sonnet 5 f7367f6df3 feat(lager): Warehouse-Epic Kern (WH-001..004+007)
CI / backend-tests (push) Successful in 1m56s
CI / frontend-build (push) Successful in 18s
Lagerort-Hierarchie (organisation/standort/gebaeude/raum/lager, self-referenzierend),
Lagerplätze mit eindeutigem Code, Bestand je Lagerplatz+Material, Ein-/Auslagerung
mit lückenlosem Materialbewegungsprotokoll (append-only, analog Lagerbewegung
auf Objekt-Ebene, hier aber Material-/Lagerplatz-fein).

- Migration 0019: 4 neue Tabellen (lagerort, lagerplatz, bestand, materialbewegung)
- Backend: CRUD Lagerort/Lagerplatz, Bestandsabfrage, Ein-/Auslagern-Endpunkte,
  Negativbestand vorab abgefangen (kein DB-Constraint-Exception-Pfad, gleiches
  Muster wie objekte.py-Fix vom 2026-09-05)
- Frontend: neuer Admin-Tab "Lager" (Lagerort/-platz-Verwaltung, Bestand+Buchung
  je Lagerplatz)
- 2 neue Tests, 139 Tests weiterhin grün

WH-005 (Umlagerung) und WH-006 (Inventur) bewusst zurückgestellt - Kern zuerst,
laut Nutzer-Entscheidung.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-05 21:42:37 +02:00
patrickandClaude Sonnet 5 84c11af3bb feat(akte): Digital-File-Epic - Aggregations-Endpunkt + Übersichtsseite (FILE-001..006)
CI / backend-tests (push) Successful in 1m58s
CI / frontend-build (push) Successful in 18s
Größte Lücke aus arbeitskacheln/03_digital_file.md: alle Teilbereiche
(Stammdaten, Standort, Verantwortlichkeit, Historie, Dokumente, Geräte-
Prüfungen, Mängel) existierten einzeln, aber keine gebündelte Akte-Ansicht
je Objekt.

- GET /api/v1/akte/objekt/{id}: aggregiert alle Teilbereiche in einem Aufruf
  (app/services/akte.py), 404 bei unbekanntem Objekt
- Zuständigkeits-Auflösung invertiert (wer ist für DIESES Objekt zuständig,
  Standort-Vererbung + Objekt-Zeile als Vereinigung, Karte 04)
- Frontend: /akte/objekt/:objektId (AktePage.tsx), Link aus der Objektliste
- 2 neue Tests (test_akte.py), 137 Tests weiterhin grün

FILE-007 (Audit-Konsistenz-Check über alle Mutations-Endpunkte) bewusst
nicht Teil dieses Commits - eigene, spätere Qualitätssicherungs-Kachel.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-05 21:13:29 +02:00
patrickandClaude Sonnet 5 fca9ee8fd8 fix(ci): CI-Testdatenbank-Encoding + 3 echte Session-/Logikfehler behoben
CI / backend-tests (push) Successful in 1m54s
CI / frontend-build (push) Successful in 17s
Root Cause der "CI rot"-Meldung gefunden und behoben:
- CI legte Testdatenbank ohne explizites ENCODING an, erbte SQL_ASCII vom
  Runner-Postgres-Template. Umlaute in JSONB (Historie-Einträge) brachen mit
  UntranslatableCharacterError - betraf auch die Produktions-DB (separat
  gemeldet, nicht Teil dieses Commits). CI legt jetzt explizit UTF8 an.

Drei echte Bugs beim Verifizieren gegen eine isolierte Testdatenbank gefunden:
- objekte.py PATCH /objekte/{id}: Selbstbezug-Check verließ sich auf den
  DB-CHECK-Constraint statt vorab zu prüfen - ein Flush-Fehlschlag hinterlässt
  die Session im Zustand DEACTIVE, jeder folgende Request in derselben Session
  crasht mit PendingRollbackError (401 statt 404 im Test). Jetzt expliziter
  Vorab-Check.
- geraet_instanz.py: gleiches Muster bei doppelter Seriennummer - jetzt
  expliziter Vorab-Check statt UNIQUE-Constraint-Exception.
- test_lagerbewegung.py: Testbug, las objekt.standort_id NACH dem POST (durch
  geteilte Session bereits auf den neuen Wert mutiert) statt vorher.

Nebenbei (Auftrag Priorität 4): "Mindermenge genehmigen"-Button direkt im
Nachfüll-Dialog der Kontroll-Erfassung (nur für materialverantwortlicher/
leitungsverantwortlicher/administration), nutzt den bereits bestehenden
POST /fehlbestaende/{id}/mindermenge Endpunkt.

Priorität 2 (Fahrzeug-Feldnamen-Mismatch) und Priorität 3 (nur Zugfahrzeuge
wählbar) waren bereits in früheren Commits erledigt (38b8ce1, 54fc296) -
Auftragsbeschreibung war auf altem Stand.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-05 17:57:14 +02:00
patrickandClaude Sonnet 5 fab3a06073 fix(dashboard): nie kontrollierte Objekte gelten nicht mehr als einsatzbereit
CI / backend-tests (push) Failing after 1m54s
CI / frontend-build (push) Successful in 16s
Nutzer-Fund (Readiness-Backlog-Review): einsatzbereitschaft() zählte ein
Objekt ohne jede Kontrolle bisher als "einsatzbereit", weil keine Kriterien
verletzt waren - fachlich falsch, "nie geprüft" ist nicht dasselbe wie
"geprüft und in Ordnung".

Neuer vierter Zustand "unbekannt": Objekte ohne abgeschlossene Kontrolle UND
ohne sonstige Blocker fallen jetzt hierunter statt unter "einsatzbereit".
Objekte mit anderen Gründen (Fehlbestand/Mangel/Prüfung/...) bleiben davon
unberührt, die zählten schon vorher korrekt.

Tests angepasst: zwei bestehende Tests nutzten ungeprüfte Objekte und
erwarteten fälschlich "einsatzbereit" - jetzt entweder explizit kontrolliert
(Ist=Soll) oder auf "unbekannt" korrigiert, plus neuer Test für den Kernfall.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
2026-09-05 15:47:39 +02:00
patrickandClaude Sonnet 5 27c249993a feat(fahrzeug): Funkkenner-Feld ergänzt (BOS-Digitalfunk-Kennung)
CI / backend-tests (push) Failing after 1m53s
CI / frontend-build (push) Successful in 17s
Nutzer-Fund: funkkenner (z.B. OPTA-Nummer) fehlte in fahrzeugdetails komplett
- eigenes Feld, nicht dasselbe wie funkrufname (gesprochener Rufname vs.
formale Funk-Identifikationsnummer im Digitalfunknetz).

Migration 0018, Model/Schema/Frontend-Formular ergänzt. Auch im Kachel-
Backlog (arbeitskacheln/05_fleet.md, FLEET-002) nachgezogen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
2026-09-05 15:37:32 +02:00
patrickandClaude Sonnet 5 95e04b521b style: Sidebar-Layout statt Topbar (Vorbild OpenFleet-Dashboard-Screenshot)
CI / backend-tests (push) Failing after 1m53s
CI / frontend-build (push) Successful in 17s
Nutzer hat Screenshot von openfleet's Dashboard geschickt: linke Sidebar-Nav
statt Topbar, KPI-Kacheln mit Icon-Box/großer Zahl, sehr flach. Layout-Wechsel
komplett über CSS (.app-shell Reihe statt Spalte, .topbar wird zur
vertikalen 230px-Sidebar) - AppShell.tsx unverändert, kein JSX-Umbau nötig.

Unter 768px klappt es zurück auf die bisherige horizontale Topbar (Mobile-
Durchgang bleibt gültig, nur die Desktop-Optik ändert sich).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
2026-09-05 15:10:45 +02:00
patrickandClaude Sonnet 5 024576cdc1 style: schlicheres Design (flach statt Schatten, kleinerer Radius)
CI / backend-tests (push) Failing after 1m52s
CI / frontend-build (push) Successful in 18s
Nutzer-Vorgabe: Design in Richtung OpenFleet (schlicht) - Schatten auf none
gesetzt, Radius 12px->8px, ruhigere Palette. Da Schatten/Radius komplett über
CSS-Variablen liefen, genügt die Token-Änderung, kein Component-Code
angefasst.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
2026-09-05 15:09:05 +02:00
patrickandClaude Sonnet 5 985e80b59d style(mobile): responsiver Durchgang - Sidebar+Liste-Layouts brechen um
CI / backend-tests (push) Failing after 1m54s
CI / frontend-build (push) Successful in 17s
4 Admin-Sektionen (ObjektSection, MaterialSection, ZustaendigkeitSection,
ObjektPositionenPanel) hatten identisches fest-20rem/12rem-Sidebar-neben-
Liste-Layout ohne Umbruch - auf Mobile lagen beide Spalten nebeneinander
breiter als der Bildschirm. Neue global.css-Klassen .split-layout/
-sidebar/-sidebar-sm/-content lösen das inline-Style-Duplikat auf und
klappen unter 768px automatisch auf eine Spalte.

Zusätzlich: .page-wide/.topbar/.card-grid/.row bekommen eigene 768px-
Anpassungen (kleinere Paddings/Schrift, Kacheln volle Breite, automatischer
Zeilenumbruch). Tabellen (Historie/Lagerbewegungen) waren schon per
overflow-x:auto abgesichert, keine Änderung nötig dort.

Mitarbeiter-Mobilflow (ObjektListPage/KontrollPage, 640px-Spalte) unverändert
- war laut Nutzer-Feedback bereits gut.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
2026-09-05 15:02:52 +02:00
patrickandClaude Sonnet 5 7ebbae802e style: visuelles Redesign (Desktop), Design-Anleihe bei Resgrid/OpenFleet/EMCS
CI / backend-tests (push) Failing after 1m56s
CI / frontend-build (push) Successful in 18s
Farbpalette/Radius/Schatten überarbeitet (global.css), alle bestehenden
Klassennamen bleiben unverändert - keine Seite muss angepasst werden. Neue
Klassen .card-grid/.stat-number für einheitliche KPI-Kacheln (Dashboard,
Mängel-Übersicht) - Muster aus allen drei Referenzprojekten (Resgrid/
OpenFleet/Emergency_Management_and_Coordination_System): Statistik-Karten
sind dort durchgängig das zentrale Dashboard-Element.

Dashboard/Mängel/Fehlbestände-Seiten von page (640px, für Mitarbeiter-
Mobilflow gedacht) auf page-wide umgestellt - das sind Verantwortliche-
Screens mit Karten/Listen, die auf Desktop-Breite gehören (Analog AdminPage).

Hartcodierte Statusfarben (#b00020/#b8860b) durch CSS-Variablen ersetzt.

Mobile/responsive Feinschliff folgt in einem eigenen Durchgang (Nutzer-
Entscheidung: erst Desktop normal bauen).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
2026-09-05 14:59:23 +02:00
patrickandClaude Sonnet 5 c56fc285de feat(rollen): granulares Rechte-System (Roadmap Phase 6, letztes Modul)
CI / backend-tests (push) Failing after 1m55s
CI / frontend-build (push) Successful in 19s
Additiv neben dem bestehenden 4-Rollen-System (mitarbeiter/material-
verantwortlicher/leitungsverantwortlicher/administration bleiben unverändert,
kein Breaking Change): Admin kann jetzt eigene Rollen (z.B. "Materialwart",
"Helfer" aus der Ursprungs-Anforderung) mit frei wählbaren Einzelrechten aus
einem Berechtigungs-Katalog anlegen und Benutzern zuweisen - auch Benutzern
ganz ohne feste RolleTyp-Zuordnung.

Neue Tabellen: berechtigung (Katalog), rolle (custom, admin-anlegbar),
rolle_berechtigung (M:N), benutzer_rolle_zuordnung (M:N, eigene Tabelle statt
Wiederverwendung des ENUM-basierten benutzer_rolle).

require_roles_or_permission() kombiniert beide Systeme: bestehende feste
Rollen ODER eine passende granulare Berechtigung. Auf die vom Nutzer genannten
Beispiel-Endpunkte angewendet: Material anlegen/bearbeiten, Lagerbewegung
durchführen, Mangel melden/lesen/bearbeiten, Prüfung durchführen - weitere
Endpunkte folgen bei Bedarf nach demselben Muster (require_permission()/
require_roles_or_permission() stehen jetzt als Bausteine bereit).

Neue Endpunkte: GET /berechtigungen, CRUD /rollen, PUT/DELETE
/rollen/{id}/berechtigungen/{id}, PUT/DELETE /benutzer/{id}/rollen/{id}.

Frontend: neuer Admin-Tab "Rollen & Rechte" (Rolle anlegen, Rechte togglen,
Benutzer zuweisen/entfernen).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
2026-09-05 14:07:03 +02:00
patrickandClaude Sonnet 5 73bf6c1605 feat(dokument): Dokumente-Modul (Roadmap Phase 5)
CI / backend-tests (push) Failing after 1m51s
CI / frontend-build (push) Successful in 17s
Polymorphe Datei-Anhänge (PDF/JPEG/PNG/WebP, Whitelist statt Blacklist -
owasp-Grundsatz) an beliebige Ressource, gleiches entitaet_typ/entitaet_id-
Muster wie Mangel/Historie. Lokale Ablage (settings.upload_dir, kein Cloud-
Zwang, Self-Hosting-Anforderung), server-generierter Dateiname verhindert
Path-Traversal/Namenskollisionen.

POST /dokumente (multipart), GET /dokumente (Filter Pflicht: entitaet_typ +
entitaet_id), GET /dokumente/{id}/download, DELETE /dokumente/{id}. Hochladen:
alle Mitarbeiter+, Löschen: Materialverantwortliche+Leitung+Admin.

Frontend: wiederverwendbares DokumentePanel (Upload/Liste/Download/Löschen),
eingebunden in ObjektSection (je Objekt) und MangelListePage (Fotos zu
Mängeln) - weitere Ressourcen (Geräteinstanz, Fahrzeugdetails, Benutzer)
können denselben Baustein später einfach wiederverwenden.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
2026-09-05 13:56:27 +02:00
patrickandClaude Sonnet 5 11ad747136 fix(historie): Audit-Lücke bei Mangel/Personal/Objekt-Änderungen geschlossen
CI / backend-tests (push) Failing after 1m47s
CI / frontend-build (push) Successful in 17s
Bisher waren nur Kontrolle/Fehlbestand/Nachfüllung/Mindermenge/Geräteinstanz
im append-only Audit-Log (historie.log() war seit Prompt 13 nie flächendeckend
verdrahtet, docstring sagte das bereits so). Drei neue Ereignisse ergänzt:

- mangel_gemeldet / mangel_status_geaendert (Mangel-Modul)
- qualifikation_erfasst (Personal-Modul, sicherheitsrelevant: "wer hat wem
  wann eine Qualifikation bestätigt" hängt fachlich direkt an "wer darf
  fahren")
- objekt_geaendert (Status-/Fahrzeug-Zuordnungsänderungen via PATCH /objekte)

Lagerbewegung bewusst NICHT zusätzlich in historie dupliziert - hat bereits
eigenes vollständiges Audit-Trail (Wer/Wann/Von/Nach/Grund in eigener
Tabelle).

Frontend: Änderungslog-Filter um geraet_instanz/mangel/benutzer_qualifikation/
objekt ergänzt (geraet_instanz fehlte dort zuvor ebenfalls).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
2026-09-05 13:50:48 +02:00
patrickandClaude Sonnet 5 417df2beb6 feat(lager): Lagerbewegung-Protokoll (Roadmap Phase 4, Modul Lager)
CI / backend-tests (push) Failing after 1m47s
CI / frontend-build (push) Successful in 17s
Objekt bleibt der Materialträger (Rucksack/Gerät/Fahrzeug, Karte 11) -
"Material verschieben" heißt: das Objekt bekommt einen neuen Standort, jede
Bewegung wird append-only protokolliert (Wer/Wann/Von/Nach/Grund, Nutzer-
Vorgabe Modul 5).

POST /objekte/{id}/lagerbewegungen setzt Standort + protokolliert in einem
Zug, GET /lagerbewegungen (Filter objekt_id/standort_id) für die Historie.
Rollen wie beim Mangel-Modul: Materialverantwortliche+Leitung+Admin dürfen
verschieben, alle Eingeloggten dürfen lesen.

Frontend: "Verschieben"-Aktion in ObjektSection, neuer Admin-Tab
"Lagerbewegungen" (reine Anzeige, analog HistorieSection).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
2026-09-05 13:46:33 +02:00
patrickandClaude Sonnet 5 8fbb356c34 feat(mangel): Leitungsverantwortliche dürfen Mangel-Status ändern/erledigen
CI / backend-tests (push) Failing after 1m40s
CI / frontend-build (push) Successful in 17s
Nutzer-Entscheidung: Status ändern/Erledigen bleibt nicht nur Materialverant-
wortlichen+Admin vorbehalten, Leitungsverantwortliche gehören ebenfalls dazu.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
2026-09-05 13:42:28 +02:00
patrickandClaude Sonnet 5 e9904d5bea feat(dashboard): drei fehlende Kacheln (Kennzahlen, Mängel, Qualifikationsablauf)
CI / backend-tests (push) Failing after 1m40s
CI / frontend-build (push) Successful in 17s
Kennzahlen: bestehender Endpoint /dashboard/kennzahlen war seit Prompt 12.1
nie im Frontend verdrahtet - jetzt eigene Kachel (offene Fehlbestände,
genehmigte Mindermengen, kürzlich erledigt, problematische Objekte, Objekte
gesamt).

Mängel: eigene Übersicht (offen/kritisch-Zahl + aufklappbare Liste) zusätzlich
zur bisherigen Erwähnung als Grund in Kachel 1 - nutzt bestehendes GET
/maengel, kein neuer Backend-Code.

Qualifikationsablauf: neuer Endpoint /dashboard/qualifikationsablaeufe
(bevorstehende_qualifikationsablaeufe(), 60 Tage Vorlauf) - analog
bevorstehende_prueftermine, aber für BenutzerQualifikation.gueltig_bis
(Nutzer-Vorgabe: "wer verliert bald Führerschein/Lehrgang-Gültigkeit").

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
2026-09-05 13:38:42 +02:00
patrickandClaude Sonnet 5 15fb8dbb16 feat(fahrzeug): Fahrzeug-Spezialfelder + 5-stufiger Status (Roadmap Phase 3)
CI / backend-tests (push) Failing after 1m40s
CI / frontend-build (push) Successful in 17s
Neue Tabelle fahrzeugdetails (1:1 zu Objekt, additiv/optional): Kennzeichen,
Funkrufname, Baujahr, Kilometerstand, Betriebsstunden, nächste HU/UVV.
objekt_status um 'in_wartung' erweitert (Nutzer-Vorgabe: einsatzbereit/
eingeschränkt/nicht einsatzbereit/in Wartung/außer Dienst - die ersten drei
bleiben weiterhin rein rechnerisch über dashboard.einsatzbereitschaft(),
in_wartung/ausser_dienst sind die beiden manuell gesetzten Zustände).

dashboard.einsatzbereitschaft(): ausser_dienst-Objekte zählen nicht mehr mit,
in_wartung und überfällige HU/UVV sind neue Gründe für "nicht einsatzbereit".

dashboard.bevorstehende_prueftermine() (Kachel 2) zeigt jetzt Geräte- UND
Fahrzeugprüfungen (HU/UVV) in einer Liste (Nutzer-Vorgabe: ein Konzept für
"welche Prüfungen bald fällig sind") - Schema dafür verallgemeinert
(typ/bezeichnung/faelligkeitsdatum statt geräte-spezifischer Felder).

Frontend: Status-Dropdown + Fahrzeugdetails-Formular in ObjektSection
(nur für Objekttypen mit ist_zugfahrzeug=True), Dashboard-Kachel 2 zeigt
gemischte Liste.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
2026-09-05 13:36:01 +02:00
patrickandClaude Sonnet 5 eb20affd5d feat(mangel): Mangel-Ticket-System (Roadmap Phase 2)
CI / backend-tests (push) Failing after 1m37s
CI / frontend-build (push) Successful in 18s
Eigener Workflow für Schäden/Defekte, getrennt von Fehlbestand (Mengen-
Abweichung Soll/Ist). Status: neu → in_bearbeitung → ersatzteil_bestellt/
reparatur_geplant → erledigt. entitaet_typ/entitaet_id optional (Objektposition
oder Geräteinstanz), analog zum bestehenden historie.entitaet_typ-Muster,
objekt_id immer gesetzt für Dashboard-Abfragen.

Ein offener Mangel mit prioritaet=hoch macht das Objekt "nicht einsatzbereit"
(neuer Grund mangel_kritisch_offen in dashboard.einsatzbereitschaft) -
niedrige/normale Mängel blockieren nicht.

Melden/Lesen: alle Mitarbeiter+. Status ändern: Materialverantwortliche+.
Neue Seite /maengel für alle eingeloggten Nutzer (Nav-Link "Mängel").

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
2026-09-05 13:23:38 +02:00
patrickandClaude Sonnet 5 d71d95e17f feat(personal): Personal/Qualifikationen-Modul (Roadmap Phase 1)
CI / frontend-build (push) Successful in 17s
CI / backend-tests (push) Failing after 1m32s
Neues Modul für die BOS-Ressourcenplattform-Erweiterung: Einheit (Zug/Gruppe,
self-referenzierend), Qualifikationstyp (Führerschein/Lehrgang/Berechtigung),
BenutzerQualifikation (mit Gültigkeit) und ObjekttypQualifikationsanforderung
(M:N) - beantwortet "wer darf dieses Fahrzeug fahren?" über
GET /objekte/{id}/berechtigung/{benutzer_id}.

Benutzer und Objekt bekommen optionale einheit_id (additiv, analog
fahrzeug_id-Muster). Nebenbei Bugfix: PATCH /benutzer konnte einheit_id nicht
auf null setzen (Feld-vorhanden-Check via model_fields_set statt is not None).

Frontend: neuer Admin-Tab "Personal" (Einheiten, Qualifikationstypen,
Benutzer-Qualifikationszuordnung), Einheit-Auswahl im Benutzer-Formular.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
2026-09-05 11:13:37 +02:00
patrickandClaude Sonnet 5 c3f141f7b0 feat(objekt): letzte abgeschlossene Kontrolle je Objekt anzeigen
CI / backend-tests (push) Failing after 1m28s
CI / frontend-build (push) Successful in 17s
Bisher nirgends vermerkt/abrufbar, wann ein Objekt zuletzt komplett
kontrolliert wurde (nur roh in kontrolle.beendet_am ableitbar). Neues Feld
ObjektRead.letzte_kontrolle_am (jüngste Kontrolle mit status=abgeschlossen),
angezeigt in Objektliste und Admin-Objektsektion ("noch nie kontrolliert"
falls keine).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
2026-09-05 11:00:49 +02:00
patrickandClaude Sonnet 5 69d6956d23 feat(login): Verantwortliche landen nach Login auf /dashboard
CI / backend-tests (push) Failing after 1m25s
CI / frontend-build (push) Successful in 24s
Materialverantwortlicher/Leitungsverantwortlicher/Administration werden nach
Login direkt zum neuen Leitungs-Dashboard geleitet statt zur Objektliste.
rollen im AuthContext laden asynchron nach - daher hier direkt /auth/me
abfragen statt auf den Context zu warten.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
2026-09-05 10:39:06 +02:00
patrickandClaude Sonnet 5 54fc29690a feat(objekt): Zugfahrzeug-Flag am Objekttyp + Leitungs-Dashboard-Kacheln
CI / backend-tests (push) Failing after 1m26s
CI / frontend-build (push) Successful in 24s
Objekttyp.ist_zugfahrzeug (Migration 0011) grenzt die Fahrzeug-Zuordnung
serverseitig auf tatsächliche Zugfahrzeuge ein (422 bei Verstoß), Frontend
filtert die Fahrzeug-Dropdowns entsprechend.

Neue Dashboard-Endpunkte /dashboard/einsatzbereitschaft und
/dashboard/prueftermine plus DashboardPage mit drei Kacheln
(Einsatzbereitschaft, Prüftermine, Ablaufdaten). Aktive
Mindermengen-Genehmigung zählt als "eingeschränkt einsatzbereit", nicht als
voll einsatzbereit (U2/Karte 08).

Neue FehlbestandListePage: Fehlbestände eigenständig nachfüllen/Mindermenge
genehmigen, ohne komplette Kontrolle des Objekts zu starten (Backend
existierte bereits, nur das Frontend fehlte).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
2026-09-05 10:33:00 +02:00
patrickandClaude Sonnet 5 38b8ce1795 fix(objekt): Fahrzeug-Zuordnung als 1:n statt n:m (fachliche Korrektur)
CI / backend-tests (push) Failing after 1m23s
CI / frontend-build (push) Successful in 29s
Nutzer-Korrektur: "Ein Objekt gehört immer nur zu genau einem Fahrzeug"
- Spalte gezogen_von_objekt_id -> fahrzeug_id (Rename-Migration 0010)
- Zuvor begonnener n:m-Ansatz (objekt_kopplung Tabelle/Endpoints/Panel)
  wieder entfernt, da fachlich falsch
- PATCH /objekte/{id} prüft Existenz + direkten Zyklus (A<->B)
- Frontend: einfache Single-Select "Fahrzeug zuordnen" statt Kopplungs-Panel

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-05 01:11:25 +02:00
patrickandClaude Sonnet 5 13ff2838fa Materialstamm: Blutdruckmanschette ALT geklärt + Zuständigkeitsliste mit Suche
CI / backend-tests (push) Failing after 1m18s
CI / frontend-build (push) Successful in 24s
89 "Blutdruckmanschette" <- 91 "Blutdruckmanschette ALT" zusammengelegt
(152 Materialien). Echter Konflikt an 7 Objekten geprüft und dokumentiert -
kein Datenverlust (Konfliktzeilen alle im Default-Zustand, einziger echter
Historie-Treffer korrekt umgehängt statt gelöscht).

ZustaendigkeitSection: gleiches zweispaltiges Layout mit Suche wie Material-/
Objektliste. screenshots/ ins .gitignore (lokale Debug-Bilder, nicht für
den Remote gedacht).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-05 00:10:22 +02:00
patrickandClaude Sonnet 5 34150d8d45 Objektliste: gleiches zweispaltiges Layout mit Suche wie Materialliste
CI / backend-tests (push) Failing after 1m20s
CI / frontend-build (push) Successful in 19s
Anlegen-Formular links fix (20rem, nur Admin), Objektliste rechts mit
Suchfeld oben (Name/Code) - gleiches Muster wie MaterialSection, wächst
mit der Anzahl Objekte mit statt unsuchbare Liste zu werden.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 23:14:27 +02:00
patrickandClaude Sonnet 5 f11162ebfb fix(admin): "Material hinzufügen" in die Kartenspalte verschoben
CI / backend-tests (push) Failing after 1m20s
CI / frontend-build (push) Successful in 25s
Saß bisher als volle Bar über Sidebar+Kartenspalte (Screenshot-Fund) - jetzt
Teil der rechten Kartenspalte, direkt über der Positionsliste. Sidebar wird
nur noch gerendert, wenn Positionen existieren (Edge-Case: leeres Objekt
konnte bisher kein erstes Material bekommen, da der ganze Bereich hinter
positionen.length>0 hing).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 23:09:29 +02:00
patrickandClaude Sonnet 5 6f047e3033 Materialliste: zweispaltiges Layout mit Suche
CI / backend-tests (push) Failing after 1m21s
CI / frontend-build (push) Successful in 23s
Formular (Anlegen/Bearbeiten) links fix, Liste rechts mit Suchfeld oben
(Name/Artikelnummer) - bei 153 Materialien war die reine Scroll-Liste ohne
Suche kaum nutzbar.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 23:00:01 +02:00
patrickandClaude Sonnet 5 423aece15f fix(admin): Fach-Sidebar bricht Layout - explizite Flex-Breite statt minWidth
CI / backend-tests (push) Failing after 1m19s
CI / frontend-build (push) Successful in 19s
Sidebar wuchs auf fast volle Containerbreite statt schmal zu bleiben (Screen-
shot-Fund). flex:"0 0 12rem" + explizite width statt nur minWidth, position:
sticky entfernt (unklarer Faktor, nicht essentiell).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 22:56:06 +02:00
patrickandClaude Sonnet 5 d8e3f3aa21 Bestückungs-Pflege: Fach-Sidebar + Verwaltung linksbündig statt zentriert
CI / backend-tests (push) Failing after 1m20s
CI / frontend-build (push) Successful in 24s
ObjektPositionenPanel: Fach-Sidebar (Vorlagen-Feature "feste Fächer-Liste")
links, damit die Bestückung übersichtlich bleibt und auch Dritte (Vertretung
ohne die Kontrollperson) sehen, wo welches Material im Rucksack hingehört.
Gruppierungslogik aus KontrollPage in gemeinsames Util (utils/fachGruppierung)
ausgelagert, da jetzt zweimal gebraucht.

.page-wide: margin:0 statt zentriert (Nutzer-Vorgabe: bei 1200px sonst viel
verschenkter Platz links/rechts auf breiten Monitoren).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 22:51:43 +02:00
patrickandClaude Sonnet 5 a7b670f6f8 Bestückung eines Objekts vollständig pflegbar (Sollmenge/Status/Neuanlage)
CI / backend-tests (push) Failing after 1m18s
CI / frontend-build (push) Successful in 19s
ObjektPositionenPanel zeigte bisher nur ablauf_charge/geraet_sn-Positionen
und konnte weder Sollmenge-Override noch Status noch neues Material ändern
- Backend-Endpunkte (PATCH/POST .../positionen) existierten schon, waren im
Frontend nicht angebunden.

Jetzt: alle Positionen sichtbar, Sollmenge-Override je Position, Entfernen/
Reaktivieren (ist_status), zusätzliches Material hinzufügen (Dropdown mit
noch nicht vorhandenen Materialien + Sollmenge).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 22:35:24 +02:00
patrickandClaude Sonnet 5 a2b201ddb8 Verwaltung: breiteres Layout für Admin/Material-/Leitungsverantwortliche
CI / backend-tests (push) Failing after 1m19s
CI / frontend-build (push) Successful in 22s
.page-wide (max-width 1200px statt 640px) für die AdminPage - Tabellen
(Änderungslog) und mehrspaltige Formulare brauchen am Desktop mehr Platz
als die mobile Kontroll-Ansicht der Mitarbeiter. Objektliste/Kontrolle/
Login bleiben bei .page (640px, mobile-optimiert).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 22:31:16 +02:00
patrickandClaude Sonnet 5 7f5bbb65d5 Rollen-differenzierte Verwaltungs-UI (Material-/Leitungsverantwortliche)
CI / backend-tests (push) Failing after 1m19s
CI / frontend-build (push) Successful in 23s
Bug: Frontend prüfte nur istAdmin, Materialverantwortliche und Leitungs-
verantwortliche sahen exakt dieselbe UI wie Mitarbeiter - obwohl das Backend
längst granular unterscheidet (require_roles je Endpunkt).

- AuthContext gibt volle Rollenliste + istVerantwortlich/istMaterial-
  verantwortlich/istLeitungsverantwortlich weiter.
- /admin-Route für alle drei Rollen offen, AdminPage filtert Tabs nach
  Rolle (Material/Leitung: Objekte-Pflege, Kontrollverantwortung,
  Änderungslog; nur Administration: Stammdaten/Benutzer/Eskalation/
  Zuständigkeit).
- ObjektSection blendet Anlegen/Duplizieren/Kopplung für Nicht-Admins aus
  (waren admin-only im Backend, hätten 403 geworfen).
- Promise.allSettled statt Promise.all beim Laden, damit ein admin-only
  Endpunkt (z.B. /benutzer) nicht die ganze Seite für niedrigere Rollen
  blockiert.
- Backend: GET /benutzer jetzt auch für Material-/Leitungsverantwortliche
  lesbar (für Kontrollverantwortung-Auswahl im Frontend nötig), Schreiben
  bleibt admin-only.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 22:25:32 +02:00
patrickandClaude Sonnet 5 6934276e8a Karte 14 Schritt 2 (Admin-Teil) + Frontend für Anhänger-Kopplung
CI / backend-tests (push) Failing after 1m21s
CI / frontend-build (push) Successful in 22s
Backend: geraet_instanz-CRUD (Liste/Anlegen/Status ändern inkl. optionalem
Fehlbestand pro Gerät/Löschen), pruefintervall_monate in Objektposition-
Schemas verdrahtet (Prüfdatum -> naechste_pruefung wird automatisch
berechnet, Monatsrechnung ohne neue Dependency).

Frontend: GeraeteInstanzenListe ersetzt das Einzel-SN-Feld im Admin-Portal
(ObjektPositionenPanel) durch eine Instanz-Liste mit Status/Prüfdatum/
Bemerkung je Exemplar - löst das Karte-14-Kernproblem (mehrere Geräte pro
Position). ObjektSection: Anhänger-Kopplung bei Anlage und nachträglich
änderbar.

Kontroll-Erfassung (PositionCard/KontrollPage) bleibt unverändert - die
komplett neue Erfassungs-UI für geraet_sn (Umsetzungsschritt 4, Karte 14)
ist bewusst nicht Teil dieses Commits.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 20:55:09 +02:00
patrickandClaude Sonnet 5 4c87bf2d84 Zuständigkeit im Frontend anbinden (Karte 04)
CI / backend-tests (push) Successful in 1m13s
CI / frontend-build (push) Successful in 19s
Neuer Admin-Tab "Zuständigkeit": Benutzer materialverantwortlich für Standort
(vererbt sich auf alle Objekte dort) oder einzelnes Objekt zuordnen, Liste,
Entfernen. Backend-Endpunkte (inkl. DELETE) waren bereits vorhanden.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 20:26:47 +02:00
patrickandClaude Sonnet 5 c1f6eaa14c Kontrollverantwortung im Frontend anbinden (Karte 01)
CI / backend-tests (push) Successful in 1m14s
CI / frontend-build (push) Successful in 23s
Backend: DELETE /kontrollverantwortung/{id} ergänzt (fehlte bisher). Frontend:
neuer Admin-Tab "Kontrollverantwortung" - Objekt + Benutzer/Gruppe zuordnen,
Liste, Entfernen. Reine Sichtbarkeit/Priorisierung, keine Pflichtkontrolle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 20:22:32 +02:00
patrickandClaude Sonnet 5 fbae3fccc7 Kontroll-Erfassung: Positionen nach Fach gruppieren
CI / backend-tests (push) Successful in 1m11s
CI / frontend-build (push) Successful in 26s
useKontrolle lädt zusätzlich die Vorlage und mappt Fach je Material.
KontrollPage gruppiert die Erfassung nach Fach (Vorlagen-Reihenfolge,
"Ohne Fach" zuletzt, keine Überschrift falls alles ohne Fach) statt flacher
Liste - näher am Regal-/Fahrzeug-Layout. E2E-Mocks um Vorlage-Route ergänzt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 20:13:38 +02:00
patrickandClaude Sonnet 5 5805366306 Admin-Portal: Eskalations-Konfiguration-UI (Karte 12)
CI / backend-tests (push) Successful in 1m12s
CI / frontend-build (push) Successful in 23s
Neuer Tab "Eskalation": Zeitschwellen (Erinnerung/Leitung, Tage) lesen/ändern
über GET/PUT /eskalation/konfiguration, "Jetzt prüfen"-Button stößt denselben
Lauf wie der tägliche systemd-Timer manuell an.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 20:04:08 +02:00
patrickandClaude Sonnet 5 e949b5e9ac Materialänderungslog: Historie-Endpunkt + Admin-Tab
CI / backend-tests (push) Successful in 1m11s
CI / frontend-build (push) Successful in 25s
historie-Tabelle (append-only Audit-Trail über Kontrolle/Fehlbestand/
Nachfüllung/Mindermenge) war bisher nur intern befüllt, ohne API/UI. Neu:
GET /api/v1/historie (gefiltert nach Typ/ID/Benutzer/Zeitraum, paginiert,
Benutzername aufgelöst), Admin-Portal-Tab "Änderungslog" mit Typ-Filter.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 19:54:01 +02:00