Commit Graph
182 Commits
Author SHA1 Message Date
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 cf97b2e13d Materialstamm: Nachkontrolle bestätigt sauber, 6 Namen getrimmt
CI / backend-tests (push) Failing after 1m16s
CI / frontend-build (push) Successful in 20s
Nach allen Merges keine Dubletten/materialtyp-Fehler mehr. Führende/
nachgestellte Leerzeichen bei 6 Namen entfernt (kosmetisch).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 22:08:40 +02:00
patrickandClaude Sonnet 5 a15b2018bf Materialstamm-Bereinigung: Rollenpflaster 151 geklärt, zu "gross" gemerged
CI / backend-tests (push) Failing after 1m15s
CI / frontend-build (push) Successful in 18s
Original-Excel (Rettungsrucksack.xlsx, PAX SEG.xlsx) nutzt unspezifiziertes
"Rollenpflaster" ohne Größenangabe, kein Kontexthinweis auf schmal/breit/
gross. Nutzer-Entscheidung mangels Evidenz: Default auf "gross" (53).
153 Materialien nach Bereinigung.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 22:07:10 +02:00
patrickandClaude Sonnet 5 682bb49b2a Standort "GA San" + 6 Rettungsrucksäcke angelegt (Audit-Trail)
CI / backend-tests (push) Failing after 1m17s
CI / frontend-build (push) Successful in 23s
Live-Anlegelauf (bereits ausgeführt): Standort "GA San", 6x Objekt aus
Vorlage "Rettungsrucksack Standard" (RK-00001 bis RK-00006), Codes auf
Nutzer-Wunsch vorerst fortlaufend, spätere Umcodierung möglich.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 22:04:48 +02:00
patrickandClaude Sonnet 5 f77d2d6fa6 Materialstamm-Bereinigung: Beatmunsmaske geklärt, zu Größe S gemerged
CI / backend-tests (push) Failing after 1m18s
CI / frontend-build (push) Successful in 19s
Excel-Kontext (Rettungsrucksack.xlsx Zeile 50, direkt nach "Beatmungsbeutel
Kind") + Nutzer-Bestätigung: "Beatmunsmaske" (102) war die S-Größe, andere
Rucksäcke führen Beatmungsmaske S/M/L bereits einzeln. Zusammengelegt mit
161 "Beatmungsmasken S" (154 Materialien).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 21:27:56 +02:00
patrickandClaude Sonnet 5 411e67a51f Materialstamm-Bereinigung 2026-09-04: 17 Dubletten zusammengelegt
CI / backend-tests (push) Failing after 1m17s
CI / frontend-build (push) Successful in 23s
Live-Datenbereinigung (172 -> 155 Materialien): Excel-Import-Tippfehler und
Leerzeichen-Varianten zusammengelegt, Material 148 "Manometer SN 1308409"
korrigiert (Name -> "Manometer", materialtyp -> geraet_sn, SN als erste
geraet_instanz-Zeile). Skript und Entscheidungsprotokoll (inkl. bewusst
unverändert gelassener Fälle) dokumentiert für Nachvollziehbarkeit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 21:24:15 +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 eff9fe4956 Fahrzeug/Anhänger-Kopplung (objekt.gezogen_von_objekt_id)
CI / backend-tests (push) Failing after 1m12s
CI / frontend-build (push) Successful in 19s
Nutzer-Vorgabe: Fahrzeug und Anhänger beide als eigenständige Objekte
möglich, optional fest gekoppelt. Selbstreferenzierende nullable FK, kein
eigener Anhänger-Objekttyp nötig (Objekt bleibt generisch, Karte 11).
POST /objekte übergibt das Feld, neuer PATCH /objekte/{id} zum
nachträglichen Setzen/Lösen.

Von postgres-expert gegengeprüft, Fixes übernommen: ON DELETE SET NULL
(Zugfahrzeug entfernen blockiert Anhänger nicht), CHECK-Constraint gegen
Selbstbezug, Existenzprüfung + direkter Zyklus-Check (A↔B) im Endpoint statt
unhandled 500. Mehrstufige Ketten bewusst nicht geprüft (kein Anwendungsfall).

Tests: Anlage mit/ohne Kopplung, nachträglich setzen/lösen, Selbstbezug,
ungültiges Ziel, direkter Zyklus.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 20:48:35 +02:00
patrickandClaude Sonnet 5 d61aabadf3 Karte 14 Schritt 1: geraet_instanz-Tabelle (additiv)
CI / backend-tests (push) Successful in 1m13s
CI / frontend-build (push) Successful in 23s
objektposition.seriennummer war ein Einzelfeld, konnte nur EIN Gerät pro
Materialtyp/Objekt abbilden (z.B. 2 Pulsoxymeter im selben Rucksack nicht
darstellbar). Neue Tabelle geraet_instanz erlaubt beliebig viele Exemplare
pro Position (Seriennummer, Prüfdatum, nächste Prüfung, Status). Zusätzlich
objektposition.pruefintervall_monate (individuell überschreibbar).

Bewusst additiv: seriennummer-Spalte bleibt vorerst stehen (Service/
Endpunkte/Frontend hängen noch daran), bestehende Werte werden per
INSERT...SELECT nach geraet_instanz kopiert. Drop + Umbau der abhängigen
Schichten folgt in Umsetzungsschritt 2 (siehe arbeitskarten/14_...).

Migration von postgres-expert gegengeprüft (ON CONFLICT DO NOTHING als
Sicherheitsnetz, DROP TYPE IF EXISTS ergänzt), Tests decken Mehrfach-
Instanzen, UNIQUE-Constraint je Position, gleiche SN an verschiedenen
Positionen und pruefintervall_monate ab.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 20:45:04 +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
patrickandClaude Sonnet 5 d7c3e52002 fix(migration): revision-id 0007 kürzen (alembic_version ist VARCHAR(32))
CI / backend-tests (push) Successful in 1m8s
CI / frontend-build (push) Successful in 18s
"0007_indizes_und_unique_constraints" (37 Zeichen) sprengte die Spalte,
Statements liefen alle durch, nur das abschließende UPDATE auf
alembic_version schlug fehl - sauber zurückgerollt (transaktionale DDL),
beim echten Deploy-Lauf aufgefallen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 18:49:24 +02:00
patrickandClaude Sonnet 5 9c85f715d9 fix(migration): 0007 - ein op.execute() pro Statement (asyncpg-Limitierung)
CI / backend-tests (push) Failing after 17s
CI / frontend-build (push) Successful in 19s
asyncpg lehnt mehrere Kommandos in einem prepared statement ab ("cannot
insert multiple commands into a prepared statement") - beim echten Deploy-
Lauf gegen die Live-DB aufgefallen, sauber zurückgerollt (transaktionale DDL).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 18:48:49 +02:00
patrickandClaude Sonnet 5 ceddeb1bf4 Multi-Agent-Review: Race Conditions, DB-Indizes, TLS/Security-Härtung
CI / backend-tests (push) Failing after 19s
CI / frontend-build (push) Successful in 25s
Konsolidierte Funde aus postgres-/sql-/jwt-/owasp-top10-expert-Review:

- Race Conditions gefixt: doppelte aktive Kontrolle (SAVEPOINT + partieller
  Unique-Index), doppelte Mindermengen-Genehmigung (FOR UPDATE + Unique-Index),
  Lost-Update bei Nachfüllung (FOR UPDATE auf Fehlbestand/Objektposition).
- Migration 0007: partielle Unique-Indizes als DB-Sicherheitsnetz + fehlende
  FK-Indizes (fehlbestand.material_id, kontrolle(objekt_id,status),
  zustaendigkeit, benutzer_rolle.rolle, objektposition.ablaufdatum u.a.).
- Connection-Pool explizit begrenzt (pool_size=5, max_overflow=5) - ohne das
  könnte jeder uvicorn-Worker den Postgres max_connections-Wert sprengen.
- Timing-Angriff bei Login-Enumeration gefixt (konstante Antwortzeit über
  Dummy-Hash), JWT-Decode verlangt jetzt exp/sub-Claims.
- App-seitiges Rate-Limiting (slowapi, 5/min) auf /auth/login als Verteidigung
  in der Tiefe zusätzlich zum nginx-Limit.
- nginx: TLS mit selbstsigniertem Zertifikat (LAN-Betrieb, keine Domain),
  HSTS, Content-Security-Policy, Permissions-Policy ergänzt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 18:47:06 +02:00
patrickandClaude Sonnet 5 0909dacf2b Flutter-Tests: ApiClient, Offline-Queue, Login-/Objektliste-Widgets
CI / backend-tests (push) Successful in 1m5s
CI / frontend-build (push) Successful in 18s
ApiClient nimmt jetzt einen injizierbaren http.Client entgegen (Testbarkeit,
kein Verhaltensunterschied im Betrieb). Tests mocken ihn mit mocktail statt
echter Netzwerkaufrufe. offline_queue_test.dart nutzt sqflite_common_ffi
(reines Dart) für die Queue-Logik ohne Gerät/Emulator: Erfolg entfernt
Eintrag, Netzwerkfehler bleibt "wartet", 4xx setzt "fehler" ohne Auto-Retry.
Dazu Widget-Tests für Login-Flow und Objektliste-Suchfilter.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 18:38:17 +02:00
patrickandClaude Sonnet 5 c68d39b45f Flutter: Offline-Queue für Kontroll-Erfassung (Prompt 17-Härtung)
CI / backend-tests (push) Successful in 1m5s
CI / frontend-build (push) Successful in 22s
lib/offline/queue.dart (sqflite) analog zur React-PWA-Queue: enqueue statt
Direkt-Senden, Status wartet/wird_uebertragen/fehler, Idempotenz, Sync bei
Reconnect (connectivity_plus) + periodisch alle 15s. KontrollScreen gleicht
per 2s-Reconciliation-Loop den Anzeigezustand ab, "Kein Netz"-Banner.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 18:36:10 +02:00
patrickandClaude Sonnet 5 c71df1ac4d Karte 12: systemd-Timer für den täglichen Eskalations-Prüflauf
CI / backend-tests (push) Successful in 1m8s
CI / frontend-build (push) Successful in 25s
scripts/eskalation_pruefen.py ruft den Service direkt gegen die DB auf (kein
HTTP/Admin-Token nötig, gleiches Muster wie scripts/create_admin.py).
mabea-eskalation.timer läuft täglich 06:00 Uhr. Zeitschwellen bleiben in der
DB (eskalation_konfiguration), nicht im Timer.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 18:28:46 +02:00
patrickandClaude Sonnet 5 e0cbf4b8de Playwright-E2E-Tests für die PWA (Login, Sperrlogik, Fortschritt, Offline-Queue)
CI / backend-tests (push) Successful in 1m6s
CI / frontend-build (push) Successful in 18s
Läuft komplett gegen gemockten Backend (e2e/mockApi.ts, page.route) - kein
echtes Backend/DB nötig, playwright.config.ts startet npm run dev automatisch.
Deckt Login-Erfolg/-Fehler, 409-Objektsperre mit Übernahme, hochzählende
Fortschrittsanzeige und Offline-Queue-Verhalten (kein Request während offline,
Sync bei Reconnect) ab.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 18:08:08 +02:00
patrickandClaude Sonnet 5 fb676a4a0b Karte 12: Eskalationslogik für lange offene Fehlbestände
CI / backend-tests (push) Successful in 1m6s
CI / frontend-build (push) Successful in 21s
Zwei Stufen (Erinnerung an Materialverantwortliche, Eskalation an
Leitungsverantwortliche/Administration) mit Tracking-Zeitstempel je Stufe
gegen Mehrfachversand. Zeitschwellen in eskalation_konfiguration (DB,
Singleton), admin-editierbar über GET/PUT /eskalation/konfiguration - bewusst
nicht fix im Code. Prüflauf per POST /eskalation/pruefen angestoßen,
Scheduling (Cron/systemd-Timer) bleibt Betriebsaufgabe.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 18:04:52 +02:00
patrickandClaude Sonnet 5 7f06d1cecc Karte 10: Test-Label-Skript + Druck-/Scan-Testcheckliste
CI / backend-tests (push) Successful in 1m3s
CI / frontend-build (push) Successful in 56s
Label-Druck-Test mit echten Geräten ist ein physischer Schritt, nicht per
Code erledigbar. Stattdessen: scripts/test_label_erzeugen.py erzeugt lokal
ein Test-PDF ohne DB-Verbindung, Karte 10 um 5-Schritt-Checkliste ergänzt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 18:01:36 +02:00
patrickandClaude Sonnet 5 66757e4cd6 Karte 10: Code128-Label als PDF (Objekt + Geräte-Exemplar)
CI / backend-tests (push) Successful in 1m5s
CI / frontend-build (push) Successful in 18s
app/services/label.py generiert druckfertiges Vektor-PDF (python-barcode +
reportlab): Mindesthöhe 10mm, Ruhezone 5mm, Klartext-Fallback als zweite
Zeile (Objekt-/Materialname). Endpunkte GET /objekte/{id}/label.pdf und
GET /objektpositionen/{id}/label.pdf (404 ohne vergebenen Geräte-Code).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 17:59:54 +02:00
patrickandClaude Sonnet 5 d8d2816758 Karte 10: Kamera-Scan in Flutter-App (Objekt-Code, Scan-First-Einstieg)
CI / backend-tests (push) Successful in 1m1s
CI / frontend-build (push) Successful in 21s
ScannerScreen auf mobile_scanner, Treffer springt direkt ins KontrollScreen,
sonst Fallback ins bestehende Suchfeld. Kamera-Berechtigung (Android Manifest/
iOS Info.plist) im README dokumentiert, da android/ios-Ordner generiert und
nicht im Repo sind.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 17:57:18 +02:00
patrickandClaude Sonnet 5 6cf28cc8ee Karte 10: Kamera-Scan im Frontend (Objekt-Code, Scan-First-Einstieg)
CI / backend-tests (push) Successful in 1m0s
CI / frontend-build (push) Successful in 18s
BarcodeScanner-Komponente auf @zxing/browser (Code128, iOS/Safari-kompatibel
im Gegensatz zur nativen BarcodeDetector-API). Treffer springt direkt ins
Kontroll-Screen, sonst Fallback ins bestehende Such-Textfeld.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 17:39:24 +02:00
patrickandClaude Sonnet 5 f06d704168 Frontend: Code-Vorschlag beim Objekt-Anlegen/Duplizieren einbinden
CI / backend-tests (push) Successful in 1m0s
CI / frontend-build (push) Successful in 15s
Präfix-Feld + "Code vorschlagen"-Button ruft GET /objekte/naechster-code
und füllt das Code-Feld vor, bleibt überschreibbar.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 17:37:15 +02:00
patrickandClaude Sonnet 5 69e7d0c8d0 Karte 10: Geräte-Code für Objektpositionen (Code128-Vorbereitung) + Code-Vorschlag
CI / backend-tests (push) Successful in 1m1s
CI / frontend-build (push) Successful in 18s
objektposition.code (nullable, unique) für Geräte-Etiketten, separat von
seriennummer. Lookup-Endpunkt für Geräte-Scan (GET /objektpositionen/code/{code})
sowie Auto-Vorschlag PRAEFIX-NNN für Objekt- und Objektposition-Codes
(GET /objekte/naechster-code, GET /objektpositionen/naechster-code).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-04 17:35:25 +02:00
patrickandClaude Sonnet 5 a2877f5672 Feste Fächer-Liste je Objekttyp (Vorlagen-Positionen: Dropdown + Sonstiges)
CI / backend-tests (push) Successful in 1m0s
CI / frontend-build (push) Successful in 5m56s
Nutzer-Vorgabe: Rucksack-Fächer sollen aus einer festen, je Objekttyp
gepflegten Liste gewählt werden können statt jedes Mal Freitext einzutippen.
Neue Tabelle fach (Migration 0004), CRUD-Endpoints /faecher, Admin-Tab
Struktur bekommt Fach-Verwaltung, Vorlagen-Editor nutzt Dropdown mit
"Sonstiges"-Freitext-Fallback.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-04 10:24:15 +02:00
patrickandClaude Sonnet 5 2f11011ed1 Admin-Portal: Bearbeiten für Bereich/Kategorie/Objekttyp/Standort/Benutzer,
CI / backend-tests (push) Successful in 57s
CI / frontend-build (push) Successful in 20s
Vorlagen-Versionierung und Objekt-Duplizieren im Frontend nachgerüstet

Backend: PATCH-Endpoints für Bereich/Kategorie/Standort/Objekttyp ergänzt
(analog zu Material), die bislang fehlten und Bearbeiten grundsätzlich
unmöglich machten.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-04 09:55:52 +02:00
patrickandClaude Sonnet 5 1987818b8c Admin-Portal: Benutzerverwaltung (anlegen, Rollen, aktivieren/deaktivieren)
CI / backend-tests (push) Successful in 57s
CI / frontend-build (push) Successful in 7m16s
Backend-API existierte bereits (/benutzer, admin-only), war im Frontend
bisher nicht angebunden.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-04 09:44:42 +02:00
patrickandClaude Sonnet 5 2c9ca3ed3e Admin-Portal: Tab-Menü statt einer langen Scroll-Seite
CI / backend-tests (push) Successful in 58s
CI / frontend-build (push) Successful in 7m5s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-04 09:29:56 +02:00
patrickandClaude Sonnet 5 032126c605 fix(kontrolle): Abbruch löscht bereits nachgefüllten Fehlbestand nicht mehr
CI / backend-tests (push) Successful in 57s
CI / frontend-build (push) Successful in 5m12s
Beim Testen des neuen Inline-Nachfüll-Dialogs (Karte 07) gefunden: Sofort-
Nachfüllung während laufender Kontrolle + anschließender Abbruch führte zu
IntegrityError (FK-Verweis aus nachfuellung), da _verwirf_kontrolldaten
jeden Fehlbestand der Kontrolle unbedingt löschte.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-04 09:14:41 +02:00
patrickandClaude Sonnet 5 d70558f124 Inline-Nachfüll-Dialog nach Abweichung in der Kontrolle (Karte 07)
CI / backend-tests (push) Successful in 54s
CI / frontend-build (push) Successful in 7m17s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-04 09:04:20 +02:00
patrickandClaude Sonnet 5 db245c5e43 PWA: Passt-Button, Fortschrittsanzeige, Ablaufdatum-Farbcodierung in Kontrolle
CI / backend-tests (push) Successful in 55s
CI / frontend-build (push) Successful in 19s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-04 08:54:22 +02:00
patrickandClaude Sonnet 5 0988f8d026 Ablauf/Charge/SN gehören zur Kontroll-Erfassung, nicht nur zur Admin-Pflege
CI / backend-tests (push) Successful in 54s
CI / frontend-build (push) Successful in 18s
Nutzer-Vorgabe: "Ablauf/Charge/SN gehört mit zu den Kontrollen wie auch die
Menge". PUT .../positionen/{material_id} akzeptiert jetzt optional
ablaufdatum/chargennummer/seriennummer und schreibt sie auf die
Objektposition (Vier-Kernbegriffe bleiben unberührt: nur diese drei Felder,
niemals istmenge - das bleibt exklusiv Nachfüllung vorbehalten). Offline-
Queue und PositionCard erweitert: Felder erscheinen nur passend zum
Materialtyp (ablauf_charge -> Datum+Charge, geraet_sn -> SN). Admin-Panel
(ObjektPositionenPanel) bleibt zusätzlich für nachträgliche Korrekturen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-04 01:11:17 +02:00
patrickandClaude Sonnet 5 a6e68b0a94 Sprint 8: Ablaufdatum/Chargennummer/Seriennummer im Admin-Portal pflegbar
CI / backend-tests (push) Successful in 53s
CI / frontend-build (push) Successful in 15s
Nutzer-Fund: bei keinem Objekt war Chargennummer/Ablaufdatum sichtbar.
Backend-Endpoint (PATCH /objekte/{id}/positionen/{position_id}) existierte
bereits (Prompt 10), war im Frontend nirgends angebunden. Kontroll-Screen
selbst bleibt unverändert (Vier-Kernbegriffe: Kontrolle erfasst nur Menge,
Ablauf/Charge/SN gehören zur Objektposition) - neue Pflege-Ansicht im
Admin-Portal pro Objekt, nur für materialtyp ablauf_charge/geraet_sn.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-04 01:03:37 +02:00
patrickandClaude Sonnet 5 f47cefcc28 fix(import): Spalte D ist Ablaufdatum-Hinweis, keine Artikelnummer
CI / backend-tests (push) Successful in 53s
CI / frontend-build (push) Successful in 53s
Nutzer-Fund: "Kompresse 10x10 / 5 / Apr 29" - Wert 47209 in Spalte D ist
Excel-Datum 2029-04-01, kein Artikelnummer. Vollständige Prüfung aller drei
Listen bestätigt: D ist überwiegend ein echtes Ablaufdatum, keine
Artikelnummer-Spalte existiert überhaupt. Material-Abgleich läuft jetzt über
den Namen; ein plausibles Datum in Spalte D klassifiziert das Material als
'ablauf_charge' statt 'standard' (Wert selbst wird nicht gespeichert - gehört
auf objektposition, nicht auf die Vorlage). Bekannte Ausreißer (Platzhalter-
wert 12754, Freitext "Jahr 2023"/"MTK 23") werden per Plausibilitätsfenster
ignoriert statt fehlzuklassifizieren.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-04 00:58:25 +02:00
patrickandClaude Sonnet 5 dcc75dd2d0 Sprint 8: Bereich/Kategorie/Objekttyp/Vorlage-CRUD im Admin-Portal
CI / backend-tests (push) Successful in 56s
CI / frontend-build (push) Successful in 18s
Vervollständigt die Stammdaten-Anlage im Frontend (bisher nur Standort/
Material/Objekt), damit ein Pilotbetrieb nicht zwingend Excel-Import
braucht. Jede Sektion eigene Datei unter pages/admin/ (Projekt-Vorgabe:
keine großen Monolith-Dateien).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-04 00:52:43 +02:00
patrickandClaude Sonnet 5 569f58b25b Sprint 8: PWA-Icons ergänzt (bisher im Manifest referenziert, aber nicht vorhanden)
CI / backend-tests (push) Successful in 54s
CI / frontend-build (push) Successful in 38s
Einfaches Platzhalter-Icon (Primärfarbe + "M"), kann später durch echtes
Logo ersetzt werden.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-04 00:50:26 +02:00
patrickandClaude Sonnet 5 f6084e2d5a Refactor: große Dateien in kleinere Module/Komponenten aufgeteilt
CI / backend-tests (push) Successful in 53s
CI / frontend-build (push) Successful in 34s
Explizite Vorgabe: keine wachsenden Monolith-Dateien. AdminPage.tsx (349
Zeilen) in pages/admin/{Standort,Material,Objekt}Section.tsx aufgeteilt,
KontrollPage.tsx (277 Zeilen) in pages/kontrolle/{useKontrolle,
PositionCard,StatusBadge,types} aufgeteilt, services/kontrolle.py (332
Zeilen) in ein Package (lifecycle/erfassung/exceptions) aufgeteilt -
öffentliche API bleibt über __init__.py unverändert re-exportiert, kein
bestehender Import musste angepasst werden. Reines Refactoring, keine
Verhaltensänderung.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-04 00:45:18 +02:00
patrickandClaude Sonnet 5 08b10c7c37 Sprint 8: Material anlegen/bearbeiten im Admin-Portal
CI / backend-tests (push) Successful in 53s
CI / frontend-build (push) Successful in 1m51s
PATCH /materialien/{id} existierte im Backend bereits (Prompt 07), im
Frontend bisher nicht angebunden. Formular dient für Anlage UND Bearbeitung
(Klick auf "Bearbeiten" befüllt dasselbe Formular).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-04 00:40:37 +02:00
patrickandClaude Sonnet 5 e3ed5e0f28 Sprint 8: modernes Design-System für die React-PWA
CI / backend-tests (push) Successful in 54s
CI / frontend-build (push) Successful in 1m43s
Gemeinsames Stylesheet (Tokens, Karten, Buttons, Badges, Formulare) plus
AppShell (Kopfzeile mit Navigation/Logout) statt Inline-Styles je Screen.
Kein UI-Framework als neue Abhängigkeit - schlankes eigenes CSS, damit
Build/Deploy-Weg unverändert bleibt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-04 00:38:02 +02:00
patrickandClaude Sonnet 5 a97886defd Sprint 8: minimale Admin-Seite (Standort/Objekt-Anlage) im Frontend
CI / backend-tests (push) Successful in 56s
CI / frontend-build (push) Successful in 1m43s
Frontend deckte bisher nur den Mitarbeiter-Kontrollflow ab, Stammdaten
mussten per API/Skript angelegt werden (Test-Deployment-Lücke). /admin
zeigt Standort- und Objekt-Anlage (aus aktiver Vorlage), nur für Rolle
administration sichtbar (/auth/me liefert Rollen an AuthContext).
Bewusst kein Bereich/Kategorie/Material-CRUD - kommt aus Excel-Import.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-04 00:33:28 +02:00
patrickandClaude Sonnet 5 8943e362e1 fix(import): nicht-numerische Menge überspringen statt Import abzubrechen
CI / backend-tests (push) Successful in 53s
CI / frontend-build (push) Successful in 7m13s
Dritte Ist-Liste (Rucksack PAX SEG) hat abweichende Kopfzeilen-Struktur
(Objekttyp-Name in Spalte C statt Menge) - beim echten Import-Lauf
gefunden. Solche Zeilen sind Titel/Deckblatt, keine Artikelzeilen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-04 00:28:25 +02:00
patrickandClaude Sonnet 5 6503beb92a fix(import): Mengen zusammenführen bei Mehrfach-Fach desselben Materials
CI / frontend-build (push) Successful in 3m29s
CI / backend-tests (push) Successful in 55s
Realer Fund beim ersten Import-Lauf gegen den Zielserver: vorlagenposition
erlaubt nur eine Zeile pro Material+Vorlage, Excel-Listen führen aber
manches Material in mehreren Fächern - UniqueViolationError. Fix: Mengen
addieren, Fächer als Liste zusammenführen statt zweite Zeile einzufügen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-04 00:27:42 +02:00
patrickandClaude Sonnet 5 f4c1124a82 Sprint 8: Admin-Seed-Skript für Erstinbetriebnahme
CI / backend-tests (push) Successful in 54s
CI / frontend-build (push) Successful in 5m42s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L85hmKbvX7Cqkq47KnQhFt
2026-09-04 00:26:19 +02:00