Command Palette lud bisher beim Öffnen ALLE Objekte und filterte nur
clientseitig per .includes() - unscharf und würde bei mehr Objekten
langsam werden. Jetzt: GIN-Trigram-Index auf objekt.name/code (Migration
0023), neuer GET /suche?q=-Endpunkt (Ähnlichkeits-Ranking per pg_trgm
similarity()), Frontend debounced (250ms) statt vollständiger Objektliste.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
44px-Mindestgröße für Buttons/Inputs (Feldeinsatz mit Handschuhen), echte
Label-Verknüpfung statt reinem placeholder auf allen Kontroll-Eingabefeldern,
aria-live-Statusansagen beim Speichern/Fehler einer Position und beim Öffnen
des Nachfüll-Dialogs, NachfuellDialog jetzt mit role="dialog"/aria-modal,
Fokus beim Öffnen und Esc zum Schließen, Pflichtfeld Begründung mit
aria-required.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
Dashboard-Raster von 12 auf 24 Spalten - bei 12 waren Reihen sofort randvoll (3 Kacheln à w:4), kein Spielraum zum Breiter-Ziehen ohne Nachbarkachel zu verkleinern. Layout-localStorage-Key auf v3 gehoben (alte v2-Koordinaten passen nicht mehr zum neuen Raster). Sidebar links jetzt einklappbar (Toggle-Button bleibt sichtbar, Zustand in localStorage) - mehr Platz für breite Dashboard-Raster auf Desktop-Monitoren.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
Vorheriger Fix (--mabea-* Zwischen-Variablen) hat den Zirkel nur eine Ebene verschoben statt aufgelöst: da @theme weiterhin --color-primary selbst neu definierte (höherer Layer als global.css), zeigte --mabea-primary auf --color-primary, welches wiederum auf --mabea-primary zeigte - derselbe Zirkel, nur indirekt. Coming from CSS-Spec: eine zirkuläre var()-Kette macht die Property zur "guaranteed-invalid value", unabhängig davon über wie viele Zwischenschritte sie läuft.
Echter Fix: kein @theme-Mapping auf --color-* mehr, damit keine Namenskollision mit global.css überhaupt erst entstehen kann. Alle betroffenen Tailwind-Klassen (bg-primary, text-danger, border-l-warning, bg-surface-sunken, text-muted-foreground, ring-primary, etc.) auf Arbitrary-Value-Syntax umgestellt (z.B. bg-[var(--color-primary)]) - referenziert global.css-Variablen direkt, ohne je einen neuen Property-Namen im Theme-Layer zu belegen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
@theme-Mapping in tailwind.css hatte Einträge wie "--color-primary: var(--color-primary)" - gleicher Name wie in global.css, also Selbstreferenz auf dieselbe Custom Property. Laut CSS-Spec wird eine zirkuläre var()-Referenz zur "guaranteed-invalid value" - die Property bricht dadurch komplett weg, nicht nur für neue Tailwind-Utilities, sondern für JEDE Regel im ganzen Projekt, die dieselbe Property liest (z.B. .btn-primary in global.css, .badge-danger, etc.). Betraf: primary, primary-hover, primary-soft, danger, danger-bg, warning, warning-bg, success, success-bg, surface, surface-sunken, border, border-strong - praktisch die gesamte Farbpalette der App, nicht auf Dashboard beschränkt. Sichtbar u.a. als unsichtbarer weißer Text auf weißem "Trotzdem übernehmen"-Button (Kontrolle-Seite bei gesperrtem Objekt). Fix: Zwischen-Variablen mit eigenem Namen (--mabea-*) in tailwind.css, keine Namenskollision mehr.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
Race Condition: bei bereits eingeloggter Session (Direktaufruf/Reload von "/" oder /dashboard/etc.) ist "eingeloggt" sofort true (Token im Storage), "rollen" aber noch [] bis /auth/me durch ist. Startseite/AdminRoute haben in genau diesem kurzen Fenster mit istVerantwortlich=false entschieden und per Navigate replace auf /objekte umgeleitet, bevor die echten Rollen (z.B. "administration") eintrafen - Admin landete dadurch nie auf dem Dashboard, sondern immer auf Objekte. Neues rollenGeladen-Flag im AuthContext, Startseite/AdminRoute warten jetzt darauf statt vorschnell mit rollen=[] zu entscheiden.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
react-grid-layout/react-resizable hängt den Resize-Griff per children-Injection an (cloneElement(child, {}, ...child.props.children, handle)) - erwartet einen DIREKTEN Kindknoten der Grid-Item-Wurzel (CSS ".react-grid-item > .react-resizable-handle"). TileFrame rendere "children" bisher nur verschachtelt in CardContent, die CSS-Regel griff dort nicht - Griff blieb unsichtbar/nicht greifbar. Fix: eigener Kachel-Inhalt läuft jetzt über eine separate "inhalt"-Prop, "children" (das react-grid-layout für den Griff nutzt) wird direkt unter Card gerendert.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
Root Cause (Screenshot-Analyse): .page-wide hatte kein width:100%/flex:1 wie .page - als Flex-Kind von .app-shell schrumpfte es auf reine Content-Breite. react-grid-layout positioniert Kacheln absolut (kein Beitrag zur intrinsischen Breite), dadurch kollabierte der ganze Grid-Container auf ~380px statt volle verfügbare Breite - Kacheln dadurch winzig, Text lief mitten im Wort ab. Fix: .page-wide bekommt flex:1/width:100%. Zusätzlich CardHeader/CardTitle mit min-w-0/truncate gegen abgeschnittene Titel, Einsatzbereitschaft-Vierer-Zeile von sm:grid-cols-4 (reagiert auf Viewport-, nicht Kachel-Breite) auf festes grid-cols-2 - lief in schmalen Kacheln trotz breitem Viewport ineinander.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
Card: 14px Radius, weicherer Schatten, Hover-Lift über box-shadow (nicht transform, würde von react-grid-layouts Inline-Positionierung überschrieben). Einsatzbereitschaft-Kachel: große Zahl "X/Y einsatzbereit", proportionaler gestapelter Statusbalken, Vierer-Zeile mit Farbpunkten+Zahl, Detail-Liste bleibt aufklappbar. Prüftermine/Ablaufdaten/Qualifikationsablauf: auf 5 Zeilen begrenzt mit "Alle anzeigen", Status-Badge links (überfällig gefüllt rot, bald fällig Outline amber, FristBadge zeigt nur noch Status), Countdown rechts tabular-nums. Neue --status-ok/warn/unknown/critical CSS-Variablen als Alias auf bestehende Farb-Tokens. Skeleton-Platzhalter statt "Lade…"-Text während des initialen Ladens. Keine API-/Datenänderungen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
@dnd-kit (nur Reihenfolge tauschen) durch react-grid-layout ersetzt - Kacheln lassen sich jetzt frei auf einem 12-Spalten-Raster positionieren (nicht nur umsortieren) UND per Ecke ziehen dynamisch in der Größe ändern (nicht nur zwischen 4 festen Stufen wechseln). Layout-Modell in layout.ts auf x/y/w/h pro Kachel umgestellt (vorher Reihenfolge-Array + Größen-Enum). TileFrame vereinfacht (kein Drag-Griff/Größen-Button mehr nötig, das übernimmt die Grid-Lib direkt an der Kachel).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
Root Cause fürs "sieht noch alt aus": global.css wurde separat unlayered importiert, Tailwind-Utilities liefen in layer(utilities). Unlayertes CSS gewinnt in der CSS-Kaskade IMMER gegen jeden Layer, unabhängig von Spezifität - die meisten neuen Tailwind-Klassen (text-4xl, rounded-lg, border-l-*, etc.) wurden dadurch von alten global.css-Regeln überstimmt, ohne sichtbaren Effekt. Fix: global.css läuft jetzt selbst in einem eigenen Layer ("global-css"), Layer-Reihenfolge explizit deklariert (global-css < theme < utilities) - Tailwind gewinnt jetzt wie vorgesehen. main.tsx importiert global.css nicht mehr separat, das übernimmt tailwind.css per @import layer(global-css).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
React.memo auf allen 8 Kachel-Komponenten + TileFrame, damit Interaktionen (Anpassen/Monitor/Größe/Ausblenden) nicht mehr alle Kacheln unnötig neu rendern. Voraussetzung dafür: onAusblendenUmschalten/onGroesseAendern als stabile useCallback-Referenzen mit id-Parameter statt pro Kachel neu erzeugter Closures. Die vier Layout-Mutationsfunktionen (dragEnde/ausblendenUmschalten/groesseAendern/layoutZuruecksetzen) über eine gemeinsame aktualisiereLayout-Helper-Funktion mit funktionalem setState dedupliziert (vermeidet stale-closure-Risiko bei schnellen Interaktionen). Instabile Index-Keys in PrueftermineTile/AufgabenTile durch stabile Keys ersetzt. maengelOffenListe in MaengelTile mit useMemo. Fehler-Anzeige bekommt "Erneut versuchen"-Button. Drag-Griff in TileFrame: type="button" + aria-roledescription für Screenreader.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
Dashboard immer Startseite für Verantwortliche (Mitarbeiter -> Objekte), kaputte Startseiten-Auswahl entfernt. Neu gemeldete Mängel als eigener Hinweis. Kacheln per Anpassen-Modus verschieb-/ausblendbar (localStorage), Status-Monitor-Modus mit Vollbild und Auto-Refresh (60s). DashboardPage dabei in kleine Dateien pro Kachel gesplittet.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
Verwendung je Material einsehbar (Objektposition/Vorlagenposition/
Bestand/Kontrollposition/Fehlbestand/Ausgabe/Nachfüllung/
Materialbewegung), POST /materialien/{id}/ersetzen hängt alle
Referenzen auf ein Ziel-Material um und löscht die Quelle. Bricht bei
Konflikten ab (z.B. dasselbe Objekt hätte danach zwei Positionen für
dasselbe Material) statt Daten stillschweigend zu verlieren. Admin-UI:
"Zusammenführen" je Material zeigt Verwendung + Ziel-Auswahl.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
Anlegen prüft jetzt case-insensitiv auf Duplikate (409 statt "Fach A"
neben "fach a"). Neuer Endpunkt GET /faecher/{id}/objekte zeigt, welche
Objekte ein Fach über ihre Vorlage tatsächlich nutzen. POST
/faecher/{id}/ersetzen benennt um und zieht alle Vorlagenpositionen
mit; landet der neue Name auf einem bereits bestehenden Fach, werden
beide zusammengeführt. Frontend: Fach anklicken öffnet Verwendung +
Ersetzen-Eingabe direkt in der Fächer-Verwaltung.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
Bei 22 nachgetragenen Fächern über mehrere Objekttypen war die flache
Liste unübersichtlich. Nutzt das bereits vorhandene Objekttyp-Dropdown
(zum Anlegen) auch als Filter für die Liste darunter, statt ein
zusätzliches Element einzuführen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
Bevorstehende Ablaufdaten waren nur im Dashboard und als
Einsatzbereitschafts-Grund sichtbar, nicht direkt an der jeweiligen
Beladungsposition in der Akte. Neue Spalte "Ablauf", rot bei
überfälligem, gelb bei <30 Tagen verbleibender Zeit.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
Beide Elemente trugen die Klasse akte-kopf und damit dasselbe
grid-area - das CSS-Grid platzierte sie übereinander statt
untereinander. Jetzt ein gemeinsamer Container mit einem grid-area.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
Neues Wartungskonzept: Wartungsplan+Position+Intervall (zeit/km/
Betriebsstunden, kombinierbar - fällig sobald ein Kriterium erreicht
ist), Wartungsauftrag mit intern/externer Werkstatt, Status offen/
in_arbeit/erledigt, Kosten, Historie, Dokument-Anhang. Ad-hoc-Aufträge
ohne Plan möglich (z.B. kleinere Reparatur). Admin-Tab "Wartungspläne".
Objektakte-Redesign (Epic 21, Nutzer-Feedback "wirkt nicht modern"):
CSS-Grid statt Karten-Stapel, einspaltig mobil, zweispaltig ab 900px;
Fahrzeug-Objekte zeigen Wartung/Fahrzeugdaten prominent, Geräte/
Rucksäcke die Beladung. Dabei gefundene Lücke: Beladung (Soll/Ist je
Position) fehlte in der Akte komplett, nur über eine laufende
Kontrolle sichtbar - jetzt eigene Karte.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
Dashboard-Listen "Nächste Prüftermine"/"Bevorstehende Ablaufdaten"
hatten keinen Link zum betroffenen Objekt - ein überfälliger Termin
war nicht erreichbar. Zusätzlich: "Prüfung heute durchgeführt"-Button
je Gerät auf der Akte (PATCH /geraete/{id}), bisher nur über die
Admin-Objektbearbeitung möglich.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
_synchronisiere_fehlbestand suchte nur nach Fehlbeständen der eigenen
Kontroll-Sitzung. Ein bereits offener Fehlbestand aus einer früheren
Kontrolle für dasselbe Objekt+Material wurde nicht wiedergefunden -
es entstand ein zweiter, paralleler Fehlbestand mit eigener (neuerer)
Sollmenge, der alte blieb mit veralteter Sollmenge offen liegen.
Lookup jetzt über objekt_id+material_id+status=offen statt
kontrolle_id; kontrolle_id am gefundenen Datensatz bleibt unverändert,
damit ein Abbruch der aktuellen Kontrolle ihn nicht fälschlich
mitlöscht. Löst sich die Abweichung über eine andere Kontrolle als
die erzeugende auf, wird der Fehlbestand jetzt sauber als erledigt
markiert (inkl. Mindermenge-Abschluss) statt stillschweigend gelöscht.
Nebenbei: Kommentare mit Kachel-/Datums-Referenzen ("Bug-Fund
2026-09-06", "UI-00X (Epic 20)") aus dem Code dieser Session entfernt.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
Karte "Letzte Aktivität" nutzt GET /historie (kein neuer Endpunkt),
statt Ereignisse nur pro Objekt in der Akte sehen zu können. Lesbare
Ereignis-Labels (EREIGNIS_LABEL) auch in AktePage statt rohem
ereignistyp-String. Angeregt durch Resgrid-Doku (Activity-Log-Panel).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
_kategorie_und_gruende() zählte "noch_nie_kontrolliert" bisher nur,
wenn es der EINZIGE Grund war - ein Objekt mit z.B. offenem
Fehlbestand UND nie kontrolliert verlor den Hinweis komplett, landete
nur unter "nicht einsatzbereit" ohne diesen Grund zu nennen. Jetzt
immer als Zusatzgrund angehängt. Neues Feld nie_kontrolliert_gesamt
liefert die tatsächliche Gesamtzahl über alle Kategorien hinweg,
Dashboard nutzt sie statt der (bewusst engeren) "unbekannt"-Kategorie.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
FehlbestandListePage, MangelListePage (Status + Prioritäts-Badge statt
Inline-Farbe) und admin/GeraeteInstanzenListe zeigten Status immer als
neutrales Badge statt farblich zu unterscheiden. Letzte hartkodierte
Hex-Fallbacks (NachfuellDialog, BeladungsplanerBoard) auf reine Tokens
umgestellt. Damit ist Epic 20 (UI-Redesign, UI-001..008) vollständig
durchlaufen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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