Zum Hauptinhalt springen

Changelog

Audit-Trail aller inhaltlichen Änderungen — je PR ein Eintrag: Datum · PR-Nummer (Link) · kurze Beschreibung inkl. getroffener Entscheidungen. Neueste zuerst. Verbindlich gepflegt (siehe docs/konventionen/agents.md §5.1, Root-CLAUDE.md → Repo/Audit-Trail). Tiefe/Begründung je Thema: HANDOFF.md §4 (Offene Punkte) + docs/fachlich/Lastenheft.md. Repo: drkv-com/taktano.

2026-07-26

  • Branch claude/next-steps-8vmq5d ([PR folgt]) — Rollen-Auswahl im Menü (interim self-declared roles, OP-AUTH-1 A-1.5) + KOSTEN_ADMIN_EMAILS-Allowlist entferntMINOR 0.156.0, OP-AUTH-1/OP-COST-1/OP-COST-3. PO: A-2 (Better Auth) geparkt; stattdessen ein einfacher, sofort wirksamer Interim. Gebaut: im ⚙-Menü wählt man seine Rolle (Werker · Buchhaltung · Werkstattleitung · Inhaber/Chef) → als ?rolle=-Query beim WebSocket-Verbinden (+ Chronik-Fetch) übergeben; der Server leitet daraus die A-1-Fähigkeiten ab (capsAusRolle — damit ist der darf()-Seam live): Werker=keine · Buchhaltung=kosten · Werkstattleitung=verwaltung · Inhaber/Chef=alle drei. Rollenwechsel lädt neu (frischer Socket). Das (bisher kosten+verwaltung vermischende) kostenAdmin-Flag um ein eigenes verwaltung-Flag gespalten (Administration/Chronik/Verwaltung-Nav gaten auf verwaltung, Kosten auf kosten). Altlast entfernt (PO): die E-Mail-Allowlist KOSTEN_ADMIN_EMAILS (+ kostenAdminFuer, Env-Feld, wrangler.toml-Block) — Autorisierung kommt jetzt aus der Rolle. Cloudflare Access bleibt als Netz-Gate (Golden Rule) + X-Taktano-User-Audit-Actor. OP-COST-3 (Allowlist-Aktivierungs-Runbook) damit hinfällig → erledigt. ⚠ Sicherheits-Charakter (bewusst, interim, RISK-12): die Rolle ist selbst-deklariert (jeder hinter Access kann „Inhaber/Chef" wählen) — kein echtes Berechtigungsmodell, sondern Demo/Pilot-Zwischenstand hinter dem Access-Netz-Gate; verifizierte Durchsetzung (Rolle aus Better-Auth-JWT) + Gate-Nachzug der ungegateten Stammdaten-Handler kommen mit A-3. Live-DO-verifiziert (WS-Probe: alle 4 Rollen + ungültig→werker korrekt; end-to-end: chef/werkstattleitung → Administration sichtbar, werker → gesperrt; ⚙-Dropdown rendert + zeigt aktuelle Rolle). Reiner Client (RolleService neu + Shell-Dropdown + verwaltung-Gates) + Server (connCaps/tailorState//audit/liste-Gate). Verifiziert: ng build prod + No-Hex + tsc (Server) + No-Console grün + Screenshots. Doku: OP-AUTH-1 (A-1.5), Kosten.md (§Gate/§12), OP-COST-1/-3, RISK-12, HANDOFF/Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #741) — ⚙-Menü: „Auf Kurs %"-Statuszeile entferntPATCH 0.155.2, OP-REDESIGN-1. PO-Feedback: die „Auf Kurs 100 %"-Zeile (samt „N gefährdet"-Indikator) im ⚙-Zahnrad-Popover raus — die Auf-Kurs-/Gefährdet-Info lebt bereits prominenter im TN-Strip der Top-Bar (Auslastung/Fahrzeuge/verortet) und in den Entscheiden-/Fluss-Sichten; im kompakten Einstellungs-/Status-Popover war sie redundant (Einfachheit). Popover trägt jetzt nur noch Einstellungen (Ansicht · Feedback · Alarm-Ton) · Foto-Queue (nur bei wartenden Uploads) · Verbindung (Neu synchronisieren). Ungenutzte aufKursProzent-Computed mitentfernt. Live-DO-verifiziert (Hell: „Auf Kurs" weg, Menü intakt). Reiner Client (1 Datei) + version.ts. Verifiziert: ng build prod + No-Hex grün + Screenshot.
  • Branch claude/next-steps-8vmq5d (PR #739) — Scope-Entscheidung: Voll-Offline-Write kategorisch ausgeschlossen + Background-Sync als OP-OFFLINE-2 angelegtreine Doku, kein Version-Bump, OP-OFFLINE-1/OP-OFFLINE-2. PO-Entscheidung 2026-07-26: Voll-Offline-Write (beliebige Aktionen offline absetzen) ist kategorisch ausgeschlossen — nicht „Backlog", sondern außerhalb des Produkt-Scopes: der Durable Object bleibt live-verbundene Single Source of Truth, die Idempotenz-/Replay-/Konflikt-Komplexität widerspricht dem Leitprinzip Einfachheit und zahlt auf keine True-North-Frage ein (Auslastung/Standort/Kapazität setzen Server-Autorität + harte Gates QS/Vier-Augen/Live-Taktung ohnehin voraus); einziger gerechtfertigter Offline-Write bleibt der enge, idempotente Foto-Upload. Background Sync (Foto-Uploads nach Tab-Schließen abschließen) — bisher nur als „Folge-Schritt" notiert — als eigener offener OP OP-OFFLINE-2 (prio: spaeter, betrifft nur den bestehenden idempotenten Foto-Upload, klar getrennt vom ausgeschlossenen Voll-Offline-Write) ausgegliedert. Doku: ops/OP-OFFLINE-2.md (neu), ops/OP-OFFLINE-1.md, architektur/Offline-PWA.md (§„Bewusst NICHT"), IDs.md, Offene-Punkte.md (gen-ops), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #738) — CodeRabbit-Nachzug zu #737PATCH 0.155.1, OP-OFFLINE-1. 7 Findings, 3 valide behoben (Rest = Doku-Konsistenz). (1, echter Bug): die client-seitige Cache-SCHEMA-Konstante blieb 1, obwohl LeitstandState.schemaVersion in #737 Pflichtfeld wurde → vor-0.155.0-Snapshots [ohne das Feld] würden noch hydriert; SCHEMA 1→2 verwirft Alt-Snapshots beim load() [genau der in #737 dokumentierte stille Selbstheilungs-Mechanismus, nur nicht ausgelöst]. (2): StateCacheService.clear() schluckte IndexedDB-Fehler → Schein-Resync möglich; gibt jetzt boolean zurück [OP-LOG-1], bei false kein Reload. (3): neuSynchronisieren() verwarf den Cache allein auf navigator.onLine → bei Aussetzer Verlust von Cache+App-Shell; neue Same-Origin-Erreichbarkeits-Probe [HEAD/no-store, 3xx/4xx=erreichbar] vor dem Verwerfen + ehrlicher „nicht neu synchronisiert"-Toast bei Nicht-Erreichbarkeit. Bewusst NICHT der schwere in-page-Resync-Umbau [Hard-Reload spiegelt das akzeptierte hartNeuLaden()-Verhalten, Probe deckt die Lücke proportional]. Timesheet/CHANGELOG-Konsistenz mitgezogen. Verifiziert: ng build prod + No-Hex + tsc (Server) + doc-consistency --strict grün. Reiner Client (3 Dateien) + version.ts.
  • Branch claude/next-steps-8vmq5d (PR #737) — Offline-Resilienz: Schema-Broadcast + „↻ Neu synchronisieren" (Offline-Stand verwerfen + Voll-Resync)MINOR 0.155.0, OP-OFFLINE-1. Deckt den PO-Fall ab: „Server per Ping erreichbar, aber das Datenmodell lässt sich nicht synchronisieren" bzw. „lokale Offline-Variante passt nicht mehr zum Server-Build → alles neu laden". Drei Bausteine: (1) Schema-Broadcast — der Server sendet die Daten-Schema-Version (SCHEMA_VERSION, DO-Persistenz) als schemaVersion im State (DTO + snapshot()); der Client stempelt jeden Offline-Snapshot mit dieser serverSchema (StateCacheService.save/load) → Cache selbstbeschreibend/inkompatibilität erkennbar. (2) Stiller Selbstschutz — die client-seitige Cache-SCHEMA-Konstante verwirft inkompatible Alt-Snapshots beim load(); der DO schickt beim Verbinden ohnehin immer den vollen, autoritativen State → Daten heilen bei Reconnect automatisch (läuft still, immer sicher). (3) Bewusste Nutzer-AktionVerbindungService.neuSynchronisieren() = View-Cache verwerfen (StateCacheService.clear()) + hartNeuLaden(); zwei Zugänge: Sekundär-Link im Offline-Banner und ⚙-Menü-Eintrag „Verbindung → Neu synchronisieren · Offline-Stand verwerfen". Entscheidungen/Leitplanken (PO-Defaults): wird nie automatisch/still ausgelöst (kein gültiger Cache ungefragt verworfen → immer nur anbieten); an vorhandenes Netz gebunden (sonst ehrlicher Toast); die persistente Foto-Upload-Queue (taktano-offline-fotos) bleibt unberührt (clear() löscht nur den View-State-Key). Live-DO-verifiziert: schemaVersion=22 im State-Broadcast, ⚙-Menü-Eintrag rendert (Hell). Reiner Client (4 Dateien) + 1 Server-Feld. Doku: OP-OFFLINE-1, architektur/Offline-PWA.md, CHANGELOG, HANDOFF §2, Timesheet, version.ts (0.155.0).

2026-07-25

  • Branch claude/next-steps-8vmq5d (PR #736) — Governance: A-1 als Zwischenstand + interim-Betreiber/Admin festgelegt (reine Doku, kein Version-Bump, OP-AUTH-1). PO-Entscheidung 07-25: OP-AUTH-1 A-1 bleibt der Zwischenstand (kein A-2/A-3 vorerst); interim-Betreiber/Admin = der PO (m.kirchhof@drkv.com). Als Entscheidung/Audit-Trail in ops/OP-AUTH-1.md festgehalten — inkl. der zwei Deploy-Voraussetzungen, damit es greift (beide nicht im Repo, PII/Secret-Regel): (1) KOSTEN_ADMIN_EMAILS = Betreiber-E-Mail via wrangler secret put; (2) Access aktiv (ACCESS_TEAM_DOMAIN+ACCESS_AUD) — sonst accessAktiv=false → alle sind Admin (Allowlist wirkungslos). Caveat notiert: wegen des bekannten A-1-Gaps (ungegatete Stammdaten-Handler) ist „nur der PO ist Admin" erst mit A-3 voll durchgesetzt. Von der Session aus nicht setzbar (keine CF-Credentials/wrangler login) → Deploy-Aktion beim PO/CI/CF-Dashboard. Reine Governance-Doku (ops/OP-AUTH-1.md), kein Code. Doku: OP-AUTH-1, CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #735) — A-1 CodeRabbit-Nachzug (Doku-Konsistenz + Coverage-Ehrlichkeit) (APP_VERSION 0.154.1 → 0.154.2, PATCH — Fix/Nachzug). Nachzug der 4 validen CodeRabbit-Findings zu #734 (kamen, als der PR schon gemergt war → Follow-up-PR, frischer Branch von main). (1) Timesheet-Summen (Minor): Kernaussage/„Investierte Zeit gesamt" — Kopf-Summe stimmte nicht mit den Komponenten überein (100.6 + 151.5 ≠ 253.5); KW27–30-Aggregat auf 152.9 h korrigiert → 100.6 + 152.9 = 253.5 h (jetzt konsistent). (2) Lastenheft §11.5 IdP (Major): „Verworfen: Clerk/WorkOS" widersprach ops/OP-AUTH-1.md (dort Fallback nur falls „schnell ohne Ops"/SAML-SSO dominiert) → Lastenheft auf die nachrangig/Fallback-Formulierung angeglichen + „Maßgeblich = ops/OP-AUTH-1.md". (3) HANDOFF Rollen-Mapping (Minor): Inhaber=alleInhaber/Chef=alle drei (deckungsgleich zu Lastenheft/OP). (4) verwaltung-Coverage ehrlich gemacht (Major, Security-Befund): der darf-Doc-Kommentar überzeichnete die Abdeckung — mehrere Stammdaten-Handler (employee.create/update/setVerfuegbarkeit/addAbwesenheit, Skill-CRUD, teilschritt.update, leistung.update) sind ungegatet (CodeRabbit korrekt). Bewusst KEINE Gates ergänzt: das ist ein vorbestehender Zustand (nicht durch A-1 eingeführt; die Handler waren nie gegatet, der Refactor blieb verhaltensgleich), und ein Gate ohne besetzte Admin-Rolle würde die Stammdaten-Pflege in Prod aussperren (bei leerer KOSTEN_ADMIN_EMAILS ist niemand Betreiber). Stattdessen: Doc-Kommentar + ops/OP-AUTH-1.md sagen jetzt ehrlich, welche Handler heute gegatet sind und dokumentieren den ungegateten Rest als bekannten A-1-Gap, der mit A-3 (zusammen mit der echten Rollen-Zuweisung) geschlossen wird — sonst Prod-Aussperrung. Verifiziert: tsc (Server) + No-Console + doc-consistency --strict grün. Reine Doku + 1 Code-Kommentar (kein Verhaltens-/Logik-Change). Doku: server/party/leitstand.ts (darf-Kommentar), ops/OP-AUTH-1.md, docs/fachlich/Lastenheft.md, HANDOFF §2, Timesheet, CHANGELOG.
  • Branch claude/next-steps-8vmq5d (PR #734) — OP-AUTH-1 A-1: Rollen-/Fähigkeits-Naht — istKostenAdmindarf(conn, faehigkeit) (APP_VERSION 0.154.0 → 0.154.1, PATCH — verhaltensgleicher Server-Refactor, OP-AUTH-1). Erster Schritt Richtung echtes User-Management (PO: „nur a-1"). Das Interim-Auth-Gate istKostenAdmin war überladen — dieselbe E-Mail-Allowlist-Prüfung trug drei verschiedene Bedeutungen (Kosten-Admin · Stammdaten-/Konfig-Mutation · Chef-Override). Umbau: eine neue darf(conn, faehigkeit)-Funktion mit benannten Fähigkeitenkosten (Infra-Kosten sehen/erfassen + Kosten-Sicht) · verwaltung (Stammdaten-/System-/Konfig-Mutation: Mitarbeiter·Skills·Prozesse·Buchten·Taxonomien·Schichten·Nacht-Halle·Editier-Präsenz·Datenbestand-Reset·OTLP-Test) · chef (G-4/OP-QS-6: Vier-Augen-Abweichung + Notfall-Klärfall-Auflösung). Alle 28 Gate-Call-Sites (server/party/leitstand.ts) von istKostenAdmin(conn) auf darf(conn, "<fähigkeit>") umgestellt (7 kosten · 19 verwaltung · 2 chef). Verhaltensgleich: darf löst interim für alle Fähigkeiten auf denselben Betreiber-Gate (istKostenAdmin → Access-E-Mail-Allowlist) auf → kein Verhaltens-Change; void faehigkeit markiert die Naht, an der A-3 (Better Auth) die rechte Seite je Fähigkeit durch die rollenbasierte Verbindungs-Projektion ersetzt. Gewinn: die Gates sind jetzt selbsterklärend (welche Berechtigung sie verlangen), und das Rollenmodell hat einen sauberen Einhak-Punkt. Geplantes Rollen→Fähigkeit-Mapping (Design, noch ohne Runtime — kommt mit A-3): Inhaber/Chef = alle drei · Werkstattleitung = verwaltung (+opt. kosten) · Buchhaltung = kosten · Werker = keine. Offen (A-2+, PO-Entscheidung): ob jeder Mitarbeiter ein eigenes Login bekommt (Employee↔User-Verknüpfung) oder nur die Leitung. Verifiziert: tsc (Server) + No-Console + Scheduler-Self-Test (npm run spike, verhaltensgleich) + doc-consistency --strict grün. Reiner Server (leitstand.ts: neue darf-Methode + 28 Call-Site-Umstellungen), kein Client/DTO/Schema. Doku-Konsistenz mitgezogen: ops/OP-AUTH-1.md (A-1 ✅ + Slices A-1…A-5 + Rollen-Mapping) · Lastenheft §11.5 (stale IdP-Kandidaten „Zitadel/Ory" → Better-Auth-Entscheidung nachgezogen). Doku: CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #733) — Top-Bar-Menü prototype-treu: „⋯" → Verwaltung direkt + Zahnrad-Popover (APP_VERSION 0.153.0 → 0.154.0, MINOR — IA-Feinschliff, OP-REDESIGN-1). PO-Feedback: „Das Menü ist nicht wie im Design-Prototyp." Befund: die Flusslinie-Prototyp-Top-Bar ist minimal — Logo · 4 Orte-Tabs + „⋯" öffnet direkt die Verwaltung (verwaltungAuf, „Stammdaten & Selten-Gebrauchtes") · True-North-Strip · Leitstand|Werkstatt-Segment · Uhr; kein Bereichs-Dropdown, keine Einstellungen/Status in der Bar. Mein 4A-Übergangsstand hatte „···" dagegen als großes gruppiertes Overflow-Menü (alle Bereiche + Einstellungen + Status) gebaut — als Gerüst, bis die IA konsolidiert ist. Da die IA jetzt komplett ist (4A–4E), ist das Gerüst überflüssig. Umbau: (1) „⋯" ist jetzt ein direkter Verwaltung-Link (routerLink="/verwaltung", roter Aktiv-Underline; die Verwaltungs-Seite gated Nicht-Betreiber selbst) — das Bereichs-Dropdown entfernt (die 4 Orte sind Tabs, Verwaltung ist „···", das Werkstatt-Terminal der Rollen-Umschalter → keine Bereichs-Navigation im Menü mehr nötig). (2) Die realen App-/Geräte-Steuerungen, die der Prototyp nicht in der Bar führt (Ansicht/Theme · Feedback-Anzeige · Alarm-Ton · Auf-Kurs · Foto-Queue), wandern in ein kompaktes Zahnrad-Popover (⚙, rechts neben der Uhr, rechts-anchored) — erreichbar, aber außerhalb der Navigations-Orte (Einfachheit; bewusste, begründete Abweichung, weil der Prototyp diese Steuerungen als reines Mock auslässt). Die navGroups-Liste bleibt als Routen-Titel-Registry für den Workspace-Sub-Header (flatNavactive), rendert aber kein Menü mehr. Live-DO-verifiziert (wrangler dev --local + gebauter Client + Playwright, Hell + Dunkel: „⋯"-Klick → /verwaltung/leistungen; ⚙-Popover zeigt nur Einstellungen [Ansicht/Feedback/Alarm-Ton] + Auf-Kurs, keine Bereichs-Gruppen; keine Page-Errors). Reiner Client (shell.component.ts: „⋯"→Link, Zahnrad-Button + repositioniertes Popover, navGroups-Rendering raus), kein Server/DTO/Schema. Verifiziert: No-Hex + ng build prod + doc-consistency --strict grün + Live-Screenshots. Doku: design/WORKSPACES.md (Top-Bar), design/CLAUDE.md (Shell), docs/betrieb/Funktionsumfang.md, CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #732) — Metrik-Trends: Termintreue + Ø Durchlaufzeit (2 neue Review-KPIs) (APP_VERSION 0.152.0 → 0.153.0, MINOR — neues Feature, OP-AUDIT-1/OP-COST-1 · OP-DATA-1). Erweitert die Metrik-Persistenz (die metrik_snapshots-DO-SQLite-Tabelle) um die letzten beiden bei #722 als „nachgelagert" markierten Trend-Kennzahlen — jetzt 5 Tages-Snapshot-KPIs in der Review-Sicht. Definitionen (ehrlich, aus den Ist-Zeiten der fertigen Aufträge): Termintreue = % fertiger Aufträge mit tatsaechlicheFertigstellung ≤ urspruenglicherAbholtermin (bis zum ursprünglich zugesagten Abholtermin fertig — es gibt keinen Ist-Abhol-Zeitpunkt, „bis Zusage fertig" ist die tragfähige Näherung); Ø Durchlaufzeit = Mittel aus tatsaechlicheFertigstellung − tatsaechlicheAnlieferung über fertige Aufträge mit beiden Ist-Zeiten (Minuten gespeichert, Client zeigt Tage). Beide NULL ohne Basis (ehrliche Lücke, D-2). Datenlücke geschlossen: tatsaechlicheAnlieferung (Ist-Ankunft) war ein deklariertes, aber nie gestempeltes Feld → wird jetzt beim Fahrzeug-Check-in (auftrag.checkinangeliefert) gesetzt (epoch Minuten, nur beim ersten Mal); der Demo-Seed setzt es (≈ Bringtermin, −2 Tage) → die Durchlaufzeit demonstriert real. Schema: Drizzle-Schema metrik_snapshots += termintreue_pct/durchlaufzeit_min (Single Source), generierte Migration drizzle/0002_*.sql (2× ALTER TABLE ADD COLUMN); Runtime-Tabellenanlage um additive Spalten-Auto-Migration erweitert (PRAGMA table_info → fehlende Spalten per ALTER, kein Exception-Spam) — bestehende Tabellen ziehen live nach. Producer/Reader (aktuelleMetrikWerte/Insert/metrikVerlaufDTO) + DTO (Server + Client) erweitert. Client (lage-review.component.ts): 2 weitere Sparklines; die Trend-Reihe kann jetzt nicht-Prozent-Einheiten (Dauer/Tage) — eigene Einheit, Fenster-Max-Skalierung der Balken, eine Nachkommastelle, Delta in der Reihen-Einheit statt fix „pp". Grid 3→5 Spalten. Live-DO-verifiziert (wrangler dev --local + frischer Demo-Seed + Playwright, Hell + Dunkel: Review zeigt alle 5 KPIs — Auslastung 0 % · FPY 33 % · Nacharbeit 67 % · Termintreue 100 % · Ø Durchlaufzeit 2.0 Tage — mit Sparkline + korrekter Einheit/Skalierung, keine Page-Errors). Client + Server + DO-SQLite (Schema/Migration, DO-Producer/Reader, Check-in-Stempel, Seed, DTO beidseitig, Consumer). Verifiziert: No-Hex + tsc (Server) + ng build prod + Persistenz-Gate (db:check, Schema↔Migration sync) + No-Console + doc-consistency --strict grün + Live-Screenshots. Doku: docs/architektur/Persistenz.md (metrik-Spalten), docs/betrieb/Funktionsumfang.md, CHANGELOG, HANDOFF §2, Timesheet. Damit sind die Review-Trend-KPIs vollständig (keine „nachgelagert"-Lücke mehr).
  • Branch claude/next-steps-8vmq5d (PR #731) — Redesign „Flusslinie" Phase 4E: Aufräumen — Verwaltung 3-Wege-Split + Chronik (Audit-Panel) → „IA-komplett" (APP_VERSION 0.151.0 → 0.152.0, MINOR — IA/Screen + Server-Lesepfad, OP-REDESIGN-1 / OP-AUDIT-1). Der letzte Voll-IA-Schritt. (1) Verwaltung 3-Wege-Split: der frühere Sammel-Screen „Stammdaten & System" wird als drei Ort-Sub-Tabs geführt — Buchten & Hof (Arbeitsplätze · Sperren · Nacht-Halle) · Schichten (Arbeitszeitfenster · Reserve) · System (Taxonomien · Mandant · Datenbestand/Purge). Entscheidung (Einfachheit, PO 07-25 „Taxonomie ganz auf System"): eine route-parametrisierte Komponente (administration.component.ts liest data.bereich via toSignal(route.data), Template @if (bereich() === …)) statt drei Dateien — so bleibt die geteilte OP-EDIT-1-Quittungs- (editResult) + Präsenz-Verdrahtung ungeteilt (kein 3×-Duplikat); da die Taxonomien ganz auf „System" bleiben, besitzt jeder Bereich genau eine Edit-Domäne. Routen plaetze/schichten/system (+ stammdatenplaetze-Redirect, /administration/verwaltung/plaetze); Verwaltung-Sub-Sidebar jetzt 7 Tabs. (2) Chronik (Audit-Panel, OP-AUDIT-1 Slice 3): der bisher disabled „folgt"-Tab ist gebaut — mit echtem Server-Lesepfad: das Audit-Log (audit_entries, D1) war write-only, jetzt liefert GET /audit/liste (DO-onRequest, admin-gegated via kostenAdminFuer, eigenes Gate — nicht der breitere Assistent-Kreis) die jüngsten Events (server-seitiger SELECT … ORDER BY ts DESC LIMIT über den (tenant,ts)-Index, nur summary — PII-arm, Detail-Diffs bleiben in der zugriffsgeschützten D1). Neuer AuditEintragDTO/AuditListe (Server- + Client-Spiegel), svc.ladeAuditVerlauf(), neuer read-only chronik.component.ts (Zeitachse Wann · Was · Wer nach Prototyp; ehrlicher Leer-/Dormant-Zustand ohne D1-Binding statt Fake). Damit ist die 4-Orte-IA komplett (kein „folgt"-Platzhalter mehr). Live-DO-verifiziert (wrangler dev --local + lokale D1-Migration + 3 seed-Audit-Zeilen + gebauter Client + Playwright, Hell + Dunkel: 7-Tab-Sub-Sidebar, System zeigt nur Taxonomien+Purge [Arbeitsplätze/Schichten/Nacht-Halle korrekt auf ihre Tabs verschoben], Chronik rendert die 3 echten D1-Audit-Zeilen [Tom Wend archiviert · Infra-Kosten · Sina Falk Urlaub] mit Event-Typ/Actor/Resource + „Detail-Diffs bleiben in der D1"-Fußnote, keine Page-Errors; der Chronik-Fetch ist same-origin in Prod — lokal via ASSISTENT_CORS_ORIGINS freigeschaltet). Client + Server (route-param. administration, neue chronik.component.ts, Verwaltung-Tabs/Routen, Server-onRequest-Route + auditListe()-DO-Methode + DTOs, Service-Fetch), kein Schema-Change (nur Lesepfad auf bestehende Tabelle — db:check grün). Verifiziert: No-Hex + tsc (Server) + ng build prod + No-Console + doc-consistency --strict grün + Live-Screenshots. Doku: ops/OP-REDESIGN-1.md (4E ✅ / „IA-komplett"), docs/architektur/Audit-Log.md (Slice 3 ✅ Lesepfad), design/WORKSPACES.md, docs/betrieb/Funktionsumfang.md, CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #730) — Redesign „Flusslinie" Phase 4D: Team-Seite (lesender Karten-Überblick) (APP_VERSION 0.150.0 → 0.151.0, MINOR — IA/Screen, OP-REDESIGN-1). Vorletzter Voll-IA-Schritt. Der Team-Ort (/staff) war bisher direkt der volle Editor (StaffComponent, 1037 Zeilen: anlegen/bearbeiten, Skills, Schichten, Abwesenheiten, Beförderungen) — der Prototyp macht daraus einen lesenden Überblick „wer kann was, wer macht was". Neuer TeamComponent (client/src/app/leitstand/pages/team.component.ts) = Karten-Grid (sm:2/xl:3): Avatar (Ink) · Name/Rolle · Status-Pille (arbeitet · Frei · Pause · krank · Urlaub; Prototyp-Wort „arbeitet" = abgeleiteter Aktiv) · Aktuell (Employee.currentTask) · Als Nächstes (frühester geplanter Teilschritt, dem der Mitarbeiter zugewiesen ist — Haupt-/Helfer-Rolle — über alle Live-Aufträge, Queue-Semantik/start wie die Tafel OP-OPT-9, als computed einmal je State vorberechnet) · Skill-Chips mit Niveau (kann was) · read-only Status-Filter (Alle + je Status mit Zähler). Entscheidung — Editor deflektiert, NICHT dupliziert (Einfachheit): die volle Pflege bleibt der StaffComponent-Editor unter Verwaltung → Team & Skills (/verwaltung/team, Phase 4B) — der Team-Ort trägt oben einen „Pflegen: Verwaltung → Team & Skills →"-Deflektor + einen Inline-Link bei fehlenden Skills; Route-Repoint /staffTeamComponent (Alt-Deep-Links landen auf dem Überblick, Editieren ein Klick weiter). Onboarding-Hinweis + „···"-Menü-Label (MitarbeiterTeam, sub „Wer kann was, wer macht was") mitgezogen. Live-DO-verifiziert (wrangler dev --local + gebauter Client + Demo-Seed + Playwright, Hell + Dunkel: Team-Tab aktiv [roter Underline], 4 Mitarbeiter-Karten, „arbeitet"/„Frei"/„Urlaub"-Pillen, Aktuell/Als-Nächstes je Karte, Skill-Chips, Filter Alle/arbeitet/Frei/Urlaub mit Zählern, Deflektor-Link, keine Page-Errors; body-bg Ink im Dark bestätigt). Reiner Client (1 neue Komponente + app.routes.ts-Repoint + Onboarding-/Shell-Label), kein Server/DTO/Schema — alle Kartendaten liegen bereits auf den DTOs. Verifiziert: No-Hex + ng build prod grün + Live-Screenshots. Doku: ops/OP-REDESIGN-1.md (4D ✅), design/WORKSPACES.md, docs/betrieb/Funktionsumfang.md, CHANGELOG, HANDOFF §2, Timesheet. Offen: 4E Aufräumen (administration-3-Wege-Split + Chronik-Screen) → „IA-komplett".
  • Branch claude/next-steps-8vmq5d (PR #729) — Redesign „Flusslinie" Phase 4C: Fluss konsolidieren (APP_VERSION 0.149.1 → 0.150.0, MINOR — IA/Screen, OP-REDESIGN-1). Dritter Voll-IA-Schritt. Befund (Explore): der Fluss (orders) war bereits ~90% konsolidiertLinie (5-Spalten-Board) · Karte (bettet <app-occupancy/> = Belegung ein) · Risiko-Timeline · Entscheiden-Spalte (geteilte EntscheidenComponent: Konflikte · Klärfälle · Ortung · Vorschläge) · Auswahl-Panel (3d-24) · QS-Modal (3d-28) existieren schon. 4C = die eine echte Lücke füllen + Nav falten (kein Neubau): (a) Annahme-Einstieg aus dem Fluss — neuer „+ Neuer Auftrag — ein Satz genügt"-Button öffnet das geteilte 720px-Annahme-Overlay (AnnahmeOverlayComponent, bisher Lage-only) direkt im Fluss (orders.component.ts: Import + annahmeOffen-Signal + Button in der Segment-Leiste + Mount); (b) /occupancy (= Fluss·Karte) + /tafel von der Lage in den Fluss-Ort verschoben — shell.component.ts orte-paths (fluss: +/occupancy +/tafel; lage: nur noch /overview +/annahme) und die „···"-Gruppen (Belegung/Tafel von Lage → Fluss) → der Fluss-Tab ist jetzt auf /occupancy//tafel aktiv. Entscheidung — bewusst NICHT gelöscht: die tiefen Workspaces conflicts (688-Zeilen-Hebel-Engine mit Konsequenz-Simulation + Bulk-Löser) · recommendations (Pain/Gain-Detail) · quality (voller QM-Screen: KPI/Queue/Checkliste/Ausgang) bleiben als Drill-downs hinter der Entscheiden-Triage bzw. dem QS-Modal — die Entscheiden-Karten routen dorthin (Triage-Fläche, kein Ersatz der Tiefe; der Prototyp hat diese Deep-Workspaces so nicht). Live-DO-verifiziert (wrangler dev --local + gebauter Client + Playwright, Hell + Dunkel: Fluss zeigt „+ Neuer Auftrag" [Fluss-Tab aktiv], Klick → Annahme-Overlay [Scrim + Satz-Input] öffnet, /occupancyFluss-Tab aktiv, keine Page-Errors). Reiner Client (orders.component.ts + shell.component.ts), kein Server/DTO/Schema. Verifiziert: No-Hex + ng build prod + doc-consistency --strict grün + Live-Screenshots. Doku: ops/OP-REDESIGN-1.md (4C ✅), design/WORKSPACES.md, docs/betrieb/Funktionsumfang.md, CHANGELOG, HANDOFF §2, Timesheet. Offen: 4D Team-Seite · 4E Aufräumen (administration-3-Wege-Split + Chronik-Screen) → „IA-komplett".
  • Branch claude/next-steps-8vmq5d (PR #728) — Phase 4B — CodeRabbit-Nachzug (APP_VERSION 0.149.0 → 0.149.1, PATCH — Fix/Nacharbeit). 6 valide CodeRabbit-Findings zu #727 (kamen als der PR schon gemergt war → Follow-up-PR, frischer Branch von main). (1) A11y (verwaltung.component.ts): ariaCurrentWhenActive="page" am aktiven Sub-Tab-Link (Screen-Reader kündigt die aktive Route an). (2) Doku↔Code (Major, design/WORKSPACES.md): die stale Crystal-Bar-Region-Tabelle (Menü-Toggle · Rail-Cluster · Auf-Kurs-Ring · Live-Status-Fuß · Rail-Screenshots) war nach der Top-Bar-Umstellung (4A) noch als aktuell beschrieben → entfernt + durch eine knappe „Archiv (pre-Phase-4A, abgelöst)"-Notiz ersetzt (keine widersprüchliche Navigations-Spec mehr). (3) Label (shell.component.ts): „···"-Verwaltung-Untertitel Stammdaten · Kosten · ChronikProzesse · Team · Stammdaten · Kosten · Chronik (die zwei zusätzlichen Editoren auffindbar). (4) True-North (Critical): die Verwaltung beantwortet die 3 Leitfragen nicht direkt — als PO-freigegebene Ausnahme dokumentiert (Navigations-/IA-Umstellung des PO-mandatierten Redesigns + Stammdaten steuern Taktung/Machbarkeit → indirekt Auslastung/Kapazität); bewusst kein True-North-Widget auf der Admin-Fläche (Einfachheit). Rationale im Component-Doc-Kommentar. (5/6) Doku-Feinschliff: Funktionsumfang Chronik[folgt]Chronik (folgt); Timesheet-Kernaussage 4B–4E offen4C–4E offen (4B ist ✅). Verifiziert: No-Hex + ng build prod + doc-consistency --strict grün. Reiner Client + Doku. Doku: CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #727) — Redesign „Flusslinie" Phase 4B: Verwaltung-Seite (Sub-Sidebar + nested Routing) (APP_VERSION 0.148.0 → 0.149.0, MINOR — IA/Screen, OP-REDESIGN-1). Zweiter Schritt der Voll-IA (nach 4A Top-Bar): das „···"-Overflow bekommt eine echte Verwaltung-Heimat statt einer flachen Bereichsliste. Neue VerwaltungComponent (client/src/app/leitstand/pages/verwaltung.component.ts) = linke Sub-Tab-Sidebar + verschachteltes <router-outlet> — das erste nested Routing der App. Hostet die bestehenden Editoren unverändert (reuse): Leistungen & Abläufe (processes) · Team & Skills (staff) · Stammdaten & System (administration: Buchten/Schichten/Mandant, eine Scroll-Seite) · Kosten (costs) · Chronik = disabled „folgt" (Audit-Verlauf net-new, OP-AUDIT-1). Modernist: flach, 2px, radius 0, Ink-Selektion mit rotem Links-Rand am aktiven Sub-Tab. Routing: verwaltung von Redirect → Component-Route mit Children (''leistungen · leistungen/team/stammdaten/kosten lazy loadComponent); Alt-Deep-Links /administration/verwaltung/stammdaten, /costs/verwaltung/kosten (nichts verwaist). Shell-„···"-Menü: die Verwaltung-Gruppe (bisher Administration + Kosten einzeln) → ein Eintrag /verwaltung (declutter). Entscheidung (minimal + reuse): Phase 4B hostet die vorhandenen Editoren, ohne die 869-Zeilen-administration in 3 Screens (Buchten&Hof · Schichten&Abwesenheiten · System) aufzuspalten und ohne den Chronik-Screen neu zu bauen — beides ist eigener Aufwand und bewusst als Nachzug (Phase 4E / OP-AUDIT-1) markiert (ehrlich, keine erfundene Fläche → „folgt"-Eintrag). Live-DO-verifiziert (wrangler dev --local + gebauter Client + Playwright, Hell + Dunkel: /verwaltung/verwaltung/leistungen [Sub-Sidebar 5 Einträge, Leistungen&Abläufe aktiv/roter Links-Rand, processes-Editor im Outlet], Klick „Kosten"→/verwaltung/kosten [costs im Outlet, Aktiv-Wechsel], Sub-Header „Verwaltung", Top-Bar intakt, keine Page-Errors). Reiner Client (1 neue Komponente + app.routes.ts + Shell-Menü-Eintrag), kein Server/DTO/Schema. Verifiziert: No-Hex + ng build prod + doc-consistency --strict grün + Live-Screenshots. Doku: ops/OP-REDESIGN-1.md (4B ✅), design/WORKSPACES.md, docs/betrieb/Funktionsumfang.md, CHANGELOG, HANDOFF §2, Timesheet. Offen: 4C Fluss konsolidieren · 4D Team · 4E Aufräumen (admin-Split + Chronik) → „IA-komplett".
  • Branch claude/next-steps-8vmq5d (PR #726) — Redesign „Flusslinie" Phase 4A: Shell Rail → 62px-Top-Bar (APP_VERSION 0.147.0 → 0.148.0, MINOR — Shell/IA-Umbau, OP-REDESIGN-1). Anlass + Korrektur: Der PO wies darauf hin, dass die Navigation im Flusslinie-Design eine Top-Bar ist, die App aber noch die alte linke Icon-Rail trug — mein früheres „OP-REDESIGN-1 UI-komplett" (#721) war auf der Shell-/IA-Dimension zu optimistisch (die 4 Orte existierten nur als Rail-Gruppen, nicht als Top-Bar). Prototyp-Analyse ergab: der Prototyp konsolidiert die 15 Workspaces in 4 Orte (Sub-Screens via Lanes/Modals/Drawer, keine Sub-Tab-Reihe) — Konflikt mit der bestehenden 15-Routen-Architektur → PO-Entscheidung: Voll-IA nach Prototyp, phasiert (ops/OP-REDESIGN-1.md Phase 4). Diese PR = Phase 4A (Shell): shell.component.ts linke Icon-Rail → 62px-Top-Bar (2px-Divider, sticky): Logo · Lage·Fluss·Takt·Team-Tabs (roter 3px-Aktiv-Underline, Fluss-Count-Badge = offene „Entscheiden"-Punkte) · „···"-Overflow (alle Bereiche gruppiert + Einstellungen [Ansicht/Feedback/Alarm-Ton] + Status [Auf-Kurs/Foto-Queue]) · True-North-Strip · Leitstand|Werkstatt-Segment (= Werker-Modus) · Uhr+Live-Punkt; darunter ein schlanker Workspace-Sub-Header (Titel + „?"). Alle 15 Screens bleiben erreichbar (Tabs → Ort-Hauptfläche, Rest über „···"/Deep-Link) — Übergang bis 4B–4D. Rail-Code (.railwrap/Proximity-Reveal/☰-Touch-Toggle/expanded/ring/sweepKey) entfernt; die Foto-Queue-Detailliste + alle Toggles ins „···" verlagert (kein Funktionsverlust). Entscheidung: Phase 4A ist bewusst reiner Shell-/Nav-Umbau (keine Screen-Änderung), damit die Top-Bar sofort steht und nichts unerreichbar wird; die Ort-Konsolidierung folgt in 4B (Verwaltung-Seite) · 4C (Fluss) · 4D (Team) · 4E (Aufräumen + „IA-komplett"). Live-DO-verifiziert (wrangler dev --local + gebauter Client + Playwright, Hell + Dunkel: 62px-Bar, 4 Tabs [Lage aktiv/Underline, Fluss-Badge 63], „···"-Menü listet alle Bereiche + Einstellungen, Leitstand|Werkstatt-Segment, TN-Strip, keine Rail mehr, keine Page-Errors). Reiner Client (shell.component.ts neu strukturiert), kein Server/DTO/Schema. Verifiziert: No-Hex + ng build prod grün + Live-Screenshots. Doku: ops/OP-REDESIGN-1.md (Phase 4 + „UI-komplett"-Korrektur), design/CLAUDE.md, design/WORKSPACES.md (Top-Bar-Sektion löst Crystal-Bar ab), docs/betrieb/Funktionsumfang.md, CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #725) — Verbindungs-Wiederherstellung + Auto-Update (Offline-PWA) (APP_VERSION 0.146.1 → 0.147.0, MINOR — neue Funktion, OP-OFFLINE-1). Schließt eine echte Betriebslücke: Weil der PWA-Service-Worker die App-Shell cached (navigationUrls: "/**"), lädt ein normaler Reload Dokument+JS aus dem Cache und geht nicht zum Server — er kann darum eine abgelaufene Cloudflare-Access-Session (die App ist per Golden Rule „Zero Trust vor Public" Access-gated; nach ~24 h WS-Upgrade 401) oder einen frisch deployten Client nicht einspielen; der WebSocket bleibt hängen, und der Offline-Cache verdeckt die Access-Anmelde-Umleitung (genau das Symptom „Reload verbindet nicht neu"). Neuer VerbindungService (client/src/app/services/verbindung.service.ts, providedIn:'root') + Shell-Wiring: (1) das Offline-Banner bekommt „↻ Erneut verbinden"hartNeuLaden() = SW-umgehender Neustart (SW deregistrieren + reload) → Dokument frisch vom Server → Access-Re-Login / neuer Client → WS verbindet (der SW re-registriert sich beim nächsten erfolgreichen Laden, Offline-Fähigkeit kehrt zurück); nur bei vorhandenem Netz (navigator.onLine) — sonst ehrlicher Toast „kein Netz" (PartySocket reconnectet bei echtem Offline ohnehin automatisch, kein Cache-Nuke ohne Nutzen). (2) SwUpdate-Auto-Update: bei Netz-Rückkehr (online) / Tab-Fokus (visibilitychange) checkForUpdate(); bei VERSION_READY erscheint das Banner „Neue Version — neu laden" (activateUpdate() + reload) → der Stale-Client-Fall ist proaktiv behoben (bisher aktivierte der SW eine neue Version erst nach Schließen aller Tabs). Entscheidung: hartNeuLaden deregistriert bewusst den SW (bulletproof gegen jede Cache-/Auth-Klemme) statt auf einen Cache-Bust-Query zu setzen; nur netz-gated, damit der Offline-Cache bei echtem Ausfall erhalten bleibt. Live-DO-verifiziert (wrangler dev --local + gebauter Client + Playwright, Hell: WS-Abriss → Offline-Banner mit „↻ Erneut verbinden"-Button, keine Page-Errors; das Neue-Version-Banner + der Reload-Pfad sind SwUpdate/unregister-Standard, tsc/build-verifiziert). Reiner Client (1 neue Service-Datei + Shell: Import/Inject/Handler + 2 Banner-Blöcke), kein Server/DTO/Schema. Verifiziert: No-Hex + ng build prod grün + Live-Screenshot. Doku: ops/OP-OFFLINE-1.md, docs/architektur/Offline-PWA.md, docs/betrieb/Funktionsumfang.md, CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #723) — Metrik-Persistenz — CodeRabbit-Nachzug zu #722 (APP_VERSION 0.146.0 → 0.146.1, PATCH — Fix/Nacharbeit). Nachzug der 6 validen CodeRabbit-Findings zu #722 (kamen als der PR schon gemergt war → als Follow-up-PR, frischer Branch von main). (1) Fix (Major, Correctness): die Review-Trend-Fensterlogik in lage-review.component.ts — (a) tagVor() bildete die Fenster-Grenze in der Runtime-Zeitzone, während der Server die tag-Buckets in Europe/Berlin schreibt → das Fenster konnte um einen Tag verrutschen; jetzt formatiert der Client die Grenze ebenfalls Europe/Berlin (deckungsgleich zu lokalerTag). (b) trendReihen baute die Punkte nur aus vorhandenen Zeilen — ein Tag ohne Snapshot fiel weg, statt als null-Lücke gerendert zu werden (Widerspruch zum eigenen Doc-Kommentar). Jetzt: explizite Kalendertag-Liste übers Fenster + Nachschlagen je Tag → fehlende Tage = leerer Balken (ehrlich, keine erfundenen Zahlen). (2) Perf (leitstand.ts): metrikVerlaufDTO() lief je Broadcast (inkl. 30-s-Solver-Ping) neu gegen die DO-SQLite, obwohl die Zeilen sich max. 1×/Tag ändern → Tages-Cache (metrikVerlaufCache, Muster wie kapazitaetCache), invalidiert beim Schreiben eines neuen Snapshots. (3–6) Doku/Metadaten: #722-Einträge in CHANGELOG + Timesheet als klickbare PR-Links (Audit-Regel); ops/OP-COST-1.md frontmatter bezug += OP-DATA-1; docs/architektur/Persistenz.md Pilot-Status synchronisiert — D5-3 „angelaufen" (die metrik_snapshots-Tabelle validiert die DO-SQLite-Mechanik live, Pilot-Kern = Migration einer bestehenden State-Klasse bleibt offen), Ist-Zustand-Stand 0.16.0 → 0.146.0. Bewusst nicht: kein neuer Selbsttest (Nachzug ohne neue Prüf-Oberfläche). Verifiziert: No-Hex + tsc (Server) + ng build prod + Persistenz-Gate + No-Console + doc-consistency --strict grün. Doku: CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #722) — Metrik-Persistenz: Review-Trend-KPIs (Auslastung · First-Pass-Yield · Nacharbeitsquote) (APP_VERSION 0.145.0 → 0.146.0, MINOR — neues Feature). Schaltet die bisher deferred Trend-Kennzahlen der Review-Sicht (3d-26 hatte dort eine ehrliche Hinweis-Karte, keine Fake-Zahlen) frei — mit echter Verlaufs-Persistenz statt Live-Snapshot. Speicher-Entscheidung (PO): direkt DO-SQLite (die laut Persistenz.md §3 entschiedene Langzeit-Heimat für Snapshots), nicht der interim Blob — erste DO-SQLite-Runtime-Tabelle des Repos: metrik_snapshots (tenant-lokal, ctx.storage.sql). Drizzle-Schema server/src/db/schema.ts = Single Source (im db:check-Gate, generierte Migration drizzle/0001_*.sql); Runtime-Anlage CREATE TABLE IF NOT EXISTS in onStart (idempotent, analog zum Audit-Pfad — Drizzle bleibt Schema-Beweis, Runtime roh). Producer: ein Tages-Snapshot je Tag (Europe/Berlin, guarded per In-Memory-Merker + PK-Idempotenz, kein Alarm) bei Boot + erster Persistenz des Tages; nur Fakten (die gemessene Quote), Prozent = NULL wenn keine Basis (ehrliche Lücke, keine erfundene 0 — D-2). Metrik-Umfang (PO): die 3 heute ableitbarenAuslastung (zeitbasierte Buchten-Quote, auslastungsQuote-Block in eine geteilte Methode extrahiert, von Broadcast + Producer genutzt) · First-Pass-Yield + Nacharbeitsquote (server-seitig aus den fertigen Aufträgen = SoT; quality.component zeigt sie live). Broadcast trägt metrikVerlauf (jüngste 90 Tage), Retention 400 Tage; der Client rendert je KPI eine Sparkline über Woche/Monat (lage-review.component.ts ersetzt die Hinweis-Karte, honester Leer-/Ein-Tag-Zustand). Best-effort — die Erfassung bricht den Laufzeitpfad nie. Live-DO-verifiziert (wrangler dev --local + gebauter Client + Demo-Seed + Playwright, Hell + Dunkel: DO legt die Tabelle an + schreibt beim Boot den Tages-Snapshot [Auslastung 1 % · FPY 33 % · Nacharbeit 67 % aus dem Seed], Broadcast liefert metrikVerlauf, Review-Sicht zeigt „1 Tag erfasst" + die 3 KPIs mit Sparkline + ehrlichem Hinweis). Client + Server + DO-SQLite (Schema/Migration, DO-Producer/Reader, LeitstandState-DTO beidseitig, Service-Selektor, Consumer). Verifiziert: No-Hex + tsc (Server) + ng build prod + Persistenz-Gate (Drizzle-Schema↔Migration sync, db:generate idempotent) + No-Console grün. Entscheidung — bewusst kein neuer OP: getrackt unter den Owning-OPs OP-AUDIT-1/OP-COST-1 (dort war die Persistenz-Voraussetzung notiert). Offen (nachgelagert): Termintreue + Ø Durchlaufzeit (brauchen abgeleitete Auftrags-Historie Fertigstellung vs. Plan). Doku: ops/OP-COST-1.md (Slice-Eintrag), docs/architektur/Persistenz.md (Ist-Zustand-Tabelle: erste DO-SQLite-Runtime-Tabelle), docs/betrieb/Funktionsumfang.md, CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #721) — Redesign „Flusslinie/Modernist" 3d-28: Quality-Check-Modal — OP-REDESIGN-1 UI-komplett (APP_VERSION 0.144.1 → 0.145.0, MINOR — net-new Layout-Feature + Redesign-Abschluss). Der letzte Redesign-Baustein: die Endkontrolle in-context als 720px-Modernist-Modal (neuer client/src/app/leitstand/qs-modal.component.ts), geöffnet aus dem Fluss-Auswahl-Panel über einen „✓ Quality-Check"-Button, der erscheint, sobald das Fahrzeug in der QS-Queue steht (imQs). Reiner View über den geteilten QsChecklisteService (3d-27): dieselbe Sichtprüfungs-Checkliste (✓/✕) und dasselbe server-harte QS-Gate (offenePunkte/abnahmebereit — in diesem Slice ebenfalls in den Service hochgezogen + im Workspace delegiert) wie der volle Qualität-Workspace → kein Duplikat-State, ein Prüf-Stand. Inhalt: Prozess-Vollständigkeit (Gate-Blocker), Sichtprüfung (4 Punkte), Freigabe-Gate „✓ Freigeben" (server-bestätigt via svc.auftragAktion 'abholen', gated auf allePass + abnahmebereit + erlaubteAktionen) · „→ Volle Endkontrolle" (Mängel/Nacharbeit-Erfassung bleibt der vollen Fläche). Entscheidung (PO-Freigabe Option A, zweistufig): erst der verhaltensgleiche State-Refactor (3d-27, sicherheitskritischer Vier-Augen-Gate G-4 isoliert), dann das Modal darauf. Live-DO-verifiziert (wrangler dev --local + gebauter Client + Demo-Seed + Playwright, Hell + Dunkel: Modal öffnet, Prozess-Vollständigkeit listet die echten offenen Punkte, Checkliste ✓/✕ toggelt über den Service, Freigeben korrekt disabled; scharfe Kanten/2px/radius 0). Weil der Demo-Seed kein Fahrzeug in der QS-Queue hält, wurde das Modal zur Screenshot-Verifikation über zwei temporäre Gate-Lockerungen sichtbar gemacht und danach wieder zurückgesetzt (committeter Code: Button/Modal an qmAuftraege gebunden). Damit ist OP-REDESIGN-1 UI-komplett (alle Phasen Token→Shell/IA→Screens→Farbsystem→Ink-Gantt→Layout-Features 3d-20…3d-28 gebaut+gemergt); nachgelagert bleiben nur die Review-Trend-KPIs nach der Metrik-Persistenz (OP-AUDIT-1/OP-COST-1). Reiner Client (1 neue Datei + QsChecklisteService-Erweiterung um die Gate-Funktionen + orders-Wiring), kein Server/DTO/Schema. Verifiziert: No-Hex + tsc + ng build prod grün + Live-Screenshots. Doku: ops/OP-REDESIGN-1.md (3d-28 ✅, UI-komplett), design/WORKSPACES.md, docs/betrieb/Funktionsumfang.md, CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #720) — Redesign „Flusslinie/Modernist" 3d-27: QS-Checklisten-State in Service hochgezogen (Fundament fürs QS-Modal) (APP_VERSION 0.144.0 → 0.144.1, PATCH — verhaltensgleicher Refactor). Der Refactor-Schritt vor dem QS-Modal (PO-Freigabe Option A: State hochziehen statt duplizieren). Der client-ephemere Sichtprüfungs-Scratchpad der Endkontrolle (✓/✕ je Prüfpunkt, keyed per QS-Runde id:runde, startet nach jeder Nacharbeit frisch) lag component-lokal in quality.component.ts → in den neuen QsChecklisteService (client/src/app/services/qs-checkliste.service.ts, providedIn:'root') hochgezogen: checkState-Signal + state/setzePruef/markiereBehoben/reset/allePass/anyFail + ckey + die exportierten QS_CHECKS/Pruef. quality.component.ts delegiert jetzt an den Service — identische Methoden-Signaturen → kein Template-Change, kein Verhaltens-Change; das server-harte QS-Gate (Prozess-Vollständigkeit/Mängel aus dem AuftragDTO) bleibt getrennt und unangetastet. Entscheidung: bewusst als eigener, isolierter Slice vor dem Modal, weil der QS-Screen den sicherheitskritischen Vier-Augen-Freigabe-Gate (G-4) trägt — so ist der riskante Umbau isoliert verifizierbar. Zweck: Workspace und das künftige QS-Modal teilen denselben Prüf-Stand (eine Wahrheit, keine Duplikat-Logik). Der Scratchpad bleibt bewusst client-ephemer (pre-Freigabe-Arbeitsstand, kein Server-Persist). Verifiziert: No-Hex + tsc + ng build prod grün + Live-DO-Render-Smoke (Qualität-Workspace rendert fehlerfrei über den Service; KPIs/Empty-States korrekt). Der ✓/✕-Interaktions-Pfad ist byte-gleiche Delegation — ein QS-Auftrag zum Anklicken stellt der Demo-Seed nicht her (alle Autos am Annahme-Start), daher tsc/build/Render-verifiziert. Reiner Client (1 neue Service-Datei + quality-Delegation), kein Server/DTO/Schema. CodeRabbit-Nachzug (in diesem PR): state() gibt eine Defensiv-Kopie zurück (keine externe Mutation des Signal-Arrays); neue entruempelt-Prune bindet die id:runde-Keys an die lebende QS-Queue (der root-Service akkumulierte sonst über die SPA-Lebensdauer). Selber PR (#720) trägt zusätzlich die Timesheet-Management-Summary (Gesamt-Stand) + Wochen-Rollup KW27–30 (Doku-Pflege, s. docs/betrieb/Timesheet.md-Kopf) — Doku + Refactor waren auf einem Branch gestapelt und werden bewusst als ein PR gemergt. Doku: ops/OP-REDESIGN-1.md (3d-27 ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #718) — Redesign „Flusslinie/Modernist" 3d-26: Lage · Review-Sicht (Woche/Monat) (APP_VERSION 0.143.1 → 0.144.0, MINOR — net-new Layout-Feature). Die Lage bekommt einen Heute/Woche/Monat-Umschalter (DD: „Review als eigener Zustand von Lage, kein eigener Workspace"): Heute = der operative Loop (3-TN-Karten · Heute-Streifen · Hof-Radar, unverändert), Woche/Monat = ein Rückblick (neuer lage-review.component.ts, in overview.component.ts gemountet). Entscheidung (PO-Freigabe „ehrlicher Client-Teil"): der Review zeigt nur echt aus dem Live-Stand ableitbare Daten — Team-Entwicklung (laufende Ausbildungsziele je Mitarbeiter, Skill aktuell★→ziel★ mit Fortschrittsbalken · Beförderungen im Zeitfenster aus Employee.befoerderungen[].ts, echte Historie · XP) und Klärfall-Ursachen (aktuell offene Klärfälle nach Grund gruppiert, Live-Snapshot, Notfall rot). Die Trend-Kennzahlen des Prototyps (Termintreue · Ø Durchlaufzeit · Auslastungs-Verlauf) brauchen persistierte Verlaufsdaten, die der Live-Stand (nur der aktuelle Zustand, „Derived State nie speichern") nicht vorhält → ehrliche Hinweis-Karte statt erfundener Zahlen (Prototype-Fixtures werden nie gebunden, design/CLAUDE.md); sie folgen mit der Metrik-Persistenz (OP-AUDIT-1/OP-COST-1). Fenster: Woche = letzte 7 Tage, Monat = letzte 30 Tage (Beförderungs-Historie). Live-DO-verifiziert (wrangler dev --local + gebauter Client + Demo-Seed + Playwright, Hell + Dunkel: Umschalter · „Rückblick — die Woche/der Monat" · Team-Entwicklung mit echten Ausbildungszielen · Klärfall-Ursachen · ehrliche Trend-Hinweis-Karte; Heute-Rückkehr stellt den operativen Loop wieder her). Reiner Client (1 neue Datei lage-review.component.ts + overview-Wiring: Import, Toggle, Mount, lageSicht/reviewSicht-Signale), kein Server/DTO/Schema. Verifiziert: No-Hex + tsc + ng build prod grün + Live-Screenshots. Doku: ops/OP-REDESIGN-1.md (3d-26 ✅), design/WORKSPACES.md, docs/betrieb/Funktionsumfang.md, CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #717) — Redesign „Flusslinie/Modernist" 3d-25: Warn-Entkopplung screen-by-screen (APP_VERSION 0.143.0 → 0.143.1, PATCH — Fix/Accessibility). Weil Rot in Taktano jetzt Primär- und Warnfarbe ist (DD-003), dürfen Warnungen nicht rein farblich kodiert sein. Nach einem vollständigen Audit aller Page- + geteilten Komponenten (Kategorie A „schon entkoppelt" [Glyph/Problemwort/role=alert/Blink] vs. B „nur Farbe") die echt farb-nur Warnungen mit persistentem Nicht-Farb-Signal versehen (⚠-Glyph + Problemwort/title): (B1) Fluss-Kanban „spät" — der pulsierende rote Punkt war unter prefers-reduced-motion unsichtbar (→ farb-nur) → persistentes „⚠ spät" (orders.component.ts); (B2) WIP-Limit-Zähler → „⚠" vor N/4 WIP bei Erreichen/Überschreiten; (B5) „Entscheiden"-Stapel-Badge → „⚠" vor der Zahl wenn Danger enthalten (entscheiden.component.ts); (B6) überbelegter Platz → persistenter „⚠ überbelegt"-Chip (occupancy.component.ts) + „⚠"-Präfix am N/Kap-Wert im Umpark-Ziel-Picker (repark-modal.component.ts); (Obs) OTLP „Letzter Export" fehlgeschlagen → „⚠" am Wert (costs.component.ts). Entscheidung — bewusst NICHT geändert: die roten Zähl-Badges an Nav/Tabs (Fluss&Risiko, Konflikte&Klärfälle, Risiko-Tab, Klärfälle=Amber) — ein Benachrichtigungs-Badge mit Zahl in der Alarm-Position neben einem Domänen-Wort („Risiko"/„Konflikte"/„Klärfälle") ist selbst schon ein Nicht-Farb-Signal; ein ⚠ im 15-px-Kreis wäre Dekor-Clutter (Leitprinzip Einfachheit, „nichts dekorativ"). Live-DO-verifiziert (wrangler dev --local + gebauter Client + Demo-Seed + Playwright, Hell + Dunkel: „⚠ spät" auf den Fluss-Karten [4×] + „⚠"-Entscheiden-Badge in beiden Themes; B2/B6 stellt der Demo-Seed nicht her → tsc/build-verifiziert). Reiner Client (5 Dateien, nur Template-Signale), kein Server/DTO/Schema. Verifiziert: No-Hex + tsc + ng build prod grün + Live-Screenshots. Doku: ops/OP-REDESIGN-1.md (3d-25 ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #715) — Neuer offener Punkt OP-AI-6: Struktur-Vorlagen je Textfeld (Stammdaten) → KI-Neuformulierung (kein APP_VERSION-Bump — reine OP-Erfassung). PO-Vorgabe (25.07.): für jedes freie Textfeld eine typische Struktur/Vorlage in den Stammdaten hinterlegbar (admin-editierbar, G-1); die In-App-KI (OP-AI-4) nutzt sie beim Neu-Formulieren der Eingabe → betriebsweit einheitliche Strukturen. Abgegrenzt zu OP-TEXTBLOCK-1 (Antipp-Bausteine = einfügen; OP-AI-6 = KI formt Freitext in die Ziel-Struktur). Als ops/OP-AI-6.md erfasst (pyramidal, Bausteine/offene Entscheidungen/Empfehlung „kleinste Stufe zuerst über OP-AI-4"), Bezug OP-TEXTBLOCK-1/OP-AI-3/OP-AI-4/OP-SEED-1/G-1; drkv_standard: kandidat — beim nächsten Template-Sync in den drkv-Standard (everything-as-code-template, G-2) übernehmen (In-App-Assistent + Stammdaten sind bereits Standard-Bausteine; Template-Repo außerhalb der Session-Scope → hier nur markiert). docs/betrieb/Offene-Punkte.md neu generiert (189 → 190 OPs). Docs-only, kein Code/DTO/Schema. Doku: ops/OP-AI-6.md, docs/betrieb/Offene-Punkte.md, CHANGELOG.
  • Branch claude/next-steps-8vmq5d (PR #714) — Redesign „Flusslinie/Modernist" 3d-24: Fluss inline-Auswahl-Panel (APP_VERSION 0.142.1 → 0.143.0, MINOR — net-new Layout-Feature). Das volle-Breite-Auswahl-Panel unter dem Fluss-Board (orders.component.ts) auf die Modernist-Flusslinie-Sprache gebracht (DD-002/DD-008): die runde Punkt-/Cyan-Puls-Phasen-Leiste ersetzt durch den 5-Stationen-Strip (Annahme · Vorbereitung · Produktion · Quality-Check · Abholung als Position auf der Flusslinie: 9×9-Quadrat je Station — vorbei = Tinte-gefüllt + Tinte-Konnektor · aktuell = Akzent --tk-brand · kommend = leer + --tk-text-faint, uppercase-Label, 2px-Konnektor), konsistent mit dem Akten-Cockpit-Drawer (3d-22). Neuer „Alle Details →"-Knopf in der Aktionszeile öffnet den geteilten Akten-Cockpit-Drawer (620px, 3d-22) ohne konkreten Teilschritt-Fokus — neues detailOffen-Signal, der Drawer-Mount honoriert panelInstanzId() || detailOffen(), der Close räumt beide. Neuer Helfer stufen(a) (Position je Station aus dem bestehenden stage(a)). Die klickbare 🚗-Fortschritts-Kette (FortschrittsIndikator, Teilschritt-Sprung ins Fly-in) bleibt daneben erhalten. Entscheidung: die Phasen-Leiste auf die Stationen-Position-Sprache angleichen und einen direkten Drawer-Einstieg schaffen — kein Refactor des funktional reichen Panels (alle Aktionen, Ausbildung/Helfer bleiben). Live-DO-verifiziert am laufenden Stack (wrangler dev --local + gebauter Client + Demo-Seed + Playwright, Hell + Dunkel: quadratischer Stationen-Strip mit rotem „Annahme"-Aktuell + leeren Folge-Quadraten; „Alle Details →" öffnet den 620px-Akten-Cockpit-Drawer korrekt in beiden Themes). Reiner Client (1 Datei), kein Server/DTO/Schema. Verifiziert: No-Hex + tsc + ng build prod grün + Live-Screenshots. Doku: ops/OP-REDESIGN-1.md (3d-24 ✅), docs/betrieb/Funktionsumfang.md, CHANGELOG, HANDOFF §2, Timesheet.

2026-07-24

  • Branch claude/next-steps-8vmq5d (PR #713) — Annahme-Overlay 3d-23a: CodeRabbit-Review-Nachzug (Timer-Cleanup · Autofokus · toter Import · Motion-Token) (APP_VERSION 0.142.0 → 0.142.1, PATCH — Fix). Nacharbeit der validen CodeRabbit-Findings zu #712 (kamen als das PR schon per Auto-Merge durch war), am annahme-overlay.component.ts: (1) Ressourcen-Cleanup (repo-Standard „Timer aufräumen") — der entprellte Dry-Run-Timer wird jetzt auch beim Nicht-mehr-bereit abgebrochen (sonst feuerte eine stale pruefeAuftrag nach, wenn der Satz wieder unvollständig wurde) und via DestroyRef.onDestroy beim Schließen des Overlays; (2) Autofokus — beim Öffnen springt der Cursor per viewChild + afterNextRender direkt in den Satz-Input (Touch-/Tastatur-Ergonomie); (3) toter Code — ungenutzter TERMINKLASSE_LABEL-Import + TK-Groundwork-Feld entfernt; (4) Motion-Token — die hartkodierten .18s/.25s-Animationsdauern → var(--tk-dur-fast)/var(--tk-dur-card) (client/CLAUDE.md: Motion-Dauern aus --tk-*). Bewusst nicht geändert (mit Begründung): der „#711-Bullet wiederherstellen"-Hinweis war ein False-Positive (der Eintrag ist vorhanden, #712 wurde darüber eingefügt — append-only intakt); die Zeitzonen-„Vereinheitlichung" nutzt dieselben geteilten Time-Helper wie die bestehende /annahme-Fläche (pre-existing, kein Slice-Scope); der OpenGrep-child_process.exec-Fund ist ein False-Positive (die Komponente hat kein child_process). Reiner Client (1 Datei), kein Server/DTO/Schema. Verifiziert: No-Hex + tsc + ng build prod grün. Doku: CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #712) — Redesign „Flusslinie/Modernist" 3d-23: Annahme-Overlay „ein Satz genügt" (APP_VERSION 0.141.0 → 0.142.0, MINOR — net-new Layout-Feature). Der Schnell-Intake als 720px-Modernist-Modal direkt aus der Lage (DD-001): neuer annahme-overlay.component.ts + Primärbutton „+ Neuer Auftrag — ein Satz genügt" auf overview.component.ts. Satz → 3 Pflicht-Tags (Kunde · Leistung · Abholung; erkannt = Ink-gefüllt, fehlend = Outline) via geteilte Heuristik parseAnnahmeSatz → echter Server-Dry-Run (svc.pruefeAuftragauftragPruefResult, seq-gated damit nur die eigene Anfrage angezeigt wird): Machbarkeit · Slot · Reserve · Preis → ✓ Annehmen (svc.createAuftrag); Fehlerfall ohne Sackgasse mit zwei Auswegen (→ Alternativ-Anlieferung übernehmen · ⚠ Trotzdem annehmen — wird Klärfall); Erfolg „AU-nnn ist im Takt" + „Auf dem Radar zeigen →" + „Nächster Satz". Entscheidung: ein reiner View über die geteilte Intake-Logik (Parse-Util + Service-Methoden) — keine Duplikation der Fachlogik und kein Refactor der bestehenden /annahme-Vollfläche (bleibt inkl. „🚗 Fahrzeug da"-Tab erreichbar); die IA-Richtung (Annahme = Overlay aus der Lage, nicht eigener Ort — DD-001) wird additiv umgesetzt, die alte Route als Fallback/Deep-Link behalten. Modernist: radius 0 (Modal-scoped-Regel), 2px-Kante, 720px zentriert, Ink-Tags, rote Primär-Aktion, tk-rise-Einblendung, Esc/Scrim/×-Schließen. Live-DO-verifiziert am laufenden Stack (wrangler dev --local + gebauter Client + Playwright, Hell + Dunkel: „▶ Beispiel einsetzen" → Tags Kaya GmbH / Vollfolierung Premium / Fr 31.07. → Machbarkeits-Panel „✓ passt in den Takt · Slot Mo 27.07. 08:00 · Waschplatz 1 · +3 T Reserve · 3.200 € · ✓ Annehmen"). Reiner Client (1 neue Datei annahme-overlay.component.ts + overview-Wiring: Import, Button, Mount, Signal), kein Server/DTO/Schema. Verifiziert: No-Hex + tsc + ng build prod grün + Live-Screenshots. Doku: ops/OP-REDESIGN-1.md (3d-23 ✅), design/WORKSPACES.md (§0 Annahme), docs/betrieb/Funktionsumfang.md, CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #711) — Redesign „Flusslinie/Modernist" 3d-22: Auftrag-Detail „Akten-Cockpit" (620px-Drawer) + Design-Handoff-Import (APP_VERSION 0.140.0 → 0.141.0, MINOR — net-new Layout-Feature + Doku-Import). Umsetzung des Auftrag-Detail-Drawers aus dem Claude-Design-Handoff „Flusslinie" (Screenshot 09, „Akten-Cockpit"): der geteilte auftrag-detail-panel.component.ts auf die Modernist-Sprache gebracht — Breite 420 → 620px (min(calc(100vw-48px),620px)), 2px-Tinte-Kante links, radius 0 durchgehend (Drawer-scoped-CSS-Regel [class*="rounded"]{border-radius:0} neutralisiert die hartkodierten Tailwind-rounded-*); die 🚗-Fortschritts-Kette ersetzt durch den 5-Stationen-Strip (Annahme · Vorbereitung · Produktion · Quality-Check · Abholung als Position auf der Flusslinie, DD-002/DD-008: 9×9-Quadrat je Station — vorbei = Tinte-gefüllt + Tinte-Konnektor · aktuell = Akzent --tk-brand · kommend = leer + --tk-text-faint); die runden farbigen Teilschritt-Status-Chips ersetzt durch Lifecycle-Marken als Form (10×10, 2px Kontur, DD-003: ■ läuft/erledigt · ◪ pausiert · □ wartet). Neue Helfer stationen/stgIndex/markeBg/markeBorder/markeTitle; FortschrittsIndikatorComponent-Import entfernt. Alle Funktionen erhalten (Kunde/Fahrzeug-Nachtrag, Foto-Doku, Doku-Gate, Vier-Augen-Freigabe, Klärfall/Notfall/Verzögerung/Notiz, Aktions-Hub, Verlauf) — reine visuelle Modernist-Angleichung, keine Feature-Reduktion. Entscheidung: die reiche bestehende Funktionalität behalten und nur die Design-Sprache (Form statt Farbe, Phase = Position, radius 0, 620px) angleichen — der Prototyp ist ein vereinfachter Mock, die App bleibt funktional reicher. Live-DO-verifiziert am laufenden Stack (wrangler dev --local + gebauter Client + injizierter Auftrag via WS + Playwright, Hell + Dunkel: 5-Stationen-Strip mit rotem „Annahme"-Aktuell, quadratische Marken, scharfe Kanten, 620px, alle Panels theme-aware). Doku-Import in diesem PR: (1) der Design-Decision-Log (DD-001…008, ADR-Stil) → docs/produkt/Design-Entscheidungen.md (Frontmatter/Landkarte/Footer nach Repo-Konvention, aus docs/README.md verlinkt; das WARUM hinter dem Redesign — Vier-Orte-IA, Flusslinie, Form-statt-Farbe, Achsentrennung, Modernist); (2) der Flusslinie-Prototyp (.dc.html + Taktano Wording.md + 22 Screenshots) → design/prototype/flusslinie/ als neue visuelle Referenz (neben v3), referenziert aus design/CLAUDE.md. Reiner Client (1 Datei) + Doku/Referenz-Import, kein Server/DTO/Schema. Verifiziert: No-Hex + tsc + ng build prod grün + Live-Screenshots. Doku: ops/OP-REDESIGN-1.md (3d-22 ✅), design/COMPONENTS.md (Akten-Cockpit-Rezept), design/CLAUDE.md, docs/produkt/Design-Entscheidungen.md, docs/README.md, docs/betrieb/Funktionsumfang.md, CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #710) — Redesign „Flusslinie/Modernist" 3d-21: Lage · „Heute kommt/geht"-Streifen (APP_VERSION 0.139.0 → 0.140.0, MINOR — net-new Layout-Feature). Zweiter net-new Layout-Schnitt (Live-DO): unter den 3-TN-Karten auf der Lage-Landing (overview.component.ts) ein zweispaltiger Tages-Digest↓ Kommt heute (Anlieferungen: status==='geplant' · bringtermin im Heute-Fenster · tatsaechlicheAnlieferung==null) · ↑ Geht heute (Abholungen: abholtermin im Heute-Fenster); je Zeile Uhrzeit · AU-Nr · Kunde, Klick fokussiert das Fahrzeug im Radar (fokusAuf); ⚠ spät (rot, Termin-Achse) markiert Abholungen, deren geplanteFertigstellung > abholtermin. Max 5/Spalte („+N weitere"), Leer-Zustände („Keine Anlieferung/Abholung heute"). Neue Helfer kommtHeute/gehtHeute/heuteFenster/istSpaet/fmtTrein aus dem Live-State abgeleitet, kein neuer State. Entscheidung: der Tages-Digest ergänzt die statischen TN-Karten um die zeitliche „was bewegt sich heute?"-Sicht (True-North Q2/Q3) direkt auf der Landing; „⚠ spät" nutzt die bestehende Konflikt-Prädikate-Logik (konsistent mit „Braucht dich"/Konflikte). Live-DO-verifiziert am laufenden Stack (wrangler dev --local + gebauter Client + 2 via WebSocket injizierte Heute-Aufträge + Playwright, Hell + Dunkel: Kommt 2 [16:00 Berger · 17:30 Sahin] · Geht 2 [beide ⚠ spät] — die spät-Aufträge erscheinen konsistent auch in „Braucht dich"). Reiner Client (1 Datei), kein Server/DTO/Schema. Verifiziert: No-Hex + tsc + ng build prod grün + Live-Screenshots. Mit-Fix (2 CodeRabbit-Nits aus #709): design/WORKSPACES.md quoteFarbe-Schwellen 60–<90 %/≥90 % (Off-by-boundary: bei genau 90 % ist es amber) · docs/betrieb/Funktionsumfang.md Version 0.1390.139.0. Doku: ops/OP-REDESIGN-1.md (3d-21 ✅), design/WORKSPACES.md (§1), docs/betrieb/Funktionsumfang.md, CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #709) — Redesign „Flusslinie/Modernist" 3d-20: Lage · 3-True-North-Karten-Reihe (APP_VERSION 0.138.0 → 0.139.0, MINOR — net-new Layout-Feature). Der erste net-new Layout-Schnitt aus dem OP-REDESIGN-1-Rest (Live-DO): die Lage-Landing (overview.component.ts) führt jetzt oben über Board+Sidebar mit drei flachen Antwort-Karten (answer-first/Minto) für die drei Leitfragen — Frage 1 Auslastung (Engpass-Quote = die engere von Mitarbeiter/Buchten, Farbe via quoteFarbe: <60 % dim · 60–90 % --tk-brand · >90 % --tk-amber) · Frage 2 Fahrzeuge (aktive Aufträge; „✓ alle verortet" grün bzw. „⚠ N ohne Standort →" amber mit Link zu Konflikte) · Frage 3 Nächste Kapazität (früheste machbare Leistung „ab " + Name). Zwei neue Helfer-Computeds tnAuslastung/tnKapNext, Frage 2 aus aktiveAuftraege/ohneStandortCountrein aus den Live-Insights abgeleitet, kein neuer State; die bestehenden detaillierten Sidebar-Panels (Auslastungs-Quote, Nächste freie Kapazität, Standorte, …) bleiben als Drill-down. Entscheidung: die Lage-Landing soll answer-first mit den drei Leitfragen führen (True-North direkt/schneller ablesbar) statt erst mit dem Radar-Board; Redundanz zum Header-True-North-Strip (3d-19/Phase 2b) ist gewollt — die Karten sind der prominente Landing-Anker, der Strip der ständig sichtbare Kopf. Live-DO-verifiziert am laufenden Stack (wrangler dev --local + gebauter Client + Demo-Seed + Playwright, Hell + Dunkel: Q1 1 % · Q2 5 ✓ verortet · Q3 „ab heute 14:42 · Vollfolierung Premium inkl. Keramik"). Reiner Client (1 Datei), kein Server/DTO/Schema. Verifiziert: No-Hex + tsc + ng build prod grün + Live-Screenshots. Doku: ops/OP-REDESIGN-1.md (3d-20 ✅), design/WORKSPACES.md (§1 Überblick), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #706) — Redesign „Flusslinie/Modernist" 3d-19: Design-Doku Prosa-Modernisierung (WORKSPACES/COMPONENTS ↔ Code) (kein APP_VERSION-Bump — reine Doku im selben PR wie 3d-18). Die Design-Doku trug noch die v3-Prototyp-Ära-Sprache, die der Code seit 3d-1..3d-18 nicht mehr abbildet — aktive Doku↔Code-Widersprüche (OP-DOCS-9, goldene Regel „every feature ships with its docs"). Bereinigt in design/WORKSPACES.md + design/COMPONENTS.md (+ design/CLAUDE.md/ops/OP-REDESIGN-1.md Phasen-Stand): JETZT-Linie „cyan, Glow" → rot (--tk-brand, 3d-1); Selektion (Kachel-Border · geklickter Schritt „ringed cyan" · Drop-Ziel „glow cyan" · Drag-Ghost · Standort-Wert · Master-Detail-Aktivzeile) → Ink (--tk-text, 3d-8/3d-9/3d-13); die 12 Workspace-Signaturfarben (— #hex-Suffix je Screen-Überschrift, Nav-„signature color glow bar", Header-Dot, Empty-State-Glyph, Segmented-Control-Hex) → entfernt/Ink (3d-14/3d-15); Glass/Glow/radius-hero/Gradient-CTAflach, radius 0, Rot-CTA (Phase 1); Konflikte/Klärfälle-Rohhex → --tk-red/--tk-amber-Token; das Ink-Gantt-Block-Encoding (Outline=geplant · gefüllt=läuft/erledigt · grau=pausiert) im Gantt-Rezept ergänzt (3d-18). Bewusst behalten: .tk-pchip-Cyan-Puls (reserviertes Live-/Präsenz-Signal, 3d-11) + funktionale Status-/Gantt-Hues (Farbe = Information). Entscheidung: nur hoch-sichere, in OP-REDESIGN-1 dokumentierte Korrekturen; nicht statisch verifizierbare Farbdetails (Szenario-Profil-Hues, Annahme-Parse-Chips) bewusst unangetastet (kein neuer Widerspruch). Reine Doku (2 Design-Docs + 2 Status-Docs), kein Code/DTO/Schema. Doku: ops/OP-REDESIGN-1.md (3d-19 ✅), CHANGELOG, HANDOFF §2, Timesheet.

2026-07-23

  • Branch claude/next-steps-8vmq5d (PR #706) — Redesign „Flusslinie/Modernist" 3d-18: Ink-Gantt (Dual-Theme → Token + Block-Stil, Live-DO-verifiziert) (APP_VERSION 0.137.1 → 0.138.0, MINOR — Design-Refactor + Dark-Mode-Fix). Teil B — Block-Stil (Ink-Gantt): die Füll-Optik der Gantt-Blöcke trägt jetzt den Arbeitsstand des Teilschritts (Hue bleibt die Auftrags-Status-Farbe): Outline = geplant („wartet" — 13%-Tint-Füllung + farbiger Rahmen + farbige Schrift, de-emphasiert) · gefüllt = in_arbeit/erledigt (solide + weiße Schrift, betont — läuft/fertig) · grau = pausiert (gedämpfte Graufüllung + dunkle Schrift). uebersprungen erscheint nicht im Gantt (gefiltert). Neue Helfer blockBg/blockBorder/blockText (gantt.component.ts); Konflikt-/Spät-Glows (blockShadow) koexistieren. Verifiziert am Live-Stack (Hell+Dunkel): geplante Blöcke jetzt Outline (leicht), aktive/fertige gefüllt (prominent) — klare visuelle Hierarchie. Bewusst: die funktionalen Status-Hues bleiben (Farbe = Auftrags-Phase), nur die Füll-Optik kodiert zusätzlich den Schritt-Stand. Der Gantt (gantt.component.ts) trug als einzige Komponente noch die Vor-Modernist-Dual-Theme-Logik: ~22 [class.…-slate-…]="!dark()" / [class.…-tk-…]="dark()"-Paare (hartkodierte slate/white im Hell-Modus) + fünf @if(dark())-gegatete Features (JETZT-Linie, ⚑/⚡/⏰-Legende, Wunsch-Abholung-Flaggen, JETZT-Kopf-Badge, Auslastungs-Heatmap), die im Hell-Modus unsichtbar waren; die Optik hing am Angular-dark-Input-Signal (aus theme.isDark()) statt an den theme-aware --tk-*-Tokens. Fix: alle Dual-Theme-Paare auf --tk-*-Tokens kollabiert (dark-Pfad byte-identisch, Hell-Pfad nutzt jetzt die verifizierten Modernist-Neutralen statt slate/white) + die fünf Feature-Blöcke entgated (zeigen in beiden Themes). Das ungenutzte dark-Input samt Parent-Binding [dark]="theme.isDark()" + ThemeService-Injection in planning.component.ts entfernt (kein dark() mehr im Gantt-Template). Behobener Bug: im Dark-Mode war der Gantt vorher ein weißes Grid auf dunklem Cockpit (Signal↔CSS-Theme entkoppelt) — jetzt folgt er dem data-theme korrekt. Verifiziert am laufenden Stack (wrangler dev --local + gebauter Client + Demo-Seed + Playwright): Vorher/Nachher-Screenshots Hell + Dunkel — Dark-Gantt jetzt korrekt dunkel, JETZT-Linie/Heatmap in Hell sichtbar. Bewusst NICHT geändert: die funktionalen Block-/Ausfall-Farben (geplant/angeliefert/in-Arbeit/pausiert · Krank/Urlaub/Wartung) bleiben — Farbe = Information; der optionale „gefüllt=läuft · Outline=geplant"-Block-Stil ist eine eigene, opinionierte Folge-Entscheidung. Reiner Client (2 Dateien, Template-Farb-/Klassen-Werte + Dead-Code), kein Server/DTO/Schema. Verifiziert: No-Hex + tsc + ng build prod grün. Doku: ops/OP-REDESIGN-1.md (3d-18 ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #705) — Redesign „Flusslinie/Modernist" 3d-17: Warn-Entkopplung Toasts (nicht-rein-farbliche Ton-Kennzeichnung) (APP_VERSION 0.137.0 → 0.137.1, PATCH — Fix). Erster Baustein der Warn-Entkopplung (OP-REDESIGN-1: weil Rot jetzt Primär-/Markenfarbe und Warnfarbe ist, dürfen Warnungen nicht rein farblich kodiert sein). Der Toast-Ton war rein über die Farbe kodiert ([style.color]="tone(t)") mit Default-Glyph fix — ein danger-Toast (rot) war so von einem brand-Toast (ebenfalls rot) nur an der Farbe unterscheidbar, und ein icon-loser danger-Toast zeigte sogar das Erfolgs- in Rot. Fix: Default-Glyph je Ton (TONE_ICON: ok ✓ · brand ✦ · warn ⚠ · danger ⚠ · info ℹ) → die Form unterscheidet den Ton (⚠ vs ✦ vs ✓), nicht mehr nur die Farbe; ein vom Aufrufer gesetztes t.icon gewinnt weiterhin. Audit-Befund: die übrigen roten Stellen tragen bereits ein Nicht-Farb-Signal (Text-Labels „getrennt"/„N ohne Standort"/„über Termin", /-Glyphen, role="alert", ganze Sätze) oder sind rote Aktionen (kein Warn-Fall) — der Toast war die klare Lücke. Reiner Client (1 Datei + COMPONENTS.md-Rezept), kein Server/DTO/Schema. Verifiziert: No-Hex + tsc + ng build prod grün. Offen (braucht Live-DO): vollständiger screen-by-screen Warn-Sicht-Durchlauf + Dark-Mode. Doku: ops/OP-REDESIGN-1.md, design/COMPONENTS.md, CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #704) — Redesign „Flusslinie/Modernist" 3d-16: Token-Hygiene — tote ws-Tokens raus, Hover tokenisiert, Störung-Achse-Farbe korrigiert (APP_VERSION 0.136.0 → 0.137.0, MINOR — Design-System-Bereinigung). Aufräum-Schritt nach der Rainbow-Ablösung: (1) die 14 ungenutzten --tk-ws-*-Workspace-Signaturfarben aus dem Token-Layer entfernttokens.json (color.workspace-Block), build.mjs (Name-Map), regeneriert tokens.css (98 → 84 Tokens, tokens:check-Round-Trip grün); kein --tk-ws-* mehr in Token-Layer oder App-Code. (2) 23× hardcodiertes hover:bg-white/[.03] (Weiß-Alpha, im Hell-Modus quasi unsichtbar, vom No-Hex-Gate nicht erfasst da Tailwind-Utility) → hover:bg-tk-hover (theme-aware Token) in costs/processes/staff. (3) Korrektur: der Klärfälle-Zähler-Badge war in 3d-15 versehentlich auf Rot gesetzt — zurück auf Amber (--tk-amber), gemäß der dokumentierten Zwei-Achsen-Regel (Termin/Konflikte = Rot, Störung/Klärfälle = Amber/Gold, bewusst nicht rot, COMPONENTS.md). (4) Design-Docs synchronisiert (goldene Regel Doku↔Code): DESIGN_TOKENS.md (ws-Tabelle → „⛔ entfernt"), design/CLAUDE.md (Signaturfarben-Regel durchgestrichen + Phasen-Stand), WORKSPACES.md + COMPONENTS.md (tote --tk-ws-*-Referenzen → --tk-red/--tk-amber/--tk-text). Entscheidung: tote Tokens statt „deprecated" entfernt (Single-Source sauber); Störung=Amber wiederhergestellt (Info-tragende Achsen-Unterscheidung). Reiner Client + Design-System (Token-Layer + 4 Screens/Komponenten-Farbwerte + 4 Docs), kein Server/DTO/Schema. Verifiziert: No-Hex + tokens:check + ng build prod grün. Doku: ops/OP-REDESIGN-1.md, CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #703) — Redesign „Flusslinie/Modernist" Phase 3d-15: ws-Signaturfarben — Screens (Rainbow-Ablösung abgeschlossen) (APP_VERSION 0.135.0 → 0.136.0, MINOR — Design-Angleich). Abschluss des ws-Signaturfarben-Feinschliffs: alle 10 verbliebenen Screens (costs · recommendations · conflicts · processes · orders · quality · planning · annahme · staff · overview) von der 14-farbigen Workspace---tk-ws-*-Rainbow befreit — kein --tk-ws-* mehr in irgendeinem Screen. Einheitliche Regel: Tab-Umschalter, Selektions-Highlights, Dekor-Glyphen/Ränder, Chips, Fortschritts-/Anteils-Balken, „neu"-Badges, Preise, Links → Ink (--tk-text); solide Primär-CTAs → Rot (--tk-brand): „✓ Übernehmen" (Vorschläge/Planung), „▶ Starten" (Team), „+ Posten" (Kosten), „✓ Freigeben" (Qualität), „🚗 Fahrzeug angeliefert" + „✓ Annehmen"-Haupt-CTA (Annahme); Konflikt-/Klärfall-Alarm-Indikatoren → Rot (--tk-red, Gefahr-Konvention aus 3d-2): Klärfälle-Zähler-Badge + Konflikt-Hebel-Fläche. Damit ist die Workspace-Rainbow-Palette komplett durch Ink+Rot ersetzt (nur die Token-Definitionen bleiben unbenutzt bestehen). Entscheidung: ein mechanischer Blanket-Durchlauf (ws→Ink) + gezielte Rot-Promotion der Primär-CTAs/Alarm-Badges — Rainbow-IA endgültig abgelöst (Modernist monochrom+rot). Reiner Client (10 Dateien, nur Farbwerte), kein Server/DTO/Schema. Verifiziert: No-Hex + ng build prod grün. Doku: ops/OP-REDESIGN-1.md (Phase 3d-15 ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #702) — Redesign „Flusslinie/Modernist" Phase 3d-14: ws-Signaturfarben — geteilte Komponenten (APP_VERSION 0.134.0 → 0.135.0, MINOR — Design-Angleich). Start des ws-Signaturfarben-Feinschliffs (die 14-farbige Workspace-Rainbow-Palette --tk-ws-*, die Modernist zugunsten Ink+Rot ablöst — 3d-2 entfärbte die Nav) auf die geteilten Komponenten (überall sichtbar, größter Konsistenz-Hebel): Auftrag-Detail-Panel — die zwei „Speichern"-Buttons (Kunde/Fahrzeug, waren --tk-ws-annahme-Vollfläche) → Rot (--tk-brand, Primär-Aktion), CRM-Link + „✦ Vorziehen vorschlagen"-Outline → Ink; Shell — Werker-Modus-Indikator ⬣ (--tk-ws-werker) → Rot (passend zum roten Werkstatt-Terminal 3d-5), die drei restlichen Nav-Badge-Farben (Annahme/Vorschläge/Qualität) → neutral Ink (--tk-text-dim — der deferrte Badge-Feinschliff aus 3d-2; Gefahr-Badges bleiben rot); Tafel (Leer-Glyph + „Auftrag annehmen"-Link), Klärung-Einplanen + Klärfall-Lösen (Container/Chips), Nächste-Aufgaben (Tab-Aktiv) → Ink. Entscheidung: ws-Vollflächen-Primär → Rot · ws-Dekor/Outline/Toggle → Ink (analog 3d-6). Reiner Client (6 Dateien, nur Farbwerte, per perl-Ersetzung + Kommentar-Nachzug), kein Server/DTO/Schema. Verifiziert: No-Hex + ng build prod grün. Doku: ops/OP-REDESIGN-1.md (Phase 3d-14 ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #701) — Redesign „Flusslinie/Modernist" Phase 3d-13: Takt/Planung-Chrome, Gantt-Bedienung & Klärfall-Palette — Cyan-Feinschliff abgeschlossen (APP_VERSION 0.133.0 → 0.134.0, MINOR — Design-Angleich). Der letzte Cyan-Feinschliff auf die verbliebene interaktive UI-Chrome: Planung/Takt (planning.component.ts) — „Alle Profile identisch"-Info-Box + ℹ → Ink, „✎ Entwurf"-Modus-Banner (Rahmen+Text) → Rot (--tk-brand, aktive Bearbeitung = Aufmerksamkeit, konsistent mit „Plan ändern" 3d-3), Testdaten-Checkbox → Rot, Optimierungs-Metrik-Farbe (3. Kennzahl) → Ink; Gantt-Bedienung (gantt.component.ts) — Zoom-Preset-Toggle aktiv + „Klick → Details"-Hinweis → Ink, Drag-Vorschau-Ghost (gültige Platzierung war Cyan) → Ink (ungültig bleibt Rot ⚠ — klarer Kontrast gültig/ungültig); Klärfall-Lösen-Palette (klaerfall-loesen.component.ts) — die mittleren Routen „Sprung zu QS" (war Cyan) + „Anderer Schritt" (war Violett) → Ink (Rainbow entschärft; „← Zurück"=Grün [sicher] + „✕ Abbruch"=Rot [destruktiv] behalten ihre semantische Farbe, die Icons ←/✓/↷/✕ tragen den Rest). Damit ist der Cyan→Ink/Rot-Feinschliff des gesamten Cockpits abgeschlossen. Bewusst als Cyan erhalten (dokumentiert, kein Rest-Aufwand): [a] funktionale Lifecycle-Status-Hues (labels.ts angeliefert/Termin-Klasse ziel, phase.ts Abholung, staff.ts artFarbe Schicht-Typ, gantt.ts wunschfrei-Block) — der Phase-1-Brief bewahrt funktionale Status-/Gantt-Hues (Farbe trägt hier Information, True-North Q2); [b] Live-/Präsenz-Signale (✎ „wird gerade bearbeitet", ⏺ „tippt/parst"-Puls, Lade-Spinner, istUmparken „parkt gerade um") — Cyan = reserviertes Echtzeit-Signal. Reiner Client (3 Dateien, nur Farbwerte), kein Server/DTO/Schema. Verifiziert: No-Hex + ng build prod grün. Offen in OP-REDESIGN-1: der Gantt-Block-Stil-Refactor (Dual-Theme dark()→Token + status-gefärbt→Ink-Gantt, braucht Live-DO zum visuellen Verifizieren) · ws-Signaturfarben-Reste (Avatar-Violett, ws-annahme) · 3-True-North-Karten-Reihe/Lage-Rest/Overlays. Doku: ops/OP-REDESIGN-1.md (Phase 3d-13 ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #700) — Redesign „Flusslinie/Modernist" Phase 3d-12: Bild-Gate & Shell-Reste Modernist (APP_VERSION 0.132.0 → 0.133.0, MINOR — Design-Angleich). Cyan-Feinschliff auf das Foto-Gate (bild-upload-gate.component.ts + bild-schutz.component.ts — On-device-Prüfung Personen/Kennzeichen vor Upload, OP-QS-2) + Shell-Reste: Bild-Gate — Prüf-Kriterien-Text-Emphase (Qualität/Personen/Inhalt), Hover-/Focus-Rahmen, Auto-Geprüft-Punkt (auto war Cyan; manuell=Amber bleibt), Markier-Modus-Toggle → Ink; die Markierungs-Nummern-Badges (Bildschirm) + die ins Bild gebrannten Marker-Kreise (Canvas-Export) → Rot (--tk-brand, hohe Sichtbarkeit + Marke für markierte Personen/Kennzeichen-Regionen); der primäre „Hochladen"-Button (freigegeben) → Rot (Primär-Aktion); Shell — Theme-Umschalt-Glyph (☀/☾) + „Auf-Kurs"-Fortschritts-Ring → Ink. Entscheidung: Selektion/Toggle/Info/Progress → Ink · Primär-Upload + Marker → Rot (Marker müssen sichtbar sein, Rot = Marke + Kontrast); manuell-Amber bleibt (Aufmerksamkeit). Reiner Client (3 Dateien, nur Farbwerte), kein Server/DTO/Schema. Verifiziert: No-Hex + ng build prod grün. Doku: ops/OP-REDESIGN-1.md (Phase 3d-12 ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #699) — Redesign „Flusslinie/Modernist" Phase 3d-11: Annahme & Prozesse Modernist (APP_VERSION 0.131.0 → 0.132.0, MINOR — Design-Angleich). Cyan-Feinschliff auf Annahme (annahme.component.ts — „Takt-Kommando"-Intake) + Prozesse (processes.component.ts — Prozess-/Schritt-Stammdaten): Annahme — Kommandozeilen-Glow entfernt (Modernist flach), Alternativ-Vorschlag-Button → Ink, „Auf dem Radar zeigen"-CTA-Glow (war Cyan an rotem Button) → Rot (angeglichen), Info-Chips (Anlieferung/Abholung/Termin-Härte-Default) → Ink; Prozesse — Info-Hinweis-Tint, Mindest-Niveau-★, Abhängigkeits-Toggle, „Foto-Vorgabe"-Outline, .tk-flag.tk-on-Toggle → Ink, Arbeitsplatz-Typ-Checkbox → Rot. Bewusst Cyan behalten: der ⏺ „tippt/parst"-Live-Puls + der Lade-Spinner in der Annahme — beides echte Live-/Verarbeitungs-Signale (konsistent mit der Live→Cyan-Regel). Entscheidung: Selektion/Toggle/Info → Ink · Checkbox → Rot · Live/Processing → Cyan; Glows raus (flach), CTA-Schatten in Marken-Rot statt Cyan. Reiner Client (2 Dateien, nur Farbwerte + 1 entfernter Glow), kein Server/DTO/Schema. Verifiziert: No-Hex + ng build prod grün. Doku: ops/OP-REDESIGN-1.md (Phase 3d-11 ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #698) — Redesign „Flusslinie/Modernist" Phase 3d-10: Belegung & Fluss-Gruppe Modernist (APP_VERSION 0.130.0 → 0.131.0, MINOR — Design-Angleich). Cyan-Feinschliff auf die Belegungs-/Karte-Sicht (occupancy.component.ts — die „wo stehen die Fahrzeuge"-Karte, Q2) + die restliche Fluss-Gruppe (conflicts.component.ts, quality.component.ts): Belegung — Drag&Drop-Hinweis-Emphase, „Wareneingang — Annahme"-Zone (Rahmen/Label/Zähler), Drag-Over-/Drag-Aktiv-Ziel-Highlight, „✓ da"/📍/🅿️-Aktions-Icons → Ink; Konflikte — Info-Box, 📝-Notiz-Button, Standort-Wert, Avatar-Farb-Rotation → Ink; Qualität — KPI „Offene Prüfungen" + Mangel-Status in_nacharbeit (war Cyan; offen=Amber/behoben=Grün bleiben funktional) → Ink. Entscheidung: Selektion/Interaktion/neutrale Info → Ink; funktionale Status-Hues (Amber-Warnung, Grün-OK, Rot-Doppelbelegung) bleiben — nur das arbiträre Cyan weicht. Drop-Ziel-Highlight bewusst Ink statt Rot (neutrale „hier ablegen"-Führung, kein Alarm). Reiner Client (3 Dateien, nur Farbwerte), kein Server/DTO/Schema. Verifiziert: No-Hex + ng build prod grün. Doku: ops/OP-REDESIGN-1.md (Phase 3d-10 ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #697) — Redesign „Flusslinie/Modernist" Phase 3d-9: Detail-Panel & geteilte Modals/Overlays Modernist (APP_VERSION 0.129.0 → 0.130.0, MINOR — Design-Angleich). Der Cyan-Feinschliff auf die geteilten Komponenten (die überall im Cockpit auftauchen) nach der Feinschliff-Regel: Auftrag-Detail-Panel (auftrag-detail-panel.component.ts — Teilschritt-Fokus-Auswahl, „angeklickt"-Label, 📝-Notiz-Toggle, „Produktion starten"-Outline, Notiz-Popin-Rahmen) → Ink; Umparken-Modal (repark-modal.component.ts — Slot-Auswahl [empfohlen + weitere], „✓ passt"-Label, „Empfohlen"-Kopf, Auftragsnummer) → Ink (die ✅/✓-Glyphen tragen die „passt"-Bedeutung, nicht die Farbe); Assistent-Chat (chat-panel.component.ts — Pin-/Issues-Toggles → Ink; User-Sprechblase → Rot --tk-brand als Marken-/Eigen-Akzent, heller Text erhalten); Feedback-Formular (Art-Auswahl + Hover → Ink); Modal-Dialog (primärer Bestätigen-Button → Rot, nicht-Gefahr = Primär-Aktion); Toast brand-Ton → Rot (war fälschlich Cyan); Feedback-Pin-/Screenshot-Region-Overlay (Markier-Rechteck → Ink, neutrale Selektion); Fortschritts-Indikator (Fokus-Ring → Ink); Werkstatt-Terminal Umpark-Karten-Rahmen → Ink. Bewusst offen: die 4-farbige Klärfall-Lösen-Options-Palette (grün/cyan/violett/rot) = semantisches Farbset, kommt als eigene Entscheidung (nicht halb entfärben); ws-Signaturfarben + Status-Hues separat. Entscheidung: Selektion → Ink · Primär/Marke/„Du" → Rot · Live/Präsenz → Cyan — die geteilten Bausteine ziehen konsistent nach, sodass das Cockpit überall gleich „spricht". Reiner Client (10 Dateien, nur Farbwerte), kein Server/DTO/Schema. Verifiziert: No-Hex + ng build prod grün. Doku: ops/OP-REDESIGN-1.md (Phase 3d-9 ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #696) — Redesign „Flusslinie/Modernist" Phase 3d-8: Fluss & Lage Modernist (APP_VERSION 0.128.0 → 0.129.0, MINOR — Design-Angleich). Die beiden zentralen True-North-Sicht-Screens (orders.component.ts = Fluss / „wo & wann", overview.component.ts = Lage/Hof-Radar) folgen der Feinschliff-Regel: Auftrags-/Slot-/Avatar-/Nachbar-Auswahl (Card-Rahmen+Tint, Slot-Kachel, Mitarbeiter-Avatar-Ring, Nav-Fokus, aktueller Prozess-Schritt, Standort-Wert) → Ink (--tk-text statt Cyan); die animierte „Flusslinie" (Radar-Sweep)Rot (--tk-brand, brand-konform — die namensgebende Fluss-Linie ist jetzt rot) mit entferntem Glow (Modernist flach); die Selektions-Glows (Slot-Kachel, Avatar) entfernt (flach); der „Produktion starten"-Outline-Link (Cyan) → Ink. Bewusst unberührt: tk-cyan2 (= --tk-brand, war schon rot: Auslastungs-Wert, Eingang, früheste Anlieferung); funktionale Status-Hues (grün „erledigt", ws-annahme „reserviert") bleiben (eigener ws-Farb-Feinschliff). Entscheidung: Selektion durchgängig Ink (hoher Kontrast, kein Alarm), Flusslinie als Marken-Rot, Glows raus (flach) — Rot bleibt Aktion/Marke. Reiner Client (2 Dateien, nur Farbwerte + 2 entfernte box-shadows), kein Server/DTO/Schema. Verifiziert: No-Hex + ng build prod grün. Doku: ops/OP-REDESIGN-1.md (Phase 3d-8 ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #695) — Redesign „Flusslinie/Modernist" Phase 3d-7: Team-Editor Modernist (APP_VERSION 0.127.0 → 0.128.0, MINOR — Design-Angleich). Der Team-Screen inkl. Mitarbeiter-Editor (staff.component.ts) folgt jetzt der Feinschliff-Regel: Vertrauens-★-Auswahl (Anlegen + Bearbeiten), Skill-Niveau-★, sowie die Abwesenheits-Toggles (Wunschfrei weich · Einfacher Wunsch · Genehmigt · Ganzer Tag/Bestimmte Schichten) im gewählten Zustand → Ink (--tk-text statt Cyan, 15 Bindungen); die Schicht-Checkboxen (accent-color) → Rot (--tk-brand); XP-Badge + Fairness-Zähler + Abwesenheits-Info-TintInk (neutrale Stat/Info); das weiche Abwesenheits-Typ-Label (war Cyan) → Ink (das harte bleibt Rot — hart/weich-Kontrast erhalten); „✓ genehmigt" → Ink. Bewusst Cyan behalten: die „✎ wird gerade bearbeitet"-Präsenz + der „parkt gerade um"-Live-Status (istUmparken, Echtzeit-Tätigkeit) + artFarbe-Schicht-Typ-Farbe (Schicht/Gantt-Visualisierung → eigener Ink-Gantt/Schedule-Slice). Entscheidung: Feinschliff-Regel unverändert (Selektion/Toggle → Ink · Primär/Checkbox → Rot · Live/Präsenz → Cyan); Schicht-Farbcodierung bleibt bei der Gantt-Slice. Reiner Client (1 Datei, nur Farbwerte), kein Server/DTO/Schema. Verifiziert: No-Hex + ng build prod grün. Doku: ops/OP-REDESIGN-1.md (Phase 3d-7 ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #694) — Redesign „Flusslinie/Modernist" Phase 3d-6: Verwaltung Modernist (APP_VERSION 0.126.0 → 0.127.0, MINOR — Design-Angleich). Der Verwaltungs-Screen (administration.component.ts) ist entfärbt: die Config-Auswahl-Chips (Taxonomie-Art · Skill-Eignung · Wochentage · Nachbar-Buchten) tragen im gewählten Zustand jetzt gefüllte Ink-Chips (--tk-text statt Cyan) — die selbst­erklärende Modernist-Selektion; die „+ Arbeitsplatz"/„+ Schicht"-Primär-Buttons (trugen die Workspace-Signaturfarben --tk-ws-bays/--tk-ws-staff) → Rot (--tk-brand); die Sekundär-Outline-Buttons „+ Sperre" / „Neu laden" (Cyan-Rahmen+Text) → Ink; die „aktiv"-Checkboxen (accent-color) → Rot. Bewusst Cyan behalten: die drei „✎ wird gerade bearbeitet"-Badges — Cyan bleibt das eine reservierte Live-/Präsenz-Signal (jemand editiert diesen Datensatz gerade, Echtzeit-Kollaboration), konsistent mit 3d-1. Entscheidung (Feinschliff-Regel, aus 3d-1/3d-3 fortgeführt): Selektion/Config-Toggle → Ink · Primär-Aktion → Rot · Live/Präsenz → Cyan — Rot bleibt selten & bedeutungstragend. Reiner Client (1 Datei, nur Farbwerte), kein Server/DTO/Schema. Verifiziert: No-Hex + ng build prod grün. Doku: ops/OP-REDESIGN-1.md (Phase 3d-6 ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #693) — Redesign „Flusslinie/Modernist" Phase 3d-5: Werkstatt-Terminal Modernist-Akzent (APP_VERSION 0.125.0 → 0.126.0, MINOR — Design-Angleich). Die Werker-Fläche „Meine Arbeit" (meine-arbeit.component.ts) trug als einzigen Akzent die Workspace-Signaturfarbe --tk-ws-werker (Indigo) — jetzt auf Rot (--tk-brand) gezogen (8 Stellen: aktiver Werker-Auswahl-Chip [Rahmen/Fläche/Text], Avatar-Tönung, Offen-Zähler-Badge, Leer-Zustand-Glyph ⬢, Status-Pille). Damit ist das Werkstatt-Terminal durchgängig monochrom + rot (Modernist). Reiner Client (1 Datei, nur Farbwerte), kein Server/DTO/Schema. Verifiziert: No-Hex + ng build prod grün + Live-Screenshot (roter ⬢-Leer-Glyph). Doku: ops/OP-REDESIGN-1.md (Phase 3d-5 ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #692) — Redesign „Flusslinie/Modernist" Phase 3d-4: Team · Kann-was-Matrix (APP_VERSION 0.124.0 → 0.125.0, MINOR — neues Feature). Der Team-Screen (staff.component.ts) führt oben eine Kann-was-Matrix: Tabelle Mitarbeiter × Skills — Zeilen = aktive Mitarbeiter, Spalten = aktive Skills (Katalog), Zellen = Könner-Stufe als ★ (Niveau 1–3, · = kein), plus eine Ausbildungsziel-Spalte („★2 → ★3 · ", erstes offenes Ziel). Ganze Zeile klickbar → bestehender Mitarbeiter-Editor (oeffneBearbeiten, Reuse); aria-label je Zeile, sticky Name-Spalte, horizontal scrollbar, Leer-Guard (ohne Mitarbeiter/Skills ausgeblendet). Rein aus Live-Signalen (svc.employees() · svc.skills(), keine Fixtures). Entscheidung: die Matrix als Team-Landing (Brief: „Team = Kann-was-Matrix") — die vorhandenen sterne()/oeffneBearbeiten()/Skill-Daten wiederverwendet, kein neuer State (Einfachheit); Doppel-sterne() beim Bau erkannt + entfernt. True-North: „wer kann was" auf einen Blick = Grundlage für Zuteilung & Auslastung (Q1). Reiner Client (staff-Template + 3 Helfer/Computed), kein Server/DTO/Schema. Verifiziert: No-Hex + tsc -p tsconfig.app.json + ng build prod grün; Team-Screen rendert Modernist (Leer-Guard greift ohne Seed-Daten). Visuell mit Daten: braucht ein laufendes DO (wie der Ink-Gantt) — Logik ist an echte DTOs gebunden, build-verifiziert. Doku: ops/OP-REDESIGN-1.md (Phase 3d-4 ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #691) — Redesign „Flusslinie/Modernist" Phase 3d-3: Takt-Controls Modernist (APP_VERSION 0.123.0 → 0.124.0, MINOR — Design-Angleich). Die Toolbar-Toggles des Takt/Planung-Screens (planning.component.ts) sind entfärbt: asap/jit aktiv (war Cyan) + Auto-Nachführung an (war Grün) → Ink (--tk-text, monochromer Aktiv-Zustand); Plan ändern (Entwurfs-/Drag-Modus, war Cyan) → Rot (--tk-brand — aktive Bearbeitung = Aufmerksamkeit, brief-konform). „⟲ Optimierung vorschlagen" war bereits rot (3d-1), der Konflikt-Sprung-Button bereits rot. Entscheidung: monochrome Toggles (Ink) für neutrale Modi, Rot nur für den aktiven Bearbeitungs-Modus — „Rot = Bedeutung". Reiner Client (planning.component.ts, nur Farbwerte), kein Server/DTO/Schema. Verifiziert: No-Hex + tsc -p tsconfig.app.json + ng build prod grün + Live-Screenshot (Ink-Toggles asap/Auto, roter „Plan ändern"-Entwurf). Hinweis/offen: der Gantt selbst (gantt.component.ts) trägt noch die Vor-Token-Dual-Theme-Logik (dark() → hartkodierte slate/white im Hell-Modus, ~24 Bindungen) + status-gefärbte statt Ink-Gantt-Blöcke (gefüllt=läuft/erledigt · Outline=geplant · grau=pausiert) — das ist eine eigene größere Slice (Dual-Theme→Token + Block-Stil; braucht Live-Daten zum visuellen Verifizieren). Doku: ops/OP-REDESIGN-1.md (Phase 3d-3 ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #690) — Redesign „Flusslinie/Modernist" Phase 3d-2: Monochrome Ort-Chips (Nav) (APP_VERSION 0.122.0 → 0.123.0, MINOR — Design-Angleich; erledigt den deferrten Teil von Phase 2b). Die Navigations-Rail zeigt nicht mehr die Rainbow---tk-ws-*-Signaturfarben je Ort, sondern monochrome Ink-Chips (--tk-text-dim); der aktive Ort wird rot (--tk-brand, via .tk-nav.tk-active { --chip: var(--tk-brand) } — Chip + Stripe + Text). Zusätzlich: Header-Platz-Punkt (das „aktueller Ort"-Signal) + Logo-Kachel-Tönung von Cyan → Rot; der Stripe-Glow entfernt (Modernist ist flach). Badges bleiben farbig (rot für Gefahr — Konflikte/Klärfälle; die restlichen Badge-Farben sind Feinschliff). shell.component.ts navGroups()-Item-color per gezieltem sed (Zeilenbereich der Computeds) auf Ink — badgeColor (Groß-C) bewusst unberührt. Entscheidung: „monochrom + Rot" nach Brief — die 4 Orte tragen keine Eigenfarbe mehr (die 12-Workspace-Signaturfarben waren an die alte IA gebunden), der aktive Ort ist der einzige farbige (rote) Akzent. Reiner Client (nur shell.component.ts, Farbwerte + eine CSS-Regel), kein Server/DTO/Schema. Verifiziert: No-Hex + tsc -p tsconfig.app.json + ng build prod grün + Live-Screenshot (Ink-Chips, aktiver „Lage"-Ort rot, Header-Punkt rot). Doku: ops/OP-REDESIGN-1.md (Phase 3d-2 ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #689) — Redesign „Flusslinie/Modernist" Phase 3d-1: Accent-Sweep — Primär-Aktionen → Rot (APP_VERSION 0.121.0 → 0.122.0, MINOR — Design-Angleich). Modernist verlangt „Rot ist Bedeutung — Akzent nur für Primäraktion". Deshalb sind die soliden background: var(--tk-cyan)-Füllungen (27 Stellen in 13 Dateien) auf var(--tk-brand) (Rot) gezogen: Primär-Aktions-Buttons (Assistent-FAB · „⟲ Optimierung vorschlagen" · „Pin vormerken" · „Notiz speichern" · Konflikt-/Annahme-/Umpark-Bestätigungen …), die JETZT/Now-Linien (Brief: „rote JETZT-Linie" — Gantt + Risiko-Timeline) und Highlight-Badges (z. B. „HQ"); die zugehörigen Glows (FAB, Now-Marker) wurden mitgezogen (Rot statt Cyan). Bewusst NICHT angefasst (eigener Feinschliff): cyan Outlines/Text/Tints (Selektion/Live), die Toggle-Aktiv-Zustände (? 'var(--tk-cyan)', ~63 Stellen) und --tk-green/--tk-ws-* — diese folgen als „Selektion → Ink, Toggle-Aktiv → Rot/Ink"-Slice. Entscheidung: gezielt nur die soliden Füllungen (= Primär-Aktionen/Now-Linien) geflippt — ein grep-sicheres Muster, das Primäres trifft ohne die semantische Selektions-/Live-Cyan blind mitzureißen (kein Bedeutungsverlust). Cyan bleibt vorerst der funktionale Selektions-/Live-Akzent (Phase-1-Entscheidung), der Rest ist Feinschliff. Reiner Client (13 Component-Templates, nur Farbwerte), kein Server/DTO/Schema. Verifiziert: No-Hex (nur --tk-*) + tsc -p tsconfig.app.json + ng build prod grün + Live-Screenshot (Takt: „Optimierung vorschlagen" + FAB jetzt rot). Doku: ops/OP-REDESIGN-1.md (Phase 3d-1 ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #688) — Redesign „Flusslinie/Modernist" Phase 3c: Lage · „Braucht dich"-Digest (APP_VERSION 0.120.0 → 0.121.0, MINOR — neues Feature). Die Lage-Landing (overview.component.ts) führt oben in der Sidebar jetzt einen „Braucht dich"-Digest: die dringendsten „Entscheiden"-Einträge (max 4 — Klärfälle/Notfälle zuerst, dann Termin-Konflikte, dann fehlende Ortung) mit Typ-Label VERSAL + 3px-Ton-Kante (danger --tk-red / warn color-mix(--tk-red 45%)), plus ein roter Zähler „N → Entscheiden"; jeder Eintrag + der Zähler verlinken in den Fluss, wo die vollständige „Entscheiden"-Ablage inkl. Aktionen liegt. Rein aus Live-Signalen abgeleitet (svc.klaerfaelle · konflikte · ohneStandort), Leer-Zustand „✓ Alles im Takt.". Entscheidung: die Lage zeigt „was zu entscheiden ist" vorab (direkter True-North-Treffer: Q2 „wo/was braucht Aufmerksamkeit"), die eigentliche Aktion bleibt im Fluss (kein doppelter Aktions-Ort). Reiner Client (overview-Template + 2 Computeds), kein Server/DTO/Schema. Verifiziert: No-Hex + tsc -p tsconfig.app.json + ng build prod grün (nach Fix eines Template-Parse-Fehlers: deutsche Anführungszeichen im title-Attribut entfernt) + Live-Screenshot (Sidebar „BRAUCHT DICH" oben, Leer-Zustand). Offen (3c-Rest/3d): 3 True-North-Karten in einer Reihe · „Heute kommt/geht" · Review-Sicht · Annahme-Overlay · 620px-Drawer · QS-Modal · Takt/Team/Verwaltung/Terminal. Doku: ops/OP-REDESIGN-1.md (Phase 3c ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #687) — Redesign „Flusslinie/Modernist" Phase 3b: Fluss · Linie/Karte-Toggle (APP_VERSION 0.119.0 → 0.120.0, MINOR — neues Feature). Der Fluss-Screen (orders) hat statt „Fluss · Risiko" jetzt die Sicht-Umschaltung „Linie · Karte · Risiko" (orders.component.ts): Linie = 5-Stationen-Pipeline (bestehend), Karte = die bestehende Belegungs-Fläche app-occupancy eingebettet (Halle/Buchten + Hof/Parkplätze, Umparken per Drag&Drop + Park-Dialog), Risiko = Dringlichkeits-Timeline (bestehend); dazu eine kontextuelle Hinweiszeile je Sicht. Entscheidung (Einfachheit/Reuse): die Karte nicht neu gebaut, sondern die vorhandene OccupancyComponent (self-contained, liest den Service) über ihren Selektor app-occupancy eingebettet — die „Entscheiden"-Spalte bleibt in allen Sichten rechts stehen (Fluss-Karte + Entscheiden = Spec-Layout). Kein Zirkel-Import (occupancy importiert orders nicht). Reiner Client (orders-Template + Tab-Enum 'fluss'|'karte'|'risiko'), kein Server/DTO/Schema. Verifiziert: No-Hex + tsc -p tsconfig.app.json + ng build prod grün + Live-Screenshot (Toggle Linie/Karte/Risiko, Karte-Grid mit Drag&Drop-Hinweis + Entscheiden-Spalte). Offen (3c+): inline-Auswahl-Panel unter der Linie · 620px-Auftrag-Drawer · Quality-Check-Modal. Doku: ops/OP-REDESIGN-1.md (Phase 3b ✅), design/WORKSPACES.md, CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #686) — Redesign „Flusslinie/Modernist" Phase 2b: True-North-Strip im Header (APP_VERSION 0.118.0 → 0.119.0, MINOR — neues Feature). Die drei True-North-Leitfragen stehen jetzt immer sichtbar in der Kopfzeile (shell.component.ts): „Auslastung X % · N Fzg · alle verortet / N ohne Standort · frei ‹Leistung›". Rein aus den Live-Insights abgeleitet (svc.insights().auslastungsQuote [Engpass = engere der Gruppen Mitarbeiter/Buchten, 0..1→%], .kapazitaet [erste machbare Leistung], aktiveAuftraege().length, ohneStandortCount()) — kein neuer State. Fehlende Ortung erscheint rot (Warnung; behält die nicht-rein-farbliche Trennung über das Label „ohne Standort"). Strip ab lg-Breite (auf schmalen Terminals ausgeblendet, kein Umbruch). Entscheidung: die always-on True-North-Antwort in die Shell gezogen (direkter True-North-Treffer, aus vorhandenen Signalen); die strukturelle Rail→62px-Top-Tab-Bar-Umstellung + monochrome Ort-Chips bleiben ein eigener, größerer Schnitt — die gruppierte Rail liefert die 4-Orte-IA bereits Modernist-gestylt, ein Big-Bang-Shell-Rewrite wäre unnötig riskant. Reiner Client-View (nur shell.component.ts); keine Server-Verhaltens-/DTO-/Schema-/Migrations-Änderung — die einzige Server-Datei ist version.ts (reine Versions-Metadaten APP_VERSION). Verifiziert: No-Hex (nur --tk-*) + tsc -p tsconfig.app.json + ng build prod grün + Live-Screenshot (Header „… · 0 Fzg · alle verortet · …"). Doku: ops/OP-REDESIGN-1.md (Phase 2b ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #685) — Redesign „Flusslinie/Modernist" Phase 3a: Fluss · „Entscheiden"-Spalte (APP_VERSION 0.117.0 → 0.118.0, MINOR — neues Feature/Screen). Die konzeptionelle Mitte des Redesigns ist gebaut: „System entscheidet, Mensch bestätigt". Neue geteilte EntscheidenComponent (client/src/app/leitstand/entscheiden.component.ts) als rechte Spalte (360px, xl+) auf dem Fluss-Screen (orders). Sie sammelt ausschließlich Live-Signale (svc.klaerfaelle · konflikte · ohneStandort · vorschlaege, keine Fixtures) zu Vorschlagskarten: 3px-Topline nach Ton (danger=--tk-red für Klärfall/Notfall/Termin, warn=color-mix(--tk-red 45%) für Ortung, idee=--tk-line für Optimierer-Vorschlag), Typ-Label VERSAL, Titel/Body, optionaler „Vorschlag"-Block (Tinte-Kante), Buttons „✓ So machen" (primär --tk-brand) / „Später", Leer-Zustand „Alles im Takt.". Aktions-Semantik (ehrlich): „So machen" wendet echte Mutationen direkt an, wo sie existieren (vorschlagVorziehen bei Vorschlag-Typ „vorziehen"), sonst springt es in die zuständige Ansicht, wo die Mutation lebt (Klärung /conflicts?tab=klaerfaelle · Konflikt/Ortung /conflicts · Idee /recommendations); „Später" blendet die Karte je Sitzung aus (kommt bei neuer Ableitung wieder — nichts geht verloren). Entscheidung: die „Entscheiden"-Ablage zuerst gebaut (größter True-North-/Konzept-Hebel, aus vorhandenen Signalen ableitbar, kein Server-Change) — Linie/Karte-Toggle, Auswahl-Panel, 620px-Auftrag-Drawer und Quality-Check-Modal bewusst als Phase 3b+. Reiner Client, kein Server/DTO/Schema/Migration. Verifiziert: No-Hex-Gate (nur --tk-*/color-mix) + tsc -p tsconfig.app.json + ng build prod (16 s) grün + Live-Screenshot (Fluss-Linie 5 Stationen links + „ENTSCHEIDEN"-Spalte rechts, Leer-Zustand „Alles im Takt."). Doku (goldene Regel): design/COMPONENTS.md (Entscheiden-Pattern), design/WORKSPACES.md (§4 Fluss-Hinweis), ops/OP-REDESIGN-1.md (Phase 3a ✅), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #684) — Redesign „Flusslinie/Modernist" Phase 2: Informationsarchitektur auf 4 „Orte" (APP_VERSION 0.116.0 → 0.117.0, MINOR — IA-Umbau). Die Navigation ist von den früheren „Kern-Loop/Weitere"-Clustern auf die 4 „Orte" Lage · Fluss · Takt · Team + Verwaltung (admin-gegated) + Werkstatt-Terminal umgestellt (shell.component.ts navGroups()). Zuordnung (nichts verwaist): Lage = Hof-Radar · Annahme · Belegung · Tafel; Fluss = Fluss&Risiko · Konflikte&Klärfälle · Vorschläge · Quality-Check; Takt = Planung/Gantt; Team = Mitarbeiter · Prozesse; Verwaltung = Administration · Kosten; Werkstatt-Terminal = Meine Arbeit. Alias-Routen /lage→overview, /fluss→orders, /takt→planning, /team→staff, /verwaltung→administration, /terminal→meine-arbeit; alle bestehenden Workspace-Routen + Deep-Links bleiben intakt (die Views selbst sind unverändert). True-North-Badges (Konflikte/Klärfälle/QM/Vorschläge-Counts) erhalten. Entscheidung: additive IA-Umstellung ohne Screen-Umbau — die Rail-Struktur/Rendering bleibt, nur Gruppierung/Labels + Routen ändern sich (kleinstmögliche, rückwärtskompatible Änderung; Einfachheit). Bewusst offen (Phase 2b/3): die Rail → 62px-Top-Tab-Bar-Optik, monochrome Ort-Chips statt Rainbow---tk-ws-*, und die zusammengeführten Ort-Screens (Fluss „Entscheiden"-Spalte, Ink-Gantt, Auftrag-Drawer, Annahme-/Quality-Overlays). Verifiziert: tsc -p tsconfig.app.json + ng build prod grün + Live-Screenshot (Header „Lage · Hof-Radar", Rail-Gruppen = Lage/Fluss/Takt/Team/Werkstatt-Terminal). Reiner Client (Shell-Nav + Routen), kein Server/DTO/Schema. Doku: ops/OP-REDESIGN-1.md (Phase 2 Nav/IA ✅), design/CLAUDE.md, CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #683) — Redesign „Flusslinie/Modernist" Phase 1: Token-Layer (APP_VERSION 0.115.0 → 0.116.0, MINOR — neue Design-Sprache). Der --tk-*-Token-Layer ist auf Modernist umgestellt und LIGHT-first: design/tokens/tokens.json trägt jetzt den Hell-Wert als Basis-$value (→ :root, Default), den Dunkel-Wert unter $extensions.taktano.dark → generiert nach :root[data-theme="dark"] (+ prefers-color-scheme:dark für „system"). PO-Entscheidung 07-23: Dark-Mode mitgeneriert (beide Themes aus einer Quelle, OP-R9-9 gewahrt — nur die Basis-Achse invertiert von dark-first zu light-first). Modernist-Identität: Marke = Rot #ec3013 (--tk-brand/--tk-red; Cyan ist nicht mehr Marke), Hintergrund #f3f2f2 / Text #201e1d, alle --tk-radius-* = 0, Font Archivo für UI und Daten (Zahlen/Zeiten via .font-mono + font-variant-numeric: tabular-nums — löst „Mono für Daten" ab), kein Ambient-Glow (--tk-backdrop-glow: none), Glow-Dots aus. Funktionale Status-/Gantt-Hues (blue/green/amber/orange/cyan/violet) bleiben erhalten, aber auf den hellen Warm-Neutral-Grund getunt (die bestehenden Hell-Werte wurden zur Basis, die Dunkel-Werte zur Dark-Override — tuned Paare erhalten). Mechanik: build.mjs invertiert (Light-Basis → :root, Dark-Override → [data-theme="dark"], Extension-Key .light.dark); ThemeService (System-Achse prefers-color-scheme: dark, isDark/isLight neu); index.html (Archivo statt Space Grotesk/JetBrains Mono, theme-color/Favicon #ec3013, Favicon radius 0); styles.css (color-scheme invertiert + .font-mono { tabular-nums }). Warnungen brauchen fortan eine nicht-rein-farbliche Kennzeichnung (Rot nicht mehr warn-exklusiv) — Umsetzung in den Komponenten-Phasen. Verifiziert: npm run tokens:check (98 Tokens, round-trip), No-Hex-Gate, tsc -p tsconfig.app.json, ng build (prod, 655 kB initial) grün + Live-Screenshot bestätigt (Body-BG rgb(243,242,242), Font Archivo, radius 0, rote Uhr/Alerts). Reiner Design-Token-/Theming-Change — kein Server/DTO/Schema, keine Migration. Bewusst offen (Phase 2/3): Workspace-Signaturfarben (bis 4-Orte-IA), Glass/Glow-Komponentenklassen, Assistent-FAB-Cyan, 2px-Divider, Wordmark/Icon-Assets. Doku: ops/OP-REDESIGN-1.md (Phase 1 ✅), design/CLAUDE.md (Vertrag aktualisiert — abgelöste Regeln markiert), design/DESIGN_TOKENS.md (Phase-1-Banner), CHANGELOG, HANDOFF §2, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #681) — Redesign „Flusslinie/Modernist": PO-Entscheidung + Phasen-Roadmap (Phase 0, docs-only) (APP_VERSION 0.114.0 → 0.115.0, MINOR — neue Produktrichtung). Der PO hat entschieden (in Anwendung der 07-23-Konvention aus PR #680): das Claude-Design-Projekt „Taktano Neu v2 – Flusslinie" (Design-System „Modernist") löst das bisherige Design-System und die Marke vollständig ab — bewusst, in Phasen (Tokens → Shell/IA → Screens), jede Phase einzeln grün + mergebar. Konflikte bewusst zugunsten Modernist aufgelöst: Cyan-Marke → Rot #ec3013 als Primär-/Markenfarbe; Dark → Light-Default (#f3f2f2/#201e1d); 12 signaturfarbene Workspaces → 4 „Orte" (Lage · Fluss · Takt · Team) + Verwaltung + Werkstatt-Terminal; Radius-Skala → radius 0; Space Grotesk/JetBrains Mono → Archivo; Glass/Glow → flache 2px-Linien. Golden-Rule-Ausnahme (bewusst, begründet): „Rot nur für Warnungen" bleibt drkv-Default und gilt in den Schwester-Repos (MED-/SERA-) unverändert; Taktano ist die dokumentierte Ausnahme (Rot = Primär) → Warnungen brauchen fortan eine nicht rein-farbliche Kennzeichnung. Phase 0 (dieser PR, docs-only, kein Code/Schema): Entscheidung + Roadmap als ops/OP-REDESIGN-1.md (OP-REDESIGN-1, status: offen); Root-CLAUDE.md § Design-Prinzipien (Taktano-lokale Rot-Ausnahme); design/CLAUDE.md (Umbau-Banner + neuer Brand-/Kontrakt-Kopf, bisherige Regeln „gültig bis Phase X ersetzt"). Kein Screen-Umbau, keine visuelle Regression. Nächster Schritt: Phase 1 = Token-Layer (Modernist) als eigener PR. Doku: ops/OP-REDESIGN-1.md, docs/betrieb/Offene-Punkte.md (regeneriert), CHANGELOG, HANDOFF, Timesheet.
  • Branch claude/next-steps-8vmq5d (PR #680) — Konvention: neues Design-System aus Claude Design → bei Konflikten fragen (docs-only, kein Code-/Schema-Change, APP_VERSION unverändert). Stehende PO-Vorgabe (07-23) als verbindliche Design-Governance-Regel in design/CLAUDE.md (§Non-negotiable design rules) festgehalten: wird ein neues/aktualisiertes Design-System aus Claude Design übernommen (z. B. ein neuer Design-Component/Prototype), das früheren Entscheidungen widerspricht (Marken-/Farbregeln — Cyan-Signatur, Rot nur für Warnungen —, --tk-*-Tokens, Radius-Skala, Komponenten-Rezepte, Workspace-Signaturfarben oder andere getroffene Design-Entscheidungen), wird der Konflikt nicht still aufgelöst/überschrieben — der konkrete Konflikt wird benannt und der PO entscheidet. Ergänzt die Rückfragen-Regel der Root-CLAUDE.md („nur an echten Weggabelungen fragen") um den Design-System-Fall. Everything-as-Code: Entscheidung landet als .md-Commit (Audit-Trail), nicht nur im Chat.
  • Branch claude/next-steps-8vmq5d (PR #679) — OP-EDIT-1 Abschluss: Leistungen/Teilschritte — Ko-Bearbeiter-Präsenz (Slice A architektonisch N/A) → Rollout KOMPLETT (APP_VERSION 0.113.0 → 0.114.0, MINOR — neues Feature). Der letzte offene OP-EDIT-1-Editor ist bewertet und abgeschlossen. Befund (Architektur): der Prozesse-Editor (processes.component.ts) ist durchgängig sofort-anwendend inline — jede Feld-Änderung (Toggle, Blur-Input, Chip, Prozess-Komposition via setLeistungProzess) feuert unmittelbar ein teilschritt.update/leistung.update mit Ein-Feld-Patch; es gibt kein „Bearbeiten→Speichern"-Formular und kein baseRev. Damit hat die optimistische Nebenläufigkeit (Slice A) hier nichts zu bewachen: kein Fenster, in dem ein veraltetes Formular einen Änderungs-Stapel still überschreiben könnte — jede Mutation ist atomar und wird sofort an alle gebroadcastet (last-write-wins gilt nur pro Ein-Feld-Klick, was bei Sofort-Anwendung gewollt ist); rev/baseRev je Feld wäre faktisch wirkungslos (der Client hat nach jedem Broadcast stets die frische Version). Force-Fit bewusst abgelehnt (Leitprinzip Einfachheit — keine Komplexität ohne True-North-Nutzen). Gebaut — Slice B adaptiert (echter Nutzen): solange jemand im Prozesse-Editor ist (editEnter('prozesse','config') beim Betreten via Constructor, editLeave via DestroyRef.onDestroy — generische, bereich-agnostische Präsenz-Infra, kein Server-Change), sehen andere ein Ko-Bearbeiter-Banner oben im Workspace („wird gerade auch bearbeitet von … — Änderungen wirken sofort für alle, bitte abstimmen"). Das adressiert das reale Risiko dieser geteilten, taktungs-harten Live-Konfig (zwei Admins stampfen sich sonst feldweise unbemerkt). Präsenz admin-gegated. Reiner Client-Change (Prozesse-Component) — kein Server/DTO/Schema, keine Migration. Entscheidung: Slice A dokumentiert N/A statt force-gefittet; Auslöser für späteres Slice A hier = eine etwaige Umstellung des Prozesse-Editors auf einen formular-basierten „Anzeigen→Bearbeiten→Speichern"-Flow. Damit ist der OP-EDIT-1-Rollout über ALLE Stammdaten-Editoren abgeschlossen (Arbeitsplatz-Referenz · Schicht · Mitarbeiter · Taxonomie mit Slice A+B; Leistungen/Teilschritte mit Slice B, Slice A N/A) — ops/OP-EDIT-1.md status erledigt. tsc (Server + Client) + No-Hex + No-Console grün (ng build in CI). Verifikations-Grenze: UI/Präsenz durch Typecheck belegt; ein Live-Zwei-Fenster-Banner bräuchte ein laufendes DO. Doku: ops/OP-EDIT-1.md (Rollout KOMPLETT ✅, status erledigt), Lastenheft §11-Anker, docs/betrieb/Offene-Punkte.md (regeneriert), CHANGELOG, HANDOFF §2/Footer, Timesheet. True North: die geteilte Prozess-Konfig wird koordiniert bearbeitet statt still gegenseitig überschrieben.
  • Branch claude/next-steps-8vmq5d (PR #678) — OP-EDIT-1 Rollout: Taxonomie-Editor bekommt optimistische Nebenläufigkeit + Präsenz-Warnung (APP_VERSION 0.112.0 → 0.113.0, MINOR — Feature-Rollout). Das OP-EDIT-1-Muster ist jetzt auch auf den inline Taxonomie-Editor (administration.component.ts, „Umbenennen") ausgerollt. Slice A (optimistische Nebenläufigkeit): TaxonomyValue trägt einen monotonen, nur serverseitig erhöhten rev; der Client schickt beim Umbenennen die Basis-Version (baseRev) mit; taxonomie.update prüft sie via revVeraltet (bestehender Kern server/src/operativ/edit-parallel.ts, test:edit) → veraltete Basis wird abgelehnt (edit.result {ok:false}), Erfolg quittiert {ok:true}. Slice B (Edit-Präsenz): über die bereich-agnostische Infra editEnter('taxonomie', id)/editLeave (kein Server-Change): -Live-Badge in der Liste am gerade umbenannten Wert. Inline-Konflikt-UX (angepasst an den Nicht-Modal-Editor): anders als bei den Formular-Editoren (Arbeitsplatz/Schicht/Mitarbeiter) schließt der Inline-Edit bei Ablehnung und ein Banner oben in der Taxonomien-Karte meldet den Konflikt — die Liste zeigt via Broadcast bereits den Gewinner-Stand, erneutes „Umbenennen" holt die frische rev. Entscheidungen: (a) der Aktiv-Quick-Toggle bleibt bewusst ohne baseRev (Ein-Feld-Aktion, kein Formular für Konflikt-UX — analog schichtToggle); (b) alle Schließ-Pfade (OK-Erfolg/Abbrechen/Konflikt) auf eine schliesseTaxEdit()-Methode zentralisiert, die die Präsenz zuverlässig räumt; (c) rev optionalkeine Migration (fehlend = 0, rückwärtskompatibel). Damit ist der OP-EDIT-1-Rollout auf 4 von 5 Editor-Gruppen (Arbeitsplatz-Referenz · Schicht · Mitarbeiter · Taxonomien); offen bleibt nur noch Leistungen/Teilschritte. tsc (Server + Client) + test:edit/test:do-migrations + No-Hex + No-Console + Persistenz-Gate grün. Verifikations-Grenze: rev-Kern per test:edit belegt und der taxonomie.update-Handler spiegelt den verifizierten schicht.update/employee.update-Handler 1:1; ein Live-Zwei-Fenster-Konflikt bräuchte ein laufendes DO. Doku: ops/OP-EDIT-1.md (Taxonomie-Rollout ✅), Lastenheft §11-Anker, CHANGELOG, HANDOFF §2/Footer, Timesheet. CI-Hinweis: läuft jetzt auf GitHub-gehosteten Runnern (CI_RUNNER=ubuntu-latest, gesetzt nach dem self-hosted-Runner-Ausfall bei #677). True North: auch die Taxonomie-Pflege wird konfliktsicher — parallele Umbenennungen überschreiben nicht mehr still.

2026-07-22

  • Branch claude/next-steps-8vmq5d (PR #677) — OP-EDIT-1 Rollout: Mitarbeiter-Editor bekommt optimistische Nebenläufigkeit + Präsenz-Warnung (APP_VERSION 0.111.0 → 0.112.0, MINOR — Feature-Rollout). Das OP-EDIT-1-Querschnittsmuster gegen stilles last-write-wins-Überschreiben ist jetzt auch auf den Mitarbeiter-Editor (staff.component.ts, Bearbeiten-Dialog) ausgerollt. Slice A (optimistische Nebenläufigkeit): Mitarbeiter trägt einen monotonen, nur serverseitig erhöhten rev; der Client schickt beim Speichern die Basis-Version (baseRev) mit; employee.update prüft sie via revVeraltet (bestehender Kern server/src/operativ/edit-parallel.ts, test:edit) → veraltete Basis wird abgelehnt (nicht angewendet, nicht gebroadcastet), der Speichernde bekommt edit.result {ok:false} → Dialog bleibt offen mit Konflikt-Hinweis; Erfolg quittiert {ok:true} → Dialog schließt (kein Race durch fremde Broadcasts). Slice B (Edit-Präsenz): über die schon vorhandene, bereich-agnostische Infra editEnter('mitarbeiter', id)/editLeave (kein Server-Change — die editPraesenz-Map ist generisch): Warn-Banner „wird gerade auch bearbeitet von …" im Dialog (blockt nicht) + -Live-Badge in der Liste. Slice C entfällt: der Mitarbeiter-Editor ist bereits view-first (Karte read-only + expliziter „✎ Bearbeiten"-Knopf öffnet erst den Dialog). Entscheidungen: (a) der rev guardt gezielt das Stammdaten-Speichern (Name/Abteilung/Funktion/Verfügbarkeit/Vertrauensstufe) — die additiven Sub-Aktionen im selben Dialog (Skill zuweisen, Ausbildungsziel, Abwesenheit) bleiben eigenständige Messages und heben rev nicht an (Granularität „je Stammdaten-Save", kein falscher Konflikt beim parallelen Skill-Zuweisen); Konsistenz-Fix (CodeRabbit): die Live-Pfade, die ein Editor-Vertragsfeld ändern (verfuegbarkeit/status via employee.setVerfuegbarkeit + employee.startRecommendation), heben rev ebenfalls an, damit ein veralteter Editor-Save eine zwischenzeitliche Live-Statusänderung nicht still zurücksetzt; (b) alle drei Dialog-Schließpfade (Backdrop/×/Schließen) auf eine schliesseBearbeiten()-Methode zentralisiert, die die eigene Präsenz zuverlässig räumt; (c) rev optionalkeine Migration (fehlend = 0, rückwärtskompatibel — ohne baseRev bleibt es beim alten Verhalten). Der Rollout auf die übrigen Editoren (Taxonomien · Leistungen/Teilschritte) bleibt als mechanische Folge offen. tsc (Server + Client) + test:edit/test:do-migrations + No-Hex + No-Console + Persistenz-Gate grün (ng build in CI — lokal Node-Version-Limit). Verifikations-Grenze: rev-Kern per test:edit belegt und der employee.update-Handler spiegelt den verifizierten schicht.update/arbeitsplatz.update-Handler 1:1; ein Live-Zwei-Fenster-Konflikt bräuchte ein laufendes DO. Doku: ops/OP-EDIT-1.md (Mitarbeiter-Rollout ✅), Lastenheft §11-Anker, CHANGELOG, HANDOFF §2/Footer, Timesheet. True North: Stammdaten-Pflege wird auch beim Mitarbeiter-Editor konfliktsicher — parallele Bearbeitung überschreibt nicht mehr still.

2026-07-21

  • Branch claude/next-steps-8vmq5d (PR #676) — OP-EDIT-1 Rollout: Schicht-Editor bekommt optimistische Nebenläufigkeit + Präsenz-Warnung (APP_VERSION 0.110.0 → 0.111.0, MINOR — Feature-Rollout). Das in OP-EDIT-1 an der Referenz (Arbeitsplatz-/Bucht-Editor) gebaute Querschnitts-Muster gegen stilles last-write-wins-Überschreiben ist jetzt auch auf den Schicht-Editor (administration.component.ts) ausgerollt. Slice A (optimistische Nebenläufigkeit): SchichtKatalog trägt einen monotonen, nur serverseitig erhöhten rev; der Client schickt beim Speichern die Basis-Version (baseRev) mit; schicht.update prüft sie via revVeraltet (bestehender Kern server/src/operativ/edit-parallel.ts, test:edit) → veraltete Basis wird abgelehnt (nicht angewendet, nicht gebroadcastet), der Speichernde bekommt eine gezielte Quittung edit.result {ok:false} → Formular bleibt offen mit Konflikt-Hinweis + „Neu laden"; Erfolg quittiert {ok:true} → Formular schließt (kein Race durch fremde Broadcasts). Slice B (Edit-Präsenz): über die schon vorhandene, bereich-agnostische Infra editEnter('schicht', id)/editLeave (kein Server-Change — die editPraesenz-Map ist generisch): beim Betreten des Bearbeiten-Modus zeigt ein Warn-Banner die fremden Bearbeiter („wird gerade auch bearbeitet von …" — blockt nicht), ein -Live-Badge in der Liste markiert aktive Bearbeitung. Slice C entfällt: der Schicht-Editor ist bereits view-first (Liste read-only + expliziter „Bearbeiten"-Knopf → kein versehentliches Editieren beim Ansehen). Entscheidungen: (a) rev optionalkeine Migration (fehlend = 0, rückwärtskompatibel — ohne baseRev bleibt es beim alten last-write-wins); (b) den quick-Toggle „aktiv" in der Liste bewusst ohne baseRev gelassen (Ein-Feld-Aktion, kein Formular für Konflikt-UX); (c) den bestehenden Quittungs-Effekt um einen schicht-Zweig erweitert statt zu duplizieren. Der Rollout auf die übrigen Editoren (Taxonomien · Mitarbeiter · Leistungen/Teilschritte) bleibt als mechanische Folge offen. tsc + test:edit/test:do-migrations/test:bereitschaft/test:ausfall/test:schicht-reserve + ng build + No-Hex + No-Console + Persistenz-Gate grün. Verifikations-Grenze: rev-Kern per test:edit belegt; ein Live-Zwei-Fenster-Konflikt bräuchte ein laufendes DO. Doku: ops/OP-EDIT-1.md (Schicht-Rollout ✅), Lastenheft §11-Anker, CHANGELOG, HANDOFF §2/Footer, Timesheet. True North: Stammdaten-Pflege wird auch beim Schicht-Editor konfliktsicher — parallele Bearbeitung überschreibt nicht mehr still.

2026-07-20

  • Branch claude/next-steps-8vmq5d (PR #675) — OP-SCHICHT-1 Slice 4: Schicht-Ende-Aufräum-Checkliste (APP_VERSION 0.109.0 → 0.110.0, MINOR — neues Feature). Eine konsolidierte To-do-Liste im Überblick („🧹 Schicht-Ende-Aufräumen"), die vor Feierabend alle offenen Nebenaufgaben an einer Stelle zeigt — statt sie über mehrere Karten/Workspaces verteilt zu lassen. Rein aus dem Live-State abgeleitet (D-2) und — wie schon Slice 2 — als reine Client-Komposition gebaut (kein Server-/DTO-Change, nichts gespeichert): die Karte aggregiert drei bereits gebroadcastete Signale — (1) 📍 Fahrzeuge ohne Standort (ohneStandortCount, mit Link in den Konflikte-Workspace), (2) 🌙 hochwertige Fahrzeuge nicht in der Halle (nachtHalle.reste aus Slice 2/3), (3) 🅿️ offene Umpark-Aufträge (umparkAuftraege, noch unterwegs). Summenanzeige „⚠ N offen" (amber) bzw. „✓ bereit fürs Schichtende" (grün) bei 0. Bewusst kein „Abhaken"/keine Persistenz — die offene Arbeit ist der Punkt; jede Zeile verschwindet automatisch, sobald die Lücke geschlossen ist (Standort erfasst / Fahrzeug in der Halle / Umparken quittiert), das braucht keinen gespeicherten „erledigt"-Zustand (D-2, keine neue Zustandsfläche). Reihenfolge = Dringlichkeit (Sicherheit/Standort zuerst). Entscheidung (Einfachheit): Konsolidierung über bestehende Signale statt neuer Server-Ableitung — der Nutzen (ein Blick vor Feierabend) entsteht rein aus Komposition. ng build (Overview-Chunk +~0,4 kB, kein Budget-Warning) + No-Hex + No-Console grün. Verifikations-Grenze: UI durch Build belegt; die Live-Zahlen bräuchten ein laufendes DO mit Belegungs-/Umpark-Daten. Damit ist die sichtbare Schicht-Ende-Sicht von OP-SCHICHT-1 komplett (Reserve · Nacht-Halle · Konfig · Checkliste); offen bleibt nur der große Scheduler-Planungsziel-Baustein. Doku: ops/OP-SCHICHT-1.md (Slice 4 ✅), Lastenheft §11-Anker, CHANGELOG, HANDOFF §2/Footer, Timesheet. True North #2: „Wo stehen die Fahrzeuge?" mündet vor Feierabend in eine klare, abarbeitbare Liste.
  • Branch claude/next-steps-8vmq5d (PR #674) — OP-SCHICHT-1 Slice 3: Nacht-Halle-Konfig — Schwelle & Nacht-Hallen-Buchten admin-editierbar (APP_VERSION 0.108.0 → 0.109.0, MINOR — neues Feature). Schließt die in Slice 2 bewusst offen gelassene Konfig-Lücke: der Admin bestimmt jetzt, ab welcher Güteklasse ein Fahrzeug „hochwertig" ist und welche Buchten die Nacht-Halle bilden. Modell: neues optionales persistiertes Feld nachtHalleKonfig { abGueteklasse: 1–3; buchtIds: string[] } (PersistedState, fehlend ⇒ Default Schwelle 2 + leere buchtIds → keine Migration, schemaVersion unverändert; onStart reicht es durch). Reine, testbare Kern-Helfer (insights.ts): nachtHalleKonfigEffektiv (Klemmung Güteklasse 1…3, Default 2) + istNachtHalleSlotbuchtIds-Allowlist (nur die gewählten Buchten zählen) ODER, wenn leer, Fallback auf den Indoor-Typ (INDOOR_TYP_RE, wie Slice 2). So bleibt das Default-Verhalten (unkonfiguriert = Indoor-Buchten) erhalten und wird gezielt überschreibbar. DO: wendet die Konfig in der Insight-Projektion an (istNachtHalleSlot je Fahrzeug-Bucht + abGueteklasse als Schwelle), emittiert die effektive Konfig im State-DTO; Admin-Message nachtHalleKonfig.update (istKostenAdmin-gated, validiert/klemmt die Schwelle, filtert buchtIds auf existierende Bucht-IDs + dedupliziert). UI: neue Karte „🌙 Nacht-Halle (Schicht-Ende)" im Administration-Workspace — Güteklasse-Select + Bucht-Chips (leer = „alle Indoor-Buchten automatisch"), sofort-anwendend (wie der Aktiv-Toggle). Die Überblick-Karte übernimmt die konfigurierte Schwelle automatisch (nachtHalle.schwelle). Entscheidungen (Einfachheit): (a) ein zentrales Konfig-Objekt statt Konfig über alle Buchten verstreut; (b) buchtIds leer = Fallback, damit Bestands-Setups ohne Konfig unverändert laufen; (c) sofort-anwendend ohne Speichern-Button (kleiner Scope, wie schichtToggle/autoOptAktiv). Selbsttest in test:insights erweitert (Schwelle-Klemmung 0/9→1/3, Allowlist vs. Indoor-Fallback). tsc + test:insights/test:do-migrations/test:assistant-tools/operativ + ng build + No-Hex + No-Console + Persistenz-Gate grün. Verifikations-Grenze: Logik per Selbsttest belegt; ein Live-Klick (Editor speichert → Überblick-Karte reagiert) bräuchte laufendes DO. Doku: ops/OP-SCHICHT-1.md (Slice 3 ✅), Lastenheft §11-Anker, docs/betrieb/Tests.md, CHANGELOG, HANDOFF §2/Footer, Timesheet. True North #2: die Nacht-Halle-Sicht ist jetzt betriebs-passend konfigurierbar statt fix verdrahtet.
  • Branch claude/next-steps-8vmq5d (PR #673) — OP-SCHICHT-1 Slice 2: Nacht-Halle-Check — hochwertige Fahrzeuge (noch) nicht in der Halle (APP_VERSION 0.107.0 → 0.108.0, MINOR — neues Feature). Ein abgeleiteter Schicht-Ende-Check beantwortet: welche hochwertigen Fahrzeuge stehen zum Schichtende noch draußen und sollten in die Halle? Reine Insight-Funktion nachtHalleReste (server/src/insights/insights.ts, D-2 — nichts gespeichert): aktive Aufträge mit Güteklasse ≥ Schwelle (Default 2 = Premium/Super-Premium; Standard = 1 darf draußen bleiben), deren Standort keine Halle/Indoor-Bucht ist — oder unbekannt — werden gelistet, dringlichste (höchste Güteklasse) zuerst, je mit Grund (nicht_in_halle / standort_unbekannt). „Halle" ohne neues Modell: der Leitstand markiert Indoor-Buchten über das schon bestehende Bucht-Typ-Label (INDOOR_TYP_RE, dieselbe Erkennung wie die Cool-down-Indoor-Pflicht) und löst den Indoor-Status pro Auftrag über die tatsächliche Bucht (Zugehörigkeit, nicht Namens-Join → robust gegen doppelte Bucht-Namen, CodeRabbit) auf → InsightAuftrag.standortIndoor; die Insight bekommt zusätzlich InsightAuftrag.gueteklasse (beide optional, rückwärtskompatibel). UI: neue Überblick-Karte „🌙 Nacht-Halle" neben der Standorte-Karte (True-North-Frage 2) — grün „✓ alle in der Halle" bzw. amber „⚠ N nicht in der Halle" + Liste (Auftragsnr · Güteklasse · Standort/„unbekannt"); Amber (Hinweis), nicht Rot. Entscheidungen (Einfachheit/Ehrlichkeit): (a) rein abgeleitet über bestehende Signale (Güteklasse + Indoor-Typ-Regex) — kein neues persistiertes Modell, keine Migration; (b) Schwelle-Default 2 als Parameter der reinen Funktion; (c) die Konfigurierbarkeit (Schwelle und dedizierte Nacht-Hallen-Buchten über die Typ-Regex hinaus) bleibt bewusst Folge-Slice — sie braucht einen Konfig-Speicher, der hier nicht mitgebaut wird (ehrlich als offen ausgewiesen statt halb angefangen). Selbsttest in test:insights erweitert (Schwelle 2 vs. 3, drinnen/draußen/Standard/unbekannt/abgeschlossen, Entwarnung). tsc + test:insights/test:assistant-tools/test:matching + ng build + No-Hex + No-Console + Persistenz-Gate grün. Verifikations-Grenze: Logik per Selbsttest belegt; ein Live-Blick auf die Karte bräuchte laufendes DO mit Belegung. Doku: ops/OP-SCHICHT-1.md (Slice 2 ✅ + Folge-Slices präzisiert), Lastenheft §11-Anker, docs/betrieb/Tests.md, CHANGELOG, HANDOFF §2/Footer, Timesheet. True North #2: „Wo stehen die Fahrzeuge?" um die Sicherheits-/Nacht-Sicht erweitert — die teuren Autos sind auf einen Blick verortet, bevor die Schicht endet.
  • Branch claude/next-steps-8vmq5d (PR #672) — OP-SCHICHT-1 Slice 1: Aufräum-Reserve am Schichtende (Default 30 Min, admin-konfigurierbar) + Gantt-Anzeige (APP_VERSION 0.106.0 → 0.107.0, MINOR — neues Feature). Jede Schicht reserviert die letzten X Minuten fürs Schicht-Ende-Aufräumen (Einparken/Nacht-Zustand) — der Scheduler plant dort keine reguläre Arbeit mehr. Neues Feld aufraeumReserveMin auf SchichtKatalog (Default 30, admin-editierbar pro Schicht, 0…120), umgesetzt über den ganzen heterogenen Stack. Scheduler (der Clou): der Abzug sitzt an genau einer Stelle — mitarbeiterAvailability (server/src/scheduler/availability.ts) verkürzt das planbare Fenster am spätesten Slot (= Schichtende; Pausen-Slots bleiben voll planbar). Weil der CP-SAT-Solver die von dort vorab expandierten avail-Intervalle konsumiert (solver/problem.tssolver-service/model.py), wirkt der Abzug paritätisch auf TS-Fallback-Scheduler UND Python-Solver — eine TS-only-Änderung, keine Solver-Anpassung nötig. Gantt: die Reserve erscheint als eigenes grünes Band art:'aufraeumen' („Aufräumen", scheduler/ausfall.ts + AUSFALL_COLOR/AUSFALL_LABEL) am Schichtende — der Nutzer sieht die reservierte Zeit. Schicht-Editor: Minuten-Eingabe (type=number, 0…120) im Administration-Workspace, Anzeige „🧹 X min" je Schicht. Server-Plumbing: SchichtPatch + schicht.create/update-Handler mit Validierung/Klemmung (klemmeReserve, 0…120, gerundet), DTO-Builder emittiert den effektiven Wert (inkl. Default 30). Entscheidungen (Einfachheit): (a) Abzug nur am spätesten Slot (Schichtende), nicht an jedem Slot — sonst würde ein Vormittags-Slot vor der Mittagspause fälschlich gekürzt; (b) Reserve uniform auf alle Schicht-Arten inkl. Überlauf/Bereitschaft (einfachste konsistente Regel); (c) Default 30 via ?? 30 greift auch für Bestand ohne Feld → keine Migration nötig (optionales Feld, schemaVersion unverändert); explizite 0 wird respektiert (?? nicht ||). Blast-Radius bewusst geprüft: der Default 30 verschiebt Makespans in Test-Fixtures — die betroffenen test:ausfall/test:bereitschaft-Fixtures wurden explizit auf aufraeumReserveMin: 0 gepinnt (isolieren ihre Ausfall-/Bereitschafts-Assertions), die volle Server-Test-Suite ist grün. Neuer Selbsttest test:schicht-reserve (14 Prüfungen: Default/Klemmung, Verkürzung am spätesten Slot, Pausen-Slot bleibt voll, Gantt-Band) als CI-Gate. tsc + alle Server-Tests + ng build + No-Hex + No-Console + Persistenz-Gate grün. Verifikations-Grenze: Scheduler-Abzug + Band per Selbsttest belegt; ein Live-Gantt-Klick bräuchte laufendes DO. Doku: ops/OP-SCHICHT-1.md (Slice 1 ✅), Lastenheft §11-Anker, docs/betrieb/Tests.md, .github/workflows/ci.yml, CHANGELOG, HANDOFF §2/Footer, Timesheet. True North #1/#3: definierter Nacht-Zustand + ehrliche Kapazität — die Schicht-Endzeit ist nicht mehr „bis zur letzten Minute verplant", das Aufräumen hat seinen festen, sichtbaren Platz.

2026-07-19

  • Branch claude/next-steps-8vmq5d (PR #671) — OP-UMPARK-3 Slice 2: Umpark-Empfehlung nach Skill-Eignung gewichten (APP_VERSION 0.105.0 → 0.106.0, MINOR — Optimierung eines bestehenden Features). Slice 1 empfahl Zielbuchten nur nach Bucht-Typ + freier Kapazität; jetzt rankt die Empfehlung zuerst nach Skill-Eignung — Buchten, die den vom aktuellen/nächsten Schritt geforderten Skill anbieten (Arbeitsplatz.skillIds ⊇ {Skill}), stehen oben, mit „🎯 "-Badge; die Überschrift nennt „· Skill ". Warum entscheidend: laut Scheduler (§6.1) kann ein Schritt nur in einer Bucht laufen, die seinen Skill anbietet — eine typ-gleiche Bucht ohne den Skill ist gar kein gültiges Ziel, Slice 1 konnte also eine unbrauchbare Bucht empfehlen. Die Verfeinerung macht die Empfehlung fachlich korrekt, nicht nur typ-plausibel. Rein Client (repark-modal.component.ts): der geforderte Skill kommt aus dem teilschritteKatalog (Instanz → teilschrittIdbenoetigteSkillId + aufgelöster Name), die Bucht-Skills aus arbeitsplaetze().skillIdsbeide schon im State, kein Server-/DTO-Change. Zwei-Stufen-Sort (Skill zuerst, dann freieste Kapazität) → nie leere Liste, wenn Skill-Tags fehlen (Fallback = Typ-Empfehlung wie Slice 1); fordert der Schritt keinen Skill (z. B. Logistik), bleibt es bei der reinen Typ-Empfehlung. Entscheidungen (Einfachheit/Ehrlichkeit): (a) von den drei OP-Faktoren (Skill · Ausstattung · Nähe) nur Skill umgesetzt — der einzige mit real matchbaren Daten und echter Scheduler-Relevanz; (b) Ausstattung bewusst nicht gewichtet — ein Teilschritt deklariert keine geforderte Ausstattung (nur Typ + Skill), es gäbe nichts zu matchen (bräuchte Datenmodell-Feld); (c) Nähe/G-4 bewusst nicht berechnet — Buchten tragen keine Standort-/Zonen-Info, eine erfundene Distanz wäre unehrlich (bräuchte Layout-/Zonen-Modell); beide als Folge-OP dokumentiert. ng build (occupancy-Chunk unverändert, kein Budget-Warning) + No-Hex grün. Verifikations-Grenze: UI durch Build belegt; ein Klick-Durchlauf (skill-passende Bucht steht oben mit 🎯) bräuchte Live-DO. Doku: ops/OP-UMPARK-3.md (Slice 2 ✅ + Offen-Punkte präzisiert), Lastenheft §11-Anker, CHANGELOG, HANDOFF §2/Footer, Timesheet. True North #1/#3: der fachlich richtige Zielplatz zuerst → bessere Bucht-Auslastung, kein Fehl-Rangieren auf eine Bucht, in der der nächste Schritt gar nicht laufen darf.
  • Branch claude/next-steps-8vmq5d (PR #670) — OP-STEP-1 Slice 4: Server-Backstop gegen out-of-order-Schritt-Abschluss (APP_VERSION 0.104.1 → 0.105.0, MINOR — neue, rückwärtskompatible Absicherung). Das Sequenz-Gating aus Slice 1 (nur der aktuelle Schritt der Reihenfolge ist abschließbar) galt bisher nur im Client; jetzt lehnt der Server-Handler teilschritt.aktion 'erledigen' einen out-of-order-Abschluss ebenfalls ab (Defense-in-Depth — ein manipulierter/veralteter Client kann die Reihenfolge nicht mehr umgehen). Umsetzung: zwei reine, testbare Prädikate in server/src/operativ/auftrag.tsistOffenerSchritt (geplant/in_arbeit/pausiert) und istAktuellerSchritt(auftrag, instanzId) (spiegelt die Client-Frontier-Logik: laufende Schritte sind immer aktuell, ein geplanter nur, wenn er die früheste Startzeit unter den offenen Schritten teilt → echte Parallel-Schritte bleiben beide abschließbar, strikt spätere sind gesperrt). Der Gate greift vor dem Doku-/Foto-Gate (Sequenz zuerst, wie PO-Entscheid 07-19) und verwirft still (der Client bietet gesperrte Schritte gar nicht an). Entscheidungen: (a) nur erledigen gaten, nicht starten — Parallelität/Vorziehen bleiben erlaubt (Einfachheit, kein Über-Sperren); (b) Frontier per Startzeit-Heuristik statt expliziter G-1-Abhängigkeit im DTO — einfachste tragfähige Näherung, deckungsgleich mit dem Client; die explizite Abhängigkeit ist eine bedingte Folge-Verfeinerung. Rein Server, keine DTO-/Schema-Änderung (nutzt status/start der Instanz). Selbsttest test:step-gate (20 Prüfungen: Front-Sequenz, erledigte Vorstufe rückt vor, laufend/pausiert immer aktuell, echte Parallelität, Robustheit unbekannte Id) → als CI-Gate im Server-Job. tsc --noEmit grün. OP-STEP-1 damit erledigt (alle 4 Slices); offen nur die bedingte „feinere Parallelität". Doku: ops/OP-STEP-1.md (Slice 4 ✅, Status erledigt), Lastenheft §11-Anker, docs/betrieb/Tests.md, .github/workflows/ci.yml, CHANGELOG, HANDOFF §2/Footer, Timesheet. True North #2: der Bearbeitungsstand bleibt korrekt — Schritte werden nur in echter Reihenfolge abgeschlossen, auch wenn ein Client danebengreift.
  • Branch claude/next-steps-8vmq5dOP-UMPARK-4 abgeschlossen: „Umparken"-Sichtbarkeit geklärt + Wortlaut vereinheitlicht (APP_VERSION 0.104.0 → 0.104.1, PATCH — Klärungs-OP + kleiner UX-Tweak). Ist-Bestandsaufnahme (Explore) aller 8 Auslöse-Stellen von „Umparken": Belegung/Hofplan (📍 Standort-Zuweisung · Fahrzeug-Chip 📍 · 🅿️ Freiräumen · Drag&Drop), Konflikte (📍 Standort zuweisen · 📍 Umparken bei geparkt_gesperrt/_vor_sperre), Auftrag-Detail-Panel (📍 Umparken), Meine Arbeit (✓ Angekommen). Kern-Erkenntnis: das Grundgerüst ist bereits sauber — ein gemeinsamer ReparkService + ein global gemountetes Repark-Modal; die Verteilung ist kontextrichtig (überall, wo man ein Fahrzeug im Blick hat) und bleibt bewusst. Entscheidungen (PO 07-19, im OP festgeschrieben): (1) zwei sprechende Begriffe — „Standort zuweisen" (Fahrzeug ohne Platz einweisen) vs. „Umparken" (Platz→Platz); der einzige Ausreißer „📍 Standort" (Belegung) ist auf „📍 Standort zuweisen" angeglichen (deckungsgleich mit der Konflikte-Sektion); (2) die zwei Direkt-Pfade (Drag&Drop-Geste + 🅿️ Freiräumen-Ein-Klick) bleiben bewusst als Komfort-Features, die übrigen 6 Trigger laufen einheitlich über das gemeinsame Modal; (3) Sichtbarkeitsregeln = Ist-Referenztabelle im OP (Trigger nur zeigen, wenn im Kontext sinnvoll — nicht „immer"). Umsetzung: reiner Wortlaut-Angleich (occupancy.component.ts) + festgeschriebene Ist-/Soll-Referenz — keine Verhaltens-/Pfad-Änderung. ng build (649,4 kB) + No-Hex + No-Console grün. Doku: ops/OP-UMPARK-4.md (Ist-Tabelle + Entscheidung, Status erledigt), Lastenheft §11-Anker, CHANGELOG, HANDOFF §2/Footer, Timesheet. True North #2: „Umparken" einheitlich benannt + dort, wo der Nutzer es erwartet.
  • Branch claude/next-steps-8vmq5d (PR #668) — OP-UMPARK-3 Slice 1: Umparken empfiehlt passende Buchten nach aktuellem Schritt (APP_VERSION 0.103.0 → 0.104.0, MINOR — neues Feature). Baut auf OP-STEP-1 („aktueller Schritt") auf: das Repark-Modal zeigt oben eine Empfehlungs-Gruppe — die Buchten, die zum aktuellen/nächsten Schritt des umzuparkenden Auftrags passen (Bucht vom geforderten Typ mit freier Kapazität, freieste zuerst), mit Begründung „✅ Empfohlen für „" · braucht ". Statt einer generischen, unsortierten Liste sieht der Nutzer sofort den fachlich richtigen Zielplatz (z. B. Folierbucht für die anstehende Vollfolierung). Der aktuelle Schritt = laufender (in_arbeit/pausiert), sonst der offene mit der frühesten Startzeit (Frontier, analog OP-STEP-1). Rein Client (repark-modal.component.ts: aktuellerSchritt/geforderteTypen/empfohlen): gematcht wird über die bereits vorhandenen Label-Felder — der Teilschritt-DTO liefert benoetigteBuchtTypen als Labels, BelegungSlotDTO.typLabel ebenso → kein Server-/DTO-Change nötig. Die empfohlenen Buchten werden aus der „Weitere Ziele"-Liste ausgeblendet (keine Doppelanzeige). Entscheidungen: (a) nur Buchten empfehlen (Parkplätze sind keine Arbeitsplätze für den nächsten Schritt); (b) keine Auto-Vorwahl — die Empfehlung ist sichtbar, der Nutzer wählt bewusst (Selbsterklärbarkeit, keine Magie); (c) Match per Typ-Label als einfachste tragfähige Näherung — Skill/Ausstattung/Nähe-Gewichtung (G-4) ist Folge-Verfeinerung. Prozess-Pause (Teil B der OP) ist weitgehend vorhanden: Umparken eines laufenden Auftrags auf einen Parkplatz setzt schon modus: 'pausieren' (OP-UMPARK-1), Transit-Puls + „Angekommen"-Quittung existieren. ng build (649,2 kB, kein Budget-Warning) + No-Hex + No-Console grün. Verifikations-Grenze: UI durch Build belegt; ein Klick-Durchlauf (Umparken öffnen → Empfehlung passt zum nächsten Schritt) bräuchte Live-Backend (DO). Doku: ops/OP-UMPARK-3.md (Slice 1 ✅ + Pause-Status), Lastenheft §11-Anker, CHANGELOG, HANDOFF §2/Footer, Timesheet. True North #1/#3: der richtige Platz zur richtigen Zeit — bessere Bucht-Auslastung, weniger Fehl-Rangieren.
  • Branch claude/next-steps-8vmq5dOP-STEP-1 Slice 3: Foto-Vorgaben je Teilschritt als Stammdaten pflegen (APP_VERSION 0.102.0 → 0.103.0, MINOR — neues Feature). Schließt die Lücke aus Slice 2 („nach Vorgabe" hatte oft keine Daten): im Prozesse-Workspace sind jetzt je Teilschritt die Pflicht-Foto-Perspektiven + Mindestanzahl editierbar (Perspektive mit Vorschlagsliste Front/Heck/Seite links/… via <datalist> + freier String G-1, Anzahl ≥1, Hinzufügen/Entfernen), dazu ein Doku-Pflicht-Toggle. Die Vorgaben speisen direkt die Abschluss-Checkliste (Slice 2) und die Foto-Pflicht-Gates im Werker-Flow. Rein Client: der Server nahm den Patch längst an (teilschritt.updatesetzeTeilschrittFelder normalisiert fotoPflicht/dokuPflicht/dokuAspekte — Anzahl≥1, Perspektiven getrimmt/dedupliziert) und emittierte die Werte bereits im Katalog-DTO (buildProzessKatalog/buildTeilschrittKatalog); es fehlten nur die Client-DTO-Felder (ProzessSchrittDTO.{dokuPflicht,fotoPflicht,dokuAspekte}), der erweiterte updateTeilschritt-Patch und der Editor (processes.component.ts: fotoAdd/fotoSetAnzahl/fotoRemove, TeilschrittRow + zuRow erweitert). Entscheidungen: (a) Editor im Prozesse-Workspace (dort leben die Teilschritt-Stammdaten), nicht in der Administration; (b) <datalist>-Vorschläge statt hartem Enum (G-1: freier Perspektiven-String bleibt erlaubt); (c) Server-Normalisierung ist die Wahrheitsquelle (Client sendet roh, fotoAnforderungen säubert) — pro-Zeile eindeutige datalist-ID (kein Duplikat im @for). ng build (646,8 kB, processes-Chunk 27,7→31,5 kB, Initial unverändert) + No-Hex + No-Console grün. Verifikations-Grenze: UI durch Build belegt; ein Klick-Durchlauf (Vorgabe setzen → im Werker-Abschluss erscheint die Perspektive) bräuchte Live-Backend (DO). Damit sind OP-STEP-1 Slices 1–3 (aktueller Schritt · geführter Abschluss · Vorgabe-Pflege) gebaut — OP bleibt „offen" nur für den optionalen Server-Backstop (out-of-order-Ablehnung). Doku: ops/OP-STEP-1.md (Slice 3 ✅), CHANGELOG, HANDOFF §2/Footer, Timesheet. True North #2: die Nachweis-Vorgabe ist jetzt pflegbar statt hartcodiert/leer.
  • Branch claude/next-steps-8vmq5d (PR #666) — OP-STEP-1 Slice 2: geführter Foto-/Doku-Abschluss (sprechende Restliste) (APP_VERSION 0.101.0 → 0.102.0, MINOR — neues Feature). Adressiert den zweiten Teil des PO-Befunds („bei Abschluss müssen Fotos nach Vorgabe ergänzt werden"). Die Foto-Pflicht-Mechanik existierte bereits (t.fotoPflicht/fotoPflichtErfuellt, „Fertig" gesperrt bis erfüllt), war aber optisch schwach: nur ein vages „📷 Pflicht-Fotos fehlen noch". Neu (reiner Client, auftrag-detail-panel.component.ts): der Abschluss-Dialog zeigt eine sprechende RestlisteabschlussReste(t) listet die konkret fehlenden Pflicht-Foto-Perspektiven (📷 ) + die Pflicht-Doku (📝), live aktualisiert beim Tippen/Fotografieren; ist alles da, erscheint grün „✓ Alles erfasst — Schritt kann abgeschlossen werden". Der Pflicht-Foto-Block trägt jetzt die Überschrift „📷 Pflicht-Fotos (Vorgabe)". Leere Vorgabe (weder Pflicht-Foto noch Pflicht-Doku) wird klar benannt („Keine Foto-/Doku-Vorgabe hinterlegt — Abschluss ohne Nachweis; Vorgabe je Leistung/Schritt pflegbar") statt kommentarlos zu fehlen — Übergang zu Slice 3 (Vorgabe-Pflege). Entscheidung: die Restliste spiegelt exakt das bestehende „Fertig"-Disabled-Gate ((dokuPflicht && kein Kommentar) || !fotoPflichtErfuellt) → keine zweite Wahrheitsquelle, nur sprechender gemacht. ng build (646 kB, kein Budget-Warning) + No-Hex + No-Console grün. Verifikations-Grenze: UI-Fluss durch Build belegt; ein Klick-Durchlauf (Foto aufnehmen → Restliste schrumpft → Fertig) bräuchte Live-Backend (DO) mit FOTOS-Binding. Doku: ops/OP-STEP-1.md (Slice 2 ✅), CHANGELOG, HANDOFF §2/Footer, Timesheet. Offen: Slice 3 (Foto-Vorgaben als Stammdaten pflegen), Server-Backstop. True North #2: der Abschluss erzwingt den Nachweis sichtbar statt ihn zu hoffen.
  • Branch claude/next-steps-8vmq5dOP-STEP-1 Slice 1: nur der aktuelle Prozessschritt ist fertigmeldbar (Reihenfolge sichtbar) (APP_VERSION 0.100.0 → 0.101.0, MINOR — neues Feature) + drei neue OPs erfasst. Befund (PO, am Auftrag-Detail-Panel): jeder offene Schritt bot gleichzeitig „✓ Fertig (mit Doku)" — man konnte außer der Reihe abschließen, der aktuelle Stand war unklar. Fix (Slice 1, reiner Client): nur der aktuelle Schritt ist fertigmeldbar und hebt sich ab („▶ jetzt dran"); spätere offene Schritte sind gesperrt mit Hinweis „🔒 kommt später — erst nach ". Der aktuelle Schritt = laufender (in_arbeit/pausiert) oder der offene Schritt mit der frühesten Startzeit (front); da der Scheduler Parallelität in die Startzeiten kodiert, teilen echte Parallel-Schritte die früheste Startzeit und bleiben beide aktionierbar, strikt spätere werden gesperrt (auftrag-detail-panel.component.ts: istAktuellerSchritt/istGesperrterSchritt/aktuellerSchrittName, kannSchrittErledigen verschärft — gated Fertig-Knopf + Foto-/Doku-UI). Entscheidungen: (a) PO-Wahl „hart" (nur aktueller Schritt, nicht nur optisch); (b) Startzeit-Frontier als einfachste tragfähige Näherung — nutzt vorhandene DTO-Felder (status/start), kein Server-/Schema-Change; die exakte G-1-Abhängigkeit (nach_vorherigem/parallel/frei) lebt auf dem ProzessSchritt und ließe sich für exaktes Gating ins Instanz-DTO heben (Folge-Slice); (c) Server-Backstop (out-of-order-Ablehnung) + geführter Foto-/Doku-Abschluss (Slice 2) + Vorgabe-Pflege (Slice 3) bleiben offen. Die Foto-Pflicht-Mechanik existiert bereits (t.fotoPflicht/fotoPflichtErfuellt, „Fertig" gesperrt bis erfüllt) — Slice 2 macht sie prominenter/geführt. ng build (645 kB, kein Budget-Warning) grün. Verifikations-Grenze: UI-Fluss durch Build belegt; ein Klick-Durchlauf bräuchte ein Live-Backend (DO). Neue OPs erfasst (Doku): OP-STEP-1 (Parent, Slices 1–3), OP-UMPARK-3 (Umparken schlägt passendste Plätze nach aktuellem Schritt vor + pausiert den Prozess), OP-UMPARK-4 (klären, wo „Umparken" sichtbar/erreichbar ist). Doku: ops/OP-STEP-1.md, ops/OP-UMPARK-3.md, ops/OP-UMPARK-4.md, Lastenheft §11-Anker, Offene-Punkte regeneriert, CHANGELOG, HANDOFF §2/Footer, Timesheet. True North #2: klarer, wo das Fahrzeug in der Bearbeitung steht.
  • Branch claude/next-steps-8vmq5d (PR #661) — OP-EDIT-1 Slice C: View-first — read-only Detailansicht + expliziter Bearbeiten-Schritt (APP_VERSION 0.99.0 → 0.100.0, MINOR — neues Feature). Dritter und letzter geplanter Baustein von OP-EDIT-1: der Arbeitsplatz-/Bucht-Editor öffnet einen Datensatz jetzt zuerst read-only, Bearbeiten ist ein bewusster Schritt (statt direkt ins Formular) — die übrigen Stammdaten-Editoren folgen erst mit dem noch offenen Rollout. Referenz-Implementierung am Arbeitsplatz-/Bucht-Editor: die Liste öffnet einen Datensatz über „Anzeigen" in einer read-only Detailansicht (Kapazität, Status, Skills/Ausstattung als sprechende Namen statt IDs, geplante Sperren, rev-Version); erst „✎ Bearbeiten" dort wechselt ins Formular (editEnter-Präsenz, Slice B), „Abbrechen"/erfolgreiches Speichern kehrt in die Anzeige zurück. Synergie mit A+B: die Präsenz-Warnung (Slice B) erscheint schon in der Anzeige (man sieht vor dem Bearbeiten, wer drin ist), ein -Live-Badge in der Liste zeigt aktive Fremd-Bearbeitung. Entscheidungen: (a) Detail read-only als eigener Zustand (ansichtId), Formular hat Vorrang, wenn beide zuträfen (ansichtOffen = ansichtId && !formOffen); (b) Referenz zuerst am Arbeitsplatz-Editor (wo A+B leben) — der Rollout auf die übrigen Editoren (Taxonomien, Schichten, Mitarbeiter, Leistungen) ist mechanische Musteranwendung und bleibt offen; (c) Löschen bleibt als eigene Aktion in der Liste (kein „Editieren"). Reiner Client, kein Server/Schema/Solver (nutzt die vorhandenen DTO-Felder + Slice-B-Präsenz). ng build (643,8 kB, admin-Chunk 39→44 kB, Initial dank OP-PERF-1 unverändert) + No-Hex (/60-Opacity-Muster wie im Bestand) + No-Console grün. Damit sind die drei geplanten OP-EDIT-1-Slices (A optimistische Nebenläufigkeit · B Edit-Präsenz · C View-first) gebaut — OP bleibt „offen" nur für den Editor-Rollout. Verifikations-Grenze: UI-Fluss durch Build/Typecheck belegt; ein Klick-Durchlauf (Anzeigen→Bearbeiten→Abbrechen/Speichern) bräuchte ein Live-Backend (DO). Doku: ops/OP-EDIT-1.md (Slice C ✅ Referenz + Rollout offen), CHANGELOG, HANDOFF §2/Footer, Timesheet. True North #2: sichere, bewusste Stammdaten-Pflege ohne versehentliche Änderungen.

2026-07-18

  • Branch claude/next-steps-8vmq5dOP-EDIT-1 Slice B: Edit-Präsenz — Warnung bei gleichzeitigem Bearbeiten (APP_VERSION 0.98.0 → 0.99.0, MINOR — neues Feature). Baut auf Slice A (optimistische Nebenläufigkeit) auf und liefert die zweite Hälfte der PO-Anforderung: „warnen, wenn ein anderer Benutzer/ein anderes Fenster den Datensatz bereits bearbeitet". Mechanik: der Server führt eine transiente Präsenz-Map je Verbindung (editPraesenz) → im State als bearbeitungen: EditPraesenzDTO[] gebroadcastet (live, nicht persistiert). Der Client meldet beim Betreten/Verlassen des Bearbeiten-Modus edit.enter/edit.leave mit einer stabilen, in-memory erzeugten fensterId (crypto.randomUUID, interim ohne echte Identität bis OP-AUTH-1); der Server räumt die Präsenz bei edit.leave und onClose (verwaiste Sitzung nach Verbindungsabbruch). Im Arbeitsplatz-Editor zeigt ein oranges Warn-Banner die fremden Bearbeiter (Name oder kurzer Fenster-Tag), sobald ≥1 anderes Fenster denselben Datensatz offen hat — live reaktiv (erscheint/verschwindet, wenn jemand ein-/aussteigt). Blockt bewusst nicht (Schreiben bleibt möglich; erst der erste Speichervorgang entwertet die anderen via Slice A → dort kommt der „bitte neu laden"-Hinweis). Entscheidungen: (a) Präsenz als eigener transienter Live-State (analog connections), nicht in PersistedState → kein Migrations-/Persistenz-Aufwand; (b) Selbst-Ausschluss client-seitig über die eigene fensterId (der Server muss dem Client nicht seine conn-Id mitteilen — die Broadcast-Zwei-Varianten-Optimierung bleibt unangetastet); (c) edit.enter admin-gegated (nur berechtigte Editoren, kein Spoofing gefälschter Präsenz); (d) Präsenz-Timeout für Zombie-Sitzungen bewusst später (onClose deckt den Normalfall). tsc + ng build (643,7 kB, kein Budget-Warning) + No-Hex + No-Console + persistence:check (kein Schema-Change) + test:do-migrations (v0→v22, keine Migration) grün. Verifikations-Grenze: die Präsenz-/Broadcast-Logik ist durch Typecheck/Build belegt; ein voller Zwei-Sitzungen-Durchlauf (Fenster A + B) braucht ein Live-Backend (DO). Slice C (View-first-Toggle über alle Editoren) bleibt offen. Doku: ops/OP-EDIT-1.md (Slice B ✅ + C offen), CHANGELOG, HANDOFF §2/Footer, Timesheet. True North #2: Stammdaten-Pflege ohne stille Kollisionen bei paralleler Arbeit am Leitstand.
  • Branch claude/next-steps-8vmq5d (PR #659) — OP-PERF-1: Initial-Bundle via Route-Level-Lazy-Loading reduziert — OP-PERF-1 abgeschlossen (APP_VERSION 0.97.0 → 0.98.0, MINOR — Optimierung). Der echte Fix zur Sofortmaßnahme aus OP-ALERT-1 Slice 3 (damals nur Budget angehoben = Headroom): alle Workspaces außer der Shell + dem Landing-Raum Überblick laufen jetzt über loadComponent-Lazy-Routing (client/src/app/app.routes.ts) → jeder der 14 übrigen Räume ist ein eigener Chunk und landet erst beim Öffnen im Browser. Gemessen (ng build): Initial-Chunk 935,7 kB → 558,8 kB, Initial-Total 1,02 MB → 643 kB (Transfer ~218 → ~155 kB, −37 %); schwerste ausgelagerte Chunks Planung/Gantt (62 kB) · Mitarbeiter (54 kB) · Annahme/Administration (je 38 kB) · Konflikte/Qualität (je ~35 kB). Budget wieder gestrafft (client/angular.json): maximumWarning 1 mb → 750 kb, maximumError 1,25 mb → 900 kb (fängt Regressionen, ~107 kB Warn-Headroom). Entscheidungen: (a) Landing-Raum eager lassen (garantierter Erst-View → kein Lazy-Flash auf dem kritischen Pfad); (b) alle übrigen Räume uniform lazy (einfachste, gleichförmige Regel, maximale Reduktion); (c) Deep-Link-Pfade unverändert (kein Bruch bestehender Links/Redirects inkl. klaerfaelleconflicts). Reiner Client, kein Server/Schema/Solver. ng build (643 kB, kein Budget-Warning) + No-Hex grün. Verifikations-Grenze: die Route-Auflösung ist durch den erfolgreichen Build mit 14 generierten Lazy-Chunks belegt; ein voller Klick-Durchlauf aller Räume braucht Live-Backend (DO). Doku: ops/OP-PERF-1.md (Umsetzung + Messung, Status erledigt), CHANGELOG, HANDOFF §2/Footer, Timesheet. True North #1–#3: schnellere Erst-Ladezeit am Leitstand/Terminal.
  • Branch claude/next-steps-8vmq5dOP-EDIT-1 Slice A: optimistische Nebenläufigkeit für den Arbeitsplatz-Editor (APP_VERSION 0.96.0 → 0.97.0, MINOR). Erster Baustein gegen stilles last-write-wins-Überschreiben (Auslöser: OP-UMPARK-2 Slice B, Sperren-Editor „ganze Liste patchen"). Jeder Arbeitsplatz/Bucht-Datensatz trägt jetzt einen monotonen Versionsstempel rev (nur serverseitig erhöht); der Client schickt beim Speichern die Basis-Version (baseRev) mit. Reiner, testbarer Kern revVeraltet/naechsteRev (server/src/operativ/edit-parallel.ts, npm run test:edit, 9 Prüfungen): ist die Basis veraltet (jemand anderes hat zwischenzeitlich gespeichert), wird das Speichern abgelehnt — nicht angewendet, nicht gebroadcastet. Quittung per Verbindung edit.result {ok}: ok=false → Formular bleibt offen mit Konflikt-Hinweis + „Neu laden"; ok=true → Formular schließt. Entscheidungen: (a) Ack-basiert statt Broadcast-Heuristik — erst die per-Verbindungs-Quittung schließt das Formular, so schließt kein fremder Broadcast es vorzeitig (Race) und keine abgelehnte Änderung verpufft still; (b) rückwärtskompatibel — ohne baseRev (Alt-Client) bleibt es beim bisherigen Verhalten; (c) Granularität je Datensatz (nicht je Feld), Empfehlung der OP. Kein Migrations-/State-Aufwand (rev nested-optional, Alt-Datensätze = 0). Slice B (Edit-Präsenz-Broadcast) + Slice C (View-first-Toggle über alle Editoren) bleiben offen. tsc + ng build (1,02 MB, bekanntes OP-PERF-1-Headroom) + No-Hex + test:edit/test:konflikte grün. Doku: ops/OP-EDIT-1.md (Slice A ✅ + B/C offen), CHANGELOG, HANDOFF §4, Timesheet, docs/betrieb/Tests.md. True North #2: Stammdaten-Pflege ohne stille Datenverluste bei paralleler Arbeit am Leitstand.
  • Branch claude/next-steps-8vmq5dZwei neue OPs festgehalten (PO, Doku-only → kein Bump): OP-EDIT-1 — Bearbeiten-Modus & gleichzeitiges Editieren von Stammdaten (View-first · explizit editieren · Edit-Präsenz-Warnung wenn ein anderer Benutzer/ein anderes Fenster den Datensatz bearbeitet · optimistisches Schreiben: Schreiben bleibt möglich, der erste Schreibvorgang entwertet die konkurrierenden Sitzungen → Meldung „bitte neu laden"; Versionsstempel je Datensatz). Löst den „last-write-wins"-Vorbehalt aus OP-UMPARK-2 Slice B; Querschnitts-Muster für alle Stammdaten-Editoren. OP-OPT-10 — Scheduler-Abwägung „Auto in der Bucht warten lassen vs. ausparken" (CP-SAT-Automatisierung des manuellen Hebels aus OP-UMPARK-2 Slice C). Doku: ops/OP-EDIT-1.md, ops/OP-OPT-10.md, Lastenheft §11-Anker, Offene-Punkte regeneriert.
  • Branch claude/next-steps-8vmq5dOP-UMPARK-2 Slice B + C: geplante Sperre zur Laufzeit + Bucht-Freiräumen — OP-UMPARK-2 damit abgeschlossen (APP_VERSION 0.95.0 → 0.96.0, MINOR). Slice B (geplante Sperre + Vorlauf): Bucht-Sperren (Zeitfenster Sperre[beginn,ende]) sind jetzt zur Laufzeit anlegbar/entfernbar — der arbeitsplatz.update-Patch trägt sperren (ganze Liste ersetzen), server-validiert über die reine, testbare validiereSperren (server/src/operativ/sperre.ts: gültiger sperre_grund + beginn<ende, ISO-parsebar; Ungültiges wird verworfen); ArbeitsplatzDTO.sperren exponiert; Sperren-Editor im Administration-Workspace (Grund-Dropdown aus der sperre_grund-Taxonomie + Von/Bis als datetime-local + optionale Beschreibung + Entfernen; 🔒-Badge in der Liste). Neuer Vorlauf-Konflikt geparkt_vor_sperre (Mittel, konflikteGeparktVorSperre): parkt ein Auto in einer noch aktiven Bucht mit kommender/laufender Sperre → „rechtzeitig umparken" mit „📍 Umparken"-Direktknopf (ergänzt geparkt_gesperrt/sperre_kollidiert). Slice C (Bucht freiräumen): in der Belegung trägt ein wartendes Auto (kein laufender Prozess) in einer Bucht einen „🅿️ Freiräumen"-Knopf, der es per Klick auf den ersten freien Parkplatz umparkt — über den bestehenden G-4-Umpark-Auftrag (OP-UMPARK-1, inkl. Transit-Puls + Quittung). Entscheidungen: (a) Sperren als ganze Liste patchen (einfachster robuster Editor-Vertrag) statt Index-Ops; (b) Slice C als manueller Hebel — die CP-SAT-Abwägung „warten lassen vs. ausparken" bleibt bewusst spätere Solver-Optimierung (heute hält der TS-Scheduler die Bucht via inBayStays). Selbsttest test:konflikte erweitert (Vorlauf-Konflikt + Sperre-Validierung). Kein Migrations-/State-Aufwand (Sperre-Feld existierte bereits). tsc + ng build (1,02 MB) + No-Hex + No-Console + persistence:check + operativ/do-migrations grün. Doku: ops/OP-UMPARK-2.md (Slices B+C, Status erledigt), CHANGELOG, HANDOFF §4, Timesheet, docs/betrieb/Tests.md. True North #2: Sperren/Wartungen planbar + Bucht-Auslastung ohne stille Blockade.
  • Branch claude/next-steps-8vmq5d (PR #653) — OP-ALERT-1 Slice 6: Alarm-Ton am Leit-Bildschirm — OP-ALERT-1 damit abgeschlossen (APP_VERSION 0.94.0 → 0.95.0, MINOR). Sobald ein neues Fahrzeug gesperrt wird (Notfall), ertönt ein akustisches Signal — zusätzlich zur immer sichtbaren Alarm-Optik (Slice 2). Entscheidung: Ton per Web-Audio (Oszillator, dringender Zwei-Ton × 3) erzeugt statt einer Audio-Datei — kein Binär-Asset (Everything-as-Code), kein Bundle-Ballast, keine Design-Token-Berührung. Browser-Autoplay-Policy respektiert: der AudioContext wird erst nach der ersten User-Geste (pointerdown/keydown, once) entsperrt — davor bleibt der Alarm rein visuell (ehrliche Degradation). Stummschaltbar als Geräte-Einstellung (localStorage tk-alarm-stumm, Toggle 🔔/🔕 im Rail, analog Werker-Modus); beim ersten Laden ertönt nichts (Basislinie, kein Ton für bereits gesperrte Fahrzeuge). Neuer AlarmtonService (Root-Singleton, Effect auf gesperrteCount, im Shell injiziert). Reiner Client, kein Server/Schema. Damit ist der Alarm-Kern von OP-ALERT-1 rund (auslösen · sichtbar/persistent · Foto-Pflicht · Werker-Knopf · Leitungs-Freigabe · Ton) → OP-ALERT-1 = erledigt. Ausgegliedert (PO-Entscheid 07-18): die Video-Beweiserfassung wird als eigener OP-ALERT-2 geführt (Video-Upload-Pfad ohne Foto-Kompressions-Varianten; ggf. später auf QS-Mängel/Schritt-Doku verallgemeinern). ng build (1,01 MB) + No-Hex + No-Console + Server-tsc grün. Doku: ops/OP-ALERT-1.md (Slice 6, Status erledigt), ops/OP-ALERT-2.md (neu), CHANGELOG, HANDOFF §4, Timesheet.
  • Branch claude/next-steps-8vmq5dAnführungszeichen-Konvention: gerade ASCII-Zeichen als Standard + CodeRabbit ruhiggestellt (Tooling/Doku-only → kein APP_VERSION-Bump). PO-Entscheid: gerade "/' sind der Projekt-Standard in Code, Doku und UI-Strings; keine typografischen Anführungszeichen in neuem Text (Bestehendes bleibt, kein retroaktiver Umbau). .coderabbit.yaml erhält globale tone_instructions, den Anführungszeichen-Stil nie mehr zu beanstanden und keine Umwandlung vorzuschlagen; Konvention in docs/konventionen/agents.md §5.1 verankert. Grund: CodeRabbit monierte wiederkehrend den Anführungszeichen-Stil — reines Review-Rauschen ohne inhaltlichen Wert.
  • Branch claude/next-steps-8vmq5dOP-ALERT-1 Slice 5: Freigabe-Workflow der Leitung (APP_VERSION 0.93.0 → 0.94.0, MINOR). Das Aufheben der Notfall-Fahrzeug-Sperre ist eine Leitungs-Entscheidung: nur der Chef/die Werkstattleitung darf sie freigeben — server-hart im klaerfall.loesen-Gate (interim Chef-Gate wie OP-QS-6 Vier-Augen, = Kosten-Admin-Allowlist bis OP-AUTH-1). Ein Versuch ohne Leitungs-Recht wird abgelehnt (Chronik) und auditiert (notfall.freigabe.abgelehnt, D1). Das Beweisfoto (Slice 3) bleibt für alle Pflicht — auch die Leitung kann ohne Foto nicht freigeben (Reihenfolge: Chef-Gate, dann Foto-Gate). Client-Vorgriff (Einfachheit, wie OP-QS-1 den Abnahme-Gate spiegelt): der Freigabe-Knopf ist geblockt mit klarem Grund statt stiller Server-Ablehnung — „🔒 Freigabe: nur Leitung" (Nicht-Chef) bzw. „🔒 Freigabe: 📷 Foto nötig" (Chef ohne Foto), im Detail-Panel und im Klärfälle-Detail (notfallFreigabeBlockiert + istChef); ist der Klärfall ein Notfall, heißt der Knopf „✓ Sperre aufheben …". Entscheidung: Client-Spiegel statt Rejection-Message-Roundtrip — der Client kennt chef + notfallFotos bereits, der Server-Gate bleibt Backstop (Defense-in-Depth). tsc + ng build (1,01 MB) + No-Hex + No-Console + test:notfall/operativ/test:abnahme (Regression) grün. Doku: ops/OP-ALERT-1.md (Slice 5), CHANGELOG, HANDOFF §4, Timesheet. Offen (OP-ALERT-1): Video-Erfassung · Alarm-Ton (OP-KOMM-1).
  • Branch claude/next-steps-8vmq5dOP-ALERT-1 Slice 4: Alert-Knopf im Werker-Modus (APP_VERSION 0.92.0 → 0.93.0, MINOR). Der Werker entdeckt den unerwarteten Schaden am Fahrzeug — er muss den Alarm direkt auslösen können, nicht nur der Leitstand. Neu: 🚨-Notfall-Knopf je Schritt-Karte in „Meine Arbeit" (neben „⚠ Klärfall") mit Grund-Presets (Beule/Kratzer/Teil gebrochen/Schaden unter dem Auto) + Pflicht-Freitext; gleicher Server-Pfad wie das Panel (auftrag.klaerfall mit art:'notfall', der auslösende Teilschritt wandert als Kontext mit — nichts dupliziert). Solange das Fahrzeug gesperrt ist, ist das Beweisfoto (Slice 3) direkt im Werker-Flow erfassbar (📷-Knopf + „Sperre erst nach Dokumentation aufhebbar", uploadNotfallFoto). Reiner Client, kein Server/Schema — voll verifizierbar (der Auslöse-Pfad braucht kein R2; nur der Foto-Upload ist ohne FOTOS-Binding dormant). ng build (1,01 MB, unter dem angehobenen 1,25-MB-Budget) + No-Hex + No-Console grün. Doku: ops/OP-ALERT-1.md (Slice 4), CHANGELOG, HANDOFF §4, Timesheet. Offen (OP-ALERT-1): Video · Alarm-Ton · Freigabe-Workflow der Leitung · Reject-Toast.
  • Branch claude/next-steps-8vmq5dOP-ALERT-1 Slice 3: Foto-Pflicht am Alarm (APP_VERSION 0.91.0 → 0.92.0, MINOR). Der Kern der OP („Foto-Pflicht + Stopp + Eskalation"): ein Notfall/Schaden muss mit ≥1 Beweisfoto dokumentiert werden, und die Fahrzeug-Sperre lässt sich erst danach aufheben — server-hart im klaerfall.loesen-Gate (notfallBeweisfotoErfuellt, server/src/operativ/auftrag.ts). Neues Foto-Ziel C notfall an FotoAttachment (polymorph neben teilschrittInstanzId|mangelId): Entscheidung — bewusst getrennt vom QS-Mangel modelliert, damit ein pre-existenter/unerwarteter Schaden nicht die Mangel-Auswertung je Skill/Mitarbeiter verfälscht (Selbsterklärbarkeit). Server: Upload-Endpoint akzeptiert ?notfall=1 (r2Key fotos/<auftrag>/notfall/…, Drei-Wege-XOR), foto.registriert löst das Notfall-Ziel auf (braucht offenen Notfall-Klärfall), snapshot gruppiert Notfall-Fotos je Auftrag → AuftragDTO.notfallFotos. Client: uploadNotfallFoto (Direkt-Upload, analog uploadMangelFoto) + im Detail-Panel — solange gesperrt — „📷 Beweisfoto aufnehmen", Pflicht-Hinweis „Sperre erst nach Dokumentation aufhebbar" + Thumbnails. Selbsttest test:notfall erweitert (Freigabe blockt ohne Foto, frei mit ≥1, regulärer Klärfall ohne Pflicht). Nebenbei: das Client-Initial-Bundle überschritt die bisherige harte Angular-Budget-Grenze (1 MB) um wenige KB → Budget bewusst auf maximumWarning 1mb/maximumError 1.25mb angehoben (Headroom, kein Fix) + neuer Folge-OP OP-PERF-1 (Initial-Bundle via Lazy-Loading der Workspaces reduzieren). tsc + ng build + No-Hex + No-Console + persistence:check + test:do-migrations (v0→v22, keine Migration — nested-optionales Feld) + operativ/test:abnahme (Regression) grün. R2-Roundtrip dormant (kein FOTOS-Binding) → Live-R2 nachziehen. Doku: ops/OP-ALERT-1.md (Slice 3), ops/OP-PERF-1.md, CHANGELOG, HANDOFF §4, Timesheet, Tests.md, IDs.md. Offen (OP-ALERT-1): Video-Erfassung · Alarm-Ton (OP-KOMM-1) · Alert-Knopf im Werker-Modus · Freigabe-Workflow der Leitung · Toast bei abgelehnter Freigabe.
  • Branch claude/next-steps-8vmq5dOP-ALERT-1 Slice 2: Alarm-Sichtbarkeit — der Notfall-Alarm „darf nicht verschwinden" (APP_VERSION 0.90.0 → 0.91.0, MINOR). Adressiert die PO-Sorge, dass ein ausgelöster 🚨-Alarm bisher nur im Klärfälle-Tab auftauchte und dort optisch gleich wie ein regulär eskalierter Klärfall aussah (nur „⚠ eskaliert"). Neu: (1) globaler, immer sichtbarer Alarm-Indikator in der Kopfzeile — rot, pulsierend (.tk-pulse), „🚨 N gesperrt", aus jedem Workspace sichtbar solange ≥1 Fahrzeug gesperrt ist, Klick → Klärfälle-Tab (shell.component.ts); (2) in der Klärfälle-Liste + Detail ein eigenes 🚨-„gesperrt"/„Fahrzeug gesperrt"-Badge (rot Vollton, klar unterscheidbar vom regulären „⚠ eskaliert"); (3) Sortierung: Notfall vor eskaliert vor Wartezeit (klaerfaelleSortiert). Rein abgeleitet (D-2): neue Computeds gesperrteFahrzeuge/gesperrteCount (= klaerfaelle mit art==='notfall') — der Alarm bleibt bestehen, bis der Notfall-Klärfall bewusst gelöst wird, verschwindet also nie still. Entscheidung: da ein Notfall serverseitig eskaliert erzwingt, ersetzt das 🚨-Badge das „⚠ eskaliert" (kein Doppel-Label); Rot = Warnung (Marken-Regel eingehalten). Reiner Client, kein Server/Schema/Migration. Deckt einen Teil der „Alarm-Optik am Leit-Bildschirm" (OP-KOMM-1) ab. ng build + No-Hex + No-Console + Server-tsc grün. Doku: ops/OP-ALERT-1.md (Slice 2), CHANGELOG, HANDOFF §4, Timesheet. Offen (OP-ALERT-1): Foto-/Video-Zwang am Alarm (OP-QS-1) · Alarm-Ton (OP-KOMM-1) · Alert-Knopf im Werker-Modus · Freigabe-Workflow der Leitung.

2026-07-17

  • Branch claude/next-steps-8vmq5dOP-UMPARK-2 Slice A: Fahrzeug in gesperrter Bucht → Umparken erzwungen (APP_VERSION 0.89.0 → 0.90.0, MINOR). Schließt die Lücke, dass eine Bucht-Sperre bisher still über ein dort physisch geparktes Auto hinweggehen konnte: Konflikt-Erkennung (sperre_kollidiert/arbeitsplatz_fehlt) prüfte nur geplante Arbeit (teilschritt.bayId), nie die physische belegung. Neuer Konflikt-Typ geparkt_gesperrt (Hoch) über die reine, abgeleitete Funktion konflikteGeparktInGesperrt(arbeitsplaetze, belegung) (server/src/operativ/konflikte.ts) — greift automatisch bei jedem Broadcast, sobald eine belegte Bucht auf gesperrt/in_wartung gesetzt wird (D-2, kein State/Migration). Client: Typ-Label + Direkt-Knopf „📍 Umparken" an der Konfliktkarte (öffnet das bestehende Repark-Modal aus OP-UMPARK-1, nur bei eindeutigem Fahrzeug). Entscheidung/Policy (PO 07-17): eine Bucht mit geparktem Auto lässt sich nicht still sperren — der Umpark-Bedarf bleibt als Konflikt sichtbar, bis umgeparkt ist; Sofort-Sperre → sofort umparken (G-4), geplante Sperre → vor beginn (Slice B, offen); „Bucht zwischen zwei Leistungen freiräumen" bleibt Standard „Auto wartet in Bucht" + späterer Hebel/Solver-Abwägung (Slice C, offen). Selbsttest npm run test:konflikte erweitert (gesperrt+Auto → Konflikt, aktiv/leer → keiner, Wartung/mehrere → sammelnd ohne Einzel-Link). tsc + ng build + No-Hex + No-Console grün. Doku: ops/OP-UMPARK-2.md, Lastenheft §11.1, docs/betrieb/Tests.md. Zusätzlich als eigener OP festgehalten: OP-SCHICHT-1 (Schicht-Ende-Aufräumen: hochwertige Fahrzeuge in die Halle [konfigurierbar], nächste Schicht vorbereiten, möglichst wenig über Nacht in Arbeit außer Cool-down/Nachruhe) — bewusst getrennt vom Umpark-Slice, da eigenes Scheduler-/Schicht-Thema.

2026-07-16

  • Branch claude/next-steps-8vmq5d (PR #646) — OP-QS-1 Slice 4 / M05: Dedizierte mangel-eigene Foto-Erfassung (APP_VERSION 0.88.0 → 0.89.0, MINOR). Ein Beweisfoto kann jetzt direkt am Mangel erfasst werden (nicht nur projiziert vom Teilschritt) — schließt die Lücke, wenn ein Mangel an einem Schritt ohne Foto-Pflicht entdeckt wird und das Pflicht-Foto (schwer/kritisch, Slice 3) sonst nicht erfüllbar wäre. FotoAttachment trägt jetzt eine polymorphe Ziel-Referenz (teilschrittInstanzId oder mangelId; beide optional, genau eines gesetzt; server/src/model/types.ts). Server: Upload-Endpoint /api/foto/upload akzeptiert ?mangel= (r2Key-Pfad fotos/<auftrag>/mangel/<id>/…); foto.registriert-Message bindet ans Teilschritt- oder Mangel-Ziel (löst beide auf, verwirft ohne gültiges Ziel); DTO merged je Mangel Schritt-Fotos (projiziert, M05 Slice 2) + mangel-eigene (fotosByMangel, dedupliziert nach id); das Abnahme-Gate (istAbnahmebereit) zählt beide Quellen fürs Pflicht-Foto. Entscheidung: mangel-eigene Fotos laufen als Direkt-Upload (uploadMangelFoto) im verbundenen QS-Kontext — bewusst nicht durch die Werker-Offline-Queue (IndexedDB/3 Varianten/ack-Drain), da am QS-Platz keine Offline-Resilienz nötig ist; das hält den zweiten Pfad minimal und das Regressionsrisiko am funktionierenden Schritt-Foto-Pfad klein. Client: 📷-Aufnahme-Knopf je aktivem Mangel im QS-Workspace (Toast bei Erfolg/Fehler). Liefert zugleich die Beweismittel-Mechanik für den Notfall-Alert (OP-ALERT-1 Foto-Zwang) — der Upload-Pfad ist einmal gebaut, beide Features nutzen ihn. Selbsttest npm run test:beweisfoto (CI-Gate, +3 Fälle): mangel-eigenes Foto erfüllt das Pflicht-Foto (auch ohne Schritt-Bezug), leer bleibt blockiert. tsc + ng build + No-Hex + No-Console + test:do-migrations (v0→v22, keine Migration nötig — nested-optionale Felder) + operativ/test:abnahme (Regression) grün. Verifikations-Grenze: der R2-Byte-Roundtrip ist ohne FOTOS-Binding dormant (identisch zur bestehenden Schritt-Foto-Funktion) — Live-R2 in einer Umgebung mit Binding nachziehen. Doku: Lastenheft §11.1 (Slice 4), ops/OP-QS-1.md, docs/betrieb/Tests.md. Offen: Video-Erfassung · manuelles „behoben"-Setzen + Vier-Augen (G-4/OP-QS-6) · Mangel-Auswertung · admin-Kategorien (G-1).

2026-07-15

  • Branch claude/next-steps-8vmq5d (PR #645) — OP-QS-1 Slice 3: Pflicht-Beweisfoto für schwere Mängel (APP_VERSION 0.87.0 → 0.88.0, MINOR). Baut auf M05 (Slice 2) auf: ein schwerer/kritischer Mangel (M03) braucht jetzt ≥1 Beweisfoto für die saubere Beweislage. Das server-harte QS-Abnahme-Gate (istAbnahmebereit, OP-QS-GATE) blockt die Abholung, bis das Foto dokumentiert ist — auch wenn der Mangel bereits behoben ist (das Beweismittel muss vor Abholung vorliegen). Entscheidung: leichte/mittlere Mängel bleiben ohne Foto-Zwang (geringe Friktion — nur bei echtem Haftungsrisiko erzwingen); der Foto-Check gilt statusunabhängig (offen/in Nacharbeit/behoben), da die Beweislage unabhängig von der Behebung dokumentiert sein muss. Neuer pure Helper mangelBrauchtBeweisfoto(schwere) + Gate-Regel (server/src/operativ/auftrag.ts); das Beweisfoto ist ein Foto des Teilschritts, an dem der Mangel entdeckt wurde (M05 — die fotosByInstanz-Anzahl im Gate). Client: offenePunkte() spiegelt die Gate-Regel (sonst zeigt die UI „abnahmebereit", bevor der Server ablehnt) + QS-Workspace zeigt „📷 Beweisfoto nötig (Pflicht bei schwer/kritisch)" am betroffenen Mangel (amber, kein Rot — Marken-Regel). Selbsttest-Erweiterung npm run test:beweisfoto (CI-Gate): schwer/kritisch → Beweisfoto-Pflicht, leicht/mittel nicht; Gate blockt schwer+behoben ohne Foto, ok mit Foto, ok leicht ohne Foto, blockt kritisch ohne Schritt-Bezug. tsc + ng build + No-Hex grün, test:abnahme (Regression) grün. Doku: Lastenheft §11.1 (Slice 3), ops/OP-QS-1.md, docs/betrieb/Tests.md. Offen: dedizierte mangel-eigene Foto-Erfassung (R2-Upload-Pfad) für Mängel ohne Schritt-Foto — speist auch OP-ALERT-1.
  • Branch claude/next-steps-8vmq5dOP-QS-1 Slice 2 / M05: Beweisfotos am Mangel (APP_VERSION 0.86.0 → 0.87.0, MINOR). Jeder QS-Mangel trägt jetzt in der QS-Sicht die Beweisfotos des Teilschritts, an dem er entdeckt wurde. Entscheidung (Leitprinzip Einfachheit): bestehende Teilschritt-Fotos wiederverwenden statt einen zweiten Upload-Pfad durch die intricate Offline-Foto-Queue (IndexedDB, 3 Varianten, ack-getriggerter Drain) zu fädeln — das vermeidet Regressionsrisiko am funktionierenden Foto-Pfad und ist ohne Live-R2 verifizierbar. Neuer pure Helper beweisfotosZuMangel(mangel, fotosByInstanz) (server/src/operativ/auftrag.ts, abgeleitet/D-2 — nichts gespeichert; ohne Schritt-Bezug leer). DTO: geteilter FotoRefDTO + toFotoRef-Mapper (dedupliziert die zuvor inline im Teilschritt-DTO gemappten Foto-Metadaten) + MangelDTO = Mangel & { fotos }; AuftragDTO.maengel reicht die Beweisfotos je Mangel durch (server/party/leitstand.ts). Client: Mangel.fotos + QS-Workspace zeigt eine Thumbnail-Leiste je aktivem Mangel (Klick → volle Anzeige, fotoUrl-Passthrough). Selbsttest npm run test:beweisfoto (CI-Gate): Fotos des betroffenen Schritts projiziert, isoliert je Schritt, leer ohne Bezug. tsc + ng build + No-Hex grün, operativ/test:qs-nacharbeit/test:leistung/test:mangel-status (Regression) grün. Doku: Lastenheft §11.1 (M05-Umsetzungsnotiz), ops/OP-QS-1.md (Slice 2), docs/betrieb/Tests.md. Offene Folge-Slices: dedizierte mangel-eigene Foto-/Video-Erfassung (getrennt von Schritt-Fotos) + Pflicht-Foto für schwere Mängel — speist dann auch den Notfall-Alert (OP-ALERT-1).

2026-07-14

  • Branch claude/next-steps-8vmq5d (PR #643) — OP-QS-1 Slice 1: Mangel-Status-Workflow (APP_VERSION 0.85.0 → 0.86.0, MINOR). Der QS-Mangel-Status (M06) ist jetzt 3-stufig offen → in_nacharbeit → behoben (zuvor nur offen/behoben). Entscheidung (Zuschnitt): die 3-Stufen-Statusmaschine vor die Foto-Doku gezogen — rein domänen-/testbar (kein Live-R2-Upload, der hier nicht verifizierbar ist), explizit in OP-QS-1 gelistet, und macht die zuvor nur implizite „in Nacharbeit"-Stufe (existiert ein verknüpfter Nacharbeitsschritt?) zu echtem, sichtbarem Zustand. Übergänge: ein Mangel wechselt offen → in_nacharbeit, sobald ein Nacharbeitsschritt für ihn eingeplant wird (neuer Domänen-Helfer markiereMangelInNacharbeit; verdrahtet in auftrag.nacharbeitEinplanen + die einstufige qs.nacharbeitErfassen erzeugt den Mangel direkt als in_nacharbeit), und → behoben, sobald der verknüpfte Schritt erledigt wird (bestehende erledige-Logik, Bedingung von === 'offen' auf !== 'behoben' geweitet). Das server-harte QS-Abnahme-Gate (istAbnahmebereit, OP-QS-GATE) blockt jetzt bis der Mangel behoben ist (offen und in_nacharbeit blocken, mit eigenem Meldetext „in Nacharbeit"). Client: QS-Workspace zeigt statt „Offene Mängel" alle noch nicht behobenen Mängel mit Status-Badge (offen=amber · in Nacharbeit=cyan · behoben=grün — Rot bleibt Warnungen vorbehalten, Marken-Regel). Migration v22 hebt Bestands-Mängel mit laufendem Schritt auf in_nacharbeit. Selbsttest npm run test:mangel-status (CI-Gate): markieren (idempotent, kein Rückschritt) · behoben bei Schritt-Abschluss · Gate blockt bis behoben. tsc + ng build + No-Hex-Gate grün, test:do-migrations (v0→v22) + operativ + test:qs-nacharbeit/test:nacharbeit/test:abnahme/test:leistung (Regression) grün. Doku: Lastenheft M06 + §11.1-Umsetzungsnotiz, ops/OP-QS-1.md → in-arbeit, docs/betrieb/Tests.md. Offene Folge-Slices: Foto-Beweismittel am Mangel (M05 — speist auch OP-ALERT-1) · manuelles „behoben"-Setzen + Vier-Augen-Frage (G-4/OP-QS-6) · Mangel-Auswertung je Kategorie/Skill/MA über die Zeit · admin-editierbare Kategorien (G-1).
  • Branch claude/next-steps-8vmq5d (PR #642) — OP-ALERT-1 Slice 1: Notfall-/Schaden-Alert (APP_VERSION 0.84.0 → 0.85.0, MINOR). Notfall-Knopf für einen unerwarteten, nicht vom Betrieb verursachten Fahrzeugschaden (Meeting 12.07.2026, Holger/Dominik). Entscheidung (Leitprinzip Einfachheit): der Alert ist keine Parallel-Mechanik, sondern eine Variante des Klärfalls (OP-R3-1) — neuer Diskriminator art: 'regulaer' | 'notfall' am KlaerfallKontext statt eines eigenen Systems. Zusatzregeln des Notfalls ggü. dem regulären Klärfall: (1) Hard-Stop aller laufenden Schritte (pausiereLaufendeSchritte), (2) erzwungene Eskalation (Flag hart true, nicht opt-in), (3) Fahrzeug gesperrt — abgeleitet fahrzeugGesperrt = art === 'notfall' (D-2, nie gespeichert). Neuer Domänen-Helfer meldeNotfall (server/src/operativ/auftrag.ts); DO-Message auftrag.klaerfall um art?: 'notfall' erweitert → eigener Zweig mit Chronik + Audit-Event notfall.gemeldet (Grund + gestoppte Schritte); Migration v21 backfillt art: 'regulaer' auf bestehende Klärfälle. Client: auftragNotfall(...) im Service; auffälliger 🚨 Notfall / Schaden-Knopf (Vollfläche rot) + Pflicht-Grund-Formular im geteilten auftrag-detail-panel; Kopf-Badge 🚨 Fahrzeug gesperrt statt „⚠ Klärfall", solange der Notfall offen ist. Ein einmal erklärter Notfall lässt sich nicht per regulärem Update herabstufen. Selbsttest npm run test:notfall (CI-Gate): Hard-Stop · Eskalation erzwungen · Sperre · regulärer Klärfall sperrt nicht · keine Herabstufung · Lösen hebt die Sperre auf. tsc --noEmit + ng build grün, test:do-migrations (v0→v21) + operativ grün, No-Hex-Gate grün. Neues Design-Doc docs/architektur/Notfall-Alert.md (pyramidal, Mermaid-State, Slice-Plan) + Landkarte + Lastenheft §5.1; ops/OP-ALERT-1.md → in-arbeit. Offene Folge-Slices: Foto-/Video-Zwang (OP-QS-1) · Alarm-Optik/-Ton am Leit-Bildschirm (OP-KOMM-1) · Alert-Knopf im Werker-Modus · Freigabe-Workflow der Leitung.
  • Branch claude/r7-p1-fortschritts-indikator (PR #641) — R7-P1: Auftrags-Fortschritts-Indikator (APP_VERSION 0.83.0 → 0.84.0, MINOR). Neue geteilte FortschrittsIndikatorComponent (client/.../leitstand/fortschritts-indikator.component.ts) — eine 🚗-Kette Annahme→Teilschritte→Ausgabe je Auftrag, Farbe je Schritt-Status. Entscheidung: Emoji-Glyphen tragen selbst keine CSS-Farbe (color wirkt nicht auf Farb-Emoji) — Status wird stattdessen über einen satt eingefärbten Chip + Ring hinter dem Symbol kommuniziert, nicht über die Emoji-Farbe selbst; „läuft"-Schritte pulsieren (tk-pchip, dieselbe Konvention wie der bestehende 5-Stufen-Strip). Dedupe: teilschrittStatusColor/teilschrittStatusIcon neu in labels.ts (eine Quelle statt der bisherigen Kopien in orders.component.ts + auftrag-detail-panel.component.ts). Verdrahtet an 3 Stellen (Lastenheft-Vorgabe „Liste/Karte und Detail"): kompakt auf der Fluss-Karte (ersetzt die alte reine Prozent-Leiste — strikt informativer, da je Schritt statt nur aggregiert), kompakt im Fly-in-Header (auftrag-detail-panel.component.ts), ausführlich im Aufträge-Detailpanel (ersetzt die alte flache Klick-Liste — Klick öffnet weiterhin das geteilte Detail-Fly-in, fokussiert auf den Schritt). HTML-Fallstrick vermieden: Knoten sind <span role="button"> statt <button>, da die Kette auf der Fluss-Karte innerhalb eines bereits klickbaren <button> sitzt (verschachtelte <button> wären ungültiges HTML). ng build grün; Live End-to-End verifiziert (wrangler dev + ng serve, Playwright): Karten-Kette, Detailpanel-Kette (Klick öffnet Fly-in fokussiert) und Fly-in-Kopf-Kette alle korrekt gerendert/verlinkt. docs/fachlich/Lastenheft.md §7.1 (R7-P1) + design/WORKSPACES.md (Aufträge-Sektion) nachgezogen.

2026-07-13

  • Branch claude/runner-desktop-preferred (PR #639) — Self-hosted Runner-Fallback 'hot''desktop' (Infra-only, kein App-Bump). Nutzer-Auftrag: „prefer selfhosted runner with label desktop". Der literale Fallback in ${{ vars.CI_RUNNER || 'hot' }} (greift, wenn das Repo-Actions-Variable CI_RUNNER NICHT gesetzt ist — hat sonst Vorrang) in allen 17 runs-on-Stellen (7 Workflow-Dateien: auto-rerun/ci/docs-deploy/fly-deploy/sync-ops/sync-pr-logs/weekly-audit) auf 'desktop' geändert. Hinweis (kein Code-Fix möglich): falls das Repo-Actions-Variable CI_RUNNER bereits explizit gesetzt ist (z. B. auf 'hot'), hat es Vorrang vor diesem Fallback und muss zusätzlich in den GitHub-Repo-Settings → Actions → Variables angepasst werden. YAML aller 7 Dateien lokal geparst (valide).
  • Branch claude/op-r8-1-slice2-ressourcen (PR #637) — OP-R8-1 Slice 2: Mitarbeiter fehlt · Arbeitsplatz fehlt · Sperre kollidiert (APP_VERSION 0.82.0 → 0.83.0, MINOR). Vervollständigt die Konflikt-Typ-Enum aus Slice 1 (#627) um die letzten 3 der 6 Lastenheft-Beispiel-Typen. Die Slice-1-Einschätzung „brauchen echten NEUEN Abgleich, deutlich größerer Slice" (ops/OP-R8-1.md) erwies sich als zu pessimistisch: der Abgleich Zuweisung↔Ausfallband existierte bereits — mitarbeiterAusfall/bayAusfall (scheduler/ausfall.ts) fassen Status/Abwesenheiten bzw. KonfigStatus/Sperren schon zu einem einheitlichen Ausfall-Modell zusammen (bislang nur fürs Gantt-Ausfallband genutzt). Keine neue Erkennungslogik — prüft je offenem (geplant/in_arbeit) Teilschritt, ob die zugewiesene Ressource im geplanten Zeitfenster einen bei der Planung noch unbekannten HARTEN Ausfall hat: Mitarbeiter fehlt (Hoch) — eingeplanter Mitarbeiter ist krank/im Urlaub/inaktiv (gefiltert auf harte Arten; Pause/Geschlossen respektiert der Scheduler schon, Wunschfrei ist weich) · Arbeitsplatz fehlt (Mittel) — eingeplante Bucht ist als Ganzes außer Betrieb (KonfigStatus ≠ aktiv) · Sperre kollidiert (Mittel) — ein Sperr-Fenster einer sonst aktiven Bucht überschneidet das geplante Zeitfenster (z. B. eine Sperre, die erst nach der Planung eingetragen wurde), sich gegenseitig ausschließend mit „Arbeitsplatz fehlt" (kein Doppel-Eintrag). Neue Funktionen konflikteMitarbeiterFehlt/konflikteArbeitsplatzFehlt/konflikteSperreKollidiert (server/src/operativ/konflikte.ts), in weitereKonflikte verdrahtet (server/party/leitstand.ts); Client-Typ-Union + Label-Map ergänzt. npm run test:konflikte (8 neue Fälle) + tsc --noEmit + ng build grün, keine Regression in npm run operativ. Live End-to-End verifiziert (wrangler dev+ng serve, WebSocket-Test + Playwright): arbeitsplatz.update auf in_wartung gesetzt → alle 10 betroffenen Vest-Seed-Aufträge korrekt als „Arbeitsplatz fehlt" im Feed erkannt (UI-Badge + Beschreibung korrekt), danach zurückgesetzt; „Mitarbeiter fehlt" nur per Unit-Test verifiziert (keine Mutations-Message für Mitarbeiter-Status existiert aktuell, nur arbeitsplatz.update ist admin-editierbar — dieselbe Server-Funktion in beiden Fällen). ops/OP-R8-1.md in-arbeit (beide Slices ✅, Feed-Filter + Hebel-Wizard-Integration als Folge-Slices offen).
  • Branch claude/sbom-architektur-diagrammdocs/architektur/Architektur-Uebersicht.md verbindlich eingeführt (Doku-only). Neue Datei mit Mermaid-Systemgrafik (Access · Client · Worker/DO · Solver-Service · D1/DO-SQLite · OTel, gestrichelt: TS-Optimierer-Fallback) + SBOM-Sektion (verweist auf den bereits bestehenden CI-Job sbom, OP-SBOM-1) — Taktano hatte den SBOM-Job bereits, aber noch keine Systemgrafik/keine Doku-Fundstelle für die SBOM. CLAUDE.md §Compliance + Tiefenquellen ergänzt. Übernommen aus Template (dortige D-53). Docs-only, kein App-Bump.
  • Branch claude/taktano-nested-claude-md-splitInstruktions-Scoping-Regel angewendet: nested CLAUDE.md für client//server//solver-service/ angelegt (Doku-only). Neu: client/CLAUDE.md (Angular 22/Tailwind v4-Stack, Build/Test, Verweis auf design/CLAUDE.md), server/CLAUDE.md (Cloudflare Worker/DO, Build/Test/Typecheck, Persistenz-/Logging-Konventionen), solver-service/CLAUDE.md (Python/CP-SAT, Run, Solver↔Worker-Vertrag). design/CLAUDE.md-Header um den Pflicht-Rückverweis „Governance siehe Root" ergänzt (Rest unangetastet). Root-CLAUDE.md entsprechend getrimmt: „Architektur / Stack" verweist jetzt auf die drei nested Files statt Details zu duplizieren; „Design-Prinzipien" auf die repo-weite Brand-Regel (Rot nur Warnungen) verkürzt, Token-/Komponenten-Details leben nur noch in client/CLAUDE.md/design/CLAUDE.md. Tiefenquellen-Tabelle ergänzt. bash scripts/check-doc-consistency.sh lokal grün (nur bestehende, unveränderte Warnungen). Docs-only, kein App-Bump.
  • Branch claude/nested-claude-md-scopingInstruktions-Scoping-Regel (Nested CLAUDE.md). Neue Sektion in CLAUDE.md — Root bleibt einzige Stelle für stack-unabhängige Governance (True North, G-n, ID-System, Compliance, Repo-Konventionen), nested CLAUDE.md je eigenständigem Tech-Stack-Unterverzeichnis (client/ Angular, server/ Worker, solver-service/ Python — Taktano ist der heterogenste der vier Repos, Referenzfall) nur für stack-lokale Build/Test/Lint-Details, mit festem Skelett + Pflicht-Rückverweis. Übernommen aus Template (dortige D-9), repo-übergreifend vereinheitlicht. Docs-only, kein App-Bump.
  • Branch claude/op-r8-19-reihenfolge (PR #633) — Neuer OP-R8-19: Reihenfolge-Abhängigkeit bei „Alle automatisch lösen" (Doku-only, kein Bump). Nutzer-Rückfrage nach OP-R8-7-Merge (#629): „müsste das nicht der Solver besser bewerten können?" — berechtigter Punkt, präzisiert statt nur in Prosa im PR-Chat beantwortet. Klargestellt: jeder einzelne Hebel-Wert IST solver-/scheduler-gestützt berechnet (konfliktHebelplaneJointMitEil/simuliereGewinnDurchFreigabe); was fehlt, ist eine gemeinsame Optimierung über MEHRERE gleichzeitige Konflikte hinweg — loeseAlleKonflikte() verarbeitet sie greedy in Auftrags-Array-Reihenfolge statt nach Dringlichkeit/Options-Anzahl, wodurch ein früh verbrauchter Hebel einen späteren Konflikt unnötig ungelöst lassen kann. Neuer ops/OP-R8-19.md (bezug: OP-R8-7, OP-OPT-9) mit konkretem Fehlerbild-Beispiel + Lösungsrichtung (CP-SAT-Meta-Modell über die Konflikt-Menge, alternativ einfachere Zwischenstufe „nach Options-Anzahl sortieren") + explizitem Bau-Trigger (YAGNI — erst bei wiederholt beobachteten Fällen, auditierbar über die bestehende konflikt.alleGeloest-D1-Audit-Zeile). ops/OP-R8-7.md „Garantie-Grenze" von vager Prosa auf den präzisen Cross-Link geschärft. docs/betrieb/Offene-Punkte.md regeneriert (179 OPs). check-doc-consistency.sh --strict unverändert bei den 5 bekannten Warnungen.
  • Branch claude/concurrency-vereinheitlichtconcurrency repo-übergreifend vereinheitlicht (Infra-only). auto-rerun.yml/docs-deploy.yml/fly-deploy.yml/sync-ops.yml/weekly-audit.yml (hatten gar keinen concurrency-Block) auf den in ci.yml bereits etablierten Standard group: ${{ github.workflow }}-${{ github.ref }} / cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} gehoben. sync-pr-logs.yml bewusst nicht angefasst — dessen Group-Key ist PR-spezifisch (sync-pr-logs-<PR-Nummer>), mit github.ref würden parallele PR-Syncs sich gegenseitig canceln. YAML aller 6 Dateien lokal geparst (valide). Docs/Infra-only, kein App-Bump.
  • Branch claude/runs-on-vereinheitlichtruns-on repo-übergreifend vereinheitlicht (Infra-only). auto-rerun.yml/docs-deploy.yml/fly-deploy.yml/sync-ops.yml/sync-pr-logs.yml/weekly-audit.yml (bisher ${{ vars.CI_RUNNER || 'self-hosted' }} bzw. ${{ vars.CI_RUNNER || 'hot' }}, ohne Fork-Gate) auf den in ci.yml bereits etablierten Standard-Ausdruck gehoben: ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || vars.CI_RUNNER || 'hot' }} — jetzt an jedem Job in jedem Workflow identisch. Kein pull_request-Trigger aus Forks bei diesen sechs Workflows, das Fork-Gate ist dort inert, schadet aber nicht und stellt Einheitlichkeit her. YAML lokal geparst (valide). Docs/Infra-only, kein App-Bump.
  • Branch claude/golden-rule-zero-trustGolden Rule „Zero Trust vor Public". CLAUDE.md: neue Compliance-Regel unter „Compliance, Sicherheit & Risiko" — jedes Online-Deployment wird zunächst per Cloudflare Zero Trust (Access) von der Öffentlichkeit abgeschottet, offener Zugriff ist begründete Ausnahme statt Default. Repo-übergreifend in sera/medidentas/taktano/everything-as-code-template vereinheitlicht. Hinweis ergänzt: automotivo.de-Analyse und produktive Kundenzugänge (Vest-POC) bleiben Access-gated. Docs-only, kein Code-Change.
  • Branch claude/op-r8-7-alle-loesen (PR #629) — OP-R8-7 Slice 1: Header-Aktion „Alle automatisch lösen" mit Sicherheits-Garantie (APP_VERSION 0.81.0 → 0.82.0, MINOR). Löst per Klick JEDEN Termin-Konflikt automatisch, statt eine eigene Simulation zu bauen — nimmt dieselbe Hebel-Liste, die der manuelle Konflikt-Lösen-Wizard schon anzeigt (konfliktHebel, OP-R8-2/3), und wählt daraus je Konflikt den wirksamsten SICHEREN Hebel über die neue reine Funktion waehleSicherenHebel (server/src/operativ/konflikt-auto-resolve.ts, npm run test:konflikt-autoloese). Rang (wirksamster zuerst): optionalen Schritt überspringen (skip) > Eilauftrag (eil) > Preemption/Unterbrechen (unterbrechen) > Wunsch-Abholtermin anpassen (abholtermin, letzter Ausweg — löst nur „auf dem Papier"). Die Garantie: ein Hebel gilt nur als sicher, wenn er keinen zu Beginn des Bulk-Laufs UNKONFLIKTIERTEN Auftrag neu in Terminverzug bringt (Prüfung gegen die Baseline-Menge der bereits bekannten Konflikte — bereits konfliktierte Aufträge dürfen weiter/stärker betroffen sein). Ohne sicheren lösenden Hebel bleibt der Konflikt unverändert für den manuellen Wizard offen — kein Rätselraten, keine stille Verschlechterung. Bewusste Entscheidung gegen eine neue Simulation: die Garantie-Prüfung nutzt dieselbe Simulieren-dann-Anwenden-Reihenfolge, die der Einzel-Wizard immer schon nutzt (synchron im selben DO-Message-Handler, kein Zustand ändert sich dazwischen) — keine kombinatorische Joint-Optimierung über alle Konflikte hinweg (wäre ein eigener, deutlich größerer Slice, dokumentiert als Garantie-Grenze in ops/OP-R8-7.md). Server: neue Message konflikt.alleLoesenloeseAlleKonflikte() wendet je Konflikt den bestehenden loeseKonflikt() mit dem gewählten Hebel an, quittiert der auslösenden Verbindung ehrlich { geloest, offen } (kein optimistisches Raten, mirroring das auftrag.stornieren.result-Muster) + D1-Audit. Client: LeitstandService.konfliktAlleLoesen() + konfliktAlleLoesenResult-Signal; Konflikte-Tab zeigt die Header-Aktion „⚡ Alle automatisch lösen" (nur bei ≥1 Termin-Konflikt) mit Toast-Bilanz. Live End-to-End verifiziert (wrangler dev + ng serve, Playwright + direkter WebSocket-Test): mehrere real erzeugte Termin-Konflikte automatisch aufgelöst, Toast „✓ 1 Konflikt automatisch gelöst" + Konflikt-Feed korrekt aktualisiert (Badge-Zähler runter, „Keine Termin-Konflikte"-Leerzustand). tsc --noEmit (Server) + ng build grün, keine Regression in npm run operativ. Bewusst offen (Folge-Slice): Überstunden-/Kapazitäts-Modellierung als anwendbarer Engpass-Hebel würde die Trefferquote erhöhen (aktuell ist engpass nur ein Hinweis, nie automatisch wählbar).
  • Branch claude/id-naming-conventions-912st8Projekt-Kürzel TKT bei neuen IDs jetzt verbindlich. Taktano hatte bisher als einziges Schwester-Repo keine Projekt-Kürzel-Klausel im ID-System (CLAUDE.md); jede neue ID trägt künftig TKT- als Prefix (TKT-D-n, TKT-OP-Rn-n, Session-ID TKT-<Datum>-<branch-slug>), analog MED-/SERA- in den Schwester-Repos. Bestehende IDs (OP-Rn-n etc.) bleiben unverändert — kein retroaktiver Umbau. Gleichzeitig in sera/medidentas/everything-as-code-template auf „verbindlich" (statt „empfohlen") vereinheitlicht. Kein Code-/Schema-Change.
  • Branch claude/op-r8-1-konflikt-typen (PR #627) — OP-R8-1 Slice 1: Konflikt-Typ-Enum definiert + 3 wiederverwendbare Typen im Feed (APP_VERSION 0.80.0 → 0.81.0, MINOR). Bis dahin gab es nur EINEN Konflikt-Typ (Termin-Konflikt) — die im Lastenheft (§5.2.3) beispielhaft genannten 6 Typen existierten als Enum gar nicht. Jetzt: KonfliktTyp = 'termin' | 'ueberbuchung' | 'skill_luecke' | 'standzeit' als Datenmodell (neues server/src/operativ/konflikte.ts, reine/testbare Funktionen, npm run test:konflikte). Für die drei neuen Typen keine neue Erkennungslogik — jeweils eine bereits vorhandene Berechnung wird nur in den Konflikt-Feed gehoben statt dupliziert: Überbuchung (das ueberbelegt-Flag der Hallen-/Hofplan-Belegung, bisher nur visuell) · Skill-Lücke (dieselbe Engpass-Logik wie der Hebel-Wizard-Hinweis „Engpass beheben", jetzt für ALLE offenen Aufträge statt nur bereits terminlich konfliktierte) · Standzeit-Verletzung (derselbe bringtermin + standzeitStunden-Vergleich, den der Scheduler für abholbereit nutzt, jetzt gegen den Wunsch-Abholtermin geprüft). Server broadcastet weitereKonflikte: KonfliktEintrag[] im State; conflicts.component.ts zeigt sie als eigene Karte (Typ-Badge, Schwere-Farbe hoch/mittel) neben der bestehenden Termin-Master-Liste — die bleibt unverändert Termin-spezifisch (Hebel-Wizard, OP-R8-2/3). Tab-Badge-Zähler kombiniert Termin- + weitere Konflikte. Live im Browser verifiziert (wrangler dev + ng serve, Playwright): Vest-Seed zeigt 5 Skill-Lücken-Konflikte (Fahrzeugannahme/Keramikversiegelung nur 1 aktive Fachkraft) korrekt im Feed. ng build + tsc --noEmit grün. Bewusst offen (Folge-Slices, ops/OP-R8-1.md): „Mitarbeiter fehlt"/„Arbeitsplatz fehlt"/„Sperre kollidiert" — brauchen echten NEUEN Abgleich Zuweisung↔Ausfallband/Sperre statt Wiederverwendung, deutlich größer; Filter „Typ/Schwere/Datum" im Feed; Hebel-Wizard-Integration der neuen Typen; admin-editierbare Taxonomie (G-1) — bewusst noch TS-Union wie AusfallArt, erst bei echtem Mehrfach-Betrieb-Bedarf.

2026-07-12

  • Branch claude/next-steps-f1buws (#623) — OP-R8-4 Slice 1: Gantt-Drag&Drop mit Sofort-Feedback (geometrische Validierung) (APP_VERSION 0.79.0 → 0.80.0, MINOR). Der Entwurfs-Modus-Drag im Planungs-Gantt (Bucht-/Zeit-Neuzuweisung) validierte bislang nur asynchron über einen vollen Solver-Lauf ("Konsequenzen berechnen") — ein Drop auf eine offensichtlich unmögliche Position (Überlappung, außerhalb der Schicht) erzeugte trotzdem einen Pin und musste erst über den Server-Roundtrip als "nicht erfüllbar" (ohne Grund) verworfen werden. Jetzt: gantt.component.ts prüft während des Ziehens live gegen den bereits geladenen Plan — keine Überlappung mit belegter Bay-Zeit (laufender Plan und andere vorgemerkte Pins, inkl. Cool-down) und nicht innerhalb eines Ausfall-/Sperr-Bandes der Ziel-Bucht ("innerhalb Schichten"); der Geist-Block wird bei Verletzung rot (⚠) statt cyan (✎), ein ungültiger Drop erzeugt keinen Pin, sondern einen Warn-Toast mit dem konkreten Grund (pinRejected-Output, in planning.component.ts verdrahtet). Gilt gleichermaßen für den Maus-Drag und den Tastatur-Pfad (moveBestaetigen, Barrierefreiheit). Bewusst unverändert: Skill-Match (hart) und feine Cool-down-Konsistenz bleiben Sache des echten Solver-Laufs bei "Konsequenzen berechnen" (Single Source of Truth — keine doppelte Constraint-Logik im Client, Einfachheits-Leitprinzip). Live im Browser verifiziert (wrangler dev + ng serve, Playwright-Treiber): Drop auf belegte Zeit → roter Geist + Toast "Verschiebung nicht möglich" + kein Pin; Drop auf freie Zeit → normaler Pin, Konsequenzen-Berechnung unverändert nutzbar. ng build grün. ops/OP-R8-4.md als Folge-Slices offen (Beschriftung „Neuzuweisung" ggf. auf Mitarbeiter-Zeilen ausweiten, konkrete Solver-Fehlgründe für Skill/Cool-down). CI-Nachzug (2 Runden): scripts/check-doc-consistency.sh scheiterte im doc-consistency-Gate auf dem macOS-Runner (Apple-bash 3.2) mit einem Syntax-Fehler bei continue — eingegrenzt auf ein case … esac innerhalb eines for-Loops, der wiederum innerhalb einer Prozess-Substitution <( … ) steht (Runde 1: Umstellung auf Mehrzeilen-Form traf die falsche Diagnose — zwei harmlose, flachere case-Stellen liefen in beiden Läufen nie an; Runde 2: die tief verschachtelte Stelle per Vorfilterung grep -vE '/_[^/]+$' statt case/continue entfernt — sidestept die Bash-3.2-Eigenart, statt sie zu erraten). Lokal bash -n + --strict unverändert grün (gleiche 5 Warnungen).
  • Branch claude/meeting-notes-integration-qcf9mgBesprechungsnotizen 12.07.2026 ins Repo überführt (reine Doku, APP_VERSION unverändert 0.79.0). Teilnehmer: Queckenstedt · Tieder · May · Kirchhof. Erstes Meeting-Protokoll angelegt (docs/betrieb/meetings/2026-07-12-produktiv-launch-app-review.md, pyramidal aus dem Notion-Export: TL;DR · Beschlüsse B1–B7 · Action Items A1–A8 · Diskussion · True-North-Bezug) + Index-Zeile in meetings/README.md, HANDOFF-Zeile aktualisiert. Beschlüsse an ihre verbindlichen Orte gespiegelt: OP-VERTRIEB-3 — konkreter Launch-Fahrplan (Aug Parallelbetrieb Vest · Sep Echtbetrieb · Okt 2–3 Pilotkunden ~2 Mon. · dann Vertrieb; kritische Größe ~50 Kunden); OP-PILOT-1 — erster externer Pilot „Lars von Mattwerk“ bestätigt + Feedback-Kriterium + Onboarding-Zweck; OP-ORTUNG-1 — Ortungs-Entscheidung (Fahrzeuge + Zuschnitt-Kartons per AirTag, Mitarbeiter über Arbeits-iPads/Betriebsvereinbarung, Alternativen wie Chipolo POP/aufladbare Karten prüfen); OP-I18N-1 — EU-Expansions-Sprachen NL/FR/ES/EN bestätigt; OP-BRAND-2 — Automotivo-Schutz + „made in Germany“, Owner Holger. Drei neue OPs: OP-ALERT-1 (Notfall-/Alert-Knopf bei unerwarteten Fahrzeugschäden: Stopp + Foto-Pflicht + Chef-Eskalation), OP-VERTRIEB-5 (Folienhersteller-Partnerschaft Suntec/Legend — Konditionen/Exklusivität-nur-Folien-Segment/Exit), OP-VERTRIEB-6 (Zielgruppen/Betriebsarten „Flavours“ + Zielländer). docs/produkt/Markt-und-Markteintritt.md um Meeting-Input-Callout ergänzt. gen-ops regeneriert (Offene-Punkte.md). Reine Doku, kein Bump.
  • Branch claude/docs-review-process-automation-soolri (#620) — Dependabot-Backlog abgearbeitet + OP-DEPS-1 (TS-7-Hold) angelegt (Doku/Prozess, APP_VERSION unverändert 0.79.0; kein Code-Diff — GitHub-Operationen + lokale Verifikation). Gebaut/entschieden: (1) Welle 1 — 4 unabhängige Dependabot-PRs (#309 paths-filter 3→4 · #424 server-minor-patch inkl. partyserver 0.0.66→0.5.8 [DO-Framework, Runtime] · #425 · #431) rebased + Auto-Merge (SQUASH) aktiviert (getrennte Verzeichnisse → keine Lockfile-Konflikte; mergen selbstständig auf grünem CI). (2) Zwei Majors lokal gegen main verifiziert (tsc --noEmit + Server-Smoke-Suite spike/operativ/replan/solve/teilplan — beide grün): #311 @cloudflare/workers-types 4→5 (types-only, kein Runtime-Effekt) → gemergt (Auto-Merge); #312 typescript 5.9.3→7.0.2gehalten (PO-Entscheid). Befund #312: trotz Branch-Name …typescript-6.0.3 real der native tsgo-Compiler (TS 7) — Einfachheits-Leitprinzip + keine Server↔Client-TS-Divergenz (Client bleibt TS ~6.0.3) → nicht jetzt, sondern gebündelt mit dem Client-TS-Bump. Als ops/OP-DEPS-1.md (offen · spaeter · technik) verankert, damit der grün-verifizierte Hold nicht im flüchtigen PR-Kommentar verloren geht. ops/-Bestand 174→175 OPs. Verifikation: gen-ops (175) · check-doc-consistency --strict · smooth-logs.
  • Branch claude/docs-review-process-automation-soolri (#619) — Session-Wrap: HANDOFF-Stand/Footer nachgezogen (reine Doku, APP_VERSION unverändert 0.79.0). Abschluss der Doku-Review-/OP-Modell-Strecke des Tages: Footer + §2-OP-Management-Zeile spiegeln jetzt den Ist-Stand — OP-Archiv vollständig migriert (166 Alt-OPs → ops/<ID>.md, §4 = Pointer, Lastenheft §11 = fachliches Detail), Board vollständig (~142 offene OPs gespiegelt, prio:/status:-Filter), Grooming/Diskussion als agentgetriebene on-demand-Tasks (agents.md §6.2a), Sync skaliert (Core-List + Backoff). smooth-logs + --strict grün.
  • Branch claude/docs-review-process-automation-soolriOP-Grooming/Diskussion als agentgetriebene Tasks verankert + Board-Sync vervollständigt (#617) (Doku, APP_VERSION unverändert 0.79.0). Kontext: nach der 174-OP-Migration (#477) den sync-ops-Lauf per Dispatch nachgefahren (Fix #512) → Board vollständig (~142 offene OPs gespiegelt). PO-Entscheide (3 Fragen) verankert in agents.md §6.2a: (1) Priorität/Reihenfolge im Repo entscheiden (prio:/status: in ops/<ID>.md, kein Board→Repo-Backflow — Everything-as-Code, eine Quelle). (2) OP-Diskussion zusammenfassen = stehender, agentgetriebener Task auf Zuruf (liest die op-sync-Issue-Kommentare via GitHub-MCP → ## Diskussion-Block in der ops-Datei → PR; keine Pipeline). (3) OP-Grooming on-demand je genanntem OP (## Grooming-Block: Akzeptanzkriterien · Aufwand · Abhängigkeiten · offene DSGVO-Fragen · prio-Vorschlag → PR). _Vorlage.md um beide optionalen Blöcke ergänzt. Reine Doku, kein Bump.
  • Branch claude/docs-review-process-automation-soolri (PR folgt) — Fix: sync-ops-issues.mjs skaliert auf den vollen OP-Bestand (Big-Bang-Folge) (#512) (Tooling, APP_VERSION unverändert 0.79.0). Befund: Der erste sync-ops-Lauf nach der 174-OP-Migration (#477) brach mit GitHub-Search-API-403 (Secondary-Rate-Limit) ab — das Skript machte eine Such-Anfrage je OP (~140), was den strengen Search-Burst-Limit sprengt; das Board war nur bis ~OP-DOCS-4 befüllt. Fix: (1) Issue-Lookup auf einen paginierten Core-List-Aufruf umgestellt (/issues?labels=op-sync&state=all → In-Memory-Index statt N× /search/issues); (2) gh()-Wrapper mit Backoff bei 403/429-Secondary-Limits (retry-after/exponentiell, 5 Versuche) + Drosselung bei fast leerem Primär-Limit; (3) 300 ms Pause zwischen Schreib-Calls. Idempotent — der Nachlauf vervollständigt den Rest. Verifikation: node --check + Dormant-Skip grün.
  • Branch claude/docs-review-process-automation-soolri (#477) — OP-DOCS-11 v3: OP-Archiv vollständig ins ops/-Modell migriert (Big-Bang, PO-Auftrag „überführe das OP-Archiv … dann haben wir das sauber") (Doku/Tooling, APP_VERSION unverändert 0.79.0). Gebaut: (1) ~166 Alt-OPs aus HANDOFF §4 + Lastenheft §11 in je eine ops/<ID>.md überführt (4 parallele Agenten, §4-Texte wortgetreu als Audit-Trail übernommen + programmatisch als byte-identisch verifiziert; Status/audience je Quelltext beurteilt, Grenzfälle dokumentiert). ops/-Bestand jetzt 174 OPs — 100 offen · 42 in Arbeit · 32 erledigt · 0 verworfen. (2) HANDOFF §4 → Pointer (184→23 Zeilen; verbindliche Liste = generierte Offene-Punkte.md, Lastenheft §11 bleibt fachliches detail:-Ziel, Stand-Schnappschuss 06-23 als Historie erhalten). (3) gen-ops.mjs ohne Archiv-Heuristik — die 📊-Statistik zählt seither exakt (kein §4-Schätz-Pie mehr). (4) 3 Sammel-Rollups (OP-R7/R8/R9 „1..9"-Zeilen) entfernt — die Einzel-OPs existieren separat. (5) Querverweise nachgezogen: CLAUDE.md · agents.md (§2.1/§3/§6.2) · IDs.md (Reverse-Lookup auf ops/) · Lastenheft-§11-Banner · Gold-Standard · ops/README · Compliance/Risikoregister/Roadmap/Funktionsumfang. Entscheidung: Big-Bang statt „wandert bei Berührung" (PO-Auftrag); §4-Texte bleiben unverändert erhalten (Wortlaut = Audit-Trail). Hinweis: der Merge löst den sync-ops-Spiegel aus → ~142 offene OPs werden als GitHub-Issues gespiegelt (op-sync-Board). Verifikation: gen-ops (174) · check-doc-consistency --strict grün · smooth-logs sauber.
  • Branch claude/docs-review-process-automation-soolri (#476) — OP-ORG-1 ✅ abgeschlossen (Board live · Kadenz wöchentlich) + CodeRabbit auf einmaligen Ready-PR-Review (Doku/Config, APP_VERSION unverändert 0.79.0). (1) OP-ORG-1 ✅: PO hat das GitHub-Projects-Board über die op-sync-Issues angelegt und die Kadenz auf wöchentlich entschieden (PO-Wochenblick aufs Board; Agenten-📊-Blick je Session-Beginn) — verankert in agents.md §6.2, ops/OP-ORG-1.md → erledigt (Rest-Ideen als YAGNI-Later notiert). (2) CodeRabbit-Umstellung (PO-Entscheid): reviews.auto_review.auto_incremental_review: false in .coderabbit.yaml (gegen das Schema verifiziert) — ein automatischer Review je Ready-PR, keine inkrementellen Re-Reviews bei Pushes; manuell weiter via @coderabbitai review. Motiv: Fair-Usage-Limit heute erreicht + „head commit changed"-Neustarts nach Marker-Amends entfallen. Verifikation: gen-ops (11: 4 offen · 0 in Arbeit · 7 erledigt) · --strict grün · smooth-logs sauber.
  • Branch claude/docs-review-process-automation-soolri (#474) — CodeRabbit-#473-Nachzug: Statistik-Quellen schlagen hart fehl + Board-Wording korrigiert (beide Findings valide) (Doku/Tooling, APP_VERSION unverändert 0.79.0). (1) risiken()/entscheidungen() in gen-ops.mjs schlagen bei Lesefehlern HART fehl statt still 0/Teilstatistik zu rendern (Haus-Stil; +Guard „keine RISK-Zeilen gefunden"). (2) Board-Wording: die Spiegel-Labels status:*/prio:* sind Filter/Slice — Board-Spalten kommen bei GitHub Projects aus dem Projects-eigenen Status-Feld, nicht aus Labels (gegen GH-Doku verifiziert; korrigiert in ops/OP-ORG-1.md + agents.md §6.2, Feld-Sync aus ops/ als optionale spätere Automation notiert — der „(Board-Spalten/Filter)"-Wortlaut im #473-Eintrag unten bleibt als Historie stehen, dieser Eintrag ist die Korrektur). Verifikation: gen-ops grün (Zahlen unverändert) · --strict grün · smooth-logs sauber.
  • Branch claude/docs-review-process-automation-soolri (#473) — OP-ORG-1 v2: Tasktracking auf GitHub-Projects-Basis + Statistik-Ausbau auf Entscheidungen & Risiken (Doku/Tooling, APP_VERSION unverändert 0.79.0). Entscheidung: GitHub Projects statt neuem Tool — Board als reiner Konsument über den vorhandenen op-sync-Issue-Spiegel (0 neue Systeme, Repo bleibt Quelle der Wahrheit, Einfachheit). Gebaut: (1) gen-ops.mjs-📊-Statistik zählt jetzt zusätzlich Entscheidungen (E-IDs aus den Sign-offs in docs/, ✅-Heuristik: 12 entschieden / 2 offen) und Risiken (Status-Spalte Risikoregister, fett-tolerant geparst: 13 offen/in Arbeit / 6 gemindert) — als Bestandstabelle neben den beiden Mermaid-Pies. (2) sync-ops-issues.mjs spiegelt status:*-Labels (Board-Spalten/Filter). (3) Sichten-&-Steuern-Ritual in agents.md §6.2 verankert (📊-Blick je Session-Beginn; Board = Stakeholder-Sicht). Offener Rest (dokumentiert in ops/OP-ORG-1.md): Board-Anlage durch PO (~5 Min, braucht Org-Projects-Rechte — per API/MCP hier nicht möglich; Anleitung im OP) + Kadenz-Entscheid. Verifikation: gen-ops (11) · check-doc-consistency --strict grün · node --check sync-ops-issues · smooth-logs sauber.
  • Branch claude/docs-review-process-automation-soolri (#469) — OP-DOCS-13 ✅ abgeschlossen: HANDOFF-§4-Archiv-Glättung + #405-Abschluss (reine Doku, APP_VERSION unverändert 0.79.0). (1) §4-Glättung (Schluss-Runde der 5-Phasen-Roadmap): 117 near-identische/überholte Zeilen entfernt — 96 Dekorations-Duplikate (Anker/Link- vs. blanke Variante, Inhalt byte-identisch; Union-Merge-Bestand) + 21 überholte Generationen desselben Eintrags (jeweils die neueste, entschiedene Fassung bleibt: z. B. OP-OPT-1 ×3→1, OP-TENANT ×7, OP-BACKUP-1 ×7, OP-SEED-1/OP-COST-*/OP-AUDIT-1-Generationen); HANDOFF 587→470 Zeilen, Mega-Zeilen (>2000) 90→52; alle 143 distinkten Alt-IDs erhalten (gen-ops-Zähler unverändert). Entscheidungen: inhaltlich verschiedene Mehrfach-Einträge (z. B. OP-AI-4 Slice 14/15, OP-PM-3 Plan vs. Umsetzung) bleiben; der verbliebene OP-BACKUP-1-Eintrag erhält eine PITR-Korrektur-Notiz (#467: nicht tabellen-selektiv, zweistufig Export→Whole-DO-PITR→Re-Append) statt stehenbleibendem Widerspruch (OP-DOCS-9); restliche Lang-Zeilen = akzeptierte Einzel-Historie, Warn-Gate adressiert nur Neues. (2) #405 abgeschlossen (cross-repo Repo-Keys TKT/MED/GRM): Branch war 1 Woche hinter main mit Server-seitigem Merge-Konflikt (GitHub wendet merge=union nicht an) — lokal union-gemergt, dabei 2 überholte „(PR folgt)"-CHANGELOG-Dubletten von main geglättet, Auto-Merge → gemergt; CodeRabbit-Nachzug-Finding umgesetzt: IDs.md „bare" → „repo-lokal, also ohne Repo-Key" (Selbsterklärbarkeit). (3) Zwei neue OPs (PO, 07-12): ops/OP-PILOT-1.md (Konzept Pilot-Phasen — Phasenmodell/Erfolgskriterien/Rollen/Abbruchkriterien für den Vest-POC, 🔴 jetzt; Abgrenzung: OP-VERTRIEB-3 = Zeitachse, OP-PILOT-1 = Inhalt) + ops/OP-ORG-1.md (Tasktracking; Empfehlung: GitHub Projects über den op-sync-Spiegel ausreizen statt neuem Tool). (4) Statistik-Vorgabe (PO, verbindlich): die Doku führt immer eine Statistik + Grafik offen vs. abgeschlossen — umgesetzt generiert (nie stale): gen-ops.mjs erzeugt in Offene-Punkte.md eine 📊-Sektion mit Zahlen + 2 Mermaid-Pies (ops/-Bestand nach Status · §4-Archiv per ✅-Heuristik); Regel in CLAUDE.md verankert, Ausbau (Entscheidungen/Risiken, Projects-Board) → OP-ORG-1. Verifikation: gen-ops (11) · check-doc-consistency --strict grün · smooth-logs sauber. Folge-Runde (#469-Review, 2 von 6 Findings valide): §4-Eintrag OP-DOCS-13 entfernt (lebt als ops/OP-DOCS-13.md ✅ — der Archiv-Eintrag widersprach dem Erledigt-Stand) · §4-Intro-Block ehrlich als „Stand-Schnappschuss 2026-06-23 (Historie)" betitelt (stand als „Aktueller Stand" neben Footer 12.07.). Abgelehnt: „Rest-Duplikate OP-R8-11/OPT-6/R9-12/R8-15/R4-3" (verifiziert: je genau 1×) · True-North-Kopf für die generierte Offene-Punkte-Übersicht (Kopf-Standard bewusst auf architektur/ gescoped, #467; erfundene Betriebsmetrik wäre selbst Feigenblatt) · OP-ORG-1-Titel (PO-Wortwahl, Zielgruppe Stakeholder/Technik, kein Werkstatt-UI) · gen-ops-Zeilen-Parsing (§4-Bullets sind konstruktionsbedingt einzeilig; Heuristik dokumentiert).
  • Branch claude/app-ux-process-review-i4b52d (#468) — OP-QS-6: Vier-Augen-Prinzip beim Quality-Check hart durchgesetzt — Abweichung nur durch den Chef (APP_VERSION 0.78.0 → 0.79.0, MINOR; setzt die G-4-Ausnahme um, PO-Zusatz 07-12: „von dieser Regel darf nur der Chef abweichen"). Begriffsschärfung: Prüfschritt = Phase qs OHNE Nacharbeit-/Klärungs-Marker (Nacharbeit + Klärung sind Ausführung in der QS-Phase). Pure Domäne istPruefschritt/qsAusfuehrende/vierAugenVerletzung (Helfer zählen nicht — der Produktive verantwortet). Durchsetzung an 4 Punkten: (1) TS-Scheduler schließt für Prüfschritte die Crews der Nicht-Prüfschritte desselben Auftrags aus (prospektiv im Lauf, plus Ist-Ausführende via AuftragInput.vierAugenAusgeschlossen); neue G-4-Heuristik „zwingende Ausführende zuerst" (der einzige Könner eines Schritts übernimmt bevorzugt auch andere Schritte — minimiert Kontextwechsel UND hält die übrigen QM-Träger als Prüfer frei, sonst „verbrennt" der Greedy den letzten Prüfer); Infeasible-Grund nennt Vier-Augen. (2) CP-SAT-Payload entfernt Ist-Ausführende aus der Prüfschritt-Eligibility (⚠ dokumentierte Lücke: prospektive Co-Zuweisung im selben CP-SAT-Lauf — echte Cross-Task-Constraint in model.py = Folge; gedeckt durch (3)). (3) Harter Ausführungs-Guard: Start/Fortsetzen eines Prüfschritts mit Ausführenden in der Crew wird serverseitig abgelehnt — UI zeigt „⚠ Vier-Augen" (Detail-Panel-Badge + Meine-Arbeit-Hinweis). (4) Hand-Zuweisungs-Gate (teilschritt.zuweisen): Ablehnung sichtbar in der Chronik. Chef-Abweichung (Entscheidung PO): je Prüfschritt qs.vierAugenFreigabe mit Pflicht-Begründung — Chef-gegated (interim = Werkstattleitungs-Allowlist wie Kosten-Admin, chef-Flag im State, bis OP-AUTH-1 Rollen liefert), Chronik + D1-Audit qs.vieraugen.freigabe; Freigabe wirkt für genau eine Instanz; UI: „🔓 Als Chef freigeben …" im Detail-Panel (nur für Chef sichtbar). Seed-Folge (Staffing-Erkenntnis): Marco erhielt skill-qm ★2 — im Premium-Prozess führen Julian (Folie ★3) und Sina (Keramik) selbst aus, ohne dritten QM-Träger wäre die Endkontrolle unplanbar → realer Punkt für den Vest-Stammdaten-Abgleich (wer prüft Güteklasse-3-Aufträge?). Tests: operativ +8 Vier-Augen-Asserts (Prüfschritt-Erkennung QS≠Nacharbeit/Klärung · Ausführenden-Set · Verletzung · Chef-Freigabe · Re-Plan respektiert die FreigabetoAuftragInput lässt den Ausschluss bei freigegebener Prüfschritt-Instanz fallen, sonst blockierte der Re-Plan die vom Chef sanktionierte Prüfung); test:eligibility auf Zwei-Personen-Setup umgebaut + dokumentiert den Ein-Personen-Engpass (Werkstatt mit einer Person kann die eigene Arbeit nicht prüfen → Endkontrolle korrekt unplanbar, Grund nennt Vier-Augen); komplette Suite (38 Skripte) grün. Doku: CLAUDE.md + Lastenheft §3 (G-4 + Chef-Satz) + §11.1 OP-QS-6 ✅, HANDOFF §4, Funktionsumfang, Roadmap, Tests.md.
  • Branch claude/app-ux-process-review-i4b52d (#449) — OP-UMPARK-1: Umparken als zuweisbare Aufgabe, G-4-platziert (APP_VERSION 0.77.1 → 0.78.0, MINOR). Setzt die Befunde des Umparken-Checks um: (1) Geteilter Fakt statt Client-Optik — Umpark-Aufträge leben im DO-State (umparkAuftraege, persistiert + Broadcast): alle Terminals sehen den „unterwegs"-Puls, Reload vergisst nichts, „✓ Angekommen" von jedem Terminal (Chronik + D1-Audit je Beauftragung/Ankunft). (2) Ehrliche Quittung — Beauftragung ist EINE Message auftrag.umparken (Server führt parken/starten/buchtwechsel-Dispatch aus, gemeinsame Logik extrahiert), Erfolgs-Toast erst mit umpark.result inkl. Zuweisung; stille Ablehnungen (z. B. Bucht-Start ohne Zuweisung) kommen jetzt mit Grund zurück — Phantom-Transit behoben. (3) G-4-Platzierung — pure Funktion waehleUmparkMitarbeiter: bevorzugt der Umpark-fähige Mitarbeiter, der als Nächstes an diesem Fahrzeug arbeitet (frühester offener Schritt), sonst ein gerade freier Umpark-fähiger (stört keinen laufenden Schritt, am wenigsten belastet), sonst „offen". (4) Skill-Gate — neuer Stammdaten-Skill skill-umparken („Umparken"): Seed Julian+Marco, Migration v20 (SCHEMA_VERSION 19→20, Katalog-Backfill, idempotent; Zuweisungen = Mitarbeiter-Workspace-Pflege); die bisher tote „Umparken"-Chip-Hervorhebung im Mitarbeiter-Workspace ist damit live. (5) „Meine Arbeit" — zugewiesene + offene Umpark-Aufgaben als Karte über der Queue („AU-nnn nach ‚Stellplatz 2' bringen … ✓ Angekommen"). Entscheidungen: Belegungs-Drag&Drop bleibt direkte Inventur-Korrektur (dokumentiert Ist, beauftragt nicht); Umparken bleibt bewusst ohne Solver-Kapazität (Minutensache, kein Teilschritt); Rollen-Gate fürs Bestätigen folgt mit OP-AUTH-1. Tests: operativ +4 Platzierungs-Asserts (nächster-am-Fahrzeug · Skill-Gate · stört-keinen-laufenden-Schritt · offen), test:do-migrations v20. Doku: Lastenheft §11.1 ✅, HANDOFF §4, Funktionsumfang, Roadmap, Tests.md, COMPONENTS.md/WORKSPACES.md (Re-park-Vertrag).
  • Branch claude/app-ux-process-review-i4b52d (#446, gemergt) — Umparken-Check ✅ + neue Regel G-4 (Kontextwechsel-Minimierung, Vier-Augen-QS) + Chronik-Fix (APP_VERSION 0.77.0 → 0.77.1, PATCH). Check (TODO 06-28, alle Pfade per Code-Review): Belegung-Drag&Drop · Repark-Modal (Detail-Panel/Belegung) · Konflikt-Preemption laufen auf konsistente Server-Pfade; Interrupt-Pflicht-Kommentar, Bucht-Typ-Bindung, Doppelbelegungs-Markierung, Guards intakt. Befunde: (1) Der Umpark-Auftrag wird niemandem zugewiesen — kein Skill/Schritt/Queue-Eintrag; „unterwegs" lebt nur client-lokal (kein DO-State/Broadcast, Reload vergisst, nur der Beauftragende kann „Angekommen" bestätigen) → OP-UMPARK-1 (echte zuweisbare Aufgabe, G-4-Platzierung); (2) Erfolgs-Toast vor Server-Antwort → Phantom-Transit bei stillen Ablehnungen (in OP-UMPARK-1); (3) gefixt: Chronik log bei auftrag.parken „Prozess beendet/pausiert", auch wenn die Transition scheiterte (z. B. beenden aus pausiert) — schreibt jetzt nur, was wirklich geschah; (4) tote „Umparken"-Skill-Hervorhebung (v3-Rest, in OP-UMPARK-1). Entscheidungen (PO, 07-12): G-4 neu (CLAUDE.md + Lastenheft §3): Aufgaben-Platzierung minimiert Kontextwechsel — wer als Nächstes am Fahrzeug arbeitet, übernimmt bevorzugt dessen Neben-/Logistikaufgaben (z. B. Umparken vor der eigenen Folierung); harte Ausnahme QS (Vier-Augen): Ausführende verifizieren nie die eigene Arbeit → OP-QS-6 (Scheduler kennt die Constraint heute nicht — QS rein skill-basiert vergeben). Doku: Lastenheft §3 G-4 + §11.1 OP-UMPARK-1/OP-QS-6, HANDOFF §4 (TODO ✅ + 2 OPs), IDs.md, Roadmap.
  • Branch claude/docs-review-process-automation-soolri (#467) — CodeRabbit-#462-Review: 9 Findings behoben, 8 begründet abgelehnt (E6-Folge) (reine Doku/Tooling, APP_VERSION unverändert 0.77.1). Behoben: (1) Backup-Restore-Kernaussage korrigiert — der native DO-SQLite-PITR ist nicht tabellen-selektiv (CodeRabbit gegen CF-Doku verifiziert); Kernaussage + neue §5-Randbedingung: Audit-Delta vor Rollback exportieren/re-appenden oder eigene Storage-Grenze (Festlegung im Restore-Slice). (2) Mandantenfähigkeit-Kernaussage: zwei zentrale Ausnahmen (Registry und Hash-Anker) + R2-Prefix-Isolation als logisch abgegrenzt. (3) Bildbewertung: dormant eindeutig an Phase 1b (1a ist gebaut). (4) Audit-Log-Slice-Bullet: „dormant … inzwischen aktiv" → ✅ aktiv mit datierter Historie-Klammer. (5) agents.md §2.1 Kopf-Standard explizit auf docs/architektur/*.md gescoped (sonst hätte jede docs/-Datei sofort verletzt; für andere schwere Docs „empfohlen") + MD031-Leerzeilen. (6) Gate §10 gehärtet: prüft nur den Block direkt nach der H1 und verlangt alle vier Felder (Status/Bezug/Zielgruppe/True North) + genau eine Kernaussage — Negativ-Test verifiziert; Tests.md-Beschreibung nachgezogen. (7) OP-VERTRIEB-4 +Negativ-Security-Check als Abnahme-Kriterium (nur /vorteilsrechner öffentlich). (8) CHANGELOG-Migrations-Zähler präzisiert (143 Alt-IDs / 7 migriert / 9 ops-Dateien). Abgelehnt mit Begründung: die 8 MD028-Findings („blank line in blockquote" in den neuen Köpfen) — das Zwei-Block-Design (Metadaten-Box + Kernaussage-Box) ist gewollt (Vorbild Doku-UX-Konzept, Template agents.md §2.1); als Design-Entscheid jetzt explizit in §2.1 dokumentiert. Verifikation: Gate-Negativ-Test (kaputter Kopf → 2 Warnungen, restauriert → 0) · check-doc-consistency --strict grün · smooth-logs sauber. Folge-Runde (#467-Review, 2 Findings): PITR-Vertrag jetzt in §§5/7/8 konsistent (E-BACKUP-1/B5-5: zweistufig Audit-Export → Whole-DO-PITR → Re-Append; keine native Selektivitäts-Behauptung mehr) · Gate §10 auf Blockquote-Zeilen geankert (Prosa-/Code-Treffer zählen nicht).
  • Branch claude/docs-review-process-automation-soolri (#462) — Doku-Review E6: architektur/-Kopf-Standard + Glossar-Alltagsbegriffe · CodeRabbit-Tuning · OP-VERTRIEB-4 (reine Doku/Tooling, APP_VERSION unverändert 0.77.1). (1) E6-Format (Befund D6): kanonischer Kopf (Status · Bezug · Zielgruppe · True-North + genau eine > **Kernaussage.**) in allen 16 architektur/-Docs durchgezogen (vorher 0/16) — inkl. Auflösung der belegten Selbstwidersprüche (In-App-Assistent „kein Code" vs. „Slices umgesetzt"; Audit-Log §2.1 „Heute alles DO-Blob" vs. „D1 ✅ aktiv" → historisch eingeordnet) und der Doppel-Kernaussagen (Offline-PWA mit erhaltener Foto-Queue-Einschränkung · Fahrzeug-3D); Standard als Regel in agents.md §2.1 verankert + Warn-Gate check-doc-consistency.sh §10 (Status/Zielgruppe/genau-eine-Kernaussage je architektur/-Doc). (2) Glossar (Befund D7, OP-DOCS-10): 11 Alltagsbegriffe ergänzt (Klärfall · Phase · Leistung · Terminklasse · Angebotsmodus · Auslastung · Endkontrolle · Nachkontrolle · Helfer · Wunschfrei · Crystal-Bar) → 68 Begriffe; ART-Label ehrlich „Fachlich (Werkstatt/Geschäft)"; Lastenheft-§13-Doppel-Glossar auf Verweis eingedampft (die dortigen Falsch-Definitionen Helfer/Standort dokumentiert entfernt; Crystal-Bar zentral gerettet); RAG-Doku-Index regeneriert (581 Chunks/51 Dateien). (3) CodeRabbit-Tuning (Nutzer-Auftrag): .coderabbit.yaml — True-North-Regel explizit auf Liefergegenstände als Ganzes gescoped (nicht je Zeile/Checkbox, Doku-Review-D6-Feigenblatt-Verbot); neue Pfad-Instruktionen für Timesheet/CHANGELOG (append-only Logs: keine True-North-/Lint-Forderungen, historische Marker nicht anmahnen) + .github/** (Template = Body-Prefill, kein MD041); nebenbei „Angular 20"→„Angular 22" gefixt. (4) Neuer OP ops/OP-VERTRIEB-4.md (PO-Wunsch): Vorteilsrechner als öffentlicher Direktlink (z. B. taktano.com/vorteilsrechner) — Klärpunkte Access-Bypass vs. separates Public-Deployment, taktano.com-Zone (OP-BRAND-1), Lead-Erfassung bleibt OP-VERTRIEB-2. (5) ops/-first gelebt: OP-DOCS-13 bei Berührung ins ops/-Format migriert (ops/OP-DOCS-13.md, in-arbeit — Migrations-Zähler jetzt 143 Alt-IDs / 7 davon migriert, 9 ops-Dateien gesamt). Verifikation: gen-ops (9 OPs) + gen-glossar (68) + doku-index + check-doc-consistency --strict (0 architektur-Kopf-Warnungen) + smooth-logs grün.
  • Branch claude/docs-review-process-automation-soolri (#459) — Template-Präzisierung: Branch-Löschung konditional (CodeRabbit-#458-Finding) (reine Doku, APP_VERSION unverändert 0.77.1). Ein-Zeilen-Fix im PR-Template: „(Branch wird nach Merge automatisch gelöscht)" → „(Branch nach Merge löschen — automatisch via Repo-Setting, sonst manuell)" — deckungsgleich mit agents.md §7 statt unbedingtem Versprechen. War als Fix in #458 gedacht, der Auto-Merge gewann den Wettlauf.
  • Branch claude/docs-review-process-automation-soolri (#458) — CodeRabbit-#457-Review: 3 Findings behoben, 2 begründet abgelehnt (OP-DOCS-15-Folge) (reine Doku/Prozess, APP_VERSION unverändert 0.77.1). Behoben: (1) Prozess-Checkliste im PR-Template vervollständigt (+Branch-first, +Remote-Writes via GitHub-API/MCP — die Vollständigkeits-Behauptung stimmt jetzt); (2) Session-Hook auf reinen Pointer reduziert (duplizierter „Kern"-Satz raus — eigene Sicht-Doktrin); (3) True-North-Bezug in ops/OP-DOCS-15.md ergänzt („schneller"-Klausel, ehrlich abgegrenzt). Abgelehnt mit Begründung: (a) H1 im PR-Template (MD041) — das Template ist Body-Prefill, kein Standalone-Doc; eine Überschrift würde jeden PR-Body verschmutzen; (b) relative Links statt blob/main auf .github/-Dateien — Repo-Datei-Links außerhalb docs/ brechen auf der Docusaurus-Site, blob-URLs sind die dokumentierte Konvention (#419, OP-DOCS-9). Verifikation: gen-ops + check-doc-consistency --strict + smooth-logs grün.
  • Branch claude/docs-review-process-automation-soolri (#457) — OP-DOCS-15: Kanonische PR-Checkliste (neu: .github/PULL_REQUEST_TEMPLATE.md) (reine Doku/Prozess, APP_VERSION unverändert 0.77.1). Schließt Empfehlung E5 des Doku-Reviews (#447, Befund D5/D10): ~20 Je-PR-Pflichten waren über ≥5 Orte verstreut, ohne PR-Template und ohne eine vollständige Checkliste. Gebaut: PR-Template als Checkbox-Liste — Pflicht jeder PR (8: CHANGELOG · HANDOFF · Timesheet · APP_VERSION · Konsistenz-Check · Log-Glätten · Branch-Sync · Verifikation) · falls zutreffend (6: Funktionsumfang · Tests.md · ops/-first · Glossar/Landkarte/IDs · Roadmap/Sanity · Compliance/Risiko) · Prozess („go"-Gate · Chat-Zusammenfassung); GitHub legt sie jedem neuen PR automatisch in den Body. Entscheidungen: (1) Checkliste = Sicht, kein neuer Regel-Owner — jede Pflicht zitiert ihre Owner-Regel (Lehre aus D4); (2) Pflege-Regel als neues agents.md §6.9: neue/geänderte Je-PR-Pflicht ⇒ Template im selben PR nachziehen; (3) kein Generator (Einfachheit — ein Artefakt, Hook/CLAUDE.md verweisen statt duplizieren). Session-Hook Punkt 4 + CLAUDE.md §Repo auf die Checkliste umgestellt; neuer ops/OP-DOCS-15.md (erledigt, ops/-first) + IDs.md/Register.md-Zeilen + Offene-Punkte regeneriert. Verifikation: gen-ops + check-doc-consistency --strict + smooth-logs grün.
  • Branch claude/docs-review-process-automation-soolri (#454) — Wrap: CodeRabbit-#453-Review adressiert (6 Findings) + Log-Finalisierung (reine Doku/Tooling, APP_VERSION unverändert 0.77.1). (1) gen-ops.mjs altBestand(): 160-Zeichen-Deckel im Zeilen-Scan entfernt (OP-IDs jenseits der ersten 160 Zeichen einer Mega-Zeile wurden übersehen; Zähler bleibt real bei 143/6 — Set-Dedup fing den Fall ab, Fix ist defensiv korrekt). (2) Rest-Widersprüche zur ops/-first-Regel getilgt: Register.md Änderungs-Reihenfolge-Regel · IDs.md Status-Zeile + Fußnote · HANDOFF §7-„Abarbeiten"/§8-Baum/§9-Reminder + Footer-Detailzeile. (3) Harte OP-Zahlen aus Hand-Docs entfernt (agents.md/Register.md verweisen auf die generierte Zählzeile — keine Zahlen-Drift). (4) Frische „(PR folgt)"-Marker finalisiert (#446 · #450 · #451 · #452 · #453 in CHANGELOG + Timesheet; historisch-mehrdeutige bewusst belassen, Präzedenz 07-11) + fehlender Teil-2-Timesheet-Eintrag nachgetragen. Verifikation: gen-ops + check-doc-consistency --strict + smooth-logs grün.
  • Branch claude/docs-review-process-automation-soolri (#453) — ops/-first verbindlich: OP-Doppel-Wahrheit aufgelöst (OP-DOCS-11 v2, Doku-Review E3/D4) (reine Doku/Tooling, APP_VERSION unverändert 0.77.1). Das Review #447 belegte: HANDOFF §4 und ops/*.md beanspruchten beide die Quelle der Wahrheit, agents.md §6.2 kannte das ops/-Format nicht (Ergebnis: Dreifach-Buchführung), und Doku-UX-Konzept Phase 5 skizzierte eine konkurrierende Zielarchitektur unter derselben OP-ID. Entschieden + umgesetzt: (1) agents.md §6.2 auf ops/-first umgeschrieben — neuer OP = ops/<ID>.md (Frontmatter, audience-Pflicht) + gen-ops; keine neuen Einträge mehr in HANDOFF §4 / Lastenheft §11 (Status-Updates am Bestand bleiben zulässig, Alt-OPs wandern bei Berührung). (2) HANDOFF §4 als Archiv gelabelt (Überschrift + Banner). (3) Migrations-Zähler in gen-ops.mjs: die generierte Offene-Punkte.md zeigt jetzt „143 distinkte Alt-OP-IDs im §4-Archiv, 6 migriert" — Fortschritt sichtbar statt behauptet. (4) Doku-UX-Konzept Phase 5 als „anders gelöst" markiert (die src/op/op.mjs-Generierung von Register/IDs/§4 ist verworfen — §4 stirbt als Archiv aus, Register/IDs bleiben kuratierte Indizes). (5) Zuständigkeits-Kopien nachgezogen: Register.md (Quelle-Tabelle zweizeilig neu/Bestand) · IDs.md (Intro + OP-Legende) · CLAUDE.md (Audit-Trail-Regel) · ops/README.md · Gold-Standard (+Archiv-Label-Lehre für drkv-Rollouts). (6) ops/OP-DOCS-11.md v2-Block. Walk-the-talk: dieser PR legt selbst KEINEN neuen HANDOFF-§4-Eintrag an — der OP-Lebenszyklus steht in ops/OP-DOCS-11.md. Verifikation: gen-ops grün (Zähler korrekt) · check-doc-consistency --strict grün · smooth-logs sauber. Doku: agents.md §6.2, HANDOFF §4-Banner+Footer, gen-ops.mjs, Offene-Punkte.md (generiert), Register.md, IDs.md, CLAUDE.md, ops/README.md, OP-Management-Gold-Standard.md, Doku-UX-Konzept.md, ops/OP-DOCS-11.md, CHANGELOG, Timesheet.
  • Branch claude/docs-review-process-automation-soolri (#452) — OP-DOCS-14 Teil 3: Doku-Gates scharf schalten — OP geschlossen (Tooling/CI/Doku, APP_VERSION unverändert 0.77.1). Schließt Befund D5 des Doku-Reviews (#447: „kein einziges Doku-Gate blockiert; Erfolgs-Behauptungen übertreiben") und damit den letzten OP-DOCS-14-Teil. (1) scripts/check-doc-consistency.sh zweistufig: harte, False-Positive-arme Teilmenge (tote Links/Bilder · Version/Build-Single-Source) blockt mit --strict (Exit 1 + ::error), alle übrigen Checks warnen weiter; drei neue Warn-Checks — Log-Zeilenlängen > 2000 Zeichen (HANDOFF/CHANGELOG, aggregiert je Datei, OP-DOCS-13) · Footer-Staleness (README/HANDOFF „Letztes Update" > 7 Tage hinter letztem Commit, Review-D3) · Landkarte-Rücklink je Leaf-Doc. Negativ-Test verifiziert (injizierter toter Link → strict Exit 1, sauber → Exit 0). (2) CI (ci.yml): doc-consistency läuft --strict und hängt jetzt am ci-gate (war bewusst draußen); der Offene-Punkte.md-Staleness-Diff nach gen-ops blockt (::error/Exit 1) statt warn-only. (3) Doku-Site: onBrokenLinks: 'warn''throw' — Build vorher und nachher komplett grün verifiziert (npm ci + build, 0 Broken-Link-Warnungen); die throw-Behauptung im Doku-UX-Konzept stimmt damit erstmals. (4) Neuer Generator scripts/gen-doc-footer.mjs (idempotent, --check): schreibt den „↩ Zurück zur Doku-Landkarte · Lesepfade · Register"-Footer statisch in die Markdown-Quellen (39 Leaf-Docs) — die Rück-Navigation existiert jetzt auch auf GitHub, nicht nur auf der gerenderten Site (Review-Kennzahl „0/16 Rücklinks im MD" behoben); der Site-Remark-Footer (docNavFooter.mjs) erkennt den relativen README-Link und doppelt nicht. Entscheidungen: (a) Timesheet.md bewusst ohne statischen Footer (append-only union-merge-Log — neue Sessions landen am Dateiende, ein End-Footer würde in die Mitte rutschen); (b) blockierende Teilmenge bewusst minimal (nur deterministische Checks) — Navigation/Hygiene/Staleness bleiben Warnungen, damit kein False-Positive einen Merge stoppt; (c) Regel-Kopien nachgezogen statt driften lassen (CLAUDE.md · agents.md §2.1/§5.1/§6.6 · session-start-hook · Tests.md · Doku-UX-Konzept §3 inkl. Korrektur der beiden übertreibenden Behauptungen). Verifikation: bash -n + beide Modi + Negativ-Test · gen-doc-footer --check grün · Docusaurus-Build grün (throw) · check-no-hex grün · gen-ops grün. Doku: check-doc-consistency.sh, gen-doc-footer.mjs (neu), ci.yml, docusaurus.config.js, 39× docs/-Footer, agents.md, CLAUDE.md, session-start-hook.sh, Tests.md, Doku-UX-Konzept.md, ops/OP-DOCS-14.md (erledigt), Offene-Punkte.md (generiert), HANDOFF §4, CHANGELOG, Timesheet.
  • Branch claude/docs-review-process-automation-soolri (#451) — OP-DOCS-14 Teil 2: Drift-Fix-Runde verbindliche Stellen (reine Doku, APP_VERSION unverändert 0.77.1). Schließt die Befunde D2 (Doku widerspricht Code/sich selbst) und D3-Vordertüren des Doku-Reviews (#447) an sechs verbindlichen Stellen: (1) docs/fachlich/operativmodell.md — der abgelöste Lifecycle (unbestaetigt→aktiv→…) und das alte Nummernformat #JJJJ-NNN durch das reale Modell ersetzt (9 Status inkl. abgebrochen, nacharbeiten-Rückkante, #000.KW00.JJJJ, sprechende UI-Labels aus labels.ts); anschließend RAG-Doku-Index regeneriert (npm run doku-index) — der In-App-Assistent antwortet nicht länger mit dem wegmigrierten Statusmodell. (2) Lastenheft §5.1 — abgebrochen (terminal, aus allen aktiven Status) + nacharbeiten (Fertiggestellt→Angeliefert) in State-Diagramm, Status-Tabelle und F02 ergänzt; das Master-Spec-Diagramm widerspricht dem Code nicht mehr. (3) design/CLAUDE.md (Detailvertrag) — Alt-Client-Beschreibung (Tailwind-CDN, STATUS_HEX, Montserrat, „Monolith zerlegen", design-system/-Pfade) durch den Ist-Stand ersetzt (Tailwind v4 auf --tk-*-Tokens via PostCSS, Shell + 15 Workspace-Pages, Token-Pipeline + design-gate, Brand-Hex im Fließtext durch Token-Namen); alle weiterhin gültigen Non-Negotiables behalten. (4) Root-README.md — Angular 17→22, Node ≥18/wrangler@3-Begründung → Node 22/Wrangler 4, Test-Abschnitt auf 4 Kern-Befehle + Link auf die lebende Liste docs/betrieb/Tests.md eingedampft, Anwender-Handbuch + Landkarte als Einstiege, Footer-Datum. (5) HANDOFF.md — Footer (16.06./„Angular 20" → 12.07./v0.77.1 mit aktuellem Fokus POC Vest + OP-DOCS-14) + §8-Dateibaum (flacher Alt-Baum docs/Lastenheft.md → reale Ordnerstruktur inkl. ops/, docs-site/, anwender/) + §6.1 „Tailwind via CDN" → Tailwind v4/Tokens. (6) docs/architektur/Persistenz.md — E-TENANT-1 von „voller D1-Sink empfohlen — offen" auf den Entscheid „✅ Variante C: D1 nur Tamper-Anker, keine PII zentral" nachgezogen (Widerspruch zu Mandantenfaehigkeit.md §4 beseitigt); Root-CLAUDE.md Observability/OP-LOG-1 von „heute noch console-basiert → migrieren" auf den Ist-Stand (OTLP → Grafana Cloud EU live, check-no-console.sh-Gate) + Owner-Pointer gekürzt. Entscheidung: Rewrites strikt gegen Code/Konfig verifiziert (auftrag.ts/labels.ts · client/package.json · .nvmrc · tokens-Pipeline) — keine Aussage ohne Beleg; check-doc-consistency + check-no-hex grün. Doku: operativmodell.md, Lastenheft §4.9/§5.1, design/CLAUDE.md, README.md, HANDOFF (Footer/§8/§6.1/§4), Persistenz.md, CLAUDE.md, server/src/assistant/doku-index.generated.ts (regeneriert), ops/OP-DOCS-14.md (Teil 2 ✅), CHANGELOG, Timesheet.
  • Branch claude/docs-review-process-automation-soolri (#450) — OP-DOCS-14 Teil 1: Anwender-Handbuch (neu: docs/anwender/, 4 Seiten) (reine Doku, APP_VERSION unverändert 0.77.1). Schließt Befund D1 des Doku-Reviews (#447): die am stärksten geführte Zielgruppe — das Werkstatt-Team — hatte kein einziges Dokument in ihrer Sprache. Gebaut: Handbuch.md (erste Schritte: Bereiche der linken Leiste mit App-Untertiteln, Werker-Modus, „?"-Hilfe, Status-Wörter, die drei Leitfragen als „Wo sehe ich das?"-Tabelle) · Mein-Arbeitstag.md (Queue mit Positionsnummern, ⏸ Pause/▶ Weiter/✓ Fertig, Doku-Fenster mit den fünf Textbaustein-Chips, Pflicht-Fotos je Perspektive, Offline-Foto-Warteschlange) · Klaerfall-melden.md (melden in 3 Schritten mit den vier Grund-Presets, die vier Lösungs-Wege als Tabelle, „⏱ Klärung einplanen" 15/30/60 min) · Fahrzeug-annehmen.md (Ein-Satz-Annahme mit den fünf Bausteinen + Termin-Härte, Check-in „🚗 Fahrzeug da" mit Car-Check-Pflicht + FIN-Pflichtfeld). Entscheidungen: (1) alle UI-Strings wörtlich aus dem Client extrahiert (Explore-Lauf über shell/meine-arbeit/annahme/quality/klaerfall-loesen/labels.ts) statt aus dem Gedächtnis — Doku↔Code-Treue ab Tag 1 (OP-DOCS-9); (2) Vier-Augen-Regel bewusst nicht beschrieben (im Client nicht umgesetzt — das Handbuch beschreibt nur Gebautes); (3) du-Form wie die App selbst, keine OP-IDs/Code-Symbole im Text; (4) Sidebar-Position 0.5 (direkt nach Lesepfaden, nicht-invasiv ohne Umnummerieren der 6 Bestands-Ordner). Anwender- + Customer-Service-Lesepfad führen jetzt zuerst ins Handbuch (statt aufs veraltete operativmodell.md); Aufgaben-Tabelle +„die App im Alltag bedienen". Doku: docs/anwender/* (neu, inkl. _category_.json), Lesepfade.md, docs/README.md, ops/OP-DOCS-14.md (Teil 1 ✅), Offene-Punkte.md (generiert), HANDOFF §4, CHANGELOG, Timesheet.
  • Branch claude/docs-review-process-automation-soolri (#447) — Doku-Review 2026-07: „Ist die Dokumentation ein Meisterwerk?" (neu: docs/betrieb/Doku-Review-2026-07.md + OP-DOCS-14) (reine Doku, APP_VERSION unverändert 0.77.0). Nutzer-Auftrag: Experten-Review der Dokumentation (inhaltlich · strukturell · Doku-Vorgaben) aus Sicht UX + Prozess-Automatisierung für stark geführte Akteure — Schwester-Review zum App-UX-Review #434. Methode: 4 parallele Tiefen-Reviews über alle ~55 Docs (fachlich+Glossar · architektur/ · betrieb/produkt/Logs · Konventionen/Governance) mit Code-Stichproben + mechanischen Messungen. Urteil: starkes Gesellenstück mit Meister-Inseln — generierte/kuratierte Sichten (Glossar, ops/, Funktionsumfang, Tests.md) nahe am Anspruch; verhindert wird das Prädikat durch D1 keine Anwender-Doku (Lesepfad führt aufs veraltete operativmodell.md) · D2 Drift an verbindlichen Stellen (operativmodell-Lifecycle abgelöst + im RAG-Index, Lastenheft §5.1 ohne abgebrochen/nacharbeiten, design/CLAUDE.md beschreibt Alt-Client, Persistenz↔Mandantenfähigkeit widersprechen sich bei E-TENANT-1) · D3 stale Vordertüren + Mega-Zeilen (README „Angular 17", HANDOFF-Footer 16.06., Roadmap 06-28, Timesheet 3 Σ-Zeilen, HANDOFF-Max 15.284 Z., CHANGELOG 70× „PR folgt") · D4 OP-Doppel-Wahrheit (HANDOFF §4 vs. ops/*.md, 5/~210 migriert, agents.md §6.2 kennt ops/ nicht) · D5 ~20 Je-PR-Pflichten ohne ein blockierendes Gate (doc-consistency nicht im ci-gate, onBrokenLinks real warn) · D6–D10 Format/Glossar/Gelebte-Prozesse/Politur/Onboarding-Last. Entscheidungen: Empfehlungen E1–E6 nach Wirkung÷Aufwand; Top-3 (Anwender-Handbuch · Drift-Fix-Runde · Gates scharf) als neuer ops/OP-DOCS-14.md (audience technik+produkt) gebündelt — E3 bleibt bei OP-DOCS-11, E6 bei OP-DOCS-13/-10; neuer OP bewusst ops/-first angelegt (ohne Lastenheft-§11-Doppelung — die Doppel-Buchführung ist selbst Befund D4). Doku: Doku-Review-2026-07.md (neu), ops/OP-DOCS-14.md (neu), Offene-Punkte.md (generiert), docs/README.md, IDs.md, Register.md, HANDOFF §4, CHANGELOG, Timesheet.
  • Branch claude/app-ux-process-review-i4b52d (#446) — Umparken-Check ✅ + neue Regel G-4 (Kontextwechsel-Minimierung, Vier-Augen-QS) + Chronik-Fix (APP_VERSION 0.77.0 → 0.77.1, PATCH). Check (TODO 06-28, alle Pfade per Code-Review): Belegung-Drag&Drop · Repark-Modal (Detail-Panel/Belegung) · Konflikt-Preemption laufen auf konsistente Server-Pfade; Interrupt-Pflicht-Kommentar, Bucht-Typ-Bindung, Doppelbelegungs-Markierung, Guards intakt. Befunde: (1) Der Umpark-Auftrag wird niemandem zugewiesen — kein Skill/Schritt/Queue-Eintrag; „unterwegs" lebt nur client-lokal (kein DO-State/Broadcast, Reload vergisst, nur der Beauftragende kann „Angekommen" bestätigen) → OP-UMPARK-1 (echte zuweisbare Aufgabe, G-4-Platzierung); (2) Erfolgs-Toast vor Server-Antwort → Phantom-Transit bei stillen Ablehnungen (in OP-UMPARK-1); (3) gefixt: Chronik log bei auftrag.parken „Prozess beendet/pausiert", auch wenn die Transition scheiterte (z. B. beenden aus pausiert) — schreibt jetzt nur, was wirklich geschah; (4) tote „Umparken"-Skill-Hervorhebung (v3-Rest, in OP-UMPARK-1). Entscheidungen (PO, 07-12): G-4 neu (CLAUDE.md + Lastenheft §3): Aufgaben-Platzierung minimiert Kontextwechsel — wer als Nächstes am Fahrzeug arbeitet, übernimmt bevorzugt dessen Neben-/Logistikaufgaben (z. B. Umparken vor der eigenen Folierung); harte Ausnahme QS (Vier-Augen): Ausführende verifizieren nie die eigene Arbeit → OP-QS-6 (Scheduler kennt die Constraint heute nicht — QS rein skill-basiert vergeben). Doku: Lastenheft §3 G-4 + §11.1 OP-UMPARK-1/OP-QS-6, HANDOFF §4 (TODO ✅ + 2 OPs), IDs.md, Roadmap.
  • Branch claude/app-ux-process-review-i4b52d (#445, gemergt) — OP-R7-16 v1: Fahrzeug-Angaben am Auftrag (FIN/Kennzeichen/Beschreibung) (APP_VERSION 0.76.0 → 0.77.0, MINOR). Domäne: Auftrag.fahrzeug = { fin?, kennzeichen?, beschreibung? } (§4.9-konform: Attribute am Auftrag, kein Fahrzeug-Objekt) + finPlausibel() (ISO 3779: 17 Zeichen ohne I/O/Q); fahrzeugAnnahme verlangt die FIN hart (Guard). Handler: auftrag.create/auftrag.checkin/auftrag.update nehmen fahrzeug an (bereinigeFahrzeug trimmt/verwirft Leerstrings; checkin patcht vor der Annahme, update merged Felder + Chronik „Nachgetragen" + D1-Audit); DTO-Passthrough. Client: Annahme-Buchung mit optionaler Fahrzeug-Zeile (Kennzeichen/FIN/Beschreibung); Check-in „Fahrzeug da" mit FIN-Pflichtfeld (vorbefüllt aus der Buchung) + Kennzeichen; Auftrag-Detail zeigt Fahrzeug-Karte + „✎ nachtragen" (Muster Kunde/CRM); Tafel zeigt Kennzeichen-Chip. Entscheidungen: (1) FIN Pflicht spätestens beim Check-in, optional bei Buchung (Fahrzeug oft noch nicht da); generischer liefern-Altpfad bleibt ohne Guard (Edge/Legacy). (2) FIN-Plausibilität warn-only (Sonder-/Altfahrzeuge blockieren nie). (3) Fotos über den bestehenden Annahme-Schritt mit Foto-Pflichtperspektiven (OP-R4-3) — kein zweiter Foto-Pfad. (4) DSGVO: FIN/Kennzeichen personenbezogen → Löschkonzept-Detail bleibt bei OP-CRUD-1/E-CRUD-4. Selbsttest npm run operativ um FIN-Pflicht/-Plausibilität erweitert; Doku: Lastenheft §4.9+§11.1, HANDOFF §4, Funktionsumfang, Roadmap (🔴-W1 erledigt).
  • Branch claude/app-ux-process-review-i4b52d (#444, gemergt) — Korrektur: Pilotkunde = Vest Automotive (OP-VERTRIEB-3) (reine Doku, APP_VERSION unverändert 0.76.0). Nutzer-Korrektur (07-12): Der Probebetrieb-Pilotkunde ist Vest Automotive — die Gründer-Call-Notiz (07-08) nannte zunächst „Festler Automotive". In ops/OP-VERTRIEB-3.md, HANDOFF §4 und Lastenheft §11.6 korrigiert, jeweils mit selbst-dokumentierender Korrektur-Notiz (kein stilles Umschreiben der Call-Notiz); Offene-Punkte.md regeneriert. Erfreuliche Folge für die POC-Vorbereitung: die Tenant-Vorlage server/src/tenants/vest-automotive.ts trägt bereits den Pilotkunden — der Blocker „Tenant-Setup" schrumpft auf Stammdaten-Abgleich (echte Leistungen/Teilschritte/Skills/Schichten/Buchten von Vest gegen die Vorlage prüfen/vervollständigen) statt Neuaufbau.
  • Branch claude/app-ux-process-review-i4b52d (PR folgt) — UX-Review B6: Bedien-Politur — Gantt-Tastatur-Pfad · Hof-Radar responsiv · Textbausteine (OP-TEXTBLOCK-1 v1) (APP_VERSION 0.75.0 → 0.76.0, MINOR, rein client-seitig). Schließt die letzten B6-Randthemen weitgehend: (1) Gantt-Entwurf per Tastatur — verschiebbare Blöcke sind im Entwurfs-Modus fokussierbar (role=button/tabindex, aria-Hinweis); Enter öffnet einen Verschiebe-Dialog (Bucht-Select + datetime-local, auf dasselbe 15-min-Raster gerastert wie der Drag), der das gleiche pinned-Event emittiert — ein Pin-Pfad, keine Parallel-Logik; außerhalb des Entwurfs bleibt Enter der Detail-Klick. (2) Hof-Radar responsiv — das 760px-Design skaliert per transform: scale() (ResizeObserver auf der Board-Spalte, Wrapper trägt Breite/Höhe × Skala, nie >1) auf schmale Container/Tablets; Pixel-Koordinaten der Kacheln bleiben unverändert gültig. (3) Textbausteine am Doku-Gate (OP-TEXTBLOCK-1 v1) — fünf feste Werkstatt-Phrasen als Antipp-Chips über dem Pflicht-Kommentar im Detail-Panel („ohne Befund" · „wie geplant ausgeführt" · „siehe Fotos" · „Kunde informiert" · „Restarbeit notiert"), Antippen hängt mit ·-Trenner an, Tippen bleibt frei — Touch-Terminal-Ergonomie; admin-editierbare Bausteine je Schritt/Aspekt bleiben offener Rest (G-1). Bewusst verbleibend aus B6: Umparken in Belegung/Hof-Radar bleibt Drag-only (Tastatur-Weg existiert über das Umpark-Modal im Detail-Panel) · Diktat = OP-DIKTAT-1. Doku: UX-Review (B6 ✅ weitgehend), HANDOFF §4 (OP-TEXTBLOCK-1 v1), Funktionsumfang.md, design/COMPONENTS.md (B6-Patterns), CHANGELOG, Timesheet. Verifikation: ng build grün · No-Hex grün · check-doc-consistency grün.
  • Branch claude/app-ux-process-review-i4b52d (PR folgt) — Kapazitätstragender Klärungs-Arbeitsschritt (OP-R3-1-Folge) (APP_VERSION 0.74.0 → 0.75.0, MINOR). Die im Engine-PR (#440) bewusst offen gelassene Folge: die Klärungsarbeit selbst (Kunde anrufen, begutachten, abstimmen) ist jetzt opt-in als geplanter Schritt einplanbar — sie kostet damit sichtbar Kapazität (True-North-Frage 1), der Klärende ist nicht doppelt verplanbar, und die Verantwortung steht im Plan. Gebaut: (1) Katalog-Template ts-klaerung (Skill skill-klaerung — der seit OP-R3-1 reservierte Skill hat seinen ersten Verwender; keine Bucht-Bindung, Doku-Aspekte als Klärungs-Leitfaden, Doku-Pflicht beim Erledigen = Klärungs-Doku) in der Tenant-Vorlage + Migration v19 (SCHEMA_VERSION 18→19, zieht das Template idempotent in Bestands-Tenants nach; Mitarbeiter-Skills bewusst NICHT migriert — wer klären darf, ist Stammdaten-Pflege). Seed: Julian trägt skill-klaerung (Niveau 2), damit frische Tenants sofort planbar sind. (2) Domäne: klaerungsArbeitsInstanz() (pure, Guards: offener Klärfall · max. eine offene Klärung · Dauer 5–480 min) + offeneKlaerungsInstanz() — Instanz in der aktuellen Auftrags-Phase, Dauer über das bewährte nacharbeitMin/zusatzSchritte-Muster (TS-Scheduler + CP-SAT, kein Solver-Redeploy). (3) Handler auftrag.klaerungEinplanen (+ REOPT_EVENT + D1-Audit klaerung.eingeplant): Einzelplan sofort; ist er nicht machbar, bleibt der Schritt vorgemerkt und die Chronik nennt die wahrscheinliche Ursache („Hat ein Mitarbeiter den Skill Klärung?"). (4) Client: geteilte klaerung-einplanen.component.ts — „⏱ Klärung einplanen …" mit Presets 15/30/60 min (bewusst grob: Schätzung statt Scheingenauigkeit) in Konflikte & Klärfälle + Detail-Panel; eingeplante Klärung zeigt sich als Badge (und ganz normal in Planung/Gantt/„Meine Arbeit"). Entscheidungen: Opt-in statt Automatik (Minutensachen bleiben formlos) · Migration nur Katalog, nicht MA-Skills · Warten-auf-Kunde (verstrichene Zeit ≠ Arbeitszeit) bewusst nicht modelliert — bei Bedarf eigene Folge. Verifikation: test:do-migrations (v19 ergänzt genau einmal + idempotent) grün · npm run operativ um Klärungs-Arbeitsschritt-Asserts erweitert (planbar · Template geseedet · Seed-MA mit Skill · Doppel-Guard · ohne-Klärfall-Guard) grün · Server-tsc grün · ng build + No-Hex + check-doc-consistency grün. Doku: Lastenheft §5.1 (Folge ✅), Operative-Durchgaengigkeit.md, Funktionsumfang.md, Tests.md, CHANGELOG, Timesheet.

2026-07-11

  • Branch claude/app-ux-process-review-i4b52d (PR folgt) — Session-Wrap-up: Log-Hygiene + Stand nachgezogen (reine Doku, APP_VERSION unverändert 0.74.0, OP-PM-2). Nach den sechs Merges des UX-Review-Zyklus (#434, #436–#440): (1) CHANGELOG.md: 16 veraltete „(PR folgt)"-Marker durch echte PR-Links ersetzt — die beiden Session-Einträge (#439/#440, inhaltlich zugeordnet) plus 14 eindeutige Ein-PR-Branches älterer Sessions (Mapping über die GitHub-API, Branch→gemergter PR); bewusst belassen: ~42 Marker von Mehrfach-PR-Branches/älteren Sessions, deren Zeile→PR-Zuordnung nicht mechanisch eindeutig ist (kein Rate-Raten im Audit-Trail). (2) HANDOFF.md §2: neue Kompakt-Zeile „UX-Review-Zyklus 07-11 + Klärungs-Engine" (v0.70.0→0.74.0, alle 6 Empfehlungen + OP-R3-1-Abschluss, größter offener Hebel OP-AUTH-1); Auslastungs-Quote-Zeile von „auf Branch" auf „auf main (#433)" korrigiert. (3) Roadmap.md: OP-ONBOARD-1 → Slice 1 ✅. (4) npm run smooth-logs sauber (keine Dubletten/Konflikt-Marker). Verifikation: check-doc-consistency grün.
  • Branch claude/app-ux-process-review-i4b52d (#440) — Klärungs-Workflow-Engine: geroutetes Klärfall-Lösen (OP-R3-1-Folge, Lastenheft §5.1) (APP_VERSION 0.73.0 → 0.74.0, MINOR). Schließt den letzten benannten OP-R3-1-Rest („volle Klärungs-Engine") und Review-Befund B2 vollständig. Gebaut (Server, operativ/auftrag.ts + party/leitstand.ts): (1) Melden = echte Unterbrechung — neue pure pausiereLaufendeSchritte() pausiert alle laufenden Schritte (mit Namen für die Chronik), KlaerfallKontext erfasst den auslösenden Schritt (teilschrittInstanzId, aus „Meine Arbeit" mitgesendet). (2) Geroutetes Lösen — neue pure, testbare loeseKlaerfallMitRoute() mit KlaerfallRoute = zurueck | qs | schritt | abbruch: zurueck (Kontext weg, Schritte bleiben pausiert → Weiterarbeit über ▶ mit allen Guards) · qs (offene Nicht-QS-Phase-Schritte werden Klärungs-übersprungen — neue ueberspringeFuerKlaerung(), die als sanktionierte OP-R3-5-Ausnahme auch Pflicht- und pausierte Schritte überspringen darf; bleibt nichts offen → fertigstellen, Auftrag landet in der Endkontroll-Queue) · schritt (doppelt interpretiert: offenes Ziel = „ab hier weiter" mit Klärungs-Skip des Offenen davor; Katalog-Ziel = Einschub-Wiederholung als neue -KL-Instanz über das bewährte nacharbeit-/zusatzSchritte-Muster + einzelplan, kein Solver-Redeploy) · abbruch (delegiert an stornieren). Lösungs-Kommentar ist Pflicht (§5.1 „Dokumentieren & Kommentieren"). (3) auftrag.klaerfall ist jetzt REOPT_EVENT und schreibt D1-Audit (klaerfall.gemeldet/klaerfall.geloest mit Route/Ziel) — beides fehlte. Abwärtskompatibel: loesen ohne route = zurueck. Client: neue geteilte klaerfall-loesen.component.ts (Routen-Chips mit Hinweis je Weg + Ziel-Picker „ab hier weiter"/„einschieben/wiederholen" + Pflicht-Kommentar) ersetzt den nackten „✓ Klärfall lösen"-Button in Konflikte & Klärfälle und im Detail-Panel (ein Server-Pfad, nichts dupliziert); „Meine Arbeit" sendet die Schritt-Instanz beim Melden mit. Entscheidungen: Klärfall-Bearbeitung bleibt ohne eigenen kapazitäts-tragenden Arbeitsschritt (Skill „Klärung" weiter reserviert — bewusste Folge); Melden pausiert alle laufenden Schritte des Auftrags (Unterbrechung gilt dem Auftrag). Verifikation: npm run operativ um den Klärungs-Engine-Selbsttest erweitert (melden-pausiert · Kommentar-Pflicht · zurück · QS-Sprung · ab-hier-weiter · Einschub planbar · Abbruch terminal) grün · test:nacharbeit grün (zusatzSchritte-Regression) · Server-tsc grün · ng build + No-Hex + check-doc-consistency grün. Doku: Lastenheft §5.1 (Umgesetzt-Block) + §11 OP-R3-1 (Engine ✅), Operative-Durchgaengigkeit.md (neuer Lösen-Vertrag), design/WORKSPACES.md, UX-Review (B2 ✅ vollständig), Funktionsumfang.md, Tests.md, HANDOFF §4 (Folge-OP ✅), CHANGELOG, Timesheet.
  • Branch claude/app-ux-process-review-i4b52d (#439) — UX-Review E4: True-North-Kacheln komplett — „Nächste freie Kapazität" je Leistung + „Standorte" im Überblick (APP_VERSION 0.72.0 → 0.73.0, MINOR). Schließt die letzte offene Review-Empfehlung: die Top-3-Antworten stehen jetzt gebündelt in der Überblick-Sidebar (Frage 1 Auslastungs-Quote #433 · Frage 3 Kapazitäts-Kachel neu · Frage 2 Standorte-Kachel neu). Gebaut: (1) Server — neue reine Funktion naechsteKapazitaeten() (server/src/insights/insights.ts): je aktiver Leistung EIN ASAP-Dry-Run des TS-Schedulers (scheduleLeistung, kein Angebots-Scan) → frühestmögliche Anlieferung („ab wann wieder Platz?") + früheste Abholbereitschaft; defensiv (kaputte Leistung reißt nie den Broadcast, grund statt Throw); Entscheidung Performance: im DO über Plan-Stempel + Stunden-Raster gecacht (kapazitaetCache) — nicht jeder Broadcast rechnet neu, „ab wann" wandert trotzdem mit der Zeit; nichts persistiert (D-2). DTO insights.kapazitaet. (2) Client — Überblick-Sidebar: Kachel „Nächste freie Kapazität" (je Leistung „ab morgen 08:00" via fmtRelative, Tooltip mit Abholbereitschaft; „kein Fenster" amber mit Grund) + Kachel „Standorte" (grün „✓ alle verortet" bzw. amber „⚠ N ohne Standort →" als Link in die Konflikte — Rot bleibt Warnungen). (3) Selbsttest test:insights erweitert (Kachel: Anlieferung ≥ ab-Zeitpunkt · abholbereit ≥ Anlieferung · unbekannte Leistung → Grund). Sanity-Checkliste Frage 3 → ✅ (erste der drei Leitfragen auf Grün; Ausbau: proaktive Kunden-Angebote OP-R9-6, Kachel-Klick → vorbefüllte Annahme). Doku: UX-Review §4 (E4 ✅ — alle sechs Empfehlungen umgesetzt), Sanity-Checkliste (F3 ✅), Funktionsumfang.md, CHANGELOG, Timesheet. Verifikation: Server-tsc + test:insights + npm run operativ grün · ng build grün · No-Hex grün · check-doc-consistency grün.
  • Branch claude/app-ux-process-review-i4b52d (#438) — UX-Review E6 / OP-ONBOARD-1 Slice 1: Onboarding „Kurz erklärt" je Workspace (APP_VERSION 0.71.1 → 0.72.0, MINOR — neues Feature, rein client-seitig). Gebaut: (1) onboarding-hinweis.component.ts — „Kurz erklärt: "-Karte beim Erstbesuch jedes Workspace, über dem Inhalt gerendert (eine Einbaustelle in der Shell, kein Change je Page): ein Satz „was ist hier?" + 2–3 konkrete erste Schritte in Werkstattsprache (gespeist aus den Rail-Untertiteln + Kern-Aktionen, 14 Workspaces abgedeckt), Workspace-Signaturfarbe als Akzent, „✓ Verstanden" blendet aus. (2) onboarding.service.ts — Gesehen-Status pro Gerät (localStorage tk-onboarding-gesehen, Signals; Privatmodus-fail-open: Hinweise erscheinen dann je Session). (3) „?"-Button im Header holt die Karte für den aktiven Workspace jederzeit zurück (aria-Label, gleiche Bedien-Sprache wie Theme-Toggle). Entscheidungen: bewusst Text-Karten statt verankerter Coachmark-Pfeile (Element-Anker brechen bei jedem Layout-Umbau; Karte bleibt wartungsarm) — Vertiefung/Fragen übernimmt der In-App-Assistent (OP-AI-4); Progressive Feature-Freischaltung + geführte Kern-Flow-Tour bleiben offen (OP-ONBOARD-1 Rest; der Werker-Terminal-Modus aus OP-UX-7 ist bereits eine manuelle Vorstufe der Staffelung). Damit sind alle sechs UX-Review-Empfehlungen adressiert (E1–E3 #436 · E5 #437 · E6 hier · E4 🟡 Rest = Kapazitäts-Kachel OP-R9-10/-6). Doku: UX-Review §4 (E6 ✅ v1), HANDOFF §4 (OP-ONBOARD-1 Slice 1 ✅), Funktionsumfang.md, design/COMPONENTS.md (Pattern „Onboarding Kurz erklärt"), CHANGELOG, Timesheet. Verifikation: ng build grün · No-Hex grün · check-doc-consistency grün. (Stolperstein erneut: deutsches Schließ-Anführungszeichen in Attribut-Bindings → aus dem aria-Label entfernt.)
  • Branch claude/app-ux-process-review-i4b52d (#437) — UX-Review E5 „Politur": token-gestylte Dialoge statt nativer Browser-Dialoge + tote Komponenten entfernt (APP_VERSION 0.71.0 → 0.71.1, PATCH — Tweaks, keine neue Funktion). (1) Native Dialoge ersetzt (Befund B6): neue geteilte Komponente client/src/app/leitstand/modal-dialog.component.ts (app-modal-dialog, Muster verallgemeinert aus Planung „Entwurf verwerfen?" OP-R8-15: Fog-Scrim + zentriertes Panel, Esc/Scrim bricht ab, optionales Pflicht-Eingabefeld mit Auto-Fokus + Enter, gefahr = rot umrandeter Bestätigen-Button) — ersetzt confirm() (Mitarbeiter-/Teilschritt-Archivieren), prompt() (neue Teilschritt-Vorlage/Leistung, Skill umbenennen); die alert()-Duplikat-Warnungen (Skill-Name vergeben) sind jetzt Warn-Toasts (nicht-blockierend, bestehender ToastService). Entscheidung/Anti-Pattern in design/COMPONENTS.md verankert: keine neuen confirm()/prompt()/alert(). (2) Tote Komponenten gelöscht (Befund B7): FlowBandComponent (v2-Pipeline-Band, durch Hof-Radar + Aufträge-Fluss überholt) und InsightsPanelComponent („Lage auf einen Blick", durch Überblick-KPI-Kacheln inkl. Auslastungs-Quote #433 überholt) — beide nirgends referenziert (Grep-verifiziert), per Git-Historie wiederherstellbar; COMPONENTS.md-Abschnitt entsprechend umgeschrieben. (3) /bild-schutz-Entscheidung: bleibt bewusst Deep-Link-Demo ohne Rail-Eintrag (OP-QS-2 Phase 1, dockt später an das R4-Foto-Upload-Feld — im Komponenten-Kommentar dokumentiert). Bewusst offen aus B6 (nicht Teil dieser Politur): Tastatur-Alternative für Drag&Drop, Hof-Radar-Responsivität, Touch-Kommentar-Ergonomie (OP-TEXTBLOCK-1/OP-DIKTAT-1). Doku: UX-Review §4 (E5 ✅), design/COMPONENTS.md (Modal-Dialog-Pattern neu, Flow-Band als entfernt markiert), CHANGELOG, Timesheet. Verifikation: ng build grün · No-Hex grün · check-doc-consistency grün · Grep: 0 native Dialoge im Client (einzige confirm-Treffer sind Methodennamen des Repark-Flows).
  • Branch claude/app-ux-process-review-i4b52d (#436) — OP-UX-7 umgesetzt: Werker-Terminal-Modus · Klärfall am Schritt · zentrale Label-Sprache (APP_VERSION 0.70.0 → 0.71.0, MINOR). Die drei Top-Empfehlungen aus dem UX-Review (#434) gebaut, rein client-seitig (kein Server-/Solver-/Schema-Change): (E1) Werker-Terminal-Modus — Rail-Footer-Toggle „⬣ Werker-Modus" (localStorage tk-werker-modus, Muster Theme-/Feedback-Toggle) reduziert die Navigation auf Meine Arbeit · Tafel · Qualität und springt beim Aktivieren nach /meine-arbeit; Entscheidung: bewusst Geräte-Einstellung ohne Security-Gate (Deep-Links bleiben erreichbar) — echte Rollen/Login bleiben OP-AUTH-1, dies ist die Vorstufe zur Mitarbeiter-Ansicht (OP-R9-4). (E2) „⚠ Klärfall" je Schritt-Karte in „Meine Arbeit" (nur produktiv Zugeteilte, kein offener Klärfall): Inline-Form mit Grund-Presets (Material fehlt · Schaden entdeckt · Rückfrage Kunde/Leitung · Maschine/Werkzeug defekt) + Pflicht-Freitext + eskalieren → bestehender Server-Pfad auftrag.klaerfall, Schrittname als Grund-Präfix (Klärfall bleibt Auftrags-Kontext, kein Modell-Change); aktiver Klärfall = rote Badge, Lösen bleibt im Panel/Konflikte. (E3) Neues zentrales Label-Modul client/src/app/leitstand/labels.ts (Muster phase.ts): Auftrag-Status (kanonisch „Fahrzeug angeliefert") + Badge-Farben, Teilschritt-Status („wartet/läuft/pausiert"), Terminklasse (Title-Case „Garantiert/Zieltermin/Best-Effort"), Aktions-Labels — ersetzt die Inline-Maps in Tafel/Detail-Panel/Gantt/Aufträge/Annahme/Meine Arbeit; Entscheidungen: Tafel-archiviert rot → neutral (Rot nur für Warnungen), Mitarbeiter-Verfügbarkeit „Verfügbar" → „Frei" (deckungsgleich mit „○ Frei melden"), Gantt-Block-Farben (--tk-gantt-*) bleiben bewusst kontext-lokal. Doku: UX-Review §4 (E1–E3 ✅, E4 🟡 — Auslastungs-Quote kam parallel via #433), ops/OP-UX-7.md erledigt + Offene-Punkte.md generiert, Funktionsumfang.md (3 Zeilen), design/COMPONENTS.md (3 neue Patterns), HANDOFF §4, Timesheet. Verifikation: ng build grün (Node 22.23; Budget-Warnung Bestand) · No-Hex-Gate grün · check-doc-consistency grün · Grep bestätigt 0 verbliebene Alt-Label-Maps.
  • Branch claude/app-ux-process-review-i4b52d (#434) — UX- & Prozess-Review der Gesamt-App (neu: docs/betrieb/UX-Review-2026-07.md + OP-UX-7) (reine Doku, APP_VERSION unverändert). Nutzer-Auftrag: Experten-Review „verständlich, konsistent, leicht bedienbar, intuitiv — ist das ein richtig cooles Meisterwerk?" aus Sicht UX + Prozess-Automatisierung für stark anzuleitende Akteure. Urteil: außergewöhnlich reifes Werkstück, noch kein Meisterwerk — Fundament auf Meisterwerk-Niveau (harte Zustandsmaschine + QS-Gate, Next-Task-Push „Meine Arbeit", „Vorschlag statt Zwang"-Automatisierung, Ehrlichkeit als UX-Prinzip, Design-Disziplin ohne Hex-Verstöße; Stärken S1–S6), aber sieben Befunde B1–B7: B1 keine Identität/Rollen (jeder agiert als jeder, alles für alle sichtbar; OP-AUTH-1) · B2 Klärfall nicht im Werker-Flow („Meine Arbeit" ohne Klärfall-Button; dokumentierter Klärungs-Workflow §5.1 ungebaut) · B3 True North 3×🟡/0×✅ (Antworten verstreut) · B4 vier belegte Label-Inkonsistenzen („angeliefert"/„Fahrzeug angeliefert" · „ziel"/„Zieltermin" · „wartet"/„geplant" · „Frei"/„Verfügbar") · B5 kein Onboarding (OP-ONBOARD-1) · B6 Bedienränder (Drag&Drop ohne Tastatur, Hof-Radar fix 760px, native confirm()/alert()) · B7 verwaiste Komponenten (FlowBandComponent/InsightsPanelComponent ungenutzt), kontrolliert-Status faktisch übersprungen. Entscheidungen: Empfehlungen E1–E6 nach Wirkung÷Aufwand priorisiert; die Top-3 (Werker-Terminal-Modus · Klärfall-Button in „Meine Arbeit" · Label-Konsolidierung nach phase.ts-Muster) als neuer ops/OP-UX-7.md (audience produkt+technik) gebündelt — E4 bleibt bei OP-R9-10, E6 bei OP-ONBOARD-1. Sanity-Checkliste um externe Bestätigung der 🟡-Bewertungen ergänzt; Landkarte + Offene-Punkte.md (generiert) nachgezogen.
  • Branch claude/next-steps-pot5hb (#433) — Zeitbasierte Auslastungs-Quote als KPI-Kachel (Sanity-Checkliste Frage 1, APP_VERSION 0.69.0 → 0.70.0 MINOR). Nutzer-Auftrag: „Was steht als nächstes an?" → aus den offenen Punkten die Spur Auslastungs-Quote KPI gewählt (Sanity-Checkliste North-Star-Frage 1 stand auf 🟡: „explizite % belegte vs. verfügbare Bucht-/MA-Zeit über Zeitraum als KPI/Dashboard-Kachel" fehlte). Gebaut: (1) reine, testbare Funktion auslastungsQuote() in server/src/insights/insights.ts — je Ressourcengruppe (Mitarbeiter · Buchten) der Anteil verplanter an verfügbarer Zeit über ein Fenster; kappt belegt ∩ verfügbar (kein Über-100-%-Artefakt), summiert überlappungsfrei (merge/subtract aus time.ts). Ergänzt den bestehenden Snapshot auslastung() (belegte Buchten jetzt) um die Zeit-Achse. (2) DO-Verdrahtung (server/party/leitstand.ts): Fenster = Planungszeitraum (dieselbe Logik wie die Gantt-Ausfallbänder); MA-Verfügbarkeit via mitarbeiterAvailability (Schicht − harte Abwesenheit), MA-Belegung aus verplanten Schritt-Intervallen; Bucht-Verfügbarkeit = offene Werkstattzeit (Envelope aller MA-Schichten) − Sperre/Wartung (bayAusfall) — bewusste Entscheidung: Buchten sind sonst 24/7, das wäre als Nenner irreführend; Bucht-Belegung aus Schritt-Bucht-Intervallen. Nichts gespeichert (D-2, rein abgeleitet). (3) Client: insights.auslastungsQuote im State-Typ + KPI-Kachel oben in der Überblick-Sidebar (overview.component.ts) mit Mini-Balken je Gruppe (Prozent · belegt/verfügbar h · Ressourcenzahl · Fenster in Tagen); Ampel-Farbe ohne Rot (dim < 60 % · Brand-Cyan 60–90 % · Amber > 90 %, Rot bleibt Warnungen — Design-Prinzip). Verifikation: test:insights um Quote-Assertions erweitert (Kappen belegt→verfügbar: 540/960 = 56 %, Bucht 300/480 = 63 %) grün; alle Server-Selbsttests (spike/operativ/replan/solve/test:teilplan/test:ausfall/test:kosten) grün; Server- + Client-tsc sauber (ng build nur wegen Node 22.22.2 < 22.22.3 lokal nicht ausführbar — CI baut). Offen (nachgezogen in Sanity-Checkliste): wählbarer Zeitraum (heute/Woche) statt fixem Planungsfenster, Historien-/Trend-Sicht. Doku: server/src/insights/insights.ts+insights-demo.ts, server/party/leitstand.ts, client/.../services/leitstand.service.ts+pages/overview.component.ts, server/src/version.ts, docs/betrieb/Sanity-Checkliste.md+Tests.md, HANDOFF §2, CHANGELOG, Timesheet.
  • Branch claude/op-audience-field (#432) — audience-Pflichtfeld für ops/*.md (OP-DOCS-11-Nachtrag) (Tooling/Doku, APP_VERSION unverändert). Nutzer-Auftrag: „Bei den OP-/Diskussionspunkten sollen wir immer entscheiden, wer die Audience ist — Technik, Produkt, Stakeholder, Legal." Gebaut: neues Pflichtfeld audience im ops/*.md-Frontmatter (Array, Werte technik/produkt/stakeholder/legal, mehrere möglich) — Standard-Entscheidung: multi-select statt single-value, da reale OPs oft mehrere Zielgruppen betreffen (z. B. Produkt und Legal). scripts/gen-ops.mjs validiert hart (fehlt/unbekannter Wert → Build bricht, wie bei status/prio), zeigt eine neue Audience-Spalte + Audience-Summenzeile in docs/betrieb/Offene-Punkte.md. scripts/sync-ops-issues.mjs setzt passende audience:*-Issue-Labels + Body-Zeile. Vier Pilot-OPs nachgezogen: OP-DOCS-11 [technik], OP-VERTRIEB-1 [produkt, stakeholder], OP-VERTRIEB-2 [produkt, stakeholder, legal], OP-VERTRIEB-3 [produkt, stakeholder]. Proaktives Flagging (CLAUDE.md §Compliance): OP-VERTRIEB-2s Legal-Bezug (externes Akquise-Tool mit Lead-Kontaktdaten Dritter, DSGVO DE/AT/CH) war im Risikoregister noch nicht erfasst — als neue Zeile RISK-19 ergänzt (offen, Score 4, verweist zurück auf OP-VERTRIEB-2 als Klärungsort). ops/README.md dokumentiert die vier Werte + Begründung (Legal-OPs verlangen Blick ins Risikoregister). Nebenbei behoben: toter Link in OP-Management-Gold-Standard.md (Offene-Punkte ohne .md-Endung — check-doc-consistency.sh flaggte ihn beim Gegenprüfen). Verifikation: gen-ops.mjs + check-doc-consistency.sh grün, docs-site Build warnungsfrei. Kein Code-/Solver-Change, kein App-Bump. Doku: ops/README.md+_Vorlage.md+4 Piloten, scripts/gen-ops.mjs+sync-ops-issues.mjs, docs/konventionen/OP-Management-Gold-Standard.md, docs/betrieb/Offene-Punkte.md (generiert), docs/betrieb/Risikoregister.md (RISK-19, neu), HANDOFF §4, CHANGELOG, Timesheet.
  • Branch claude/op-management-gold-standard (#430) — OP-Management-Gold-Standard: ops/*.md + GitHub-Issues-Spiegel (OP-DOCS-11) (Tooling/Doku, APP_VERSION unverändert). Nutzer-Auftrag: Diskussion zu offenen Punkten — GitHub Issues wären fachlich passend, aber für Nicht-Techniker nicht intuitiv, Eigenbau unerwünscht; Frage nach Gitbook oder Alternative; harte Anforderung: Claude Code und Codex sollen sauber damit arbeiten (umsetzen, abhaken). Empfehlung gegeben + umgesetzt: GitHub Issues + optionales Projects-Board (vorhandener Baustein, beide Agenten haben native GitHub-Tool-Unterstützung) statt Gitbook (reines Doku-Rendering-Tool, kein Status/Board/Diskussions-Modell — wäre dritte Quelle) oder Linear/separates SaaS (neuer Vendor/Kosten). Löst damit den seit 06-28 offenen OP-DOCS-11 (Optionsanalyse A/B/C/D, Empfehlung C Hybrid war schon dokumentiert, jetzt entschieden + gebaut). Gebaut: (1) ops/<ID>.md — ein Markdown-File je offener Punkt (Frontmatter id/title/status/prio/bereich/bezug/detail), git-nativ konfliktfrei bei den vielen parallelen Claude-/Codex-Branches dieses Repos; Format-Doku ops/README.md + Vorlage ops/_Vorlage.md. (2) scripts/gen-ops.mjs — generiert docs/betrieb/Offene-Punkte.md (nach Status gruppierte Tabellen, sortiert nach Priorität), hart fehlschlagend bei kaputtem Frontmatter (Muster wie gen-glossar.mjs); npm run gen-ops in server/. (3) scripts/sync-ops-issues.mjs + .github/workflows/sync-ops.yml — spiegelt ops/*.md einseitig (Repo → GitHub) nach Issues (Label op-sync), idempotent über Titel-Suche, kein Zurückschreiben in die Dateien; läuft mit dem Standard-GITHUB_TOKEN der Action bei jedem Push auf ops/**. (4) Pilot: vier OPs migriert (OP-DOCS-11 selbst, OP-VERTRIEB-1/-2/-3 aus #426/#427) — zwei davon (OP-VERTRIEB-2/-3, Status offen) live als GitHub Issues erstellt (#428, #429, lokal getestet über die MCP-GitHub-Tools, da der Sandbox-GITHUB_TOKEN kein direktes REST-PAT ist — die Action bekommt ein echtes). (5) docs/konventionen/OP-Management-Gold-Standard.md (neu) — das Muster generisch für alle drkv-Projekte dokumentiert (Problem/Alternativen-Analyse, 3-Schichten-Architektur inkl. Mermaid, Rollout-Checkliste). CI: doc-consistency-Job bekommt actions/setup-node + zwei neue, nicht-blockierende Schritte (node scripts/gen-ops.mjs hart, Diff-Check warnt bei Staleness — Job war schon vorher nicht in ci-gate.needs). Entscheidungen: (a) Migration der ~150 Bestands-OPs (HANDOFF §4/Lastenheft §11) bewusst nicht Teil dieses Schritts — neue OPs entstehen ab sofort im neuen Format, Bestand wandert schrittweise bei Berührung (Risiko/Aufwand einer Big-Bang-Migration vermieden, Präzedenz OP-DOCS-13 nicht-invasiver Rollout); (b) zwei near-identische OP-DOCS-11-Dubletten in HANDOFF.md §4 (Union-Merge-Artefakt) beim Aktualisieren konsolidiert. Verifikation: gen-ops.mjs + check-doc-consistency.sh grün, docs-site Build warnungsfrei, Mermaid-Diagramm via MCP valid:true. Doku: ops/README.md+_Vorlage.md+4 Piloten (neu), scripts/gen-ops.mjs+sync-ops-issues.mjs (neu), .github/workflows/sync-ops.yml (neu), docs/konventionen/OP-Management-Gold-Standard.md (neu), docs/betrieb/Offene-Punkte.md (generiert, neu), docs/fachlich/Lastenheft.md §11.10, docs/konventionen/IDs.md+Register.md+docs/README.md, server/package.json, .github/workflows/ci.yml, HANDOFF §2+§4, CHANGELOG, Timesheet.

2026-07-08

  • Branch claude/vorteilsrechner-prospects-0hm08a (#427) — Vorteilsrechner als Landingpage für Interessenten (OP-MARKET-2) (Doku-Site, APP_VERSION unverändert 0.69.0). Nutzer-Auftrag: „Vorteilsrechner für Interessenten einbauen — Akquise-wie? Hubspot?". Befund: docs/produkt/Produkt-und-Marketing.md §3 hatte bereits eine ausformulierte Rechen-Logik-Skizze („für ein späteres Tool") inkl. Eingangsdaten und Payback-Formel — aber kein Tool. Gebaut: neue Docusaurus-Seite docs-site/src/pages/vorteilsrechner.js (rein client-seitig, React, self-contained wie index.js — Theme-CSS-Variablen, kein Hex): 4 Eingaben (Fahrzeuge/Woche, Ø Auftragswert, Marge, Lösungskosten/Monat) → Δ Fahrzeuge/Woche, Δ Umsatz/Monat, Δ Deckungsbeitrag/Monat, Payback in Monaten, jeweils mit konservativer Bandbreite (Verbesserungsfaktor 8–22 %, erwartet 15 %) statt Scheingenauigkeit; Link von der Startseite (index.js). Entscheidung (Nutzer, per Rückfrage): Scope = Quick-Rechner (nicht der vollständige Rechner aus §3.1 mit allen Eingangsdaten); Akquise-Anbindung (Hubspot) bewusst noch offen gelassen — Nutzer hat sich noch nicht zwischen Hubspot-Formular-Embed / Hubspot-Forms-API / eigenem Kontaktformular entschieden. Seite geht deshalb v1 ohne Lead-Erfassungs-Backend live (nur mailto:-Kontaktlink als Platzhalter) — neuer offener Punkt OP-MARKET-2, damit die Anbindung nicht verloren geht. Verifikation: npm run build (Docusaurus, docs-site) grün, neue Seite kompiliert fehlerfrei. Kein Code-/Solver-/Token-Change, kein App-Version-Bump (Doku-Site-only, Präzedenz #205/#206 u. a.). Registriert in docs/produkt/Produkt-und-Marketing.md §3, docs/konventionen/IDs.md, docs/konventionen/Register.md, HANDOFF §2+§4, CHANGELOG, Timesheet.
  • Branch claude/vorteilsrechner-prospects-0hm08a (Nachtrag, PR #427) — OP-ID-Reconciliation mit #426. Beim Aktuellhalten des Branches gegen main zeigte sich: #426 (parallel gemergt, „Vertriebsthemen aus Meeting als OP-VERTRIEB-1..3") hatte inzwischen genau denselben Rechner bereits als OP-VERTRIEB-1 dokumentiert (Anlass: Gründer-Call vom selben Tag) — der oben neu erfundene OP-MARKET-2 war damit redundant. Aufgelöst zugunsten der autoritativen Gründer-Call-IDs: OP-VERTRIEB-1 in HANDOFF §4 + Lastenheft §11.6 auf ✅ v1 umgesetzt gesetzt (Entscheidung „Web-Tool vs. Sales-Deck/Excel" → Web-Tool); die Akquise-/Lead-Erfassungs-Frage verweist jetzt auf das bereits existierende OP-VERTRIEB-2 („Akquise-/Orga-Tool — Build vs. Buy, z. B. Hubspot", kein Code bis (a)–(c) entschieden — betrifft den separaten Lead-Tracker für 50–100 Anbahnungen, nicht das Rechner-Formular selbst). OP-MARKET-2 zurückgezogen; OP-VERTRIEB-1/-2/-3 zusätzlich in IDs.md/Register.md registriert (fehlten dort nach #426 noch — Lücke mitgeschlossen). Code-Kommentar in vorteilsrechner.js + Callout in Produkt-und-Marketing.md §3 entsprechend angepasst. check-doc-consistency.sh grün. Kein App-Bump.

2026-07-07

  • Branch claude/documentation-structure-ux-qzof50 (Folge nach #421, PR folgt) — Kernaussage-Korrekturen (CodeRabbit-#421-Review) — OP-DOCS-9/-13 (Doku, APP_VERSION unverändert 0.69.0). Zwei in Phase 4 (#421) neu eingeführte Kernaussage-Blöcke waren inhaltlich zu stark/veraltet (CodeRabbit, je Major): (1) Audit-Log.md — sagte „in separater D1 (EU)", der finale Zuschnitt (E-TENANT-1 = C) ist aber DO-SQLite je Tenant + D1 nur als Tamper-Anker (Chain-Kopf); korrigiert → jetzt deckungsgleich mit §2 des Docs. (2) Offline-PWA.md — „Fotos nie verloren" überzeichnet (die Garantie hängt an funktionierender IndexedDB-Queue; uploadFoto() meldet sonst statt still zu verlieren) → auf konditional abgeschwächt. Nachzug: #421-Referenzen im Phase-4-CHANGELOG/Timesheet-Eintrag finalisiert. Verifikation: check-doc-consistency.sh grün. Lehre: pyramidale TL;DR-Blöcke gegen die Doc-eigene Detailsektion gegenprüfen (OP-DOCS-9).
  • Branch claude/documentation-structure-ux-qzof50 (Folge nach #420, #421) — OP-DOCS-13 Phase 4: Lesbarkeit — Kernaussage-Blöcke + HANDOFF-§4-Entdichtung (Worst-Offender) (Doku, APP_VERSION unverändert 0.69.0). Nutzer-Wahl „Worst-Offender + Kernaussage". (1) Pyramidale Kernaussage-Blöcke (> **Kernaussage.**) oben in 7 schweren Docs: Lastenheft.md, HANDOFF.md + die 5 architektur/-Docs ohne TL;DR (Akademie, Audit-Log, Fahrzeug-3D, Kosten, Offline-PWA) — wer nach dem ersten Absatz aufhört, hat das Wesentliche (Minto). (2) HANDOFF §4 entdichtet: Befund — §4 war eine union-Merge-Dublettenhalde (226 OP-Bullets, nur ~116 distinkte OPs; OP-AUDIT-1 ×9, OP-TENANT/OP-BACKUP-1 ×7 …). 19 byte-identische Dubletten-Zeilen entfernt (226 → 207) — sicher & verifiziert (jede entfernte Zeile existiert weiter, kein Info-Verlust; OP-PM-2-Glätten). (3) Format-Konvention in agents.md §6.2: neue §4-Einträge kurz + strukturiert (Titel + Status), keine Mega-Zeilen (Tiefe ins Owning-Doc). Verifikation: check-doc-consistency.sh grün (keine toten Links durch die Dedup). Bewusst offen: die near-identischen Mega-Zeilen (z. B. die zwei ~15k-Zeichen-OP-OPT-1-Kopien, 15250 vs 15284) sind nicht byte-identisch → brauchen eine gezielte, per-OP verifizierte Glätt-Runde (eigener PR, um den append-only Audit-Trail nicht zu riskieren). Nachzug: #420-Ref im Vor-Eintrag finalisiert. Offen: §4-Vollglättung · Phase 5 (OP-Register, OP-DOCS-11).
  • Branch claude/documentation-structure-ux-qzof50 (Folge nach #419, #420) — OP-DOCS-13 Phase 3b Teil B: Konsistenz-Gate gehärtet (statt README-Generierung) (Tooling/Doku, APP_VERSION unverändert 0.69.0). Entscheidung (Nutzer „Check härten"): Beim Grounding zeigte sich, dass check-doc-consistency.sh §4 bereits prüft, dass jede docs/**-Datei in der README-Landkarte verlinkt ist — die Haupt-Drift war abgesichert. Volle Generierung (~38-Doc-kurz:-Migration + kuratierte README-Tabellen durch generierte ersetzen) hätte nur marginalen Zusatznutzen; daher Gate härten statt generieren (Einfachheit, die kuratierte Landkarte bleibt). Gebaut (scripts/check-doc-consistency.sh): (a) 3-Ebenen-Glob — verschachtelte Docs (betrieb/meetings/, künftige Unterordner) werden jetzt geprüft, _-Partials ausgenommen; (b) _category_.json-Check für jeden md-Ordner (bis 3 Ebenen); (c) sidebar_position-Eindeutigkeit je Ordner (hätte den Tests/Timesheet-40/40-Clash gefangen); (d) Zielgruppen-Parität glossar.mjs ZIELGRUPPEN == Lesepfade.md-Rollen-Anker (hätte den 4-vs-7-Drift gefangen; gen-glossar hard-failt sonst). docs/betrieb/Tests.md nachgezogen. Verifikation: bash -n + Lauf grün (0 Findings); Negativ-Tests bestätigt (Positions-Clash und Taxonomie-Divergenz werden korrekt geflaggt, danach sauber revertiert). Damit Phase 3b vollständig (Bänder + Anti-Drift). Offen: Phase 4 (Mega-Zeilen in HANDOFF §4/CHANGELOG brechen) · Phase 5 (OP-Register generiert, OP-DOCS-11).
  • Branch claude/documentation-structure-ux-qzof50 (Folge nach #418, #419) — Broken Links & Anchors der Doku-Site bereinigt (OP-DOCS-9/-13) (Doku, APP_VERSION unverändert 0.69.0). Anlass (Nutzer): die docs-deploy-Build-Warnungen „Docusaurus found broken links/anchors" (Rauschen im Deploy-Log). Behoben (Build jetzt warnungsfrei — vorher 6 Links + 2 Anchors): (1) Repo-Datei-Links außerhalb docs/.github/workflows/ci.yml (IDs.md ×4, HANDOFF.md) + design/WORKSPACES.md (IDs.md ×2) — auf absolute GitHub-Blob-URLs umgestellt (funktionieren auf Site und GitHub; die relativen Pfade brachen auf der Site, weil sie aus dem Docs-Baum herauszeigen); (2) Links auf betrieb/meetings/_Vorlage.md (README-Landkarte + meetings-Index) auf GitHub-URL — Docusaurus schließt _-präfixierte Dateien vom Routing aus (Partial-Konvention) → keine Site-Route; (3) blanker ../-Parent-Link im meetings-Index entfernt (der Landkarte-Link daneben bleibt); (4) Anchor #2-marktabschatzung-tamsamsom (Umlaut-Slug) via explizite {#…}-Heading-ID in Markt-und-Markteintritt.md fixiert → die Verweise aus Wettbewerbsanalyse.md/Markt lösen wieder auf. Verifikation: npm run build grün, 0 Broken-Link-/Anchor-Warnungen; check-doc-consistency.sh grün. Kontext: docs-deploy nach #418 wieder grün (Run #211, success) — der React-19-Peer-Fix (.npmrc) wirkt.
  • Branch claude/documentation-structure-ux-qzof50 (Folge nach #417, #418) — docs-deploy-Fix (React-19-Peer) + OP-DOCS-13 Phase 3b Teil A (architektur/-Bänder) + CodeRabbit-#417-Finalisierung (Doku/Doku-Tooling, APP_VERSION unverändert 0.69.0). docs-deploy repariert (Priorität — Nutzer-Screenshot): der docs-deploy.yml-Job scheiterte auf main an npm ci (ERESOLVE) — @easyops-cn/docusaurus-search-local@0.45 deklariert einen React-Peer <20, inkompatibel mit dem React-19-Stand (Framework-Bump 2026-07-06); durch #417 (erster docs-site-Push seither) sichtbar geworden. Fix: neues docs-site/.npmrc mit legacy-peer-deps=truenpm ci überspringt den überstrengen Peer (das Plugin läuft mit React 19, Build grün). Verifiziert: npm ci und npm run build lokal grün, package-lock.json unverändert. Rückbau, sobald search-local einen React-19-Peer deklariert. Phase 3b Teil A: die 16 flachen architektur/-Docs in 5 thematische Sidebar-Bänder gruppiert (Betrieb · Daten · Produkt/Flow · KI/QS · Zugang/Team) via sidebar_label-Präfix + zusammenhängende sidebar_position (10–160). CodeRabbit-Review #417 (4 Findings, alle adressiert): „PR folgt"→#417 in CHANGELOG/Timesheet finalisiert; True-North-Frage 3 in Lesepfade.md auf die kanonische Plural-Form angeglichen; True-North-Bezug im Doku-UX-Konzept-Status als „schneller"-Klausel präzisiert (MD022-Leerzeile bewusst übersprungen — entspricht dem Stil aller Datums-Überschriften der Datei, kein CI-Gate). Verifikation: npm run build grün (Bänder korrekt sortiert), check-doc-consistency.sh grün. Offen: Phase 3b Teil B (generierte Landkarte gen-doku-landkarte.mjs + kurz:-Frontmatter-Migration ~37 Docs) · Phase 4/5.
  • Branch claude/documentation-structure-ux-qzof50 (#417) — Doku entwirren: Konzept (OP-DOCS-13) + Phase-1-Drift-Fixes (Doku/Doku-Tooling, APP_VERSION unverändert 0.69.0). Anlass (Nutzer): „Die Dokumentation wirkt verworren — wie kann das verbessert werden bzgl. Struktur, Lesbarkeit, Navigation und UX?". Diagnose (3 Explore-Analysen): kein Inhalts-, sondern Struktur-/Redundanz-/Dichte-Problem — Mensch-/Maschinen-Doku im selben Prosastrom · ~155 OP-IDs als Kurzschrift-Prosa · Leitplanken mehrfach statt einmal besessen · vier überlappende OP-Indizes · Mega-Zeilen 5k–15k Z. in HANDOFF §4/CHANGELOG · 20/41 Leaf-Docs = Navigations-Sackgassen (alle 16 architektur/). Entscheidung: nicht-invasiv (keine Datei-Verschiebungen), fünf einzeln lieferbare Phasen nach dem Glossar-Generator-Muster; neues Owning-Doc docs/betrieb/Doku-UX-Konzept.md (pyramidal, Mermaid, messbare Kriterien) + OP-DOCS-13. Phase 1 (Drift-Fixes): Zielgruppen-Taxonomie 4→7 in glossar.mjs (deckungsgleich mit Lesepfade.md; entsperrt gen-glossar.mjs für devops/security/support, das sonst hart fehlschlägt) · sidebar_position-Clash Tests.md/Timesheet.md (40/40 → 40/50) · stale _category_.json-Aufzählungen (architektur 7/16 · konventionen) → generisch · stale Pfade docs/Timesheet.mddocs/betrieb/Timesheet.md (agents.md 3×) + docs/agents.mddocs/konventionen/agents.md (CHANGELOG-Intro) · Topic-Split-Querlinks Mandantenfähigkeit↔Seed-Ablöse-Plan + Flow-Analyse-Status „größtenteils umgesetzt (Historie)" (behebt Widerspruch zu Flow-Refactor-Plan). Registriert in HANDOFF §4 · Roadmap · IDs.md · README-Landkarte · CLAUDE.md-Tiefenquellen. Phase 2 (Leitplanken-Single-Source, ebenfalls dieser PR): die zwei verbose-duplizierten Blöcke OP-DOCS-9 + OP-PM-2 in der immer-geladenen CLAUDE.md auf Essenz + Owner-Pointer (agents.md §5.1/§6.5/§6.6) gekürzt (~12 Zeilen Duplikat weniger, jede Regel erhalten); True-North-Owner-Link in Lesepfade.md (SemVer & ID-Legende sind bereits single-source). Phase 3 (Navigation, ebenfalls dieser PR): Aufgaben-Lesepfade aus README in zielgruppen/Lesepfade.md konsolidiert (eine menschliche Vordertür statt zwei überlappender Lesepfad-Systeme); neues Remark-Plugin docs-site/src/remark/docNavFooter.mjs hängt einen einheitlichen „↩ Landkarte · Lesepfade · Register"-Footer an jedes Leaf-Doc der Haupt-Instanz → schließt alle 20 Navigations-Sackgassen driftfrei (idempotent: überspringt Hubs, Projekt-Instanz und Docs mit vorhandenem Rücklink); Sidebar-Brücke /docs/projekt (sidebars.js/sidebars-projekt.js, die zwei Instanzen waren unverbunden); konventionen als Prozess-/Agenten-Tier gelabelt (Mensch/Maschine-Split sichtbar). Verifikation: npm run build grün (Plugin läuft, Sidebars kompilieren; nur vorbestehende Broken-Link-Warnungen), Footer-Injektion + Idempotenz + Skip-Regeln am Build-Output geprüft; check-doc-consistency.sh grün. Offen (Folge-PRs): Phase 3b (generierte Landkarte + architektur/-Bänder) · Phase 4 (Mega-Zeilen in HANDOFF §4/CHANGELOG brechen, pyramidale Kernaussage) · Phase 5 (OP-Register generiert, OP-DOCS-11).
  • Branch claude/docs-guidelines-tech-standards-zhu4a5 (#416) — Entwicklungsansatz-Übersichtsseite + drkv-Standard-Bausteine referenziert (Doku-only, APP_VERSION unverändert). Neue Seite docs/konventionen/Entwicklungsansatz.md — True North · Leitprinzipien (Einfachheit · Selbsterklärbarkeit · Dokumentation-als-Meisterwerk · Everything-as-Code) · Way-of-Working · Standard-Bausteine, mit Mermaid und Hinweis „Taktanos G-1…G-3 sind Scheduler-Constraints, nicht die drkv-Leitprinzipien". CLAUDE.md: neuer Abschnitt Standard-Bausteine (drkv) — Taktano ist Referenz-Implementierung (Echtzeit · moderne Frameworks · In-App-Chatbot · Feedback, kanonisch im Template everything-as-code-template/docs/Standard-Tech-Stack.md) + Regel „Way-of-Working sichtbar (Entwicklungsansatz.md)" + Tiefenquellen (Entwicklungsansatz, In-App-Assistent). docs/README.md-Landkarte ergänzt. Anlass (Nutzer): Guideline „Way-of-Working sichtbar in der Doku" + drkv-weite Governance/Standard-Tech-Stacks; Taktanos bewährte Bausteine (In-App-Assistent OP-AI-4, Feedback, Echtzeit) sind die Referenz. Konsistent in allen drei Schwester-Repos (Template kanonisch, medidentas gespiegelt).
  • Branch claude/confirmation-dialog-scope-7627x6 (#415) — Konvention: Chat-Zusammenfassung bei wichtigen Entscheidungen + sparsame Rückfragen (Doku-only, APP_VERSION unverändert). CLAUDE.md (Repo/Audit-Trail) um eine Regel ergänzt: bei wichtigen Entscheidungen und vor jedem Push/PR eine kurze Chat-Zusammenfassung (Was gebaut · Warum/Entscheidung · Offen) als Chat-Sicht fürs Arbeiten über mehrere Projekte/Chats — zusätzlich zu CHANGELOG/HANDOFF, nur an relevanten Punkten (kein Rauschen); Rückfragen nur an echten Weggabelungen. Anlass (Nutzer): besserer Durchlauf der Coding-Chats + Wiedereinstieg beim Multi-Projekt-Arbeiten. Konsistent in allen drei Schwester-Repos ergänzt.

2026-07-06

  • Branch claude/angular-react-version-bump-rq4eis (#414) — Framework-Bump: Angular 20 → 22 (Client) + React 18 → 19 / Docusaurus 3.6 → 3.10.1 (Doku-Site) (Version 0.68.0 → 0.69.0, MINOR — Toolchain-Optimierung, rückwärtskompatibel). Auslöser (Nutzer): „Bump angular and react to recent version" — beide Frameworks lagen hinter den aktuellen Stable-Releases (Angular 22 = Juni 2026; React 19). Entscheidungen: (1) Angular auf die aktuelle Stable 22 (nicht nur LTS 21) via ng update @angular/core@21 → @22 (Angular erlaubt nur je eine Major-Stufe; Zwischenschritt 21 committet) — alle @angular/* auf 22.0.5, TypeScript ~6.0.3, zone.js unverändert 0.15.1. Automatische, verhaltensbewahrende Migrationen: Block-Control-Flow-Syntax, explizite ChangeDetectionStrategy.Eager, extendedDiagnostics-Suppress (nullishCoalescingNotNullable/optionalChainNotNullable), Safe-Navigation. (2) React nur in der Docusaurus-Doku-Site (docs-site/, zwei Landingpages index.js/team.js) → react/react-dom 19.2.7; React 19 verlangt Docusaurus ≥ 3.7, daher @docusaurus/* auf die aktuelle 3.x 3.10.1 gehoben; @types/react (transitiv) stimmig 19.2.17. Keine Peer-Konflikte, keine React-Code-Änderung nötig. Manuelle Anpassungen (durch TS-6-/v22-Diagnostik erzwungen, kleinstmöglich): bild-upload-gate.component.tsImageData aus frischer Uint8ClampedArray-Kopie (TS-6-lib.dom: ArrayBufferLikeArrayBuffer; gleiches Muster wie die vorhandenen pii-/nsfw-Adapter); ungenutzten EmptyStateComponent-Import in quality/staff-Page entfernt (NG8113). Node: lokal 22.23.1 nötig (Angular-CLI 22 verlangt ≥ 22.22.3; CI node-version: 22 löst ohnehin die neueste 22.x auf) — .nvmrc/CI unverändert 22. Verifikation: client ng build grün (nur vorbestehende Bundle-Budget-Warnung), Selbsttests test:bildgate/test:fotoqueue/test:queue bestanden; docs-site npm run build grün ([SUCCESS]; die Broken-Link/Anchor-Warnungen sind vorbestehende Inhalts-Links, unabhängig vom Bump). Doku: Stack-Verweise „Angular 20 → 22" in CLAUDE.md · HANDOFF.md (Diagramm/Client/Baum) · design/INTEGRATION_PLAN.md · docs/architektur/Fahrzeug-3D.md (dated/historische Log-Einträge bewusst unverändert; kein neuer OP, da abgeschlossene Wartung), CHANGELOG, Timesheet.

2026-07-05

  • Branch claude/fix-no-hex-pr-ref (#413) — No-Hex-Gate: PR-/Issue-Referenzen (#409) nicht mehr als Hex-Farbe fehlgemeldet (Tooling/scripts/check-no-hex.sh + Doku, kein App-BumpAPP_VERSION unverändert 0.68.0). Auslöser: main-CI (Design-Job) rot, weil check-no-hex.sh in conflicts.component.ts:402 den Kommentar „…Review #409)" als 3-stelligen Hex-Code (#rgb) matchte — jede 3-/6-stellige PR-Nummer (#100#999, #100000+) ist syntaktisch gültiges Hex, ein reiner False-Positive (keine Farbe). Fix: Das Gate ignoriert jetzt Kommentar-Anteile (// … · /* … */ · <!-- … -->) je Zeile — ein Hex in einem Kommentar rendert nichts, ist also kein Token-Verstoß, und PR-Referenzen leben dort. Umsetzung: Kandidaten-Treffer werden vor der Bewertung um ihren Kommentar-Anteil bereinigt (sed) und nur gemeldet, wenn das Hex außerhalb des Kommentars steht; tk-allow-hex-Marker unverändert. Der Original-Kommentar (#409) bleibt erhalten (GitHub-Ref) und dient als Regressionsfall. Rest-Risiko: seltene mehrzeilige Block-Kommentare (per-Zeile-Neutralisierung greift dort nur teilweise) — im Header dokumentiert. Verifikation: lokale Fälle grün — (1) #409-Kommentar passiert, (2) echter Hex im Code blockt weiter (auch mit Trailing-Kommentar), (3) reiner Kommentar-Hex passiert, (4) echter Hex nach einer https://-URL auf derselben Zeile blockt weiter; check-doc-consistency.sh ohne neue Warnung. Review (CodeRabbit, 2 Findings gefixt): (a) Major//-Stripping URL-sicher gemacht (s#([^:])//.*$#\1#; s#^//.*$##:// gilt nicht als Kommentar-Start, sonst hätte ein Hex nach https:// als „im Kommentar" fälschlich durchgerutscht = False-Negative); (b) Minor — Timesheet MD037 (Kommentar-Syntax-Liste in Backticks, damit /* */ nicht als Emphasis geparst wird); (c) Major/* *//<!-- -->-Stripping von greedy (.*) auf non-greedy (negierte Klasse [^*]/[^>], stoppt am nächsten Closer) umgestellt, sonst hätte /* a */ #fff /* b */ als ein Block den echten Hex verdeckt; Fehlrichtung nun „meldet zu viel" statt „verdeckt echten Hex". Doku: scripts/check-no-hex.sh (Header), docs/betrieb/Tests.md, CHANGELOG, Timesheet.
  • #411 2026-07-05 — Auto-Rerun bei flakigem Runner (auto-rerun.yml, §6.8) (Tooling/Workflow, kein App-Bump). Neuer workflow_run-getriggerter Job: schlägt ein CI-Lauf fehl, werden die fehlgeschlagenen Jobs einmalig neu angestoßen (run_attempt < 2 → genau 1 Retry, kein Loop). Heilt die typische self-hosted-Flakiness (github.com:443-Timeout, Runner mitten im Job gestorben). Nicht neugestartet: abgebrochene Läufe (Concurrency-Cancel = cancelledfailure) und Fork-PRs. Idempotenz: concurrency: auto-rerun-<run_id> (serialize-not-cancel) gegen doppelte/redelivered workflow_run-Events; Timeouts curl --connect-timeout 10 --max-time 30 + Job timeout-minutes: 5, damit ein hängender API-Call keinen hot-Runner-Slot blockiert (CodeRabbit-Review #411). Dependency-frei via curl (kein gh/Node-Action → keine node20-Warnung). Deploys bewusst ausgenommen. Doku: agents.md §6.8, .github/workflows/auto-rerun.yml, CHANGELOG.
  • Branch claude/missing-vehicles-clarification-n3eqe8 (#412) — OP-UX-6-Nachschärfung: freie Notiz am Auftrag + Verlauf im Detail-Panel (Version 0.67.0 → 0.68.0, MINOR). Nutzer-Befund zum „Fahrzeug da"/Klärfälle-Screenshot: (a) man möchte „auch einen allgemeinen Kommentar (z. B. nochmal angerufen und gefragt) ergänzen können", und (b) die seit Wochen überfälligen Fahrzeuge sollten in der Klärfälle-Liste erscheinen. Klärung zu (b): die überfälligen Anlieferungen erscheinen bereits — Sektion „⏱ Überfällige Anlieferungen" im Klärfälle-Tab (OP-UX-6/#409, ueberfaelligeAnlieferung = status geplant + bringtermin < jetzt, identisch zum „erwartet seit"-Badge im Annahme-Screen); eine leere Liste bei sichtbar überfälligen Fahrzeugen bedeutet nur, dass der laufende Build vor #409 liegt (Deploy-Nachzug), kein Logikfehler. Entscheidung (Nutzer): freie Notiz „überall am Auftrag" — kein Statuswechsel, kein Klärfall-Zwang, keine Re-Optimierung. Gebaut: neue Client-Message auftrag.notiz (Handler hängt einen Notiz: …-Protokoll-Eintrag an, leere Notizen verworfen, nicht in REOPT_EVENTS) + Service auftragNotiz + UI an zwei Stellen: (1) „📝 Notiz"-Aktion + Mini-Formular im geteilten auftrag-detail-panel plus neuer „Verlauf"-Block (Protokoll, neueste zuerst — war bislang im DTO vorhanden, aber nirgends angezeigt), (2) „📝 Notiz"-Button + Inline-Feld direkt an der Überfällig-Zeile im Klärfälle-Workspace (Anruf dokumentieren ohne Umweg über Storno/Klärfall). Verifikation: tsc + operativ + ng build grün. Doku: HANDOFF §4 (OP-UX-6), CHANGELOG, Timesheet.
  • Branch claude/cleanup-logs-frontmatter-ae43ki (#410) — Log-Hygiene: Timesheet-ID-Kollision geglättet + fehlendes Doku-Frontmatter (OP-PM-2/OP-DOCS-9, Doku/Tooling-only, kein App-BumpAPP_VERSION unverändert 0.67.0). scripts/check-doc-consistency.sh flaggte zwei Punkte auf main. (1) Timesheet-ID-Kollision: die Sessions 37–47 existierten doppelt — ein zweiter, inhaltlich eigenständiger Block aus dem parallelen Branch claude/seed-usage-audit-frsx52 (OP-SEED-1 · S-SEED-1…5 · E-TENANT/E-BACKUP-Entscheidungen) hatte dieselben laufenden Nummern gegriffen (die Vor-OP-PM-3-Zahl-Kollision paralleler Branches; union-Merge konkatenierte statt zu überschreiben). Kein byte-identisches Duplikat → smooth-logs löst das bewusst nicht automatisch. Auflösung: der Seed-Audit-Block auf eindeutige IDs 53–63 umnummeriert (nach dem bisherigen Max 52), inkl. der zeileninternen „(Session NN)"-Selbstverweise; die Start-Spalte trägt ohnehin die echte Chronologie. (2) Frontmatter: docs/architektur/Fahrzeug-3D.md begann ohne ----Block → sidebar_position: 75 (zwischen Bildbewertung 70 und Persistenz 80) + sidebar_label: Fahrzeug-3D (OP-R6-2) ergänzt, konsistent mit den übrigen architektur/-Docs. Verifikation: check-doc-consistency.sh meldet keine Session-ID-/Frontmatter-Warnung mehr; keine doppelten numerischen IDs. Doku: docs/betrieb/Timesheet.md, docs/architektur/Fahrzeug-3D.md, CHANGELOG, Timesheet.
  • Branch claude/ci-cache (#408) — Persistenter Angular-Build-Cache + hot-Runner-Pinning (§6.8) (Tooling/ci.yml + Angular-Config + Doku, kein App-BumpAPP_VERSION unverändert). (1) Build-Cache: client/angular.jsoncli.cache.environment: "all" (Angular deaktiviert den Disk-Cache in CI sonst) + actions/checkout clean: false im Client-Job → .angular/cache überlebt den git clean zwischen Läufen = inkrementeller Angular-Build (content-adressiert, selbst-invalidierend → unbedenklich). (2) hot-Pinning: alle 11 CI-Jobs runs-on: … || 'hot' statt generisch self-hosted — die Cache-/Offline-Hebel (warmes ~/.npm, entfernter npm-Cache, .angular/cache) greifen nur auf persistenten hot-Runnern; ephemere tragen ephemeral. Fork-Gate (ubuntu-latest) + CI_RUNNER-Override unverändert. Kapazität: hot-Runner-Zahl = Parallelitäts-Obergrenze. Verifikation: ci.yml + angular.json valide, kein self-hosted-Default mehr. Doku: agents.md §6.8, ci.yml, client/angular.json, CHANGELOG.
  • Branch claude/ci-speedup (#407) — CI-Installs beschleunigt (§6.8) (Tooling/ci.yml + Doku, kein App-BumpAPP_VERSION unverändert). Alle npm ci-Aufrufe in ci.yml (server · persistence-gate · client · sbom · deploy) laufen jetzt mit --prefer-offline --no-audit --fund=false → nutzt das warme lokale ~/.npm ohne Audit-/Funding-Netz-Calls (spart Zeit, robuster bei flakiger github.com-Anbindung). Der Pfad-Filter (changes-Job) war bereits vorhanden → taktano-PRs sind schon bereichs-schlank; die Konvention §6.8 hält beides fest. Kein fetch-depth-Change nötig (Server-Job ist bereits shallow; nur der Deploy-Job braucht volle History, läuft aber ohnehin nur auf main). Gegenstück in medidentas (#…: Pfad-Filter + Installs + shallow Checkout, D-37). Verifikation: ci.yml YAML-Parse grün, keine bare npm ci mehr. Doku: agents.md §6.8, ci.yml, CHANGELOG.
  • Branch claude/ci-concurrency-guideline (#406) — CI-Concurrency-Konvention (§6.8) + npm-Cache-Fix (Doku/Konvention + ci.yml, kein App-BumpAPP_VERSION unverändert). Neue Way-of-Working-Regel docs/konventionen/agents.md §6.8: jede Workflow-Pipeline nutzt einen concurrency-Block, wo er Nutzen bringt — CI/PR-Läufe gruppieren nach ci-${{ github.workflow }}-${{ github.ref }} und canceln überholte Läufe außer auf main (cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}); Deploy-Pipelines nach fixem Ziel + cancel-in-progress: true; serielle Jobs (Log-Sync) cancel-in-progress: false. Faustregel + Zusammenspiel mit der Trigger-Hygiene (OP-CI-1). Concurrency-Block war bereits da (ci.yml/sync-pr-logs.yml) → die Konvention hält den Ist-Zustand fest (Doku↔Code). Zusätzlich (Umsetzung derselben Regel): cache: npm aus allen setup-node-Steps in ci.yml entfernt — auf dem persistenten self-hosted Runner ist ~/.npm warm; cache: npm (für ephemere Runner gedacht) lud nur ein großes Archiv langsam durch den Actions-Cache-Service (Timeout-Risiko auf flakiger Anbindung). Fork-PRs (ubuntu-latest) laden dann frisch aus der Registry. Gegenstück in medidentas §6.6 + ci.yml (dort zusätzlich Trigger push[main] + neuer Concurrency-Block). Verifikation: YAML-Parse ci.yml grün, keine aktive cache:-Direktive mehr. Doku: agents.md §6.8, ci.yml, CHANGELOG.

2026-07-04

  • Branch claude/cross-repo-id-scheme (#405) — Repo-übergreifendes ID-Schema (Repo-Key TKT/MED/GRM) (Doku/Konvention, kein App-Bump — APP_VERSION unverändert). Auslöser (Nutzer): OP-*-IDs kollidieren repo-übergreifend (taktano/medidentas/gh-runner-manager führen je eigene OP-n). Entscheidung: IDs bleiben repo-lokal bare; cross-repo mit Repo-Key qualifizieren (TKT-OP-CI-2, MED-OP-SIGN-1, GRM-OP-2) — analog GitHubs owner/repo#123; keine Massen-Umbenennung bestehender IDs (Einfachheit/YAGNI). Doku: docs/konventionen/IDs.md (neue Sektion „Repo-übergreifende IDs"). Parallel in medidentas (agents.md §3) + gh-runner-manager (open-points.md) verankert.
  • Branch claude/design-input-integration-ae43ki (#409, Folge-PR zu #402, Branch von main neu aufgesetzt) — OP-UX-6: Überfällige Anlieferung = Klärfall + Auftragsstorno (Version 0.66.0 → 0.67.0, MINOR). Nutzer-Befund („Fahrzeug da"-Screenshot: alle 15 erwarteten Anlieferungen überfällig, aber niemand zuständig; kein Weg, ein Fahrzeug rauszunehmen). Entscheidungen (Nutzer): überfällige Anlieferungen automatisch abgeleitet in die Klärfälle (kein persistierter State, D-2: status geplant + bringtermin < jetzt); Auftragsstorno aus dem Klärfall-Kontext mit Pflicht-Grund. Gebaut: Domänen-Helfer stornieren (Grund-Pflicht · abbrechenabgebrochen terminal · Grund in Chronik) + Handler auftrag.stornieren (Quittung, Audit auftrag.storniert, REOPT-Event) + Client ueberfaelligeAnlieferung-Kategorie/stornoAuftrag + Klärfälle-Workspace: Sektion „⏱ Überfällige Anlieferungen" (Storno mit Pflicht-Grund-Textarea) und „✕ Auftrag stornieren" im Klärfall-Detail; Nav-/Tab-Badge zählt jetzt Klärfälle + überfällige. Selbsttest im operativ-Durchlauf (Grund-Pflicht · abbrechen · Chronik · Doppel-Storno abgelehnt). Verifikation: tsc + operativ + ng build grün. Doku: HANDOFF §2/§4 (OP-UX-6 neu), IDs.md, CHANGELOG, Timesheet.
  • Branch claude/runner-env-variables-v5tc5h (#404) — Runner-Tool-Cache: Provisionierung auf Runner-Ebene statt Workflow-env (self-hosted, OP-CI-2-Nachzug) (Tooling/Workflows, kein App-BumpAPP_VERSION unverändert 0.65.0). Auslöser (Nutzer): Ergänzung zur self-hosted-Umstellung — auf dem lokalen Org-Runner ist der geteilte Host-Tool-Cache (/opt/hostedtoolcache) nicht je Lauf isoliert/beschreibbar → setup-node/setup-python können bei parallelen Jobs kollidieren oder an Schreibrechten scheitern. Ergebnis (nach Iteration): Der Workflow-Weg (Step-env RUNNER_TOOL_CACHE/AGENT_TOOLSDIRECTORY = ${{ runner.temp }}/_tool) fixte zwar setup-node, aber setup-python ignoriert die Umleitung auf macOS — das actions/python-versions-Install-Skript legt den Toolcache hart unter /Users/runner/hostedtoolcache an → mkdir: /Users/runner: Permission denied (Runner-User darf unter /Users/ nichts anlegen). Entscheidung (mit Nutzer): Toolcache/Toolchain auf Runner-Ebene provisionieren (beschreibbares /Users/runner/hostedtoolcache bzw. RUNNER_TOOL_CACHE in der Runner-.env + vorinstallierte Node/Python-Toolchain) statt im Workflow — die Cache-env:-Blöcke wurden daher wieder aus allen Workflows entfernt (ci/docs-deploy/fly-deploy/weekly-audit; sync-pr-logs hatte keine). Nebeneffekt-Fix: ein parallel auf main gelandeter invalider job-level env: mit runner.temp (→ „Unrecognized named-value: 'runner'", brach main-CI/Deploys) wird damit ebenfalls beseitigt. Verifikation: YAML-Parse aller Workflows grün, kein runner.temp/RUNNER_TOOL_CACHE mehr unter .github/workflows/; CI auf den provisionierten Runnern. Doku: .github/workflows/*.yml, CHANGELOG, HANDOFF §4 (OP-CI-2), Timesheet.
  • Branch claude/design-input-integration-ae43ki (#402, Folge-PR zu #400, Branch von main neu aufgesetzt) — OP-UX-5: Trennung Auftragsannahme (Buchung) / Fahrzeugannahme (Check-in) (Version 0.65.0 → 0.66.0, MINOR). Das Datenmodell trennte die Ereignisse längst (geplantliefernangeliefert mit Ist-Stempel + harter Reservierung), die UX nicht: „Fahrzeug angeliefert" war ein nackter Status-Button ohne Check-in. Entscheidungen (Nutzer): Fahrzeugannahme als Tab im Annahme-Workspace · Doku-Pflicht (Check-in erledigt den Standard-Annahme-Schritt OP-R3-1 mit Pflicht-Zustandskommentar/Car-Check). Gebaut: reiner, getesteter Domänen-Helfer fahrzeugAnnahme (Kommentar-Pflicht · nur aus geplant · erledigt Annahme-Schritt · liefern atomar — Doppel-Check-in = sauberer Fehler statt Duplikat) + Handler auftrag.checkin (Quittung, Protokoll, Audit auftrag.angeliefert, REOPT-Event) + UI-Tabs „⌨ Auftrag anlegen" / „🚗 Fahrzeug da" (Badge = erwartete Anlieferungen; Liste nach Bringtermin, überfällige amber „erwartet seit …"; aufklappbarer Check-in). DTO additiv +bringtermin. Selbsttest im operativ-Durchlauf (+Tests.md), OP-UX-5 in IDs.md, WORKSPACES §0. Verifikation: tsc + operativ + ng build grün. Doku: HANDOFF §2/§4 (OP-UX-5 neu), CHANGELOG, Timesheet. Nachtrag (gleicher PR, Nutzer-Anweisung): alle 5 GitHub-Workflows (ci · docs-deploy · fly-deploy · sync-pr-logs · weekly-audit) zwischenzeitlich von ubuntu-latest auf self-hosted Runner umgestellt (GitHub-gehostete Runner nahmen ab ~15:55 UTC keine Jobs mehr an). Beim Merge von main durch die kanonische Lösung aus #403 (OP-CI-2, „runner-unabhängig — self-hosted Default + Fork-Gate, aus medidentas D-29") ersetzt: runs-on: ${{ …fork && ubuntu-latest || vars.CI_RUNNER || self-hosted }} — Fork-PRs laufen sicher auf GitHub-hosted, sonst konfigurierbar via Repo-Variable CI_RUNNER, Default self-hosted. Meine [self-hosted]-Zwischenlösung ist damit obsolet (Konflikt zugunsten #403 gelöst). Zusätzlich Tool-Cache-env (RUNNER_TOOL_CACHE/AGENT_TOOLSDIRECTORY = ${{ runner.temp }}/_tool) je Setup-Job ergänzt, damit setup-node/setup-python auf den (nicht-ephemeren, macOS-ARM64) self-hosted Runnern den Tool-Cache finden. Nachtrag 2 (gleicher PR, Nutzer-Wunsch): OP-ORTUNG-2 neu — „Standort unbekannt" (DTO standort: null) soll Klärfall werden statt stilles „—", plus Skill „Fahrzeug finden" analog zum Umparken-Flow (Suchauftrag → Fund → Belegung setzen → Klärfall gelöst); Hardware-loser Fallback/Prozess-Vorlage zu OP-ORTUNG-1 — HANDOFF §4 + IDs.md. Nachtrag 3 (gleicher PR, Nutzer-Wunsch): OP-KOMM-1 neu — Broadcast-Nachrichten ans Team (Durchsagen + Rückfragen mit Kurz-Antwort) über die vorhandene Broadcast-Infrastruktur (Muster plan.autoAngewendet); bewusst kein Chat; Klärfall-anbindbar (z. B. Standort-Suche OP-ORTUNG-2) — HANDOFF §4 + IDs.md. Review (CodeRabbit, 3 Runden/10 Findings) im selben PR gefixt: Car-Check-Doku-Garantie für Alt-Aufträge (Chronik-Eintrag im Domänen-Helfer, eine Quelle), Panel-Race der Check-in-Quittung, Offline-/Disconnect-Guards, Textarea-Sperre während des Sendens, Minuten-genauer Überfällig-Vergleich.
  • Branch claude/nifty-euler-esi8p6 (#403) — OP-CI-2: CI/Deploy runner-unabhängig — self-hosted Default + Fork-Gate (aus medidentas D-29 übernommen) (Tooling/Workflows/Doku, kein App-BumpAPP_VERSION unverändert 0.65.0). Auslöser (Nutzer, „vergleiche die runner config"): Der Vergleich der GitHub-Actions-runs-on-Konfiguration beider Repos zeigte: medidentas war bereits auf einen self-hosted Runner umgestellt (Entscheidung D-29, Header-Kommentar: „2026-07-04 startete GitHub Actions für die Org keine gehosteten Jobs mehr — Billing/Limit"), taktano stand noch überall auf hartkodiertem ubuntu-latest. Da beide Repos in derselben Org drkv-com liegen, trifft das Hosted-Minuten-Limit taktano genauso → CI + alle Deploys (fly/docs/app) stünden still. Entscheidung (Nutzer „ja"): D-29-Strategie 1:1 auf taktano portiert. Gebaut (nur Workflows + Doku, kein Code/Schema): alle 5 Workflows nutzen jetzt runs-on: ${{ vars.CI_RUNNER || 'self-hosted' }} → Default = lokaler Org-Runner, ohne Commit auf GitHub-Runner umschaltbar über die Repo-/Org-Variable CI_RUNNER (z. B. CI_RUNNER=ubuntu-latest). Sicherheits-Gate (RISK-18, neu): in ci.yml (läuft auf pull_request, auch aus Forks) trägt jeder der 11 Jobs den erweiterten Ausdruck ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || vars.CI_RUNNER || 'self-hosted' }}Fork-PRs (fremder Code) laufen nie auf dem self-hosted Runner, immer auf GitHub-Wegwerf-Runnern. sync-pr-logs.yml bekommt die einfache Form (Fork-PRs werden dort ohnehin per Guard 2 vor dem Checkout abgewiesen, fremder Code läuft nie); fly-deploy/docs-deploy/weekly-audit laufen nur auf main-Push/Dispatch/Cron im eigenen Repo (kein Fremd-PR) → einfache Form. Jeder Workflow-Kopf erklärt Runner-Wahl + Hintergrund + Fork-Gate. Rest-Offen: Runner-Host härten (ephemer/isoliert, least-privilege im Org-Netz), sobald der lokale Runner produktiv trägt (RISK-18). Verifikation: YAML-Parse aller 5 Workflows grün; grep runs-on bestätigt kein hartes ubuntu-latest mehr (nur im Fork-Zweig). Doku: .github/workflows/*.yml (Kopf-Kommentare), Risikoregister RISK-18, HANDOFF §4 (OP-CI-2), konventionen/IDs.md, CHANGELOG, Timesheet.
  • Branch claude/design-input-integration-ae43ki (#400, Folge-PR zu #399, Branch von main neu aufgesetzt) — OP-UX-4-Nachschärfung 2: Alternativen statt Sackgasse + Trotzdem-Annehmen + Leistungs-Schnellauswahl + Kunden-Lookup (Version 0.64.0 → 0.65.0, MINOR). Nutzer-Befund (Screenshot): „✗ Kein machbarer Plan: kein verfügbares Ressourcen-Set …" war eine Sackgasse — keine Option, den Auftrag dennoch anzunehmen oder auf einen machbaren Termin auszuweichen. (1) Alternativen: auftrag.pruefen probt bei Infeasibility spätere Anlieferungen (gleiche Uhrzeit, +1…+14 Tage) und liefert die erste machbare als alternativeAnlieferung/alternativeFertig; das Panel bietet sie als Ein-Klick-Übernahme („→ Anlieferung Mo 06.07. 08:00 übernehmen (fertig …)"). Bei geplatztem Wunschtermin (Warnung) analog fruehesteAbholung → „→ Abholung auf … setzen". Entscheidung: Termin-Übernahmen als overrides-Signal, das das Parsing übersteuert (Termine lassen sich nicht sinnvoll in den Satz zurück-patchen); manuelles Weitertippen setzt sie zurück — der Satz bleibt die eine Quelle. (2) Trotzdem annehmen: auftrag.create mit trotzdem-Flag legt den Auftrag auch ohne machbaren Plan an — Prozess-Schritte als ungeplante Platzhalter-Instanzen (bayId leer, 0-Dauer, Status geplant → der Auftrag bleibt für die Re-Optimierung wählbar und wird eingeplant, sobald Ressourcen da sind; CodeRabbit-Befund), als Klärfall markiert (Grund = Scheduler-Befund) → sichtbar im Klärfälle-Workspace statt still verloren; amber Button „⚠ Trotzdem annehmen (wird Klärfall)". (3) Leistungs-Schnellauswahl: Chip-Zeile aller aktiven Leistungen unter der Kommandozeile — Klick ergänzt den Satz (Nutzer-Vorgabe; ersetzt die bisher erkannte Nennung per Stamm-Suche, sonst angehängt), erkannte Leistung ist markiert. (4) Kunden-Lookup: „Meintest du: ☺ …"-Vorschläge aus den Kunden bisheriger Aufträge (Substring-Match ab 2 Zeichen, max. 3, inkl. CRM-Hinweis); Übernahme ersetzt die Kurzform im Satz durch den vollen Namen, und beim Annehmen wird der CRM-Link des bekannten Kunden automatisch mit verknüpft. Verifikation: tsc + ng build + operativ + test:annahme-parse grün. Doku: CHANGELOG, HANDOFF §4 (OP-UX-4), Timesheet.
  • Branch claude/design-input-integration-ae43ki (#399, Folge-PR zu #398, Branch von main neu aufgesetzt) — OP-UX-4-Rest: Kunde/CRM-Nachtrag im geteilten Detail-Panel (Version 0.63.0 → 0.64.0, MINOR). Die frühere U5-Funktion (Kunde-Name korrigieren + CRM-Link nachtragen an bereits angelegten Aufträgen) hatte seit dem v3-Redesign keine UI mehr (das „Zuletzt angenommen"-Panel wich dem Erfolgs-Screen). Jetzt als Kunde-Karte im Fakten-Grid des geteilten auftrag-detail-panel: Name + klickbarer CRM-Link, „✎ nachtragen" öffnet den Inline-Edit (Name Pflicht, CRM optional) → bestehender auftrag.update-Handler (Audit/Chronik unverändert). Damit von überall erreichbar, wo das Panel öffnet (Aufträge · Tafel · Radar · Planung-Gantt · Klärfälle · Meine Arbeit) — besser als das alte Annahme-only-Panel. Reiner Client-Pfad, kein Server-Change. Verifikation: ng build grün. Doku: HANDOFF §4 (OP-UX-4-Offen-Liste), CHANGELOG, Timesheet.
  • Branch claude/design-input-integration-ae43ki (Folge-PR zu #397, Branch von main neu aufgesetzt) — OP-UX-4-Nachschärfung: Dauer-Angaben + Quellen-Anzeige im Takt-Kommando (Version 0.62.0 → 0.63.0, MINOR). Nutzer-Befund (Screenshot): „…kommt mo, 14 Tage Zeit" ließ die Abholung leer — die Heuristik kannte nur „bis ‹X›", und ob das LLM überhaupt geantwortet hatte, war unsichtbar. (1) Dauer-Parsing: Heuristik versteht jetzt Dauer-Angaben („14 Tage Zeit", „in 3 Tagen", „2 Wochen") → Abholung = Anlieferung (sonst heute) + Dauer, 17:00; derselbe Fall steht explizit im LLM-System-Prompt. (2) Robustere LLM-Validierung: Voll-ISO-Zeiten mit Sekunden/Zeitzone (LLM-typisch) werden auf die Minute gekürzt statt verworfen (ISO_MINUTE_PREFIX). (3) Dezente Quellen-Anzeige unter den Baustein-Chips: „Analyse: KI (LLM) + Heuristik" (magenta Punkt) · „Analyse: Heuristik" · „… (KI nicht konfiguriert)" bei dormant · „… (KI nicht erreichbar)" (amber) bei Fehler — der LLM-Status ist damit erstmals sichtbar (llmStatus-Signal statt stummem Catch). Fehlen-Hinweis nennt jetzt auch das Dauer-Beispiel. Selbsttest test:annahme-parse +2 Asserts (ISO-Kürzung, Dauer-Regel im Prompt). Verifikation: tsc + test:annahme-parse + ng build grün; Nutzer-Satz parst komplett per Heuristik (Mo 06.07. 08:00 → Mo 20.07. 17:00). Doku: CHANGELOG, HANDOFF §4 (OP-UX-4), Timesheet.
  • Branch claude/design-input-integration-ae43ki (#397, gemergt) — OP-UX-4: v3-Kern-Loop-Redesign aus Claude Design umgesetzt (Version 0.61.0 → 0.62.0, MINOR). Design-Handoff „Car intake UI redesign" als neue lebende Design-Quelle abgelegt (design/prototype/Taktano Werkstatt-OS v3.dc.html ersetzt v2 · Handoff-Spec design/prototype/HANDOFF-Kernloop-Slice1.md · 10 Referenz-Screenshots; Bundle-Tokens byte-identisch mit design/tokens/) und exakt umgesetzt — alle 8 Kern-Workspaces, mit echten Daten statt Prototyp-Fixtures. Entscheidungen (Nutzer, 07-04): (a) alle 8 Workspaces in dieser Session; (b) Ein-Satz-Parsing direkt mit LLM (Assistent-Infrastruktur) + Heuristik als Fallback; (c) Crystal-Bar = 8 Prototyp-Workspaces oben + übrige („Weitere") darunter; (d) Konflikte & Klärfälle zusammengelegt (ein Workspace, zwei Tabs; /klaerfaelle → Redirect). Gebaut: Shell (Nav-Reihenfolge/Glyphen/Badge-Farben je Kontext, Logo-Gradient, Backdrop-Grid, Header 17 px + Glow-Dot + JETZT-Uhr) · Annahme „Takt-Kommando" (Ein-Satz-Intake: 5 Baustein-Chips live via Client-Heuristik util/annahme-parse.ts + LLM-Endpoint POST /annahme/parse — enum-gebundenes Function-Calling gegen den echten Leistungs-Katalog, dormant ohne ASSISTENT_LLM_KEY; Machbarkeits-Panel = echter Dry-Run auftrag.pruefen [erweitert um startMin/slotName des ersten Schritts] mit Reserve-Pille/Preis/„✓ Annehmen" in einem Schritt [Panel = U4-Bestätigung]; Erfolgs-Screen „AU-nnn ist im Takt." + Radar-Fokus; Selbsttest test:annahme-parse + CI) · Überblick = Hof-Radar (Buchten-/Hof-Kacheln aus der Ist-Belegung, Radar-Sweep, Mitarbeiter-Avatare aus dem Plan — ehrlich beschriftet („Ortung abgeleitet aus Plan & Belegung", keine BLE/RFID-Behauptung), „Als Nächstes"-Takt-Vorschau, Live-Ortung-Panel mit echtem Sync-Zähler; Cross-Links ?fokus=AU-… / ?mitarbeiter=…) · Aufträge (Fluss = 5 Prozess-Stationen mit WIP-Limit 4 · Risiko = Dringlichkeits-Timeline · Vollbreiten-Detail-Panel mit Terminklassen-/Reserve-Pille, Faktenzeile [neu AuftragDTO.leistungIds], 5-Stufen-Strip, Kontext-Aktionen ⚡/✦/📍; Lifecycle-Aktionen/Helfer/Fly-in erhalten) · Konflikte & Klärfälle (Tabs mit Kontext-Badges, Hebel-Zeilen mit „✓ Termin hält"/„✗ hält nicht" + ↷ Knock-on, Engpass-Box ◎, Lösen mit Crumple + 26-Pixel-Dissolve; Klärfall-Detail mit „✓ lösen"/„📍 Hofplan") · Vorschläge (Karten-Grid minmax(420px,1fr), Badges inkl. „☺ von dir", Impact-Rows in festen Spalten, Quelle mono) · Mitarbeiter (Karten mit Plan-Ortung, ✦-Empfehlungs-Box magenta, „Umparken"-Chip cyan, Status-Aktionen ✓/▶/○/⏸/✕ + 📍 Radar; CRUD/XP/Statistik erhalten) · Qualität (KPI-Zeile real abgeleitet, 3 Spalten, ✓/✕-Checkliste + Release-Gate „✓ Freigeben — in den Ausgang", Zwei-Wege-Nacharbeit: „🛠 In QS behoben" [neues sofortBehoben-Flag an qs.mangelErfassen → Mangel entsteht als behoben, Aufwands-Log „QS-Aufwand auf Auftrag erfasst" mit Σ = Ist-Aufwand-Hook] / „↩ Nacharbeit → Produktion" [bestehender OP-QS-4-Pfad, vorbefüllt]; Ausgang-Feed mit NEU-Pille + Nachkontrolle). Planung: bereits v3-konform (Konflikt-Chip „⚡ n → nächster", JETZT-Linie, ⚑-Flags, Heatrow gebaut); der Prototyp-Detail-Strip ist bewusst durch das reichere geteilte Detail-Fly-in (OP-R8-16) abgedeckt. Bewusste Abweichungen: Ortung ehrlich als abgeleitet beschriftet; „Zuletzt angenommen"-Panel (U5) weicht dem Erfolgs-Screen — Kunde-Nachtrag als OP-UX-4-Rest notiert. Verifikation: tsc + ng build + test:annahme-parse + test:qs-nacharbeit + operativ + No-Hex grün. Doku: design/WORKSPACES.md (v3-Abschnitte inkl. neuem §0 Annahme), HANDOFF §2/§4, Tests.md, CHANGELOG, Timesheet. Nachtrag (gleicher PR, Nutzer-Wunsch): OP-ORTUNG-1 neu — echte Live-Ortung für Mitarbeiter (Handy/BLE) + Fahrzeuge (BLE/RFID/UWB) fürs Hof-Radar (heute Plan-/Belegungs-Ableitung als ehrlicher Stand); inkl. Radar-Fusion mit Abweichungs-Signal, D-2-Datenmodell (rohe Sichtungen ≠ Abgeleitetes) und Datenschutz/Mitbestimmung DE/AT/CH (BetrVG §87/DSGVO, Zonen- statt Bewegungsprofil, Pilot mit Fahrzeug-Tags zuerst) — HANDOFF §4 + IDs.md.
  • Branch claude/3d-vehicle-models-sfljc1 (#396) — OP-R6-2 Recherche: Fahrzeug-3D — Modell-Quellen, Rendering & Markierungen (reine Doku, APP_VERSION unverändert). Nutzer-Frage „Quelle für 3D-Fahrzeugmodelle, easy einbettbar/drehbar (Web + später iOS), mit nummerierten Markierungen + Kommentar/Foto?" recherchiert und als neues Architektur-Doc docs/architektur/Fahrzeug-3D.md festgehalten. Ergebnis/Empfehlung (Entscheidung offen): (1) generisches Karosserietyp-Set statt fahrzeuggenauer Modelle — CC0-GLBs (Quaternius/Poly Pizza/Kenney), Ablage im bereits vorgesehenen R2-Bucket taktano-models (dormantes Binding) mit Lizenz-Nachweis; keine Marken-Modelle (Editorial-Lizenz/Markenrecht, Redistributions-Verbot offener Formate). (2) <model-viewer> (v4.3.1, aktiv) als einfachste tragfähige Web-Einbettung — Drehen/Zoomen + nummerierte Hotspot-Markierungen out of the box, Setzen per Klick (positionAndNormalFromPoint), als erste Lazy-Route. (3) Markierungs-Datenmodell renderer-neutral (FahrzeugMarkierung am Auftrag: Position+Normale, kommentar, mangelId?, fotoIds[] → knüpft an FotoAttachment/Mangel/OP-R7-16 an). (4) iOS-nativ später über dieselben Assets (GLB→USDZ einmalig, RealityKit/Quick Look); model-viewer-AR-Modus deckt „AR vorbereiten" strukturell ab. Konsequenz: das ⚠-Aufwand-Flag in OP-R6-2 relativiert — Stufe 1 kann direkt generisches 3D sein (statt 2D-Silhouette-Umweg); Slices V-1…V-4 skizziert. Doku: Lastenheft §11.1 OP-R6-2 + HANDOFF §4 (Recherche-Verweis), Doku-Landkarte + CLAUDE.md-Tiefenquellen (neue Datei), Timesheet.
  • Branch claude/planning-queue-optimization-iniw7z (#395, Branch von main neu aufgesetzt — #394 gemergt) — OP-OPT-9 Slice 5: Queue-Hinweis in der Tafel (Version 0.60.0 → 0.61.0, MINOR). Der letzte OP-OPT-9-Folgepunkt ohne Login-Abhängigkeit (Nutzer-Wahl „Tafel-Queue-Hinweis"): Jede Tafel-Auftragszeile zeigt unter dem aktuellen Schritt jetzt „→ als Nächstes: · ab " — den nach dem aktuellen Schritt nächsten wartenden Schritt in Queue-Reihenfolge (queueVergleich aus queue-reihenfolge.ts, Startzeit statt Template-Reihenfolge — dieselbe Semantik wie die Planung-Queues und „Meine Arbeit"; die Wiederverwendung des geteilten Helfers ist der Punkt, keine dritte Kopie). Reine Projektion (S-2), kein Server-Change; rückt durch die Auto-Nachführung automatisch mit. Damit beantwortet die Tafel True-North-Frage 2 einen Tick voraus: nicht nur wo steht der Auftrag jetzt, sondern was passiert als Nächstes. Verbleibende OP-OPT-9-Punkte (personalisierte Push-Zustellung, Rollen-Gate für den Auto-Schalter) hängen an OP-AUTH-1 und bleiben dort notiert. Verifikation: ng build + No-Hex grün (client-only). Doku: Lastenheft OP-OPT-9 (Slice 5, Offen-Liste) · HANDOFF §2/§4 · Funktionsumfang · CHANGELOG · Timesheet.

2026-07-03

  • Branch claude/planning-queue-optimization-iniw7z (#394, Branch von main neu aufgesetzt — #393 gemergt) — OP-OPT-9 Slice 4: Auto-Nachführung an-/abschaltbar + In-App-Benachrichtigung bei Auto-Anwendung (Version 0.59.0 → 0.60.0, MINOR). Setzt zwei der offenen OP-OPT-9-Folgepunkte um. (1) Schalter: neues persistiertes Feld autoOptAktiv (PersistedState, Default an, onStart-Backfill ?? true — Persistenz-Gate D5-4 gedeckt) + ClientMsg autoopt.setzen; die Event-Re-Opt wendet nur bei aktivem Schalter automatisch an, sonst bleibt alles bestätigungspflichtiger Vorschlag (Verhalten wie vor v0.59.0). Toggle-Button „⟲ Auto-Nachführung an/aus" in der Planung-Toolbar (grün = an, Tooltip erklärt das Kriterium); jeder Schaltvorgang wird auditiert (plan.autoopt.konfiguriert, D1). Entscheidung: Schalter global je Werkstatt-DO (= je Tenant, da ein DO pro Tenant — OP-TENANT), nicht je Nutzer — die Planungs-Policy ist eine Betriebs-, keine Personen-Einstellung; Rollen-Gate folgt mit OP-AUTH-1. (2) Benachrichtigung: beim Auto-Anwenden broadcastet der DO plan.autoAngewendet (Grund + betroffene Auftragsnummern/Δ) an alle Verbindungen → Toast „⟲ Plan automatisch nachgeführt · …" (Leitstand und Werker-Terminals in „Meine Arbeit" — die nachgerückte Queue springt nicht mehr kommentarlos). Entscheidung: In-App-Broadcast statt Push/E-Mail — es gibt noch keinen Mitarbeiter-Login/Push-Kanal (OP-AUTH-1/OP-R1-2); der Toast an alle ist die ehrliche v1, personalisierte Zustellung folgt mit dem Login. Verifikation: Server tsc + Persistenz-Gate (check-persistence.sh, 20/20 Felder gedeckt) · Client ng build + No-Hex grün. Doku: Lastenheft OP-OPT-9 (Slice 4, Offen-Liste) · HANDOFF §2/§4 · Funktionsumfang · CHANGELOG · Timesheet.
  • Branch claude/planning-queue-optimization-iniw7z (#393) — OP-OPT-9: „Nächste Aufgaben"-Queues je Mitarbeiter/Arbeitsplatz + Auto-Anwenden terminneutraler Re-Opt-Verbesserungen (Version 0.58.0 → 0.59.0, MINOR). Nutzer-Impuls (07-03): „Hat jeder Platz/Mitarbeiter eine priorisierte Queue geeigneter nächster Aufträge? Wird bei jeder Veränderung neu das nächste Optimum vorgeschlagen? Das würde das Ganze dynamischer machen, anstatt einen pseudo-korrekten Plan zu huldigen." Befund: die Dynamik existierte bereits (event-getriggerte Re-Opt rechnet nach jedem materiellen Event neu), aber (a) ohne Ressourcen-Queue-Sicht und (b) jede Verbesserung blieb bestätigungspflichtig. (1) „Nächste Aufgaben" je Mitarbeiter/Arbeitsplatz (neu client/src/app/leitstand/naechste-aufgaben.component.ts, in der Planung unter dem Gantt): die priorisierte Queue jeder Ressource als reine Projektion des aktuellen Plans (Derived State S-2 — kein neues Schema, kein Server-Change): läuft jetzt (▸) · pausiert (⏸) · kommt als Nächstes (1…n in Plan-Reihenfolge); je Eintrag Start · Auftrags-Nr. · Schritt · 🎓-Helfer-Kennung · ⚡ bei Termin-Konflikt; Karten-Kopf zeigt je Ressource „frei ab …" bzw. „jetzt frei" (True-North-Frage 3 — nächste freie Kapazität); Tabs Mitarbeiter/Arbeitsplätze (Bucht-Freigabe inkl. Cool-down via bayEnd); Klick öffnet das geteilte Detail-Panel (fokussierter Schritt). Entscheidung — Architektur bleibt globaler Plan: echte lokale Dispatch-Queues (greedy „nimm den nächsten geeigneten Auftrag") verworfen — sie verlieren gegen CP-SAT Abhängigkeiten, Termingarantien, Park-/Buchtkonflikte, G-2/G-3; die Queue ist die Ressourcen-Projektion des globalen Optimums, nicht sein Ersatz. (2) Auto-Anwenden (Server): die event-getriggerte Re-Opt (aktualisiereVorschlaegeAuto) wendet terminneutrale Pareto-Verbesserungen jetzt direkt an statt nur vorzuschlagen. Kriterium pure + getestet in neu server/src/operativ/autoopt.ts (autoAnwendbar): ≥1 Auftrag echt früher fertig UND keiner später — „keiner später" garantiert zugleich, dass kein Wunsch-Abholtermin neu reißt; reine Umsortierungen ohne Zeitgewinn werden bewusst NICHT angewendet (Plan-Stabilität — kein Zappeln durch gleichwertige CP-SAT-Alternativlösungen, keine Endlos-Nachführung). Beim Anwenden: Chronik-Eintrag je geändertem Auftrag („Plan automatisch nachgeführt: X früher fertig"), Audit-Event plan.auto (wie in docs/architektur/Audit-Log.md vorgesehen), solverInfo „Auto-Optimierung angewendet: …", Persist + Broadcast; Trade-offs (jemand würde später fertig) bleiben unverändert bestätigungspflichtiger Vorschlag im Feed — „Vorschlag statt Zwang" gilt weiter für alles Nicht-Risikofreie. Neuer Selbsttest test:autoopt (+ CI) fixiert genau diese Grenze. (3) Persönliche Queue in „Meine Arbeit" (Folge-Slice im selben PR): die Werker-Sicht sortiert die eigenen Schritte jetzt in Plan-Reihenfolge (laufend → pausiert → geplant nach Optimierer-Startzeit, vorher Auftragsnummer), nummeriert die wartenden Schritte (1 = als Nächstes dran), zeigt je geplantem Schritt „ab " und im Kopf „laut Plan frei " — dieselbe Projektion wie die Planung-Queues, für den einzelnen Werker. Review-Härtung (CodeRabbit): Queue-Reihung/Positions-Nummern/„frei ab" als pure Helfer extrahiert (client/src/app/leitstand/queue-reihenfolge.ts, von Planung-Queues und „Meine Arbeit" geteilt) + neuer Selbsttest test:queue (+ CI, Tests.md); „laut Plan frei"-Badge prüft nicht mehr falsy (formatierter String statt Zahl — Zeitwert 0 bliebe sichtbar, Sentinel ist null); OP-ID-Kommentar-Korrekturen (OP-OPT-8→9 in ci.yml/leitstand.ts), unnötiger CommonModule-Import entfernt; Fog-Finding (Queue im Entwurfs-Modus gemutet) als gewolltes OP-R8-15-Verhalten begründet abgelehnt, von CodeRabbit zurückgezogen. Verifikation: Server tsc + test:autoopt · Client ng build + test:queue grün. Doku: Lastenheft §11.2 OP-OPT-9 · HANDOFF §2/§4 · Funktionsumfang · Tests.md · Sanity-Checkliste (F3) · Timesheet.
  • Branch claude/pickup-date-special-requests-6hrlnc (#391) — OP-UX-1/U9 + R7-F10: Frühestmöglicher Abholtermin direkt in der Annahme angeboten + Sonderwünsche erfassen (Version 0.57.0 → 0.58.0, MINOR). Nutzer-Wunsch (07-03, Screenshot): „In der Annahme soll direkt der frühestmögliche Abholtermin basierend auf dem gewählten Service angeboten werden. Sonderwünsche müssen auch erfasst werden können." (1) Termin-Vorschlag: neuer Dry-Run auftrag.terminvorschlag ({leistungId, anlieferung, gueteklasse}auftrag.terminvorschlag.result mit fruehesteAbholung = scheduleLeistung(...).abholbereit inkl. Standzeit — dieselbe Größe, an der auftrag.create/pruefen die Wunschtermin-Warnung messen; kein State-Change/Broadcast/Reopt, wie auftrag.pruefen). Das Annahme-Formular fragt ihn entprellt (300 ms) bei Leistung-/Anlieferung-/Güteklasse-Änderung an (ohne Anlieferung ab „jetzt"). Entscheidung Vorbefüll-Regel: ein leeres oder zuvor automatisch befülltes Wunsch-Abholung-Feld wird sofort vorbefüllt; ein Hand-Wert bleibt unangetastet (Zeile „Frühestmöglich: … · Übernehmen" darunter); nicht machbar ⇒ dezenter Amber-Hinweis mit konkretem Grund (hartes Gate bleibt der Prüfen-Schritt). Neue Zeit-Helfer minToInput/nowInput (client/src/app/util/time.ts, UTC-Wanduhr-Konvention wie Server-parseIso). (2) Sonderwünsche (R7-F10 — war spezifiziert, nicht gebaut): optionales Freitext-Feld in der Annahme → auftrag.create.sonderwuenscheAuftrag.sonderwuensche (additiv/optional, keine Migration) → sichtbar im Bestätigungs-Dialog + im Aufträge-Detail (Fakten-Grid, volle Breite). Abgrenzungen (Entscheidungen): Freitext am Auftrag genügt v1 — Struktur/Häufigkeits-Auswertung bleibt OP-FIND-1, Sonderwünsche als geprüfter QS-Punkt bleibt der vertagte istAbnahmebereit-Erweiterungspunkt (OP-QS-GATE), Kommentar-Verlauf mit Foto/Voice bleibt OP-R7-12; kein neuer Self-Test (Handler = dünner Wrapper über den getesteten TS-Scheduler, Feld = Pass-through). Verifikation: Server tsc + Smokes (spike/operativ/test:teilplan/test:abnahme/test:preis) · Client ng build grün. Doku: Operative-Durchgaengigkeit.md §U9 · Lastenheft §5.1 F10 + §5.2.2 · Funktionsumfang.md · HANDOFF §2 · Timesheet.
  • Branch claude/dependabot-vulnerabilities-0wzu6o (#389) — RISK-4/OP-SBOM-1/OP-SEC-1: Dependabot-/Vuln-Assessment + Safe-Fixes (Version 0.57.0 → 0.57.1, PATCH — Security-Tweaks, keine neue Funktion). Befund: 0 Prod-Runtime-Vulns (Server/Client npm audit --omit=dev = 0, pip-audit Solver grün; auch die neuen Client-Runtime-Deps html2canvas-pro/@angular/service-worker advisory-frei) — alle 57 Voll-Audit-Findings (Server 8 · Client 12 · docs-site 37) lagen ausschließlich in Dev-/Build-Toolchains. Entscheidung (Nutzer-Wahl): „Assess + Safe-Fixes" — nur nicht-brechende Bumps, keine Major-/Force-Upgrades. Fixes: (1) wrangler ^4.100 → ^4.105 (Server + docs-site) → undici-TLS-Bypass-/ws-DoS-/miniflare-Highs beseitigt; (2) Client npm audit fix (Angular-Build 20.3.28→20.3.31, vite 7.3.2→7.3.5 — Highs weg) + Patch-Override http-proxy-middleware 3.0.7 (Angular pinnt exakt die verwundbare 3.0.5; Override = kleinste nicht-brechende Lösung, wieder entfernbar sobald Angular selbst bumpt); (3) flyctl-Action SHA-gepinnt (ed8efb3… = v1.6; war die letzte @master-Referenz → Supply-Chain-Lücke zu, Dependabot github-actions trackt den Pin). Akzeptierte Dev-only-Residuen (begründet, kein nicht-brechender Fix): drizzle-kit→@esbuild-kit/esbuild (moderate; npm-„Fix" wäre Downgrade auf drizzle-kit 0.18 — abgelehnt), Client babel-/uuid-Ketten (low/moderate, Angular-Exakt-Pins), docs-site serialize-javascript (high, aber nur Build-Cache der statisch generierten Doku mit vertrauenswürdigen Inputs; npm-„Fix" wäre Docusaurus-Downgrade — abgelehnt; löst sich mit Docusaurus-Bump). Verifiziert: Prod-Gates grün, ng build + docs-site-Build grün. Doku: Risikoregister RISK-4 (Prüfdatum 07-03) + Compliance C-05 + HANDOFF OP-SBOM-1 (flyctl-Pin aus „Offen" erledigt; 1 Union-Merge-Duplikat entfernt — ältere §4-Generationen-Dubletten verbleiben für eine eigene Glättungs-Session), CHANGELOG, Timesheet.
  • Branch claude/markup-rendering-issue-tooltips-8i90j3 (#388) — OP-DOCS-2/-7: Markdown-Rendering im Doku-Widget + Issue-Details-Tooltip mit Screenshot-/Bild-Vorschau (Version 0.56.0 → 0.57.0, MINOR — 0.55/0.56 parallel von #379/#384 vergeben, OP-PM-2-Muster). Befund (Nutzer-Screenshot): Assistent-Antworten im Doku-Widget erschienen als roher Markdown-Text (###, **fett**, [Link](…) unformatiert); Wunsch: die Issue-Liste soll Details im Tooltip inkl. verlinkter Screenshots/Bilder zeigen. (1) Markdown-Rendering: widget-eigener minimaler Renderer mdHtml (Entscheidung: keine Markdown-Lib — Leitprinzip Einfachheit, kein neues Bundle-Gewicht): erst wird alles escaped, dann zeilenbasiert Überschriften/Listen/Trennlinien/```-Code-Blöcke + Inline **fett**/*kursiv*/`Code`/[Links](…) mit Schema-Allowlist (nur http(s)/relativ; javascript:/data: bleiben Text) umgesetzt; escapeHtml escapet jetzt auch " (Attribut-sicher); Nutzer-Blasen bleiben Klartext. (2) Issue-Details-Tooltip: FeedbackIssue um details (Issue-Body ohne <sub>-Meta-Fußzeile/Bild-Markup, 600 Zeichen gekappt) + bilder (extrahierte Bild-Links: Markdown-Bilder, <img src>, Bild-URLs inkl. GitHub-Attachments + Access-gated Screenshot-Link aus feedbackZuIssue) erweitert — reine Helfer detailsAusIssueBody/bilderAusIssueBody (github-issues.ts), DTO-Symmetrie beidseitig. Doku-Widget: Hover-/Fokus-Tooltip je Issue-Zeile (position:fixed gegen Panel-Overflow-Clipping; bleibt beim Überfahren offen → Bild-Links klickbar; 📷-Marker bei angehängten Bildern); App-Formular „Bisheriges Feedback“: derselbe Tooltip (verzögertes Ausblenden; Entscheidung: Details dort als Klartext, kein eigener Markdown-Renderer im Angular-Client — Einfachheit). Nachschärfung (Nutzer „Ich sehe die Issues nur im Chat-Dialog — wo ist das in der App?“): die Übersicht war in der App nur im Feedback-Formular versteckt → neuer „🗂 Issues“-Umschalter im Assistent-Panel (Kopfzeile neben „📍 Feedback“) zeigt die read-only Liste direkt im Chat-Drawer; Liste + Tooltip in wiederverwendbare Komponente feedback-issues-liste.component.ts extrahiert (Formular + Panel nutzen dieselbe — Wiederverwendung statt Duplikat). Bilder laden best-effort (Access-/GitHub-gated Quellen brauchen ggf. Anmeldung; Link öffnet im Tab). Verifikation: test:assistant-feedback (+10 Asserts: Bild-Extraktion · Details ohne Meta/Bilder · Kappung · Mapping) · Server-tsc · ng build · Widget-JS-Syntax-Check grün. Merge-Auflösung: #379 (Feedback-Overlay statt Dialog-Liste) hat die Formular-Liste entfernt → dort gilt mains UX; die Panel-Liste bleibt als Gesamtsicht komplementär zum route-bezogenen Overlay; Server-Helfer beider Seiten (selektor + details/bilder) zusammengeführt. Doku: In-App-Assistent.md §9 Slice 15, HANDOFF (OP-AI-4), Tests.md, CHANGELOG, Timesheet.
  • Branch claude/chatbot-docs-bug-6zvwnv (#324) — OP-DOCS-2: Doku-Chatbot-Widget funktionierte produktiv nicht → Same-Origin-Proxy (Version 0.53.0 → 0.54.0 — Bugfix + neues Feature „Feedback-Übersicht“, s. u.). Befund (Nutzer-Screenshot): jede Frage im Widget auf docs.taktano.com endete mit „⚠ Server nicht erreichbar“. Ursache: der Cross-Origin-Fetch nach app.taktano.com kam nie am Worker an — Cloudflare Access an der Edge fing CORS-Preflight (OPTIONS trägt nie ein Cookie) und credentials-POST (kein App-Access-Cookie im Docs-Browser-Kontext) mit einem Login-Redirect ohne CORS-Header ab → fetch-TypeError → Catch-Zweig des Widgets. Die Worker-seitige CORS-/OPTIONS-Behandlung (#291) war korrekt, lief aber hinter dem Edge-Gate; die Slice-11-Annahme „Access-Vars leer ⇒ Fetch klappt“ verwechselte Worker-JWT-Prüfung mit Edge-Gate. Entscheidung — Fix als Code statt Access-Dashboard-Konfiguration (Everything-as-Code): Same-Origin-Proxy auf der Docs-Site — neue Pages-Function docs-site/functions/parties/[[pfad]].js (bewusst eng: nur POST auf assistant · feedback · feedback/aehnliche, kein WS-/State-Durchgriff) + Service-Binding APP_WORKER auf den Worker taktano (docs-site/wrangler.toml) — Worker-zu-Worker, nicht über die Edge ⇒ kein CORS-Preflight, kein zweites Access-Cookie; Alternative „gemeinsame Access-App + Access-CORS-Settings“ verworfen (Dashboard-Zustand außerhalb des Repos, hätte zusätzlich einen bestehenden App-Login im Browser vorausgesetzt). Widget + docusaurus.config.js defaulten auf same-origin (leerer TAKTANO_APP_ORIGIN; Override für Preview/Staging bleibt). Sicherheit unverändert: Access gated weiterhin docs.taktano.com (intern-only); der DO erkennt das Doku-Frontend weiter über den Origin-Header (ASSISTENT_CORS_ORIGINS) → Werkzeugfilter dokuSuche+datenmodell greift. Folge-Hinweis: beim Scharfschalten der Worker-JWT-Prüfung (OP-COST-3) Docs-AUD akzeptieren bzw. gemeinsame Access-App (In-App-Assistent.md §9 Slice 12). Verifikation: docs-site npm run build grün · Proxy-Pfad-Allowlist per Node geprüft · Server tsc grün. Zusätzlich im selben PR — Feedback-Übersicht (Nutzer-Wunsch, MINOR): App + Doku zeigen read-only, wo es offenes und geschlossenes Feedback gibt, gespeist aus den GitHub-Issues des Feedback-Pfads (Label feedback — kein zweiter Datenbestand). Server: neuer DO-Endpoint GET /feedback/liste (FeedbackListe, dormant ohne TAKTANO_FEEDBACK_TOKEN, Berechtigung wie /assistant) + reine Helfer githubFeedbackListePfad (List-Issues, state=all), issuesAusListe (PRs raus, Status sprechend offen/geschlossen), routeAusIssueBody (liest die beim Anlegen strukturiert hinterlegte Verortung/Route aus dem Issue-Body zurück). App: Sektion „Bisheriges Feedback“ im Feedback-Formular (Status-Badge amber/grün · Titel-Link · Route). Doku-Widget: dritter Tab „Issues“ (read-only Liste, über den Same-Origin-Proxy; Allowlist um GET feedback/liste erweitert; Formular im Issues-Tab ausgeblendet). DTO-Symmetrie FeedbackIssue/FeedbackListe beidseitig; test:assistant-feedback um Listen-Pfad/Route-Rücklese/Status-Mapping erweitert (Tests.md nachgezogen). Verifikation: Server tsc + test:assistant-feedback · Client ng build + No-Hex · docs-site build · Proxy-Allowlist-Check (POST+GET) grün. Doku: In-App-Assistent.md (§9 Slice-11-Korrektur + Slice 12 + Slice 13), HANDOFF (§2-Tabelle + OP-AI-4), Tests.md, CHANGELOG, Timesheet.
  • Branch claude/vectorize-rag-analysis-ad9mt5 (neu von main aufgesetzt — #304 ist gemergt; #323) — OP-OBS-1/OP-DOCS-2: CI-Warnungen in den zentralen Log-Sink + Leitlinie „OTLP/Grafana ist DER Log-Sink" (Tooling/Workflows/Doku, kein App-Bump). Auftrag (Nutzer): „Can we make that step continue on error aber mit Warnung in log" + „Add general guideline: OTLP/Grafana is log sink". Befund: der RAG-Push-Step war bereits continue-on-error + ::warning::-Annotation — aber die Annotation ist nur im Actions-Run sichtbar, nicht in Grafana, wo Warnungen betrachtet werden. Gebaut: (1) scripts/push-doku-index.mjs sendet bei jedem Fehler zusätzlich ein WARN-Log-Event an den OTLP-Endpoint (meldeWarnungAnGrafana, service.name=taktano-ci, gleiche Konventionen wie server/src/obs/otlp.ts: <endpoint>/v1/logs, Header key=value,… URL-dekodiert; best-effort mit Timeout, dormant ohne Endpoint) → gescheiterte Re-Indizierungen erscheinen im „Fehler & Warnungen"-Panel statt still zu bleiben; beide Workflow-Steps (ci.yml deploy + docs-deploy) reichen OTEL_EXPORTER_OTLP_ENDPOINT/_HEADERS durch. (2) Leitlinie verankert (Root-CLAUDE.md §Observability + Observability.md §1): OTLP/Grafana ist der zentrale Log-Sink für Laufzeiten UND Tooling-/CI-Schritte; console/Actions-Annotationen sind Kontext-Ergänzung, nie Ersatz; best-effort + dormant, bricht nie den Deploy-Pfad. Verifikation: node --check · Fehlerpfad-Dry-Run (Bogus-Creds + unerreichbarer OTLP-Endpoint → Actions-Warnung + „nicht zustellbar"-Hinweis + Exit 0) · Workflow-YAML valide · doku-index regeneriert. Doku: CLAUDE.md, Observability.md §1, ci.yml, docs-deploy.yml, CHANGELOG, Timesheet.
  • Branch claude/chatbot-docs-bug-6zvwnv (2. Neuauflage) (PR folgt) — OP-DOCS-7: Neues Feedback in Echtzeit an alle (Partykit-Broadcast) (Version 0.55.0 → 0.56.0 MINOR). Nutzer-Befund: neues Feedback erschien nicht direkt in der UI — soll „weiterhin per Echtzeit/Broadcast/Partykit an alle mitgeteilt werden“. Gebaut: DO broadcastet nach erfolgreichem Anlegen in erstelleFeedbackIssue (deckt deterministischen /feedback-Pfad UND LLM-Tool) ein neues ServerMsg-Event feedback.neu mit dem fertigen FeedbackIssue (Nummer aus der Issue-URL, Titel/Labels aus dem Entwurf, Route/Selektor aus dem Anker — kein GitHub-Re-Fetch; best-effort, bricht das Anlegen nie) an alle Verbindungen. App: LeitstandService reicht an neues FeedbackService.issueEingegangen weiter — mergt vorn+dedupliziert in die Übersicht (Marker/Seiten-Chip aktualisieren live über die Signals) + dezenter Info-Toast „💬 Neues Feedback · #N“ für alle. Doku bewusst ohne WebSocket (Doku-Frontend erhält keine Live-State-Broadcasts, OP-DOCS-5-Schranke): 60-s-Frische-Refresh solange das Overlay an ist + Refresh bei Seitenwechsel (TTL 60 s) + sofortiger Refresh nach eigenem Widget-Feedback. Verifikation: Server tsc · Client ng build (prod) · docs-site build grün. Doku: In-App-Assistent.md §9 Slice 14a, HANDOFF, CHANGELOG, Timesheet.
  • Branch claude/chatbot-docs-bug-6zvwnv (Neuauflage) (PR folgt) — OP-DOCS-7/OP-FEEDBACK-1: Feedback-UX-Umbau — Ein-Schritt-Screenshot · Feedback-Overlay statt Dialog-Liste · globaler Toggle (Version 0.54.0 → 0.55.0 MINOR). Nutzer-Feedback: „der Feedback-Dialog ist nicht gut“ — drei Wünsche: Markierung/Verpixelung direkt beim Screenshot (Element-Auswahl + Aufnahme + Nachbearbeitung = ein Schritt), bisheriges Feedback nicht im Dialog sondern als Overlay/„Tooltip“ in App & Doku, globaler Ein-/Aus-Toggle wie Light/Dark. Gebaut: (a) neues Vollbild-Editor-Overlay screenshot-editor-overlay.component.ts (öffnet direkt nach Region-Ziehen ODER Element-Auswahl; bild-upload-gate unverändert wiederverwendet); der Feedback-Pin erfasst das angeklickte Element automatisch als Screenshot (sichtbarer Ausschnitt + 12 px Rand, best-effort; Pin-Overlay/Formular via data-tk-screenshot-ignore nie im Bild); Formular verschlankt (nur Auslöser + Status). (b) Feedback-Overlay App feedback-marker-overlay.component.ts: Marker am verorteten Element — Server liest dafür den Element-Anker aus dem Issue-Body zurück (neu selektorAusIssueBodyFeedbackIssue.selektor, DTO beidseitig; kein zweiter Datenbestand) — Klick-Tooltip (● offen amber / ✓ geschlossen grün · Titel-Link), Seiten-Chip für Feedback ohne (auffindbaren) Anker, Positionen folgen Scroll/Resize/Navigation (rAF-gedrosselt); Dialog-Liste entfernt. Doku: Navbar-Toggle 💬 (html-Navbar-Item + Delegation im Client-Modul) + Seiten-Chip mit Popover der Issues dieser Seite; Widget-Tab „Issues“ (Gesamtliste) bleibt. (c) Toggle Rail-Button „Feedback-Anzeige“ (unter dem Theme-Umschalter) bzw. Doku-Navbar; localStorage tk-feedback-overlay, Default aus. Verifikation: Server tsc + test:assistant-feedback (Selektor-Rücklese) · ng build + No-Hex + test:bildgate · docs-site build grün. Doku: In-App-Assistent.md §9 Slice 14, HANDOFF, CHANGELOG, Timesheet.
  • Branch claude/chatbot-docs-bug-6zvwnv (PR folgt) — OP-DOCS-2: Doku-Chatbot-Widget funktionierte produktiv nicht → Same-Origin-Proxy (Version 0.53.0 → 0.54.0 — Bugfix + neues Feature „Feedback-Übersicht“, s. u.). Befund (Nutzer-Screenshot): jede Frage im Widget auf docs.taktano.com endete mit „⚠ Server nicht erreichbar“. Ursache: der Cross-Origin-Fetch nach app.taktano.com kam nie am Worker an — Cloudflare Access an der Edge fing CORS-Preflight (OPTIONS trägt nie ein Cookie) und credentials-POST (kein App-Access-Cookie im Docs-Browser-Kontext) mit einem Login-Redirect ohne CORS-Header ab → fetch-TypeError → Catch-Zweig des Widgets. Die Worker-seitige CORS-/OPTIONS-Behandlung (#291) war korrekt, lief aber hinter dem Edge-Gate; die Slice-11-Annahme „Access-Vars leer ⇒ Fetch klappt“ verwechselte Worker-JWT-Prüfung mit Edge-Gate. Entscheidung — Fix als Code statt Access-Dashboard-Konfiguration (Everything-as-Code): Same-Origin-Proxy auf der Docs-Site — neue Pages-Function docs-site/functions/parties/[[pfad]].js (bewusst eng: nur POST auf assistant · feedback · feedback/aehnliche, kein WS-/State-Durchgriff) + Service-Binding APP_WORKER auf den Worker taktano (docs-site/wrangler.toml) — Worker-zu-Worker, nicht über die Edge ⇒ kein CORS-Preflight, kein zweites Access-Cookie; Alternative „gemeinsame Access-App + Access-CORS-Settings“ verworfen (Dashboard-Zustand außerhalb des Repos, hätte zusätzlich einen bestehenden App-Login im Browser vorausgesetzt). Widget + docusaurus.config.js defaulten auf same-origin (leerer TAKTANO_APP_ORIGIN; Override für Preview/Staging bleibt). Sicherheit unverändert: Access gated weiterhin docs.taktano.com (intern-only); der DO erkennt das Doku-Frontend weiter über den Origin-Header (ASSISTENT_CORS_ORIGINS) → Werkzeugfilter dokuSuche+datenmodell greift. Folge-Hinweis: beim Scharfschalten der Worker-JWT-Prüfung (OP-COST-3) Docs-AUD akzeptieren bzw. gemeinsame Access-App (In-App-Assistent.md §9 Slice 12). Verifikation: docs-site npm run build grün · Proxy-Pfad-Allowlist per Node geprüft · Server tsc grün. Zusätzlich im selben PR — Feedback-Übersicht (Nutzer-Wunsch, MINOR): App + Doku zeigen read-only, wo es offenes und geschlossenes Feedback gibt, gespeist aus den GitHub-Issues des Feedback-Pfads (Label feedback — kein zweiter Datenbestand). Server: neuer DO-Endpoint GET /feedback/liste (FeedbackListe, dormant ohne TAKTANO_FEEDBACK_TOKEN, Berechtigung wie /assistant) + reine Helfer githubFeedbackListePfad (List-Issues, state=all), issuesAusListe (PRs raus, Status sprechend offen/geschlossen), routeAusIssueBody (liest die beim Anlegen strukturiert hinterlegte Verortung/Route aus dem Issue-Body zurück). App: Sektion „Bisheriges Feedback“ im Feedback-Formular (Status-Badge amber/grün · Titel-Link · Route). Doku-Widget: dritter Tab „Issues“ (read-only Liste, über den Same-Origin-Proxy; Allowlist um GET feedback/liste erweitert; Formular im Issues-Tab ausgeblendet). DTO-Symmetrie FeedbackIssue/FeedbackListe beidseitig; test:assistant-feedback um Listen-Pfad/Route-Rücklese/Status-Mapping erweitert (Tests.md nachgezogen). Verifikation: Server tsc + test:assistant-feedback · Client ng build + No-Hex · docs-site build · Proxy-Allowlist-Check (POST+GET) grün. Doku: In-App-Assistent.md (§9 Slice-11-Korrektur + Slice 12 + Slice 13), HANDOFF (§2-Tabelle + OP-AI-4), Tests.md, CHANGELOG, Timesheet.
  • Branch claude/vectorize-rag-analysis-ad9mt5 (neu von main aufgesetzt — #304 ist gemergt; PR folgt) — OP-OBS-1/OP-DOCS-2: CI-Warnungen in den zentralen Log-Sink + Leitlinie „OTLP/Grafana ist DER Log-Sink" (Tooling/Workflows/Doku, kein App-Bump). Auftrag (Nutzer): „Can we make that step continue on error aber mit Warnung in log" + „Add general guideline: OTLP/Grafana is log sink". Befund: der RAG-Push-Step war bereits continue-on-error + ::warning::-Annotation — aber die Annotation ist nur im Actions-Run sichtbar, nicht in Grafana, wo Warnungen betrachtet werden. Gebaut: (1) scripts/push-doku-index.mjs sendet bei jedem Fehler zusätzlich ein WARN-Log-Event an den OTLP-Endpoint (meldeWarnungAnGrafana, service.name=taktano-ci, gleiche Konventionen wie server/src/obs/otlp.ts: <endpoint>/v1/logs, Header key=value,… URL-dekodiert; best-effort mit Timeout, dormant ohne Endpoint) → gescheiterte Re-Indizierungen erscheinen im „Fehler & Warnungen"-Panel statt still zu bleiben; beide Workflow-Steps (ci.yml deploy + docs-deploy) reichen OTEL_EXPORTER_OTLP_ENDPOINT/_HEADERS durch. (2) Leitlinie verankert (Root-CLAUDE.md §Observability + Observability.md §1): OTLP/Grafana ist der zentrale Log-Sink für Laufzeiten UND Tooling-/CI-Schritte; console/Actions-Annotationen sind Kontext-Ergänzung, nie Ersatz; best-effort + dormant, bricht nie den Deploy-Pfad. Verifikation: node --check · Fehlerpfad-Dry-Run (Bogus-Creds + unerreichbarer OTLP-Endpoint → Actions-Warnung + „nicht zustellbar"-Hinweis + Exit 0) · Workflow-YAML valide · doku-index regeneriert. Doku: CLAUDE.md, Observability.md §1, ci.yml, docs-deploy.yml, CHANGELOG, Timesheet.
  • Branch claude/llm-cost-auto-deduction-o3pd0p (#322) — OP-AI-4: Hybrid-Matching für Live-Daten (exakt + semantisch) (Version 0.52.0 → 0.53.0 MINOR — neues Feature). Befund (Nutzer-Screenshot): „Wer kann Kaffee kochen?“ fand den Skill „Kaffee machen“ nicht — der datenListe-Filter war ein Ganz-Phrasen-Substring ("kaffee machen".includes("kaffee kochen") = false); die semantische Suche (RAG) deckte nur die Doku ab. Gebaut (Nutzer-Wunsch „Kombination aus exakter und semantischer Suche auch für Live-Daten“) — dreistufig: (1) Token-Matching (neues reines Modul server/src/assistant/matching.ts: tokens/tokenTreffer — ein Anfrage-Wort genügt, Ganz-Phrase bleibt Teilmenge); (2) semantisch: ohne Token-Treffer wird die Anfrage eingebettet (EU-Modell, wie RAG) und per Cosine gegen lazy gecachte Embeddings der Skill-Namen gerankt (semantischeTreffer, Schwelle 0.6/top 3) — Vektoren transient im DO-Speicher (derived, nie persistiert, nicht Vectorize: nur Taxonomie-Namen, kein PII → RISK-17 unverändert), Treffer dem LLM transparent als „semantisch ähnlich“ markiert (Anti-Halluzination), Embed-Calls zählen in taktano_llm_tokens{zweck=embedding}; (3) Selbstkorrektur: bleibt alles leer, nennt das Werkzeug die verfügbaren Skill-Namen → das LLM matcht in der nächsten Tool-Runde selbst. datenListeText async (+llm), Token-Matching auch für skills/leistungen-Filter. Neuer Self-Test test:matching (CI Server-Job + Tests.md — der neue Warn-Check aus #302 hat das Fehlen prompt selbst angemahnt, Regel wirkt). Verifikation: tsc + test:matching + test:assistant-tools + check-no-console grün. Doku: In-App-Assistent.md (§Hybrid-Matching), Tests.md, ci.yml, CHANGELOG, HANDOFF, Timesheet.
  • Branch claude/llm-cost-auto-deduction-o3pd0p (#321) — OP-OBS-1/OP-AI-4: LLM-Dashboard + Token-Verbrauchs-Metrik (Version 0.51.1 → 0.52.0 MINOR — neues Feature). Auftrag (Nutzer): dediziertes Dashboard für die LLM-Nutzung, Variante „b — mit Token-Metrik“. Gebaut: (1) Token-Metrik: LlmKonfig.onUsage-Callback + reiner Parser leseUsage() (server/src/assistant/llm.ts, defensiv gegen fehlende/kaputte usage-Blöcke, wirft nie) — der DO zählt taktano_llm_tokens{zweck,art} (zweck=chat|embedding · art=prompt|completion) je API-Antwort; test:assistant-tools um leseUsage-Asserts erweitert. (2) Neues Dashboard grafana/dashboards/taktano-llm.json (uid taktano-llm, wird vom #307-API-Push automatisch eingespielt): Turn-Rate je Frontend/Ergebnis · Turn-Latenz P50/P95 · Token-Verbrauch (Rate + Summe im Zeitraum) · RAG-Wirkung (3 Panels aus dem Technik-Board) · Kosten-Pull-Gesundheit · letzte Assistent-Fehler (Loki, detected_level). Scope-Leitplanke bestätigt: Nutzungs-/Technik-Sicht in Grafana — die Euro-Kosten bleiben im Kosten-Workspace der App (OP-COST-2). Verifikation: tsc + test:assistant-tools + test:grafana-dashboards (2 Dashboards) grün. Doku: grafana/README.md (Datei- + Metrik-Liste), CHANGELOG, HANDOFF, Timesheet.
  • Branch claude/llm-cost-auto-deduction-o3pd0p (#320) — OP-OBS-1: Build-Nummer + Build-Zeit dezent im Grafana-Dashboard (Version 0.51.0 → 0.51.1 PATCH — kleiner Tweak). Auftrag (Nutzer): „Bitte auf dem Grafana Dashboard auch die Build-Nummer und Zeitstempel dezent anzeigen.“ Gebaut: (1) Server: OtlpResource um buildZeit erweitert (APP_BUILD_ZEIT → Resource-Attribut service.build_zeit in Logs- und Metrics-Payload; alle 4 Resource-Stellen: DO-Flush, Verbindungstest, Client-Endpoint) — damit steht der Deploy-Zeitstempel an jeder Telemetrie-Zeile, nicht nur in der seltenen Boot-Zeile. (2) Dashboard: schmales Stat-Panel (h2, rechte Spalte unter Fehler/Warnungen, textMode=name, ohne Farbe/Graph = dezent) zeigt v{{service_version}} · Build {{service_build}} · {{service_build_zeit}} aus den Log-Resource-Labels; Fehler/Warnungen-Stats auf h3 verschlankt (Spalte bleibt bündig). Mehrere Werte im Zeitfenster = ehrlicher Rollover-Hinweis. Verifikation: tsc + test:obs + test:obs-client + test:grafana-dashboards grün. Doku: CHANGELOG, HANDOFF, Timesheet; Dashboard aktualisiert sich nach Merge automatisch (API-Push #307).
  • Branch claude/llm-cost-auto-deduction-o3pd0p (#319) — OP-OBS-1: Dashboard-Queries auf OTLP→Loki-Realität umgestellt (Fix „No data“) (Dashboard/Doku, kein App-Bump). Befund (Nutzer-Screenshot): Dashboard „Taktano — Technik-Telemetrie“ zeigte überall „No data“ + JSONParserErr — die Daten waren in Loki (Serie service_name=taktano-server sichtbar), aber die Panels parsten | json, während der Grafana-Cloud-OTLP-Gateway den Log-Body nur als Kurz-Nachricht (msg) liefert und Level/Attribute als Structured Metadata (detected_level, severity_text, dienst …). Fix: alle 5 Loki-Queries umgestellt — Volumen/Fehler/Warnungen filtern auf detected_level (Label statt Parse), Kosten-Pull nutzt Zeilenfilter |= \"infraKosten.pull\" + dienst-Label; Legende {{detected_level}}; Panel-/README-Doku angepasst (Praxis-Befund festgehalten). Wirkung: erster echter Beleg der gesamten Kette — Dashboard aktualisiert sich nach Merge automatisch über den frisch gebauten API-Push (#307). Verifikation: test:grafana-dashboards grün (JSON valide). Doku: grafana/README.md (Label-Hinweis), CHANGELOG, HANDOFF, Timesheet.

2026-07-02

  • Branch claude/llm-cost-auto-deduction-o3pd0p (PR #307) — OP-OBS-1: Grafana-Dashboards automatisch per API einspielen (Dashboards-as-Code end-to-end) (CI/Tooling + Doku, kein App-Bump). Auftrag (Nutzer): „Erst Dashboard-Push per API" — Antwort auf die Frage, ob Dashboards automatisch über OTLP erscheinen (nein — OTLP transportiert nur Daten; Dashboards mussten bisher von Hand importiert werden). Gebaut: dependency-freies scripts/push-grafana-dashboards.mjs — spielt alle grafana/dashboards/*.json per Grafana-HTTP-API ein (POST /api/dashboards/db, overwrite: true; stabile uid ⇒ Update-in-place, kein Duplikat; entfernt id/__inputs/__requires). CI: (1) Deploy-Job pusht nach dem Worker-Deploy (dormant ohne GitHub-Secrets GRAFANA_URL + GRAFANA_DASHBOARD_TOKEN — Deploy bricht nie, Muster wie die Secret-Syncs); (2) neues netzfreies Gate test:grafana-dashboards (--check) im Server-Job: JSON parsebar · title/uid vorhanden · uid eindeutig · Payload baubar — ein kaputtes Dashboard bricht den PR, nicht erst den Deploy. In docs/betrieb/Tests.md eingetragen (mitführen-Regel). Entscheidungen: Repo = Single Source (Hand-Edits in Grafana werden beim Deploy überschrieben — Everything-as-Code); Grafana-API direkt statt Terraform/Grizzly (Leitprinzip Einfachheit: null neue Abhängigkeiten, ein 100-Zeilen-Script); Service-Account-Token mit Rolle Editor (least privilege). Aktivierung (Nutzer): Grafana-Service-Account + Token anlegen → 2 GitHub-Secrets setzen (grafana/README.md §Einspielen). Verifikation: --check grün (1 Dashboard valide) + dormant-Pfad verifiziert (übersprungen ohne Env). Doku: grafana/README.md (§Einspielen per API), Observability.md (§6a Auto-Provisioning), Tests.md, ci.yml, CHANGELOG, HANDOFF, Timesheet.
  • Branch claude/ipdad-fix-rinfjx (#306) — Build-Zeit sichtbar (UI + Logs) (Version 0.49.1 → 0.50.0 MINOR — kleines rückwärtskompatibles Feature; Build auto). Auftrag (Nutzer): neben Build-Nummer auch die Build-Zeit anzeigen. Gebaut: scripts/stamp-build.mjs stempelt zusätzlich APP_BUILD_ZEIT (Stempel-/Deploy-Zeitpunkt, ISO-UTC ohne Millisekunden) in server/src/build-number.ts (committeter Fallback bleibt leer = ehrlicher „ungestempelter Dev-Stand“, keine Fake-Zeit); version.ts re-exportiert die Zeit und hängt sie ans APP_VERSION_LABEL (→ Boot-Log-Zeile trägt sie automatisch); DO-State reicht appBuildZeit an den Client (baueState); Planung-Statuszeile zeigt „v… · Build … · 2026-07-02 18:30 UTC“ (kompakt bis Minute, Tooltip erklärt Leer=Dev). Entscheidungen: Stempel-Zeitpunkt = Deploy-Zeit (nicht Commit-Zeit — beantwortet „wann kam dieser Stand live?“); leerer Fallback statt Pseudo-Zeit; Anzeige im bestehenden Versions-Label (kein neues UI-Element). Verifikation: Stempel-Skript lokal (schreibt Nummer + Zeit, Fallback restauriert), Server-typecheck + ng build (prod) + No-Hex grün. Doku: CLAUDE.md §Versionierung, CHANGELOG, Timesheet.
  • Branch claude/ipdad-fix-rinfjx (#305) — OP-FEEDBACK-1: Screenshot-Aufnahme auf dem iPad repariert (html2canvashtml2canvas-pro) (Version 0.49.0 → 0.49.1 PATCH — Bugfix; Build auto). Befund (Nutzer, iPad): beim Feedback-Screenshot erschien „Screenshot-Aufnahme nicht verfügbar: Attempting to parse an unsupported color function “color”“. Ursache (verifiziert): das unmaintainte html2canvas@1.4.1 kann moderne CSS-Farbfunktionen (color(), oklch, lab, color-mix) nicht parsen; iPadOS/Safari liefert computed Styles als color(srgb …) → die Aufnahme bricht genau dort ab (Desktop-Chrome serialisiert als rgb(...), darum fiel es nur auf dem iPad auf). Fix (einfachste tragfähige Lösung): Wechsel auf html2canvas-pro@2.2.1 — der gepflegte, API-kompatible Fork, dessen Kernfeature genau die Unterstützung dieser Farbfunktionen ist; im screenshot.service.ts nur der Lazy-Import getauscht (Optionen backgroundColor/useCORS/scale/ignoreElements unverändert; deckender --tk-bg-Hintergrund bleibt wegen backdrop-blur). Nebeneffekt: der Fork liefert ESMallowedCommonJsDependencies-Workaround aus angular.json entfernt. Entscheidung: Fork statt Eigenbau/Workaround (kein CSS-Umschreiben auf Alt-Syntax, kein Patchen der Lib) — minimalste Änderung, gleiche API, Problem an der Wurzel. Verifikation: ng build grün (Capture-Lib bleibt Lazy-Chunk html2canvas-pro-esm ~246 kB raw, Initial-Bundle unverändert). Doku: In-App-Assistent.md §9 Slice 10, Bildbewertung.md, Lastenheft.md §11 OP-FEEDBACK-1, HANDOFF §4, CHANGELOG, Timesheet.
  • Branch claude/llm-cost-auto-deduction-o3pd0p (PR #303) — OP-OBS-1 Slice C1: Client-Telemetrie (Angular) → Grafana (Version 0.48.4 → 0.49.0 MINOR — neues Feature; Build auto). Auftrag (Nutzer): Slice C, Variante A (minimal, dependency-frei). Warum: unbehandelte Frontend-Fehler waren bisher unsichtbar (Blindflug). Kern-Entscheidung — kein Token im Browser: der Client POSTet same-origin an den Access-gegateten Worker-Endpoint POST /api/obs/client; der Worker mappt (rein/gehärtet, server/src/obs/client-logs.ts: parseClientLogPayload + clientEventsZuLogs) auf LogEvent[] (service=taktano-client) und leitet serverseitig via postOtlpLogs weiter (ctx.waitUntil) → Grafana-Token bleibt im Worker. Dormant ohne OTEL_EXPORTER_OTLP_ENDPOINT204. Client (client-obs.service.ts + TaktanoErrorHandler): Angular-ErrorHandler + window.onerror + unhandledrejection (+ manuelle error/warn/info); Ringpuffer (50), Batch-Flush alle 10 s + pagehide/visibilitychange (sendBeacon); best-effort, kein Re-Queue (keine Endlosschleife); Konsole zeigt Fehler weiterhin. Härtung (Browser-Payload = unvertrauenswürdig): Level-Whitelist, Anzahl-Deckel (50), Längen-/Content-Length-Limits, PII-Scrubbing. Neuer Test test:obs-client (CI Server-Job) + in docs/betrieb/Tests.md eingetragen (dogfood der neuen „mitführen"-Regel). Scope: Fehler-Forwarder; volles RUM (Web-Vitals/Sessions) = Faro = Slice C2 (offen). Verifikation: tsc + test:obs-client + check-no-console + ng build + check-doc-consistency grün. Doku: Observability.md (§ Slice C1), Tests.md, ci.yml, CHANGELOG, HANDOFF, Timesheet.
  • Branch claude/llm-cost-auto-deduction-o3pd0p (PR #302) — OP-DOCS-9: lebende Test-Übersicht + Regel „immer mitführen" (Doku + CI-Gate-Tweak, kein App-Bump). Auftrag (Nutzer): „Übersicht über alle automatischen Tests in der Doku immer mitführen." Gebaut: neue lebende Doku docs/betrieb/Tests.md — vollständige Liste aller automatischen Prüfungen in Tabellen (29 Server-test:*-Selbsttests · Server-Smokes · Client-Tests · Solver-Self-Test · alle Gates), je mit Befehl · Prüfgegenstand · OP-Bezug · CI-Job + „alles-lokal-ausführen"-Block. Stehende Regel verankert: CLAUDE.md §Tests & CI + docs/konventionen/agents.md (neue/entfernte Prüfung je PR nachziehen, wie CHANGELOG/HANDOFF). Mechanischer Rückhalt (warnt, blockt nicht): scripts/check-doc-consistency.sh Block 5 flaggt jedes test:*-Script (server/ + client/ package.json), das in Tests.md fehlt → „immer mitführen" ist durchsetzbar, nicht nur Vorsatz. In Landkarte (docs/README.md) + Tiefenquellen (CLAUDE.md) verlinkt. Verifikation: check-doc-consistency.sh grün (alle 31 test:* erfasst, keine toten Links/Frontmatter-Lücken). Doku: Tests.md (neu), CLAUDE.md, agents.md, docs/README.md, check-doc-consistency.sh, CHANGELOG, HANDOFF, Timesheet.
  • Branch claude/in-app-chatbot-feedback-vpv8ed (PR #301) — OP-FEEDBACK-1: Screenshot-Feedback-Bugfixes (Aufnahme sichtbar · Markierungen nutzbar · Bild landet im Issue) (Version 0.48.3 → 0.48.4 PATCH — Bugfix; Build auto). Befund (Nutzer): beim Feedback-Screenshot (1) wurde die Aufnahme nicht angezeigt, (2) ließen sich keine nummerierten Markierungen anbringen, (3) erschien das Bild nicht im GitHub-Issue. Ursachen (2 Wurzeln, verifiziert): (a) Kamera-Qualitäts-Gate blockierte den Upload — das Formular reichte den Screenshot durch das Standard-Gate (min. 640×480/Schärfe); ein UI-Ausschnitt ist fast immer „zu klein" → Status „Gesperrt" → „Hochladen" deaktiviert → freigegeben feuert nie → kein screenshotKeykein Bild im Issue. (b) Leere/transparente Aufnahmehtml2canvas mit backgroundColor: null auf dem dunklen color-mix/backdrop-blur-Cockpit ergab ein leer wirkendes Bild; Capture-Fehler wurden nur in ein Signal geschrieben, das das Formular nicht anzeigte → nichts zu sehen, nichts zu markieren. Fixes: (1) bild-upload-gate.component.ts erhält @Input gateConfig (Default STANDARD_GATE — Foto-Verhalten unverändert); analysiere() nutzt sie für bewerteQualitaet + entscheideGate. (2) feedback-form.component.ts reicht eine entschärfte Screenshot-Konfig (keine Größen-/Schärfe-/Helligkeits-Sperre, NSFW-Schwelle bleibt) → „Hochladen" ist nicht mehr fälschlich gesperrt; Verpixeln + Markierungen unverändert. (3) screenshot.service.ts: Aufnahme mit deckendem Hintergrund (aufgelöste --tk-bg, Fallback white — kein Hex) statt transparent; entarteter Zuschnitt (<8px) → ehrliche Meldung statt 1×1-„Bild". (4) Capture-Fehler werden jetzt im Formular angezeigt (Danger-Banner + „Erneut aufnehmen"). Verifikation: test:bildgate + ng build --configuration production + No-Hex grün. Doku: CHANGELOG, Timesheet.
  • Branch claude/ipdad-fix-rinfjx (#308) — Log-Hygiene (OP-PM-2): 10 CHANGELOG-Dubletten aus union-Merges entfernt (Doku-only, kein Bump). Wrap-up-Glättung nach den parallelen Merges #295–#306: zehn Einträge existierten doppelt — einmal final mit PR-Link (#230/#231/#243/#282/#286/#288/#295/#298/#302/#303), einmal als ältere „(#308)"-/Format-Variante desselben Inhalts (Diff-verifiziert: nur Präfix, kein Inhaltsverlust) → jeweils die verlinkte Fassung behalten. Die drei #257-Einträge sind bewusst nicht angefasst (inhaltlich verschiedene Folge-Captures). Historische Singleton-„(PR folgt)"-Einträge (Altbestand vor der PR-Link-Pflicht) bleiben unverändert. Verifikation: check-doc-consistency.sh ohne CHANGELOG-Hinweise; verbleibend nur die 11 bekannten Legacy-Timesheet-Session-IDs (OP-PM-3-grandfathered). Doku: CHANGELOG, Timesheet.
  • PR #304 (Branch claude/vectorize-rag-analysis-ad9mt5) — OP-DOCS-2/OP-AI-4: RAG aktiviert — Vectorize-Self-Provisioning + Embeddings-Push + CI-Re-Index + Wirkungs-Metriken (Version 0.48.4 → 0.51.0 MINOR — Feature-Aktivierung; ursprünglich 0.49.0, wegen Versions-Kollisionen mit den parallel gemergten #303 [nahm 0.49.0] und #306 [nahm 0.50.0] auf 0.51.0 korrigiert; Build auto). Auftrag (Nutzer): „Implement RAG" — überstimmt die am selben Tag zunächst festgehaltene kriteriengebundene Zurückstellung (Eintrag darunter); Retrieval-Kern + Keyword-Fallback waren fertig, gebaut wurde die Aktivierungsschicht. Gebaut: (1) scripts/push-doku-index.mjs (npm doku-index:push = frisch chunken + pushen): stellt den Vectorize-Index taktano-doku selbst sicher (GET→CREATE, 1024 Dims/cosine = mistral-embed), embeddet die Chunks batchweise über den EU-Endpoint (ASSISTENT_LLM_BASE_URL, Dimension validiert) und upsertet sie als NDJSON über die Cloudflare-REST-API (Metadaten = rankVectorize-Vertrag: datei/titel/text/sichtbarkeit; gleiche IDs → Re-Index überschreibt; bewusste Grenze: verwaiste Vektoren nach Abschnitts-Löschungen → Index neu anlegen, im Script dokumentiert). Dormant-sicher (Muster Assistent-Secrets): ohne CF-Token → Skip; ohne ASSISTENT_LLM_KEY → nur Index sicherstellen (Deploy-sicher), Retrieval fällt auf Keyword zurück. (2) [[vectorize]]-Binding DOKU_INDEX in wrangler.toml einkommentiert → der bereits gebaute semantische Pfad (leitstand.ts dokuSuche) wird produktiv. (3) CI: deploy-Job pusht vor wrangler deploy (Self-Provisioning ⇒ Binding existiert garantiert); docs-deploy re-indext bei Doku-only-Änderungen (Fast-Track überspringt deploy) — OP-DOCS-1 d erfüllt. Compliance/Risiko nachgezogen: neue Zeile C-19 (Compliance.md: Vectorize ohne EU-Jurisdiktion, Datenminimierung by design — nur Doku-Chunks, kein PII/Kundendaten; AVV-Scope C-10) + RISK-17 → „in Arbeit (akzeptiert)". Verifikation: npm run doku-index (499 Chunks) · Push-Script-Dry-Run (dormant-Pfad) + Chunk-Parse-Check (Parser-Bug DokuChunk[] vs. Array-Start gefunden + gefixt) · tsc · test:assistant-retrieval grün; echter Index-Push erfolgt beim ersten main-Deploy (Secrets nur in CI). CodeRabbit-Review (5 Findings, alle umgesetzt — Leitsatz „Deploy-Verfügbarkeit > Index-Frische"): Push-Script nicht-blockierend gehärtet — AbortSignal.timeout (30 s) + 1 Retry (429/5xx/Netz) auf jedem externen Call, Top-Level-Catch → ::warning:: + Exit 0 (Laufzeit-Keyword-Fallback trägt, nächster Deploy re-indext; echtes Existenz-Gate bleibt wrangler deploy); beide Workflow-Steps zusätzlich continue-on-error: true + timeout-minutes: 10 (Crash/Hänger ≠ Deploy-Blocker); fragiles TS-Text-Scraping ersetzt durch JSON-Sidecar doku-index.generated.json (Build-Artefakt, .gitignore; build-doku-index.mjs schreibt beide). Fehlerpfad end-to-end verifiziert (Bogus-Creds → Warning + Exit 0). RAG-Wirkung messbar (Nutzer 07-02 „can we track the impact of the rag?"): dokuSuche instrumentiert über den bestehenden OP-OBS-1-Stack — Counter taktano_doku_suche{pfad,grund,ergebnis} (semantisch vectorize·ok vs. Keyword-Fallback mit Grund dormant/fehler/leer; ergebnis=leer = Frage ohne Treffer → Recall-Signal, vormals das Aktivierungskriterium, jetzt Erfolgs-Monitor), Histogramme taktano_doku_suche_dauer{pfad} (Pain live: Embed+Query-Latenz vs. Keyword ~0 ms) + taktano_doku_suche_score (Cosine-Top-Score, SCORE_BUCKETS 0,4–0,95 — Match-Qualität/Index-Drift), Logzeile assistent.dokuSuche (pfad·grund·anzahl·topScore·dauerMs·frageLaenge — ohne Fragetext, OP-LOG-1) + 3 Grafana-Panels (RAG-Anteil & Fallback-Gründe · Latenz P95 je Pfad · Top-Score P50/P90). Doku: In-App-Assistent.md §8.1/§9, Compliance.md (C-19), Risikoregister (RISK-17), Observability.md (Slice A2), wrangler.toml, grafana/dashboards/taktano-technik.json, HANDOFF, CHANGELOG, Timesheet.
  • PR #304 (Branch claude/vectorize-rag-analysis-ad9mt5) — OP-DOCS-2/OP-AI-4: Vectorize/RAG-Pain-Gain-Analyse → Aktivierung bewusst zurückgestellt (kriteriengebunden) + Residenz-Flag RISK-17 (Doku-only, kein App-Bump). Auftrag (Nutzer): „Vectorize/RAG — what is the pain/gain?" → Entscheidung festhalten. Analyse: Code ist fertig + dormant-sicher (semantischer Pfad in leitstand.ts aktiviert sich mit DOKU_INDEX-Binding, TF-IDF-Keyword-Fallback läuft); Rest-Pain = reine Ops (Index anlegen · Embeddings-Push · Re-Index je Doku-Deploy, Drift-Risiko) + Query-Latenz (~100–300 ms, Fallback fängt Ausfälle); Kosten vernachlässigbar (~460 Chunks × 1024 Dims). Gain = Recall bei Vokabular-Mismatch (deutsche Komposita/Flexion, Nutzer- vs. Glossar-Sprache) — für interne Nutzer heute ausreichend per Keyword, kritisch erst bei externen Widget-Nutzern/wachsendem Korpus. Entscheidungen (Nutzer 07-02): (1) Aktivierungskriterium statt Sofort-Provisionierung — scharf schalten erst bei externer Doku-Sicht/Widget (OP-DOCS-5) ODER realen Recall-Beschwerden interner Nutzer; Runbook-Kurzform dokumentiert (In-App-Assistent.md §8.1, Detail wrangler.toml). (2) Proaktiver DSGVO-Flag → neuer RISK-17: Vectorize bietet keine EU-Jurisdiktions-Option (anders als R2) — bei Aktivierung lägen Doku-Chunks (inkl. intern, aber kein PII/keine Kundendaten) global; bei Aktivierung Compliance-Zeile + RISK-17-Update Pflicht. Die EU-Residenz-Entscheidung 07-01 deckt nur das Embedding-/LLM-Modell, nicht den Vektor-Store. Doku: docs/architektur/In-App-Assistent.md (neu §8.1), docs/betrieb/Risikoregister.md (RISK-17), HANDOFF (§2 OP-AI-4-Zeile), CHANGELOG, Timesheet.
  • PR #302 (Branch claude/llm-cost-auto-deduction-o3pd0p) — OP-DOCS-9: lebende Test-Übersicht + Regel „immer mitführen" (Doku + CI-Gate-Tweak, kein App-Bump). Auftrag (Nutzer): „Übersicht über alle automatischen Tests in der Doku immer mitführen." Gebaut: neue lebende Doku docs/betrieb/Tests.md — vollständige Liste aller automatischen Prüfungen in Tabellen (29 Server-test:*-Selbsttests · Server-Smokes · Client-Tests · Solver-Self-Test · alle Gates), je mit Befehl · Prüfgegenstand · OP-Bezug · CI-Job + „alles-lokal-ausführen"-Block. Stehende Regel verankert: CLAUDE.md §Tests & CI + docs/konventionen/agents.md (neue/entfernte Prüfung je PR nachziehen, wie CHANGELOG/HANDOFF). Mechanischer Rückhalt (warnt, blockt nicht): scripts/check-doc-consistency.sh Block 5 flaggt jedes test:*-Script (server/ + client/ package.json), das in Tests.md fehlt → „immer mitführen" ist durchsetzbar, nicht nur Vorsatz. In Landkarte (docs/README.md) + Tiefenquellen (CLAUDE.md) verlinkt. Verifikation: check-doc-consistency.sh grün (alle 31 test:* erfasst, keine toten Links/Frontmatter-Lücken). Doku: Tests.md (neu), CLAUDE.md, agents.md, docs/README.md, check-doc-consistency.sh, CHANGELOG, HANDOFF, Timesheet.
  • PR #303 (Branch claude/llm-cost-auto-deduction-o3pd0p) — OP-OBS-1 Slice C1: Client-Telemetrie (Angular) → Grafana (Version 0.48.4 → 0.49.0 MINOR — neues Feature; Build auto). Auftrag (Nutzer): Slice C, Variante A (minimal, dependency-frei). Warum: unbehandelte Frontend-Fehler waren bisher unsichtbar (Blindflug). Kern-Entscheidung — kein Token im Browser: der Client POSTet same-origin an den Access-gegateten Worker-Endpoint POST /api/obs/client; der Worker mappt (rein/gehärtet, server/src/obs/client-logs.ts: parseClientLogPayload + clientEventsZuLogs) auf LogEvent[] (service=taktano-client) und leitet serverseitig via postOtlpLogs weiter (ctx.waitUntil) → Grafana-Token bleibt im Worker. Dormant ohne OTEL_EXPORTER_OTLP_ENDPOINT204. Client (client-obs.service.ts + TaktanoErrorHandler): Angular-ErrorHandler + window.onerror + unhandledrejection (+ manuelle error/warn/info); Ringpuffer (50), Batch-Flush alle 10 s + pagehide/visibilitychange (sendBeacon); best-effort, kein Re-Queue (keine Endlosschleife); Konsole zeigt Fehler weiterhin. Härtung (Browser-Payload = unvertrauenswürdig): Level-Whitelist, Anzahl-Deckel (50), Längen-/Content-Length-Limits, PII-Scrubbing. Neuer Test test:obs-client (CI Server-Job) + in docs/betrieb/Tests.md eingetragen (dogfood der neuen „mitführen"-Regel). Scope: Fehler-Forwarder; volles RUM (Web-Vitals/Sessions) = Faro = Slice C2 (offen). Verifikation: tsc + test:obs-client + check-no-console + ng build + check-doc-consistency grün. Doku: Observability.md (§ Slice C1), Tests.md, ci.yml, CHANGELOG, HANDOFF, Timesheet.
  • PR #301 (Branch claude/in-app-chatbot-feedback-vpv8ed) — OP-FEEDBACK-1: Screenshot-Feedback-Bugfixes (Aufnahme sichtbar · Markierungen nutzbar · Bild landet im Issue) (Version 0.48.3 → 0.48.4 PATCH — Bugfix; Build auto). Befund (Nutzer): beim Feedback-Screenshot (1) wurde die Aufnahme nicht angezeigt, (2) ließen sich keine nummerierten Markierungen anbringen, (3) erschien das Bild nicht im GitHub-Issue. Ursachen (2 Wurzeln, verifiziert): (a) Kamera-Qualitäts-Gate blockierte den Upload — das Formular reichte den Screenshot durch das Standard-Gate (min. 640×480/Schärfe); ein UI-Ausschnitt ist fast immer „zu klein" → Status „Gesperrt" → „Hochladen" deaktiviert → freigegeben feuert nie → kein screenshotKeykein Bild im Issue. (b) Leere/transparente Aufnahmehtml2canvas mit backgroundColor: null auf dem dunklen color-mix/backdrop-blur-Cockpit ergab ein leer wirkendes Bild; Capture-Fehler wurden nur in ein Signal geschrieben, das das Formular nicht anzeigte → nichts zu sehen, nichts zu markieren. Fixes: (1) bild-upload-gate.component.ts erhält @Input gateConfig (Default STANDARD_GATE — Foto-Verhalten unverändert); analysiere() nutzt sie für bewerteQualitaet + entscheideGate. (2) feedback-form.component.ts reicht eine entschärfte Screenshot-Konfig (keine Größen-/Schärfe-/Helligkeits-Sperre, NSFW-Schwelle bleibt) → „Hochladen" ist nicht mehr fälschlich gesperrt; Verpixeln + Markierungen unverändert. (3) screenshot.service.ts: Aufnahme mit deckendem Hintergrund (aufgelöste --tk-bg, Fallback white — kein Hex) statt transparent; entarteter Zuschnitt (<8px) → ehrliche Meldung statt 1×1-„Bild". (4) Capture-Fehler werden jetzt im Formular angezeigt (Danger-Banner + „Erneut aufnehmen"). Verifikation: test:bildgate + ng build --configuration production + No-Hex grün. Doku: CHANGELOG, Timesheet.
  • Branch claude/in-app-chatbot-feedback-vpv8ed (#295) — OP-DOCS-2: Doku-Widget-Bugfixes (Enter-Senden · Antworten/Fehler sichtbar · Art-Chips nur bei Feedback) (Version 0.48.2 → 0.48.3 PATCH — Bugfix; Build auto; nach Merge von #287/#292/#297/#298 u.a.). Befund (Nutzer-Screenshot): im Doku-Widget (1) ließen sich Fragen nicht per Enter absenden, (2) kam keine Antwort (auch kein Fehler) zurück, (3) wurden die Art-Chips (Fehler/Wunsch/Lob/Frage) auch im Doku-Frage-Tab angezeigt. Ursachen & Fixes (docs-site/src/clientModules/assistentWidget.js + custom.css): (1) ein <textarea> sendet bei Enter nicht → Keydown-Handler: Enter sendet, Umschalt+Enter = Zeilenumbruch (wie im App-Chat). (2) Antworten/Fehler wurden imperativ an den Body gehängt, aber das anschließende render() im finally überschrieb den Body sofort → sie verschwanden. Jetzt sind Chat-Antworten und -Fehler Teil des verlauf (Assistent-Blase) und die Feedback-Quittung eine persistente status-Zeile, die render() mitzeichnet → nichts verschwindet mehr; HTTP-Status wird im Fehlertext genannt (Diagnose). (3) die Regel arten.hidden = tab !== 'feedback' griff nicht, weil .tk-assi-arten { display:flex } das [hidden]-Attribut schlug → CSS .tk-assi-arten[hidden] { display:none } ergänzt; Chips erscheinen nur noch im Feedback-Tab. Hinweis (Betrieb): Bleibt die Chat-Antwort „Server nicht erreichbar", ist es die dokumentierte Access-Cross-Origin-Voraussetzung (gemeinsame Access-App über *.taktano.com), nicht der Client. Zusatz-Fix (blockierte den Docs-Deploy): der beim Merge eingeflossene Glossar-Eintrag nacharbeit-stufe (#287) trug einen ungültigen zielgruppen-Key businessgen-glossar bricht hart ab (Durchsetzungspunkt der Single-Source-Daten) und der komplette Docs-Build/-Deploy scheiterte (auch auf main). Korrigiert zu ['nutzer','fach'] (fach = „Fach/Management" deckt das ab). Verifikation: docs-site npm run build grün (Glossar generiert, Widget SSR-sicher) · typecheck grün. Doku: CHANGELOG, Timesheet.
  • Branch claude/llm-cost-auto-deduction-o3pd0p (PR #300) — OP-OBS-1/RISK-16: AVV/DPA mit Grafana dokumentiert (Compliance) (Doku-only, kein Bump). Kontext: OTLP-Secret vom Nutzer gefixt → Telemetrie-Export nach Grafana Cloud EU läuft (401 behoben). Verbleibende RISK-16-Restschuld = Auftragsverarbeitung/DPA belegen. Gebaut (Doku): neue Tracker-Zeile C-18 „Telemetrie-Datenverarbeitung EU-konform (Grafana)" in Compliance.md (Datenminimierung: nur PII-gescrubbte Betriebs-Telemetrie, keine Kundendaten by design; EU-Region belegt; nächster Schritt = Grafana-Labs-Standard-DPA gegenzeichnen + ins VVT); C-10 (AVV/Subdienstleister) um Grafana Labs ergänzt; C-06 (Logging-Prozess) auf „OTel-Wrapper + OTLP→Grafana EU live" aktualisiert; C-07 (EU-Residenz) + C-09 (PII-Scrubbing im Logger live) nachgezogen. RISK-16 aktualisiert: AVV/DPA dokumentiert (C-18), Rest-offen = Gegenzeichnung/VVT durch Nutzer/Legal (kein Code). Proaktiver DSGVO-Flag (verbindlich): die tatsächliche DPA-Unterzeichnung ist eine Rechts-/Betriebshandlung vor Go-Live — Taktano kann sie dokumentieren/vorbereiten, nicht abschließen. Doku: Compliance.md, Risikoregister.md, CHANGELOG, HANDOFF, Timesheet.
  • Branch claude/llm-cost-auto-deduction-o3pd0p (PR #298) — OP-OBS-1/OP-LOG-1: fehlgeschlagener Auto-Pull loggt jetzt warn statt info (Version 0.48.1 → 0.48.2 PATCH — Bugfix Log-Schärfe). Auslöser (Nutzer): ein infraKosten.pull.skip mit grund=Mistral-Usage-API HTTP 401 lief auf info — ein echter Auth-/API-Fehler gehört auf warn (sichtbar in Grafana/Alerting), nicht in den Info-Strom. Fix: die drei Pull-Funktionen (pullGithubKosten/pullLlmKosten/pullMistralKosten) markieren den „kein Secret"-Fall explizit mit dormant: true; neuer Helper protokollierePullFehler() unterscheidet sauber — dormant (erwartbarer Konfig-Zustand) → info, echter Fehler (HTTP 401/5xx, Timeout …) → warn, Teil-Erfolg (anzahl>0) → info. Statt String-Heuristik ein expliziter Diskriminator (robust, Leitprinzip Einfachheit). Log-Zeile bleibt infraKosten.pull.skip (kein Dashboard/Metrik hängt daran — das trägt der Counter taktano_infra_pull{ergebnis}). Verifikation: Server tsc + check-no-console.sh grün. Doku: Observability.md, CHANGELOG, HANDOFF, Timesheet.
  • Branch claude/llm-cost-auto-deduction-o3pd0p (PR #297) — OP-OBS-1: selbsterklärender Fehler-Hinweis an der Telemetrie-Karte (Version 0.48.0 → 0.48.1 PATCH — UX-Tweak, keine neue Funktion). Auslöser (Nutzer-Screenshot): der neue Verbindungstest lieferte real HTTP 401 vom EU-Grafana-Gateway — der Test hat also sofort einen bis dahin still scheiternden Export sichtbar gemacht (Auth abgelehnt → Logs/Metriken kamen nie an). Code + CI-Secret-Sync verifiziert korrekt → Ursache ist der Credential-Wert im Secret OTEL_EXPORTER_OTLP_HEADERS, nicht der Code. Gebaut: obsHinweis() in costs.component.ts gibt je Fehlerbild einen Klartext-Tipp unter „Grund" (amber): 401/403 → „Authentifizierung abgelehnt — Token/Instance-ID im OTLP-Header prüfen (Grafana-Cloud-Access-Policy-Token mit logs:write + metrics:write, Format Authorization=Basic base64(InstanceID:Token))"; 404 → Endpoint (…/otlp ohne /v1/…); 5xx → vorübergehend, später testen. Macht die häufigen OTLP-Fehler ohne Doku-Blick lösbar (Leitprinzip Selbsterklärbarkeit). Verifikation: ng build + check-no-hex.sh grün (Hinweis nutzt var(--tk-amber), kein Hex). Doku: Observability.md (§6a Hinweis), CHANGELOG, HANDOFF, Timesheet.
  • Branch claude/llm-cost-auto-deduction-o3pd0p (PR #296) — OP-OBS-1: Telemetrie-Verbindung prüfbar + Status in der App (Version 0.47.0 → 0.48.0 MINOR — neues Feature; Build auto). Auftrag (Nutzer): „Können wir prüfen, ob die Weiterleitung der Logs und Metriken funktioniert? Den Status der Verbindung dann auch in der App anzeigen." Gebaut: (1) aktiver Verbindungstest — neuer DO-Handler obs.test (admin-gegated, dormant ohne OTEL_EXPORTER_OTLP_ENDPOINT): testeObsExport() sendet synchron (await, nicht fire-and-forget) einen synthetischen Log + eine Test-Metrik (taktano_obs_test) an den OTLP-Endpoint und liefert das echte HTTP-Ergebnis (Log-/Metrik-Status) zurück → end-to-end-Beleg, dass Grafana wirklich annimmt (nicht nur „konfiguriert"). (2) laufender StatusobsStatus (transient je DO-Lebenszeit): jeder reguläre flushObs()-Export (Logs + Metriken) und jeder Test aktualisiert merkeObsExport() (letztes ok/HTTP-Status/Grund/Zeit + Zähler logsGesendet/metrikenGesendet); obsStatusDTO() gibt nur Host + letztes Ergebnis an den Client (Region sichtbar, kein Token/Secret), ausschließlich im Admin-Broadcast-Zweig. (3) UI — im Kosten-Workspace (Tab „Infra") eine Karte „Telemetrie · Grafana": Ampel (grün=letzter Export ok · amber=Fehler/dormant · faint=noch keiner), Host/Region, „Letzter Export" (rel. Zeit + HTTP-Status), Zähler Logs/Metrik-Exporte, Button „↻ Verbindung testen" → quittiert via Toast (ok/dormant/Fehler, eigene seq je Klick, Muster wie Auto-Pull OP-COST-2). Entscheidungen: Verbindungstest admin-gegated wie die Kosten-Pulls (kein Info-Leak, kein Test-Spam durch Nicht-Berechtigte); Status transient (kein persistenter State, DTO ist reine Ableitung — Leitprinzip „derived state nie speichern"); Test synchron (Regulär-Export bleibt fire-and-forget via waitUntil, nur der explizite Test wartet auf die Antwort). Verifikation: Server tsc + test:obs + check-no-console.sh + check-no-hex.sh + Client ng build grün. Doku: Observability.md (§6a Verbindungstest/Status), CHANGELOG, HANDOFF, Timesheet.
  • Branch claude/llm-cost-auto-deduction-o3pd0p (PR #294) — OP-OBS-1 Slice A+B: Dauer-Histogramme + console→Wrapper-Migration + No-Console-Gate; RISK-16 EU-umgestellt (Version 0.46.0 → 0.47.0 MINOR; Build auto). Auftrag (Nutzer): „A, b, pr und merge" (Folge-Slices A+B). Slice A (Dauer-Histogramme): die Histogramm-Fähigkeit der Registry verdrahtet — taktano_solve_dauer{modus} (CP-SAT-Aufruf) + taktano_assistent_turn_dauer{frontend} (Assistent-Turn), ms-Buckets → P50/P95/P99 in Grafana. Slice B (console→Wrapper + Gate): die verbliebenen Laufzeit-console.* im DO (Boot bereits; jetzt Kosten-Protokoll, Assistent-Feedback/-Frage/-Fehler, Purge, Employee-Archiv/-Reaktivierung) auf den Logger-Wrapper migriert (this.log, strukturiert, PII-gescrubbt) → alle DO-Laufzeit-Logs erscheinen in Grafana/Loki. Neues CI-Gate scripts/check-no-console.sh (Server-Job) verhindert Rückfälle — Ausnahmen: *-demo.ts/spike.ts (CLI/Self-Tests) + Zeilen-Marker obs-allow-console (consoleSink-Transport in logger.ts + die 2 OTLP-Fehlversand-console.warn, die NICHT via Wrapper laufen dürfen → Endlosschleife). Review-Fixes (CodeRabbit, 3 valide): (a) Metrics-Export gedrosseltflushObs() postete Metriken bei jeder Message (Registry ab Boot dauerhaft nicht-leer durch metricsLogSink); jetzt Zeit-Gate METRICS_FLUSH_INTERVAL_MS=30_000 (cumulative → 30-s-Kadenz reicht), Logs bleiben ereignis-getrieben; (b) .catch() an beiden OTLP-waitUntil-Ketten (fire-and-forget-Schutz wie d1Audit); (c) dienst-Label je Pull-Case in ein lokales const gehoben (kein 4-fach-Recompute, Counter-Label == Log-/Response-Label). RISK-16 (Nutzer stellte auf EU um): Stack jetzt Grafana Cloud EU (otlp-gateway-prod-eu-west-2) → DSGVO-Residenz erfüllt (US-Test-Stack abgelöst); RISK-16 gemindert, Rest-offen nur AVV/DPA-Beleg. Verifikation: test:obs + check-no-console.sh + check-no-hex.sh + Server tsc grün. Doku: Observability.md (§6a Slice A/B + RISK-16 erfüllt), Risikoregister.md (RISK-16), ci.yml, scripts/check-no-console.sh, CHANGELOG, HANDOFF, Timesheet.
  • Branch claude/llm-cost-auto-deduction-o3pd0p (PR #294) — OP-OBS-1 Slice 2: native OTLP-Metrics (Prometheus/Mimir) (Version 0.45.0 → 0.46.0 MINOR — neues Feature; Build auto). Auftrag (Nutzer): „Emittieren wir auch Metriken?" → nein (nur Logs) → „go" für native Metriken. Gebaut: pure server/src/obs/metrics.ts: Metrik-Registry (MetricsRegistry, Counter + explizite-Bucket-Histogramme, in-memory je DO-Lebenszeit, cumulative → mappt auf Prometheus-Counter) + dependency-freier OTLP/HTTP-JSON-Payload-Builder (resourceMetrics, sum/histogram) + best-effort POST an /v1/metrics. metricsLogSink am Logger → jeder Log zählt als taktano_log_events{level} (echte Fehler-/Volumen-Rate, nicht nur log-abgeleitet); zusätzlich taktano_infra_pull{dienst,ergebnis} an den Auto-Pull-Pfaden; Histogramm-Fähigkeit (ms-Buckets) für künftige Dauer-Metriken. DO: Registry lazy je Boot, flushObs() schickt jetzt Logs + Metrik-Snapshot via ctx.waitUntil (dormant ohne OTEL_EXPORTER_OTLP_ENDPOINT). Dashboard grafana/ um Prometheus-Panels ergänzt (Log-Events-Rate nach Level, Kosten-Pull-Rate je Dienst/Ergebnis). Naming-Konvention: Code ohne _total (OTel) → OTLP→Prometheus ergänzt _total → PromQL taktano_log_events_total/taktano_infra_pull_total (README-Hinweis, ggf. Serien-Name einmalig verifizieren). Verifikation: test:obs erweitert (Registry-Aggregation label-reihenfolge-unabhängig, Histogramm-Buckets, OTLP-Metrics-Payload sum/histogram/ns, metricsLogSink, best-effort/dormant) grün + Server tsc + Dashboard-JSON valide. Scope: technische Metriken (Grafana), True-North bleibt in der App. Offen: Traces (Tempo), Dauer-Histogramme verdrahten (Solve-/Request-Zeit), Client/Solver. Doku: Observability.md (§6a Slice 2), grafana/README.md, CHANGELOG, HANDOFF, Timesheet.
  • Branch claude/llm-cost-auto-deduction-o3pd0p (PR #294) — OP-OBS-1: Telemetrie-Residenz-Ausnahme dokumentiert (US-Test-Stack) (Doku-only, kein Bump). Kontext: Grafana-Cloud-Free-Stack drkv + OTEL-Secrets gesetzt → OTLP-Log-Export live. Der Endpoint liegt in der US-Region (otlp-gateway-prod-us-central-0). Proaktiver DSGVO-Flag (verbindlich): US-Telemetrie widerspricht der EU-Residenz-Leitplanke (DE/AT/CH). Nutzer-Entscheidung 07-02: „US erstmal zum Testen" (Dev/Non-Prod, PII-gescrubbt, geringes Volumen). Festgehalten als RISK-16 (akzeptiert/befristet) im Risikoregister + Observability.md §6a: verbindliche Maßnahme vor Go-Live = EU-Stack (Grafana Cloud Frankfurt oder self-hosted LGTM), code-frei via OTLP umstellbar. Doku: docs/betrieb/Risikoregister.md (RISK-16), docs/architektur/Observability.md, CHANGELOG, Timesheet.
  • Branch claude/d5-1-implementation-qg0myg (#287) — OP-QS-4: QS-Nacharbeit direkt als zuweisbarer Prozessschritt + Leistungs-Schwellwerte (Version 0.45.0 → 0.46.0 MINOR — neue Features; Build auto, OP-PM-2). Auftrag (Nutzer): Nacharbeiten in der QS direkt als Prozessschritte (mit überschreibbaren Zeiten) erfassen, Mitarbeitern zuweisen (manuell + automatisch), Auftrag erst abschließbar wenn alle QS-Schritte erledigt; pro Leistung normal/gesteigert/extrem definieren und Aufträge bei Überschreitung markieren; Feature-Liste in der Doku führen. Befund: Abschluss-Gate (OP-QS-GATE, server-hart istAbnahmebereit) und Nacharbeit-Solver-Fluss (OP-UX-3) waren bereits gebaut → nur die echten Lücken umgesetzt. Gebaut: (1) einstufige Erfassung qs.nacharbeitErfassen (Auto-Mangel im Hintergrund + Nacharbeits-Schritt in einem Zug, überschreibbare Zeit; Bezug auf Ursprungsschritt speist die Qualitätsbewertung unverändert). (2) manuelle Zuweisung teilschritt.zuweisen + Feld TeilschrittInstanz.manuellZugewiesen → Crew bleibt bei Re-Opt fix (applyPlanung respektiert die Hand-Zuweisung), automatisch bleibt Default. (3) Abschluss-Gate gehärtet: transition(→fertiggestellt) erledigt Nacharbeits-Schritte nicht mehr auto (schließt die in OP-QS-GATE vertagte Lücke). (4) Leistungs-Schwellwerte nacharbeitSchwelleGesteigertMin/ExtremMin (Minuten, optional/admin-editierbar) + reine Fn nacharbeitStufe() + AuftragDTO.nacharbeitStufe (aus max(geplant, tatsächlich), D-2) + Client-Badge (amber/rot) + Editor-Felder im Prozess-Katalog. (5) Nachzug: nacharbeitEinplanen überspringt bereits verplante Mängel (keine Doppel-Einplanung). (6) Lebende Feature-Liste docs/betrieb/Funktionsumfang.md (neu, in Doku-Landkarte verlinkt) — ab jetzt pro PR mitpflegen. Entscheidungen (Sign-off, Nutzer): Mangel automatisch im Hintergrund · Schwellwerte absolute Minuten · erfassbar ab fertiggestellt · Gate server-hart. Verifikation: neuer Self-Test test:qs-nacharbeit (CI-Gate: Stufen · Auto-Erledigen-Härtung · Abnahme-Gate · fixe Hand-Zuweisung) + test:abnahme/test:nacharbeit/test:leistung/operativ/replan unverändert grün · ng build + No-Hex + Persistenz-Gate grün. Keine Migration (alle neuen Felder optional/additiv). Doku: Operative-Durchgaengigkeit.md (OP-QS-4 + Mermaid), Lastenheft §5.1, HANDOFF §4, IDs.md, Register.md, Glossar (Nacharbeit-Stufe), Funktionsumfang.md, CHANGELOG, Timesheet. Review-Nachzug (Commits daee056/7d10833): 6 CodeRabbit-Findings behoben (onStart-Boot-Repair nimmt Nacharbeit aus · Schwellwert-Patch validiert finite Zahlen · zuweisen-Guard · manuelle Crew nur nurAktive · Badge-Typ verengt · Offline-Guard in erfasseNacharbeit) + 2 Re-Review-Funde (rohe WS-Payload-Validierung · Client filtert archivierte Mitarbeiter); 3 Findings begründet vertagt (mAufwand-Konvention · Crew-als-CP-SAT-Constraint · Voll-Idempotenz via Mutation-IDs). OP-QS-5 (mit dabei): Mangel bleibt eigenständiges Objekt, aber der Nacharbeitsschritt ist Single Source der DaueralleMaengel überschreibt den Aufwand step-authoritativ (Fallback erfasster Wert), keine Dauer-Doppelführungs-Sync mehr; Mangel.nacharbeitAufwandMin = Ersterfassung/Intent. Entscheidung (Nutzer): eigenständig lassen + Duplikat entschärfen. Self-Test test:qs-nacharbeit (5); kein Feld-Löschen/keine Migration.

2026-07-01

  • Branch claude/llm-cost-auto-deduction-o3pd0p (PR #294) — OP-OBS-1 / OP-LOG-1 Slice 1: Logs nach Grafana (Logger-Wrapper + OTLP-Export + Dashboards-as-Code) (Version 0.44.1 → 0.45.0 MINOR — neues Feature; Build auto). Auftrag (Nutzer): „Logs und Metriken in Grafana auswerten/visualisieren." Befund: OP-OBS-1 war bis dato nur Design — alle Laufzeiten console-basiert, kein OTLP-Export, keine Grafana-Instanz. Backend-Entscheidung (Nutzer 07-02): Grafana (löst die offene Wahl Grafana vs. Sentry); Cloud EU ↔ self-hosted LGTM dank OTLP code-frei umschaltbar. Gebaut (Slice 1, Worker/DO): (1) Logger-Wrapper server/src/obs/logger.ts (OP-LOG-1) — strukturierte Events mit service/version/build/trace_id, PII-Scrubbing (sensible Keys → [redacted], E-Mail-Maskierung, RISK-3), Level-Filter, child-Logger; Sinks: console (interim, deploy-sicher) + optional OTLP-Puffer. (2) OTLP/HTTP-Export server/src/obs/otlp.ts — dependency-freie resourceLogs-JSON-Payload + best-effort POST; nimmt jeder OTLP-Collector (Grafana Alloy/Cloud-Gateway). (3) DO-Verdrahtung — Logger (console + OTLP-Puffer nur wenn OTEL_EXPORTER_OTLP_ENDPOINT gesetzt), flushObs() via ctx.waitUntil (blockiert den Laufzeitpfad nicht); erste Adopter: Boot + Kosten-Pull-Pfade (rohe console.log dort ersetzt). Dormant/deploy-sicher ohne Endpoint. (4) Dashboards-as-Code grafana/dashboards/taktano-technik.json + grafana/README.md (Log-Volumen/Level, Fehler/Warnungen, Kosten-Pull-Ergebnisse, letzte Fehler); Metriken in Slice 1 aus Logs abgeleitet (LogQL), native OTLP-Metrics/Traces = Folge-Slices. (5) Env via GitHub-Secrets OTEL_EXPORTER_OTLP_ENDPOINT/OTEL_EXPORTER_OTLP_HEADERS/LOG_LEVEL (CI-deploy-Sync); wrangler.toml-Doku. Scope-Leitplanke: Grafana = technische Telemetrie; die fachlichen True-North-Dashboards bleiben in der App. Verifikation: neuer Self-Test test:obs (Scrubbing/Level/child/Sink-Isolation + OTLP-Payload/severity/ns/KeyValue + best-effort-POST) grün (in CI verdrahtet) + Server tsc --noEmit grün + Dashboard-JSON valide. Aktivierung (Pre-Prod, OP-OBS-1): Grafana-Instanz + OTEL_*-Secrets setzen → Export geht live. Offene Folge-Slices: Client (Faro/RUM), Python-Solver, native Metrics+Traces, Rest-console-Migration, Backend-Fixierung Cloud-EU-vs-self-host. Doku: docs/architektur/Observability.md (§6a + Env-Vertrag + Status), grafana/README.md, wrangler.toml, ci.yml, HANDOFF (§4 OP-OBS-1), CHANGELOG, Timesheet.
  • Branch claude/in-app-chatbot-feedback-vpv8ed (#291) — OP-DOCS-2: Doku-Widget auf docs.taktano.com (Assistent-Frontend Nr. 2) + CORS + Frontend-Werkzeug-Gate (Version 0.44.0 → 0.45.0 MINOR — neues Feature/Frontend; Build auto). Auftrag (Nutzer): das parked Doku-Widget bauen — dasselbe Assistent-/Feedback-Backend als Widget auf der Doku-Seite („ein Kern, mehrere Frontends"). Entscheidungen (Nutzer): docs.taktano.com ist intern-only (Access-gegated); Widget-Umfang Doku-Q&A + Feedback (keine Live-/Betriebsdaten übers Doku-Frontend). Gebaut: (1) CORS (App-Worker) — reiner Helfer server/src/http/cors.ts (parseCorsAllowlist/corsErlaubt/corsHeaders; spiegelt den konkreten Origin, nie * mit credentials; Self-Test test:cors in CI). Im Worker-fetch: OPTIONS-Preflight vor dem Access-JWT-Check beantwortet (Preflight trägt kein Cookie → sonst 401), CORS-Header via mitCors auf /parties/…- (Assistent/Feedback) + /api/feedback/screenshot-Antworten. Neue Env ASSISTENT_CORS_ORIGINS (wrangler.toml; leer ⇒ kein Cross-Origin, Same-Origin-App unberührt). (2) Doku-Frontend = beschränkter Werkzeugsatz — derselbe Origin-Allowlist-Treffer markiert im DO (leitstand.ts onRequest) das Doku-Frontend → fuehreDialog erhält werkzeugFilter: ['dokuSuche','datenmodell'] (kein datenListe/issueSuche/auslastung/…) + System-Zusatz; handler.ts filtert die dem LLM angebotenen TOOL_DEFS. intern bleibt true (staff-only → volle Doku-Sicht). (3) Widget (Docs-Site) — SSR-sicheres Vanilla-Client-Modul docs-site/src/clientModules/assistentWidget.js (schwebender Button → Panel mit Tabs Doku-Frage/assistant und Feedback/feedback, credentials:'include', minimales sicheres Text-Rendering), App-Origin via <meta name="taktano-app-origin"> (headTags + customFields.appOrigin, override per TAKTANO_APP_ORIGIN), Styling über Infima-Variablen (custom.css, kein --tk-*); dormant-/fehlersicher (503/Netz → Hinweis). Entscheidungen: eine Origin-Allowlist steuert CORS + Werkzeug-Gate (eine Quelle); Doku-Frontend nie mit Live-Daten (OP-DOCS-5/OP-FEEDBACK-2). ⚠ Infra-Voraussetzung (dokumentiert, nicht Code): docs + app sind getrennte Origins → das CF_Authorization-Cookie trägt nur mit einer Access-App über *.taktano.com; heute Access-Vars leer (Edge-only) → Fetch klappt mit CORS, beim Scharfschalten (OP-COST-3) gemeinsame App nötig. Verifikation: typecheck + test:cors + test:assistant-tools (Doku-Modus → nur dokuSuche+datenmodell erreichen das LLM; App-Modus → alle 10) + docs-site npm run build (Modul SSR-sicher) grün. Doku: In-App-Assistent.md §9 (Slice 11) + §6, CHANGELOG, Timesheet. Merge main (nach #289/#290, OP-COST-2): nur version.ts-Konflikt (0.44.1 vs. 0.45.0 → 0.45.0). CodeRabbit-Review-Fixes (#291): (a) mitCors überspringt WebSocket-Upgrades (status === 101 unverändert zurückgeben — Rekonstruktion verlöre die Upgrade-Metadaten; latent, da nur der Doku-Origin gelistet ist); (b) CORS auch auf den Fehler-Pfaden von /api/feedback/screenshot (503/415/400/413) — sonst opaker Netzfehler statt echter Meldung; (c) normalisiereOrigin-Helfer in cors.ts (Dedupe); (d) docusaurus.config.js: TAKTANO_APP_ORIGIN/TAKTANO_ROOM als je eine Konstante + <meta>; (e) Widget liest Room (wie App-Origin) aus <meta name="taktano-room"> (Preview/Staging-override-bar); (f) PR-Links in CHANGELOG/Timesheet.
  • Root-CLAUDE.md (#291) — Neues Leitprinzip „Einfachheit (geringste Komplexität)" (Nutzer-Vorgabe): immer die einfachste tragfähige Lösung in Code, Technik, UI und UX wählen (kleinste sinnvolle Änderung · Wiederverwendung statt Neuerfindung · YAGNI · keine ungefragten Refactorings · vorhandene Bausteine statt neuer Dienste · wenige klare Schritte). Guiding Principle, kein Code-Change.
  • Branch claude/in-app-chatbot-feedback-vpv8ed (#288) — OP-FEEDBACK-1: Screenshot-Feedback mit Bild-Schutz + nummerierten Markierungen (PR-B) (Version 0.43.0 → 0.44.0 MINOR — neues Feature; Build auto). Auftrag (Nutzer): den Screenshot-Feedback-Fluss auf Basis des in PR-A gebauten Markierungs-Layers fertigstellen (Region aufnehmen → Bild-Schutz → nummerierte Markierungen → ans Issue). Gebaut: (1) Aufnahme (Client)services/screenshot.service.ts (Regions-Auswahl-State + lazy html2canvas-Import → eigener 38-kB-Chunk; rendert die Seite, schneidet auf die gezogene Region zu, ignoreElements über data-tk-screenshot-ignore) + leitstand/screenshot-region-overlay.component.ts (Ziehen-zum-Auswählen-Overlay, in shell.component.ts gemountet). (2) Immer Bild-Schutz + Markierungen — das Feedback-Formular (feedback-form.component.ts) bettet app-bild-upload-gate [bildQuelle] mit dem aufgenommenen Bild ein (Gate aus PR-A: Qualität/PII-Verpixeln/NSFW + „① Punkt markieren"); auf freigegeben {blob, markierungen} lädt der Client das geschützte + annotierte Bild hoch. (3) Transport (Server) — neuer Outer-Fetch-Zweig /api/feedback/screenshot (leitstand.ts): POST Bild-Bytes → FOTOS-Bucket-Key feedback/<uuid>{ r2Key }; dormant → 503 ohne FOTOS-Binding (Feedback filet weiter als Text); Client-Helfer FeedbackService.ladeScreenshotHoch. (4) Ans IssueFeedbackAnfrage (+ Client-Spiegel) trägt screenshotKey? + markierungen?; der /feedback-Handler validiert den Key (^feedback/…) und baut den Access-gated Link aus url.origin; feedbackZuIssue (feedback.ts) hängt eine „Screenshot (intern, Access-gated)"-Sektion + die nummerierten Markierungen (als Bullet-Liste) an den Issue-Body. Entscheidungen: Aufnahme via html2canvas (lazy, allowedCommonJsDependencies); Bild im bestehenden EU-FOTOS-Bucket, Link Access-gated (intern; Kunden-Sichtbarkeit = OP-FEEDBACK-2). Verifikation: typecheck + test:assistant-feedback (Screenshot-Link + Markierungs-Mapping) + test:bildgate + ng build --configuration production + No-Hex grün. Doku: In-App-Assistent.md §9 (Slice 10) + §6, Bildbewertung.md, Lastenheft.md §11 OP-FEEDBACK-1 (gebaut) / OP-FEEDBACK-2 (offen), CHANGELOG, Timesheet. ➡ OP-FEEDBACK-1 vollständig (PR-A+PR-B).
  • Branch claude/llm-cost-auto-deduction-o3pd0p (#290) — OP-COST-2: Auto-Pull-Buttons quittieren sichtbar (Fix „Buttons reagieren nicht") (Version 0.44.0 → 0.44.1 PATCH — UX-Fix; Build auto). Befund (Nutzer-Screenshot): Klick auf „↻ GitHub/Mistral/Anthropic ziehen" zeigte keine Reaktion. Ursache (kein Fehler, fehlendes Feedback): ohne gesetztes Provider-Secret ist der Pull dormant (No-op) und der Server gab dem Client keine Rückmeldung → „reagiert nicht" war von „erfolgreich" nicht unterscheidbar. Gebaut: der DO schickt der auslösenden Verbindung nach jedem Pull ein infraKosten.pull.result ({dienst, ok, anzahl, grund?}, analog auftrag.create.result); der Client (leitstand.service.ts) hält es als infraKostenPullResult-Signal (mit seq), die Kosten-Seite quittiert per Toast: Klick → „⟳ wird gezogen …", dann Erfolg („N Posten aktualisiert"), aktuell („keine Änderung") oder dormant/Fehler mit echtem Grund (z. B. „MISTRAL_ADMIN_KEY nicht gesetzt (dormant)", „HTTP 401"); Offline (nur Ansicht) → sofortiger Hinweis statt stiller Verwerfung. Effekt: die Buttons reagieren jetzt immer sichtbar und sind selbst-diagnostizierend (zeigen, dass nur noch der Admin-Key fehlt). Review-Fix (CodeRabbit): Teil-Erfolg ehrlich behandeln — der Mistral-Pull zieht 2 Monate; gelingt einer (anzahl>0) und scheitert der andere, quittiert der Toast jetzt „N Posten aktualisiert" (Warn-Ton + Grund) statt irreführend „nicht gezogen" (Client wertet anzahl>0 unabhängig von ok). Verifikation: Server tsc --noEmit + ng build grün. Doku: costs.component.ts, leitstand.service.ts, server/party/leitstand.ts, CHANGELOG, Timesheet.
  • Branch claude/llm-cost-auto-deduction-o3pd0p (#289) — OP-COST-2: Mistral (realer Anbieter) — ECHTE LLM-Kosten über die Admin-Usage-API ziehen (Version 0.43.0 → 0.44.0 MINOR — neues Feature; Build auto). Auftrag (Nutzer): „Checke die Mistral-API und nutze dort die tatsächlichen Kosten." Befund: Der In-App-Assistent läuft real über Mistral (EU), nicht Anthropic. Mistrals offizielles SDK exponiert keinen Usage-/Billing-Endpoint, aber es gibt eine Admin-(Beta-)API mit den echten Kosten (Nutzer-Screenshot verifiziert): GET https://console.mistral.ai/api/admin/usage?month=M&year=Y mit Authorization: Bearer <ADMIN_API_KEY> (Admin-Key ≠ ASSISTENT_LLM_KEY), liefert Usage und Kosten je Modell/Zeitraum. Gebaut: pure server/src/kosten/mistral-billing.ts (mistralUsageZuPosten/mistralUsageUrl) → ein Monatsposten „Mistral (LLM)" mit den tatsächlichen Beträgen der API (nicht Token×Listenpreis), quelle:'api'/quelleRef=mistral:YYYY-MM (idempotenter Upsert). DO pullMistralKosten() zieht laufenden + Vormonat (Monatswechsel-sicher), dormant/deploy-sicher ohne Secret MISTRAL_ADMIN_KEY; Aktion infraKosten.pullMistral (admin-gegated) + Button „↻ Mistral ziehen" (der bisherige generische LLM-Button ist jetzt „↻ Anthropic ziehen"); Pull = OP-AUDIT-1-Event; „zuletzt erfolgreich gezogen"-Stempel wie GitHub/Anthropic. Key via GitHub-Actions-Secret MISTRAL_ADMIN_KEY (CI-deploy-Job spiegelt es via wrangler secret put, Everything-as-Code). Schema-Unsicherheit (bewusst, ehrlich): Die Beta-Console-API ist öffentlich nicht dokumentiert (docs.mistral.ai bot-blockiert, SDK ohne Route) → der Kosten-Extraktor ist defensiv (explizites Gesamt-Kostenfeld bevorzugt, sonst Summe der Posten-Liste; Feldnamen/Einheit an EINER Stelle justierbar, MISTRAL_BETRAG_IN_CENT für Cent-Antworten) und best-effort; nach dem ersten echten Pull Feld/Einheit einmalig verifizieren. Entscheidungen: echte API-Kosten statt Selbst-Messung Token×Preis (Nutzer-Vorgabe; Selbst-Messung verworfen, da die Admin-API die realen Kosten liefert); Anthropic-Pfad (Slice 2) bleibt parallel dormant nutzbar. Verifikation: test:kosten (Mistral-Mapper: beide Antwort-Formen, Cent-Einheit, URL-Bau, Leer/Kaputt) + Server tsc --noEmit + ng build + No-Hex-Gate grün. Aktivierung = OP-COST-4: GitHub-Secret MISTRAL_ADMIN_KEY (Admin-Key) setzen. Doku: docs/architektur/Kosten.md (§4 + §11 Slice 3), wrangler.toml, ci.yml, HANDOFF (§4 OP-COST-2), CHANGELOG, Timesheet.
  • Branch claude/llm-cost-auto-deduction-o3pd0p (#289) — OP-COST-2: LLM-API-Spend automatisch ziehen + „zuletzt erfolgreich gezogen"-Stempel je Auto-Pull-Komponente (Version 0.42.1 → 0.43.0 MINOR — neues Feature; Build auto). Auftrag (Nutzer): „Die LLM-Kosten sollen auch automatisch gezogen werden. Für jede automatisch gezogene Kosten-Komponente soll der Zeitstempel des letzten erfolgreichen Abholens dezent auch angezeigt werden." Gebaut: (1) Zweiter Auto-Pull-Provider analog GitHub (OP-COST-2): reine, I/O-freie server/src/kosten/llm-billing.ts (llmCostZuPosten) bildet die Anthropic Usage-/Cost-API (/v1/organizations/cost_report, data[]-Zeitbuckets starting_at+results[].amount/currency) je Monat auf einen InfraKostenPosten ab (Dienst „Anthropic API (LLM)", quelle:'api', quelleRef=llm:YYYY-MM → idempotenter Upsert), Beträge ganzzahlig in Cent, Betrag/Datum defensiv geparst (kaputt ⇒ 0/übersprungen). DO pullLlmKosten() dormant/deploy-sicher ohne Secret LLM_BILLING_KEY (Endpoint/Label per LLM_BILLING_URL/LLM_BILLING_DIENST [vars] überschreibbar, provider-flexibel); Aktion infraKosten.pullLlm (admin-gegated) + Button „↻ LLM ziehen"; Pull = OP-AUDIT-1-Event (infraKosten.pull, Actor llm-pull). Key-Bereitstellung wie ASSISTENT_LLM_KEY: der CI-deploy-Job (.github/workflows/ci.yml) spiegelt das GitHub-Actions-Secret LLM_BILLING_KEY vor wrangler deploy via wrangler secret put nach Cloudflare (Everything-as-Code; dormant-sicher übersprungen, wenn ungesetzt). (2) Zeitstempel des letzten erfolgreichen Abholens je Komponente: neuer persistierter Fakt infraKostenPull: Record<Dienst, epoch-ms> (State, schemaVersion 17→18, Merge-Default) — gesetzt bei jedem erfolgreichen HTTP-Abruf (auch ohne inhaltliche Änderung), auch für den bestehenden GitHub-Pull; im DTO als letzterPull zum Client. Dezent angezeigt (costs.component.ts): Caption unter dem jeweiligen „↻ …ziehen"-Button (zuletzt: vor 3 Min / noch nie gezogen), Inline-Stempel je API-Posten-Zeile und im API-Badge-Tooltip (relativ, ab 1 Tag absolut). Entscheidungen: Anthropic-Cost-API als LLM-Spend-Quelle (Doku-Vertrag §4; Endpoint/Label var-überschreibbar für den EU-/Mistral-Fall) · Stempel bei Erfolg (nicht nur bei Änderung), da „letztes erfolgreiches Abholen" · persistiert (Fakt, überlebt Reconnect) · Trigger interim on-demand (Cron-Automatik = Folge-Slice). Verifikation: test:kosten (LLM-Mapper: Monats-Aggregation, Idempotenz, Label/Währungs-Konfig, Betrag-Robustheit) + test:do-migrations (v0→v18) + Server tsc --noEmit + ng build + No-Hex-Gate grün. Aktivierung = Pre-Prod-Requirement OP-COST-4: GitHub-Actions-Secret LLM_BILLING_KEY setzen (CI-Sync nach Cloudflare). Doku: docs/architektur/Kosten.md (§4 + §11 Slice 2), wrangler.toml, HANDOFF (§4 OP-COST-2), CHANGELOG, Timesheet (taktano-2026-07-02-llm-cost-auto-deduction-o3pd0p).

2026-07-01

  • Branch claude/in-app-chatbot-feedback-vpv8ed (#286) — OP-FEEDBACK-1: Nummerierte Markierungen im Bild-Schutz (wiederverwendbar) (Version 0.42.2 → 0.43.0 MINOR — neues Feature; Build auto). Auftrag (Nutzer): die nummerierten Markierungen als Teil des allgemeinen Bild-Schutz-Features bauen (das kommende Screenshot-Feedback konsumiert sie; PR-A des 2-PR-Plans). Gebaut: (1) Reiner Kern (client/src/app/leitstand/bild/upload-gate.ts): Typ Markierung { nummer; xProzent; yProzent; notiz? } (Position prozentual → auflösungsunabhängig) + reine Helfer markierungHinzufuegen / markierungEntfernen (lückenlose Re-Nummerierung ab 1) / markierungNotiz / markierungenText (Text fürs Feedback); von test:bildgate mitgeprüft (Nummerierung/Clamp/Entfernen/Notiz/Reinheit). (2) Komponente (bild-upload-gate.component.ts): neuer Modus „① Punkt markieren" neben „✎ Bereich markieren" (schließen sich aus) — Tippen setzt einen nummerierten Pin (prozent-positionierte Vorschau-Kreise --tk-cyan), Liste mit optionaler Notiz + Entfernen. Beim Upload werden die Kreise auf eine Off-Screen-Kopie ins Bild eingebrannt (Canvas arc+fillText, Farben aus --tk-* via getComputedStyleNo-Hex-konform, idempotent). Neuer programmatischer Eingang bildQuelle / ladeBlob(blob) (einbettbar, nicht nur Datei-Input); Ausgabe angereichert zu freigegeben: { blob; markierungen }. (3) Vorschau-Seite /bild-schutz konsumiert die reichere Ausgabe (zeigt eingebrannte Markierungen als Text). Entscheidungen: eigenes Canvas (keine Annotation-Lib); Markierungs-Layer wiederverwendbar (nicht feedback-spezifisch); Einbrennen auf Off-Screen-Kopie (sichtbares Canvas bleibt sauber). Verifikation: test:bildgate + ng build --configuration production + No-Hex grün. Doku: Bildbewertung.md §7 (Phase 1c), Lastenheft.md §11 OP-FEEDBACK-1 (Teil-gebaut), CHANGELOG, Timesheet. Offen (PR-B): Screenshot-Aufnahme (html2canvas) → Bild-Schutz+Markierungen → R2/D1-Eintrag.
  • Branch claude/in-app-chatbot-feedback-vpv8ed (#285) — OP-AI-4: Datenmodell-Grounding + Anti-Halluzinations-Regel (Assistent erfand Mitarbeiter/Fakten) (Version 0.42.1 → 0.42.2 PATCH — Accuracy-Bugfix; Build auto). Befund (Nutzer): Der Assistent (a) sollte die Wertebereiche/Ober-/Untergrenzen des Datenmodells kennen und (b) erfand Mitarbeiter und andere Fakten, statt nur echte Werkzeug-Daten zu nennen. Gebaut: (1) neuer Datenmodell-Steckbrief server/src/assistant/datenmodell.ts (DATENMODELL: EnumFakt[] = verbindliche Skalen/Enums: Skill-Niveau/Vertrauensstufe/Güteklasse/Anspruch 1–3, Auftrag-Status-Lifecycle, Teilschritt-/Mitarbeiter-Status, fachliche Phasen, Abhängigkeit, Schicht-Art, Leistung-Status — synchron zu model/types.ts + operativ/auftrag.ts, OP-DOCS-9), plus datenmodellPrompt()/datenmodellText(). (2) System-Prompt (handler.ts) injiziert den Steckbrief immer (grounded) + zwei feste Regeln: „ERFINDE NIEMALS Fakten — nenne Mitarbeiter/Namen/Aufträge/Zahlen/Status nur, wenn ein Werkzeug sie geliefert hat; sonst ehrlich ‚keine Daten' sagen" und „halte dich strikt an die Wertebereiche (kein Niveau 4/5, Skala 1–3)"; die frühere Einzeiler-Niveau-Regel (#282) ist darin aufgegangen. (3) neues read-only Tool datenmodell (Registry tools.ts 9 → 10 Werkzeuge, gebunden in leitstand.ts) für Schema-/Wertebereichs-Fragen. Verifikation: typecheck + test:assistant-tools grün (10 Werkzeuge · Dispatch datenmodell→„1–3" · System-Prompt enthält „ERFINDE NIEMALS" + Skill-Niveau-Skala). Doku: In-App-Assistent.md, CHANGELOG, Timesheet.
  • Branch claude/in-app-chatbot-feedback-vpv8ed (#282) — OP-AI-4: Skill-Niveau-Skala grounden (Assistent erfand Niveau 4) (Version 0.42.0 → 0.42.1 PATCH — Accuracy-Bugfix; Build auto). Befund (Nutzer-Screenshot): Der Assistent listete korrekt Mitarbeiter mit „Niveau 3", behauptete dann aber „keine mit höchstem Niveau (4)" und schlug „Schulung auf Niveau 4" vor — SkillNiveau ist aber 1–3 (server/src/model/types.ts, „Sterne", 3 = höchste). Ursache: datenListe gab (N3) ohne Skala aus → das LLM riet die Obergrenze. Fix: (a) datenListeText (Mitarbeiter) zeigt die Skala explizit als Sterne + „(n/3)" (z. B. Keramikversiegelung ★★★ (3/3)); (b) System-Prompt (handler.ts): Skill-Niveau ist 1–3, 3 ist das Höchste, keine höheren Stufen erfinden. Verifikation: typecheck + test:assistant-tools grün. Doku: CHANGELOG, Timesheet.
  • Branch claude/in-app-chatbot-feedback-vpv8ed (#281) — OP-DOCS-7 / OP-AI-4: Duplikat-Erkennung · Assistent liest Issues + Live-Listen · Erfolgs-Quittung (Version 0.41.4 → 0.42.0 MINOR — neue Features; Build auto). Auftrag (Nutzer): (1) Erfolgsmeldung bei angelegtem Issue, (2) beim Feedback nach offenen OPs+Issues suchen (Duplikate vermeiden), (3) OP für spätere Kunden-Sichtbarkeit aufnehmen, (4) Assistent soll auf Issues zugreifen, (5) Assistent soll konkrete Listen-/Daten-Fragen beantworten (nur Bedienungshinweise, wenn Daten zu groß / explizit gefragt). Gebaut: (a) reine server/src/assistant/github-issues.ts (Suchterme, Such-Pfad GitHub-Search-API, Antwort-Mapping) + DO sucheOffeneIssues (dormant ohne TAKTANO_FEEDBACK_TOKEN). (b) /feedback/aehnliche-Endpoint → ähnliche offene Issues + OPs (OPs via keywordSuche über Lastenheft/Register/IDs); Client zeigt „Ähnliche offene Einträge", Nutzer bestätigt „Trotzdem anlegen" (warn+confirm). (c) neue Assistent-Tools issueSuche (Issues nachschlagen/Duplikate vermeiden) + datenListe (Mitarbeiter/Aufträge/Skills/Leistungen/Buchten aus dem Live-State, gefiltert, gekappt); System-Prompt: Daten-Fragen mit echten Daten beantworten (behebt „kein Zugriff auf Live-Daten"). (d) Erfolgs-Toast „Issue #N". (e) OP-FEEDBACK-2 (Kunden-Sichtbarkeit einschränken, HANDOFF §4). Verifikation: typecheck + test:assistant-tools|-feedback|-retrieval (9 Werkzeuge, Issue-Such-Mapping) + ng build + No-Hex grün. Doku: In-App-Assistent.md §9 (Slice 8), HANDOFF §4, CHANGELOG, Timesheet. Noch offen (nächster PR): Screenshot-Feedback mit Bild-Schutz + nummerierten Markierungen (OP-FEEDBACK-1).
  • Branch claude/in-app-chatbot-feedback-vpv8ed (#278) — OP-DOCS-7: Feedback-Fehler sichtbar machen (Version 0.41.3 → 0.41.4 PATCH — Bugfix; Build auto). Befund (Nutzer): Bei einem Fehler beim Feedback-Senden wurde der Fehler nicht angezeigt. Ursache: Das Feedback-Formular ist ein Vollbild-Scrim (z-50) und liegt in der DOM-Reihenfolge nach app-toasts (auch z-50) → der Fehler-Toast wurde hinter dem Formular gerendert (bei Erfolg schließt das Formular, daher war nur der Erfolgs-Toast sichtbar); zudem kappte der Toast-sub (truncate) lange Gründe. Gebaut: Fehler wird jetzt inline im Formular angezeigt (FeedbackService.fehler-Signal → Danger-Banner in feedback-form.component.ts, voller Text, Status-Tokens wie repark-modal), Formular bleibt offen für Retry; Erfolg quittiert weiter per Toast. Zusätzlich Toast-Container auf z-[70] gehoben (Toasts liegen generell über Modals — hilft auch repark-modal). Verifikation: ng build --configuration production + No-Hex grün. Doku: CHANGELOG, Timesheet.
  • Branch claude/in-app-chatbot-feedback-vpv8ed (#275) — OP-DOCS-7: deterministischer Feedback-Pfad (Fix „kein Issue") (Version 0.41.2 → 0.41.3 PATCH — Bugfix; Build auto). Befund (Nutzer): Element-Feedback legte kein GitHub-Issue an. Diagnose (Deploy-Log + D1): Secrets ASSISTENT_LLM_KEY + TAKTANO_FEEDBACK_TOKEN sind gesetzt, Issues aktiviert — die Ursache lag im Design: (1) das Anlegen hing davon ab, dass das LLM das Tool feedbackAnlegen aufruft, und (2) API-Fehler wurden als „Feedback vermerkt" maskiert (403 = Erfolg nicht unterscheidbar). Entscheidung (Nutzer): GitHub-Issues beibehalten (nicht Discussions — REST/actionable). Gebaut: (a) Server — neuer DO-Endpoint /feedback (onRequest, kein LLM, deterministisch); Issue-Erstellung in erstelleFeedbackIssue(): FeedbackErgebnis extrahiert, liefert ehrlich { ok, issueUrl?, status?, grund? }; LLM-Tool nutzt denselben Kern + gibt echte Fehler zurück; reiner feedbackFehlerGrund-Mapper (test:assistant-feedback erweitert); Audit-Event bleibt. (b) Clientfeedback.service.ts POSTet direkt /feedback, ehrliche Toasts (Erfolg mit Issue-Bezug / Fehler mit echtem Grund, z. B. „HTTP 403 — Token-Scope"); neues feedback-form.component.ts (Art-Chips + Text), der 📍-Pin öffnet es statt des Chats; toter LLM-Feedback-Pfad in chat.service.ts entfernt. Effekt: Anlegen ist deterministisch, Konfig-Fehler sind selbst-diagnostizierend. Verifikation: typecheck + test:assistant-* + ng build + No-Hex grün. Doku: In-App-Assistent.md §9 (Slice 7), CHANGELOG, Timesheet.
  • Branch claude/in-app-chatbot-feedback-vpv8ed (#274) — OP-AI-4: Assistent-Antworten als Markdown rendern (Version 0.41.1 → 0.41.2 PATCH — UI-Fix; Build auto). Befund (Nutzer-Screenshot): Der Chat zeigte rohes Markdown (**, ###, -) als Klartext — das Panel interpolierte den Text nur ({{ }}). Gebaut: kleiner, abhängigkeitsfreier Markdown→HTML-Renderer client/src/app/services/markdown.ts (Überschriften, fett/kursiv/Inline-Code, geordnete/ungeordnete Listen, Absätze) — HTML wird zuerst escaped (kein Roh-HTML aus der LLM-Antwort), Ausgabe zusätzlich über Angulars [innerHTML]-Sanitizer gebunden (Defense-in-Depth, XSS-geprüft). Pure Pipe markdown.pipe.ts (memoisiert); chat-panel.component.ts rendert Assistent-Antworten via [innerHTML], Nutzer-Nachrichten bleiben Klartext. Styles über Tokens (::ng-deep .tk-md, No-Hex-Gate grün). Entscheidung: eigener Mini-Renderer statt marked-Lib (Bundle-Budget + kleinere XSS-Fläche). Verifikation: ng build --configuration production grün · Renderer-Ausgabe + XSS-Escaping manuell geprüft. Doku: CHANGELOG, Timesheet.
  • Branch claude/in-app-chatbot-feedback-vpv8ed (#273) — Doku-Nachzug: CodeRabbit-Review zu #272 (Doku/Kommentar-only, kein Bump). Drei ASSERTIVE-Findings adressiert: „PR folgt"-Platzhalter in CHANGELOG.md + Timesheet.md → konkrete Referenz #272 (Traceability); wrangler.toml-Kommentar präzisiert (nur leere GITHUB_FEEDBACK_ORG/REPO fallen auf BILLING zurück — der Token selbst hat keinen Fallback, ohne ihn bleibt Feedback dormant). CodeRabbit schlug fälschlich #271 vor (die Vorgänger-PR); korrekt ist #272.
  • Branch claude/in-app-chatbot-feedback-vpv8ed (#272) — OP-AI-4: Feedback-Token-Rename + CI-Secret-Sync (Version 0.41.0 → 0.41.1 PATCH — Config/CI, keine neue Funktion; Build auto). Auftrag (Nutzer): „Rename GITHUB_FEEDBACK_TOKENTAKTANO_FEEDBACK_TOKEN; API-Keys sind in GitHub-Secrets gesetzt, aus dort ziehen." Gebaut: (1) Worker-Secret GITHUB_FEEDBACK_TOKENTAKTANO_FEEDBACK_TOKEN umbenannt (server/party/leitstand.ts Env + feedbackAnlegen, wrangler.toml) — Grund: GitHub-Actions-Secrets dürfen kein GITHUB_-Präfix tragen (reserviert). GITHUB_FEEDBACK_ORG/_REPO bleiben (sind [vars], kein Secret). (2) CI-deploy-Job (.github/workflows/ci.yml) spiegelt ASSISTENT_LLM_KEY + TAKTANO_FEEDBACK_TOKEN aus gleichnamigen GitHub-Secrets via wrangler secret put (stdin, non-interaktiv) vor wrangler deploy nach Cloudflare — dormant-sicher (nicht gesetzt → übersprungen, Deploy bricht nicht). Kein neuer Token-Scope nötig (bestehendes CLOUDFLARE_API_TOKEN mit „Edit Workers"). Entscheidung: CI-verwaltete Secret-Sync (Everything-as-Code) statt einmaligem CLI-secret put — Nutzer-Wunsch. Verifikation: npm run typecheck grün · test:assistant-* grün · ci.yml YAML valide. Doku: In-App-Assistent.md (§9 Aktivierung), CHANGELOG, Timesheet (2026-07-01-in-app-chatbot-feedback-vpv8ed-2).
  • Branch claude/in-app-chatbot-feedback-vpv8ed (#271) — OP-AI-4 / OP-DOCS-2/-7: In-App-Assistent (Chatbot + Feedback), Slices 4–6 (Version 0.40.2 → 0.41.0 MINOR — neues Feature; Build auto, OP-PM-2). Auftrag (Nutzer): „Ein Chatbot in der App, der Fragen zur App + zu den Daten beantwortet und Feedback zu konkreten Elementen aufnimmt; dasselbe später in der Doku." Entscheidungen (Nutzer 07-01): App-first (Doku-Widget als Folge-PR) · EU-gehostetes LLM (DSGVO-Residenz) · RAG-Retrieval (Cloudflare Vectorize, mit Keyword-Fallback) · Feedback → GitHub-Issue. Gebaut (auf den bereits gebauten read-only Insights-Slices 1–3): (1) Reine, testbare Server-Kerne (server/src/assistant/): retrieval.ts (Keyword-Ranking + Berechtigungsfilter + Vectorize-Ranking), doku-index.generated.ts aus docs/**/*.md (scripts/build-doku-index.mjs, 458 Chunks), llm.ts (EU-OpenAI-kompatibler Client hinter LlmClient-Interface → Fake-testbar), tools.ts (7 Werkzeuge, 1:1 auf bestehende Funktionen), handler.ts (System-Prompt → Tool-Schleife → Antwort, Rundenlimit), feedback.ts (reiner Feedback→Issue-Mapper). (2) DO-Endpoint /assistant (leitstand.ts onRequest, am Live-State/Engine, §4): Tools binden an insights.ts, konfliktHebel (nur Simulation, kein Auto-Apply, §3) und Doku-Suche; dormant ohne ASSISTENT_LLM_KEY (503, deploy-sicher); Feedback→Issue dormant ohne GITHUB_FEEDBACK_TOKEN + Audit-Event assistent.feedback. (3) Angular (shell.component.ts): chat.service.ts (signals, POST same-origin ⇒ Access-Cookie, Route/Workspace-Kontext), chat-panel.component.ts (Drawer rechts, Tokens statt Hex), feedback-pin.service.ts + feedback-pin-overlay.component.ts (Capture-Klick → Element-Anker → feedbackAnlegen). Config: wrangler.toml (ASSISTENT_LLM_/GITHUB_FEEDBACK_/Vectorize dormant), Env-Felder. Verifikation: npm run typecheck grün · neue Self-Tests test:assistant-retrieval|-tools|-feedback grün (in CI verdrahtet) · ng build --configuration production + No-Hex grün. Compliance/Risiko: Compliance.md C-17 (LLM EU-Datenverarbeitung) + C-10 (AVV), Risikoregister.md RISK-10 (Prompt-Injection, Härtung) + RISK-15 (EU-LLM-Datenfluss). Doku: docs/architektur/In-App-Assistent.md (§8 Entscheidungen, §9 Slices 4–6), HANDOFF (§4 OP-AI-4), CHANGELOG, Timesheet (2026-07-01-in-app-chatbot-feedback-vpv8ed).
  • Branch claude/op-liste-doc-hyperlinks-7e3s6o (#267) — OP-Listen tragen klickbare OP-ID-Sprünge (Direkt-Navigation) (Doku-only, kein Bump; Build auto, OP-PM-2). Auftrag (Nutzer): „Die OP-Liste in der Doku soll immer Hyperlinks zum direkten Sprung dorthin enthalten." Gebaut (nur Doku): (1) In den beiden kuratierten OP-Navigations-Indizes — Register.md §1 (Navigations-Index) + IDs.md (Reverse-Lookup) — ist jede OP-ID jetzt selbst ein Sprung-Link an ihr Zuhause: Owning-Doc, sonst der passende Lastenheft-§11-Anker bzw. HANDOFF.md §4. (2) Dafür stabile explizite Heading-Anker ergänzt: docs/fachlich/Lastenheft.md §11.1–§11.10 ({#11-1-auftraege}{#11-10-tests-qs}) und HANDOFF.md §4 ({#op-parked}). (3) Als verbindliche Konvention verankert (damit „immer"): agents.md §2 Punkt 5 (OP-Listen tragen klickbare OP-ID-Sprünge) + Pflege-Notizen in Register.md/IDs.md. Entscheidung: Link-Ziel je OP = Detail-Quelle (Owning-Doc, wo vorhanden; sonst fachliche Master-Spec Lastenheft §11; rein-geparkte OPs → HANDOFF §4) — reine Wiederverwendung bereits dokumentierter, verifizierter Ziele, keine erfundenen Anker. Folge-Ausbau (gleiche Session, „1 und 2"): (4) Per-OP-Präzision — jede führende OP-ID in Lastenheft §11 (80 OPs) und HANDOFF §4 (145 OPs) trägt nun einen eigenen <a id="op-<id>">-Anker; (5) die volle OP-Liste HANDOFF §4 verlinkt jede führende OP-ID auf ihre Detail-Quelle (Owning-Doc / Lastenheft-#op-<id> / Selbst-Permalink); (6) die Register-Indizes springen für Einzel-OPs jetzt exakt auf #op-<id> (Familien-Zeilen weiter auf §11-Sektion). Transformation skriptgestützt + validiert (Anker eindeutig, alle internen Links auflösbar; nur echte Multi-OP-Sammelzeilen OP-R7-1..9/OP-AUTH-1/2 bewusst ausgelassen). Kein Code-/Schema-/Solver-Change. Doku: Lastenheft §11 (Sektions- + per-OP-Anker), HANDOFF §4 (Anker + OP-ID-Links), Register.md, IDs.md, agents.md §2.5, CHANGELOG, Timesheet (2026-07-01-op-liste-doc-hyperlinks-7e3s6o).
  • Branch claude/coderabbit-config (PR folgt) — OP-DEVTOOL-1: versionierte .coderabbit.yaml (Review-Tiefe schärfen) (kein Versions-Bump — reine Dev-Tooling-Config, kein App-Change). Auftrag (Nutzer): „Wie kann CodeRabbit einen detaillierten Review durchführen, nicht nur Summary?" + Entscheidung „Nur CodeRabbit schärfen" (kein zusätzlicher GitHub-Copilot-Review). Befund: Review-Config lag bisher nur im CodeRabbit-Dashboard („Configuration used: Organization UI", Profil chill) → Verstoß gegen Everything-as-Code; die Detail-Findings kommen ohnehin (nach der Summary), aber Profil chill = bewusst wenige. Gebaut: neue .coderabbit.yaml im Repo-Root — reviews.profile: assertive (deutlich detailliertere Zeilen-Reviews), high_level_summary/review_status: true, auto_review.enabled: true, request_changes_workflow: false (CodeRabbit kommentiert, blockt nicht — Merge-Gate bleibt der aggregierte „CI Gate"), path_instructions je Bereich (server/party/** → DO-State/Migrationen/Idempotenz/Ownership; client/src/app/** → Signals/Leak-Freiheit/No-Hex/Service-Zugriff; docs/** → pyramidal/widerspruchsfrei/PR-Link). Entscheidung/Abwägung: kein Copilot-Review (Redundanz zu CodeRabbit + zweite externe Vendor-/DSGVO-Fläche; die Security-Achse ist via CodeQL Default Setup + Dependabot + security-audit bereits abgedeckt). Bewusst NICHT: CodeRabbit-als-MCP-Client (Richtung 1, Review-Kontext) — bleibt offener OP; optional Review-Sprache Deutsch. Verifikation: YAML valide; No-Hex/Doku-Konsistenz unberührt; nächster CodeRabbit-Lauf fährt mit assertive. Doku: HANDOFF (§4 OP-DEVTOOL-1 Schritt (i) ✅), CHANGELOG, Timesheet (2026-07-01-coderabbit-config).
  • Branch claude/foto-varianten-3 (PR #265) — OP-R4-1: drei Bild-Varianten (Thumbnail · verkleinert · Original), Thumbnail-priorisiert (Version 0.36.0 → 0.37.0 MINOR — neues Feature; Build auto, OP-PM-2). Auftrag (Nutzer): „immer 3 Varianten eines Bilds speichern: Original, verkleinert (~1024px) und Thumbnail; Thumbnails immer zuerst priorisiert bearbeiten/hochladen/runterladen." Gebaut: (1) Client-Aufbereitung (foto-kompression.ts): neues erzeugeFotoVarianten(file) dekodiert einmal (createImageBitmap, EXIF) und rendert thumb (256px, q0.70) · display (1024px, q0.82) · original (volle Auflösung = Datei); best-effort (kein Bild/Decode-Fehler → alle drei = Original). Altes komprimiereFoto entfernt (Ersetzung). (2) Queue-Modell (offline-foto-queue.ts): FotoQueueEintrag hält drei FotoVarianteState (je eigene uploaded/registered); reine Maschine naechsterVariantenSchritt(v, connected) (upload→register→fertig/warten) + fotoEintragStatus (höchstpriorisierte offene Variante) + fotoEintragFertig (alle drei → löschen); FOTO_VARIANTEN_PRIO = [thumb,display,original]. (3) Drain (LeitstandService): iteriert Varianten AUSSEN, Einträge INNEN → Thumbnails aller wartenden Fotos zuerst, dann verkleinert, dann Original; putFoto(..., variante) + WS foto.variante; Ack-getriggert (fotoVarianteImState prüft thumbR2Key/r2Key/originalR2Key). (4) Server (leitstand.ts): /api/foto/upload akzeptiert variante=thumb (Key-Pfad thumb/, Limit 5MB; display 15, original 30); neuer WS-Handler foto.variante = Upsert nach id (der zuerst eintreffende Thumbnail legt den FotoAttachment an, weitere Varianten hängen an); DTO + FotoAttachment.thumbR2Key. Alte foto.registriert/foto.original-Handler bleiben (Back-Compat). (5) UI: Detail-Panel-Kacheln laden Thumbnail (thumbR2Key, loading=lazy), verkleinert beim Öffnen, Original via „HQ"; Popover zeigt Varianten-Status + Fortschritt N/3. Migration: SCHEMA_VERSION 16 → 17 (thumbR2Key additiv, kein Transform — fehlt ⇒ kein Thumbnail). Entscheidungen (Nutzer-bestätigt): Größen 256 / 1024 (Original voll); Download thumb-first, dann on-demand; Priorität absteigend Thumbnail → verkleinert → Original. Abwägung: ~3 R2-Objekte je Foto (Egress-Ersparnis beim Anzeigen via Thumbnails überwiegt; Original bleibt beweiskräftig). Review-Fixes (CodeRabbit, PR #265): (a) Drain bricht nach permanentem 4xx ababgebrochen-Set verhindert, dass weitere Varianten eines bereits als „nicht gespeichert" gemeldeten Fotos noch hochgeladen/registriert werden; (b) Server-Upsert mit Ownership-Guardfoto.variante hängt eine Variante nur an, wenn Auftrag/Instanz des Alt-Records übereinstimmen (schützt vor fotoId-Kollision/Replay-nach-Purge); (c) kein leeres Pflichtfeld — neu angelegter FotoAttachment seedet r2Key mit der eintreffenden Variante statt ""; (d) Kachel-Link-Fallback fotoUrl(foto.r2Key || foto.thumbR2Key || '') (öffnet nie einen leeren Key, solange Display aussteht); (e) CHANGELOG/Timesheet-PR-Link. Verifikation: test:fotoqueue (Varianten-Maschine + Priorität + Fertig-Kriterium) grün · test:do-migrations (v0→v17) grün · Server tsc + operativ grün · ng build + No-Hex grün. Doku: docs/architektur/Offline-PWA.md (3-Varianten-Abschnitt), HANDOFF (§4), CHANGELOG, Timesheet (2026-07-01-foto-varianten-3).
  • Branch claude/unused-skills-org-7r4k6l (PR #269) — OP-SKILL-1 Variante B: Skill-Pflege im Prozess-Editor (Skills „wandern" zu den Prozessen) (Version 0.38.0 → 0.39.0 MINOR — neues Feature; Build auto, OP-PM-2). Auftrag (Nutzer): „B" — die im Vor-Slice angebotene Variante B umsetzen (Skills dort pflegen, wo sie gebraucht werden). Gebaut: (Client) der Prozesse-Workspace (client/src/app/leitstand/pages/processes.component.ts) bietet je Teilschritt am „Geforderter Skill"-Picker zwei neue Aktionen: „+ neu" (Inline-Input → neuen Skill anlegen und sofort diesem Teilschritt zuweisen) und „✎ umbenennen" (benennt den aktuell geforderten Skill katalogweit um, via updateSkill); Signals neuerSkillFuer/neuerSkillName, Methoden skillAnlegen/benenneSkillUm. (Service) createSkill(name, beschreibung?, teilschrittId?) reicht optional die teilschrittId durch. (Server) die skill.create-Message trägt optional teilschrittId; der Handler weist den (neu angelegten oder reaktivierten) Skill danach via setzeSkillAnforderung dem Teilschritt zu (Mindest-Niveau/Personenzahl unverändert) — atomar in einem State-Broadcast, was die Race-Bedingung löst (die Skill-ID wird serverseitig generiert, der Client kann sie nicht vorher kennen). Entscheidungen: (a) atomar server-seitig (statt Client wartet auf neue ID + zweiter Message) — race-frei; (b) Katalog bleibt Single Source (kein zweiter Speicherort, kein Schema-Change); (c) skill.create bleibt ungegated + audit-frei wie die bestehenden Skill-Handler (Konsistenz; Härtung folgt mit OP-AUTH-1/OP-AUDIT-1). Verifikation: Server tsc --noEmit + test:prozess grün · ng build grün · No-Hex-Gate grün. Kein Solver-Redeploy, kein Schema-Change. Doku: processes.component.ts, leitstand.service.ts, server/party/leitstand.ts, server/src/version.ts, docs/fachlich/Lastenheft.md (§11.7 OP-SKILL-1 → Variante B ✅), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-29-unused-skills-org). Offen (C): Mitarbeiter-Sicht filtert verwaiste Skills. Bezug: OP-R3-3, OP-R1-3, OP-CRUD-1, OP-AUTH-1, OP-AUDIT-1, G-1, S-2.
  • Branch claude/unused-skills-org-7r4k6l (PR #269) — OP-SKILL-1 Variante C: Mitarbeiter-Sicht priorisiert prozess-getragene Skills + CodeRabbit-Review-Fixes (Version 0.39.0 → 0.40.0 MINOR — neues Feature; Build auto, OP-PM-2). Auftrag (Nutzer): „C als gedimmt und nach unten sortiert inkl. Tooltip." Gebaut (Variante C, reiner Client-Pfad): an den beiden Skill-Auswahl-Pickern der Mitarbeiter-Sicht (Qualifikation hinzufügen · Ausbildungsziel, staff.component.ts) werden verwaiste Skills (in keinem Prozess/Teilschritt gefordert) ans Ende sortiert (verwaisteAnsEnde, stabil — prozess-getragene zuerst), gedimmt (--tk-text-faint) und mit Tooltip + Suffix „· in keinem Prozess" markiert; bewusst nicht ausgeblendet (Selbsterklärbarkeit — bleiben wählbar, nur nachrangig; bestehende Zuweisungen unberührt). Wiederverwendung von istVerwaist aus Variante A (derived, kein Server/Schema). ➡ OP-SKILL-1 vollständig (A+B+C). CodeRabbit-Review-Fixes (PR #269, 4 Kommentare): (1) CHANGELOG doppelte ## 2026-07-01-Überschrift → in die bestehende Sektion einsortiert (MD024); (2) neuerSkillName leakte über Zeilen/Escape (Major) → toggleNeuerSkill/schliesseNeuerSkill leeren beide Signals synchron beim Öffnen/Wechseln/Schließen; (3) benenneSkillUm ohne Namens-Eindeutigkeit → Duplikat-Check gegen svc.skills() vor updateSkill (analog Anlegen/Server-Reaktivierung); (4) nativer autofocus unzuverlässig bei @if-Inputs → kleine standalone AutofocusDirective (afterNextRender-Fokus). Verifikation: Server tsc + test:prozess grün · ng build grün · No-Hex-Gate grün. Kein Server/Solver/Schema/Token-Change (C ist rein Client; die Fixes ebenso). Doku: staff.component.ts, processes.component.ts, server/src/version.ts, docs/fachlich/Lastenheft.md (§11.7 OP-SKILL-1 → A+B+C ✅), HANDOFF (§4), Register, CHANGELOG, Timesheet (2026-06-29-unused-skills-org). Bezug: OP-R3-3, OP-R1-3, OP-R9-4/7, OP-CRUD-1, G-1, S-2.
  • Branch claude/unused-skills-org-7r4k6l (PR #269) — CodeRabbit-Nachzug (Runde 3): Duplikat-Namens-Guard auch im Skill-Katalog-Dialog + Doku-Konsistenz (Version 0.40.0 → 0.40.1 PATCH — kleine Fixes; Build auto, OP-PM-2). (1) StaffComponent.benenneSkillUm (staff.component.ts, Skill-Katalog-Dialog) spiegelt jetzt den Duplikat-Namens-Check aus ProcessesComponent.benenneSkillUm (kein zweiter Skill mit gleichem Label; bei Kollision Hinweis + Eingabe zurückgesetzt) — verhindert, dass der Katalog-Dialog die im Prozess-Editor blockierte Doppel-Label-Situation wieder erzeugt. (2) Doku-Konsistenz (Lastenheft.md §11.7): der veraltete „Zu klären"-Schwanz an der als A+B+C vollständig markierten OP-SKILL-1 (widersprach HANDOFF/CHANGELOG) → durch „Geklärt (durch A/B/C)" ersetzt (Anzeige-Ort/SoR/reservierte Skills beantwortet; offen bleibt nur die Stammdaten-Einzelfrage skill-ppf konsolidieren vs. eigener PPF-Teilschritt). Verifikation: ng build + No-Hex-Gate grün. Kein Server/Solver/Schema. Doku: staff.component.ts, docs/fachlich/Lastenheft.md §11.7, server/src/version.ts, CHANGELOG, Timesheet.
  • Branch claude/unused-skills-org-7r4k6l (PR #269) — CodeRabbit-Nachzug (Runde 4): Katalog-Dialog Anlegen/Umbenennen gehärtet (Version 0.40.1 → 0.40.2 PATCH; Build auto, OP-PM-2). (1) legeSkillAn (Skill-Katalog-Dialog) warnt jetzt bei aktivem Namensgleichstand (Anlegen wäre ein No-Op, da der Server per Name dedupliziert) und bricht ab — bewusst nur bei aktiven Skills: ein deaktivierter gleichnamiger Skill wird weiterhin reaktiviert (dokumentiertes Feature „Reaktivieren statt Duplikat" im skill.create-Handler; CodeRabbits pauschaler Block hätte diese Reaktivierung gebrochen → bewusst abweichend umgesetzt). (2) benenneSkillUm setzt bei leerem/unverändertem Namen das Eingabefeld auf den aktuellen Namen zurück (das [value]-Binding greift sonst nicht, Feld bliebe sichtbar leer). Verifikation: ng build + No-Hex grün. Kein Server/Solver/Schema. Doku: staff.component.ts, server/src/version.ts, CHANGELOG, Timesheet.

2026-06-29

  • Branch claude/unused-skills-org-7r4k6l (PR #269) — OP-SKILL-1 Variante A: verwaiste Skills im Katalog markieren (Version 0.34.0 → 0.35.0 MINOR — neues Feature; Build auto, OP-PM-2). Auftrag (Nutzer): „Zeige mir Skills, die in keinem Prozess vorkommen" → kleinster Schnitt (Variante A) umgesetzt. Gebaut (reiner Client-Pfad): der Skill-Katalog-Dialog (client/src/app/leitstand/pages/staff.component.ts) markiert jeden Skill, den kein Teilschritt fordert, mit Badge „⚠ in keinem Prozess verwendet" + Kopf-Hinweis mit Zähler („N Skill(s) in keinem Prozess verwendet — … einem Teilschritt zuweisen oder deaktivieren"). Abgeleitet, nichts gespeichert (S-2): verwendeteSkillIds = computed-Set über svc.teilschritteKatalog().map(t => t.benoetigteSkillId); istVerwaist(id) = nicht im Set; verwaisteAnzahl = computed-Zähler. Design: Amber (Hinweis/Achtung) via --tk-amber + color-mix, nicht Rot (Rot bleibt echten Warnungen/Klärfall vorbehalten, Design-G); kein Hardcoded-Hex (No-Hex-Gate grün). Verifikation: ng build grün · No-Hex-Gate grün. Kein Server/Solver/Schema/Token-Change. Entscheidung: verwaist ist abgeleitet (nicht persistiert) und ≠ inaktiv (ein aktiv:true-Skill kann verwaist sein); die Sicht schlägt vor, archiviert/löscht nicht (Propose-not-execute, OP-CRUD-1 Klasse A). Offen (Folge-Slices): B = Skill-Pflege im Prozess-Editor · C = Mitarbeiter-Sicht filtert verwaiste. Doku: staff.component.ts, server/src/version.ts, docs/fachlich/Lastenheft.md (§11.7 OP-SKILL-1 → Variante A ✅), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-29-unused-skills-org). Bezug: OP-R3-3, OP-R1-3, OP-R1-6, OP-CRUD-1, OP-R3-1, G-1, S-2.
  • Branch claude/unused-skills-org-7r4k6l (PR #269, reine Doku/OP-Capture) — OP-SKILL-1 + OP-R1-6 neu festgehalten (kein Bump, Doku-only). Auftrag (Nutzer, 2 Eingaben + Screenshot): (1) „Zeige mir Skills, die in keinem Prozess vorkommen — die Skills sollten zu den Prozessen/Teilschritten wandern, da passt es besser (und macht die Mitarbeiter-Sicht leichter)." (2) „Mitarbeiter-Seite für 10–50 Mitarbeiter optimieren — erst verschiedene Konzepte entwickeln und vergleichen, dann umsetzen." Erfasst (kein Code): OP-SKILL-1 — Befund verifiziert: Skill-Katalog ist Separat-Liste (7 Skills, vest-automotive.ts), Teilschritt referenziert genau einen Skill (benoetigteSkillId, F11); 5 von 7 verwendet, verwaist = skill-ppf + skill-klaerung (in keinem Teilschritt). Zwei Aspekte: (1) verwaiste Skills als abgeleiteten Hinweis sichtbar (derived, S-2; verwaist ≠ inaktiv), (2) Skills im Prozess-Editor verankern → schlankere Mitarbeiter-Sicht. Optionen A (Diagnose-Badge) / B (Pflege im Prozess-Editor) / C (Mitarbeiter-Sicht filtert). Bewusste Sonderfälle: skill-klaerung für OP-R3-1 reserviert, skill-ppf = Variante von skill-folie. Propose-not-execute (Klasse A, OP-CRUD-1). OP-R1-6 — Mitarbeiter-Seite (staff.component.ts, Karten je MA) skaliert nicht auf 10–50 MA; zweistufiges Vorgehen (Nutzer-Vorgabe): erst 2–3 Konzepte (Matrix/Heatmap · Tabelle+Filter+Detail-Panel · virtualisiertes Karten-Grid · Gruppierung) als Mockup vergleichen (Übersicht·Pflege·True North·Aufwand), dann bauen. Status: Konzeptphase. Doku: docs/fachlich/Lastenheft.md (§11.7 OP-SKILL-1, §11.3 OP-R1-6), HANDOFF (§4), docs/konventionen/Register.md, CHANGELOG, Timesheet (2026-06-29-unused-skills-org). Bezug: OP-R3-3, OP-R1-3, OP-R9-4/7/8, OP-CRUD-1, OP-R3-1, G-1, S-2.
  • Branch claude/offline-foto-queue (PR #264) — OP-OFFLINE-1 Stufe C: verzögerter Foto-Upload (Offline-Queue) (Version 0.35.2 → 0.36.0 MINOR — neues Feature; Build auto, OP-PM-2). Auftrag (Nutzer): „Stufe c" (die aus der Offline-Anforderung vertagte versetzte Bild-Upload-Fähigkeit). Befund: Foto-Upload war rein online — putFoto() nutzt plain fetch (scheitert offline) und foto.registriert läuft über den send()-Guard (verwirft offline) → ein offline erfasstes Foto war verloren. Gebaut: (1) Persistente Queue: neuer OfflineFotoQueueService (IndexedDB taktano-offline-fotos, Store queue/keyPath fotoId, nach StateCacheService-Muster) puffert die komprimierten Blobs (+ optional Original) bis Upload+Registrierung durch sind; count-Signal → Shell-Badge „N warten". (2) Reine Zustandsmaschine naechsterFotoQueueSchritt(entry, connected) (offline-foto-queue.ts, Angular-frei) — upload → register → upload-original → register-original → fertig, warten wenn WS zu; uploaded/registered-Flags = idempotenter Replay. (3) Enqueue+Drain in LeitstandService: uploadFoto() legt nur noch in die Queue (löst sofort auf) + drainFotoQueue() (Trigger: Socket-open/Reconnect + online-Event + nach Erfassung); HTTP-Fehler=offline → Eintrag bleibt liegen. (4) Server-Idempotenz (minimal): /api/foto/upload leitet den R2-Key deterministisch aus ?foto=<fotoId> ab (statt Zufalls-UUID) → Reconnect-Replay überschreibt denselben Key (kein Orphan); Fallback UUID wenn Param fehlt; foto.registriert dedupliziert schon nach id (unverändert). Kein Schema-Change. (5) UI: Detail-Panel-Toast „Foto erfasst" (+ „offline — wird bei Verbindung gesendet"), kein synchroner Fehler-Toast mehr; Shell-Badge im Footer. Entscheidungen: (a) always-enqueue + drain (uniform online/offline, keine Halb-Zustände); (b) R2-Key aus fotoId statt Client-Orphan-Management; (c) kein Background Sync in Stufe C (in-page-Drain deckt „offline erfassen → Reconnect bei offenem Tab"; Upload nach Tab-Schließen = Folge-Schritt). Review-Fixes (CodeRabbit, PR #264): (a) Persistenz-Fehler nicht mehr still verschluckenput()/add()/update() liefern boolean; uploadFoto() wirft bei Puffer-Fehlschlag (Queue hält die einzige Kopie des Fotos), das Detail-Panel zeigt statt „erfasst" einen Warn-Toast. (b) Registrierung ack-getriggert — die registered-Flags werden nicht mehr blind nach send() gesetzt (verpuffte WS-Meldung ⇒ Foto fehlt im State ⇒ Eintrag würde fälschlich gelöscht); erst wenn der Server das Foto in den State zurückspielt (fotoImState/fotoOriginalImState), gilt die Registrierung als bestätigt — der State-Broadcast triggert den nächsten Drain (idempotent, Server dedupt nach id). (c) Permanent vs. transient — ein Server-4xx (außer 408/429) entfernt den Eintrag + meldet zentral (fotoUploadFehler → Shell-Toast) statt endlos zu retryen; Offline/5xx bleiben liegen. (d) update()-Persist-Fehler stoppt den Schritt (In-Memory-Flag darf dem IndexedDB-Stand nicht vorauslaufen). (e) Fehler-Liste statt EinzelwertfotoUploadFehler ist eine Liste (mehrere 4xx-Ablehnungen im selben Drain-Turn würden bei einem Einzel-Signal koalieren → ein Toast ginge verloren); die Shell konsumiert je Fehler genau einen Toast. Nutzer-Wünsche (Folge in diesem PR): (1) Queue-Detailsicht (Popover): das Footer-Badge „N warten" ist klickbar → kompaktes Popover je wartendem Foto (Thumbnail via Objekt-URL, Auftragsnummer · Perspektive, Status lädt/registriert/wartet auf Verbindung, „HQ"-Marke bei Original); neues eintraege-Signal im OfflineFotoQueueService, Objekt-URLs per Effect synchron gehalten + bei Entfernen/Destroy freigegeben (kein Leak). (2) Original immer mitarchiviert (OP-R4-1): zu jedem Foto wird zusätzlich die volle Auflösung über die Queue nachgeladen (beweiskräftig QS/Audit) — der frühere „Original archivieren"-Schalter entfällt (Panel-Hinweis „Original wird mitarchiviert"). Entscheidung/Abwägung: ~doppeltes R2-Volumen bewusst in Kauf genommen (Nachweisbarkeit > Speicher). Klarstellung: die volle Auflösung liegt immer vor — hat die Kompression verkleinert, wird eine zweite (Original-)Datei nachgeladen; hat sie nichts verkleinert, ist die einzige gespeicherte Datei bereits das Original (kein zweiter Upload). Verifikation: neuer test:fotoqueue (blockierender CI-Gate, 8 Fälle) grün · ng build grün · Server tsc grün. Doku: docs/architektur/Offline-PWA.md (Stufe C ✅ + Architektur/Verifikation), docs/konventionen/IDs.md (OP-OFFLINE-1), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-29-offline-foto-queue).
  • Branch claude/ci-path-filters (PR folgt) — OP-CI-1 Folge-Hebel: Pfad-Filter je Bereich + SBOM nur auf main (Version 0.35.1 → 0.35.2 PATCH — reiner CI-Tweak; Build auto, OP-PM-2). Auftrag (Nutzer): „beide" (die im Vor-PR angebotenen Folge-Hebel umsetzen). Gebaut (nur .github/workflows/ci.yml + Doku): (1) Pfad-Filter je Bereich: der changes-Job (dorny/paths-filter) liefert jetzt Bereichs-Outputs server/client/solver/design/security (OR-Quantifier; geteilte Dateien scripts/**+ci.yml triggern per YAML-Anker &shared alle Bereiche); jeder schwere Job läuft nur bei needs.changes.outputs.<Bereich> == 'true' github.event_name == 'push' → ein bereichsfremder PR (z. B. nur client/**) überspringt server (27 tsx-Tests) + solver + persistence-gate. Sicherheitsnetz: auf main-Push laufen via ‖ push alle Jobs voll → volle Validierung + korrekte deploy-needs vor jedem Release (Deploy bleibt unangetastet). Doku-only (docs/**+*.md) matcht keinen Bereich → Fast-Track bleibt. (2) SBOM nur auf main: sbom-Job auf github.event_name == 'push' gegated (Artefakt, kein Merge-Gate) → spart je PR npm ci; „immer aktuell" auf main gewahrt (OP-SBOM-1-Wortlaut in CLAUDE.md nachgezogen). Entscheidungen: (a) Bereiche sind physisch getrennt (server/ ↔ client/ ↔ solver-service/) → ein Bereichs-PR kann einen anderen nicht brechen; geteilte Dateien triggern sicherheitshalber alles; (b) main-Push validiert immer voll (fängt bereichsübergreifende Fälle vor dem Deploy). Verifikation: YAML-Parse (Jobs/ifs/Anker-Auflösung je Bereich geprüft) — keine outputs.code-Reste; die vier übrigen Workflows unberührt (schon schlank). Kein Server-/Client-/Solver-/Schema-Change. Doku: .github/workflows/ci.yml (Kommentare), CLAUDE.md (OP-SBOM-1), konventionen/IDs.md (OP-CI-1), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-29-ci-path-filters).
  • Branch claude/ci-optimize-minutes (PR #262) — OP-CI-1: GitHub-Actions-Build-Minuten halbieren (Doppelläufe weg + überholte Läufe abbrechen) (Version 0.35.0 → 0.35.1 PATCH — reiner CI-Tweak; Build auto, OP-PM-2). Auftrag (Nutzer): „Build-Minuten optimieren, damit das Actions-Kontingent nicht so schnell ausgeschöpft wird" (ausgelöst durch einen Actions-Kontingent-/Incident-Stau, der PR #261 zeitweise blockierte). Befund: ci.yml lief mit on: push und on: pull_request ohne Branch-Filter → jeder Push auf einen PR-Branch startete zwei komplette Läufe; zudem kein concurrency → überholte Läufe liefen weiter. Gebaut (nur .github/workflows/ci.yml): (1) push auf branches: [main] beschränkt — Feature-Branches werden nur noch über das pull_request-Event geprüft (keine Doppelläufe; Deploy = main+push bleibt unberührt). (2) concurrency-Gruppe je github.ref mit cancel-in-progress außer auf main (kein Abbruch laufender Deploys). Entscheidungen: (a) Push-CI nur auf main — Preis: Branch ohne PR bekommt keine CI (läuft beim PR-Öffnen; üblicher Standard); (b) Concurrency canceled bewusst nicht auf main (Deploy-Schutz). Bewusst NICHT (als Folge-Hebel angeboten): Pfad-Filter je Bereich (server/client/solver/design nur bei Bereichs-Änderung) + SBOM von jedem PR auf main/Schedule verlegen. Verifikation: ci.yml per YAML-Parse geprüft (top-keys + concurrency korrekt); die anderen vier Workflows (docs-deploy/fly-deploy/sync-pr-logs/weekly-audit) sind bereits schlank (main+Pfad-Filter/Schedule/manuell). Kein Server-/Client-/Solver-/Schema-Change. Doku: docs/konventionen/IDs.md (OP-CI-1 neu), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-29-ci-optimize-minutes).
  • Branch claude/pwa-read-offline (PR #261) — OP-OFFLINE-1 Stufe B: Offline-Fähigkeit als PWA (Service Worker + Read-Offline), keine native App (Version 0.34.0 → 0.35.0 MINOR — neues Feature; Build auto, OP-PM-2). Auftrag (Nutzer): „Offline-fähig — abwägen App vs. Webbrowser nach einmaligem Laden; Bild-Upload soll definitiv versetzt erfolgen können." Entscheidung: PWA statt nativer App (Infra schon PWA-tauglich: HTTPS + statische Worker-Assets; ein Web-Deploy bedient alle Plattformen). Gebaut (Stufe B, reiner Client + Build-Konfig): (1) PWA-Shell: @angular/service-worker + client/ngsw-config.json (App-Shell prefetch, Fonts/Bilder lazy, navigationUrls ohne /api/**); angular.json serviceWorker + assets(public); provideServiceWorker(..., { enabled: !isDevMode(), registrationStrategy: 'registerWhenStable:30000' }) in app.config.ts (nur Prod); Web-Manifest client/public/manifest.webmanifest + SVG-Icon client/public/icon.svg (everything-as-code, kein Binär-Master) + <link rel="manifest"> in index.html. (2) Read-Offline: neuer StateCacheService (IndexedDB, ein Snapshot des LeitstandState; IndexedDB statt localStorage wegen Größe); LeitstandService persistiert je state-Broadcast (lastStateAt/hydratedFromCache) und hydriert beim Start aus dem Cache, solange kein Live-Broadcast kam (Broadcast hat Vorrang); Offline-Banner in der Shell (offlineStale → „Offline — Stand von HH:MM · nur Ansicht"; Datum, wenn der Stand nicht von heute ist). Read-Only hart durchgesetzt: LeitstandService.send() verwirft Schreib-Kommandos bei !connected() → offline landet nichts in PartySockets flüchtiger In-Memory-Queue (kein halb-abgesetzter, nicht-idempotenter Reconnect-Replay). Cache-Versionierung: der Snapshot trägt eine SCHEMA-Version; load() verwirft Alt-/inkompatible Snapshots (kein Hydrieren veralteter LeitstandState-Shapes). Review-Fixes (CodeRabbit, PR #261): PR-Link im CHANGELOG; Banner-Datum nach Mitternacht; Read-Only-send()-Guard; Cache-SCHEMA. Raster-PNG-Icons (192/512) als optionaler Folge-Schritt notiert (Toolchain hat keinen SVG→PNG-Rasterizer; Chromium akzeptiert SVG-Manifest-Icons; SVG bleibt everything-as-code-Master). Bewusst NICHT: Offline-Schreiben von Aktionen (großer Folge-OP, Idempotenz/Reconnect-Replay/Konflikte) und Foto-Upload-Queue (Stufe C / PR C, baut auf der PWA-Shell auf). Design-Gate: manifest/index.html liegen außerhalb des No-Hex-Scopes (check-no-hex.sh scannt nur client/src/app + styles.css) → literale Brand-Hex erlaubt; Banner nutzt var(--tk-amber) via color-mix (kein Hex). Verifikation: ng build grün → ngsw-worker.js + ngsw.json (assetGroups app/assets, Manifest + Icon im Hash-Table) erzeugt; No-Hex-Gate grün. Kein Server-/Solver-/Schema-Change. Doku: docs/architektur/Offline-PWA.md (neu, ADR + Stufenplan), docs/konventionen/IDs.md (OP-OFFLINE-1), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-29-pwa-read-offline).
  • Branch claude/server-checks-timing-omm2he (PR #260) — OP-QS-GATE: QS-Vollständigkeits-Gate vor der Abholung (server-hart) + Nacharbeit als QS-Phasen-Schritt (Version 0.33.1 → 0.34.0 MINOR — neues Feature; Build auto, OP-PM-2). Auftrag (Nutzer): „Nacharbeit als Prozessschritte innerhalb der QS hinzufügen — dokumentiert, dass Nacharbeit erforderlich war; in der QS auch prüfen, dass alle Prozessschritte ausgeführt und dokumentiert wurden." Gebaut: (1) Nacharbeit = QS-Phasen-Schritt: neues optionales TeilschrittInstanz.phase (Per-Instanz-Override); nacharbeitInstanz setzt phase: 'qs' → die Nacharbeit dokumentiert sich als QS-Schritt (statt die Produktions-Phase des Original-Templates zu erben); aktuellePhase + Teilschritt-DTO bevorzugen die Instanz-Phase vor phaseByTs. (2) Server-hartes Gate (abholen): neue pure istAbnahmebereit(auftrag, dokuPflichtByTs, fotoAnfByTs, fotosByInstanz){ ok, offen[] }: jeder nicht übersprungene Teilschritt muss erledigt + (falls pflichtig) dokumentiert (Kommentar) + Foto-Pflicht erfüllt sein und kein QS-Mangel offen; der auftrag.aktion-Handler lehnt abholen ab, wenn !ok (kein Übergang), sendet auftrag.aktion.result (neuer ServerMsg, mit offen[]) + Audit auftrag.abnahme.abgelehnt (OP-AUDIT-1). Schließt die Lücke: bisher akzeptierte der Server abholen blind (transition fertiggestellt→abgeschlossen ohne Prüfung). (3) Client (Qualität-Sicht): neue Prozess-Vollständigkeits-Tafel je Auftrag (pro Schritt erledigt?/Doku?/Foto? + offene Mängel, aus dem DTO) — spiegelt das Server-Gate; „Übergeben" zusätzlich an abnahmebereit(a) gebunden; abgelehnte Server-Abholung als Toast (auftragAktionResult-Signal); die manuelle Sicht-Checkliste startet frisch je QS-Runde (Schlüssel ${id}:${nacharbeit-Schritt-Anzahl} → kein veraltetes „Bestanden" nach Nacharbeit, kein neues Server-Feld). Entscheidungen (Sign-off): (a) kein separater Lifecycle-Status nacharbeit — der bestehende nacharbeitEinplanen-Mechanismus (Solver-Replan) bleibt, die Nacharbeit wird stattdessen als QS-Phasen-Schritt geführt; (b) Gate server-seitig hart (auditierbar/manipulationssicher), nicht nur Client; (c) Sonderwünsche bewusst vertagt (eigener PR) — istAbnahmebereit ist als Erweiterungspunkt dafür vorbereitet. Verwandte, bewusst NICHT in diesem PR: transition()fertiggestellt setzt offene Schritte weiterhin auf erledigt (das Gate fängt undokumentierte ab) — optionale Härtung als Folge-Schritt notiert. Migration: SCHEMA_VERSION 15 → 16 (additiv, Per-Instanz-Phase; kein Transform — fehlt ⇒ Template-Phase). Verifikation: Server tsc + neues test:abnahme (blockierender CI-Gate, 7 Fälle: erledigt/Doku/Foto/übersprungen/Mangel-Matrix) + test:do-migrations (v0→v16) + test:nacharbeit/operativ/replan grün · ng build grün. Kein Solver-Redeploy. Doku: docs/fachlich/Lastenheft.md (§5.1 QS-Gate + Nacharbeit-als-QS-Schritt), docs/architektur/Operative-Durchgaengigkeit.md (OP-QS-GATE), docs/konventionen/IDs.md, HANDOFF (§4), CHANGELOG, Timesheet (2026-06-29-server-checks-timing-omm2he).
  • Branch claude/nacharbeit-mangel-behoben (PR folgt) — OP-UX-3-Nachzug: Mangel automatisch behoben beim Abschluss der Nacharbeit (Version 0.33.0 → 0.33.1 PATCH — kleiner Nachzug; Build auto, OP-PM-2). Auftrag (Nutzer): beim Abschluss des Nacharbeits-Schritts den zugehörigen Mangel automatisch auf behoben setzen (blieb bisher offen). Gebaut (reiner Server-Pfad): neue Verknüpfung TeilschrittInstanz.mangelId (gesetzt bei nacharbeitInstanz, durchgereicht aus auftrag.nacharbeitEinplanen = mangel.id); die pure erledige-Funktion setzt beim Erledigen eines Nacharbeits-Schritts den verknüpften Auftrag.maengel-Eintrag auf behoben (idempotent, nur wenn noch offen); der teilschritt.aktion-Handler ergänzt Protokoll + Audit mangel.behoben (OP-AUDIT-1, Actor aus per-Connection-E-Mail). Damit schließt sich der QS-Kreis Mangel → Nacharbeit → behoben. Kein Client-Change nötig (Mangel-Status fließt über das bestehende maengel-DTO). Self-Test test:nacharbeit um zwei Fälle erweitert: (5) Abschluss behebt den verknüpften Mangel; (6) ein normaler Schritt lässt Mängel unberührt. Verifikation: Server tsc + test:nacharbeit + operativ/replan/running-process grün. Kein Solver-Redeploy, kein Schema (nested-optional). Doku: docs/architektur/Operative-Durchgaengigkeit.md (§OP-UX-3 Nachzug), docs/architektur/Audit-Log.md (Event mangel.behoben), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-29-nacharbeit-mangel-behoben).
  • Branch claude/nacharbeit-gantt (PR #258, gemergt) — OP-UX-3: Nacharbeit nach QS-Mangel live im Gantt (Version 0.32.0 → 0.33.0 MINOR — neues Feature; Build auto, OP-PM-2). Auftrag (Nutzer): Flow-Audit-Backlog — QS-Nacharbeit war nur eine Kennzahl (Auftrag.maengel[].nacharbeitAufwandMin + client-lokale Markierung), kein geplanter Schritt: keine Kapazität, kein Gantt-Block, keine Verschiebung von geplanteFertigstellung/Reserve → Cockpit beantwortete Auslastung & „wann fertig/frei?" falsch. Gebaut (voll solver-integriert): (1) Scheduler-Kern: dynamische zusatzSchritte im AuftragInput werden in scheduleLeistung (TS) und buildProblem (CP-SAT) nach dem Skip-Filter an den statischen Leistung.prozess angehängt (Wiederverwendung ProzessSchritt.dauerOverrideMin+abhaengigkeit); neue TeilschrittInstanz.nacharbeitMin (optional, abwärtskompatibel) trägt die Vorgabe-Dauer; toAuftragInput erzeugt daraus die Zusatzschritte; applyPlanung bleibt index-stabil (nach Reopen sind statische Schritte erledigt/geskippt → einziger planbarer Schritt = Nacharbeit). (2) Lifecycle: neue Transition nacharbeiten: fertiggestellt → angeliefert. (3) Handler auftrag.nacharbeitEinplanen: offene Aufwands-Mängel → je eine Nacharbeits-TeilschrittInstanz (Skill/Bucht-Typ vom betroffenen Schritt, Dauer = Aufwand, Bucht+Crew solver-frei), Reopen, sofortiger Einzel-Plan (konkrete Bucht/Zeit/Crew → live im Gantt) + REOPT_EVENTS (globale CP-SAT-Reopt als Vorschlag), Audit nacharbeit.eingeplant; TeilschrittDTO.nacharbeit-Flag. (4) Client: Qualität-Sicht-Button „⚠ Nacharbeit einplanen" (Sichtbarkeit/Badge persistiert über offene Mängel statt client-lokaler Set), Detail-Panel kennzeichnet Nacharbeits-Schritte (⚠), Gantt-Block trägt den „Nacharbeit: …"-Namen; Reserve/Konflikt aktualisieren sich automatisch über geplanteFertigstellung. Entscheidungen (Sign-off): (a) erst bestätigen (expliziter Einplanen-Schritt statt Auto-Reopen); (b) voll solver-integriert (echter Solver-Schritt, TS+CP-SAT); (c) Solver wählt Bucht/Mitarbeiter frei (Skill+Dauer fix vom Mangel-Schritt). Verifikation: Server tsc + neues test:nacharbeit (blockierender CI-Gate: Zusatzschritt fließt durch Scheduler+Mapping, verschiebt Fertigstellung) + operativ/replan/running-process/spike grün · ng build grün · No-Hex + persistence:check grün (nested-optional → kein Gate-Treffer) · ci.yml strict-YAML. Kein Solver-Redeploy, kein Schema-Change. Doku: docs/architektur/Operative-Durchgaengigkeit.md (§OP-UX-3 + Backlog abgehakt), docs/fachlich/Lastenheft.md §4.9.1, docs/konventionen/IDs.md + Register.md (OP-UX-3-Zeile), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-29-nacharbeit-gantt).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257) — main eingepflegt + Review-Fixes (CodeRabbit) + Version-Rebase (Version 0.31.2 → 0.32.1 PATCH; Build auto). (1) Merge origin/main (#254 Klärfälle-Workspace · #255 OP-/Entscheidungs-Register · #256 Wettbewerbsanalyse): einziger Konflikt server/src/version.ts (main 0.32.0 ↔ Branch 0.31.2) → auf 0.32.1 rebased (PATCH über main); union-merge-Logs sauber konkateniert. (2) CodeRabbit-Review-Fixes: Tooltip in occupancy.component.ts an „Vorbereitung starten" angeglichen (war noch „Produktion starten"); addStep() nutzt jetzt angeboteneTeilschritte() (nicht-archivierte) als Default statt der vollen Katalogliste (verhindert Einfügen archivierter Vorlagen — Folge des Bugfix-Katalogs); sprechende Labels in Prosa nachgezogen („Sprung zu QS" → „Sprung zu Quality-Check", „Annahme/Aufbereitung/QS" → „…/Vorbereitung/Quality-Check") in CLAUDE.md + Lastenheft.md §5.1/OP-R3-1 (technische Keys qs/aufbereitung unverändert); „PR folgt"-Platzhalter im CHANGELOG durch PR-#257-Link ersetzt; Roadmap.md um Zielgruppe/Wofür-Zeile ergänzt. Verifikation: Server typecheck + test:prozess + Client ng build grün (nach Merge + Fixes). Doku: server/src/version.ts, client/.../{occupancy,processes}.component.ts, CLAUDE.md, docs/fachlich/Lastenheft.md, docs/betrieb/Roadmap.md, CHANGELOG, Timesheet. Offen (CodeRabbit-Nitpick, bewusst nicht umgesetzt): HANDOFF §4 thematisch gruppieren — gehört zur strukturellen OP-Entdoppelung (OP-DOCS-11), nicht in diesen PR.

2026-06-28

  • Branch claude/comments-image-support-caix8o (PR folgt) — OP-R4-3 / F16: Inhaltliche Doku-Vorgaben am Kommentar + OP-PM-3: Session-ID-Repo-Präfix (Version 0.40.2 → 0.41.0 MINOR — neues Feature; Build auto, OP-PM-2). Auftrag (Nutzer): Jede Kommentarfunktion (Auftragsabschluss/nächster Schritt) soll Bilder anzeigen, eine Mindestanzahl bestimmter Bilder erzwingen, und inhaltlich vorgeben, auf welche Aspekte eine Beschreibung eingehen soll (Diktat/Textbausteine/Mehrsprachigkeit „später"). Befund: Bild-Anzeige, Foto-Mindestanzahl je Perspektive (fotoPflicht, F15) und Pflicht-Kommentar (dokuPflicht, F14) sind bereits gebaut — alle Kommentar-Einstiege (Aufträge/Gantt/Tafel/Meine Arbeit) laufen durch dasselbe geteilte Detail-Panel-Gate. Neu gebaut (F16): Teilschritt.dokuAspekte: string[] — kuratierter inhaltlicher Leitfaden „Worauf eingehen?", der die geforderten Aspekte über dem Kommentarfeld einblendet (weiche Vorgabe; der Pflicht-Kommentar selbst bleibt dokuPflicht). End-to-end: types.ts (Feld + Helper dokuAspekte, normalisiert), setzeTeilschrittFelder-Patch (prozess.ts), TeilschrittDTO server+client, toAuftragDTO/buildProzessKatalog/snapshot-Map, Anzeige im Kommentar-Gate (auftrag-detail-panel.component.ts); Seed-Beispiele an Annahme/Aufbereitung/Folierung/QM (vest-automotive.ts) + Ergebnis-Foto-Pflicht an der Endkontrolle; test:prozess Abschnitt 9b. Roadmap als Design-Doc docs/architektur/Doku-und-Kommentare.md (pyramidal, Zielgruppen, Mermaid-Durchstich): additive Folgestufen OP-DIKTAT-1 (Sprach-Diktat), OP-TEXTBLOCK-1 (Textbausteine), OP-I18N-1 (Mehrsprachigkeit), OP-AI-2 (KI-Plausibilität), OP-ABSCHLUSS-1 (separate Doku-/Übergabe-Notiz auf Auftrags-Ebene — heute liegt Doku nur je Teilschritt) — alle auf demselben Doku-Modell; Empfehlung Textbausteine → Diktat → Mehrsprachigkeit. Entscheidungen: (a) dokuAspekte = weiche Vorgabe (angezeigt, nicht je-Aspekt hart erzwungen — Erzwingung ob die Aspekte tatsächlich adressiert sind = KI-Plausibilität OP-AI-2); (b) keine neue Editor-UI für dokuAspekte (server-seitig patchbar, konsistent mit dokuPflicht/fotoPflicht, Editor folgt mit OP-R3-3). OP-PM-3 (Nutzer-Wunsch dieser Session): Timesheet-Session-IDs ab jetzt mit Repository-Präfix <repo>-<Datum>-<branch-slug> (Timesheet §Protokoll/Kopf, agents.md §6.6, CLAUDE.md, session-start-hook.sh; erste Session mit der neuen ID = Dogfooding). Verifikation: Server tsc + test:prozess + operativ + ng build (prod) grün. Reiner Server+Client-Pfad, kein Solver-Redeploy. Doku: docs/architektur/Doku-und-Kommentare.md (neu), HANDOFF (§4 OP-R4-3/OP-PM-3/OP-DIKTAT-1/OP-TEXTBLOCK-1), CHANGELOG, Timesheet (taktano-2026-06-28-comments-image-support-caix8o).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257) — Fachliche Phasen-Labels umbenannt („Aufbereitung" → „Vorbereitung", „QS" → „Quality-Check") + OP-PHASE-1 (Produktions-Benennung & Vor-Produktion) festgehalten (Version 0.31.0 → 0.31.1 PATCH — sprechende Labels/kleiner Tweak; Build auto, OP-PM-2). Auftrag (Nutzer, iterativ): „Nenne ‚Aufbereitung' im Prozess ‚Vorbereitung & Car-Check'" → präzisiert: „Aufbereitung → Vorbereitung (inkl. Car-Check und Folien-Produktion)", „QS → Quality-Check", und „Folien-Produktion / bessere Produktions-Benennung als OP festhalten". Gebaut: (1) Rename (nur sprechende Labels): fachliche Phase 2 „Aufbereitung" → „Vorbereitung" (Scope: Waschen + Car-Check + Folien-Produktion/Zuschnitt) und „QS" → „Quality-Check"; die technischen Phasen-Keys bleiben aufbereitung/qs (Muster wie Status „Fahrzeug angeliefert"/Key angeliefert — kein Schema-/Enum-Change, keine Migration). Single-Source client/src/app/leitstand/phase.ts (PHASE_LABEL) → propagiert automatisch in Flow-Band/Orders/Detail-Panel; Wareneingang-Button „▶ Aufbereiten starten" → „▶ Vorbereitung starten" (occupancy.component.ts). (2) OP-PHASE-1 neu (zwei Aspekte): (a) bessere Benennung der Produktions-Phase (generisch „Produktion" vs. gewerk-/leistungs-spezifisch „Folien-Applikation"/„Lackierung"; multi-Gewerk → abgeleitet vs. Tenant-/Admin-konfigurierbar, G-1); (b) „Vor-Produktion" differenzieren — Folien-Zuschnitt/Druck + Material-Bestellung sind vorgelagert, können nach der Annahme beginnen, belegen Plotter/Zuschnitt-Kapazität (nicht die Fahrzeug-Bucht); Scheduler muss Zeitraum + Auslastung der Folienproduktion als eigene Kapazität einplanen (True-North-Frage 1), verzahnt mit OP-R3-2 (Folien-Vorlauf/Lieferzeit). Entscheidungen: (a) nur Labels, Key/Enum/Schema unangetastet (minimal, migrationsfrei); (b) Produktions-Spezialisierung + Vor-Produktion bewusst als OP geparkt (Tragweite: Scheduler/Datenmodell/multi-Gewerk). Verifikation: No-Hex-Gate unberührt (kein Hex); Label-Change rein textuell. Reiner Client + Doku, kein Server-/Solver-/Token-/Schema-Change. Doku: CLAUDE.md (Standard-Prozess), docs/fachlich/Lastenheft.md (§5.1 + Mermaid + OP-R3-1 + OP-PHASE-1 neu), docs/zielgruppen/Lesepfade.md, design/COMPONENTS.md, design/WORKSPACES.md, HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Captures derselben Session — reine Doku/OP) — drei weitere Nutzer-Eingaben als offene Punkte festgehalten (kein Code): (1) OP-FEEDBACK-1 neu — In-App-Feedback mit Screenshot-Markierung; Frage „Chatbot oder Plugin?" → Empfehlung schlankes Eigen-Widget (html2canvas + Annotations-Overlay + Auto-Kontext Route/Version/Build/trace_id → R2-Bild + D1 + Triage) statt SaaS-Plugin (DSGVO/EU-Residenz; Infra R2/D1/DO/OTel + Assistent ist da); Chatbot = optionaler Zusatzkanal über OP-AI-4. (2) OP-I18N-1 geschärft — UI-Sprachen ausdrücklich + Chinesisch + Ukrainisch (Treiber: mehrsprachige Werkstatt-Belegschaft, nicht nur EU-Markt); auch in Lastenheft §8 (Internationalisierung/NFA) nachgezogen. (3) OP-AI-3 erweitert — Audio-Notizen zusätzlich mit Translator (Muttersprache → Transkript + Übersetzung in die Auftrags-/UI-Sprache, Original erhalten) und Domänen-Anpassung an taktano (ASR + Übersetzung auf Werkstatt-/Glossar-Vokabular getrimmt). (4) OP-BRAND-2 neu — „Automotivo" defensiv als Marke schützen (Markteintritts-Barriere); mit Proaktiv-Flagging der rechtlichen Risiken (automotivo.de = bestehende Nutzung/ältere Rechte · Bad-Faith-/Sperrmarken-Angreifbarkeit · „Automotivo" stark beschreibend → ggf. schutzunfähig · Portfolio-Aufwand) — kein Rechtsrat, vor Anmeldung Anwalt/Recherche DE/AT/CH. Doku: docs/fachlich/Lastenheft.md (§11.8 OP-AI-3 + OP-FEEDBACK-1 neu, §8-Internationalisierung), HANDOFF (§4: OP-I18N-1 + OP-FEEDBACK-1 + OP-AI-3-Notiz), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Capture — reine Doku/OP) — OP-R1-4 neu: Rückwirkende Abwesenheiten (Urlaub/Krank) trotz erfasster Arbeit + Abgrenzung gegen Datev/Lohnbuchhaltung (Nutzer). (1) Rückwirkend Urlaub/Krank eintragen, obwohl im Zeitraum Leistungsnachweise/Einsatz existieren → Widerspruch: flaggen (Klärfall) vs. blocken, Wirkung auf abgeleitete Urlaubs-/Krankheitstage + Überstundenkonto, Berechtigung + lückenlose Auditierung (OP-AUDIT-1). (2) Leitthese: taktano = SoR für operative Planung/Kapazität + Arbeits-Ist, nicht für die rechtsverbindliche Lohnabrechnung (bleibt Datev/Lohnbuchhaltung; Export/Schnittstelle statt Doppelpflege). ⚠ Proaktiv-Flagging DE/AT/CH (kein Rechtsrat): Arbeitszeiterfassungspflicht (BAG/EuGH), Krankheitsdaten = DSGVO Art. 9 (nur „krank", keine Diagnose), eAU als offizieller Nachweis, rückwirkende Korrektur = Manipulations-/Compliance-Risiko. Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.1 OP-R1-4 neu), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Capture — reine Doku/OP) — OP-ONBOARD-1 neu: In-App-Tutorials + sukzessive Feature-Freischaltung (Nutzer). (1) geführtes Onboarding/Tutorials in der App für die Kern-Flows in Werkstatt-Sprache (wiederverwendet Glossar-Sprechblasen, Empty-State-CTAs/OP-UX-1, In-App-Assistent/OP-AI-4; Form Coachmarks/Video/Doku-Link + „erledigt"-Status offen). (2) Features progressiv freischalten (progressive disclosure): Einsteiger sehen erst den Kern (Tafel/Annahme/Meine Arbeit), Fortgeschrittenes gestaffelt — Mechanik via Feature-Flags je Tenant (G-1)/Rolle (OP-AUTH-1)/Onboarding- bzw. Akademie-Fortschritt (OP-R1-3) offen; darf Funktionen gestaffelt einführen, nicht verstecken (Selbsterklärbarkeit). Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.8 OP-ONBOARD-1 neu), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Captures — reine Doku/OP) — zwei weitere offene Punkte (Nutzer): OP-CAL-1 neu — Feiertage je Bundesland vorschlagen (Betriebskalender): gesetzliche Feiertage je Bundesland (DE 16; analog AT/CH-Kantone) aus dem Region-Stammdatum des Tenants vorschlagen/vorbefüllen (inkl. beweglicher Feiertage), Vorschlag nicht hart (Betrieb bestätigt/überschreibt — Brückentage/Betriebsferien); Wirkung: betriebsweite Schließtage → Kapazität↓, Scheduler/Ausfall-Band „Geschlossen"/Termin+Reserve; Tenant-weiter Betriebskalender (admin-editierbar G-1); lohnrechtliche Feiertagsbehandlung bleibt Datev (OP-R1-4). OP-STAGE-1 neu — Mehrere Stages / Release-Stände: heute nur Produktion → getrennte Stages dev/test→staging/preview→production (Preview je Branch/PR, Promotion-Flow), via CF Worker-Environments (eigene DO/D1/R2 + Access je Stage), Fly separate App, Versions/Gradual Deployments (Canary), Release-Channels (komplementär OP-ONBOARD-1); ⚠ DSGVO: Non-Prod ohne echte PII → synthetischer Seed, strikte Trennung (OP-TENANT/OP-SEED-1). Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.1 OP-CAL-1, §11.10 OP-STAGE-1), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Capture — reine Doku/OP) — OP-R7-12 neu: Kommentare/Notizen bei der Auftragsaufnahme (Annahme) (Nutzer; Phase per Rückfrage geklärt = Annahme). Das Annahme-Formular (/annahme) erfasst heute nur strukturierte Felder, kein Freitext-Kommentar — §5.1 fordert je Phase „Doku & Kommentar"; Annahme = Stelle für Zustand bei Annahme/Kundenhinweise/Sonderwünsche/Vorschäden. Gewünscht: Kommentar-/Notizfeld bei der Annahme → gespeichert am Auftrag (Chronik/protokoll, sichtbar Aufträge/Detail). Offen: Pflicht vs. optional (OP-R4-3-Doku-Gate/ts-annahme), Sichtbarkeit (intern vs. an Mitarbeiter, R1 §4.1), einheitliche Textfeld-Komponente mit Foto-Upload (R4) + Diktat/Übersetzer (OP-AI-3). Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.1 OP-R7-12 neu), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Captures — reine Doku/OP) — OP-R7-12 verallgemeinert + OP-R7-13 neu (Nutzer). OP-R7-12 (vorher „Kommentar bei der Annahme") auf die Leitlinie „immer Kommentare erlauben — je mit Foto/Voice" erweitert: einheitliche, überall verfügbare Kommentar-Fähigkeit (jede Phase/Auftrag/Teilschritt), jeder Kommentar mit Foto (R4/OP-R4-3) + Voice/Audio (Transkript+Übersetzer, OP-AI-3) + Freitext, als Verlauf in Chronik/protokoll; konkreter Auslöser bleibt das fehlende Kommentarfeld bei der Annahme. OP-R7-13 neu: Umgang mit „freien Aufträgen" — Begriff zu schärfen; Lesarten (a) freier Prozess/ad-hoc-Leistung ohne Katalog-Leistung (Taktung braucht dennoch Dauer/Skill/Bucht), (b) freier Termin/best_effort, (c) ohne Kunde/Fahrzeug (interner Auftrag/Demo); zu klären Lesart(en) + Mindestangaben + Verhältnis Prozess-Editor (OP-R3-3) + Auslastungs-Zählung. Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.1 OP-R7-12 erweitert + OP-R7-13 neu), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Captures — reine Doku/OP) — OP-R3-4 neu (Vorbedingungen) + OP-R7-14 (Anzahlungen-Feststellung) (Nutzer). OP-R3-4: Vorbedingungen je Auftrag/Schritt erfassen + rechtzeitig veranlassen — verallgemeinert OP-R3-2 (Folie/Material „bestellt & eingetroffen" + Lieferzeit) auf beliebige Vorbedingungen (z. B. Ersatzteil für eine kleine Reparatur rechtzeitig bestellen, Werkzeug, Kundenfreigabe): Status offen→bestellt→eingetroffen/erfüllt, Vorlaufzeit → früheste Startschranke + Start-Gate bis erfüllt + Verzugswarnung. OP-R7-14: Feststellung „Anzahlungen werden in taktano nicht erfasst" — Ist nur Preis-Snapshot (Auftrag.preisCent); Abgrenzung (vgl. OP-R1-4): Geldflüsse = SevDesk (OP-BILLING-1), nicht taktano; offene Entscheidung = operatives „Anzahlung erhalten?"-Flag/Gate (Produktionsstart erst nach Anzahlung, analog OP-ACCESS-1) ohne Beträge zu verbuchen. Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.1 OP-R3-4 + OP-R7-14 neu), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Capture — reine Doku/OP) — OP-R7-15 neu: Prozess-Vorschau bei der Auftragserfassung + auftragslokal anpassen/kommentieren (Nutzer). Bei der Annahme (/annahme) nach Leistungswahl eine Vorschau des Prozesses (Teilschritte mit Dauer/Skill/Bucht/Phase aus buildProzessKatalog) zeigen → erlaubt weitere Schritte hinzufügen + bestehende Schritte kommentieren (Kommentar mit Foto/Voice via OP-R7-12) vor/bei der Anlage. Auftragslokale Anpassung der Prozess-Instanz (≠ Katalog-Edit OP-R3-3, der auf alle wirkt; passt zur Materialisierung E-CRUD-2). Zusatz-Schritte brauchen Dauer/Skill/Bucht → fließen in die Taktung (§5.2.2 Angebotsmodus/Machbarkeit/Preis/Reserve). Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.1 OP-R7-15 neu), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Captures — reine Doku/OP) — OP-BACKOFFICE-1 neu + TODO „Umparken checken" (Nutzer). OP-BACKOFFICE-1: Backlog der Vorarbeiten für Back-Office/Vorgesetzte — die Vorbedingungen/Vorarbeiten (OP-R3-4: Teile/Material bestellen, Beschaffung, Freigaben) auftragsübergreifend als Backlog/Arbeitsliste für eine Back-Office-Rolle/Vorgesetzten anzeigen (analog Werker-Sicht „Meine Arbeit", aber dispositiv): je Vorbedingung Auftrag/Fahrzeug · Typ · Status · Fälligkeit (aus Vorlaufzeit) · Priorität; Aktionen setzen den Vorbedingungs-Status → Start-Gate auf; reine Projektion (S-2); beantwortet „was muss jetzt beschafft werden, damit Termine halten?"; OP-R3-4 um Cross-Ref ergänzt. TODO „Umparken checken": Verifikations-Notiz — Umpark-Funktion (Belegung-Drag&Drop + repark.service.ts/repark-modal, interrupt-aware) end-to-end + Edge-Cases prüfen; in HANDOFF §4 als TODO geparkt (noch nicht abgearbeitet). Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.8 OP-BACKOFFICE-1 + §11.1 OP-R3-4 Cross-Ref), HANDOFF (§4 + TODO), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Capture — reine Doku/OP) — OP-QS-3 neu: Während der Bearbeitung verursachte Schäden erfassen → Nacharbeit-Kette mit Ersatzteil (Nutzer). Selbst verursachter Schaden beim Bearbeiten (z. B. Befestigungs-Clip bricht) direkt am laufenden Schritt/Auftrag als Mangel/Schaden erfassen (nicht erst in der QS) → durchgängige Kette: Schaden → Nacharbeit → Ersatzteil-Bedarf → Bestellung (als Vorbedingung OP-R3-4, im Back-Office-Backlog OP-BACKOFFICE-1, mit Vorlauf) → bei Eintreffen Einbau-Schritt planen/freigeben → eingebaut → behoben. Status-Workflow offen→bestellt→eingetroffen→Einbau geplant→behoben (erweitert OP-QS-1); Nacharbeit-Schritt trägt Ressourcen/Skill/Bucht → Taktung (Termin/Reserve); intern verursacht → Kosten/Verantwortung (OP-COST-1/OP-R10-1). Gleicher Mechanismus wie QS-Mangel (§4.9.1), aber Auslöser = während Bearbeitung. Erfassung mit Foto/Voice (OP-R7-12). Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.1 OP-QS-3 neu), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Capture — reine Doku/OP) — OP-R7-16 neu: Fahrzeug-Angaben bei der Annahme erfassen (Nutzer). Bei der Annahme (/annahme) direkt am Auftrag (§4.9: Fahrzeug = Attribute am Auftrag) Fahrzeugbeschreibung (Hersteller/Modell/Farbe), ein paar Fotos (Zustands-/Annahme-Doku, R4/OP-R4-3), Fahrgestellnummer (FIN) — immer (Pflicht), Kennzeichen — optional („manchmal"). Nutzen: eindeutige Identifikation (FIN), Beweissicherung/Vorschäden (verknüpft OP-R7-12/OP-QS-3), Wiedererkennung (OP-R6-1). Datenmodell: Auftrag.fahrzeug = {beschreibung, fin(Pflicht), kennzeichen?, fotos[]}, optional FIN-Plausibilität (17 Stellen ISO 3779). ⚠ DSGVO-Flag: FIN/Kennzeichen/Fotos personenbezogen → Zweckbindung + Löschkonzept (OP-CRUD-1, Fotos R2 eu). Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.1 OP-R7-16 neu), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Capture — reine Doku/OP) — OP-R6-2 neu: Fahrzeug-Visualisierung (Silhouette/3D/AR) + Besonderheiten-Wissensbasis je Modell (Nutzer). (1) Immer eine Fahrzeug-Silhouette anzeigen — 2D min., Ziel 3D (drehbar), AR vorbereiten — zum räumlichen Markieren von Schäden/Besonderheiten (⚠ 3D-Asset-Pipeline je Modell erheblich → stufenweise 2D→3D→AR). (2) Besonderheiten je Fahrzeugmodell aus dem Learning festhalten (Bsp. Nutzer: Porsche 911 ab GT mit Leichtbauscheiben); bei Annahme bekanntes Modell erkennen (FIN/Beschreibung, OP-R7-16) → Besonderheiten vorschlagen, sonst anlegen (Fahrzeugmodell-Katalog, getrennt von der auftragslokalen Fahrzeug-Instanz §4.9). (3) Cross-Tenant-Wissen als kostenpflichtiges Add-on (Schwarm-Wissen) — ⚠ Flag: widerspricht der Tenant-Isolation (OP-TENANT) → bewusst geteilte, opt-in + anonymisierte zentrale Wissensbasis (kein PII-Leak), Add-on-Subscription (OP-BILLING-1), Wettbewerbs-/Einwilligungs-Abwägung. Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.1 OP-R6-2 neu), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Capture — reine Doku/OP) — OP-R6-2 erweitert: Silhouette schon bei der Annahme zum Markieren von Arbeitsbereichen (Nutzer). Die Fahrzeug-Silhouette (OP-R6-2 Aspekt 1) direkt in der Annahme nutzen, um Arbeitsbereiche/Scope am Fahrzeug zu markieren (Beispiel: „länger gezogene Ladekante") — markierte Zonen verknüpfen Arbeitsumfang/Leistung mit dem Ort am Fahrzeug (Bezug OP-R7-15 Prozess-Vorschau, OP-R7-16 Fahrzeug-Angaben) und dienen Produktion/Quality-Check als gemeinsame Referenz; Annahme-Erststufe = 2D-Silhouette mit Zonen-Markierung (volle 3D/AR später, stufenweise). Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.1 OP-R6-2 Aspekt 1 erweitert), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Capture — reine Doku/OP) — OP-R2-3 neu: Buchten-Gantt aus der Planung in die Belegung verschieben + mehr Detail (Nutzer). Den Bucht-bezogenen Gantt (zeitliche Belegung je Arbeitsplatz/Bucht) aus Planung → Belegung verschieben (gehört thematisch zur Belegung, ergänzt den Hallen-/Hofplan OP-R2-2; beantwortet True-North-Frage 2 Standort-über-Zeit + 3 nächste freie Kapazität via Bucht-Lücken). Mehr Detail als Voraussetzung: je Bucht-Block Auftrag/Fahrzeug · Teilschritt · Mitarbeiter · Status/Phase · Standort · Cool-down/Settle · Ausfall-Bänder (scheduler/ausfall.ts) · freie Slots hervorheben. Offen: verschieben vs. duplizieren (Planung behält MA-/Optimierer-Sicht), gantt.component.ts auf Bucht-Zeilen parametrisieren, Detailtiefe vs. Übersicht. Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.2 OP-R2-3 neu), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Capture — reine Doku/OP) — OP-OPT-8 neu: Zeitlage-Präferenz je Leistung/Teilschritt (asap vs. jit/spät) (Nutzer). Auf Prozess-/Leistungs-Ebene festlegen, ob ein Schritt so früh wie möglich (asap) oder so spät wie möglich / just-in-time (jit, „optimiert/geplant") getaktet wird. Bsp.: Folierung asap, Fahrzeug-Aufbereitung/Endreinigung spät (kurz vor Abholung, damit es nicht wieder einstaubt). Heute nur Terminklasse je Auftrag + globale asap/jit-Zielmodi (§6.2); neu = teilschritt-/leistungsspezifisch (zeitlage: asap|jit|neutral, Prozess-Editor OP-R3-3, G-1). Scheduler als Soft-Goal (asap min. Startzeit, jit max. Startzeit bei harten Terminen), CP-SAT + TS. ⚠ Abwägung: jit reduziert Reserve/Puffer → nur weich, nachrangig zur Termintreue. Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.2 OP-OPT-8 neu), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Capture — reine Doku/OP) — OP-DATE-1 neu: konsistente, kontext-bewusste Datums-/Zeit-Darstellung (Nutzer; Ansatz entworfen + zur Diskussion). Statt nur „Di 08:00 Uhr" (mehrdeutig) generell Wochentag + Uhrzeit + Datum + relativen Bezug („heute/morgen/nächste Woche Dienstag"). Vorgeschlagener Ansatz: ein zentraler Formatter formatZeitpunkt(ts,{now,stil}) (Single-Source analog phase.ts), distanz-abhängig (heute/morgen relativ · gleiche Woche Wochentag+Datum · nächste Woche „nächste Woche Di, Datum" · weiter volles Datum · Vergangenheit analog), Datum immer ab >übermorgen, Tooltip = voller absoluter Zeitstempel, locale-aware (OP-I18N-1); ersetzt die ad-hoc-toLocale*-Aufrufe + die bestehende „morgen 08:00"-Logik überall (Karten/Gantt-Tooltips/Detail/Tafel/Shell/Annahme). Offen (Diskussion): Schwellen, Kurz-/Langform je Kontext, Zeitzone/Sommerzeit. Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.8 OP-DATE-1 neu), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Capture — reine Doku/OP) — OP-R8-13 neu: Konfliktvermeidungs-Hebel „Bereitschaft / (genehmigte) Wunschfrei heranziehen" (Nutzer, als Beispiel). Bei Termin-/Kapazitätskonflikt (§5.2.3) zusätzliche Kapazitäts-Hebel: (1) Bereitschaft (Überlauf-/Bereitschaftsschicht öffnen), (2) (genehmigte) Wunschfrei (weichen Frei-Wunsch zugunsten der Konfliktlösung überschreiben). Bausteine + Pönale-Reihung existieren aus OP-OPT-7 (Wunsch 2 < Bereitschaft 5 < genehmigte Überstunde 200 → weichste Quelle zuerst); neu = als konkrete, quantifizierte Hebel im Konflikt-Wizard, Propose-not-execute. ⚠ Zu klären: das „Ziehen" einer genehmigten Wunschfrei braucht ggf. MA-Zustimmung/Benachrichtigung (arbeitsrechtlich/Fairness sensibel) + Audit (OP-AUDIT-1). Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.2 OP-R8-13 neu), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Capture — reine Doku/OP) — OP-R3-5 neu: Reihenfolge der Prozessschritte hart durchsetzen — kein Überspringen (Nutzer). Ein Schritt startet erst, wenn die laut Abhängigkeit (nach_vorherigem) vorausgehenden erledigt sind; kein Out-of-Order-Start/Überspringen von Pflicht-Schritten (Guard in teilschritt.aktion; der Optimierer respektiert Abhängigkeiten bereits hart §6.1 — hier geht es um die manuelle Ausführung/UI); schließt die Flow-Analyse-Lücke (Start Schritt 3 vor Schritt 1). ⚠ Abgrenzung/Konsistenz (OP-DOCS-9): scheinbarer Widerspruch zu bestehenden Skip-Mechanismen — optional-Schritte (F05), Konflikt-Hebel „optionalen Schritt überspringen" (§5.2.3), frei/parallel-Abhängigkeit (G-1), Klärfall „Sprung zu QS"; Leitlinie: Pflicht-Schritte mit nach_vorherigem = hart/nicht überspringbar, abweichen nur explizit optional/frei/parallel + Klärfall; zu entscheiden: ob „kein Überspringen" auch optionale Schritte sperrt (Konflikt mit Skip-Hebel) + Override/Audit. Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.1 OP-R3-5 neu), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257) — Bugfix: neu angelegte Teilschritte erscheinen nicht (auch nach Reload) (Version 0.31.1 → 0.31.2 PATCH; Build auto). Befund (Nutzer-Bug): „+ Neuer Teilschritt" (OP-CRUD-1 C3) legte die Vorlage zwar persistent an, sie war aber nirgends sichtbar. Ursache: die Teilschritte-Liste im Prozesse-Workspace wurde ausschließlich aus den Leistungen abgeleitet — buildProzessKatalog emittiert Teilschritte nur, wenn sie in einer Leistung verwendet werden (Client processes.component baute teilschritte aus prozesse()), also blieb ein neuer, noch keiner Leistung zugeordneter Teilschritt unsichtbar (auch nach Reload, da serverseitig dieselbe Ableitung). Fix: Server liefert jetzt einen vollen Teilschritt-Katalog (buildTeilschrittKatalog → neues State-Feld teilschritteKatalog: ProzessSchrittDTO[], ALLE Vorlagen unabhängig von der Verwendung); der Client seedet die Teilschritte-Liste aus dem Katalog und reichert die „Verwendet in: …"-Info aus den Leistungen an. Verifikation: Server typecheck + test:prozess grün · Client ng build grün. Reiner Server+Client-Pfad, derived (kein Schema/Migration), kein Solver-Redeploy. Folge-Hinweis (Prod, OP-AUTH-1): die Create-/Archiv-Mutationen sind interim über istKostenAdmin gegated — in Prod kann ein Nicht-Kosten-Admin keine Katalog-Einträge anlegen (lokal fail-open); die saubere Rollentrennung (Katalog-Admin ≠ Kosten-Admin) gehört zu OP-AUTH-1. Doku: server/party/leitstand.ts, client/.../leitstand.service.ts, client/.../pages/processes.component.ts, server/src/version.ts, CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Captures — reine Doku/OP) — drei neue OPs (Nutzer): OP-R3-6: Kommentare & besondere Hinweise je Teilschritt und Leistung (Katalog-Ebene) — dauerhafte Hinweise an der Vorlage (gilt bei jeder Verwendung; ≠ auftragslokaler Kommentar OP-R7-12 ≠ Modell-Besonderheit OP-R6-2), Teilschritt.hinweis/Leistung.hinweis (Text + Foto/Voice), Prozess-Editor (OP-R3-3). OP-AI-5: KI-gestützte Meeting-Minutes — Besprechungs-Protokolle (docs/betrieb/meetings/ besteht) per ASR/KI: Transkript rein → Zusammenfassung auf taktano-Vokabular/Glossar („taktano lingo") → .md; offen Provider/EU-DSGVO, Glossar-Prompt-Kontext (OP-AI-3 (e)), PII-Scrubbing, Mensch-Bestätigung. OP-FIND-1 (Owner: Dominik & Julian): Sonderwünsche — Häufigkeit + Auffindbarkeit — welche Sonderwünsche kommen häufig vor (Auswertung); auffindbar über Synonyme + über den Nutzen (nicht nur Fachbegriff); später Chatbot (OP-AI-4) macht Begrifflichkeiten zugänglich; fachliche Vorarbeit Dominik/Julian. Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.1 OP-R3-6, §11.8 OP-AI-5 + OP-FIND-1), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Captures — reine Doku/OP) — zwei neue OPs (Nutzer): OP-COST-5 (Roadmap): Rentabilitätsberechnung & Prognosen / Ziel-Tracking — Leitfrage „wieviele Aufträge muss ich noch abwickeln, um unser Ziel zu erreichen?"; kombiniert Umsatz/Marge (OP-R7-6/SevDesk) × Auslastung/Kapazität (True North 1+3) × Zielvorgabe → Forecast (Ist vs. Plan, „noch X Aufträge à Ø-Marge bis Ziel", Szenarien); grob umrissen, Konzept noch ordentlich auszuarbeiten (Ziel-Datenmodell, Forecast-Methodik, Dashboard OP-R9-10). OP-R7-17: Rabatte / Nachlässe — welche Rabatte sind möglich; auf dem Preismodell (OP-R7-6) prozentual/absolut, je Auftrag/Position/Kunde, Aktions-/Mengen-/Treue-/B2B/Kulanz; Wirkung auf Auftragswert + Marge (OP-COST-1); Audit (wer/wieviel/warum, OP-AUDIT-1); Berechtigung/Freigabe (OP-AUTH-1); Rechnung/Steuer bleibt SevDesk (OP-BILLING-1). Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.3 OP-COST-5, §11.1 OP-R7-17), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, Folge-Capture — reine Doku/OP) — OP-R1-5 neu: Arbeitszeitkonten & Abfeiern + „Auftrag fertigstellen trotz Schichtende" (Nutzer). (1) Überstundenkonto (derived, §4.1) + Abfeiern (Comp-Time als planbare Abwesenheit, reduziert Verfügbarkeit wie Urlaub/Wunschfrei). (2)Erst nach Hause, wenn das fertig ist": Auftrag/Schritt als „muss jetzt fertig" markieren → plant Überstunden (pönalisiert, mit Zustimmung), Mehrzeit → Arbeitszeitkonto (später abfeierbar) — schließt den Kreis Überstunde⇄Abfeiern. ⚠ Abgrenzung (OP-R1-4): rechtsverbindliches Konto = Datev/Lohn; taktano operativ + Export. ⚠ Flag DE/AT/CH: ArbZG-Grenzen (Höchstarbeitszeit/Ruhezeiten) bei geplanten Überstunden. Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.1 OP-R1-5 neu), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, reine Doku/OP) — OP-PM-3 neu: OP-Priorisierung nach Dringlichkeit + rollierende 4-Wochen-Planung (Nutzer) → neues lebendes Dokument docs/betrieb/Roadmap.md. OPs aus §11/§4 nach Dringlichkeit gruppiert (🔴 Jetzt / 🟠 Next / 🟢 Später) + 4-Wochen-Plan (Entwurf ab 29.06): W1 Umparken-Check/OP-DATE-1/OP-R7-16, W2 OP-R7-12-Text/OP-R7-15, W3 OP-R3-4+OP-BACKOFFICE-1, W4 OP-QS-3/OP-R2-3. Status: Entwurf — Priorisierung vom PO zu bestätigen (offene Fragen: Goal der 4 Wochen, OP-R3-5 optional-skip, früh-wichtige „Später"-Themen). Lebend (Session-Start + nach Merges nachziehen, wie Sanity-Checkliste); in docs/README.md-Landkarte registriert. North Star = MVP 1.0.0. Kein Code. Doku: docs/betrieb/Roadmap.md (neu), docs/README.md, HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, reine Doku/OP) — OP-R7-7 geschärft (Roadmap): Customer Self-Service per Web-Portal + WhatsApp (Nutzer). Über den reinen Self-Service-Link hinaus ein Kunden-Kanal (Web-Portal + WhatsApp): Auftragsstatus verfolgen, Freigaben/Kostenvoranschlag bestätigen (OP-R3-4), Kommunikation, Fotos/Doku ansehen (OP-R7-12/-16), Wunsch-/Abholtermin abstimmen; Zielgruppe Customer Service; Sicherheit Token/Magic-Link bzw. IdP (OP-AUTH-1), DSGVO/EU. ⚠ WhatsApp: Business-API, Opt-in, Templates, Meta/US-Transfer datenschutzrechtlich prüfen. In docs/betrieb/Roadmap.md (🟢 Später, Kunde/Self-Service) aufgenommen. Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.1 OP-R7-7 geschärft), docs/betrieb/Roadmap.md, HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, reine Doku/OP) — OP-PM-3: PO-Priorisierung bestätigt + OP-R3-5 entschieden (Nutzer-Sign-off 06-28, via Rückfrage). (1) Fokus der nächsten 4 Wochen = „Annahme-Flow meisterhaft" (OP-R7-16 Fahrzeugdaten → OP-R7-12 Kommentar → OP-R7-15 Prozess-Vorschau; + OP-DATE-1 + Umparken-Check); 4-Wochen-Plan in docs/betrieb/Roadmap.md entsprechend gesetzt. (2) E-R3-5 ✅: nur Pflicht-Schritte (nach_vorherigem) unüberspringbar; optionale/frei/parallel bleiben überspringbar, der Konflikt-Hebel „optionalen Schritt überspringen" (§5.2.3) bleibt (Lastenheft §11.1 OP-R3-5 + HANDOFF aktualisiert). (3) In-App-Feedback (OP-FEEDBACK-1) aus „Später" in Woche 2 vorgezogen (frühes Betriebs-Feedback). Kein Code. Doku: docs/betrieb/Roadmap.md, docs/fachlich/Lastenheft.md (OP-R3-5 Entscheidung), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, reine Doku/OP) — OP-R3-5 ergänzt: Konsistenz-Check bestehender Prozess-Instanzen (Nutzer). Mit der harten Reihenfolge müssen bereits materialisierte TeilschrittInstanz (E-CRUD-2) auf Status-Konsistenz geprüft werden — die frühere Heuristik ließ Out-of-Order zu, also kann ein Schritt erledigt sein, obwohl ein nach_vorherigem-Vorgänger noch offen ist. Vorgehen: idempotenter Prüf-/Reparatur-Lauf (schemaVersion-Migration, OP-DATA-1) + laufender Invarianten-Check (eindeutige Fälle glätten, sonst als Klärfall §5.1 markieren — nicht still überschreiben), abgesichert als blockierender Self-Test (analog test:running-process). Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.1 OP-R3-5), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, reine Doku/OP) — OP-DOCS-11 neu: OP-Verwaltung als Single Source + Query-Views (Nutzer-Frage „GitHub Issues o. Ä. + Query in der Doku, keine Inkonsistenzen — sinnvoll?"). Befund: OPs liegen heute redundant über Lastenheft §11/HANDOFF §4/Roadmap/Timesheet/CHANGELOG → Drift-Risiko (manuell via OP-DOCS-9 gehütet). Optionen knapp verglichen: (A) Markdown-Listen Status quo; (B) GitHub Issues als Quelle (Workflow-stark, verlässt das Repo → gegen Everything-as-Code); (C) Hybrid: ein Markdown-File je OP (Frontmatter) als In-Repo-Quelle → generierte Views (analog gen-glossar.mjs), Issues optional als Spiegel; (D) In-Doc-Feedback = anderes Thema. Empfehlung (C) Hybrid — löst Inkonsistenz an der Wurzel (eine Quelle statt fünf) ohne Repo-als-Wahrheit aufzugeben. Kein Code. Doku: docs/fachlich/Lastenheft.md (§11.10 OP-DOCS-11), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/aufbereitung-folien-produktion-mvn691 (PR #257, reine Doku/OP) — OP-Konsolidierung (Session 2026-06-28): Konsistenz-Audit + konsolidierter OP-Index. Audit: alle ~30 heutigen OPs in Lastenheft §11 UND HANDOFF §4 vorhanden, keine Doppel-IDs (mechanisch geprüft); check-doc-consistency + smooth-logs gelaufen — 0 neue Befunde (die 11 Warnungen sind vorbestehende Timesheet-Session-Dubletten 37–47 aus parallelen Alt-Sessions, abweichender Inhalt → manuell). Neu: Konsolidierter OP-Index in docs/betrieb/Roadmap.md — eine Tabelle aller Session-OPs (ID · Kurztitel · Dringlichkeit · Status neu/erweitert/entschieden/✅gebaut), inkl. Owner (FIND-1 = Dominik & Julian) und Code-Stände (Phasen-Rename v0.31.1, Bugfix v0.31.2). Strukturelle Entdoppelung (eine Quelle je OP) bleibt als OP-DOCS-11 vorgemerkt. Kein Code. Doku: docs/betrieb/Roadmap.md (Konsolidierter OP-Index), CHANGELOG, Timesheet (2026-06-28-aufbereitung-folien-produktion).
  • Branch claude/competitive-analysis-market-entry-vb79s4 (PR folgt) — Team-Seite: namenloses Mitglied benannt — „Lucas Tiede" (Doku-Site-only → kein Version-/Build-Bump). Nutzer-Angabe: „im Team: Der unbenannte heisst Lucas Tiede". Gebaut: in docs-site/src/pages/team.js den Platzhalter-Eintrag 'Mitarbeiter von Dominik' (Initialen ?, To-do „Namen ergänzen") ersetzt durch name: 'Lucas Tiede' (Initialen LT, Foto-Pfad-Kommentar /img/team/lucas-tiede.jpg, To-do auf „Rolle & Titel schärfen" reduziert); die globale To-do-Zeile „Namen des Mitarbeiters von Dominik ergänzen." entfernt; Rolle/Schwerpunkte unverändert (nur der Name war offen). docs-site/static/img/team/README.md um das Beispiel lucas-tiede.jpg ergänzt. Kein Code-/Solver-/Token-Change. Doku: docs-site/src/pages/team.js, docs-site/static/img/team/README.md, CHANGELOG, Timesheet (2026-06-28-competitive-analysis-market-entry).
  • Branch claude/competitive-analysis-market-entry-vb79s4 (PR folgt) — Mitbewerbsanalyse + Marktabschätzung/Markteintrittsstrategie als neue Produkt-Docs (OP-COMPETE-1 + OP-MARKET-1; reine Doku → kein Version-/Build-Bump, Präzedenz pure-docs 2026-06-28 optimizer-docs/glossary). Nutzer-Auftrag: „ergänze Mitbewerbsanalyse und Marktabschätzung/Markteintrittsstrategie in die docs". Befund: docs/produkt/Produkt-und-Marketing.md hatte nur eine Mitbewerber-Beobachtung (Automotivo) + ROI-Gerüst — keine eigenständige Wettbewerbs- oder Marktsicht. Gebaut — zwei neue Business/Management-Docs (pyramidal, Mermaid, alle Zahlen/Einschätzungen als Annahme markiert + Spalte „zu validieren", Stil wie der ROI-Rechner): (1) docs/produkt/Wettbewerbsanalyse.md (OP-COMPETE-1) — Kernaussage „kein direkter Vollkonkurrent, Wettbewerb fast nur indirekt"; 4-Kategorien-Landschaft (Automotivo / KFZ-DMS / generische Tools / Status quo „Zettel & Whiteboard" = häufigster Gegner) als Tabelle + Mermaid-Positionierung, Differenzierungsmatrix (Burggraben = Domänenmodell und echte Taktung/CP-SAT — kein Wettbewerber hat beides), SWOT, Risiko-Verweise. (2) docs/produkt/Markt-und-Markteintritt.md (OP-MARKET-1) — TAM/SAM/SOM mit transparentem Rechenweg + Mermaid-Trichter (Annahme ~8–15k Betriebe DACH → SAM ~3–5k → SOM ~150–400, ARPA-Hypothese ~3.000 €/J), Segmentierung (Gewerk × Größe × Region, Beachhead = Folierbetriebe DE), Go-to-Market (Mermaid-Gantt: Pilot → Referenz → Verband/Hersteller-Hebel → Skalierung + Phasen-Tabelle, zwei Kanäle Direkt + Multiplikator), Pricing-Hypothese (verweist auf OP-BILLING-1, kein Festpreis), Compliance als Kaufanlass (E-Rechnung DE/DSGVO). Entscheidungen: (a) zwei eigene Docs (statt Einbau/Kombi) — je eigene OP-ID, Pattern „ein Doc pro Belang"; die belegte Automotivo-Tabelle bleibt im Produkt-Doc, der Rest verlinkt; (b) Gerüst mit markierten Annahmen statt erfundener Präzision — Validierung via Pilot/Verbandsstatistik vor großer Vertriebsinvestition; (c) kein Version-Bump (reine Doku). Registriert: docs/README.md (produkt-Tabelle), docs/zielgruppen/Lesepfade.md (§Fach), docs/konventionen/IDs.md (OP→Doc), HANDOFF (§2 + §4 OP-COMPETE-1/OP-MARKET-1), docs/betrieb/Risikoregister.md (RISK-13 Wettbewerber kopiert Nische, RISK-14 Markt zu klein/SOM überschätzt), Produkt-und-Marketing.md (Querverweis-Block). Glossar (docs-site/src/glossar/glossar.mjs Single-Source → npm run glossar): vier neue fachliche Begriffe TAM/SAM/SOM · Beachhead · ARPA · Go-to-Market (50 → 54). Verifikation: alle 3 Mermaid-Diagramme via MCP validiert (valid:true: flowchart/flowchart/gantt); npm run glossar grün (54 Begriffe/4 Rubriken). Kein Code-/Solver-/Token-Change. True North: indirekt (Business-Entscheidungsgrundlage · „Dokumentation als Meisterwerk"). Doku: docs/produkt/Wettbewerbsanalyse.md (neu), docs/produkt/Markt-und-Markteintritt.md (neu), docs/produkt/Produkt-und-Marketing.md, docs/README.md, docs/zielgruppen/Lesepfade.md, docs/konventionen/IDs.md, docs/betrieb/Risikoregister.md, docs-site/src/glossar/glossar.mjs, docs/glossar/Glossar.md (generiert), HANDOFF, CHANGELOG, Timesheet (2026-06-28-competitive-analysis-market-entry).
  • Branch claude/op-register (PR folgt) — Doku: „OP- & Entscheidungs-Register" (navigierbarer Gesamt-Index) (Doku-only → kein Version-Bump). Nutzer: „eine explizite Seite mit den OP und weiteren Entscheidungspunkten — keine Duplikate, ggf. verlinken". Neu docs/konventionen/Register.md: ein Einstieg zu allen offenen Punkten (OP-*, thematisch gruppiert; Modul-Familien OP-R*-n als Sammelzeile) und allen Entscheidungen/Constraints (G·A·S·UC·E) — je ID · Kurz-Gloss · Link. Bewusst Duplikat-frei („Nicht-Duplikat-Vertrag"): Status/Detail bleibt HANDOFF.md §4, ID→Owning-Doc bleibt IDs.md, G/A/S/UC-Definitionen bleiben Lastenheft §2/§3/§9/§10, E-* in den Owning-Docs — das Register verlinkt nur. Quervernetzt: docs/README.md (Lesepfad „Architektur-Entscheidung nachschlagen" + konventionen-Tabelle) und docs/konventionen/IDs.md (Kopf-Hinweis) zeigen aufs Register; IDs.md bleibt die kuratierte Owning-Doc-Lookup (Arbeitsteilung, kein Voll-OP-Index-Duplikat). Entscheidung: Register = Navigations-Index, keine Status-/PR-Pflege (die bleibt HANDOFF §4/CHANGELOG); Modul-OP-Familien gruppiert statt ~50 Sub-IDs transkribiert (Drift-arm). Reine Doku, kein Code/Token/Schema. Verifikation: alle Doku-internen Links existieren (geprüft); check-doc-consistency.sh ohne neue Befunde. Doku: docs/konventionen/Register.md (neu), docs/README.md, docs/konventionen/IDs.md, CHANGELOG, Timesheet (2026-06-28-op-register).
  • Branch claude/klaerfaelle-workspace (PR folgt) — OP-UX-2 / U8: Klärfälle-Workspace (Störung-Achse: Sicht + Zähler) (Version 0.31.0 → 0.32.0 MINOR — neues Feature; Build auto, OP-PM-2). Auftrag (Nutzer): Folge aus U7 — die in U7 entwirrten zwei roten Warn-Achsen symmetrisch machen: die Termin-Achse hatte mit dem Konflikte-Workspace + Nav-Badge ein Zuhause, die Störung-Achse (Klärfall) nur Inline-Anzeigen. Gebaut (reiner Client-Pfad): neuer Workspace „Klärfälle" (client/src/app/leitstand/pages/klaerfaelle.component.ts; Cluster Steuerung, nach Konflikte; Signaturfarbe --tk-ws-klaerfaelle = Amber/Gold #f59e0b, Glyph , Route /klaerfaelle) — listet alle Aufträge mit aktivem klaerfall (svc.klaerfaelle()), dringlichkeits-sortiert (eskaliert zuerst, dann am längsten ungeklärt via klaerfall.seit); je Zeile Auftragsnummer · ★ · ⚠ eskaliert-Pille · Grund · „seit … · X offen"; Klick → geteiltes auftrag-detail-panel mit bestehendem „✓ Klärfall lösen" (keine eigene Lös-Logik). Service: klaerfaelle + klaerfaelleCount (computed) → Nav-Badge. Token --tk-ws-klaerfaelle in tokens.json (+ build.mjs-NAME-Map) → npm run tokenstokens.css. Entscheidung (Sign-off): Workspace-Signaturfarbe Amber/Gold (nicht rot) — rot bleibt der Termin-Achse (Konflikte) vorbehalten; die inline Klärfall-Pille bleibt rot. Damit haben beide Warn-Achsen je Liste + Badge (Symmetrie). Kein Server/Solver/Schema (Klärfall-Modell + Handler bestehen, OP-R3-1). Verifikation: ng build grün · No-Hex grün (Hex nur in tokens.json) · persistence:check grün · Token-Staleness grün (npm run tokens lief). Doku: docs/architektur/Operative-Durchgaengigkeit.md (OP-UX-2/U8 ✅), design/COMPONENTS.md+WORKSPACES.md+DESIGN_TOKENS.md, docs/konventionen/IDs.md (OP-UX-2-Zeile), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-klaerfaelle-workspace).
  • Branch claude/team-lucas-tiede (PR #253) — Team-Seite: Platzhalter „Mitarbeiter von Dominik" → „Lucas Tiede" (Docs-Site-only → kein Version-Bump). Nutzer: „‚Mitarbeiter von Dominik' durch ‚Lucas Tiede' ersetzen". In docs-site/src/pages/team.js die Platzhalter-Person konkretisiert: Name Lucas Tiede, Initialen LT (Avatar-Fallback), Foto-Pfad-Hinweis /img/team/lucas-tiede.jpg, To-do auf „Rolle & Titel schärfen" reduziert; den erledigten Listenpunkt „Namen des Mitarbeiters von Dominik ergänzen" aus den Team-To-dos entfernt. Reine Inhalts-/Doku-Änderung, kein Code/Token/Schema. Doku: docs-site/src/pages/team.js, CHANGELOG, Timesheet (2026-06-28-team-lucas-tiede).
  • Branch claude/warn-achsen-entwirren (PR #252, gemergt) — OP-UX-1 / U7: Zwei rote Warnsysteme entwirrt (Störung-Achse ⚠ vs. Termin-Achse) (Version 0.30.0 → 0.31.0 MINOR — UX-Optimierung; Build auto, OP-PM-2). Auftrag (Nutzer): die zwei roten Warnsysteme entwirren (Backlog aus dem Flow-Audit). Befund: Auf der Werkstatt-Tafel kollidierten zwei rote Signale gleicher Optik (--tk-red/danger-bg) für Verschiedenes — eine Zeile konnte −3T über (rote Reserve-Pille) + ⚡ überfällig (rotes Flag) + ⚠ Klärfall (rotes Flag) zeigen: drei rote Pillen, zwei davon für dieselbe Termin-Bedingung. Gebaut (tafel.component.ts): zwei klar getrennte Achsen — (1) Störung-Achse = Klärfall ⚠ (rot), das einzige rote Flag (Prozess-Störung, Mensch muss eingreifen); (2) Termin-Achse = Reserve-Pille mit Schweregrad statt zweitem rotem Icon: ≥0 grün · −1…−3T amber (Achtung) · ≤−4T rot (Warnung) — die 4-Tage-Schwelle spiegelt die Konflikte-Triage (conflicts.component) → eine Termin-Logik über beide Sichten. Das redundante ⚡ überfällig-Flag auf der Tafel entfällt (die Reserve-Pille trägt die Termin-Achse, quantifiziert + mit Tooltip). Effekt: Rot auf einer Zeile heißt jetzt Klärfall (Eingriff) oder ernster Verzug (≤−4T) — nicht mehr jeder kleine Slip. Entscheidungen: (a) Termin-Achse quantifiziert (Reserve-Pille) statt generisches rotes Icon; (b) Schweregrad-Farbe (Amber=Achtung/Rot=Warnung) statt binär, an die Konflikte-Schwelle (4 T) angeglichen; (c) reserviert für die Störung-Achse. Folge-Idee (offen): symmetrische Klärfall-Sicht/-Zähler (Störung-Achse) analog zum Konflikte-Workspace — eigener OP, falls gewünscht. Verifikation: ng build grün (Template-Typecheck) · No-Hex grün (nur Tokens). Reiner Client-Pfad, kein Server-/Solver-/Schema-Change. Doku: docs/architektur/Operative-Durchgaengigkeit.md (U7 ✅ + Backlog-Zeile), design/COMPONENTS.md („Warn-Achsen"-Pattern), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-warn-achsen-entwirren).
  • Branch claude/annahme-zuletzt-update (PR #251, gemergt) — OP-UX-1 / U5: „Zuletzt angenommen"-Panel + Kunde/CRM nachtragen (Version 0.29.0 → 0.30.0 MINOR — neues Feature; Build auto, OP-PM-2). Auftrag (Nutzer): rechts im Annahme-Schirm die zuletzt angenommenen Fahrzeuge zeigen — „falls man noch etwas nachtragen möchte". Gebaut: (Server) neue Message auftrag.update ({ id, kunde: {name?, crmLink?} }) — ändert nur die R5-v1-Kunde-Felder eines bestehenden Auftrags (Name bleibt Pflicht), schreibt ein Audit-Event auftrag.aktualisiert (OP-AUDIT-1, Actor aus der per-Connection verifizierten Access-E-Mail) + Chronik-Eintrag und broadcastet; kein Leistung-/Termine-Edit. Neuer per-Connection-connEmail-Actor-Map (alle Verbindungen, nicht nur Kosten-Admins). (Client) Annahme-Workspace jetzt zweispaltig (grid lg:grid-cols-[minmax(0,1fr)_340px], stapelt mobil): rechts „Zuletzt angenommen" mit den letzten ~6 aktiven Aufträgen (neueste zuerst, sortiert über die Anlage-Reihenfolge aus id AU-<seq> — kein createdAt vorhanden); je Zeile Auftragsnummer · Status · Kunde, Inline-„✎ nachtragen" für Kunde-Name + CRM-Link → updateAuftragKunde + Toast; CRM-Link klickbar. Entscheidungen (Sign-off): (a) Kunde/CRM nachbearbeitbar (statt nur Schnellzugriff) — neue auftrag.update-Aktion, bewusst eng auf die R5-v1-Felder begrenzt; (b) Recency über AU-<seq> (kein neues Timestamp-Feld). Verifikation: Server tsc + operativ grün · ng build grün · No-Hex + persistence:check grün. ➡ OP-UX-1 inkl. aller Annahme-Slices komplett (U1–U6). Reiner Server+Client-Pfad, kein Solver-Redeploy, kein neues Schema (Kunde-Feld bestand). Doku: docs/architektur/Operative-Durchgaengigkeit.md (U5 ✅), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-annahme-zuletzt-update).
  • Branch claude/annahme-reopt (PR #250, gemergt) — OP-UX-1 / U6: Reopt bei Annahme (globale CP-SAT-Optimierung nach Anlage) (Version 0.28.0 → 0.29.0 MINOR — neues Verhalten; Build auto, OP-PM-2). Auftrag (Nutzer-Sign-off): die Annahme soll zusätzlich eine globale Reopt anstoßen, damit der neue Auftrag sofort optimal unter allen eingeplant wird. Gebaut: auftrag.create ist jetzt ein REOPT_EVENT — nach erfolgreichem Anlegen läuft (wie bei liefern/starten/teilschritt.aktion/verzoegerung) automatisch ein globaler CP-SAT-Reopt (aktualisiereVorschlaegeAuto, TS-Fallback), der den neuen Auftrag optimal unter allen einplant und das Ergebnis als Idee/Vorschlag in den Feed schiebt (Propose-not-execute, §7 — kein stilles Umplanen). Der Dry-Run auftrag.pruefen löst keinen Reopt aus (reine Vorschau). Damit ist die Solver-Frage vollständig beantwortet: TS-Machbarkeit sofort bei der Prüfung, CP-SAT-Global-Reopt nach Anlage (als Vorschlag). Entscheidung: exakt das bestehende Event-Reopt-Muster wiederverwendet (kein neuer Solver-Pfad, kein Auto-Apply — konsistent mit „Propose-not-execute"). Verifikation: Server tsc + operativ grün. Einzeiler im Server-Pfad (REOPT_EVENTS += auftrag.create), kein Solver-Redeploy, kein Schema-Change. Doku: docs/architektur/Operative-Durchgaengigkeit.md (U6 ✅), HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-annahme-reopt).
  • Branch claude/annahme-preis-vorschau (PR #249, gemergt) — OP-UX-1 / U4: Annahme-Vorschau (Preis & Reserve) + „Wirklich anlegen?"-Bestätigung (Version 0.27.0 → 0.28.0 MINOR — neues Feature; Build auto, OP-PM-2). Auftrag (Nutzer): vor dem Anlegen erst Preis + Reserve zeigen und „Wirklich anlegen?" abfragen (kostenpflichtiger Auftrag); plus die Frage „läuft bei der Prüfung nicht auch der Solver?". Solver-Antwort: die Annahme-Prüfung läuft den TS-Scheduler (angebot()/scheduleLeistung, synchron im DO) — schnelle Einzelauftrags-Machbarkeit; der CP-SAT (SOLVER_URL) macht die globale Mehrauftrags-Optimierung (separat, event-getriggert; eine Reopt-bei-Annahme folgt als Slice U6). Gebaut: (1) Preismodell (OP-R7-6 erster Schnitt): Leistung.grundpreisCent (Seed: Basic 1.400 € < Premium 3.200 € < Super-Premium 4.800 €; optional → keine Migration), pure Summen-Funktion auftragspreisCent in server/src/operativ/preis.ts (+ Self-Test test:preis + CI-Step), Preis-Snapshot Auftrag.preisCent bei Anlage; Picker zeigt „ab X €". Güteklasse-/Anspruch-Zuschläge bleiben OP-R7-6-Folge. (2) Vorschau-Dry-Run: neue Message auftrag.pruefen + ServerMsg auftrag.pruefen.result (per-Connection, Muster wie U3b) — läuft angebot(), leitet Machbarkeit + Reserve (floor((abholtermin−earliest.completion)/1440)) + Preis ab, legt nichts an. (3) Annahme-UI zweistufig: „Prüfen & anlegen" → Spinner „prüft …" → bei Machbarkeit Bestätigungs-Dialog (Kunde · Leistung · Termine · Reserve grün/rot · Preis · ggf. Termin-Warnung) mit „Abbrechen" / „✓ Wirklich anlegen (kostenpflichtig)" → erst Bestätigung ruft auftrag.create; nicht machbar → Grund inline (kein Dialog). Entscheidungen (Sign-off): (a) einfaches Preismodell jetzt (Grundpreis je Leistung) statt Preis vertagen; (b) Geld als Cent-Integer (wie infraKosten.betragCent); (c) Reserve/Preis über einen echten Dry-Run statt optimistischer Anzeige. Verifikation: Server tsc + test:preis + operativ + test:running-process + spike grün · ng build grün · No-Hex + persistence:check grün · ci.yml strict-YAML (keine Dup-Keys). Reiner Server+Client-Pfad, kein Solver-Redeploy. Doku: docs/architektur/Operative-Durchgaengigkeit.md (U4 ✅), HANDOFF (§4, OP-R7-6-Notiz), CHANGELOG, Timesheet (2026-06-28-annahme-preis-vorschau).
  • Branch claude/optimizer-docs-rationale-ypqmcl (PR folgt) — Doku: Problematik der Optimierung + Begründung der mehreren Optimierer in docs/fachlich/solver.md (reine Doku → kein Version-/Build-Bump). Nutzer-Auftrag: „beschreibe in der Doku die Problematik bei der Optimierung, auch warum es die unterschiedlichen Optimierer gibt". Gebaut: zwei vorangestellte, pyramidale (Minto — Kernaussage zuerst) Abschnitte: §1 Die Problematik: Warum Taktung schwer ist — benennt das Problem als NP-schwer (verwandt mit Job-Shop-Scheduling) mit vier Treibern: (a) kombinatorische Explosion (Reihenfolge N! + voller Entscheidungsraum Startzeit/Bucht/Mitarbeiter), (b) widersprüchliche Ziele (§6.2: Durchlaufzeit ↔ Makespan ↔ Wechsel G-2 ↔ Lücken G-3 → bewusste lexikografische Reihenfolge nötig), (c) gekoppelte harte Constraints (§6.1: Skill, Bucht-No-Overlap+Cool-down, Abhängigkeiten, Standzeit, getypte Parkplätze), (d) Dynamik + Worker-Laufzeit (harte Reservierungen, Eilaufträge, live; CF Worker/DO kann OR-Tools nativ nicht ausführen). §2 Warum es mehrere Optimierer gibt — das Konflikt-Dreieck Optimalität × Antwortzeit × Worker-Lauffähigkeit lässt sich nicht gleichzeitig maximieren → gestaffelte Kaskade mit Fallback (Greedy-Decoder → TS-Decoder-Optimierer → CP-SAT-Service), mit Vergleichstabelle (Code/Freiheitsgrade/Optimalität/Tempo/Worker/Rolle), Dispatch-Mermaid (Laufzeit-Auswahl im Leitstand) und expliziter „warum nicht nur einer?"-Begründung (graceful degradation). Entscheidung: bestehende Lösungs-Beschreibung beibehalten, aber die Problematik & Rationale pyramidal voranstellen (statt nur „Ansatz") — die Folgeabschnitte (Ansatz/Zielfunktion/Demo/CP-SAT/Leitstand) wurden 1→3 … 5→7 umnummeriert und mit Querverweisen verzahnt. Verifikation: neues Mermaid via MCP validiert (valid:true, flowchart); check-doc-consistency.sh zeigt nur Vorbestands-Timesheet-Dubletten (union-Merge), nichts Neues. Kein Code-/Solver-/Token-Change. True North: indirekt (Selbsterklärbarkeit · „Dokumentation als Meisterwerk"). Doku: docs/fachlich/solver.md, CHANGELOG, Timesheet (2026-06-28-optimizer-docs-rationale).
  • Branch claude/glossary-classification-filtering-vpb0ub (PR folgt) — OP-DOCS-10 Slice 2: Glossar-Klassifikation (Art × Ebene) + interaktiver Filter; Lesepfade/Glossar/Sprechblasen auf der Startseite; Sidebar-Rubrik umbenannt (Doku-Site-only → kein Version-/Build-Bump, Präzedenz Slice 1/#205/#206). Drei Nutzer-Wünsche: (1) Glossar-Begriffe nach technisch/fachlich klassifizieren und je Art nach Grundprinzip vs. erweiterter Liste, jeweils sinnvoll filterbar („um sich einen Eindruck zu verschaffen"); (2) Lesepfade nach Zielgruppe auf die Doku-Startseite + dort Mouse-over und Glossar erwähnen; (3) Sidebar-Rubrik „Betrieb · Compliance · Governance" → „Governance · Compliance". Gebaut — selbe Single-Source (docs-site/src/glossar/glossar.mjs): zwei neue Pflichtfelder je Eintrag art (fachlich|technisch) + ebene (grund|erweitert) + Label-Maps ART/EBENE; alle 50 Begriffe klassifiziert (Fachlich 20 = 7 Grund/13 Erw · Technisch 30 = 6 Grund/24 Erw). Generator scripts/gen-glossar.mjs gruppiert in vier Rubriken (stabile Anchor #kat-fachlich-grund u. a., Begriffe als h3 + Badges 🔧/💻 · ⭐/➕, Erklär-Sektion + Anzahl-Matrix) → die Glossar.md liest sich schon statisch (GitHub) als Filter/Eindruck. Interaktiv auf /docs/glossar/: neues Client-Modul src/clientModules/glossarFilter.js (registriert in docusaurus.config.js, Styles in src/css/custom.css, kein Hex → Infima-Variablen) baut eine Filter-Leiste — Chips Art × Ebene + Volltext-Suche + Trefferzähler; blendet Einträge/Rubriken datengetrieben (importiert GLOSSAR) per Heading-#id ein/aus; ohne JS bleibt die Seite voll lesbar. Startseite src/pages/index.js: Button „Lesepfade nach Zielgruppe" + Absatz, der die vier Zielgruppen-Pfade nennt und auf Mouse-over/Klick-Sprechblasen + Glossar (filterbar) hinweist. Rubrik-Umbenennung in allen kanonischen Quellen (docs/betrieb/_category_.json Label+Title, docs/README.md, docs/betrieb/meetings/README.md). Entscheidungen: (a) Klassifikation als zwei orthogonale Achsen (Art × Ebene) statt flacher Liste; (b) Filter datengetrieben aus der Single-Source (keine DOM-Heuristik); (c) kein App-Bump (Doku-Site-only). Verifikation: npm run build (Docusaurus) grün; Playwright gegen den Build: Leiste vorhanden, „Technisch" → 30, „Technisch+Grundprinzip" → 6 (nur kat-technisch-grund sichtbar), Suche „makespan" → 4; Startseite zeigt Lesepfade/Mouse-over/Glossar; Label „Governance · Compliance" im Build, alte Bezeichnung nirgends mehr. Kein Code-/Solver-Change. Doku: docs-site/src/glossar/glossar.mjs, docs-site/scripts/gen-glossar.mjs, docs/glossar/Glossar.md (generiert), docs-site/src/clientModules/glossarFilter.js, docs-site/docusaurus.config.js, docs-site/src/css/custom.css, docs-site/src/pages/index.js, docs/betrieb/_category_.json, docs/README.md, docs/betrieb/meetings/README.md, CLAUDE.md, HANDOFF (§4), CHANGELOG, Timesheet (2026-06-28-glossary-classification-filtering). True North: indirekt (Selbsterklärbarkeit/Doku als Meisterwerk).
  • Branch claude/op-ux-empty-states (PR folgt) — Einheitliche Leere-Zustände (app-empty-state) (Version 0.26.0 → 0.27.0 MINOR — neue wiederverwendbare Komponente + UI-Konsistenz; Build auto, OP-PM-2). Auftrag: „inkonsistente Leere-Zustände vereinheitlichen" (Flow-Audit-Backlog, OP-UX-1). Problem: Inventur fand 25 „Keine …"-Platzhalter quer durch die Workspaces — alle inline/ad-hoc, nur 2 reich, 20 dünn; manche ließen den Nutzer in einer Sackgasse. Gebaut: eine Standalone-Komponente client/src/app/leitstand/empty-state.component.ts (Signal-Inputs variant/glyph/glyphColor/title/sub/dashed, optionaler CTA-Slot via <ng-content>) mit 3 Variantencard (Voll-Raum, dashed=„wartet auf Daten"), bare (in bestehender Karte, ohne Rahmen), inline (verschachtelte Unterliste, eine gedämpfte Zeile). Alle Fundstellen migriert (~12 Dateien: tafel, meine-arbeit, orders, conflicts, quality, recommendations, overview, annahme, processes, administration, staff, insights-panel). CTAs ergänzt, wo der Flow es trägt (Nutzer-Entscheidung): leere Tafel/Aufträge → „+ Auftrag annehmen" (/annahme), Überblick „keine Produktion" → /annahme, Vorschläge leer → „Zur Planung" (/planning), Annahme ohne Leistung → „Zu Prozesse" (/processes); Erfolgs-/Auswahl-Prompts (keine Konflikte/Endkontrollen, „Auftrag wählen") bleiben CTA-frei. Entscheidungen (Sign-off): (a) Shared-Komponente + alle migrieren (statt nur die dünnen primären aufwerten); (b) CTAs hinzufügen, wo es den Flow trägt. Glyph-Farbe = Workspace-Signatur, wo es Identität stärkt; Erfolg = var(--tk-green). Nur --tk-*-Tokens (No-Hex). Verifikation: ng build grün · No-Hex-Gate grün. Reiner Client + Doku, keine Token-/Schema-/Server-/Solver-Änderung. Doku: design/COMPONENTS.md (## Empty state), HANDOFF (§2), CHANGELOG, Timesheet (2026-06-28-op-ux-empty-states).
  • #245 (gemergt) — OP-UX-1 / U3b: Machbarkeits-Rückmeldung der Annahme (Version 0.25.0 → 0.26.0 MINOR — neues Feature; Build auto, OP-PM-2). Auftrag: „Infeasibility-Rückmeldung" (Folge-Punkt aus U3). Problem: auftrag.create war fire-and-forget — bei nicht machbarem Plan legte der Server still nichts an, der Anwender bekam kein Feedback. Gebaut: (Server) auftrag.create antwortet jetzt der anlegenden Verbindung über eine neue ServerMsg-Variante auftrag.create.result (conn.send in onMessage): abgelehnt (ok:false) mit konkretem Grund — strukturell nicht planbar → ScheduleResult.reason aus dem fehlgeschlagenen Schritt (z. B. kein qualifizierter Mitarbeiter/keine passende Bucht für die Güteklasse), plus Validierung „Abholung muss nach Anlieferung liegen" / „ungültige Zeitangaben"; angenommen (ok:true) mit Auftragsnummer + optionaler Termin-Warnung, wenn der Auftrag planbar ist, aber frühestens nach der Wunsch-Abholung fertig wird (earliest.abholbereit > abholtermin, formatIso). (Client) neues LeitstandService.auftragCreateResult-Signal (gesetzt aus dem Socket-Handler, seq macht jede Antwort eindeutig); der Annahme-Workspace zeigt jetzt einen Spinner („prüft …", Button deaktiviert), bei Erfolg Toast + Formular-Reset (+ ggf. Termin-Warn-Toast), bei Ablehnung den Grund inline (rot) + Toast, Formular bleibt zum Korrigieren; 8-s-Sicherheitsnetz gegen hängenden Spinner (z. B. Verbindungsabriss). Entscheidungen: (a) per-Connection-Antwort (kein Broadcast — nur der Anleger sieht das Ergebnis), Muster wie die per-Connection State-Sends; (b) reason aus dem Scheduler durchreichen statt generischer Text (konkret = handlungsleitend); (c) Deadline-Miss bleibt nicht-blockierend (Auftrag wird angenommen + Warnung), nur strukturelle Infeasibility lehnt ab — verhaltenskonsistent zu vorher. Verifikation: Server tsc + operativ + test:running-process grün · ng build grün · No-Hex-Gate grün. Reiner Server+Client-Pfad, kein Solver-Redeploy, kein neues Schema. Doku: docs/architektur/Operative-Durchgaengigkeit.md (U3b ✅), HANDOFF (OP-UX-1 §4), CHANGELOG, Timesheet (2026-06-28-op-ux-u3b-annahme-feedback).
  • #244 (gemergt) — OP-UX-1 / U3: Annahme „Auto kommt → Auftrag anlegen" → OP-UX-1 vollständig (Version 0.24.0 → 0.25.0 MINOR — neues Feature; Build auto, OP-PM-2). Auftrag: „u3". Entscheidung vorab (Nutzer-Sign-off 06-28): E-UX-3 = eigener Annahme-Workspace (statt „+ Auftrag"-Button). Gebaut: (1) Workspace „Annahme" (client/src/app/leitstand/pages/annahme.component.ts, Route /annahme, erster Eintrag im Operativ-Cluster = Start des Flows, Signaturfarbe --tk-ws-annahme [neuer Token], Glyph ⊕): Formular (Single-Modal-Geist, S-1) Kunde (Name + CRM-Link) · Leistung (Picker aus aktivem Prozess-Katalog prozesse()) · Güteklasse + Anspruch (Segmente) · Anlieferung + Wunsch-Abholung (datetime-local, UTC) · Termin-Härte → bestehender auftrag.create-Handler (prüft Machbarkeit im Angebotsmodus, legt nur machbare Aufträge an); Eingabe-Validierung clientseitig, Erfolg-Toast, Formular-Reset. Ersetzt die Demo-Buttons als realer Eingang. (2) Kunde v1 neu im Datenmodell (R5-v1 — war in §4.9 spezifiziert, aber nie gebaut): Auftrag.kunde = {name, crmLink?} + AuftragMeta.kunde, in materialisiereAuftrag gesetzt, im auftrag.create-Handler sanitisiert (Name-Pflicht, sonst weggelassen), in toAuftragDTO + Client-AuftragDTO exponiert. Optionales Feld → keine Migration. Entscheidungen: (a) eigener Workspace (E-UX-3); (b) Kunde = nur Name + CRM-Link am Auftrag (kein eigenes Kundenobjekt, Voll-Modell = FR-1); (c) Machbarkeits-/Infeasibility-Rückmeldung bewusst als Folge-Punkt vermerkt (heute kein Feedback bei nicht machbarem Plan — braucht Request/Response-Kanal). ➡ OP-UX-1 VOLLSTÄNDIG (U1 Tafel · U2 Meine Arbeit · U3 Annahme gebaut; E-UX-1…3 entschieden) — der Flow ist von der Vordertür bis zur Abholung durchgängig. Verifikation: Server tsc + operativ + replan + test:teilplan + test:running-process + test:archiv grün · ng build grün · No-Hex-Gate grün · tokens.css neu generiert (nicht stale). Reiner Server+Client-Pfad, kein Solver-Redeploy. Doku: docs/architektur/Operative-Durchgaengigkeit.md (U3 ✅ + E-UX-3 ✅), design/DESIGN_TOKENS.md (Workspace-Farben tafel/werker/annahme nachgezogen), HANDOFF (§2+§4), CHANGELOG, Timesheet (2026-06-28-op-ux-u3-annahme).
  • #243 (gemergt) — OP-UX-1 / U2: Werker-Sicht „Meine Arbeit" (Version 0.23.0 → 0.24.0 MINOR — neues Feature; Build auto, OP-PM-2). Auftrag: „dann U2". Entscheidungen vorab (Nutzer-Sign-off 06-28): E-UX-2 = eigener Workspace „Meine Arbeit" (statt Filter-Modus der Tafel) + Mitarbeiter-Picker (Schichtterminal) als Identität für den ersten Slice (echtes Per-MA-QR/Login = R1-Future). Gebaut: neuer touch-/tablet-tauglicher Workspace (client/src/app/leitstand/pages/meine-arbeit.component.ts, Route /meine-arbeit, Nav-Cluster Operativ, Signaturfarbe --tk-ws-werker [neuer Token in tokens.jsonnpm run tokens], Glyph ⬣): Schichtterminal-Picker (aktive Mitarbeiter, Offen-Badge je Person) → darunter nur seine offenen/laufenden Schritte über alle aktiven Aufträge (produktiv aus mitarbeiterIds, zusätzlich als 🎓 Helfer aus helferIds), laufend zuerst sortiert; je Schritt Auftrags-Kontext (Nr./★/Bucht/📍 Standort) + große Aktionen ⏸ Pause / ▶ Weiter / ✓ Fertig über teilschrittAktion. Doku-/Foto-Pflicht (OP-R4-3) ohne Duplikat: braucht „Fertig" ein Gate (Pflicht-Kommentar/-Fotos), führt der Klick ins geteilte Detail-Panel (dort lebt Gate + Foto-Upload); sonst direkt erledigt; Inline-Hinweis nennt das Fehlende. Reine Projektion des Live-States — kein neues Schema, keine Server-/Solver-Änderung (Aktionen über bestehende Handler). Macht aus dem Leitstand erstmals eine Hand-Sicht. Offen: U3 Annahme-Maske (E-UX-3). Verifikation: ng build grün · No-Hex-Gate grün · tokens.css neu generiert (nicht stale) · Server tsc grün. Doku: docs/architektur/Operative-Durchgaengigkeit.md (U2 ✅ + E-UX-2 ✅), HANDOFF (§2+§4), CHANGELOG, Timesheet (2026-06-28-op-ux-u2-meine-arbeit).

2026-06-27

  • #242 (gemergt) — OP-UX-1 / U1: Werkstatt-Tafel — durchgängige Auftragszeile (Version 0.22.0 → 0.23.0 MINOR — neues Feature; Build auto, OP-PM-2). Auftrag: Flow-Audit „ein Auto kommt, was passiert dann? Ist die UI/UX ein echtes Meisterwerk?" → Befund: Cockpit nahe am Meisterwerk, aber Alltags-Fakten über drei Seiten (Aufträge · Gantt · Belegung) verstreut, keine Werker-Sicht, keine echte Annahme-Maske → als OP-UX-1 aufgenommen + Design-Doc, Slice U1 (Dashboard) gebaut. Gebaut: neuer Workspace „Tafel" (client/src/app/leitstand/pages/tafel.component.ts, Route /tafel, Nav-Cluster Überblick, Signaturfarbe --tk-ws-tafel [neuer Token in tokens.jsonnpm run tokens], Glyph ▤): je aktivem Auftrag eine Zeile mit Auftragsnummer/★ · Status- + Phase-Pill · aktuellem Schritt (in_arbeit→pausiert→nächster geplanter) mit Mitarbeiter-Namen + Bucht · 📍 Standort · Fortschrittbalken (erledigt/gesamt) · Reserve · Warn-Flags (⚠ Klärfall · ⚡ überfällig · ⚠ Zuweisung nötig · ⏱ verzögert); operativ dringlichkeits-sortiert; Klick öffnet das geteilte Detail-Panel. Reine Projektion des Live-States (AuftragDTO+RessourcenDTO+employees) — Derived-State (S-2), kein neues Schema, keine Server-/Solver-Änderung. Beantwortet True-North-Frage 2 (Wo stehen die Fahrzeuge — physisch und in Bearbeitung) auf einen Blick. Entscheidung E-UX-1 ✅ = U1 als eigener Workspace (statt Umbau Aufträge/Überblick) — hält bestehende Seiten unverändert, gibt der Durchgängigkeit einen klaren Ort. Offen (dokumentiert): U2 Werker-Sicht (E-UX-2), U3 Annahme-Maske (E-UX-3). Verifikation: ng build grün · No-Hex-Gate grün · tokens.css aus tokens.json neu generiert (nicht stale) · doc-consistency nur Vorbestands-Timesheet-Dubletten. Doku: docs/architektur/Operative-Durchgaengigkeit.md (neu), docs/README.md, docs/konventionen/IDs.md, HANDOFF (§2+§4), CHANGELOG, Timesheet (2026-06-27-op-ux-1-tafel).
  • Branch claude/e-crud-4-decision (PR folgt) — OP-CRUD-1: E-CRUD-4 entschieden → OP-CRUD-1 abgeschlossen (reine Doku → kein Version-/Build-Bump). Nutzer-Sign-off (06-27): E-CRUD-4 = (A) Hart-Delete für Infra-Kosten/Foto beibehalten — die einzigen referenzfreien, nicht-historischen Entitäten (Klasse C) bleiben physisch löschbar (infraKosten.entfernen/foto.entfernen), aber mit Audit-Event (OP-AUDIT-1). Begründung: kein Schutzgewinn durch ein zweites Soft-Delete-Modell (keine verwaisten Referenzen; Audit hält den Vorgang fest); bei Fotos spricht DSGVO/„Recht auf Vergessen" sogar für echtes Löschen statt dauerhaftes Liegenlassen im R2-Speicher. ➡ OP-CRUD-1 ist damit vollständig entschieden UND umgesetzt (alle Slices C1–C4 gebaut, alle E-CRUD-1…4 entschieden): jede Entität hat ein bewusstes Lösch-/Lebenszyklus-Verhalten, der Prozess-Katalog ist voll editierbar, und die Running-process-Schutz-Invariante ist als blockierender CI-Gate gesichert. Aktualisiert: docs/architektur/Entitaeten-Lebenszyklus.md (§7), HANDOFF (OP-CRUD-1 abgeschlossen). Kein Code. Doku: architektur/Entitaeten-Lebenszyklus.md, HANDOFF, CHANGELOG, Timesheet (2026-06-28-e-crud-4-decision).
  • #240OP-CRUD-1 / C3: Prozess-Katalog Create (neue Teilschritte + Leistungen) (Version 0.21.0 → 0.22.0 MINOR — neues Feature; Build auto, OP-PM-2). Auftrag: „weiter" → C3 (letzter Slice). Gebaut: (1) pure, testbare erstelleTeilschritt/erstelleLeistung in server/src/operativ/prozess.ts (sinnvolle Defaults: Teilschritt 30 Min [G-3-konform], 1 Person, Phase produktion; Leistung aktiv + leerer Prozess) + Self-Test test:prozess (Anlegen, Defaults, leerer Name → No-op, neue Leistung sofort komponierbar). (2) Handler teilschritt.create/leistung.create (admin-gegated; Skill/Kategorie aus msg falls gültig, sonst erste; Audit teilschritt.erstellt/leistung.erstellt); ID-Generatoren neueTeilschrittId/neueLeistungId. (3) Client (processes.component): „+ Neuer Teilschritt"/„+ Neue Leistung"-Button je Tab (prompt-basiert). Damit ist der Prozess-Katalog voll editierbar (Create neu; Update bestand; Delete = Teilschritt-Archiv [C2] / Leistung-status-Soft). Entscheidungen: (a) Create-Logik pure in prozess.ts (CI-getestet) statt im DO; (b) neue Leistung mit leerem Prozess (Schritte folgen via setProzess) — Running-process-Sicherheit durch E-CRUD-2 + C4-Gate bereits abgedeckt; (c) kein Hard-Delete ergänzt (Delete bleibt Soft/Archiv, OP-COMPLIANCE-1). ➡ OP-CRUD-1 bis auf E-CRUD-4 vollständig. Verifikation: typecheck + test:prozess + test:archiv + test:running-process + Smokes + ng build + No-Hex + persistence:check grün. Reiner Server+Client-Pfad, kein Solver-Redeploy. Doku: docs/architektur/Entitaeten-Lebenszyklus.md (C3 ✅ + §1-Matrix), HANDOFF (OP-CRUD-1), CHANGELOG, Timesheet (2026-06-27-op-crud-c3-katalog-create).
  • #239OP-CRUD-1 / C4: Running-process-Testmatrix (blockierender CI-Gate) (Version 0.20.0 → 0.21.0 MINOR — neue Sicherungs-/Test-Infrastruktur; Build auto, OP-PM-2). Auftrag: „weiter" → C4 (entschiedene Reihenfolge C2→C4→C3). Gebaut: Self-Test test:running-process (server/src/operativ/running-process-demo.ts) als blockierender Server-CI-Step (vor solve) — beweist die E-CRUD-2/Running-process-Schutz-Invariante über die pure buildProblem-Fläche: (1) Mitarbeiter archiviert → nurAktive nimmt ihn aus dem Solver-Input, buildProblem läuft ohne Crash weiter und plant dieselben Aufträge (genau der Archivierte fehlt im Pool, Auftrags-Schritte unverändert); (2) Teilschritt-Vorlage archiviert (bleibt im Input — schedulerInput filtert Vorlagen nicht) → die Aufträge behalten alle Schritte (Resolve/Materialisierung schützt Laufendes, kein verlorener Prozessschritt). Entscheidungen: (a) Test gegen die pure buildProblem-Funktion in src/ (der DO ist nicht leicht instanziierbar) — deckt die korrektheitskritischen Eigenschaften maschinell ab; (b) als blockierender Gate verdrahtet (E-CRUD-3), damit künftige Slices (C3 Katalog-Create/Delete) die Schutz-Invariante nicht still brechen; (c) ci.yml strikt auf doppelte YAML-Keys geprüft (Lehre aus D5-4). Verifikation: test:running-process grün; typecheck + Smokes grün; ci.yml strict-YAML ok (keine Dup-Keys). Kein App-Laufzeit-/Verhaltens-Change (nur Test + CI), kein Solver-Redeploy. Doku: docs/architektur/Entitaeten-Lebenszyklus.md (C4 ✅), HANDOFF (OP-CRUD-1), CHANGELOG, Timesheet (2026-06-27-op-crud-c4-running-process-tests).
  • #238OP-CRUD-1 / C2: Soft-Delete vereinheitlichen — Teilschritt-Archivierung (Version 0.19.0 → 0.20.0 MINOR — neues Feature; Build auto, OP-PM-2). Auftrag: „weiter" → C2 (entschiedene Reihenfolge C2→C4→C3). Befund bei der Umsetzung: Skill (aktiv, create reaktiviert) und Leistung (status=inaktiv, UI dimmt) haben bereits funktionierenden Soft-Delete — ein zweites archiviert-Flag wäre redundant; die einzige echte Lücke war Teilschritt (gar kein Flag). Gebaut: (1) Teilschritt extends Archivierbar (generisches Flag aus C1) + Handler teilschritt.archivieren/reaktivieren (admin-gegated; Audit teilschritt.archiviert/.reaktiviert via d1Audit). (2) Running-process-Schutz (E-CRUD-2): archivierte Vorlagen werden NUR am Angebots-Punkt gefiltert (Add-Dropdown der Prozess-Komposition, angeboteneTeilschritte); buildProzessKatalog resolved sie weiter → bestehende Leistungs-Prozesse + materialisierte Auftrags-Instanzen bleiben intakt (ProzessSchrittDTO.archiviert). (3) Client (processes.component): Archivieren/Reaktivieren-Button im Teilschritt-Katalog + dimmt archivierte Vorlagen. Entscheidungen: (a) kein redundantes Flag für Skill/Leistung — ihr fachliches aktiv/status IST der Soft-Delete (Doku §1-Matrix nachgezogen); (b) Filterung nur am Angebots-Punkt, nicht im Resolve/Lookup (Running-process-Safety); (c) MINOR (neues Feature, verhaltensgleich für Bestehendes). ➡ Damit haben alle Klasse-A-Entitäten „archiv statt löschen". Verifikation: typecheck + test:archiv + test:prozess + Regression-Smokes (operativ/replan/solve/teilplan) + ng build + No-Hex + persistence:check grün. Reiner Server+Client-Pfad, kein Solver-Redeploy. Doku: docs/architektur/Entitaeten-Lebenszyklus.md (C2 ✅ + §1-Matrix), HANDOFF (OP-CRUD-1), CHANGELOG, Timesheet (2026-06-27-op-crud-c2-soft-delete).
  • #237OP-CRUD-1: E-CRUD-3 entschieden (Slice-Reihenfolge + Running-process-Testmatrix als Gate) (reine Doku → kein Version-/Build-Bump). Nutzer-Sign-off (06-27): Reihenfolge nach C1 ✅ = C2 → C4 → C3 (erst das generische archiviert-Flag über die restlichen Klasse-A-Entitäten — Skill/Leistung/Teilschritt — vereinheitlichen, dann die Running-process-Testmatrix als blockierenden CI-Gate festzurren, zuletzt Prozess-Katalog Create/Delete). Die Testmatrix („archiviere/ändere Stammdatum während laufendem Prozess → läuft/pausiert sauber, kein Crash/Datenverlust") läuft als blockierender Server-CI-Job (wie test:archiv). Begründung: Konsistenz vor neuer Fläche; die Schutz-Invariante ist billige Dauer-Versicherung. Aktualisiert: docs/architektur/Entitaeten-Lebenszyklus.md (§5/§6/§7), HANDOFF (OP-CRUD-1). Kein Code. Doku: architektur/Entitaeten-Lebenszyklus.md, HANDOFF, CHANGELOG, Timesheet (2026-06-27-e-crud-3-decision).
  • #236OP-CRUD-1 / C1: Mitarbeiter-Archivierung (Archiv statt Hard-Delete) (Version 0.18.0 → 0.19.0 MINOR — neues Feature; Build auto-gestempelt, OP-PM-2). Auftrag: „Op-crud slice c1" (erste echte CRUD-Lücke aus docs/architektur/Entitaeten-Lebenszyklus.md). Gebaut: (1) generisches Archiv-Flag (E-CRUD-1) in server/src/model/types.ts: Archivierbar-Interface (archiviert?/archiviertAm?) + istArchiviert/nurAktive; Mitarbeiter extends Archivierbar. (2) Handler employee.archivieren/employee.reaktivieren (admin-gegated wie übrige Stammdaten; Audit-Event mitarbeiter.archiviert/.reaktiviert via d1Audit, OP-AUDIT-1; Ops-Log ohne PII). (3) Aus aktiver Verwendung genommen via nurAktive an allen Workforce-Punkten: Solver schedulerInput, mitarbeiterGesamt, Ausbildungs-/Niveau-Vorschläge, Engpass-Hinweis, Ausfall-/Ressourcen-Sicht — referenzstabil (Leistungsnachweise/Historie/Audit lösen archivierte weiter auf). (4) Running-process-Schutz: beim Archivieren wird der Live-Task gelöst (Schritt → Neuzuweisung, wie bei Verfügbarkeit≠aktiv) — geordnete Übergabe statt Entzug. (5) Client (staff.component): „Archivieren"-Button (Rückfrage) + eigener Archiviert-Abschnitt mit „Reaktivieren"; archiviert im Employee-DTO; aktive Zähler/Filter nutzen nur Aktive. (6) Self-Test test:archiv + CI-Step. Entscheidungen: (a) generisches Flag statt Status-Enum (E-CRUD-1-Sign-off) — orthogonal zu MitarbeiterStatus (fachliche Zustände bleiben), archiviert = Lebenszyklus-Dimension. (b) Kein Hard-Delete (referenzstabil/revisionssicher, OP-COMPLIANCE-1). (c) Kein Migrationsbedarf (archiviert? optional, undefiniert = aktiv) → kein SCHEMA_VERSION-Bump. (d) Cards behalten alle Mitarbeiter im DTO (mit archiviert-Flag) → Client steuert Anzeige/Reaktivierung. Verifikation: typecheck + test:archiv + Regression-Smokes (spike/operativ/replan/solve/teilplan/eligibility/prozess/leistung/progression) + ng build + No-Hex + persistence:check grün. Reiner Server+Client-Pfad, kein Solver-Redeploy. Doku: docs/architektur/Entitaeten-Lebenszyklus.md (C1 ✅ + §1-Matrix), HANDOFF (OP-CRUD-1), CHANGELOG, Timesheet (2026-06-27-op-crud-c1-mitarbeiter-archiv).
  • #232OP-DATA-1 / D5-4: CI-Gate vereinheitlichen — Persistenz-Gate (Drizzle-Staleness + DO-State-Coverage) (Version 0.17.0 → 0.18.0 MINOR — neues CI-Gate/Tooling; Präzedenz D5-1 #230; Build auto-gestempelt, OP-PM-2). Auftrag: D5-4-Slice aus docs/architektur/Persistenz.md §5 + das aus D5-2 vertagte Token-Muster-Gate. Gebaut: (1) DO-State-Migrations-Coverage-Gate scripts/check-do-state-coverage.mjs — Token-Muster (CLAUDE.md §Repo): jedes nicht-optionale PersistedState-Feld braucht einen expliziten saved.<feld> ??-onStart-Default; statisch/heuristisch (parst den PersistedState-Typ + den Hydrations-Merge aus leitstand.ts, kein TS-Compile). Verhindert den S-SEED-5-Schmerzpunkt (neues Feld ohne Backfill fällt erst zur Laufzeit auf). (2) Vereinheitlichtes scripts/check-persistence.sh (npm persistence:check) bündelt Drizzle-Schema-Staleness (D5-1, check-drizzle.sh) + das Coverage-Gate in EIN Gate (analog check-no-hex.sh); beide Teil-Checks bleiben einzeln aufrufbar. (3) CI: der bisherige db-check-Job → persistence-gate umbenannt (läuft persistence:check), in ci-gate-Required-Liste nachgezogen. (4) leitstand.ts: expliziter bays: saved.bays ?? this.state.bays-Default ergänzt (verhaltensgleich — bays kam bisher nur über ...saved/...this.state) → Coverage-Invariante lückenlos (19/19 Pflichtfelder). Entscheidungen: (a) Coverage prüft explizite saved.X ??-Defaults (nicht den ...saved-Spread) — eindeutig, low-false-positive; der eine reale Gap (bays) wurde geschlossen statt ausgenommen. (b) Optionale Felder (schemaVersion?/demoHistorieGeseedet?) sind exempt (über die Versions-Registry bzw. falsy-Default abgedeckt). (c) Job umbenannt (id persistence-gate) statt zweiten Job — „vereinheitlichen" wörtlich; Branch-Protection verlangt ohnehin nur CI Gate, daher kein Required-Check-Bruch. Verifikation: persistence:check grün (Drizzle synchron + 19/19 Felder); Negativtest (Pflichtfeld-Default entfernt → Gate exit 1 mit klarer Meldung, danach restauriert exit 0); typecheck grün. Kein Code-/Verhaltens-Change am Laufzeitpfad (nur additiver bays-Default), kein Solver-Redeploy. ➡ Damit ist OP-DATA-1 bis auf den optionalen DO-SQLite-Pilot (D5-3) umgesetzt. Doku: docs/architektur/Persistenz.md (D5-4 ✅), HANDOFF (OP-DATA-1), CHANGELOG, Timesheet (2026-06-27-d5-4-persistence-gate).
  • #231OP-DATA-1 / D5-2: DO-Blob-Migrations-Registry (Variante A, verhaltenstreu) (Version 0.16.0 → 0.17.0 MINOR — neue, verhaltensgleiche Abstraktion; Präzedenz S-SEED-4 #225; Build auto-gestempelt, OP-PM-2). Auftrag: D5-2-Slice aus docs/architektur/Persistenz.md §5. Gebaut: (1) neue Registry server/src/persistence/do-state-migrations.ts — die früher inline in LeitstandServer.onStart verstreuten versionsgegateten if (sv < N)-Remaps (v2/3/4/5/7/12/14) als geordnete, benannte DO_MIGRATIONS-Liste + Runner migriereDoState(state, fromVersion); SCHEMA_VERSION (=15) wandert hierher als Single Source (von leitstand.ts re-importiert). (2) Round-Trip-Self-Test server/src/persistence/do-migrations-demo.ts + npm-Script/CI-Step test:do-migrations: Voll-Migration v0→v15, Idempotenz (sv=15-Blob bleibt byte-gleich), Versions-Gating (gültiges „abgeschlossen" bei sv≥2 bleibt unangetastet), Registry-Invarianten (aufsteigend/eindeutig/≤SCHEMA_VERSION). (3) onStart ruft nur noch migriereDoState. Entscheidungen: (a) Scope = nur versionsgegatete Remaps (empfohlene, risikoärmste Variante); der emptiness-gegatete Abwesenheits-Historie-Backfill (v11) und die idempotenten Feld-Default-Merges (saved.x ?? this.state.x) bleiben bewusst in onStart — sie sind nicht sv-gegatet, ihre Verlagerung in die Versions-Registry würde die Semantik ändern. (b) SCHEMA_VERSION bleibt eine eigene Konstante (nicht aus max(migration.version) abgeleitet) — spätere Bumps (v13/v15) waren reine Feld-Ergänzungen via Default-Merge, daher ist die Registry lückenhaft. (c) Migrationen arbeiten auf einem losen DoStateBlob (untypisierte Altdaten) — wie zuvor mit as-Casts; das vermeidet Import-Verflechtung mit dem Worker-Runtime und hält den Self-Test isoliert lauffähig. (d) Token-Muster-Gate („neues PersistedState-Feld ⇒ Migration/Default vorhanden") nach D5-4 verschoben (CI-Gate-Bündelung). Verifikation: typecheck grün; test:do-migrations grün; Regression-Smokes operativ/replan/test:teilplan/test:fairness grün. Kein Storage-/Verhaltens-Change, kein Solver-Redeploy. Doku: docs/architektur/Persistenz.md (D5-2 ✅ + §1-Ist-Zustand), HANDOFF (OP-DATA-1), CHANGELOG, Timesheet (2026-06-27-d5-2-do-state-migrations).
  • Branch claude/taktano-meeting-minutes-jfekpr (PR folgt) — Besprechungs-Protokolle (Meeting-Minutes) als Doku-Struktur (Version 0.17.0 → 0.17.1 PATCH — Doku-Zuwachs, kein Code/Verhalten). Auslöser: Frage „Welche Meeting-Minutes gibt es zu Taktano?" → Befund: keine vorhanden (weder im Repo noch via angebundenem Notion — kein Notion-MCP-Connector aktiv). Gebaut: neuer Ordner docs/betrieb/meetings/ mit (1) README.md (Index + Anleitung + Konventionen, pyramidal), (2) _Vorlage.md (Protokoll-Template: TL;DR → Beschlüsse → Action Items → Diskussion → True-North-Bezug), (3) _category_.json (Docusaurus-Sidebar). Eintrag in docs/README.md (Landkarte). Entscheidungen: (a) Meeting-Minutes leben im Repo (Everything-as-Code, einzige Quelle der Wahrheit) statt nur in externem Tool; (b) eine Datei je Termin JJJJ-MM-TT-thema-slug.md (chronologisch, kollisionsfrei — analog Timesheet-Session-IDs, OP-PM-2); (c) protokollierte Beschlüsse werden zusätzlich am verbindlichen Ort gespiegelt (CHANGELOG/HANDOFF §4/design/CLAUDE.md) und per ID referenziert — das Protokoll ersetzt den Audit-Trail nicht, es ergänzt ihn; (d) Notion-Anbindung als Option dokumentiert (Connector erforderlich, DSGVO-Drittland-Hinweis → Risikoregister-Kandidat). Doku: docs/betrieb/meetings/*, docs/README.md, CHANGELOG, HANDOFF, Timesheet (2026-06-27-taktano-meeting-minutes).
  • Branch claude/op-crud-lifecycle (PR folgt) — Neuer OP-CRUD-1: Entitäten-Lebenszyklus (CRUD · Versionierung · Archiv statt Löschen · Schutz laufender Prozesse) (reine Doku → kein Version-/Build-Bump). Nutzer-Wunsch: „Für alle Entitäten die CRUD durchgehen — welche sollten versioniert sein, beim Löschen ggf. nur archivieren statt hart löschen; laufende Prozesse dürfen nicht gestört werden, sondern ordentlich weiterlaufen." Gebaut: neuer Design-Doc docs/architektur/Entitaeten-Lebenszyklus.md mit (1) CRUD-Ist-Matrix je Entität → echte Lücken benannt (Mitarbeiter-/Skill-Delete fehlen; Leistung/Teilschritt ohne Create/Delete); (2) drei Lösch-Klassen (A archivieren/soft-deaktivieren für referenz-/historie-behaftete Stammdaten · B Lifecycle-Archiv = Auftrag · C hart+Audit nur referenzfrei = Infra-Kosten/Foto) + Business-Begründung „warum nie hart löschen" (verwaiste Verweise/Statistik/Revisionssicherheit/DSGVO); (3) Versionierung = OP-AUDIT-1 generisch, eigene Versionierung nur für Prozess-Katalog; (4) Running-process-Schutz als Invariante (Materialisierung bei Auftragsstart + Referenz-Guards + geordnete Übergabe via Klärfall); (5) Lücken-Slices C1…C4 + (6) Entscheidungen E-CRUD-1…4. Entscheidungen (Nutzer-Sign-off 06-27): E-CRUD-1 ✅ = generisches archiviert-Flag (orthogonal zu den fachlichen Status-Enums, uniform filterbar) · E-CRUD-2 ✅ = Materialisierung-bei-Start bestätigt (keine gültigAb-Versionierung jetzt); E-CRUD-3/4 bleiben offen. OP als Design-Doc + HANDOFF §4 registriert — noch keine Code-Änderung (Umsetzung der Slices C1…C4 folgt separat). Registriert: docs/README.md (Landkarte), docs/konventionen/IDs.md (OP→Doc), HANDOFF §4 (OP-CRUD-1). Kein Code, keine Gates/Solver berührt. Doku: architektur/Entitaeten-Lebenszyklus.md (neu), HANDOFF, README, IDs, CHANGELOG, Timesheet (2026-06-27-op-crud-lifecycle).
  • Branch claude/notion-claude-code-integration-4yxtzf (PR folgt) — Notion-Anbindung via MCP für Claude (Contributor-Tooling) (kein Versions-Bump — reines Dev-/Doku-Tooling, kein Worker-/Laufzeit-/Build-Change; Präzedenz Doku/Tooling-only #182/#185/#188/Session 40). Auftrag: „Notion in Claude Code nutzen — sowohl lokal in Claude Desktop als auch in Claude Code in der Cloud" (Nutzer-Wahl: Ziel-Repo taktano, Auth Integrations-Token). Gebaut: (1) eingecheckte .mcp.json im Repo-Root — Server notion via npx -y @notionhq/notion-mcp-server, Token als ${NOTION_TOKEN}-Env-Expansion (kein Secret im Repo) → Claude Code findet den Server lokal und in der Cloud automatisch. (2) Doku docs/konventionen/Notion-Integration.md (zielgruppen-gerecht IT-Dev/DevOps, pyramidal + Mermaid): Setup für Claude Code (lokal: Shell-Env; Cloud: Umgebungs-Secret) und Claude Desktop (Connector-OAuth oder claude_desktop_config.json), Bereichs-Freigabe (Container-Seite, Freigabe vererbt sich → least privilege), Troubleshooting. (3) Doku-Landkarte docs/README.md (konventionen-Tabelle) ergänzt. Entscheidungen: (a) Token statt OAuth für die Cloud — headless-Sessions können den Browser-OAuth-Flow (https://mcp.notion.com/mcp) nicht durchführen; Token via Env-Secret ist robust und hält das Geheimnis aus dem Code (${NOTION_TOKEN}). (b) stdio + npx (offizielles @notionhq/notion-mcp-server, Env NOTION_TOKEN verifiziert gegen das Paket-README) statt gepinnter Version — -y zieht aktuell. (c) kein Versions-Bump — ändert weder server/-Runtime noch Build/Deploy. (d) Claude Desktop bleibt geräte-lokal (claude_desktop_config.json, nicht im Repo) — die Repo-.mcp.json gilt nur für Claude Code. Compliance: Token = Geheimnis (nie im Klartext, Rotation bei Verdacht); von Claude gelesene Notion-Inhalte werden vom Modell verarbeitet → nur freigeben, was vorgesehen ist (Hinweis in der Doku + Verweis Compliance/Risikoregister). Verifikation: .mcp.json valides JSON; Paketname/Env-Var gegen offizielles README geprüft. Kein Solver-/Daten-/Verhaltens-Change. Doku: docs/konventionen/Notion-Integration.md (neu), docs/README.md, HANDOFF (§2), CHANGELOG, Timesheet (2026-06-27-notion-claude-code-integration).
  • #230OP-DATA-1 / D5-1: Drizzle-Toolchain auf der bestehenden Audit-D1 (Schema-First, kein Verhaltens-Change) (Version 0.15.0 → 0.16.0 MINOR — neue, rückwärtskompatible Toolchain; Build auto-gestempelt, OP-PM-2). Auftrag: „Implementiere d5-1" (Slice aus docs/architektur/Persistenz.md §5). Gebaut: (1) drizzle-orm + drizzle-kit als devDependencies in server/ — bewusst nicht Prod (die Schema-Datei wird nur von drizzle-kit konsumiert, nicht vom Worker-Laufzeitpfad → kein Prod-Bundle, kein npm audit --omit=dev-Surface; verifiziert: 0 prod-Vulns). (2) server/src/db/schema.ts = Single Source des SQL-Schemas: das schon existierende audit_entries-Schema (raw server/migrations/0001_audit_entries.sql, remote bereits angewandt) deklarativ als Drizzle nachgezogen — gleiche Tabelle/Spalten/Nullability/Indizes (ausloeser statt SQLite-Keyword trigger, tenant_id first-class). (3) server/drizzle.config.ts (dialect: 'sqlite', out: ./drizzle) + generierte Migration server/drizzle/0000_*.sql (+ meta/), deckungsgleich zu 0001. (4) CI-Gate db-check in .github/workflows/ci.yml (npm run db:checkscripts/check-drizzle.sh: drizzle-kit generategit status muss leer sein) + npm-Scripts db:generate/db:check; als Required-Job in ci-gate verdrahtet. Entscheidungen: (a) getrennte Migrations-Verzeichnisse — Drizzle schreibt nach server/drizzle/, wrangler liest weiter nur server/migrations/ (migrations_dir) → die remote angewandte, idempotente (IF NOT EXISTS) raw-0001 bleibt der einzige Apply-Pfad, kein Doppel-Apply; das Drizzle-Pendant ist rein der maschinen-geprüfte Schema-Beweis. (b) Drizzle als devDependency (s. o.) — kein Laufzeit-Query in D5-1, daher kein Prod-Risiko/Bundle-Zuwachs. (c) Das Staleness-Gate prüft git status (nicht nur git diff --exit-code), damit neue, untracked Migrationsdateien (= Schema editiert, aber db:generate vergessen) nicht durchrutschen. Verifikation: npm run typecheck grün; drizzle-kit generate zweifach → „No schema changes" (idempotent); npm audit --omit=dev --audit-level=high → 0 Vulns. Kein Solver-/Daten-/Verhaltens-Change. Doku: docs/architektur/Persistenz.md (D5-1 ✅ gebaut), HANDOFF (OP-DATA-1), CHANGELOG, Timesheet (2026-06-27-d5-1-implementation).
  • Branch claude/docs-navigation-structure-wf696m (PR folgt) — Doku-Navigation: Findability-Layer (Frontmatter-Lesereihenfolge · Kategorie-Index · Glossar · ID-/OP-Index · Lesepfade · Drift-Checks) (Doku/Tooling-only → kein App-Version-/Build-Bump, APP_VERSION bleibt 0.14.4; Build auto-gestempelt; Präzedenz #205/#218/#222). Nutzer-Wunsch: „Doku ist unübersichtlich/schwer navigierbar — zum Masterpiece machen." Das Fundament (5 Themenordner + Docusaurus + Volltextsuche, #205) stand; diese PR schließt die Detail-Lücken. Gebaut: (1) YAML-Frontmatter in allen 19 docs/**-Dateien — sidebar_position in 10er-Schritten = sinnvolle Lesereihenfolge (statt alphabetisch), sidebar_label für kurze Sidebar-Titel; kein title: (Titel bleibt aus H1 = Single Source). (2) Kategorie-Landing-Pages: link: generated-index + Beschreibung in allen 5 _category_.json → jede Gruppe hat eine echte Übersichtsseite statt nur Aufklappen. (3) Glossar docs/konventionen/Glossar.md (A–Z, Pointer-Stil → Link zur maßgeblichen Definition; Master bleibt Lastenheft §13, keine Zweitdefinition). (4) ID-/OP-Index docs/konventionen/IDs.md (Präfix-Legende + Reverse-Lookup „OP → Owning-Doc"; volle OP-Liste bleibt HANDOFF §4 — bewusst kein Voll-Index/Generator). (5) Landkarte docs/README.md: neuer Abschnitt Lesepfade nach Aufgabe (Onboarding · Scheduler verstehen · PR machen · Architektur nachschlagen · Begriff nachschlagen) + fehlendes architektur/Bildbewertung.md nachgetragen (Drift geschlossen). (6) Drift-Checks in scripts/check-doc-consistency.sh (warnt, blockt nicht, OP-DOCS-9): jede docs/**-Datei ist in der Landkarte verlinkt · hat Frontmatter (sidebar_position) · jeder Ordner hat _category_.json (hätte das Bildbewertung-Loch gefangen; Negativtest bestätigt). (7) Navbar (Glossar + IDs) in docs-site/docusaurus.config.js; Lastenheft toc_max_heading_level: 3 (tiefere On-Page-TOC). (8) Konsistenz-Pass: veraltete Pfad-Referenzen aus dem Ordner-Umzug korrigiert (docs/Lastenheft.mddocs/fachlich/Lastenheft.md, analog Risikoregister/Sanity/Timesheet/Compliance/agents) in 9 Docs. Entscheidungen: (a) keine Datei-Renames — sichtbare Konsistenz über sidebar_label/H1 statt riskanter Umbenennungen (würde ~25+ Pfad-Referenzen + Site-URLs/Bookmarks brechen; „keine ungefragten Refactorings"); (b) bestehende Status-/Bezug-Kopfblöcke bewahrt (architektur/* sind dicht & als Audit-Trail wertvoll) statt in ein starres Template zu pressen — Konvention dafür neu in agents.md §2.1 dokumentiert; (c) Glossar/IDs als Pointer, nicht als Zweitquelle (G-2, keine Decision-Sprawl); (d) Lastenheft nicht gesplittet (meist-referenziert, hunderte §-Anker) — nur TOC-Tiefe verbessert; (e) kein Version-Bump (Doku/Tooling). Verifikation: scripts/check-doc-consistency.sh grün (inkl. der neuen Checks; Negativtest erkennt fehlendes Frontmatter + Landkarten-Eintrag); cd docs-site && npm run build erfolgreichkeine neuen Broken-Link-Warnungen (die zwei neu eingeführten Cross-Instance-Links zu HANDOFF.md/design/WORKSPACES.md als Backtick-Referenz entschärft; die verbleibenden Warnungen sind vorbestehend/cross-instance, nicht aus dieser PR). (9) Warnungsfreier Doku-Site-Build (Folge-Commit, „Copy-+-Rewrite"-Ansatz auf Nutzer-Wunsch): die Site rendert jetzt eine Staging-Kopie der Repo-Markdown (docs-site/prepare-content.mjs ersetzt das alte copy-projekt; docs-staged/ + projekt-docs/ gitignored) und schreibt die wenigen Cross-Instance-Links (Haupt-Instanz docs/ ↔ Projekt-Instanz aus HANDOFF/README/CHANGELOG/CLAUDE) resolve-basiert auf Site-Routen um — die Original-.md bleiben GitHub-korrekt (Single Source). Ergebnis: npm run build ohne Broken-Link-Warnungen (vorher 7 vorbestehende Cross-Instance-Warnungen → 0); CHANGELOG + CLAUDE sind nun ebenfalls auf der Site (/projekt/…). Resolve-basiert, damit z. B. ../README.md aus agents.md (zeigt auf die Landkarte docs/README.md) korrekt unangetastet bleibt, während ../README.md aus der Landkarte (Root-README) zur Instanz-Index-Route /projekt/ wird. Kein Solver-/Worker-Redeploy. Doku: alle docs/**-Frontmatter, docs/konventionen/{Glossar,IDs}.md (neu), docs/README.md, docs/*/_category_.json (5), docs/konventionen/agents.md (§2.1), scripts/check-doc-consistency.sh, docs-site/{docusaurus.config.js,package.json,.gitignore,prepare-content.mjs}, CLAUDE.md (Tiefenquellen), HANDOFF (§2), CHANGELOG, Timesheet (Session 2026-06-27-docs-navigation-structure). True North: indirekt (schnellere/korrektere Navigation → die 3 Leitfragen-Antworten leichter auffindbar).
  • #226North Star erweitert: „Dokumentation als Meisterwerk" (zielgruppen-gerecht · pyramidal · visuell) (Doku-only → kein Version-/Build-Bump, Präzedenz #205/#207). Nutzer-Wunsch: „Add to North Star: clear and concise documentation as a masterpiece, per audience (IT-Dev / Business-Manager / User / IT-Ops / DevOps / CISO / Customer-Service), pyramidal structure, visualisations where helpful." Gebaut: (1) Neues Leitprinzip in CLAUDE.md direkt nach Selbsterklärbarkeit — Doku als Liefergegenstand, pyramidal (Minto: Kernaussage→Gründe→Details), zielgruppen-gerecht (sieben benannte Leserkreise), visuell wo es trägt (Mermaid/Tabellen/Beispiele), selbsterklärbar & OP-DOCS-9-konsistent; True-North-Regel um den Doku-Halbsatz ergänzt. (2) docs/zielgruppen/Lesepfade.md von 4 → 7 Zielgruppen erweitert (neu: DevOps, CISO/Security, Customer Service) inkl. kuratiertem Lesepfad + Glossar-Begriffen je Rolle und einer Mermaid-Rollen-Landkarte (verkörpert das Visuell-Prinzip). Entscheidungen: (a) Prinzip lebt in CLAUDE.md (Guiding-Principles-Heimat), Rollen-Detail in Lesepfade.md (keine Duplizierung); (b) Audience-Mapping business-manager=fach, user=nutzer; (c) keine Links auf noch-ungemergte Docs (Backup-Restore/Persistenz aus #225) → Security-Pfad referenziert bestehende Observability/Audit-Log. Verifikation: check-doc-consistency.sh grün (keine toten Links). Doku: CLAUDE.md, docs/zielgruppen/Lesepfade.md, HANDOFF, CHANGELOG, Timesheet.
  • #225Seed-Ablösung: Stammdaten persistiert + admin-editierbar + Seed → benannte Tenant-Vorlage (OP-SEED-1 / S-SEED-1…4 / OP-TENANT)konsolidierter PR der Branch claude/seed-usage-audit-frsx52, auf main@0.14.4 rebased (Version 0.14.4 → 0.15.0 MINOR; Build automatisch, OP-PM-2). Bündelt die unten als „(PR folgt)" geführten Slices (OP-SEED-1 · S-SEED-1..4 · Design-Docs OP-DATA-1/OP-BACKUP-1) zu einem Merge. Rebase-Entscheidungen: version.ts behält die Build-Count-Mechanik (OP-PM-2) + Version auf 0.15.0; auftrag.starten kombiniert die R7-Invariante (hatZuweisung, aus main) mit den dynamischen belegungSlots (Branch); die drei neuen Architektur-Docs (Seed-Abloese-Plan/Persistenz/Backup-Restore) in die OP-DOCS-8-Struktur docs/architektur/ eingepasst (Querverweise nachgezogen); append-only Logs union-gemergt, kollidierende Timesheet-Session-IDs (37–42) auf sprechende Branch-IDs geglättet (OP-PM-2). CodeRabbit-Review (9 Funde) adressiertEntscheidungen: (1) alle neuen Stammdaten-CRUD-Nachrichten (arbeitsplatz/taxonomie/schicht.*) server-seitig gegatet (istKostenAdmin, wie admin.purge) — die UI-Gate allein reichte nicht (Critical, Security); (2) keine Actor-PII (E-Mail) im Laufzeit-console des Purge — Identität gehört in die D1-Audit-Senke (OP-LOG-1/OP-AUDIT-1); (3) taxonomieInUse zählt jetzt auch die append-only abwesenheitHistorie (keine verwaisten Typ-IDs); (4) arbeitsplatz.remove löscht keine referenzierten Buchten (Belegung/geplante Schritte) mehr — nur deaktivieren; (5) taxonomie.update verhindert, dass eine Umbenennung die logik-tragende Parkplatz-Semantik (G-1, /parkplatz/i) eines genutzten Typs kippt; (6) Client-[(ngModel)]→Signal-Felder auf [ngModel]="x()"+(ngModelChange)="x.set($event)" umgestellt (Signal wurde sonst beim Editieren durch einen Plain-Wert ersetzt); (7) Purge meldet Erfolg erst nach Server-Ack (neuer State) statt Fire-and-forget — inkl. Nicht-verbunden-/Timeout-Fehlermeldung; (8) logik-tragende Taxonomie-Einträge (Parkplatz/Indoor/Folierbucht) im Editor nicht umbenennbar/löschbar (G-1); (9) gemeldetes „doppeltes BelegungSlot" als False-Positive begründet beibehalten (genau eine Deklaration; BelegungSlotDTO ist ein anderer Typ; tsc grün). Verifikation: server typecheck + Self-Tests (spike/operativ/replan/solve/teilplan/prozess) + client ng build (prod) + No-Hex + Doc-Consistency grün. Kein Solver-Redeploy. Doku: docs/architektur/{Seed-Abloese-Plan,Persistenz,Backup-Restore}.md, HANDOFF (OP-SEED-1/OP-TENANT/OP-BACKUP-1/OP-DATA-1), CLAUDE.md (Tiefenquellen), CHANGELOG, Timesheet (2026-06-27-branch-ahead-review-pr).
  • Branch claude/seed-usage-audit-frsx52 (PR folgt) — Entscheidung: Tenant-Isolation (OP-TENANT) — Daten pro Tenant physisch getrennt (reine Doku → kein Version-/Build-Bump). Nutzer-Entscheidung (06-27): Mandantendaten + Audit je Tenant in DO-SQLite (Isolations-Option A, „Room=Tenant", physische Trennung, kein Cross-Query-Surface); Tenant-Registry zentral via Better Auth Organizations (EU-D1, OP-AUTH-1). Folgen festgehalten: (1) löst zugleich E-DATA-1 = B (DO-SQLite) in docs/Persistenz.md; (2) proaktiv geflaggte Compliance-Folge beim Audit — verlässt die separate D1 (= physische Gewaltenteilung): Mitigation = Audit in der Tenant-DO-SQLite append-only + Hash-Chain (Tamper-Evidenz) + das bestehende live D1 taktano-audit (#186) umgewidmet zum zentralen forward-only Compliance-/Cross-Tenant-Sink (nicht weggeworfen); ⮕ E-TENANT-1 (Sink ja/nein) offen. Neu: docs/architektur/Mandantenfaehigkeit.md (OP-TENANT — Entscheidungs-Record: Datenhaltung je Klasse, Audit-Reconciliation §4, Enforcement Identität→Tenant→DO-Room, Slices T-1…T-6, ⮕ E-TENANT-1/2/3). Aktualisiert: docs/Persistenz.md (E-DATA-1 ✅ entschieden = B), docs/Audit-Log.md (§2 Speicher-Verfeinerung: primär DO-SQLite je Tenant + Hash-Chain, D1 → zentraler Sink; alte D1-Hybrid-Entscheidung als §2.1 erhalten), HANDOFF §4 (OP-TENANT/OP-DATA-1/Audit), CLAUDE.md (Tiefenquellen). Kein Code, keine Gates/Solver berührt; der heutige D1-Dual-Write bleibt bis zu den Folge-Slices (T-3/T-4) unverändert nutzbar.
  • Branch claude/seed-usage-audit-frsx52 (PR folgt) — E-TENANT-1 entschieden: (C) zentraler Hash-Anker fürs Audit (reine Doku → kein Bump). Nach Abwägung A (voller zentraler Event-Sink) · B (rein per-Tenant + Fan-out) · C (nur Chain-Kopf zentral) wählt der Auftraggeber C: per-Tenant-Audit in DO-SQLite append-only + Hash-Chain (eintrag_n.hash = H(payload ‖ vorheriger_hash)); zentral wird nur der Chain-Kopf je Tenant verankert ({tenant_id, seq, head_hash, ts}, taktano-audit umgewidmet zu Tabelle audit_anchors) — keine Events, keine PII zentral. Liefert off-box-Manipulationsnachweis ohne zentrale Datenhaltung (ehrt „komplett getrennt" maximal); Cross-Tenant-Reporting bleibt Fan-out, Upgrade-Pfad C→A nur bei echtem Bedarf. Heutiger D1-Dual-Write schreibt interim noch volle Events → End-Zustand reduziert auf den Anker (Folge-Slices T-3/T-4). Festgehalten in docs/architektur/Mandantenfaehigkeit.md §4/§6/§7, docs/architektur/Audit-Log.md §2, HANDOFF §4 (OP-TENANT). Kein Code.
  • Branch claude/seed-usage-audit-frsx52 (PR folgt) — E-TENANT-2 entschieden: (3) ein R2-Bucket + Prefix je Tenant, gekapselt (reine Doku → kein Bump). Nach Abwägung 1 (Prefix) · 2 (Bucket je Tenant, physisch) · 3 (Prefix gekapselt + Opt-in-Split) wählt der Auftraggeber 3: Fotos in einem EU-Bucket unter tenant/<id>/…, ausschließlich über tenantBucket()/tenantKey() + unrätbare Ids + signierte URLs; tenant_id aus verifizierter Identität. Begründung (bewusst nicht „physisch um jeden Preis"): (a) die sensible Relation Foto↔Tenant↔Auftrag liegt bereits physisch in der DO-SQLite — R2 hält nur opake Bytes; (b) Zielmarkt = viele kleine Betriebe → tausende Mandanten → Bucket-je-Tenant rennt ins R2-Bucket-Limit/Konto + Provisionierungs-Ops, Prefix skaliert unbegrenzt. Bucket-je-Tenant = dokumentiertes Opt-in-Upgrade für einzelne High-Compliance-Tenants (mechanisch dank Kapselung) — gleiches „minimal jetzt, Upgrade auf Bedarf"-Muster wie E-TENANT-1=C. Festgehalten in docs/architektur/Mandantenfaehigkeit.md §3/§5/§6 (T-7)/§7. Kein Code.
  • Branch claude/seed-usage-audit-frsx52 (PR folgt) — E-TENANT-3 entschieden: zurückgestellt („auf Anforderung") (reine Doku → kein Bump). Per-Tenant-Verschlüsselung at-rest (Envelope, eigene Keys) wird nicht vorab gebaut — bis ein konkreter Compliance-/Vertragsbedarf sie fordert gilt die Plattform-Verschlüsselung at-rest (DO/D1/R2 EU) als ausreichend; Re-Evaluierung bei Enterprise-/regulatorischen Anforderungen (OP-COMPLIANCE-1). ➡ Damit sind alle Tenant-Isolations-Sign-offs abgeschlossen (E-DATA-1=B · E-TENANT-1=C · E-TENANT-2=3 · E-TENANT-3=zurückgestellt); offen bleiben nur die OP-BACKUP-1-Detailfragen (E-BACKUP-1/2/3). Festgehalten docs/architektur/Mandantenfaehigkeit.md §7. Kein Code.
  • Branch claude/seed-usage-audit-frsx52 (PR folgt) — E-BACKUP-1/2/3 entschieden + Housekeeping (reine Doku → kein Bump). E-BACKUP-1 = native DO-SQLite-PITR, SELEKTIV angewandt: Restore stellt nur die Fachtabellen auf T wieder her, die Audit-Tabelle bleibt unangetastet — Cross-Check mit E-TENANT-1=C ergab, dass ein blindes Whole-DO-PITR das in derselben DO-SQLite liegende Audit mitrollen und die Events zwischen T↔jetzt vernichten würde (Konsistenz-Falle, proaktiv gelöst); + B5-1 Pre-Purge-Snapshot als Sofort-Netz, kein eigenes Event-Log. E-BACKUP-2 = 30 Tage rollierende Retention (= PITR-Fenster) + Plattform-Verschlüsselung at-rest; Recht-auf-Vergessen via Aging (Lösch-SLA „aus Backups ≤30 Tage"), Audit ausgenommen (PII-gescrubbt). E-BACKUP-3 = ja, „durch Restore überholte" Audit-Einträge nur darstellungsseitig markieren (kein Schreibzugriff). ➡ OP-BACKUP-1 vollständig entschieden. Housekeeping: veraltete „auszuarbeiten"-Stub im HANDOFF-OP-BACKUP-1 entfernt; alle flachen docs/<x>.md-Verweise in HANDOFF auf die docs/architektur/-Struktur (OP-DOCS-8) nachgezogen; drei doppelte „## Summe"-Kopfzeilen im Timesheet (Union-Merge-Artefakt) auf die main-Linie (~102.0 h) kollabiert. Festgehalten docs/architektur/Backup-Restore.md §5/§6/§7/§8, HANDOFF §4. Kein Code.
  • Branch claude/seed-usage-audit-frsx52 (PR folgt) — Design-Docs: S-SEED-5/OP-DATA-1 (Persistenz) + OP-BACKUP-1 (Backup/Restore) ausgearbeitet (reine Doku → kein Version-/Build-Bump, Präzedenz #182/#185). Nutzer-Auftrag: „1, dann 2" — erst S-SEED-5 als Design-Doc mit der DO/D1-Entscheidung als Kern, dann OP-BACKUP-1 ausarbeiten. (1) docs/Persistenz.md (OP-DATA-1 / S-SEED-5): Ist-Zustand (DO-Blob + handgepflegte onStart-Remaps + SCHEMA_VERSION 15, nicht maschinell geprüft; D1 nur fürs Audit, raw-SQL 0001, kein Drizzle) → Ziel: Drizzle als Single Source + generierte Migrationen + CI-Gate. Drei Daten-Heimaten abgewogen (DO-Blob · DO-SQLite · D1) mit Leitkonvention je Datencharakter; ⮕ E-DATA-1 (Sign-off): (A) DO-Blob + Migrations-Hygiene [empfohlen sofort] · (B) DO-SQLite + Drizzle [Zielbild, koppelt an OP-TENANT + OP-BACKUP-1] · (C) D1 für Stammdaten. Slices D5-1 (Drizzle-Toolchain auf bestehender D1 retrofitten, kein Verhaltens-Change) · D5-2 (DO-Blob-Migrations-Registry + Round-Trip-Test + Token-Gate) · D5-3 (DO-SQLite-Pilot) · D5-4 (CI-Gate). (2) docs/Backup-Restore.md (OP-BACKUP-1): Snapshot vs. echtes PITR; drei Wege (Snapshot-Kadenz · Event-Sourcing · DO-SQLite-natives PITR) — Kern-Erkenntnis: DO-SQLite hat natives Point-in-Time-Recovery → mit OP-DATA-1 gemeinsam entscheiden, dann PITR fast geschenkt. Beantwortet die zwei Nutzer-Kernfragen: (a) Restore-Punkt über die Audit-Timeline wählen; (b) Audit-Log wird NICHT mitgerollt — bleibt append-only/unveränderlich (OP-AUDIT-1), der Restore ist selbst ein neues state.restore-Event; bewusste Divergenz Fachzustand↔Audit + Reconciliation-Regel. Sofort-Netz B5-1 (Pre-Purge-Snapshot nach R2). DSGVO/Retention vs. Recht-auf-Vergessen behandelt; ⮕ E-BACKUP-1/2/3. Doku-Registrierung: beide Docs in CLAUDE.md (Tiefenquellen) + HANDOFF §4 (neuer OP-DATA-1-Bullet, OP-BACKUP-1 von „auszuarbeiten" → ausgearbeitet) + docs/Seed-Abloese-Plan.md (S-SEED-5-Verweis). Kein Code, keine Gates berührt.
  • Branch claude/seed-usage-audit-frsx52 (PR folgt) — S-SEED-4: Seed → benannte Tenant-Vorlage extrahiert (server/src/tenants/) (Version 0.15.0 → 0.16.0 MINOR, Build 18 → 19). Nutzer-Auftrag: „ja" (S-SEED-4 weitermachen). Ziel: den (nach S-SEED-1/2/3 nur noch als Vorlage genutzten) Seed formal zur benannten Tenant-Vorlage machen — kein impliziter Laufzeit-Default mehr. Gebaut: (1) Stammdaten per git mv (Historie erhalten) von server/src/model/seed.tsserver/src/tenants/vest-automotive.ts; Modul-Typ-Import ./types../model/types angepasst; (2) neuer Typ TenantVorlage ({ id, name, daten: SchedulerInput }, server/src/tenants/types.ts) + Wrapper export const vestAutomotive: TenantVorlage = { id: 'vest-automotive', name: 'Vest Automotive GmbH', daten: vestAutomotiveSeed }; (3) Registry server/src/tenants/index.ts (TENANT_VORLAGEN, tenantVorlage(id), DEFAULT_TENANT_ID, aktiveTenantVorlage()); (4) leitstand.ts bezieht die Vorlage über aktiveTenantVorlage()const AKTIVE_TENANT, TENANT_ID = AKTIVE_TENANT.id, interne vestAutomotiveSeed = AKTIVE_TENANT.daten (alle bestehenden vestAutomotiveSeed.*-Referenzen unverändert); (5) model/seed.ts = dünner Re-Export-Shim (export { vestAutomotiveSeed } from '../tenants/vest-automotive'), damit die Demo-/Spike-/Self-Test-Skripte (*-demo.ts, spike.ts) ihren Import from '../model/seed' behalten. Entscheidungen: (1) Re-Export-Shim statt ~11 Demo-Imports umzubauen — niedrigeres Risiko, der Runtime-Pfad (DO) nutzt bereits die Registry (Ziel erreicht); Shim-Entfernung als Folge notiert; (2) vestAutomotiveSeed-Name im DO lokal beibehalten (= AKTIVE_TENANT.daten) → keine Churn an den vielen Referenzstellen; (3) MINOR statt PATCH, da neue Abstraktion (TenantVorlage + Registry) = Fundament für OP-TENANT, rückwärtskompatibel/verhaltensgleich. ➡ Damit ist der Seed kein impliziter Laufzeit-Default mehr, sondern eine explizit benannte Vorlage — Code-Fundament für echtes Multi-Tenancy (OP-TENANT). Verbleibend im Ablöse-Plan: nur S-SEED-5 (Drizzle/Migrationen, OP-DATA-1). Verifikation: Server-Typecheck (inkl. aller Demos via Shim) + spike/operativ/replan/solve/test:teilplan/test:prozess + ng build (prod, Client unverändert) + No-Hex grün. Reiner Restrukturierungs-/Server-Pfadkein Verhaltens-/Datenmodell-Change, kein Solver-Redeploy. Doku: docs/Seed-Abloese-Plan.md (S-SEED-4 ✅ + §4-Abschluss), HANDOFF §4 (OP-SEED-1 + OP-TENANT-Fundament), CHANGELOG, docs/Timesheet.md (Session 41).
  • Branch claude/seed-usage-audit-frsx52 (PR folgt) — S-SEED-3: Schicht-Katalog (R1-S2) persistiert + admin-editierbar (Schicht-Editor) (Version 0.14.0 → 0.15.0 MINOR, Build 17 → 18). Nutzer-Auftrag: „S-SEED-3". Befund: der Schicht-Katalog war der letzte Stammdaten-Block am Seed im Laufzeitpfad — SCHICHTEN/SCHICHT_DTOS/SCHICHT_IDS lasen vestAutomotiveSeed.schichten read-only, und der Scheduler bezieht Verfügbarkeits-/Ausfallfenster über input.schichten. Gebaut (Server): schichten: SchichtKatalog[] in den DO-State (persistiert; onStart-Backfill; in baueState/Purge unter „Taxonomie & Struktur"); SCHICHTENschichtenMap, SCHICHT_DTOSschichtDtos, SCHICHT_IDSschichtIds als Instanz-Getter über state.schichten; schedulerInput() reicht schichten: state.schichten durch → editierte Schichten wirken direkt auf mitarbeiterAusfall/mitarbeiterAvailability/Solver. CRUD schicht.create|update|remove: Name + Wochentage (bereinigeTage → gültig/dedupliziert/Mo→So) + Zeit-Slots (bereinigeSlotsHH:mm-Regex, start<ende) + art (regulär/standard/überlauf) + aktiv-Soft-Deaktivierung; hartes Löschen nur unzugewiesen (schichtInUse prüft mitarbeiter.schichtIds und Abwesenheits-Schichtbezug); Snapshot um schichtenKatalog: SchichtKatalogDTO[] (rohe editierbare Struktur inkl. inUse) erweitert, die kompakten schichten-Anzeige-DTOs (Tage/Zeiten als Strings) bleiben für die Mitarbeiter-Schicht-Zuweisung. Gebaut (Client): Schicht-Editor im Admin-Workspace /administration — Liste (Name/Tage/Zeiten/Art/Aktiv) + Anlegen/Bearbeiten-Formular mit Wochentag-Picker, variabler Zeit-Slot-Liste (type=time, Hinzufügen/Entfernen, Rot-Markierung bei start≥ende), Art-Dropdown; Service-Typen SchichtKatalogDTO/SchichtSlot/Wochentag + Actions + State-Feld. Entscheidungen: (1) Logik-tragend bleibt fix: Wochentage/Zeitfenster steuern die Solver-Verfügbarkeit — Werte editierbar, das HH:mm-Format ist validiert/fix; (2) zwei DTO-Sichten (kompakt für Zuweisung, roh für Editor) statt die bestehende SchichtDTO-Anzeige umzubauen (kein Bruch der Mitarbeiter-Seite); (3) Löschen-vs-Deaktivieren wie bei Taxonomie/Arbeitsplatz; (4) CRUD ungated wie übrige Stammdaten (Nav admin-gegated, OP-AUTH-1). ➡ Meilenstein: nach S-SEED-1/2/3 liest kein Produktivpfad mehr vestAutomotiveSeed.{arbeitsplaetze,taxonomy,schichten} direkt — verbleibend nur S-SEED-4 (Vorlage formal extrahieren) + S-SEED-5 (Drizzle, OP-DATA-1). Verifikation: Server-Typecheck + spike/operativ/replan/solve/test:teilplan/test:prozess + ng build (prod) + No-Hex grün. Reiner Server+Client-Pfadkein Solver-Redeploy (SchedulerInput.schichten unverändert, nur Quelle Seed→State). Doku: docs/Seed-Abloese-Plan.md (S-SEED-3 ✅), HANDOFF §4 (OP-SEED-1), CHANGELOG, docs/Timesheet.md (Session 40).
  • Branch claude/seed-usage-audit-frsx52 (PR folgt) — S-SEED-2: Taxonomien (G-1) persistiert + admin-editierbar (Taxonomie-Editor) (Version 0.13.0 → 0.14.0 MINOR, Build 16 → 17). Nutzer-Auftrag: „S-SEED-2". Befund: die Taxonomie (Abteilungen, Arbeitsplatz-/Abwesenheits-/Sperre-Typen, Ausstattung, Leistung-Kategorien) war der letzte große read-only Seed-Block im Laufzeitpfad — ~11 Modul-Konstanten (ABTEILUNGEN, TYP_LABEL, ARBEITSPLATZ_TYPEN, AUSSTATTUNG_TYPEN, ABWESENHEIT_TYPEN, Validierungs-Sets …) + 3 Modul-Funktionen lasen vestAutomotiveSeed.taxonomy; auch der Scheduler/CP-SAT erkennt Parkplatz/Indoor über input.taxonomy-Labels. Gebaut (Server): taxonomy: TaxonomyValue[] in den DO-State (persistiert; onStart-Backfill für Altzustände; in baueState/Purge unter Kategorie „Taxonomie & Struktur"); alle Modul-Konstanten → Instanz-Getter über state.taxonomy (this.abteilungen, this.typLabel, this.arbeitsplatzTypen, this.ausstattungTypen, this.abwesenheitTypen, this.arbeitsplatzTypIds, …); die Modul-Funktionen toAuftragDTO/buildProzessKatalog/bauBelegungSlots bekommen die Taxonomie bzw. Label-Map als Parameter (statt Seed-Zugriff); schedulerInput() reicht taxonomy: state.taxonomy durch → editierte Taxonomie wirkt direkt auf Eignung/Belegung/Solver. CRUD taxonomie.create|update|remove: Anlegen (Art + Label, reaktiviert gleichnamige deaktivierte Werte case-insensitive), Umbenennen + aktiv-Soft-Deaktivierung (G-1 „Soft-Deaktivierung statt Löschen"), hartes Löschen nur unreferenziert (taxonomieInUse prüft Mitarbeiter/Arbeitsplätze/Teilschritte/Leistungen/Sperren); Snapshot um taxonomie: TaxonomieDTO[] (inkl. inUse-Flag). Gebaut (Client): generischer Taxonomie-Editor im Admin-Workspace /administration — Art-Auswahl (6 Arten) × Werte-Liste mit Inline-Umbenennen, Aktiv-Toggle und Löschen (deaktiviert bei inUse), plus Anlegen; Service-Typen TaxonomieDTO/TaxonomyKind + Actions + State-Feld. Entscheidungen: (1) Logik-tragende Konventionen bleiben fix (G-1): der Scheduler erkennt Stellplätze/Indoor über Label-Regex (/parkplatz/i, /indoor|folierbucht/i) — die Regex bleibt im Code, der Editor warnt sichtbar, solche Typen nicht umzubenennen (robusteres kind-Flag als Folge notiert); (2) kind/id unveränderlich, nur Label + aktiv editierbar (Referenz-Stabilität); (3) Löschen vs. Deaktivieren: referenzierte Werte können nur deaktiviert werden (keine verwaisten IDs), unreferenzierte hart löschbar; (4) Mangel-Kategorien (§4.9.1, MANGEL_KATEGORIEN) sind eine separate feste Liste (nicht Teil der Stamm-Taxonomie) und bleiben vorerst hart (als Folge notiert); (5) CRUD ungated wie die übrigen Stammdaten, erreichbar nur über die admin-gegatete /administration-Nav (OP-AUTH-1). Verifikation: Server-Typecheck + spike/operativ/replan/solve/test:teilplan/test:prozess + ng build (prod) + No-Hex grün. Reiner Server+Client-Pfadkein Solver-Redeploy (das Resource-/Taxonomie-Modell ist unverändert, nur die Quelle wandert Seed→State). Doku: docs/Seed-Abloese-Plan.md (S-SEED-2 ✅), HANDOFF §4 (OP-SEED-1 aktualisiert), CHANGELOG, docs/Timesheet.md (Session 39). ➡ Nach S-SEED-1+2 berührt kein Produktivpfad mehr vestAutomotiveSeed.{arbeitsplaetze,taxonomy} direkt — verbleibend: Schichten (S-SEED-3) + Vorlage-Extraktion (S-SEED-4).
  • Branch claude/seed-usage-audit-frsx52 (PR folgt) — S-SEED-1: Arbeitsplätze/Buchten persistiert + editierbar (Seed-Ablösung) + neuer OP-BACKUP-1 (Version 0.12.0 → 0.13.0 MINOR, Build 15 → 16). Nutzer-Auftrag: „S-SEED-1 angehen" + „neuer OP: Backup & Restore (gern Point-in-Time; ggf. Rollback-Zeitpunkt am Audit-Log bestimmen; auch klären, was mit dem AuditLog beim Rollback passiert)". Befund: die Buchten/Arbeitsplätze (Arbeitsplatz, R2) waren der nächste noch hart verdrahtete Stammdaten-Block — der Solver/schedulerInput(), BELEGUNG_SLOTS (Belegung/Inventur) und ressourcenDTO().bays (Ausfallbänder) lasen vestAutomotiveSeed.arbeitsplaetze read-only. Gebaut (Server): arbeitsplaetze: Arbeitsplatz[] in den DO-State aufgenommen (persistiert; onStart-Backfill für Altzustände; in baueState/Purge unter Kategorie „Taxonomie & Struktur", Demo-Wartungssperre nur beim Voll-Demo-Seed); Modul-Konstante BELEGUNG_SLOTSInstanz-Getter belegungSlots (bauBelegungSlots(state.arbeitsplaetze)); ressourcenDTO().bays + schedulerInput() lesen aus dem State; CRUD arbeitsplatz.create|update|remove (Name + gültiger Typ Pflicht; Kapazität ≥1; Skill-/Ausstattungs-IDs gegen Bestand validiert/dedupliziert; remove räumt die belegung des Slots mit auf); Snapshot um arbeitsplaetze: ArbeitsplatzDTO[] (Typ-Label + Parkplatz-Flag + Sperren-Zähler) + Editor-Optionen arbeitsplatzTypenAlle (inkl. Parkplatz-Typen) + ausstattungTypen erweitert. Gebaut (Client): Arbeitsplatz-Editor im Admin-Workspace /administration — Liste mit Typ/Kapazität/Status/Skill-Zähler + Anlegen/Bearbeiten-Formular (Name, Typ-Dropdown, Kapazität, Konfig-Status, Skill-Chips, Ausstattung-Chips) + Entfernen; Service-Typen ArbeitsplatzDTO/ArbeitsplatzPatch + Actions + State-Felder. Entscheidungen: (1) arbeitsplaetze (R2-Solver-Modell) persistiert, nicht das separate UI-bays-Board — letzteres ist eine eigene, bereits persistierte Repräsentation (Vereinheitlichung als Folge notiert); (2) Taxonomie der Typen bleibt Seed-basiert bis S-SEED-2 (Typ-/Ausstattungs-Auswahl liest weiter die Seed-Taxonomie — bewusst kleiner Slice); (3) Sperren dieser Iteration nur read-only Zähler (sperrenAnzahl), Sperren-Editor als Folge; (4) CRUD ungated wie die übrigen Stammdaten (employee/skill/teilschritt), erreichbar nur über die admin-gegatete /administration-Nav (echtes Rollen-Gate = OP-AUTH-1). Neuer OP-BACKUP-1 (noch auszuarbeiten): Backup & Restore möglichst Point-in-Time; Rollback-Zeitpunkt über das append-only Audit-Log (OP-AUDIT-1) bestimmen; Leitlinie: das Audit-Log bleibt unveränderlich und wird nicht mitgerollt — der Rollback selbst wird als neues Audit-Event geschrieben; offene Fragen (Snapshot vs. Event-Sourcing, Konsistenz Fachzustand↔Audit, Retention/PII, Tenant-Scope, DSGVO/EU-Residenz) in HANDOFF §4 festgehalten. Verifikation: Server-Typecheck + spike/operativ/replan/solve/test:teilplan/test:prozess + ng build (prod) + No-Hex grün. Reiner Server+Client-Pfadkein Solver-Redeploy (das Solver-Resource-Modell ist unverändert, nur die Quelle wandert Seed→State). Doku: docs/Seed-Abloese-Plan.md (S-SEED-1 ✅), HANDOFF §4 (OP-SEED-1 aktualisiert + neu OP-BACKUP-1), CHANGELOG, docs/Timesheet.md (Session 38).
  • Branch claude/seed-usage-audit-frsx52 (PR folgt) — OP-SEED-1 / OP-TENANT: Seed-Audit + Datenbestand-Purge + Tenant-Vorlage-Fundament (Version 0.11.0 → 0.12.0 MINOR, Build 14 → 15). Nutzer-Auftrag: „wo werden noch Seeds verwendet?" → konkreter Ablöse-Plan + „lass mich entscheiden, welche Seeds nach einem Purge geladen werden" + „Purge-Option im Admin-Bereich" + „ergänze als OP: Mandantenfähigkeit — vestAutomotive als Tenant konfigurierbar". Audit-Befund: der statische vestAutomotiveSeed (server/src/model/seed.ts) wird nur serverseitig genutzt (kein Client-Code); im Produktivpfad (leitstand.ts) sind Mitarbeiter/Skills/Teilschritte/Leistungen bereits abgelöst (persistiert+editierbar), noch hart verdrahtet sind Buchten, Taxonomie, Schichten; die *-demo.ts/spike.ts-Skripte nutzen den Seed bewusst als Testdatensatz und bleiben. Gebaut: (1) baueState(kategorien) = einzige Stelle, an der die Tenant-Vorlage vest-automotive (TENANT_ID) zu State wird — Boot-Default baueState(ALLE) ist bit-identisch zum bisherigen Voll-Seed-Boot (regressionsfrei); (2) Admin-Kommando admin.purge (admin-gegated über denselben Access-Owner-Gate wie Kosten, interim bis OP-AUTH-1) setzt den gesamten Datenbestand zurück und lädt einzeln wählbare Seed-Kategorien (Taxonomie & Struktur · Prozess-Katalog · Demo-Mitarbeiter · Demo-Historie) — löscht zusätzlich transiente Arbeitszustände (Vorschau/Vorschläge/Live-Tasks); (3) persistiertes Flag demoHistorieGeseedet verhindert, dass seedDemoHistorie() nach einem Purge ohne Demo-Historie beim nächsten Cold-Boot wieder Demo-Daten nachschiebt (legacy/undefiniert = Altverhalten, rein additiv, keine Migration); (4) neuer Admin-Workspace /administration (Cluster „System", nav-/server-gegated wie Kosten) mit Gefahrenzone: Preset-Schnellwahl („Leeres Gerüst" [Default] · „Voller Demo-Seed" · „Komplett leer"), Einzel-Checkboxen je Kategorie, Ergebnis-Vorschau und Tipp-Bestätigung (LÖSCHEN) vor der destruktiven Aktion (Rot nur für Warnung/Confirm-Button, nur --tk-*-Tokens). Entscheidungen (06-26, empfohlene Defaults — interaktive Rückfrage scheiterte am Permission-Stream der Remote-Session, im Dialog/Plan überstimmbar): D1 alle vier Kategorien einzeln wählbar · D2 Purge-Default „Leeres Gerüst" (Struktur+Prozess, keine Mitarbeiter/Aufträge) · D3 Tenant-Umfang = „Fundament + OP" (eine benannte Vorlage + selektives Re-Seeding; echtes Tenant-Switching/-Isolation als spätere Slices). Ablöse-Plan (Slices, je eigene PR): S-SEED-1 Buchten persistieren+editieren · S-SEED-2 Taxonomie-Editor (G-1) · S-SEED-3 Schicht-Katalog · S-SEED-4 Vorlage nach server/src/tenants/vest-automotive.ts extrahieren · S-SEED-5 Drizzle/Migrationen (OP-DATA-1) — danach berührt kein Produktivpfad mehr den Seed direkt (Voraussetzung für Multi-Tenancy). ⚠ Vor Produktivgang (proaktiv geflaggt): Purge ist destruktiv & irreversibel — vor Go-Live Export/Backup vor Purge (OP-EXPORT-1), Purge-Audit-Event ins D1-Audit (OP-AUDIT-1, heute nur Ops-Log-Zeile mit Actor, OP-LOG-1) und echtes Rollen-Gate (OP-AUTH-1) ergänzen. Verifikation: Server-Typecheck + operativ- & test:prozess-Smoke + ng build (prod) + No-Hex-Gate grün. Reiner Server+Client-Pfadkein Solver-Redeploy. Doku: neu docs/Seed-Abloese-Plan.md (Audit · Entscheidungen · Slices · OP-TENANT-Zielbild), HANDOFF §4 (OP-SEED-1 + OP-TENANT), CHANGELOG, docs/Timesheet.md.
  • #220Glossar (inkl. CP-SAT) + automatische Begriffs-Sprechblasen in der gesamten Doku + Lesepfade nach Zielgruppe (OP-DOCS-10 neu; OP-DOCS-4 teil-adressiert; Doku/Doku-Site-only → kein App-Version-/Build-Bump, Präzedenz #205/#206). Aufgabe (Nutzer): „CP-SAT im Glossar erklären; alle Glossar-Begriffe in der Doku als Mouse-over/Click-Bubble erläutern (aus dem Glossar); Doku nach Zielgruppen aufbauen (Nutzer · nicht-IT-Fachleute · IT-Arch/-Dev · IT-Operations)." (1) Glossar — eine Quelle, drei Verbraucher: strukturierte Wahrheit in docs-site/src/glossar/glossar.mjs (50 Begriffe inkl. CP-SAT, OR-Tools, Solver/Scheduler/Decoder, Makespan/Durchlaufzeit/Zielfunktion, Constraint/Pönale/G-2/G-3, Auftrag/Teilschritt/Bucht/Belegung, Durable Object/Cloudflare Worker/partyserver, Solver-Service/Fly.io/Access/D1, SBOM/Compliance/DSGVO/OTel/trace_id …) — je Eintrag kurz (Sprechblasen-Text), zielgruppen, siehe. Daraus generiert npm run glossar (Script scripts/gen-glossar.mjs, läuft im prebuild/prestart) die gut browsebare Seite docs/glossar/Glossar.md (Banner „AUTO-GENERIERT — nicht handeditieren"; Muster wie tokens.json → tokens.css). (2) Sprechblasen automatisch: Remark-Plugin src/remark/glossarTooltips.mjs umschließt in beiden Docs-Instanzen (Haupt-Docs + projekt/HANDOFF+README) je Seite die erste Fundstelle jedes Begriffs mit <span class="tk-term">; Client-Modul src/clientModules/glossarTooltip.js zeigt bei Mouse-over und Klick/Tap (angepinnt) die Kurz-Erklärung + „Siehe auch" + „Im Glossar öffnen →" (tastatur-zugänglich, Escape schließt). Übersprungen werden Überschriften, Links, Code (Block+inline), bereits gesetzte HTML-Knoten und die Glossar-Seite selbst; Wortgrenzen verhindern Falsch-Treffer (z. B. „Auftragsnummer" ≠ „Auftrag"); längste Oberflächenform zuerst (CP-SAT-Solver vor CP-SAT). (3) Lesepfade nach Zielgruppe: docs/zielgruppen/Lesepfade.md (Sidebar-Position 0) als nicht-invasiver Überbau — vier kuratierte Pfade (Anwender · Fach/Management · IT-Arch&Dev · IT-Operations) mit „Wer · Worauf es ankommt (True-North-Bezug) · Lesepfad · Begriffe", verlinkt nur bestehende Docs (keine Datei verschoben). Entscheidungen: (a) eine Quelle (glossar.mjs) speist Seite, Sprechblasen und Suche statt doppelter Pflege; (b) Begriffe automatisch (Remark) statt manueller Markup-Edits in jeder .md — auch HANDOFF/README profitieren; (c) erste Fundstelle je Seite (klassische Glossar-UX, kein Zukleistern); (d) Pure-CSS/Vanilla-Client-Modul ohne neue npm-Abhängigkeit; (e) kein Hex (Infima-Theme-Variablen → dark/light); (f) Zielgruppen als Überbau (OP-DOCS-4 Schritt 1) statt sofortiger Ordner-Trennung/Login-Sichtbarkeit (bleibt OP-DOCS-4/-5); (g) Glossar.md im Ordner glossar/ ⇒ Docusaurus-Index-Route /docs/glossar/ (Dateiname == Ordnername) — Navbar/Client-Links darauf gesetzt. Verifikation: npm install + npm run build (Docusaurus) grün; Sprechblasen in 21 Doku-Seiten gerendert (CP-SAT auf 8 Seiten inkl. HANDOFF), Glossar-Anker (#cp-sat …) vorhanden, Client-Popover gebündelt, Remark-Logik per Standalone-Test geprüft (Heading/Link/Code übersprungen, Wortgrenze, Longest-Match). Verbleibende Broken-Link-Warnungen sind vorbestehend/dual-kontextuell (Landkarte/Lesepfade → repo-root ../HANDOFF.md/../README.md GitHub-relativ; brechen den Build nicht, onBrokenLinks: 'warn'). Doku: docs-site/src/glossar/glossar.mjs, scripts/gen-glossar.mjs, src/remark/glossarTooltips.mjs, src/clientModules/glossarTooltip.js, src/css/custom.css, docusaurus.config.js, package.json; docs/glossar/Glossar.md (generiert) + _category_.json; docs/zielgruppen/Lesepfade.md + _category_.json; docs/README.md, HANDOFF (§2 + OP-DOCS-10), CHANGELOG, Timesheet. Kein Solver-Redeploy, kein App-Code.
  • Branch claude/sync-bot-token-doc (PR folgt) — OP-PM-2 doc: SYNC_BOT_TOKEN-Setup dokumentiert + Status auf ✅ geschlossen (Doku-only → kein Version-/Build-Bump, Doku-Fast-Track). Nutzer-Wunsch (Folge zu #222): Setup-Anleitung für das optionale SYNC_BOT_TOKEN festhalten. Gebaut: docs/konventionen/agents.md §6.6 erhält einen „Setup SYNC_BOT_TOKEN"-Block — warum (Default-GITHUB_TOKEN-Push triggert keine PR-CI, GitHub-Loop-Schutz), wie (fine-grained PAT, nur drkv-com/taktano, Contents R/W + Pull requests R/W; alternativ GitHub-App-Token; klassischer PAT braucht workflow-Scope für Workflow-Dateien), wo (Settings → Secrets → Actions, oder gh secret set), Compliance (OP-SEC-1/Risikoregister: Ablauf + Rotation, breite PATs meiden). Inline-Befehlspfad in §6.6 Maßnahme 5 auf Repo-Root-Form node scripts/smooth-logs.mjs vereinheitlicht. Status: „Allow auto-merge" wurde vom Nutzer aktiviert (an #222 live verifiziert: Auto-Merge-Squash feuerte auf CI-Gate-grün) → OP-PM-2 in HANDOFF auf ✅ umgesetzt geschlossen (letzter offener Repo-Setting-Punkt erledigt). Verifikation: check-doc-consistency.sh grün; smooth-logs:check grün. Kein Code-/Solver-Change. Doku: docs/konventionen/agents.md (§6.6), HANDOFF (OP-PM-2), CHANGELOG, Timesheet (Session 2026-06-27-concurrent-prs-merges). True North: indirekt (Governance/Audit-Bereitschaft).
  • #222OP-PM-2: Concurrent-PR-Handling — Log-Glätter + Auto-Sync-Workflow + „GitHub-kann-nicht-union-mergen"-Befund (CI/Tooling/Doku-only → kein App-Version-/Build-Bump, APP_VERSION bleibt 0.14.4; Build auto-gestempelt). Nutzer-Aufgabe: „we need to handle concurrent prs and merges". Die OP-PM-2-Infrastruktur (union-Merge-Logs · Auto-Build-Nummer · branch-abgeleitete Session-IDs · check-doc-consistency.sh-Flags) war da — diese PR schließt die Lücken. (A) Log-Glätter scripts/smooth-logs.mjs (npm run smooth-logs / :check, in server/; bzw. vom Repo-Root node scripts/smooth-logs.mjs): macht das bislang manuelle Glätten der union-Duplikate zum Befehl — entfernt byte-identische Duplikate verlustfrei (CHANGELOG-Eintragszeilen · Timesheet-Session-Zeilen, Zahl- und Datum-Slug-ID; erste Vorkommnis bleibt), meldet nur Mehrdeutiges (Konflikt-Marker-Reste · gleiche Session-ID mit abweichendem Inhalt), sortiert bewusst nicht um; --check = schreibfreier Dry-Run (Exit 1 bei Bedarf). EOL-erhaltend (kein CRLF→LF-Churn). Komplement zum nur-flaggenden check-doc-consistency.sh (das jetzt darauf hinweist). (B) Befund (verifiziert): GitHubs server-seitiger Merge — Update branch-Button, update-branch-API und die Mergeability-Berechnung — wendet merge=union nicht an; derselbe main-Merge, der lokal sauber durchläuft, wird server-seitig mit 422 merge conflict abgelehnt, log-berührende PRs bleiben dirty. union greift also nur lokal. Dokumentiert in .gitattributes, agents.md §6.6 (Maßnahme 5) und HANDOFF (OP-PM-2 Pkt 7). (C) Workflow .github/workflows/sync-pr-logs.yml — macht den nötigen lokalen union-Merge + smooth-logs + Push + PR-Kommentar per Knopfdruck (Auslöser /sync-logs-Kommentar oder workflow_dispatch); guards Fork/nicht-offen, bricht bei echten Konflikten ab (smooth-logs-Fehler stoppt den Job, kein || true), least-privilege; optionales Secret SYNC_BOT_TOKEN (PAT) für CI-Re-Trigger (Default-GITHUB_TOKEN-Push löst keine neue PR-CI aus). Entscheidungen: (a) nur verlustfreie Auto-Fixes (Mehrdeutiges wird gemeldet, nicht geraten); (b) kein CI-Block (Agenten-Werkzeug, warnt/fixt); (c) keine Umsortierung; (d) explizite Auslöser für den Auto-Sync (keine Push-Loops); (e) actions/checkout@v7 beibehalten = Repo-Konvention (ci.yml/weekly-audit/docs-deploy/fly-deploy nutzen durchweg @v7/@v6; CodeRabbits „v7 unpublished" ist für dieses Repo/Stand ein False-Positive). Nebenbei (gleiche Session): offene PRs abgearbeitet — #221 (Owner) gemergt; #213 (upload-artifact 4→7, CI-Gate grün, SBOM-Job nutzt v7) + #214 (ortools-Floor >=9.10>=9.15.6755, vorher lokal auf main gehoben, Solver-Selbsttest grün) squash-gemergt; #220 (Glossar) parallele Session belassen. Repo-Settings (§6.7): delete_branch_on_merge/main-Protection/Squash ✅ (per MCP); „Allow auto-merge" vom Nutzer aktiviert (war der offene OP-PM-2-Punkt). CodeRabbit-Review #222 adressiert: Befehlspfad (node scripts/… statt root-npm run), || true entfernt (smooth-logs-Fehler surfacen), CHANGELOG auf einen PR-Eintrag konsolidiert, EOL-Erhaltung in smooth-logs.mjs; checkout@v7 begründet beibehalten. Verifikation: smooth-logs-Synthetik-/Real-Test + sauberes --check; sync-pr-logs.yml YAML-validiert; lokaler union-Merge real auf #220 und diesem Branch (keine Log-Duplikate); check-doc-consistency.sh grün. Kein Solver-/Worker-Redeploy. Doku: scripts/smooth-logs.mjs, .github/workflows/sync-pr-logs.yml, .gitattributes, server/package.json, scripts/{check-doc-consistency,session-start-hook}.sh, docs/konventionen/agents.md (§6.6), CLAUDE.md (§Repo), HANDOFF (OP-PM-2), CHANGELOG, Timesheet (Session 2026-06-27-concurrent-prs-merges). True North: indirekt (Governance — reibungsärmere, korrektere parallele Merges).
  • #221OP-DEVTOOL-1 erfasst: CodeRabbit ↔ MCP-Integration als offener Punkt (Doku, kein Code → kein Version-/Build-Bump, Präzedenz #203/#198). Nutzer-Frage 06-27: „Können wir CodeRabbit als MCP integrieren?" → recherchiert + als OP-DEVTOOL-1 geparkt (keine Umsetzung jetzt). Zwei Richtungen festgehalten: (1) CodeRabbit als MCP-Client (offiziell GA) — zieht MCP-Kontext in die PR-Reviews, konfiguriert per Dashboard + versionierter .coderabbit.yaml, ephemeral/zero-retention, Pro-Feature, braucht gehostete Remote-MCP-URL; (2) CodeRabbit als MCP-Server (community bradthebeeble/coderabbitai-mcp, MIT) — exponiert PR-Review-Kommentare als MCP-Tools für Claude Code, braucht GitHub-PAT. Befund Repo-Stand: CodeRabbit reviewt bereits PRs, aber keine versionierte .coderabbit.yaml (Review-Config nur im Dashboard → Everything-as-Code-Lücke). Empfehlung: (i) kleiner Schritt zuerst — versionierte .coderabbit.yaml (Vorbedingung Richtung 1); (ii) Richtung 1 = besserer Fit, falls Pro + nützlicher Kontext-Server; (iii) Richtung 2 hier nicht empfohlen (dupliziert vorhandenen GitHub-MCP + inoffizielles-Tool-mit-PAT-Risiko → Risikoregister/OP-COMPLIANCE-1/OP-SEC-1). Offene Entscheidungen (Nutzer): CodeRabbit-Plan (Pro?) + gewünschter Review-Kontext (GitHub/Cloudflare/intern). True North: Dev-Prozess-Tooling, kein direkter Auslastung/Standort/Kapazität-Beitrag → niedrige Priorität. Kein Code/Solver-Redeploy. Doku: HANDOFF (OP-DEVTOOL-1), CHANGELOG, Timesheet (Session 2026-06-27-coderabbit-mcp-integration-xm9zpu).
  • Branch claude/merge-churn-reduction-vo24s7 (PR folgt) — Doku-Fast-Track: reine Doku-PRs überspringen die schwere CI + Auto-Merge (CI/Tooling-only → kein App-Version-/Build-Bump; Build ist seit OP-PM-2/#210 auto-gestempelt, APP_VERSION bleibt 0.14.4 (main-Stand)). Nutzer-Wunsch: „Simple Commits (z. B. Timesheet-Fix) direkt auf main?" → Antwort: nicht Direkt-Push (würde den Audit-/PR-Nummern-Trail und CI-Gate löchern), sondern ein dokumentierter Fast-Track über Branch+PR mit fast null Friktion. Gebaut (.github/workflows/ci.yml): (1) neuer changes-Job (dorny/paths-filter@v3, predicate-quantifier: 'every') erkennt docs-only = jede geänderte Datei liegt unter docs/ oder ist *.md; (2) die schweren Jobs (server/client/solver-service/design-gate/sbom/security-audit) sind auf needs: changes + if: code == 'true' gegated → bei docs-only übersprungen; (3) neuer aggregierter Job CI Gate (if: always(), needs alle schweren Jobs) = einziger Required-Check: grün, solange kein benötigter Job fehlschlägt (skipped = ok) → ein Doku-PR ist mergebar/auto-mergebar ohne die App-CI zu binden; (4) deploy entfällt bei docs-only-main-Push automatisch (kein Redeploy für reine Doku). Entscheidungen: (1) Branch+PR auch für Doku (kein Direkt-Push) — lückenloser Audit-/CHANGELOG-Trail schlägt Bequemlichkeit; statt Bypass eine friktionsarme Spur; (2) CI Gate als einziger Required-Check (Aggregator-Muster) löst das „skipped Required-Check blockt Merge"-Problem sauber; (3) breite Doku-Definition (**/*.md + docs/**, nicht nur Root) — auch design/*.md/HANDOFF.md etc. zählen; (4) Mergify/Tooling verworfen für heute — natives GitHub (Squash + Auto-Merge + ggf. Merge-Queue) deckt den „pr-weise"-Flow ohne neuen Auftragsverarbeiter (DSGVO Art. 28) ab; (5) komplementär zu OP-PM-2/#210 — dieses PR senkt CI-Kosten/Merge-Mechanik, #210 verhindert Log-/Build-Konflikte an der Wurzel (zwei Hälften derselben Churn-Story). Repo-Voraussetzung (Admin, nicht im Code): Branch-Protection von main auf nur CI Gate umstellen + „Allow auto-merge" aktivieren (sonst greift der Fast-Track technisch nicht). Verifikation: ci.yml YAML-validiert (10 Jobs inkl. changes/ci-gate); auf den neuen main (#210/#211) gemergt — koexistiert mit doc-consistency, gated auch security-audit, manueller Build-Bump verworfen (OP-PM-2 Auto-Stamp). Doku: agents.md §7 (Doku-Fast-Track-Regel + Footer), HANDOFF (§2), CHANGELOG, Timesheet (Session 46). Kein Solver-Redeploy.
  • #218Doku/Tooling: sprechende Session-IDs (OP-PM-2) + Zertifizierungs-/Compliance-Tracker (OP-COMPLIANCE-1) (Doku/Tooling-only → kein Version-/Build-Bump). Zwei Nutzer-Wünsche. (1) „Session-ID sprechend gestalten → weniger Konflikte": Die fortlaufende Timesheet-Session-Zahl kollidierte bei parallelen Branches (jeder griff „die nächste Nummer" → union-Merge erzeugte Duplikate → Hand-Umnummerierung, zuletzt 50→52). Umstellung auf branch-abgeleitete ID <Datum>-<branch-slug> (z. B. 2026-06-27-sprechende-session-ids): der Branch-Name ist git-weit eindeutig → die ID kann nicht kollidieren, der union-Merge konkateniert nur. Sprechend (Datum=wann, Slug=was) + chronologisch sortierbar; Alt-Sessions 0…52 behalten ihre Zahl (nicht rückwirkend umgeschrieben, CHANGELOG-Verweise bleiben gültig). scripts/check-doc-consistency.sh 3b generalisiert: Dublettencheck erfasst jetzt beide ID-Formen (Zahl und Datum-Slug), Datum-only-Rückblickzeilen ausgeschlossen. (2) „Tracker bzgl. ISO-Zertifizierung / Compliance DSGVO aufnehmen": docs/betrieb/Compliance.md erhält einen At-a-glance-Tracker „Zertifizierungs-/Compliance-Tracker (lebend)" — Statustabelle C-01…C-16 (ISO/IEC 27001/ISMS · Datenschutz DSGVO/BDSG/DSG/revDSG · TÜV/Produkt- & IT-Sicherheit · E-Rechnung · Security-Audit) mit Status (☐ offen/◐ in Arbeit/☑ erfüllt) · git-nahem Beleg · nächstem Schritt · OP-Bezug; Review-Takt = je Session-/PR-Beginn, neue Themen als Zeile ergänzen. Ersetzt die bisherige Prosa-Bereitschafts-Checkliste durch die strukturierte Tabelle. SBOM-Frage des Nutzers beantwortet: SBOM ist dokumentiert (Compliance.md §SBOM + CLAUDE.md §Compliance) → im Tracker C-05 = ☑ (CycloneDX-CI sbom + Dependabot + npm/pip-audit-Gates + CodeQL Default Setup; offen: Solver-CycloneDX + signierte Release-SBOM). Entscheidungen: (a) ID branch-abgeleitet statt Zahl (Kollisionsfreiheit by construction, kein Renumber mehr); (b) Bestand nicht rückwirkend umschreiben; (c) Tracker als kanonische Statustabelle, Detail in OPs/§SBOM. Verifikation: check-doc-consistency.sh grün (keine toten Links, ID-Dublettencheck ohne Falsch-Positive auf Datum-Zeilen). Kein Code-/Solver-Change. Doku: docs/betrieb/Timesheet.md, docs/betrieb/Compliance.md, docs/konventionen/agents.md (§6.6), CLAUDE.md, scripts/{check-doc-consistency.sh,session-start-hook.sh}, HANDOFF (OP-PM-2/OP-COMPLIANCE-1), CHANGELOG, Timesheet (Session 2026-06-27-sprechende-session-ids). True North: indirekt (Governance/Audit-Bereitschaft + reibungsärmere Doku-Pflege).
  • #217Bugfix: Foto-Schutz — erneutes Markieren nach dem ersten Verpixeln ging nicht (Version 0.14.3 → 0.14.4 PATCH). Nutzer-Report (iPad): „Nachdem das erste Mal Bereiche markiert und verpixelt wurden, funktioniert das neue Markieren nicht mehr." Ursache: Das Flag verpixelt blieb nach dem Verpixeln dauerhaft true und wurde an drei Stellen als Guard missbraucht (boxenProzent(), syncOffeneBoxen(), der Gate-Input in analysiere() verpixelt ? [] : …) → alle danach gezogenen Markierungen wurden ausgeblendet/ignoriert (kein Box-Overlay, kein „Verpixeln"-Button). Fix: die drei verpixelt-Guards entfernt (sie dürfen neue Markierungen nicht blocken) und in verpixelnJetzt() nach dem Einbrennen die Boxen-Listen geleert (manuelleBoxen/autoTreffer → leer, da ins Bild eingebrannt) → frischer Zustand für die nächste Runde. verpixelt steuert weiterhin nur das Upload-Label „(verpixelt)" und die ehrliche-Befund-Logik (piiUngeprueft). Verifikation: echter Browser-Test (Chromium/Playwright headless): markieren → verpixeln (Button verschwindet) → erneut markieren → Verpixeln-Button und Box-Overlay wieder da. Plus ng build + No-Hex grün. Reiner Client-Pfad — kein Server-/Solver-Change (nur version.ts). Doku: CHANGELOG, Timesheet (Session 52). True North: Bedienbarkeit des Foto-Schutzes (mehrfaches Markieren/Verpixeln pro Bild).
  • Branch claude/codeql-default-setup-docs (PR folgt) — OP-SEC-1/OP-SBOM-1: CodeQL via GitHub Default Setup aktiviert + Agenten-Instruction für nicht-automatisierbare Checks (Doku/Tooling-only → kein App-Version-/Build-Bump). Nutzer: Code scanning als Default Setup aktiviert (+ Squash-only/auto-merge/auto-delete bestätigt); zusätzlich „für alle Checks, die nicht per MCP laufen, eine Agenten-Instruction zum Prüfen". Gebaut: (1) CodeQL-Status korrigiert von „blockiert" → ✅ aktiv via Default Setup (TS+Python automatisch, PR/Push, null Wartung; kein eigener codeql.yml — advanced + default schließen sich aus) in RISK-4, Compliance, Observability §6, HANDOFF (OP-SBOM-1), Sanity-Checkliste. (2) scripts/check-security-setup.sh angepasst: fehlender CodeQL-Workflow ist jetzt korrekt (ℹ️ Default Setup) statt ⚠️; echter Status weiter best-effort via gh (default-setup state). (3) Neue verbindliche Agenten-Instruction docs/konventionen/agents.md §6.7 „Nicht-automatisierbare Checks (nicht per MCP/Skript prüfbar)": Repo-Settings (Squash-only · allow_auto_merge · delete_branch_on_merge · Code-Scanning-Modus · Branch-Protection) + semantische Doku-Konsistenz → bei Session-Start/vor PR per gh api ODER Rückfrage beim Nutzer verifizieren, Abweichungen melden; gespiegelt als Punkt 6 in den SessionStart-Hook scripts/session-start-hook.sh. Entscheidungen: (a) Default Setup statt eigenem Workflow (Nutzer-Wahl — empfohlen, wartungsfrei, deckt TS+Python); (b) nicht-per-MCP-prüfbare Kontrollen werden Agenten-Pflicht (kein Skript ersetzt sie), verankert in agents.md + SessionStart-Hook + Sanity-Checkliste. Log-Hygiene: #215-Eintrag von „(PR folgt)" auf [#215] gezogen. Verifikation: bash -n + lokaler Lauf von check-security-setup.sh grün (CodeQL jetzt ℹ️ statt ⚠️); check-doc-consistency grün. Kein Solver-/Worker-Redeploy. Doku: docs/konventionen/agents.md (§6.7), scripts/{check-security-setup.sh,session-start-hook.sh}, docs/betrieb/{Risikoregister,Compliance,Sanity-Checkliste}.md, docs/architektur/Observability.md, HANDOFF, CHANGELOG, Timesheet (Session 51).
  • #215OP-SEC-1/OP-SBOM-1/RISK-4: Wöchentlicher Security-/Setup-Sanity-Lauf (CI/Tooling+Doku-only → kein App-Version-/Build-Bump). Nutzer-Wunsch: „weekly run an audit if all is set + als Sanity-Check dokumentieren". Gebaut: (1) .github/workflows/weekly-audit.yml — Cron Montags 06:37 UTC + workflow_dispatch (manuell); fährt die Vuln-Audits zeitgesteuert neu (npm audit --omit=dev --audit-level=high Server/Client + pip-audit Solver = blockierend; voll-Audit inkl. Dev informativ) → fängt neu bekannt gewordene Advisories auf unveränderten Deps, ohne dass ein Push/PR nötig ist (Zeit-Achse zum push/PR-Gate security-audit). (2) scripts/check-security-setup.sh — Setup-Sanity „ist alles gesetzt?": prüft Dependabot-Config · CI-Jobs security-audit+sbom · gepinnte Actions (kein @main/@master/@latest) · CodeQL-Workflow · und best-effort via gh die Repo-Settings allow_auto_merge/delete_branch_on_merge/Code-Scanning-Status; warnt, blockt nicht (Exit 0, ::warning:: + Markdown-Report in die Step-Summary), lokal aufrufbar. (3) Doku als Sanity-Check: neuer Abschnitt „Security-/Setup-Sanity (wöchentlich)" in docs/betrieb/Sanity-Checkliste.md (Prüf-Tabelle + bekannte offene Punkte) + Verweise in Compliance/HANDOFF. Entscheidungen: (a) GitHub-Actions-Cron statt externer Scheduler (Everything-as-Code, lebt im Repo); (b) Vuln-Audit blockierend, Setup-Sanity warnend (Konvention wie doc-consistency); (c) least-privilege permissions: contents:read. Verifikation: bash -n + lokaler Lauf grün (Exit 0; flaggt korrekt die zwei realen offenen Punkte ungepinnte flyctl-actions@master und fehlendes CodeQL/Code-Scanning); yaml.safe_load für den Workflow valide; check-doc-consistency grün. Kein Solver-/Worker-Redeploy. Doku: .github/workflows/weekly-audit.yml, scripts/check-security-setup.sh, docs/betrieb/Sanity-Checkliste.md, docs/betrieb/Compliance.md, HANDOFF (OP-SBOM-1), CHANGELOG, Timesheet (Session 50). True North: indirekt (Betriebssicherheit/Compliance-Governance).
  • #212Foto-Schutz: Touch/Pencil-Markierung am iPad + ehrliche Befund-Box ohne Auto-Erkennung (Version 0.14.2 → 0.14.3 PATCH; Build-Nummer auto-gestempelt, OP-PM-2). Zwei Nutzer-Reports am echten Gerät. (1) Touch/Pencil-Markierung am iPad ging nicht: der Aufzieh-Rahmen nutzt Pointer-Events, aber ohne touch-action: none schluckte der Browser die Geste (Scroll/Zoom) und ohne Pointer-Capture brach das Ziehen ab, sobald der Finger das Element verließ. Fix: am Zeichen-Wrapper [style.touch-action]="zeichnend() ? 'none' : 'auto'" + setPointerCapture(pointerId) in ziehStart + ev.preventDefault() (down/move) + (pointercancel)-Handler. (2) Grüne „Freigegeben — keine Beanstandung"-Box war irreführend, wenn die Auto-Erkennung NICHT lief: ein Selfie mit Gesichtern wurde als „keine Beanstandung" angezeigt, obwohl Personen/Kennzeichen mangels gehosteter Modelle gar nicht geprüft wurden. Fix: neue Anzeige-Helfer anzeigeFarbe/anzeigeLabel/anzeigeMeldungen — bei Status ok und noch nicht verpixelt und kein echter PII-Detektor erfolgreich gelaufen (piiAutoGeprueft = PII-spezifisches Signal, nicht der geteilte autoStatus — ein NSFW-Fehler darf nicht „PII ungeprüft" suggerieren; CodeRabbit-Review #212) wird die Box amber „Bitte prüfen" mit Klartext „Personen/Kennzeichen wurden NICHT automatisch geprüft — bitte ggf. selbst markieren und verpixeln" (statt grün „Freigegeben"); NSFW-/Qualitäts-Blockaden unberührt, Upload bleibt erlaubt (nur Hinweis). Verifikation: echter Browser-Test (Chromium/Playwright headless): (a) Touch-PointerEvent-Drag (pointerType:'touch') erzeugt eine Markierung → „verpixeln"-Button erscheint; (b) Befund-Label bei inaktiver Erkennung = „Bitte prüfen" (nicht „Freigegeben"). Plus ng build + No-Hex grün. Reiner Client-Pfad — kein Server-/Solver-Change (nur version.ts). Doku: CHANGELOG, Timesheet (Session 49). True North: Bedienbarkeit am Touch-Gerät + ehrliche Datenschutz-Aussage (keine falsche Entwarnung).
  • Branch claude/sonarqube-sentry-snyk-eval-5eag1a (PR #211) — OP-SEC-1/OP-SBOM-1/RISK-4: Security-Quick-Wins GitHub-nativ (Dependabot · npm-audit/pip-audit-Gate; CodeQL durch Repo-Setting blockiert) (CI/Tooling-only → kein App-Version-/Build-Bump). Nutzer-Wunsch: „Quick wins direkt". Schließt die im Werkzeug-Befund (06-27) empfohlenen kostenlosen Lücken — ohne Drittanbieter/Quellcode-Export (DSGVO-arm). Gebaut: (1) .github/dependabot.yml — wöchentliche Updates für npm (Server+Client), pip (Solver) und github-actions; Patch/Minor gruppiert (PR-Lärm), Major einzeln. (2) CI-Job security-audit (ci.yml): blockierender Gate npm audit --omit=dev --audit-level=high für Server+Client (= das ausgelieferte Risiko) + pip-audit für den Solver; voll-Audit inkl. Dev informativ (nicht-blockierend); least-privilege permissions: contents:read. CodeQL (3) gebaut → wieder entfernt: der CodeQL-Workflow (TS+Python, security-and-quality) scheiterte beim SARIF-Upload mit Code Security must be enabled for this repository to use code scanningCode Scanning ist im Repo nicht aktiviert (privat = GitHub Advanced Security), eine Admin-Repo-Einstellung. Workflow entfernt; Follow-up (Admin): Code Scanning aktivieren → CodeQL re-aktivieren (1 Datei). Empirisch verifiziert (vor Push): Produktiv-Deps Server+Client sauber (high+), Solver pip-audit keine Vulns → Gates grün; npm audit läuft ohne npm ci nur mit Lockfile (im CI bestätigt). Entscheidungen: (1) Gate auf --omit=dev — die 4 vorhandenen High-Vulns (undici/ws via Wrangler/Miniflare) sind Dev-Toolchain, werden nicht in den Worker gebündelt → dürfen CI nicht brechen; sie laufen über Dependabot-PRs ein und sind im informativen Voll-Audit sichtbar (kein silent cap). (2) GitHub-nativ statt Snyk/SonarQube (Befund 06-27: gratis, kein Code-Export). (3) Audit-Gate blockiert PR/CI, aber NICHT deploy.needs (CodeRabbit-Review + Availability: ein nicht-patchbares Prod-Advisory soll keine main-Deploy-Sperre auslösen; neue Advisories werden via CI auf main trotzdem rot sichtbar). (4) kein App-Bump (reine CI/Tooling-Änderung, kein Runtime-Verhalten). CodeRabbit-Review adressiert: least-privilege permissions ergänzt; Deploy-Deadlock-Risiko durch Entfernen aus deploy.needs gelöst. Verifikation: yaml.safe_load valide; Audit-Gates lokal grün; Merge mit main (4 zwischenzeitliche PRs) konfliktfrei aufgelöst (union-Logs, Session-Renumber 45→48). Doku: .github/{dependabot.yml,workflows/ci.yml}, docs/betrieb/Compliance.md, docs/betrieb/Risikoregister.md (RISK-4 → gemindert, Score 6→4), docs/architektur/Observability.md §6, HANDOFF (OP-SBOM-1), CHANGELOG, Timesheet (Session 48). Kein Solver-/Worker-Redeploy aus diesem Commit.
  • Branch claude/sonarqube-sentry-snyk-eval-5eag1a (PR folgt) — OP-OBS-1: Backend-Kandidaten bewertet + Grafana/Sentry-Vergleich festgehalten; SonarQube/Snyk-Befund (Doku-only → kein Version-/Build-Bump, Präzedenz #205/#206/#198/#203). Nutzer-Fragen 06-27: „Hilft uns SonarQube/Sentry/Snyk?" + „Wie könnte Grafana helfen?". Neue Doku docs/architektur/Observability.md (Muster Audit-Log.md/Kosten.md) hält die offene OP-OBS-1-Backend-Wahl als bewertete Kandidaten fest: Grafana (LGTM: Loki/Tempo/Mimir/Faro/Alerting, self-host bevorzugt)Sentry (Crash-DX, EU-Region+Scrubbing) als zwei Hauptoptionen, Cloudflare-nativ nur als Worker-Ergänzung (deckt Client+Solver nicht), Honeycomb zurückgestellt (US-Residenz). Alle über OTLP code-frei austauschbar (kein Lock-in). Empfehlung: Grafana self-hosted (EU-Datenhoheit, analog Better-Auth OP-AUTH-1) oder Grafana Cloud EU; Wahl Grafana↔Sentry offen (User-Entscheidung). Scope-Leitplanke dokumentiert: technische OTel-Telemetrie ≠ Cockpit/True-North-Dashboards (gehören in die App, Selbsterklärbarkeit) ≠ Kosten-Dashboard (OP-COST-1)Audit-Log (OP-AUDIT-1). Begleit-Befund (SonarQube/Snyk): echte, aber zuerst gratis & GitHub-nativ zu schließende Lücken — Snyk → Dependabot+CodeQL+npm audit/pip-audit (RISK-4), SonarQube → ESLint+ruff/mypy+CodeQL (Lint-Gate), beide ohne Quellcode-/Dependency-Export (DSGVO-arm); externe Tools erst später als Komfort/Audit-Dashboard. Entscheidungen: (1) eigenes Architektur-Dok statt nur HANDOFF-Zeile (festgezurrte Bewertung, Muster architektur/); (2) Grafana self-host bevorzugt wegen EU-Residenz (Compliance + Verkaufsargument); (3) Sicherheits-Tools GitHub-nativ vor SaaS; (4) Doku-only → kein Bump. Doku: docs/architektur/Observability.md (neu), HANDOFF (OP-OBS-1), docs/README.md (Landkarte), CLAUDE.md (Tiefenquellen), docs/betrieb/Compliance.md (SBOM/Security-Befund), docs/betrieb/Risikoregister.md (RISK-4), CHANGELOG, Timesheet (Session 48). Kein Code/Solver-Redeploy.
  • #210OP-PM-2: Merge-Churn der parallelen PRs entschärfen (union-Merge · Auto-Build-Nummer · Log-Hygiene) (Tooling/Doku, kein App-VerhaltenAPP_VERSION unverändert 0.14.2). Auslöser: Beim Mergen von #207 lief main 4× weiter (#205/#206/#208/#209) → Dauer-Konflikte in den append-only Logs plus Build-/Versions-Kollisionen (jede PR bumpte version.ts von Hand). Nutzer: „1+2+3" + „regelmäßig Logs checken/glätten, alles dokumentieren". Gebaut: (1) .gitattributes merge=union für CHANGELOG.md/HANDOFF.md/docs/betrieb/Timesheet.md → parallele PRs konkatenieren statt zu blocken. (2) Build-Nummer automatisch aus Git-Commit-Count: server/src/build-number.ts (auto-gestempelt) + scripts/stamp-build.mjs + predeploy-Hook + Deploy-Checkout fetch-depth: 0; version.ts re-exportiert APP_BUILD und trägt nur noch das manuelle APP_VERSIONkeine Build-Kollision mehr (Umstellung Build 19 → Commit-Count, akt. 165). (4) Log-Hygiene verbindlich (agents.md §6.6 + §5.1, CLAUDE.md): Logs regelmäßig glätten (Session-Start + nach Merges) — scripts/check-doc-consistency.sh flaggt jetzt Marker-Reste · doppelte Timesheet-Session-Nummern · doppelte CHANGELOG-PR-Zeilen (warnt, blockt nicht). (3) Offen (Repo-Setting): GitHub Merge Queue / „Allow auto-merge" aktivieren (Settings → Pull Requests) — war beim #207-Merge deaktiviert; serialisiert Merges. Entscheidungen: Build = Git-Commit-Count (deterministisch/reproduzierbar, fetch-depth:0) statt Run-Number; version.ts bewusst nicht union (SemVer-Konflikt soll sichtbar bleiben). Verifikation: stamp-build (Build 165) + Server-typecheck + check-doc-consistency (inkl. Log-Hygiene) + ng build (prod) grün. Doku: CLAUDE.md (§Repo/§Versionierung), docs/konventionen/agents.md (§5.1/§6.6), .gitattributes, scripts/, HANDOFF (OP-PM-2), docs/betrieb/Timesheet.md. Schließt zudem den Verify-Punkt OP-R9-12 (Nutzer 06-27: „ist ok").
  • #207OP-DOCS-9: Doku-Konsistenz-Check in den Guidelines + Memory + CI (Doku/Tooling, kein App-Code → kein Version-/Build-Bump). Nutzer-Wunsch: Konsistenz-Check der Doku einbauen — in sich und gegen die Implementierung —, im Memory halten und die Guidelines anpassen (mit Rückfrage bei Unklarheiten). Gebaut: (1) Guidelines — Root-CLAUDE.md (Repo-Guiding-Principle) + docs/konventionen/agents.md §5.1 (verbindlicher Doku-Konsistenz-Check, Achsen Doku↔Doku [IDs/Glossar/Workspace-·Phasen-Liste/Status/Version·Build/Querverweise] & Doku↔Code [Feldnamen/Enums/DTOs/Routen/Token, beschriebenes=gebautes & gebautes=beschriebenes]) + §6.5 (Workflow). (2) Memory = SessionStart-Hook scripts/session-start-hook.sh in .claude/settings.json (versioniert, da kein Memory-Tool — agents.md §1). (3) CI scripts/check-doc-consistency.sh + Job doc-consistency (mechanisch: tote Links/Bilder + Version/Build-Single-Source) — warnt, blockt nicht (::warning::, nicht in deploy.needs; Token read-only-scoped + persist-credentials: false per CodeRabbit). Entscheidungen (vom Nutzer gewählt): Cadence Session-Start + je PR; Durchsetzung Guideline + nicht-blockierendes CI-Skript (semantischer Teil bleibt Agenten-Pflicht); „im Memory halten" = Repo-Guideline + SessionStart-Hook. Verifikation: bash scripts/check-doc-consistency.sh lokal grün (keine toten Links, Version/Build eindeutig). Doku: CLAUDE.md, docs/konventionen/agents.md (§5.1/§6.5), HANDOFF.md (OP-DOCS-9), .github/workflows/ci.yml, scripts/, CHANGELOG, docs/betrieb/Timesheet.md.
  • #207Bugfix: linke Rail-Sidebar (Crystal-Bar) lässt sich auf dem iPad/Touch nicht mehr schließen (Version 0.14.1 → 0.14.2 PATCH, Build 18 → 19). Problem (Nutzer-Report, iPad): Die Icon-Rail (client/.../leitstand/shell.component.ts, OP-R9-12) klappt rein per CSS über :hover/:focus-within auf — ein Maus-Konzept. Auf Touch-Geräten gibt es kein echtes :hover (Safari emuliert es, der Zustand „klebt" bis zum Tap woanders) und :focus-within bleibt aktiv, sobald ein Nav-Link den Fokus hält → das Panel bleibt dauerhaft offen und legt sich (per absolute) über den Inhalt; kein Toggle, kein Backdrop → nicht schließbar. Fix (pointer-abhängiges Konzept): (1) Proximity-Reveal (:hover/:focus-within) nur noch für Feinzeiger (@media (hover: hover) and (pointer: fine)) — Desktop/Trackpad unverändert. (2) Geräteunabhängiger expliziter Aufklapp-Zustand über .railwrap.is-open, getrieben von einem neuen Signal expanded(). (3) Touch-Toggle (☰/✕) oben in der Rail, nur auf Grobzeiger-/Touch-Geräten sichtbar (@media (hover: none), (pointer: coarse)). (4) Backdrop (.tk-railscrim, token-gefärbt, kein Hex) bei offenem Touch-Overlay → Tap schließt. (5) Auto-Einklappen beim Navigieren (Kopplung an NavigationEnd). (6) a11y: der Hintergrund-Inhalt wird bei offenem Overlay inert (Fokus bleibt in der Crystal-Bar; CodeRabbit-Review). Die schmale 84px-Icon-Rail bleibt im Ruhezustand immer sichtbar (Selbsterklärbarkeit). Entscheidungen: (a) Hover-Reveal behalten, wo es passt (Maus), expliziter Toggle, wo nötig (Touch); (b) Default-Touch = schmale Icon-Rail; (c) Schließen über Toggle, Backdrop und Navigation. Verifikation: ng build (prod) + No-Hex-Gate grün (iPad-Augenschein durch Nutzer offen — Playwright im Cloud-Env nicht installiert). Reiner Client-Pfad — kein Server-/Solver-Change (nur server/src/version.ts bumpt). Doku: CHANGELOG, HANDOFF (OP-R9-12), docs/betrieb/Timesheet.md. True North: Bedienbarkeit des Cockpits auf dem iPad/Touch.
  • #207Doku-Nachzug zum Crystal-Bar-Fix: Begriff, Screenshots, Verify-Punkt, wöchentliche Management-Summary, Jira-OP (Doku-only, kein Code → kein Version-/Build-Bump). Nutzer-Wünsche im Anschluss an den iPad-Fix: (1) Verify-Punkt „Ist das Verhalten der Toolbar so gut?" als offener Prüfpunkt am echten iPad/Touch in HANDOFF (OP-R9-12) festgehalten (Toggle-Auffindbarkeit, Schließwege, Touch-Default, Quer-/Hochformat). (2) Begriff „Crystal-Bar" für die linke Navigations-Rail eingeführt — Glossar docs/fachlich/Lastenheft.md §13 + ausführlicher Abschnitt in design/WORKSPACES.md (pointer-abhängiges Verhalten Maus↔Touch). (3) Screenshots mit Einordnung der Bereiche: 3 reale Zustände (Ruhe-Icon-Rail · aufgeklappt · Touch-Overlay mit Backdrop) aus dem laufenden Client (Chromium/Playwright, Media-Emulation pointer/hover) in design/assets/crystal-bar/, eingebettet in WORKSPACES.md mit Regionen-Legende (Logo · Cluster Überblick/Operativ/Steuerung/Qualität/Wirtschaftlichkeit · Workspace-Badges · Theme · Auf-Kurs-Ring · Live-Status · Touch-Toggle). (4) Timesheet zeigt jetzt wer gearbeitet hat (Beteiligte = MK + Claude, KI-Pair-Programming; Methodik-Bullet) + wöchentliche Management-Summary (KW-Tabelle mit Aufwand/Schwerpunkten/Versionsstand) + 2 Grafiken (Mermaid xychart-beta: Aufwand je KW und je Tag KW26 — versioniert/diff-bar, keine Binär-Charts). (5) Neuer OP-PM-1: Task-/Ticket-Pflege später mit Jira synchronisieren (Richtung/SoR/Mapping/Auth/Scope/Audit zu klären) — Vormerkung, kein MVP-Blocker. Entscheidungen: Crystal-Bar als kanonischer Name (Synonyme Icon-Rail/Rail/Sidebar bleiben gültig); Screenshots als PNG-Belege (reale UI) + Mermaid-Grafiken für die Statistik (Everything-as-Code-Prinzip „Markdown + Mermaid"). Verifikation: ng build (prod) + No-Hex grün; beide Mermaid-Charts gegen Renderer validiert. Doku: docs/fachlich/Lastenheft.md §13, design/WORKSPACES.md, design/assets/crystal-bar/, HANDOFF (OP-R9-12 + OP-PM-1), docs/betrieb/Timesheet.md, CHANGELOG.
  • #209Bugfix: Foto-Schutz zeigte das gewählte Bild nicht an (Version 0.14.0 → 0.14.1 PATCH, Build 17 → 18). Nutzer-Report: „Take photo … Foto-Auswahl öffnet, Foto ausgewählt, dann passiert nichts." Ursache: In bild-upload-gate.component.ts greift onDatei() auf this.canvas.nativeElement zu, bevor das Signal geladen auf true gesetzt ist — das <canvas> liegt aber im @else-Zweig (@if (!geladen())) und existiert erst danach im DOM, also war this.canvas zu dem Zeitpunkt undefinedTypeError → das Bild wurde nie gezeichnet (still verschluckt im await). Fix: Reihenfolge umgestellt — erst geladen.set(true) + ChangeDetectorRef.detectChanges() (rendert den @else-Zweig, ViewChild canvas/wrap werden verfügbar), dann zeichnen + analysiere(). Zusätzlich input.value = '' im finally, damit dieselbe Datei erneut wählbar ist (sonst feuert change beim zweiten Mal nicht). Verifikation: echter Browser-Test (Chromium/Playwright headless, statisch geserved): Datei in input[type=file] gesetzt → Canvas rendert mit 800 px, Befund-Panel zeigt „Freigegeben"/„800×600" — vor dem Fix erschien kein Canvas. Plus ng build (prod) + No-Hex grün. Reiner Client-Pfad — kein Server-/Solver-Change (nur version.ts). Doku: CHANGELOG, Timesheet (Session 45). True North: Bedienbarkeit des Foto-Schutzes (Pre-Upload-Gate funktioniert sichtbar).
  • #206Doku-Site: Start-Seite als Produkt-Übersicht + neue Team-Seite (docs-site/, Doku-Site-only → kein App-Version-/Build-Bump, Präzedenz Doku-PRs). Start-Seite (src/pages/index.js): von einer dünnen Doku-Verlinkung zu einer kurzen Produkt-Übersicht umgebaut — Ein-Satz-Positionierung, Herzstück (Taktung-/Reihenfolge-Optimierung Scheduler+CP-SAT, „KI schlägt vor, Mensch entscheidet"), die drei True-North-Leitfragen als Karten und die Werthebel (Effizienz/Durchsatz · Termintreue · Transparenz/Team · Qualität/Doku) als Karten, plus Buttons (Produkt & Nutzen · Lastenheft · Doku-Landkarte · Handoff). Inhaltlich gespiegelt aus docs/produkt/Produkt-und-Marketing.md. Nebenbei behoben: die Start-Seiten-Buttons zeigten nach der OP-DOCS-8-Reorg noch auf /docs/Lastenheft & /docs/datamodel (Regression, da onBrokenLinks: 'warn' den Build nicht brach) → jetzt korrekt /docs/fachlich/…. Team-Seite (src/pages/team.js + Navbar-Item „Team"): Kernteam mit Rolle/Schwerpunkten + Portrait-Avataren (Initialen-Platzhalter mit gewireter foto-Slot → static/img/team/<name>.jpg, Anleitung in static/img/team/README.md) — Dominik May (Fachmann · Gallionsfigur · Netzwerk), Mitarbeiter von Dominik (Prozess-Optimierung · Daily Challenges, Name offen), Holger Queckenstedt (Business Plan · Finance), Dr. Michael Kirchhof (IT · Betrieb); plus To-do-Sektion je Person und seitenweit (u. a. „Rollen und Titel schärfen", „Portrait-Fotos ergänzen", „Name des Mitarbeiters ergänzen"). Verifikation: npm run build (Docusaurus) grün — beide Seiten kompilieren; verbleibende Broken-Link-Warnungen sind vorbestehend/dual-kontextuell (Landkarte ../HANDOFF.md u. a. sind GitHub-relativ; HANDOFF→docs/fachlich/Flow-* im /projekt-Instanz-Kontext) und brechen den Build nicht. Entscheidungen: (1) Start-/Team-Seite als JS-Pages (wie die bestehende index.js) für Portrait-/Karten-Layout, Daten als editierbare Arrays am Dateikopf; (2) kein Hex (Docusaurus-Theme-CSS-Variablen → dark/light-tauglich); (3) Portraits als Platzhalter (keine echten Fotos vorhanden) + To-do statt Fake-Bilder. Doku: docs-site/src/pages/{index,team}.js, docusaurus.config.js (Navbar), static/img/team/README.md, HANDOFF (§2), CHANGELOG, Timesheet (Session 42). Kein Solver-Redeploy.

2026-06-26

  • #205Docs-Struktur optimiert: Doku-Landkarte + physische Unterordner-Gliederung (OP-DOCS-8 ✅; Doku/Kommentar-only → kein Version-/Build-Bump, Präzedenz #182/#185/#188). Problem: docs/ war flach (17 Dateien ohne Gruppierung), die Doku-Site-Sidebar autogenerated/alphabetisch (Master-Spec zwischen Kosten und Produkt), keine Startseite/Navigation. Teil 1 — Landkarte: docs/README.md als kategorisierter Einstieg (je „wann lesen"/OP-Bezug + Session-Start-Reihenfolge + True-North + ID-System); wirkt doppelt (GitHub-Index beim docs/-Browsen und Docusaurus-Startseite der bisher index-losen Site). Teil 2 — physische Reorg (Nutzer-Wunsch „Ja" auf den größeren Umbau): alle 17 Dokumente per git mv (History bewahrt) in 5 thematische Unterordnerfachlich/ (Lastenheft·datamodel·operativmodell·solver·Flow-Analyse·Flow-Refactor-Plan) · architektur/ (Audit-Log·Kosten·Akademie·In-App-Assistent·Billing-Zugang) · betrieb/ (Compliance·Risikoregister·Sanity-Checkliste·Timesheet) · konventionen/ (agents) · produkt/ (Produkt-und-Marketing); docs/README.md bleibt als Index im Root. Je Ordner ein _category_.json (Label + position) → die Docusaurus-autogenerated-Sidebar spiegelt jetzt die Gruppen statt alphabetisch zu mischen. Alle Referenzen nachgezogen: sämtliche klickbaren ](…md)-Links (49 repo-weit, per Skript verifiziert → alle auflösbar) + die aktiven docs/<name>.md-Pfade in HANDOFF/CLAUDE/README/design//Code-Kommentaren (10 Code-Stellen: types.ts/seed.ts/infra.ts/github-billing.ts/insights.ts/leitstand.ts/migrations/wrangler.toml). Entscheidungen: (1) append-only Logs nicht umgeschrieben — historische docs/<name>.md-Erwähnungen in CHANGELOG.md und in den alten Timesheet-Einträgen bleiben als Code-Span-Prosa stehen (kein 404, beschreiben den damaligen Stand) statt revisionistischer Massen-Edits; (2) agents.md + Produkt-und-Marketing.md in eigene 1-Datei-Ordner (Tree 1:1 zu den Landkarte-Kategorien) statt im Root zu belassen; (3) autogenerated Sidebar + _category_.json statt manueller sidebars.js (selbst-pflegend) oder front-matter (verschmutzt Roh-.md auf GitHub). Verifikation: Skript-Check „jeder ](…md)-Link resolved auf eine existierende Datei" grün (49/49); _category_.json valides JSON. Hinweis: der Docusaurus-Build selbst ist in der reinen Doku-Session nicht ausführbar (kein node_modules in docs-site/); onBrokenMarkdownLinks: 'ignore' + die verifizierten Link-Ziele decken das ab — beim nächsten Site-Deploy (OP-DOCS-1 d, Trigger docs/**) gegenprüfen. Folge: publizierte URLs ändern sich /docs/<name>/docs/<ordner>/<name> (interne, Access-gegatete Site → unkritisch). Doku: docs/README.md, docs/*/_category_.json (neu), HANDOFF (§2 + OP-DOCS-8), CLAUDE.md, README.md, betrieb/Timesheet.md (Session 40). Kein Solver-Redeploy.

  • Branch claude/order-assignment-requirement-4bbw4g (PR folgt) — R7-Invariante: „Ohne Zuweisung kann ein Auftrag nicht in Arbeit sein" (Version 0.12.0 → 0.13.0 MINOR, Build 15 → 16). Nutzer-Wunsch: „ohne zuweisung kann ein auftrag nicht in arbeit sein". Zuweisung = mindestens ein produktiv zugeteilter Mitarbeiter an einem (Nicht-Annahme-)Teilschritt; Helfer/Auszubildende (helferIds) zählen nicht (sie tragen die Arbeit nicht), der nicht-solver-geplante Annahme-Doku-Schritt zählt nicht (leere mitarbeiterIds). Gebaut (Domäne, pure): hatZuweisung(auftrag) + Guard in transitionjeder Übergang nach in_arbeit (starten/fortsetzen) verlangt eine Zuweisung, sonst wird er abgelehnt (klare Fehlermeldung); erlaubteAktionen(status, auftrag?) blendet starten/fortsetzen ohne Zuweisung aus (UI-Buttons verschwinden). Server: DTO trägt hatZuweisung; der auftrag.starten-Handler lehnt ohne Zuweisung explizit ab (Doppel-Sicherung). Client (Selbsterklärbarkeit): Badge „⚠ Zuweisung nötig" im Aufträge-Detail, im geteilten Detail-Panel und im Belegungs-Wareneingang; „▶ Aufbereiten starten" ist dort deaktiviert, solange keine Zuweisung besteht. Entscheidungen: (1) Invariante am Lifecycle-Übergang erzwungen (eine Wahrheit, gilt für jeden Aufrufpfad) statt nur in der UI; (2) Guard auf Ziel in_arbeit (deckt starten und fortsetzen) — der Status „in Arbeit" ist nie ohne Zuweisung erreichbar; (3) Helfer ≠ Zuweisung (sie reduzieren die Zeit nicht, sind kein produktiver Träger); (4) kein schemaVersion-Bump (rein additive Logik/Feld, keine Altdaten-Migration). Verifikation: Server-typecheck + operativ-Selbsttest (neuer Zuweisungs-Abschnitt: ohne Zuweisung → starten blockiert + Aktion ausgeblendet; mit Zuweisung → in_arbeit) + ng build (prod) + No-Hex grün. Reiner App-Pfadkein Solver-Redeploy. Doku: docs/Lastenheft.md §5.1 (R7), HANDOFF (R7-Zeile + §3), CHANGELOG, Timesheet.

  • #203OP-COST-4 erfasst: GitHub-Billing-Token-Aktivierung als Pre-Prod-Requirement (Doku, kein Code → kein Version-/Build-Bump). Nutzer-Wunsch: „Aktivierung des GitHub-Tokens als OP erfassen". Der GitHub-Kosten-Pull (OP-COST-2 Slice 1, #202) ist dormant, bis das Secret GITHUB_BILLING_TOKEN gesetzt ist → als eigenes OP-COST-4 = Go-Live-Vorbedingung festgehalten (HANDOFF §4, analog OP-COST-3): wrangler secret put GITHUB_BILLING_TOKEN (Billing/Plan-Read-Scope, minimaler Scope = nur Billing-Read, kein Repo-Schreibrecht; GITHUB_BILLING_ORG/GITHUB_BILLING_REPO bereits als [vars]), danach „↻ GitHub ziehen" → API-Posten. docs/Kosten.md §4 querverweist OP-COST-4. Kein Solver-Redeploy. Doku: HANDOFF (OP-COST-4), docs/Kosten.md §4, CHANGELOG (#203), Timesheet (Session 38).

  • #202OP-COST-2 Slice 1: GitHub als Infra-Kosten-Provider (projekt-bezogener Auto-Pull) (Version 0.11.0 → 0.12.0 MINOR, Build 14 → 15). Nutzer-Wunsch: „zeige auch die projekt-bezogenen Kosten von GitHub an". Erste echte OP-COST-2-Slice (automatischer Provider-Pull statt nur manuell). Gebaut: (1) Modell InfraKostenPosten um quelle:'api'|'manuell' + quelleRef (Idempotenz-Key) — optional → kein Migrations-/schemaVersion-Bump. (2) Pure server/src/kosten/github-billing.ts: mappt die GitHub-Enhanced-Billing-Usage-API (/organizations/<org>/settings/billing/usage, usageItems[].netAmount) je Monat auf einen „GitHub"-Posten, projekt-bezogen auf das Repo gefiltert (repositoryName), Cent/USD; Self-Test in test:kosten (Repo-Filter, Idempotenz, org-weit, null/leer). (3) DO pullGithubKosten()dormant/deploy-sicher (No-op ohne Secret GITHUB_BILLING_TOKEN + GITHUB_BILLING_ORG/GITHUB_BILLING_REPO-[vars], wie der D1-/R2-Pfad) → fetch GitHub → Mapper → idempotenter Upsert (infraKostenUpsert, ersetzt by quelleRef); Pull = OP-AUDIT-1-Event (infraKosten.pull) + Ops-Log (OP-LOG-1). (4) Trigger interim on-demand: admin-gegatete Action infraKosten.pullGithub + Client-Button „↻ GitHub ziehen" + API-Badge an automatisch gezogenen Posten. Entscheidungen: (a) GitHub als erster Provider (explizit gewünscht); (b) on-demand in Slice 1, Cron-Automatik (die „verbindliche Richtung") als Folge-Slice; (c) projekt-bezogen = Repo-Filter; (d) dormant bis Token-Secret (kein Deploy-Bruch, kein Repo-PII); (e) quelle optional → kein schemaVersion-Bump (kollisions-arm bei schnell wandernder main). Aktivierung: wrangler secret put GITHUB_BILLING_TOKEN (Billing/Plan-Read-Scope). Verifikation: Server-typecheck + test:kosten (erweitert) + operativ + test:prozess + ng build (prod) + No-Hex grün. Reiner App-Pfadkein Solver-Redeploy. Doku: docs/Kosten.md §4, HANDOFF (OP-COST-2), server/wrangler.toml, CHANGELOG (#202), Timesheet (Session 37).

  • Branch claude/workflow-reservation-pickup-6m2q37 (PR folgt) — OP-R4-1: Volle Auflösung optional im Hintergrund archivieren (Version 0.10.0 → 0.11.0 MINOR, Build 13 → 14). Nutzer-Wunsch: „als Option volle Auflösung — im Hintergrund". Zweite Stufe nach der Kompression: Standard bleibt der schnelle, komprimierte Upload (Anzeige-Variante); optional (pro Browser gemerkter Toggle „Original in voller Auflösung archivieren (Hintergrund)") wird zusätzlich das unkomprimierte Original ins Archiv geladen — fire-and-forget im Hintergrund, blockiert weder UI noch das Foto-Pflicht-Gate. Zwei-Varianten-Modell: FotoAttachment um originalR2Key/originalContentType/originalGroesseBytes erweitert (r2Key = komprimierte Anzeige-Variante, originalR2Key = Archiv). Korrelation: Client erzeugt die Foto-ID (crypto.randomUUID()) und reicht sie in foto.registriert mit → der Hintergrund-Upload hängt die volle Auflösung per neuer Message foto.original an dasselbe Foto; foto.registriert jetzt idempotent (doppelte ID ignoriert). Worker-Route: POST /api/foto/upload?variante=original legt unter eigenem Key-Pfad …/<perspektive>/original/<uuid> ab, Limit 30 MB (komprimiert weiterhin 15 MB). Optimierung: Original-Upload entfällt, wenn die Kompression das Bild gar nicht verkleinert hat (dann ist die Anzeige-Variante schon das Original). UI: Toggle + „lädt im Hintergrund"-Toast-Hinweis + „HQ"-Badge am Thumbnail (verlinkt die volle Auflösung), sobald der Hintergrund-Upload durch ist. Entscheidungen: (1) Original opt-in (Default aus) — Bandbreiten-/Speicher-schonend by default, volle Auflösung nur wenn bewusst gewählt (Beweis-/Archiv-Qualität); (2) Hintergrund/best-effort statt blockierend — Zustands-Doku darf nicht am Original-Upload hängen; (3) Client-generierte ID für robuste Vordergrund/Hintergrund-Korrelation. Verifikation: Server-typecheck + test:prozess + operativ-Smoke + ng build (prod) + No-Hex grün; lokale Miniflare-R2-Probe (komprimiert + variante=originalfoto.originaloriginalR2Key im DTO + Download der vollen Auflösung) grün. Kein Solver-Redeploy. Offen (Folge): getrennte reduzierte PDF-Auflösung + asynchrones Speichern; KI-Plausibilität weiter DSGVO-geblockt (OP-AI-2).

  • Branch claude/workflow-reservation-pickup-6m2q37 (PR folgt) — OP-R4-1: Client-seitige Bild-Kompression vor dem R2-Upload (Version 0.9.0 → 0.10.0 MINOR, Build 12 → 13). Nutzer-Wunsch: „Kompression vor Upload". Annahme-Fotos kommen i. d. R. direkt von der Handy-Kamera (mehrere MB, 4000+ px Kante); das treibt Upload-Zeit (Werkstatt-WLAN/Mobilfunk), R2-Speicher und R2-Egress beim Anzeigen unnötig hoch. Gebaut: neuer Helfer client/src/app/leitstand/foto-kompression.tskomprimiereFoto(file): dekodiert via createImageBitmap (EXIF-Orientierung from-image), skaliert auf längste Kante 1600 px herunter (kein Hochskalieren), re-encodiert als JPEG q=0.82 über ein <canvas>. Robust/best-effort: Nicht-Bilder, Dekodier-Fehler (z. B. HEIC ohne Browser-Support), fehlendes Canvas oder kein GrößenvorteilOriginaldatei wird unverändert hochgeladen (nie ein Fehler). Eingehängt in LeitstandService.uploadFoto vor dem POST /api/foto/upload (Body + Content-Type = komprimiertes File); der Server liefert die tatsächliche groesseBytes zurück → DO-Metadaten stimmen. Entscheidungen: (1) Kompression im Service (eine Stelle, gilt für alle Aufrufer) statt in der Komponente; (2) Parameter (1600 px / q0.82) als bewusste Fix-Defaults (Detail/Größe-Kompromiss für Zustands-Doku), nicht admin-editierbar; (3) immer Fallback aufs Original statt Upload zu blockieren — Zustands-Doku darf nicht an einem Decoder scheitern. Verifikation: ng build (prod) + No-Hex-Gate grün. Reiner Client-Pfad — kein Server-/Solver-Change (nur version.ts bumpt). Offen (Folge): Server-seitige Größen-/Format-Validierung bleibt unverändert (15 MB / image/*); KI-Plausibilität weiter DSGVO-geblockt (OP-AI-2).

  • Branch claude/op-r4-3-foto-perspektiven (PR folgt) — OP-R4-3 R2-Bucket aktiviert (Config). R2-Bucket taktano-fotos vom Nutzer in EU-Jurisdiction (--jurisdiction eu, DSGVO-Residenz) angelegt; das [[r2_buckets]]-Binding in server/wrangler.toml aktiviert mit jurisdiction = "eu" (Pflicht — EU-Buckets liegen in separatem Namespace; ohne den Zusatz findet der Worker den Bucket nicht). Damit ist der Foto-Upload-/Download-Pfad live, sobald deployed. ⚠️ Vorbedingung Merge→main: der CI-CLOUDFLARE_API_TOKEN braucht R2-Edit-Recht, sonst bricht wrangler deploy (eigener Scope, analog D1 §7.4). Kein Code-Change.

  • Branch claude/op-r4-3-foto-perspektiven (PR folgt) — OP-R4-3 Foto-Upload (R2) + Foto-Gate (Build 10 → 11, Version bleibt 0.8.0 — selbe Feature-PR). Zweite Stufe nach dem Konfig-Modell: echter Foto-Upload + Pflicht-Gate. Attachment-Modell: FotoAttachment (§4.10, polymorphe Ziel-Ref Auftrag+Teilschritt-Instanz + Perspektive; Bytes in R2, Metadaten im DO-State fotos[]) + Helfer fotoPflichtErfuellt. Worker-Routen (hinter Access): POST /api/foto/upload (Bild → R2, max 15 MB, nur image/*, Key fotos/<auftrag>/<instanz>/<perspektive>/<uuid>) + GET /api/foto?key= (Stream aus R2). Deploy-sicher/dormant wie der D1-Pfad: Env.FOTOS?: R2Bucket optional, kein [[r2_buckets]]-Binding committed → ohne Bucket antworten die Routen 503 (kein Deploy-Bruch); Aktivierung dokumentiert in wrangler.toml (Bucket weur anlegen + Binding einkommentieren). DO: Messages foto.registriert (nach Upload, Metadaten persistieren) / foto.entfernen; TeilschrittDTO um fotos[] + fotoPflichtErfuellt; Erledigen-Gate verlangt jetzt zusätzlich erfüllte Foto-Pflicht. schemaVersion 14 → 15 (Foto-Metadaten leer init, idempotent). Client: im Detail-Panel je geforderter Perspektive Aufnahme-Button (<input capture>) + Thumbnails + Zähler n/Soll; „Fertig" blockiert, bis Kommentar und Pflicht-Fotos da sind. uploadFoto/fotoUrl/entferneFoto im Service. Test: test:prozess Abschnitt 9 (fotoPflichtErfuellt). Lokal verifiziert (wrangler dev + Miniflare-R2): Upload→R2, Download, foto.registriert, Gate 5/5→erfüllt — Probe grün. Entscheidungen: (1) deploy-sicher dormant (R2-Provisionierung = bewusste Folge-Aktion); (2) Bilder in R2 (nicht DO-Blob); (3) KI-Plausibilität weiter offen — ⚠️ DSGVO (Bilder an externe API). typecheck + alle Self-Tests + ng build + No-Hex grün. Kein Solver-Redeploy.

  • Branch claude/op-r4-3-foto-perspektiven (PR folgt) — OP-R4-3 Foto-Perspektiven-Pflicht: Konfig-Modell + Anzeige (Version 0.7.0 → 0.8.0 MINOR, Build 9 → 10). Erste, infra-freie Stufe des Foto-/KI-Ausbaus (Anschluss an PR7-Doku-Gate). Datenmodell: Teilschritt.fotoPflicht?: FotoAnforderung[] (F15, {perspektive, anzahl}) + Helfer fotoAnforderungen() (Normalisierung: Anzahl ≥1, leere/doppelte Perspektiven raus) + Vorschlagsliste FOTO_PERSPEKTIVEN (G-1: freier String bleibt erlaubt) in server/src/model/types.ts. Seed: ts-annahme fordert die Rundum-Zustandsdoku (Front/Heck/Seite L/R/Innen ×1). Editierbar: TeilschrittFelderPatch um fotoPflicht (+ dokuPflicht) erweitert (setzeTeilschrittFelder, Handler teilschritt.update). DTO: fotoPflicht an TeilschrittDTO (Anzeige) + ProzessSchrittDTO (Editor) inkl. phase/dokuPflicht. Client: Anzeige der geforderten Perspektiven am Schritt im Auftrags-Detail-Panel („📷 erforderlich: Front ×1 …"). Test: test:prozess Abschnitt 9 (Seed-Annahme, Normalisierung, Patch). Bewusst NICHT in diesem Slice (Folge-Slices, je eigene Entscheidung): echter Foto-Upload (Attachment-Modell §4.10 + Cloudflare-R2 + presigned, OP-R4-1) und KI-Plausibilität (Vision-LLM, OP-AI-2) — Letzteres DSGVO-relevant (Fahrzeugfotos/Kennzeichen an externe API → Datenschutz/Provider/Residenz zu klären, proaktiv geflaggt). Editor-Oberfläche für fotoPflicht + Standalone-Standard-Schritte (Annahme ist nicht Teil einer Leistung → erscheint nicht im Leistungs-Katalog) als Folge. typecheck + alle Self-Tests + ng build + No-Hex grün. Kein Solver-Redeploy.

  • Branch claude/auto-image-rating-options-4upp3q (PR folgt bei Bedarf) — OP-QS-2: Auto-Erkennung — sichtbare Fehler-Warnung + tfjs-Slim-Improvement festgehalten (Version 0.9.4 → 0.9.5 PATCH; Build 16 → 17). Nutzer-Wunsch 06-27: wenn das Rating fehlschlägt oder nicht einkommentiert ist, soll gewarnt werden (statt still auf manuell zurückzufallen). Gebaut: (1) detektoren.ts liefert jetzt AutoStatus (aus/aktiv/fehler) statt nur aktiv-Bool: aus = dormant (MODELLE_BASIS_URL leer, kein Hinweis nötig) · aktiv = Adapter geladen · fehler = konfiguriert, aber Adapter-/Modell-Load schlägt fehl (z. B. Binding nicht einkommentiert → /models 404). (2) bild-upload-gate.component.ts zeigt den Status: ● aktiv · ○ inaktiv · ⚠ amber Warn-Banner im Fehlerfall mit Aufforderung zur manuellen Markierung/Prüfung (+ Detailtext); zur Laufzeit setzt die Komponente den Status bei Detektor-Fehlern auf fehler (einmal fehler bleibt sichtbar, Stubs „heilen" nicht). Detektor-Fehler blockieren nie (manuelle Markierung bleibt nutzbar). (3) Demo-Seite reicht initialerAutoStatus durch (eigenes Badge entfernt, jetzt in der Komponente). Improvement festgehalten (kein Bau): schlankeres tfjs-Backend / kleineres nsfwjs-Bundle (heute ~40 MB, da nsfwjs ganz TF.js bündelt → künftig @tensorflow/tfjs-core + tfjs-backend-wasm/-webgl, nur nötige Ops; kein akuter Blocker, lazy+Cache) — als Folge-Punkt in OP-QS-2 (docs/Bildbewertung.md §7 + HANDOFF). Tests: ng build · test:bildgate · No-Hex · Server-typecheck grün. Reiner Client — kein Server-/Solver-Change (nur version.ts). Doku: docs/Bildbewertung.md (§7 Status/Warnung + Improvement), HANDOFF, CHANGELOG, Timesheet (Session 35).

  • Branch claude/auto-image-rating-options-4upp3q (PR folgt bei Bedarf) — OP-QS-2: Modell-Upload-Skript + nsfwjs-Adapter auf eingebautes Modell (Version 0.9.3 → 0.9.4 PATCH; Build 15 → 16). Liefert den letzten Aktivierungs-Baustein: scripts/upload-models.sh bereitet die On-Device-Modelle auf und lädt sie in den privaten EU-Bucket taktano-models. Empirisch verifiziert (06-27, Scratch-Install): (1) MediaPipe @mediapipe/tasks-vision liefert vision_bundle.mjs (self-contained ESM) + wasm/ (6 Dateien: vision_wasm_internal/_module_internal/_nosimd_internal je .js+.wasm); (2) .tflite (blaze_face_short_range) von storage.googleapis.com/mediapipe-models/… erreichbar (HTTP 200); (3) nsfwjs bündelt sich via esbuild zu einem self-contained ESM (tfjs + eingebautes MobileNetV2-Modell, ~40 MB) — load() ohne URL nutzt das eingebaute Modell. Folge-Korrektur: nsfw-nsfwjs.adapter.ts lädt nun ein Bundle nsfwjs/nsfwjs.bundle.mjs + load() (statt separater tfjs-Datei + Modell-URL — das hätte nicht funktioniert, da die nsfwjs-Modelle als JS-Module ins Paket gebündelt sind, nicht als model.json+.bin). Skript: Temp-npm i → esbuild-Bundle → .tflite-Download → wrangler r2 object put … --jurisdiction eu --remote mit korrekten Content-Types (.wasmapplication/wasm, .mjstext/javascript); Bucket bleibt privat (Hinweis aufs CI-Privacy-Gate). Asset-Set reduziert: kein separates tfjs/… und kein nsfwjs/model/… mehr nötig (im Bundle enthalten). Entscheidungen: (a) nsfwjs als ein Bundle mit eingebautem Modell statt URL-geladenem Modell — robust, da das Paket die Modelle als JS-Module shipped; (b) ~40 MB lazy akzeptiert (nur bei aktiver Auto-Erkennung, danach Browser-Cache); (c) Upload bleibt Operator-Schritt (braucht wrangler-Auth aufs EU-Konto). Tests: bash -n (Skript-Syntax) · ng build (Adapter weiter winzige Lazy-Chunks, Libs runtime-geladen) · test:bildgate/No-Hex/Server-typecheck grün. NICHT hier ausführbar: der tatsächliche Upload (wrangler-Auth) + Browser-Laufzeit. Doku: docs/Bildbewertung.md (§7b Schritt 2: verifizierte Asset-Liste + Skript), HANDOFF, CHANGELOG, Timesheet (Session 35). Reiner Client/Tooling — kein Server-/Solver-Change (nur version.ts).

  • Branch claude/auto-image-rating-options-4upp3q (PR folgt bei Bedarf) — OP-QS-2: Modelle privat ausliefern (R2-Binding, kein öffentlicher Bucket) + CI-Privacy-Gate (Version 0.9.2 → 0.9.3 PATCH; Build 14 → 15; deploybare Worker-Änderung). Nutzer-Entscheidung 06-27: taktano-models soll nicht öffentlich sein → Architektur von „öffentliche Custom-Domain" auf privat, Worker-served umgestellt + ein Pipeline-Check, der Öffentlichkeit verhindert. Gebaut: (1) Privates R2-Serving im Worker (server/party/leitstand.ts): Env.MODELLE_BUCKET?: R2Bucket + serveModellAsset liefern GET /models/* aus dem privaten Bucket same-origin (Access-geschützt, kein CORS; Content-Type je Endung inkl. application/wasm/text/javascript, ..-Schutz, 404 ohne Binding/Objekt). [[r2_buckets]]-Binding (jurisdiction = "eu") in wrangler.toml auskommentiert = dormant/deploy-sicher (Muster D1 #184). MODELLE_BASIS_URL zeigt nun auf /models (same-origin) statt einer öffentlichen Domain. (2) CI-Privacy-Gate scripts/check-r2-private.mjs — prüft via CF-REST-API (/r2/buckets/{b}/domains/managed + /domains/custom, Header cf-r2-jurisdiction: eu), dass taktano-models UND taktano-fotos nicht öffentlich sind (kein r2.dev Public Dev URL, keine aktive Custom-Domain); läuft im Deploy-Job vor wrangler deploy und blockiert ihn bei Öffentlichkeit. Fail-soft: fehlende Creds / Token ohne R2-Leserecht → Warnung + Skip (kein False-Positive-Deploybruch; für ein wirksames Gate braucht das Token R2-Read). Entscheidungen: (a) privat + Worker-served statt öffentlicher Domain — strenger, kein CORS, alles hinter Access; (b) Binding auskommentiert/dormant (deploy-sicher bis Bucket+Assets bereit); (c) Gate schützt beide Buckets (auch den Foto-Speicher taktano-fotos/OP-R4-3). Bucket-Trennung dokumentiert: taktano-fotos (EU, privat) = Fotos; taktano-models (EU, privat) = Modelle. Cloudflare-MCP-Grenze festgehalten: keine EU-Jurisdiktions-Sicht/-Anlage (empirisch: r2_bucket_get 404 für den EU-Bucket) → EU-R2-Ops via wrangler/Dashboard. Tests: Server-typecheck (R2Bucket/HTMLRewriter typisiert) · Gate-Dry-Run (ohne Creds → Skip/Exit 0) · ng build/test:bildgate/No-Hex grün. NICHT hier verifizierbar: echte CF-API-Antwort des Gates + Laufzeit-Auslieferung (Deploy/Browser). Doku: docs/Bildbewertung.md (§7a Verschärfung + §7b Runbook neu: privat/Worker-served + Gate), HANDOFF (OP-QS-2), CHANGELOG, Timesheet (Session 35). Worker-Redeploy: ja (beim Merge; verhaltensgleich solange Binding/Var dormant).

  • Branch claude/auto-image-rating-options-4upp3q (PR folgt bei Bedarf) — OP-QS-2: Worker-Injection der Modell-URL (env-gesteuert) — Aktivierung per 1 Variable (Version 0.9.1 → 0.9.2 PATCH; Build 13 → 14; deploybare Worker-Änderung). Schließt das Wiring ab: die Auto-Erkennung wird künftig allein über eine Worker-Variable scharfgeschaltet — kein Angular-Rebuild, kein index.html-Edit. Gebaut: (1) Env.MODELLE_BASIS_URL? + [vars] MODELLE_BASIS_URL = "" in server/wrangler.toml (leer = dormant; öffentliche URL → kein Secret). (2) Im Worker-fetch (server/party/leitstand.ts): nach env.ASSETS.fetch wird bei gesetzter Var und text/html-Antwort per HTMLRewriter ‹script›window.__TAKTANO_MODELLE_URL__=…‹/script› in den SPA-<head> vorangestellt (greift den schon verdrahteten Client-Runtime-Override aus #v0.9.1). Sicherheit: der Wert ist env-/operator-gesetzt (keine Nutzereingabe) und wird JSON.stringify + <<-escaped (kein </script>-Ausbruch). Leer/ungesetzt ⇒ nichts injiziert, exakt bisheriges Verhalten (dormant, deploy-sicher). Aktivierung jetzt: in wrangler.toml MODELLE_BASIS_URL auf die R2-Custom-Domain setzen + wrangler deploy (Runbook §7b Schritt 4 entsprechend auf den Worker-Weg umgestellt). Tests: Server-typecheck grün (HTMLRewriter typisiert) · ng build/test:bildgate/No-Hex (Client unverändert) grün. Doku: docs/Bildbewertung.md (§7b Schritt 4), HANDOFF (OP-QS-2), CHANGELOG, Timesheet (Session 35). Solver-Redeploy: nein; Worker-Redeploy: ja (beim Merge auf main, verhaltensgleich solange Var leer).

  • Branch claude/auto-image-rating-options-4upp3q (PR folgt bei Bedarf) — OP-QS-2: Auto-Erkennungs-Aktivierung vorbereitet — MODELLE_BASIS_URL-Wiring + R2-Runbook (Version 0.9.0 → 0.9.1 PATCH — Config-Tweak; Build 12 → 13). Macht die dormante Auto-Erkennung (Phase 1b) aktivierbar ohne Code-Umbau. Gebaut: (1) Runtime-Override in bild/modelle.config.tsMODELLE_BASIS_URL liest vorrangig window.__TAKTANO_MODELLE_URL__ (vor dem Bootstrap, z. B. Worker-injiziertes Inline-Script je Umgebung), sonst den Build-Default → Auto-Erkennung pro Umgebung schaltbar ohne Angular-Rebuild. (2) Aktivierungs-Runbook docs/Bildbewertung.md §7b: R2-Bucket taktano-models (EU) · Asset-Pfade exakt wie die Adapter lesen (mediapipe/vision_bundle.mjs+wasm/+blaze_face_short_range.tflite · tfjs/tf.esm.js · nsfwjs/nsfwjs.esm.js+model/) · Custom-Domain models.taktano.com + CORS (GET von app.taktano.com) · Override setzen · Browser-Verifikation (/bild-schutz → „aktiv", Gesicht→Box, NSFW→gesperrt, Fetches first-party). ⚠ Compliance-Entscheidung (proaktiv geflaggt): R2-Bucket bewusst NICHT per MCP angelegtr2_bucket_create kann keine EU-Jurisdiktion setzen, die aber bei Erstellung fix ist (DSGVO-Residenz, nachträglich nicht änderbar); daher Operator-Schritt wrangler r2 bucket create taktano-models --jurisdiction eu. Stand 06-26 verifiziert: das per MCP verbundene Konto ist erreichbar und hat 0 Buckets (kein Namenskonflikt); Konto-Match-Vorbehalt wie #185. Tests: test:bildgate · ng build (prod) · No-Hex grün. Reiner Client — kein Server-/Solver-Change (nur version.ts). Doku: docs/Bildbewertung.md (§7b Runbook), HANDOFF (OP-QS-2), CHANGELOG, Timesheet (Session 35). Offen: Operator-Aktivierung (Bucket+Assets+Domain) → dann Browser-Verifikation.

  • Branch claude/auto-image-rating-options-4upp3q (PR folgt bei Bedarf) — OP-QS-2 Phase 1b: Auto-Erkennungs-Adapter gebaut (dormant) — Entscheidung ①+Ⓐ (Version 0.8.0 → 0.9.0 MINOR — additive Auto-Erkennungs-Capability; Build 11 → 12). Füllt die PiiDetektor/NsfwKlassifikator-Naht aus Phase 1a mit echten Adaptern, deploy-sicher dormant (PR-184-Muster). Nutzer-Entscheidung 06-26 ①+Ⓐ: Hosting self-host first-party (R2/Pages, EU, lazy); Scope Gesichter (MediaPipe) + NSFW (nsfwjs) jetzt, Kennzeichen manuell; ⊘ Auto-Kennzeichen Ⓑ = offene Frage (zurückgestellt). Gebaut (reiner Client): (1) bild/modelle.config.tsMODELLE_BASIS_URL (first-party, leer = Auto-Erkennung aus) + ladeModul (dynamischer Import einer absoluten URL, bewusst vor dem Bundler verborgen via Function('u','return import(u)')keine npm-Dep, kein Bundle-Wachstum, kein Public-CDN/Drittland-Fetch). (2) bild/pii-mediapipe.adapter.ts (MediaPipe Vision-Tasks Face Detector — nur Lokalisieren/Box, keine Biometrie) + bild/nsfw-nsfwjs.adapter.ts (nsfwjs, Klassen porn/hentai/sexy → unangemessen+Score; Schwelle/Block via entscheideGate), beide laden Lib+Gewichte zur Laufzeit von MODELLE_BASIS_URL. (3) bild/detektoren.ts-Factory: bei aktiver Config Adapter als eigene Lazy-Chunks (769/707 B — Libs nicht gebundelt) laden, sonst Stubs; try/catch → Fallback auf manuell. (4) Demo-Seite zeigt Aktiv/Inaktiv-Status; Komponente fängt Detektor-Fehler ab (manuelle Markierung bleibt immer nutzbar). Entscheidungen: (a) Runtime-Self-Host statt npm-Bundle — hält Build sicher, Basis-Bundle schlank, Repo frei von Modell-Blobs, Privacy/Drittland gewahrt. (b) Dormant/deploy-sicher (PR-184-Präzedenz): aktiv erst nach Asset-Hosting + MODELLE_BASIS_URL. (c) Version MINOR (additive Capability). Aktivierung (Deploy/Infra, offen): MediaPipe-WASM+.tflite · TF.js+nsfwjs-ESM · nsfwjs-Modell auf R2/Pages (EU) ablegen, MODELLE_BASIS_URL setzen → live. Tests: test:bildgate (14 Asserts) · ng build (prod, Adapter als 769/707-B-Lazy-Chunks, Initial-Bundle unverändert) · No-Hex grün. NICHT hier verifizierbar: Laufzeit-Inferenz + Asset-Hosting (Browser-Augenschein beim Deploy). Reiner Client — kein Server-/Solver-Change (nur version.ts). Doku: docs/Bildbewertung.md (§ Status + §7 Phase 1b + §7a Entscheidung), HANDOFF (OP-QS-2 ✅ Phase 1b + ⊘ Ⓑ), CHANGELOG, Timesheet (Session 35).

  • Branch claude/auto-image-rating-options-4upp3q (PR folgt bei Bedarf) — OP-QS-2: Auto-Erkennungs-Slice — Optionen aufbereitet (Doku, kein Code → kein Version-/Build-Bump). docs/Bildbewertung.md §7a: drei Entscheidungs-Achsen für die Modell-gestützte B-3/B-4-Auto-Erkennung. (A) Modelle: Gesichter via MediaPipe tasks-vision (empfohlen, kein voller TF.js) vs. BlazeFace/TF.js vs. nativer FaceDetector (verworfen); Kennzeichen via YOLO-nano/ONNX bzw. OpenCV.js — vorerst manuell (schwächster/teuerster Teil); NSFW via nsfwjs; TF.js-Backend WASM vs WebGL. (B) Gewichte-Hosting (Kern-Dependency-Entscheidung): self-host first-party (R2/Pages, EU, lazy — empfohlen) vs. In-App-Bundle (+MB/Repo-Bloat) vs. Public-CDN (Drittland/Verfügbarkeit → abgeraten). (C) Integration: Lazy-Load nur bei Foto-Upload (Basis-Bundle unberührt), Adapter über die Naht aus §7, Modell nicht in CI laden. Empfehlung: MediaPipe + nsfwjs, Gewichte self-hosted first-party, lazy, WASM; Auto-Kennzeichen späterer Slice. Entscheidung offen (Hosting-Weg + Scope). Doku: docs/Bildbewertung.md (§7a), HANDOFF (OP-QS-2), CHANGELOG, Timesheet (Session 35). Kein Code/Solver-Redeploy.

  • Branch claude/auto-image-rating-options-4upp3q (PR folgt bei Bedarf) — OP-QS-2 Phase 1a gebaut: On-Device-Pre-Upload-Schutz (B-1 Qualität · B-3 Verpixelung · B-4 NSFW-Gate) (Version 0.7.1 → 0.8.0 MINOR — neues, rückwärtskompatibles Feature; Build 10 → 11). Erster Bau nach der Optionen-Doku (docs/Bildbewertung.md). Gebaut (reiner Client): (1) DOM-freier Kern client/src/app/leitstand/bild/upload-gate.ts — rechnet auf rohen RGBA-Pixeln (RGBAImage), in Node selbst-testbar: B-1 bildstatistik (mittlere Luma + Laplace-Varianz/Schärfe in einem Durchlauf) + bewerteQualitaet (zu_klein/unscharf/zu_dunkel/zu_hell, Schwellen konfigurierbar STANDARD_QUALITAET); B-3 verpixele(img, boxen, block) — Mosaik je Box auf einer Kopie (Original unberührt); B-4 + Gesamt-Entscheidung entscheideGate (Priorität NSFW > Qualität > PII > ok, Schwellwert konfigurierbar); Detektor-Naht PiiDetektor/NsfwKlassifikator (Default-Stubs KeinPiiDetektor/UnkritischerNsfw) → BlazeFace/Plate/NSFWJS dockt ohne Umbau an. (2) Angular-Standalone-Komponente bild/bild-upload-gate.component.ts (Canvas-Glue + UX, OnPush, Signals): Bild wählen → Canvas → getImageData → Kern; Befund-Panel (Status ok/Achtung/Gesperrt + Statistik); Bereiche manuell markieren (Pointer-Ziehen, Box-Overlay in %) + Verpixeln; Upload-Button nur bei nicht-blockiert; das Original verlässt die Komponente nie — nur der (ggf. verpixelte) image/jpeg-Blob wird via (freigegeben) emittiert. (3) Demo-/Vorschau-Seite pages/bild-schutz.component.ts unter Deep-Link /bild-schutz — bewusst nicht im Workspace-Rail (kein fertiges Feature vortäuschen, bis das reale R4-Upload-Feld existiert). (4) Self-Test npm run test:bildgate (upload-gate.demo.ts, synthetische RGBA-Bilder: Schärfe/Helligkeit/Größe, Verpixel-Invarianz [Block eingeebnet, Original/Außenbereich unverändert], Entscheidungs-Priorität) + CI (Client-Job vor ng build); tsx als Client-devDep. Entscheidungen: (a) Heavy ML-Deps (TF.js/NSFWJS/BlazeFace) bewusst NICHT gezogen — Bundle-/Modell-Hosting-/Verifizierbarkeits-Kosten; stattdessen Detektor-Naht + reale manuelle Markierung/Verpixelung (B-3 trägt heute), Auto-Erkennung = eigener Slice mit Dep-Entscheidung. (b) On-device, Original bleibt lokal (Privacy-by-Design, §4a/§4b) — nur der redigierte Blob geht raus. (c) Version = MINOR (additives Feature, kein Breaking). (d) Demo-Route ohne Rail-Eintrag statt halbfertigem Workspace. Offen: Auto-Erkennung (BlazeFace/Plate/NSFWJS), EXIF-Stripping, „blockiert"-Override (rollen-gegated OP-AUTH-1 + OP-AUDIT-1-Event), Anbindung an R4-Upload (OP-R4-3). Tests: test:bildgate (14 Asserts grün) · ng build (prod) grün (Bundle-Budget-Warnung vorbestehend) · No-Hex-Gate grün (alle Farben --tk-*/color-mix). Reiner Client-Pfadkein Server-/Solver-Verhaltens-Change (nur server/src/version.ts bumpt). Doku: docs/Bildbewertung.md (§ Status + §7 Umsetzung), HANDOFF (OP-QS-2 ✅ Phase 1a), CHANGELOG, Timesheet (Session 35). True North: indirekt (QS-/Doku-Qualität + Datenschutz/Governance).

  • Branch claude/auto-image-rating-options-4upp3q (PR folgt bei Bedarf) — OP-QS-2: Optionen für automatische Bildbewertung festgehalten (Optionen-/Design-Doku, kein Code → kein Version-/Build-Bump, Präzedenz #182/#187/#188). Neue lebende Doku docs/Bildbewertung.md (Nutzer-Frage 06-26 „welche Optionen für eine automatische Bildbewertung?"). Zwei getrennte Ziele festgehalten: B-1 Foto-technische Qualität (Upload-Gate an jedem R4-Foto-Feld) und B-2 fachliche Bewertung (QS-Endkontrolle/Mangel-Doku/Anlieferung). Abgrenzung zu OP-AI-2/OP-AI-3 (Upload-Plausibilität ≠ Gewerk-Qualität); Bezug OP-QS-1 (Mangel-Foto). Optionen A–F bewertet: A Vision-LLM (Claude Vision, liegt bereits im Stack A-4-KI-Layer/A-5-Pragma) · B generische Cloud-Vision (nur OCR/Grob-Labels) · C eigenes CNN (später, datenintensiv) · D klassische Bildverarbeitung (deterministisches Gate) · E on-device/Edge · F Hybrid = Empfehlung (D/E-Gate → A für B-2, gestuft; „KI schlägt vor, QS entscheidet"). ⚠ Compliance proaktiv geflaggt (DE/AT/CH): Fahrzeugfotos personenbezogen (Kennzeichen/Personen/EXIF) → A/B = Drittland/AVV; EXIF strippen + Schwärzung + R2-Retention (OP-AUDIT-1) vor Bau klären — docs/Compliance.md/RISK-10-Bezug. Entscheidung: Optionen empfohlen (Hybrid F), Umsetzung noch nicht beschlossen. Nachtrag (gleiche Session, Nutzer-Wunsch): B-3 PII-Schutz vor Upload — beim Foto-Upload on-device auf Personen/Kennzeichen scannen, warnen und Verpixeln von Gesichtern/Kennzeichen anbieten (Privacy-by-Design DSGVO Art. 25). B-3-Entscheidungen: Erkennung+Verpixelung on-device, vor Upload (Option E; nur redigierte Kopie geht hoch, Server-Blur zu spät) · Gesichter MediaPipe/BlazeFace, Kennzeichen leichtes Objektmodell/OpenCV-Heuristik — nur lokalisieren, kein OCR/Biometrie · Erkennung ≠ perfekt → manuelle Box-Korrektur Pflicht-Fallback · „anbieten" (opt-in), aber Cloud-Pfad A/B → Redaktion default/erzwungen (sonst PII an US-Dienst; „ohne Verpixeln" begründet/rollen-gegated + OP-AUDIT-1) · B-3 = Voraussetzung für A/B; entschärft das §4-Compliance-Risiko an der Quelle. docs/Bildbewertung.md §1 (Ziel B-3) + §4a (UX/Detektion/Entscheidungen) + §5 (Phase 1 erweitert). Nachtrag 2 (gleiche Session, Nutzer-Wunsch): B-4 Inhalts-/NSFW-Check — beim Foto-Upload on-device prüfen, ob das Bild unangemessen (NSFW) ist → warnen + Upload blocken (anders als B-3 nicht redigierbar). B-4-Entscheidungen: on-device via NSFWJS (TF.js, gleicher Pre-Upload-Pass wie B-1/B-3; kein Bild-Leak; Cloud-Moderation nur optional nach Upload + Drittland) · Reaktion = blockieren, Override nur begründet + rollen-gegated (OP-AUTH-1) + OP-AUDIT-1-Event · Schwellwert/Strenge konfigurierbar (G-1) · Abgrenzung Content-Moderation ≠ B-2/B-3. docs/Bildbewertung.md §1 (Ziel B-4) + §4b + §5 (Phase 1 = ein on-device-Pass B-1+B-3+B-4). Doku: docs/Bildbewertung.md (neu), HANDOFF (OP-QS-2 inkl. B-3/B-4), CHANGELOG, Timesheet (Session 35). Kein Code/Solver-Redeploy. True North: indirekt (QS-Beschleunigung/Qualitätssicherung + Datenschutz + Governance, nicht direkt Auslastung/Standort/Kapazität).

  • #200Infra-Kosten-Änderungen werden protokolliert (OP-COST-1 · OP-AUDIT-1 · OP-LOG-1) (Version 0.8.0 → 0.9.0 MINOR, Build 11 → 12). Nutzer-Wunsch: „im Log festhalten, wenn die Infra-Kosten aktualisiert wurden". Gebaut: jede infraKosten.hinzufuegen|aktualisieren|entfernen-Aktion schreibt (1) eine Ops-Log-Zeile (interim console, wie die Boot-Zeile, inkl. Version/Build, ohne Klartext-PII) und (2) ein dauerhaftes Audit-Event ins D1-Audit-Log (audit_entries: event_type=infraKosten.*, resource_type=infra_kosten, summary + delta_json mit Dienst/Monat/Betrag/Währung, ts in ms) — best-effort/No-op ohne D1-Binding. Actor = die verifizierte Access-E-Mail der Verbindung (neu je Verbindung gehalten), sonst unbekannt, solange das Owner-Gate nicht scharf ist (OP-COST-3). Entscheidung: „Beides" — durables Audit (Historie/Compliance) plus Ops-Zeile (sofortige Sicht, funktioniert auch ohne D1-Binding); schließt den in docs/Kosten.md §11 offenen Punkt „Audit der Posten-Änderungen = OP-AUDIT-1" (der Actor folgt vollständig mit OP-COST-3). Reiner Server-Pfadkein Solver-Redeploy. Verifikation: Server-Typecheck + test:kosten + operativ-Smoke grün. Doku: docs/Audit-Log.md §3 (Event-Typ-Katalog), docs/Kosten.md §11, HANDOFF (OP-COST-1), CHANGELOG (#200), Timesheet (Session 35).

  • #198OP-COST-3: Kosten interim für alle freigeschaltet; Owner-only-Scharfschaltung als Pre-Prod-Requirement (Doku/Konfig, kein Code → kein Version-/Build-Bump). Nutzer-Entscheidung 06-26: Das Owner-only-Gate (Sicht B) wird nicht jetzt scharf geschaltet — die Infra-Kosten bleiben für alle Access-authentifizierten Nutzer sichtbar (ACCESS_TEAM_DOMAIN/ACCESS_AUD in server/wrangler.toml bleiben leerkostenAdminFuer = true; der Zugang selbst bleibt durch Cloudflare Access am Edge geschützt). Das Scharfschalten ist als neues OP-COST-3 = Pre-Prod/Go-Live-Requirement festgehalten: HANDOFF §4 (OP-COST-3 mit Lockout-Warnung), docs/Risikoregister.md (RISK-12 „mitigiert" → „offen (interim akzeptiert)", W 1→2), docs/Kosten.md §12 (Status-Callout + bereitliegende drkv-com-Werte ACCESS_TEAM_DOMAIN/ACCESS_AUD für die spätere 1-Schritt-Aktivierung). Entscheidung/Begründung: interim ok, da aktuell nur Infra-/Cloud-Spend exponiert ist (Sicht A Marge/Sätze noch nicht gebaut) und der Edge-Access bereits authentifiziert; echtes Owner-only wird vor Produktivgang scharf, endgültig per OP-AUTH-1. Kein Code/Solver-Redeploy (ACCESS_* unverändert leer; nur Doku + wrangler.toml-Kommentar). Doku: HANDOFF (OP-COST-3), docs/Risikoregister.md (RISK-12), docs/Kosten.md §12, server/wrangler.toml, Timesheet (Session 34).

  • #196OP-COST-1 Follow-up (Doku/Konfig, kein Code → kein Version-/Build-Bump): Prod-Gate-Runbook · Sicht-A-Stundensatz-Design · OP-COST-2 · OP-EXPORT-1. Erfasst die Nutzer-Entscheidungen vom 06-26: (1) Sicht A (Arbeitskosten je Auftrag) — Stundensatz je Abteilung + Override je Mitarbeiter, jeder Satz mit Von-Bis-Gültigkeit (historisiert, nie überschrieben); die Berechnung (istMin × zum Leistungs-Zeitpunkt gültiger Satz) entsteht nur im Report (D-2, nie persistiert) — docs/Kosten.md §3.1/§3.2. (2) OP-COST-2: Infra-Kosten via Provider-APIs — automatischer Pull je Dienst (Cloudflare/Fly/Anthropic/Registrar-APIs, Cron-Worker) als verbindliche Richtung; manuelle Erfassung bleibt Fallback; Datenmodell quelle:'api'|'manuell' + Idempotenz-Key, API-Keys als Secrets — §4. (3) OP-EXPORT-1: Reports immer mit Diagramm + Export (PDF + CSV + Excel) für alle Reports — §13. (4) Prod-Gate-Aktivierungs-Runbook (docs/Kosten.md §12) + server/wrangler.toml-Cleanup: KOSTEN_ADMIN_EMAILS aus [vars] entfernt (PII → Secret wrangler secret put, vermeidet Var/Secret-Clash), ACCESS-Kommentare + Lockout-Warnung geschärft. Kein Code/Solver-Redeploy. Doku: docs/Kosten.md (§3/§4/§11–§13), HANDOFF (OP-COST-1 + OP-COST-2 + OP-EXPORT-1), server/wrangler.toml, Timesheet (Session 33).

  • Direkt auf main (reine Way-of-Working-Doku, via GitHub-API committet — Commits 087b59a/dbbd62b): GitHub-Operationen über die GitHub-API/MCP statt lokales git/gh für Remote-Writes (PR/Merge/Kommentar/Commit/Push; CI/Mergeability via pull_request_read) — in docs/agents.md §7 + CLAUDE.md verankert (Nutzer-Anweisung; Grund: lokale git-Pushes sind in der Remote-Session unzuverlässig).

  • #197Bugfix: linke Rail-Sidebar scrollt bei niedrigem Fenster (Version 0.7.0 → 0.7.1 PATCH, Build 9 → 10). Problem (Nutzer-Report): die Icon-Rail (client/.../leitstand/shell.component.ts, OP-R9-12) füllt mit h-screen + overflow-hidden exakt die Viewport-Höhe; bei zu niedrigem Fenster liefen die Nav-Items (und der untere Auf-Kurs-/Status-/Theme-Block) über und wurden abgeschnitten — ohne Scrollmöglichkeit (im aufgeklappten Zustand verschärft, weil die Cluster-Titel zusätzliche Höhe einnehmen). Fix: der <nav>-Block wird zur scrollbaren Zone (flex-1 min-h-0 overflow-y-auto; overflow-x-hidden erhält das Label-Clipping beim Ein-/Ausklappen), Logo (oben) und Status/Theme (unten) bleiben fixiert (shrink-0 statt mt-auto); dezenter, token-gefärbter Scrollbalken (--tk-line, kein Hex). Entscheidung: nur die Nav scrollt (Logo + Status bleiben sichtbar) statt das ganze Panel — beste Erreichbarkeit; min-h-0 ist der Schlüssel, damit das Flex-Item unter seine Inhaltshöhe schrumpfen darf. Verifikation: ng build (prod) + No-Hex-Gate grün (Browser-Augenschein offen — Playwright im Cloud-Env nicht installiert). Reiner Client-Pfad — kein Server-/Solver-Change (nur server/src/version.ts bumpt). Doku: CHANGELOG (#197), HANDOFF (OP-R9-12), Timesheet (Session 32). True North: Bedienbarkeit des Cockpits auf kleinen/geteilten Fenstern (Navigation bleibt erreichbar).

  • #195Timesheet-Nachtrag: Session 31 (Wrap-up der Gantt-OPs) (kein Code → kein Version-/Build-Bump, Präzedenz #168). Bucht die nach dem Build (#193) folgende Merge-Orchestrierung (update-from-main inkl. Auflösung der Versions-Kollision mit der parallelen OP-COST-1-B1-PR #192, PR #193 + Squash-Merge, Deploy-Verifikation) als eigene Session 31 (~0.5 h) — getrennt von Session 28 (Build) wegen des >1 h-Gaps (Gap-Regel). Summe → ~85.2 h (inkl. der parallel via #194 gemergten Flow-Sessions 29/30), Stand 06-26 ~13:00. Hintergrund (Repo-Hygiene): Remote-Branch-Löschung gemergter Feature-Branches ist in der Cloud-Session blockiert (git push --delete → 403, kein MCP-Branch-Delete) → empfohlen, im Repo „Automatically delete head branches" zu aktivieren. Doku: docs/Timesheet.md (Session 31 + Summe), CHANGELOG (#195). Kein Code/Solver-Redeploy.

  • Flow-Refactor (OP-R3-1) — PR-Bündel + main-Abgleich (#194, Version 0.6.0 → 0.7.0 MINOR, Build 8 → 9). Fasst den Branch claude/workflow-reservation-pickup-6m2q37 (Analyse + Flow-Refactor-Plan + PR 1–7, Einträge unten 2026-06-24/25) zum Pull Request gegen den aktuellen main zusammen. Inhalt: fachliche Phase first-class (Achse 2) durchgängig Daten→DTO→UI · Annahme als nicht-solver-geplanter Doku-Schritt · QS/Abholung/Nachkontrolle entzerrt · Klärfälle (abbrechen/abgebrochen + Klärfall-Kontext + Skill „Klärung") · Pflicht-Doku-Gate je Schrittabschluss. Zwei main-Abgleiche eingepflegt (zuletzt #192/#193/Way-of-Working) — Konflikte gelöst (Importe inkl. ConnectionContext; SCHEMA_VERSION — main 11/12/13 [Infra-Kosten] → Phase-Migration v14; CHANGELOG/Timesheet beide behalten). Verifikation: Server-typecheck + alle Self-Tests (inkl. main's fairness/progression) grün · ng build (prod) + No-Hex grün · Laufzeit-Probe gegen lokalen PartyServer (neuer Auftrag → phase=annahme + Annahme-Schritt + Doku-Pflicht; Klärfall melden; Abbruch → abgebrochen/reservierung keine). Kein Solver-Redeploy.

  • #193Gantt: Zeit-Zoom (OP-R8-18) + Heute-Linie/Echtzeit-Überfälligkeit (OP-R8-17) (Version 0.5.0 → 0.6.0 MINOR, Build 7 → 8). Baut die beiden am 06-25 erfassten Gantt-OPs (Nutzer-Wahl „Gantt: Heute-Linie + Zoom"). OP-R8-18 (Zeit-Zoom): der bisher fixe SCALE (0.6 px/min) wird ein scale-Signal und durchzieht die gesamte Zeit-Geometrie (Blöcke, Zeitachse, JETZT-Linie, Pins/Drag, Auslastungs-Heatmap); Bedienung über Presets Std/Tag/Woche/Monat + Feinzoom −/+ (geclippt [0.012, 6] px/min); Zoom-Anker = Viewport-Mitte (die Zeit unter der Mitte bleibt beim Zoomen stehen). Adaptive Achsen-Dichte je Zoom — Gitterlinien, Tages-/Wochen-Labels, Intraday-Zeit-Labels und Heatmap-Zellen wählen ihre Schrittweite aus Leitern, damit die Achse nie zu dicht/spärlich wird (adressiert zugleich den Performance-Punkt teilweise: keine DOM-Flut beim Auszoomen; volle Virtualisierung bleibt offen). OP-R8-17 (Heute-Linie): Befund — die vertikale JETZT-Linie (cyan, Glow, 30-s-Live-Tick, „Jetzt"-Badge) existierte bereits über alle Zeilen (Dark-Cockpit, jetztLeft); gebaut wurde die fehlende „was-ist-überfällig"-Hälfte: noch nicht begonnene (geplant) Teilschritte, deren geplanter Start links der JETZT-Linie liegt, bekommen einen dezenten Amber-Ring „⏰ läuft spät" (in Hell und Dunkel, wie der bestehende rote Termin-Konflikt-Ring; Priorität Sprung-Highlight > Konflikt > spät) — plus die Linie ist jetzt zoom-fest. Entscheidungen: (1) Heute-Linie nicht neu gebaut (existierte) — stattdessen die Echtzeit-Überfälligkeit ergänzt + zoom-fest gemacht; kein Doppelbau. (2) Linie bleibt Dark-Cockpit-gegated wie die übrigen Overlays (⚑ Wunsch-Abholung, Heatmap) — eine Hell-Modus-Variante ist als optionaler Folge-Schritt notiert (Kontrast-Tokens), statt die bestehende Design-Entscheidung still aufzubrechen. (3) Überfälligkeit = Amber, nicht Rot — Rot bleibt dem harten Termin-Konflikt vorbehalten (Design-Regel „Rot nur für Warnungen"; zwei Rot-Bedeutungen vermieden). (4) Zoom-Anker Mitte als robustester Default (Cursor-/Heute-Anker + Strg-Scroll bleiben mögliche Folge). Tests: ng build (prod) grün · No-Hex-Gate grün (alle neuen Farben über --tk-*/color-mix, inkl. Zoom-Buttons) · Server-Typecheck grün. Reiner Client-Pfadkein Server-/Solver-Verhaltens-Change (nur server/src/version.ts bumpt). Doku: HANDOFF (OP-R8-17/18 → gebaut), CHANGELOG (#193), Timesheet (Session 28). True North: beantwortet Frage 2 („was läuft jetzt / was ist überfällig") direkter und macht Frage 1/3 (Auslastung/Kapazität) über Stunden ↔ Monate schneller ablesbar.

2026-06-25

  • Branch claude/workflow-reservation-pickup-6m2q37 (PR folgt bei Bedarf) — Flow-Refactor PR 7: Pflicht-Doku-Gate je Schrittabschluss (OP-R4-3)schließt den Flow-Refactor-Plan ab (PR 1–7). Server: Master Teilschritt.dokuPflicht? (F14; Default pflichtig, false schaltet ab) + Helfer dokuPflichtig; Instanz TeilschrittInstanz.kommentar?; erledige(…, kommentar?) speichert die Abschluss-Doku; teilschritt.aktion erledigen trägt kommentar und lehnt ohne Kommentar ab, wenn der Schritt doku-pflichtig ist (Gate); Kommentar landet zusätzlich in der Chronik. TeilschrittDTO um dokuPflicht/kommentar erweitert (via dokuPflichtByTs im Snapshot). Client: per-Schritt „✓ Fertig (mit Doku)" im Detail-Panel mit Pflicht-Kommentar-Eingabe (verdrahtet die zuvor ungenutzte teilschrittAktion), erfasster Kommentar wird am erledigten Schritt angezeigt. Test: test:prozess Abschnitt 8 (dokuPflichtig-Default/Override; erledige speichert Kommentar). Entscheidungen: (1) Doku-Pflicht Default an (OP-R4-3 „gilt immer"), per Schritt abschaltbar; (2) Gate am per-Schritt-Abschluss (der reguläre Doku-Punkt); Bulk-fertigstellen bleibt bewusst Operator-Override ohne Gate; (3) Foto-Perspektiven + KI-Plausibilität + Diktat (restliche OP-R4-3/OP-AI-2/3) als Folge-Ausbau. typecheck + alle Self-Tests grün, ng build + No-Hex grün. Kein Solver-Redeploy. ➡ Flow-Refactor (OP-R3-1) komplett: Phase first-class (Daten→DTO→UI), Annahme-Doku-Schritt, QS/Abholung/Nachkontrolle entzerrt, Klärfälle/Abbruch, Doku-Gates.
  • Branch claude/workflow-reservation-pickup-6m2q37 (PR folgt bei Bedarf) — Flow-Refactor PR 6: Klärfälle — Abbruch + Klärfall-Kontext + Skill (OP-R3-1; Server + Client). Lifecycle (S-6): neue Aktion abbrechen + terminaler Status abgebrochen, erlaubt aus geplant/angeliefert/in_arbeit/pausiert (Unterbrechung an jeder Stelle → Abbruch); reservierungsmodus('abgebrochen')='keine'; abgebrochen als inaktiv/terminal eingestuft (Insights ABGESCHLOSSEN, Client aktiveAuftraege raus → Archiv-Sicht, Flow-Band aus dem Fluss). Klärfall-Kontext (Auftrag.klaerfall?: {grund,eskaliert,seit}, OP-R3-1): pure Helfer setzeKlaerfall/loeseKlaerfall (Grund pflicht, orthogonal zum Status), Server-Message auftrag.klaerfall (melden/lösen, mit Protokoll-Eintrag), im AuftragDTO. Skill „Klärung" (skill-klaerung) geseedet. Client: Status-/Aktions-Labels für abgebrochen/abbrechen; Klärfall-Badge (⚠, eskaliert) im Detail-Panel + Orders; Klärfall melden (Grund-Pflichtfeld + Eskalieren-Checkbox) / lösen im Aktions-Hub; „Abbrechen" erscheint via erlaubteAktionen. Test: operativ-Selbsttest (Klärfall setzen/lösen, Grund-Pflicht, Abbruch aus pausiert/geplant → terminal, Reservierung keine). Entscheidungen: (1) kein SCHEMA_VERSION-Bump — neuer Enum-Wert + optionales Feld sind rein additiv, kein Remap von Altdaten nötig; (2) Klärfall orthogonal zum Lifecycle (ändert Status nicht) statt eigener Status; (3) Re-Entry-Routing (zurück/Sprung-zu-QS/anderer-Schritt) über die bestehenden Teilschritt-Aktionen, kein neuer Mechanismus (volle Klärungs-Workflow-Engine bleibt Folge-OP). Server-typecheck + alle Self-Tests grün, ng build + No-Hex grün. Kein Solver-Redeploy. Offen: PR 7 (Pflicht-Doku-Gates, OP-R4-3).
  • Branch claude/workflow-reservation-pickup-6m2q37 (PR folgt bei Bedarf) — Flow-Refactor PR 5: QS-Freigabe vs. Abholung vs. Nachkontrolle entzerrt (OP-R3-1; reiner Client). Befund (Analyse): „Freigeben (zur Abholung) →" rief direkt abholen (→ abgeschlossen = abgeholt) und vermengte so QS-Freigabe und tatsächliche Abholung; kontrolliert (Nachkontrolle) war faktisch verwaist. Entscheidung (Nutzer-Frage scheiterte technisch → empfohlene Minimal-Variante gewählt, ohne neuen Lifecycle-Status/Migration; Alternative „neuer Status abholbereit" bleibt nachrüstbar): QS-Seite ist die Endkontrolle/Abnahme vor der Übergabe — Primär-Button ehrlich umbenannt zu „✓ Abnahme bestanden — Fahrzeug übergeben →" (macht weiterhin abholen, nun klar als Handover/Abholung benannt, Toast „Übergeben · abgeholt"). Neu: Nachkontrolle-Sektion unter der Prüfung listet abgeschlossene (abgeholte) Aufträge mit „Nachkontrolle erledigt ✓" → kontrollieren (→ kontrolliert) — macht den zuvor verwaisten Schritt sichtbar/erreichbar und stellt End- (vor) vs. Nachkontrolle (nach Abholung) klar. Service: nachkontrolleAuftraege (Status abgeschlossen). Entscheidungen: (1) keine Auto-Fallback-Aktion mehr (abholen nur wenn erlaubt, statt erlaubteAktionen[0]); (2) QS-Checkliste bleibt client-seitig/ephemer (kein QS-Pass-Persistieren) — daher kein neuer Status nötig. ng build (prod) grün, No-Hex-Gate grün. Offen: PR 6 (Klärfälle: abbrechen/abgebrochen + Skill „Klärung"), PR 7 (Doku-Gates, OP-R4-3).
  • Branch claude/workflow-reservation-pickup-6m2q37 (PR folgt bei Bedarf) — Flow-Refactor PR 4: UI liest First-Class-Phase (Flow-Sprache) (OP-R3-1; reiner Client, nutzt PR 3). Flow-Band (flow-band.component.ts) ordnet Stationen jetzt aus AuftragDTO.phase zu — die fragile Aufbereitung/Produktion-Heuristik entfällt; kontrolliert↔Abholung-Bug korrigiert: fertiggestellt (Prozess inkl. QS fertig) = Station Abholung, abgeschlossen/kontrolliert (Nachkontrolle nach Abholung)/archiviert = aus dem Fluss. Gemeinsame Flow-Sprache neu in client/.../leitstand/phase.ts (PHASE_LABEL/PHASE_COLOR/phaseLabel()/phaseColor(), Farben = Flow-Band-Stationen, nur --tk-*): Flow-Band-Defs, Orders-Liste und Detail-Panel zeigen denselben Phasen-Chip (annahme→qs, plus „Abholung" für fertiggestellt) — getrennt vom Status- und Terminklasse-Badge (Achsen sichtbar entkoppelt). Client-DTO um phase: Phase|null + Phase-Typ erweitert. Entscheidung: Phase first-class aus dem DTO statt Status-Heuristik; eine TS-Helfer-Quelle statt dupliziertem Mapping je Komponente. ng build (prod) grün, No-Hex-Gate grün. Offen (Folge): „▶ Aufbereiten starten" auch im Flow-Band/Detail (heute nur Belegung); Gantt-Legende auf Phase; PR 5 (QS-Freigabe/Nachkontrolle).
  • Branch claude/workflow-reservation-pickup-6m2q37 (PR folgt bei Bedarf) — Flow-Refactor PR 2: Annahme als Standard-Doku-Schritt (OP-R3-1; QS war mit PR 1 bereits first-class via ts-qm/Phase qs). Entscheidung (Nutzer): Annahme = getrackter Doku-Schritt, NICHT solver-geplant (belegt Parkplatz statt Bucht; G-3 <15 Min). Umsetzung: Seed-Skill skill-annahme + Stammschritt ts-annahme (Phase annahme, 10 Min, keine Bucht-Bindung) — bewusst nicht in den Leistung-Prozessen, daher vom Solver nie instanziiert. materialisiereAuftrag stellt bei meta.mitAnnahme eine Annahme-Instanz voran (Factory annahmeInstanz, bayId:'', keine Mitarbeiter); nur der reguläre Anlage-Pfad (auftrag.create) setzt das Flag → Demos unberührt. Schlüssel-Invariante: istPlanbarerSchritt schließt ts-annahme global aus → Annahme leakt nie in den Optimierer und verschiebt nicht die positionsweise Zuordnung Solver-Schritt↔Instanz (toAuftragInput/applyPlanung/Vorschau-Diff). Test: test:prozess Abschnitt 7 (genau +1 Schritt, an erster Stelle, nicht planbar, currentBays unverändert, frischer Auftrag → Phase annahme). Entscheidungen: (1) Annahme im teilschritte[]-Array (sichtbar in Timeline/Flow, Phase ableitbar) statt separater Entität; (2) kein Backfill bestehender Aufträge (nur neue erhalten Annahme) — risikoarm; (3) historische §5.1-Vereinfachung „Annahme/Endausgabe keine Teilschritte" damit teil-abgelöst. Additiv; alle CI-Self-Tests + typecheck grün. Kein Solver-Redeploy. Offen: PR 4 (Flow-Band/UI liest AuftragDTO.phase).
  • Branch claude/workflow-reservation-pickup-6m2q37 (PR folgt bei Bedarf) — Flow-Refactor PR 3: Phase abgeleitet + im AuftragDTO (OP-R3-1; nutzt PR 1). Reiner Helfer aktuellePhase(auftrag, phaseByTs) in server/src/operativ/auftrag.ts — abgeleitet aus dem phase-Tag der Teilschritte: maßgeblich der laufende, sonst pausierte, sonst nächste offene Schritt (analog bearbeitungsphase); null = keine offenen Schritte → Lifecycle trägt die Sicht (z. B. Abholung). AuftragDTO.phase: Phase|null ergänzt; toAuftragDTO/snapshot bauen phaseByTs aus den persistierten Teilschritten (phaseEffektiv) und liefern die Phase live mit — kein Derived State gespeichert (D-2). Test: test:prozess (CI) um Abschnitt 6 erweitert (laufend>pausiert>nächster; nur-QM→qs; alles erledigt→null). Entscheidung: die fragile Flow-Band-Heuristik wird damit serverseitig ersetzt; der Client liest die Phase künftig aus dem DTO (PR 4). Additiv (Feld neu, Producer-seitig), Client unverändert. typecheck + test:prozess/test:teilplan/test:insights/operativ/spike/replan/solve grün. Kein Solver-Redeploy. Offen: PR 2 (Annahme/QS als echte Standard-Teilschritte), PR 4 (Flow-Band/UI liest DTO-Phase).
  • Branch claude/workflow-reservation-pickup-6m2q37 (PR folgt bei Bedarf) — Flow-Refactor PR 1: Phase als Teilschritt-Tag (Achse 2 first-class, OP-R3-1; erster Schritt aus docs/Flow-Refactor-Plan.md). Datenmodell (additiv): neues Enum Phase='annahme|aufbereitung|produktion|qs' + Feld Teilschritt.phase? (F13, G-1-Ausnahme: logik-tragend) + Helfer phaseEffektiv()/PHASE_RANG in server/src/model/types.ts. Seed explizit getaggt (ts-wash=aufbereitung, ts-qm=qs [Endkontrolle vor Abholung, ≠ Nachkontrolle kontrolliert], Folie/Keramik/Super=produktion). Migration SCHEMA_VERSION 10→11 in server/party/leitstand.ts: idempotenter Remap taggt untaggte persistierte Teilschritte über dieselbe phaseEffektiv-Ableitungsregel (Id/Name → Default produktion). Test: test:prozess (CI) um Abschnitt 5 erweitert (Seed-Tags · Altdaten-Ableitung · expliziter Tag schlägt Heuristik). Entscheidungen: (1) Phase als Tag am Teilschritt-Master, aktuelle Auftrags-Phase bleibt abgeleitet (kein Derived State gespeichert); (2) eine einzige Ableitungsregel (phaseEffektiv) für Seed-Default + Migration; (3) „Abholung" ist KEINE Arbeits-Phase, sondern Lifecycle fertiggestellt→abgeschlossen. Abwärtskompatibel (Feld optional, Solver unberührt). typecheck + test:prozess/test:teilplan/operativ/spike/replan/solve grün. Kein Solver-Redeploy. Folge: PR 2 (Annahme/QS als echte Standard-Teilschritte), PR 3 (Ableitung+DTO).
  • Branch claude/workflow-reservation-pickup-6m2q37 (reine Doku/Plan; PR folgt bei Bedarf) — Flow-Refactor-Plan zum Zielbild „Phasen first-class" (docs/Flow-Refactor-Plan.md, verlinkt aus docs/Flow-Analyse.md). Setzt die Analyse-Empfehlung in einen inkrementellen 7-PR-Plan um. Leitentscheidung: Achse 1 (Lifecycle/Reservierung) bleibt unverändert; Achse 2 „fachliche Phase" wird First-Class als Enum Phase='annahme|aufbereitung|produktion|qs'Tag am Teilschritt-Master (server/src/model/types.ts:188), aktuelle Phase abgeleitet (Erweiterung bearbeitungsphase() insights.ts:120, kein Derived State gespeichert) → die fragile Flow-Band-Heuristik entfällt. Anlieferung ≠ Annahme: angeliefert = physisch da (Lifecycle), Annahme wird echter erster Teilschritt (Doku-Pflicht). QS-Doppelmodellierung aufgelöst: Endkontrolle = Teilschritt Phase qs (vor Abholung), Nachkontrolle = Lifecycle kontrolliert (nach Abholung); Flow-Band-Mapping kontrolliert↔Abholung korrigiert. Plan-Reihenfolge: PR1 Phase-Tag (additiv) · PR2 Annahme/QS als Standard-Teilschritte · PR3 einheitliche Ableitung+DTO · PR4 konsistente UI-Flow-Sprache (geteilte Primitives) · PR5 QS-Freigabe/Nachkontrolle entkoppeln · PR6 Klärfälle (abbrechen/abgebrochen + Klärfall-Kontext, Skill „Klärung") · PR7 Pflicht-Doku-Gates (OP-R4-3). Jeder schemaverändernde PR bumpt SCHEMA_VERSION mit idempotentem Remap (Muster leitstand.ts:753-801). Schärft OP-R3-1/OP-R4-3; Umsetzung noch nicht beschlossen. Keine Code-Änderung (kein Build/Solver betroffen).
  • #192OP-COST-1 Slice B1: Infra-/Cloud-Kosten (Sicht B) gebaut (Version 0.4.0 → 0.5.0 MINOR — neues, rückwärtskompatibles Feature; Build 6 → 7). Erster Bau auf dem Design #187 (docs/Kosten.md): Kosten-Workspace mit Tab Infra (Sicht B — Cloud-/Betriebs-Spend; Tab Betrieb/Sicht A vorgemerkt). Gebaut: (1) pure server/src/kosten/infra.tsgespeicherte Fakten InfraKostenPosten (Dienst × Monat, Beträge in Cent) + abgeleitete infraKostenAuswertung (Summe gesamt · je Dienst + Anteil · je Monat · Monats-Trend [kalendarischer Vormonat, Lücke = kein Trend] · größte Posten · Mehrwährungs-Flag) — nie persistiert (D-2), Self-Test test:kosten (+ CI). (2) DO-Verdrahtung (server/party/leitstand.ts): infraKostenPosten im State, schemaVersion 12 → 13 (idempotent leer initialisiert), Actions infraKosten.hinzufuegen|aktualisieren|entfernen. (3) Per-Connection-Rollen-Gate (kein Broadcast-Leak): der Worker verifiziert das Access-JWT, extrahiert die email-Claim und injiziert sie vertrauenswürdig als Header X-Taktano-User (client-gesetzte Kopie wird zuvor gestrippt — Anti-Spoofing); der DO bestimmt je Verbindung kostenAdmin über die Allowlist KOSTEN_ADMIN_EMAILS und filtert die Infra-Kosten je Verbindung aus dem Broadcast (Nicht-Berechtigte erhalten das Feld nie; Schreib-Actions ebenso gegated). (4) Client: Service-Typen/Selektoren/Actions + Workspace pages/costs.component.ts (KPI-Kacheln · Spend je Dienst · Monats-Verlauf · größte Posten · CRUD-Erfassung; Mono, nur --tk-*) + Route /costs + nur für kostenAdmin sichtbarer Nav-Eintrag. (5) Token --tk-ws-costs (#84cc16 / Light #4d7c0f, provisorische Signaturfarbe). Entscheidungen: (a) Gate = Access-E-Mail-Allowlist, per-Connection (Empfehlung ggü. „alle Access-Nutzer sehen es") — design-treu (§6 „kein Leak"), geringstes Bedauern, bereitet OP-AUTH-1 vor; fail-closed in Prod sobald ACCESS_*+KOSTEN_ADMIN_EMAILS gesetzt sind (sonst interim für alle Access-Nutzer sichtbar — s. HANDOFF/PR-Flag), lokal ohne Access sichtbar (demobar). (b) Version = MINOR (0.5.0) — additives Feature, State migriert idempotent. (c) Cent statt Float; Mehrwährung ehrlich gespeichert, aber ungewichtete Summe + Hinweis (FX = future, OP-I18N-1). (d) dienst als freier String + Vorschlagsliste (G-1). (e) interim manuelle Erfassung — Provider-Billing-API-Pull später (OP-OBS-1). Merge main: parallele PRs #189/#190 (OP-R1-3) + #191 (Gantt-OPs) eingepflegt (Version → 0.5.0/Build 7, schemaVersion → 13 entkoppelt). Tests: Server-Typecheck · test:kosten · test:progression · ng build (prod) · No-Hex · tokens-Staleness · operativ-Smoke · WS-Upgrade-Live-Check (wrangler dev: 101 + Live-State + Gate) grün; CI auf PR #192 grün. Kein Solver-Redeploy. Doku: docs/Kosten.md (§11 Stand + Status), HANDOFF (§2 + OP-COST-1), design/WORKSPACES.md (§10) + design/DESIGN_TOKENS.md, docs/Risikoregister.md (RISK-12 → mitigiert), docs/Compliance.md, server/wrangler.toml, Timesheet (Session 27). True North: schärft Frage 1 „Auslastung" um die Wirtschaftlichkeit (Infra-Spend-Transparenz).
  • #191OPs erfasst: Heute-Linie (OP-R8-17) + Zoom (OP-R8-18) im Gantt (Backlog, kein Code → kein Version-/Build-Bump). Zwei Nutzer-OPs (06-25) zur Gantt-Navigation/Lesbarkeit: OP-R8-17 vertikale „Jetzt"-Linie über alle Zeilen (was läuft jetzt / überfällig); OP-R8-18 Zeit-Zoom (Stunden↔Tage↔Wochen, Tag/Woche/Monat-Presets). Offene Klärungen je OP (Live-Tick/Styling bzw. Zoom-Stufen/Anker/Performance) in HANDOFF §4. Doku: HANDOFF (OP-R8-17/18). Kein Code/Solver-Redeploy. (Hinweis: parallel zur unmergten OP-R1-3-Slice-2-PR #190 erfasst; Timesheet wird beim Merge nachgezogen.)
  • #190OP-R1-3 Slice 2: begründungspflichtige Beförderung + Audit-Historie (Version 0.3.0 → 0.4.0 MINOR, Build 5 → 6). Macht jede Skill-Niveau-Erhöhung begründungspflichtig und revisionssicher. Gebaut: (1) employee.setSkillNiveau trägt jetzt einen Grund (grundKategorie externer_lehrgang/xp_basiert/manager + optionaler grundText); der „Anheben"-Button auf der MA-Karte öffnet einen Begründungs-Dialog (Pflicht), bevor befördert wird. (2) Neue append-only befoerderungsHistorie (BefoerderungEintrag: wer · wann · von→auf · Grund · Akteur) — beim Niveau-Anstieg schreibt protokolliereBefoerderung einen unveränderlichen Eintrag (Muster wie die Abwesenheits-Historie #183; Akteur interim 'system' bis OP-AUTH-1). (3) Die jüngsten Beförderungen je Mitarbeiter erscheinen als Audit-Spur auf der Karte (Employee.befoerderungen, server-abgeleitet). Entscheidungen: (1) Audit interim im DO-Blob (wie #183) — der D1-Umzug (durable, abfragbar) folgt mit der OP-AUDIT-1-D1-Migration. (2) Manager-Aktionen vertagen/verwerfen + Übersichts-Liste = Slice 3 (Dismiss-State + Vorschlags-Filter) — Slice 2 fokussiert die Begründungspflicht + Nachweis-Spur (das Headline-Requirement von OP-R1-3). Tests: Server-Typecheck + test:progression/test:leistung (unverändert grün) + ng build (prod). Kein Solver-Redeploy. Doku: docs/Akademie.md (Status), HANDOFF (OP-R1-3 Slice 2), Timesheet (Session 25). True North + OP-COMPLIANCE-1: die Beförderungs-Historie = lückenloser Kompetenz-/Zertifizierungs-Nachweis.
  • #189OP-R1-3 Slice 1: Skill-Niveau-Progression — niveau-gezielte Ausbildungsziele + XP-gegatete Aufstiegs-Vorschläge (Version 0.2.2 → 0.3.0 MINOR, Build 4 → 5). Erster Bau nach dem Design (#188, docs/Akademie.md). Gebaut: (1) Mitarbeiter.ausbildungsZiele: string[]{skillId, zielNiveau}[] (neuer Typ Ausbildungsziel, Migration v12: Alt-Skill-IDs → Ziel-Niveau = aktuelles+1, sonst 2); Editor mit ★-Ziel-Auswahl, Anzeige aktuell→Ziel, nur noch nicht erreichte Ziele (niveau < zielNiveau, server-gefiltert). (2) per-Skill-XP erfahrungspunkteProSkill (gleiche Gewichtung wie erfahrungspunkte, gefiltert auf den Skill) + XP-Schwellen XP_SCHWELLE_NIVEAU {2:60, 3:150} (dokumentierte Konstanten; admin-editierbare Stammdaten G-1 = Folge-Slice). (3) niveauVorschlaege XP-gegatet — Aufstieg nur bei XP ≥ Schwelle und bestehenden Qualitäts-Gates (Nacharbeit/Bewertung); der Vorschlag trägt xp/schwelle, die MA-Karte zeigt den XP-Fortschritt („N/M XP"). Entscheidungen: (1) Reuse statt Parallelpfad — der bestehende niveauVorschlaege-/Karten-Pfad wird XP-verfeinert statt einer zweiten „beförderungsreif"-Engine. (2) XP-Schwellen als Konstanten in Slice 1 (Stammdaten-Editor = Slice 2), um Migrations-/DTO-Fläche klein zu halten. (3) Begründungspflichtige Beförderung + Audit + Übersicht = Slice 2 (heute bleibt setSkillNiveau Ein-Klick). Tests: Server-Typecheck + neuer test:progression (per-Skill-XP; XP-Gate blockt bei 50/öffnet bei 70; niveau-gezielte Ausbildungsziele) + test:leistung (unverändert grün) + ng build (prod) + CI-Step ergänzt. Kein Solver-Redeploy. Doku: docs/Akademie.md (Status), HANDOFF (OP-R1-3 Slice 1), Timesheet (Session 24). True North: genauere Eignungs-/Kompetenzdaten → bessere Taktung.
  • #188OP-R1-3 erfasst + Design festgezurrt → docs/Akademie.md: Skill-Niveau-Progression (niveau-gezielte Ausbildungsziele · begründete Beförderung · XP-Todo · Akademie-Vorbereitung) (Design-PR, kein Code → kein Version-/Build-Bump). Neuer OP (Nutzer 06-25), erweitert OP-R1-2: (1) Ausbildungsziele zielen auf eine Stern-Stufe (z. B. Keramik ★★) — Mitarbeiter.ausbildungsZiele: string[]{skillId, zielNiveau}[]; nur noch nicht erreichte Ziele anbieten. (2) XP-Schwellen je Niveau (G-1; heute Heuristik in niveauVorschlaege), XP künftig je Skill. (3) Beförderung begründungspflichtig (externer Lehrgang/Manager/XP) → OP-AUDIT-1-Event (= Zertifikats-Nachweis). (4) Gesammelte XP als „beförderungsreif"-Todo (MA-Karte + Übersicht; derived D-2, propose-not-execute). Bereitet Akademie/Zertifizierungen vor (evtl. OP-ACADEMY-1). Offene Frage (anstehende Beförderung „zählt nicht"/„weitere XP erforderlich") mit Vorschlag erfasst: Manager-Aktionen bestätigen/vertagen/verwerfen am Todo. Design (docs/Akademie.md): Datenmodell (ausbildungsZiele{skillId, zielNiveau}, XP-Schwellen je Niveau G-1, Beförderungs-Historie append-only als OP-AUDIT-1-Event), per-Skill-XP-Ableitung (XP-Schwelle + Qualitäts-Gate kombiniert), Beförderungs-Flow bestätigen/vertagen/verwerfen (= Antwort auf die offene Frage; XP nie genullt), Rollen (Manager/OP-AUTH-1), Slices, Akademie/Zertifizierungs-Vision (evtl. OP-ACADEMY-1). Doku: docs/Akademie.md (neu), HANDOFF (OP-R1-3), CLAUDE.md (Tiefenquellen), Timesheet (Session 23). Kein Code/Solver-Redeploy.
  • #187OP-COST-1: Kosten-Dashboard-Architektur festgezurrt (Design-PR, kein Code → kein Version-/Build-Bump, Präzedenz #182). Neue lebende Doku docs/Kosten.md pinnt das Design der Kostenkontrolle in der App. Scope-Entscheidung (Nutzer-Wahl 06-25): zwei getrennte SichtenA betriebswirtschaftlich (Arbeits- + Materialkosten + Marge je Auftrag/Leistung, Soll-Ist; Management-Sicht) · B Infra-/Cloud-Kosten (Cloudflare/Fly/D1/LLM-Spend; Ops-Sicht) — getrennte Datenquellen/Rollen, kein Misch-KPI. Design-Entscheidungen: (1) Arbeitskosten abgeleitet aus den vorhandenen Leistungsnachweise.istMin (OP-R1-2) × Stundensatz-Stammdaten je Abteilung (abteilungId/TaxonomyValue, neu, admin-editierbar G-1; Mitarbeiter-/Skill-Override später — Freitext-role als Schlüssel ungeeignet). (2) Materialkosten konsumieren OP-R10-1 (strukturierte Materialerfassung Menge/Charge/Verschnitt) × Materialpreise — nicht dupliziert. (3) Umsatz/Marge aus OP-R7-6 (Preismodell/Auftragswert) bzw. SevDesk (OP-BILLING-1). (4) Derived nie speichern (D-2) — wie leistung.ts (Fakten gespeichert, Sichten abgeleitet). (5) Rollen/Sichtbarkeit: Kosten = sensibel → Management/Owner-Gate, hängt an OP-AUTH-1 (interim server-seitiges Admin-Flag, kein Broadcast-Leak, OP-SEC-1 #6); Stundensatz-/Preis-Änderungen als OP-AUDIT-1-Event. (6) Abgrenzung: ≠ Rechnungsstellung (SevDesk/OP-BILLING-1), ≠ SaaS-Paygate (OP-PAY-1), ≠ Betriebs-Logs (OP-LOG-1). Build-Slices: A1 Arbeitskosten je Auftrag = baubar JETZT (keine neue Abhängigkeit, nur Stundensatz-Stammdaten + Ableitung, test:kosten) · A2 Materialkosten (gated OP-R10-1) · A3 Marge+Dashboard (gated OP-R7-6/SevDesk) · B1 Infra-Kosten (manuell→Provider-APIs, OP-OBS-1). Split (Nutzer-Wahl „split"): auf eigenem Branch claude/op-cost-1-design, getrennt von der parallelen Audit-Binding-PR #186 (claude/loving-lovelace-x0cht6). Doku: docs/Kosten.md (neu), HANDOFF (OP-COST-1), CLAUDE.md (Tiefenquellen), docs/Risikoregister.md (RISK-11 Garbage-in-Stammdaten, RISK-12 Sichtbarkeit vor Rollenmodell), Timesheet (Session 22). Kein Code / kein Solver-Redeploy. True North: schärft „Auslastung" um Wirtschaftlichkeit/Marge (Frage 1).
  • #186OP-AUDIT-1: D1-Audit-Binding gesetzt — Dual-Write live (Version 0.2.1 → 0.2.2 PATCH, Build 3 → 4). Aktiviert den seit #184 dormant gebauten D1-Schreibpfad: [[d1_databases]]-Binding (binding = "DB"taktano-audit, database_id 6a080ffd-…, migrations_dir = "migrations") in server/wrangler.toml ergänzt. Beim Merge auf main deployt der strikte CD-Job (ci.yml) den Worker mit DB-Binding → env.DB ist gesetzt → der guarded Dual-Write (protokolliereAbwesenheit → Blob + D1, fire-and-forget) und der Boot-Backfill (d1BackfillFromBlob) werden live; ohne Binding waren beide No-ops (exakt bisheriges Verhalten). Vorbedingungen — beide nutzerseitig bestätigt, bevor das Binding gesetzt wurde (docs/Audit-Log.md §7.4): (a) das per Cloudflare-MCP verbundene Konto (in dem taktano-audit liegt) ist das Deploy-Konto (CLOUDFLARE_ACCOUNT_ID) → database_id löst beim Deploy auf; (b) der CI-CLOUDFLARE_API_TOKEN hat D1-Bearbeitungsrechtewrangler deploy mit Binding läuft durch (sonst strikter CD-Job → main rot). Entscheidungen: (1) Version = PATCH (0.2.2) — diese PR ergänzt nur das Binding (Config); die Dual-Write-/Backfill-Logik kam bereits in #184 (selbst PATCH), kein neuer Code-/Feature-Surface, rückwärtskompatibel (additiv, Blob bleibt synchrone Fairness-Quelle). Build +1 (→ 4) je harter Regel (deploybare Verhaltensänderung). (2) Kein Doppel-Apply-Risiko — Migration 0001 ist remote bereits angewandt (#185) und idempotent (CREATE … IF NOT EXISTS); wrangler deploy wendet ohnehin keine D1-Migrationen an. (3) Hybrid unverändert — DO-Blob bleibt Quelle der synchronen Fairness, D1 ist der durable append-only Sink; Lese-Umstellung auf D1 (async+Cache) + Slice 2/3 (breite Erfassung · Panel/Rollen/Suche) bleiben offen. Kein Solver-Redeploy. Doku: docs/Audit-Log.md (§7 Schreibpfad + D1-Aktivierung [Schritte 1–4 ✅]), HANDOFF (OP-AUDIT-1), docs/Compliance.md (ISO-27001-Checkliste: Audit-Log-EU-Persistenz aktiv), Timesheet (Session 21). True North: stützt OP-OPT-7 (durable Fairness-Historie) + OP-COMPLIANCE-1 (EU-Residenz/Audit-Bereitschaft jetzt persistent). Go-Live: beim Merge auf main.
  • #185OP-AUDIT-1: D1-Audit-DB provisioniert + migriert (Binding bewusst zurückgestellt) (Nutzer-Wahl „DB anlegen, Binding später"; kein Codekein Version-/Build-Bump, Präzedenz #182). Aktiviert die Infra für den in #184 dormant gebauten D1-Pfad ohne Deploy-Risiko: D1-DB taktano-audit in EU-Region weur (DSGVO-Residenz) via MCP d1_database_create angelegt (database_id 6a080ffd-9cad-4c8e-80df-314beebdab9b) + Migration 0001_audit_entries.sql angewandt (audit_entries INSERT-only + 4 Indizes; Remote per sqlite_master-Query verifiziert: Tabelle + ix_audit_tenant_ts|_type_ts|_res_ts|_actor_ts). Entscheidungen: (1) Binding NICHT gesetztserver/wrangler.toml bleibt unangetastet, env.DB weiter undefined → exakt bisheriges Laufzeit-/Deploy-Verhalten, null Risiko (deploy-sicher wie #184). (2) Zwei harte Aktivierungs-Vorbedingungen festgehalten (docs/Audit-Log.md §7), beide nutzerseitig zu bestätigen, bevor das Binding gemergt wird: (a) das per MCP verbundene CF-Konto muss das Deploy-Konto sein (sonst löst die database_id beim Deploy nicht auf), (b) der CI-CLOUDFLARE_API_TOKEN braucht D1-Rechte (sonst bricht wrangler deploy). (3) Konto-Vorbehalt dokumentiert — die DB liegt im aktuell verbundenen Konto; Identität mit dem Deploy-Konto noch zu verifizieren. Kein Solver-Redeploy, kein Worker-Verhaltens-/Deploy-Risiko (dormant). Doku: docs/Audit-Log.md (Status + §7-Aktivierung [Schritte 1+2 ✅, 3+4 ⛔] + §8), HANDOFF (OP-AUDIT-1), Timesheet (Session 20 + Summe-Rollup 18–20 nachgezogen). Offen (Go-Live): Konto-Match + Token-D1-Rechte bestätigen → Binding mergen → Dual-Write live. True North: stützt OP-OPT-7 (Fairness-Historie) + OP-COMPLIANCE-1 (EU-Residenz/Audit-Bereitschaft).
  • #184OP-AUDIT-1: D1-Verdrahtung (deploy-sicher, dormant) + OP-COST-1 erfasst (Version 0.2.0 → 0.2.1, Build 3). Bringt das im Design (#182) entschiedene D1-Audit-Log code-seitig an, ohne den Produktiv-Deploy zu gefährden. Gebaut: (1) Schema-Migration server/migrations/0001_audit_entries.sql (audit_entries INSERT-only + 4 Indizes; Spalte ausloeser statt SQLite-Keyword trigger); (2) Env.DB?: D1Database optional; (3) guarded Dual-WriteprotokolliereAbwesenheit schreibt jeden Abwesenheits-Historien-Eintrag zusätzlich fire-and-forget nach D1 (d1InsertAudit, INSERT OR IGNORE, Fehler blocken den Broadcast nie), nur wenn das DB-Binding existiert (sonst No-op); (4) idempotenter Backfill der Interim-Blob-Historie nach D1 beim Boot (d1BackfillFromBlob, nur wenn D1 leer). Entscheidungen: (1) Kein [[d1_databases]]-Binding in wrangler.toml in dieser PRwrangler deploy validiert D1-Bindings, eine fehlende/nicht erreichbare DB würde den Deploy-on-Merge brechen; daher bleibt der D1-Pfad dormant (Binding fehlt → env.DB undefined → exakt bisheriges Verhalten, kein Risiko) und wird erst aktiviert, wenn die DB provisioniert und der CI-CLOUDFLARE_API_TOKEN D1-Rechte hat (Aktivierungs-Checkliste: docs/Audit-Log.md §7). (2) Hybrid beibehalten: der DO-Blob bleibt in diesem Slice die Quelle der synchronen Fairness (snapshot()); D1 ist der durable append-only Sink — die Lese-Umstellung der Fairness auf D1 (async + Cache) ist ein Folge-Slice. (3) Best-effort Dual-Write (Blob maßgeblich) — Retry/Pufferung bei D1-Ausfall folgt. Zusätzlich neuer OP OP-COST-1 erfasst (Nutzer-Wunsch): Kostenkontrolle / Kosten-Dashboard in der App — Arbeits-/Material-Kosten + Marge je Auftrag/Leistung (Basis: Leistungsnachweise/Ist-Zeit), Scope (betriebswirtschaftlich vs. Infra-/Cloud-Kosten) + Datenquellen/Rollen zu klären (HANDOFF §4). Tests: Server-Typecheck (D1-Typen) + test:fairness + Smoke (spike/operativ) + No-Hex grün. Kein Solver-Redeploy; kein Worker-Verhaltens-/Deploy-Risiko (dormant). Doku: docs/Audit-Log.md (§7 Integration + D1-Aktivierung, §8, Status), HANDOFF (OP-AUDIT-1 + OP-COST-1), Timesheet (Session 19). Offen (Aktivierung): D1-DB provisionieren (EU weur) + Binding + migrations apply + CI-Token-D1-Rechte bestätigen → dann geht der Dual-Write live.

2026-06-24

  • Branch claude/workflow-reservation-pickup-6m2q37 (reine Doku/Analyse; PR folgt bei Bedarf) — Flow-Analyse Auftrags-Flow (Reservierung → Anlieferung → Annahme → Aufbereitung → Produktion → QS → Abholung). Auf Nutzer-Eindruck „nicht intuitiv" geprüft aus Daten-, Prozess- und UX-Sicht; neues Dokument docs/Flow-Analyse.md. Befund: drei nicht deckungsgleiche „Flows" (8-Status-Lifecycle vs. 5-Phasen-Standard-Prozess vs. 5-Stationen-UI-Flow-Band); der gefühlte 7-Schritt-Flow vermischt zwei orthogonale Achsen (Lifecycle/Reservierung vs. fachliche Phase); Anlieferung ≠ Annahme auf einen Status angeliefert; QS doppelt modelliert + End-/Nachkontrolle vermengt. Entscheidung: Zielbild „Phasen first-class" → schärft OP-R3-1 (umgesetzt in PR 1–7, siehe 2026-06-25). Keine Code-Änderung.

  • #183OP-AUDIT-1 Slice 1: Abwesenheits-/Wunschfrei-Historie → OP-OPT-7-Fairness (erster Bau nach dem Design #182; Version 0.1.0 → 0.2.0, Build 1 → 2). Problem: Eine entfernte Abwesenheit verschwand spurlos aus Mitarbeiter.abwesenheiten — die Fairness-Frage „wer hatte in den letzten Monaten wie viel Wunschfrei" (OP-OPT-7, Design-Entscheidung #173) war damit unbeantwortbar. Bau: neue append-only AbwesenheitHistorieEintrag[] im DO-State (server/src/model/types.ts); jedes Hinzufügen/Entfernen einer Abwesenheit hängt über protokolliereAbwesenheit einen unveränderlichen Eintrag an (Entfernen = zweiter Eintrag aktion='entfernt', nie Löschen). schemaVersion 10 → 11 mit idempotentem Backfill aus den aktuellen Abwesenheiten (Erfassungszeit unbekannt → Stand-in von), damit die Fairness sofort einen Stand zeigt. Abgeleitet (D-2, nie gespeichert): pure, selbst-getestete fairnessAusHistorie (server/src/operativ/fairness.ts) zählt je Mitarbeiter die im gleitenden 90-Tage-Fenster gewährten Wunschfrei-Blöcke (FairnessDTO an Employee) — inkl. später entfernter (die Fairness gilt der Gewährung, nicht dem Bestand); in der Mitarbeiter-Karte als „Wunschfrei 90 T: N · M genehmigt" sichtbar (staff.component.ts, nur --tk-*-Tokens). Entscheidungen: (1) Interim im DO-Blob statt sofort D1 — niedrig-volumig, kleinster nutzbarer Schritt; bewusst als Interim markiert, wandert mit der D1-Verdrahtung (OP-DATA-1) um (Design docs/Audit-Log.md §8-Hinweis). (2) Scope = nur Abwesenheits-Historie: bereitschaft.geoeffnet (on-call gezogen) und zugang.stufe/override (OP-ACCESS-1) bleiben offen, weil ihre Quell-Events noch nicht existieren → sauber als Slice-1-Rest dokumentiert statt Platzhalter zu bauen. (3) Fairness zählt die Gewährung (Erfassung im Fenster), nicht netto-effektive Tage — robust gegen Entfernen und genau die zuvor verlorene Spur; netto-Tage bleiben einem späteren Slice vorbehalten. (4) Akteur interim 'system' (kein Identitäts-Plumbing bis OP-AUTH-1). (5) Derivation als pure Funktion (Repo-Konvention) → npm run test:fairness (CI) beweist die Kern-Eigenschaft „Gewährung überlebt Entfernen" + Härtegrad/Fenster/Mitarbeiter-Isolation/genehmigt-Teilmenge. Tests: Server-Typecheck + test:fairness + Smoke (spike/operativ/replan) + ng build (prod) + No-Hex-Gate grün. Kein Solver-Redeploy (reine DO-/Client-/Ableitungs-Änderung; Optimierer-Verhalten unverändert — Wunschfrei-Pönale steckt bereits in #179/#180). Doku: docs/Audit-Log.md (Status + §8 Slice-1-Stand), HANDOFF (OP-AUDIT-1), CHANGELOG, Timesheet (Session 18). True North: stützt OP-OPT-7 (fairere/vertrauenswürdigere Kapazitäts-/Bereitschafts-Entscheidungen, Frage 3) + OP-COMPLIANCE-1 (Audit-Bereitschaft).

  • #182OP-AUDIT-1: Audit-Log-Architektur festgezurrt (Design-PR, kein Code; User-Wahl „erst Architektur festzurren"). Neue lebende Doku docs/Audit-Log.md pinnt: Speicher-Entscheidung D1 (Cloudflare SQLite, EU) statt DO-Blob (abfragbar · append-only · skalierbar · EU-Residenz; Hybrid — der DO behält die Live-Geschäftsfakten, D1 nur das Audit-Log; folgt OP-DATA-1/Drizzle); D1-Schema-Entwurf (audit_entries + Indizes, INSERT-only, Korrektur = kompensierender Eintrag); Event-Katalog (typisiert, Akteur Mensch/system + Auslöser-Kausalkette); „nicht reverse-engineerbar"-Sicht-/Suchmodell (rollenbasiert; kein Oracle über Existenz/Inhalt/Anzahl/Timing verborgener Einträge — uniforme Leerantwort, Counts/Pagination nur über autorisierte Teilmenge; Bezug OP-SEC-1); Retention + PII-Scrubbing (DSGVO DE/AT/CH, EU-D1); DO→D1-Schreibpfad (fire-and-forget, blockt den Broadcast nie); Build-Slices (1 Abwesenheits-/Bereitschafts-Historie → entsperrt OP-OPT-7-Fairness + OP-ACCESS-1-Nachweis; 2 breite Event-Erfassung; 3 read-only Panel + Rollen + Suche). Abgrenzung: Audit-Log ≠ Betriebs-Logs (OP-LOG-1) ≠ Auftrags-Protokoll. Doku: HANDOFF (OP-AUDIT-1 §4-Eintrag), CLAUDE.md (Tiefenquellen), docs/Audit-Log.md, Timesheet (Session 17). Kein Code / kein Solver-Redeploy.

  • #181Projekt-Konventionen & Governance: Versionierung (SemVer) + Build-Nummer · SBOM · Compliance/Zertifizierung · Risikoregister · Log-Handling. Mehrere stehende Konventionen in CLAUDE.md verankert + die konkrete Version/Build-Anzeige gebaut.

    • Versionierung (SemVer, bewusst hochgezählt): erstes Ziel MVP = 1.0.0 (Vor-MVP bleibt 0.x); MINOR = Optimierungen/Features (1.0.0→1.1.0), PATCH = Bugfixes/Tweaks (1.1.0→1.1.1), MAJOR = Meilenstein/Breaking. Build-Nummer parallel, monoton, +1 je PR. Single Source server/src/version.ts (APP_VERSION='0.1.0', APP_BUILD=1) → über den State an den Client; sichtbar in der UI (Cockpit-Toolbar neben dem Solver-Build) und in den Logs (DO-Boot-Zeile).
    • SBOM immer pflegen (OP-SBOM-1): CycloneDX via npm run sbom (Server+Client) + CI-Job sbom (Artefakt je Lauf → immer aktuell); Python-Solver-SBOM offen.
    • Compliance/Zertifizierung (OP-COMPLIANCE-1): lebende docs/Compliance.md (TÜV/ISO 27001/Security-Audit-Bereitschaft · Zielmärkte DE/AT/CH · Rahmen DSGVO/E-Rechnung/Arbeitszeit) + proaktives Flagging kritischer/regulatorischer Themen mit Optionen.
    • Risikoregister docs/Risikoregister.md: 10 Risiken geseedet (DO-Blob-Wachstum, fehlende Wunschfrei-Historie, PII/DSGVO, Supply-Chain, Mandanten-Isolation …), Review je Session/PR.
    • Log-Handling (OP-LOG-1): Logger-Wrapper (strukturiert, Version/Build + trace_id, keine rohe console im Laufzeitpfad, PII-Scrubbing) als OP erfasst; Transport via OP-OBS-1; heute interim console (Boot-Zeile).
    • Entscheidung: Vor-MVP-Version = 0.1.0 (passt zur bestehenden package.json-Version beider Pakete); 1.0.0 markiert das fertige MVP. Server-Typecheck + ng build (prod) + alle Self-Tests + No-Hex grün. Kein Solver-Redeploy. Doku: CLAUDE.md (§Versionierung, §Compliance, Tiefenquellen), HANDOFF (OP-LOG-1/OP-SBOM-1/OP-COMPLIANCE-1), docs/Compliance.md, docs/Risikoregister.md, Timesheet (Session 16).

2026-06-23

  • #180OP-OPT-7 Slice 2: Bereitschaft/Überlauf als Hybrid-Vorschlag (baut auf #179). Kern-Korrektur („nie still"): Überlauf-/Bereitschafts-Schichten (Schicht.art='ueberlauf') zählten bisher wie reguläre Schichten zur Verfügbarkeit — der Optimierer konnte sie still belegen. mitarbeiterAvailability blendet sie jetzt standardmäßig aus (neuer includeUeberlauf-Schalter); Bereitschaft ist damit aus dem Normalbetrieb heraus. Hybrid-Vorschlag (Entscheidung #173): der Optimierer rechnet zusätzlich eine Variante, die die Bereitschaft öffnet (berechnePlaene(…, bereitschaft=true)buildProblem/scheduleLeistung schalten ueberlauf via ueberlaufFenster frei), und vergleicht sie mit dem besten normalen (flow) Plan. Nutzt die Variante die Bereitschaft und lohnt sie sich, entsteht ein bestätigungspflichtiger Eintrag im Vorschläge-Feed (VorschlagAktion bereitschaft) mit konkreter Wirkung: welche Termine gehalten/gerettet (per-Auftrag deltaMin/termin) und wer aus dem On-Call gezogen würde (bereitschaftGezogen). Übernehmen = den Bereitschafts-Plan einmal rechnen + schreiben; nie automatisch. Auslöser (Nutzer-Wahl „auch bei Zeitgewinn"): Vorschlag, sobald Bereitschaft einen Termin rettet oder Aufträge früher fertig macht. Pönale-Ordnung (Slice-1-softBlocks wiederverwendet): geöffnete Bereitschaft wird als Soft-Block mit BEREITSCHAFT_POENALE_PRO_MIN=5 belegt — teurer als ein einfacher Wunschfrei (2 → „erst Wunschfrei, dann Bereitschaft"), aber billiger als ein genehmigter (200 → eine zugesagte freie Schicht ist stärker geschützt als On-Call): 2 < 5 < 200; im TS-Greedy via softBlockRang (frei → Wunsch → genehmigt → Bereitschaft, zuletzt). Kein model.py/Solver-Redeploy: Bereitschaft ist nur ein weiteres gewichtetes softBlock-Fenster — die CP-SAT-Pönale aus #179 trägt es bereits; nur der Worker (Verfügbarkeit/buildProblem) + DO + Client ändern sich. Client: der bestehende Vorschläge-Feed (recommendations.component) rendert + übernimmt/verwirft den Bereitschafts-Vorschlag generisch (nur VorschlagAktion-Typ gespiegelt). Entscheidungen: (1) Auslöser „auch bei Zeitgewinn" (Termin-Rettung ODER früher fertig); (2) Vorschlag im manuellen „Optimierung vorschlagen"-Lauf (optimierenVorschau) — hält den Auto-Feed latenzarm (Auto-Bereitschaft = möglicher Folge-Schritt); (3) Vorschlag nur, wenn die Variante die Bereitschaft wirklich belegt (bereitschaftGezogen nicht leer) — kein irreführender Bereitschafts-Vorschlag bei reiner Solver-Streuung. Tests: test:bereitschaft (Überlauf zählt nicht zur Default-Verfügbarkeit; includeUeberlauf/ueberlaufFenster schalten frei; Status-Gate) + CI; Server-Typecheck + alle Self-Tests + ng build (prod) + No-Hex grün. Damit OP-OPT-7 Slice 1+2 fertig (Wunschfrei-Pönale + Bereitschaft-Hybrid); offen bleibt nur die Verteilung/Fairness-Historie (Block-Füllen + Wunschfrei-/Bereitschafts-Historie) — hängt an OP-AUDIT-1. Folge-Ideen aufgenommen (User): (e) konfigurierbarer Bereitschafts-Vorlauf (Mindest-Ankündigung), (f) verschiedene Bereitschafts-Arten (mehrere On-Call-Typen, Taxonomie-artig), (g) Bereitschafts-Dienstplanung (Roster: wer wann Bereitschaft hat) — s. HANDOFF OP-OPT-7. Doku: HANDOFF OP-OPT-7, Lastenheft §4.4a/F05, Timesheet (Session 15). True North: genauere, vertrauenswürdigere Planung (Frage 1/3) — Bereitschaft wird nie verdeckt verplant, sondern als transparenter Vorschlag mit Wirkung gezeigt.
  • #179OP-OPT-7 Slice 1: Wunschfrei-Pönale im Optimierer (Solver-Anbindung der weichen Soft-Blocks aus #173). Weiche „Wunschfrei"-Blöcke (Abwesenheit.hart=false) reduzieren die Verfügbarkeit weiterhin nicht, werden vom Optimierer jetzt aber gewichtet gemieden — in beiden Solvern (Parität wie OP-OPT-5): CP-SAT (solver-service/model.py) pönalisiert je zugewiesenem Schritt die Überlapp-Minuten mit den Soft-Block-Fenstern des Mitarbeiters (add_max/min_equality für den Überlapp + „nur wenn zugewiesen"-Gate via only_enforce_if(on), additiv zu extras); TS-Fallback misst wunschfreiMin in objective.ts (Tie-Break in istBesser direkt nach Durchsatz) und der Greedy reiht in schedule.ts die Kandidaten frei → Wunsch → genehmigt (pickCrew nimmt die ersten passenden). Abstufung (Design-Entscheidung 3): neues Feld Abwesenheit.genehmigt — einfacher Wunsch (Faktor 1) vs. vorgesetzten-genehmigt = „quasi-hart" (WUNSCHFREI_GENEHMIGT_FAKTOR=100); Editor-Toggle im Mitarbeiter-Raum (nur im Wunschfrei-Modus) + „✓ genehmigt"-Marker in der Liste. Geteilter Helper weicheBloecke (availability.ts) speist Solver-Payload (problem.tsemployees[].softBlocks mit gewicht/min) und Fallback aus einer Quelle. Gewichte (WUNSCHFREI_POENALE_PRO_MIN=2) als Konstanten, kalibriert unter Reserve/Termintreue: ein einfacher Wunsch beugt sich Deadlines/Reserve, schlägt aber marginalen Flow; genehmigt (×100) ist faktisch quasi-hart, nur von Eil/Garantiert/Termintreue zu brechen. Entscheidungen: (1) Slice 1 = nur Wunschfrei — Bereitschaft/Überlauf (Schicht.art='ueberlauf') folgt als Slice 2, weil das per Design „Hybrid" ist (Optimierer rechnet, übernimmt aber nie still → bestätigungspflichtiger Vorschlag mit Effekt-Vorschau) — eine Vorschlags-UX, kein reiner Penalty; (2) deploy-sicher: das neue softBlocks-Feld liest der Solver mit .get → der aktuell deployte Solver ignoriert es (kein Bruch), der TS-Fallback honoriert es sofort; (3) genehmigt optional (Reader defaulten) → kein schemaVersion-Bump (Parität zu #173). Tests: python model.py um den Wunschfrei-Fall erweitert (gleich geeigneter, unblockierter MA wird gewählt; ohne Alternative bleibt der Block belegbar → genehmigt ist weich, nicht hart) · test:ausfall um weicheBloecke/bewerte/istBesser (Pönale-Minuten, genehmigt-Faktor ×100, Tie-Break). Deploy: die solver-service/**-Änderung triggert beim Merge auf main automatisch fly-deploy.yml (Fly-Auto-Deploy, vorab vom python model.py-Gate geschützt) → die CP-SAT-Pönale geht ohne manuellen Schritt live (flyctl/Token hier nicht verfügbar). Server-Typecheck + alle Self-Tests (CP-SAT + TS) grün · ng build (prod) + No-Hex grün. Doku: HANDOFF OP-OPT-7 (Slice-1-Stand) + OP-R8-11, Lastenheft §4.4a/F05, Timesheet (Session 14). True North: genauere, vertrauenswürdigere Planung (Frage 1/3) — der Plan respektiert reale Wunschfrei-Wünsche, statt sie zu ignorieren.
  • #178Eingriffsregeln am Preemption-Hebel durchgesetzt (OP-R3-3, server-seitig — User-Wahl „kein Solver-Redeploy"; schließt OP-R3-3 ab). Architektur-Befund: Der Optimierer splittet/preemptet Schritte nie (atomare Single-Crew-Intervalle in TS-Scheduler + CP-SAT), Preemption ist ein manueller Hebel, und das Resume behält die Crew (starteTeilschritt). Es gibt also nichts im Solver zu pönalisieren — die Regeln greifen dort, wo der Eingriff real entschieden wird: am Konflikt-/Preemption-Hebel. unterbrechung: vermeiden: Kandidaten werden „erlaubt vor vermeiden" gereiht + tragen einen ⚠-Soft-Hinweis („sollte möglichst nicht unterbrochen werden"); verboten bleibt ganz aus der Kandidatenliste (istUnterbrechbar). uebernahme: am Hebel sichtbar — verboten → „nur der ursprüngliche Mitarbeiter darf fortsetzen, bei Ausfall blockiert der Schritt", vermeiden → „möglichst derselbe Mitarbeiter"; da das Resume die Crew unverändert lässt, ist uebernahme: verboten im normalen Ablauf gewahrt. Pure Logik preemptionHinweis/preemptionUnterbrechungsRang (operativ/preemption.ts) + test:preemption erweitert; HebelDTO.warnung (server+client); Anzeige am Hebel in conflicts.component.ts (var(--tk-amber)). Entscheidungen: (1) server-seitig statt CP-SAT (User-Wahl) — eine in den Solver integrierte Pönale hätte heute keine Wirkung (keine Auto-Preemption / kein Step-Splitting) und bräuchte Redeploy → als Zukunfts-Option dokumentiert; (2) uebernahme: verboten nicht als hartes Block des Hebels (Preempten bleibt erlaubt — derselbe MA setzt fort), sondern als Warnung; (3) kein neuer Crew-Reassign-Pfad nötig (es existiert keiner; Resume behält die Crew). Server-Typecheck + test:preemption/test:prozess/spike grün · ng build (prod) grün · No-Hex grün. Kein Solver-Redeploy. Damit ist OP-R3-3 server-seitig abgeschlossen (Editor #175–#177 + Eingriffsregeln #178); eine CP-SAT-integrierte Pönale bleibt optionale Zukunft (erst bei Step-Splitting).
  • #177Leistungs-Prozess-Editor (R3a; schließt den OP-R3-3-Editor ab, baut auf #175/#176). Je Leistung admin-editierbar: Stammfelder (Name · Standzeit · Status aktiv/inaktiv) und die Prozess-Komposition — Schritt-Reihenfolge (↑/↓), Teilschritt je Schritt (Picker), Abhängigkeit (nach_vorherigem/parallel/frei), Dauer-Override (sonst Standarddauer), Schritte hinzufügen/entfernen. Persistenz: leistungen jetzt im DO persistiert (Voll-Persist wie OP-R1-1; structuredClone + onStart-Backfill + SCHEMA_VERSION 9→10); schedulerInput() speist sie ein und buildProzessKatalog liest sie → Edits wirken auf neue Aufträge (Komposition/Standzeit/Dauer fließen in Taktung). Server: pure setzeLeistungFelder + setzeLeistungProzess (ersetzt die Komposition atomar; unbekannte Teilschritte / ungültige Abhängigkeiten / Override <1 werden verworfen) + Handler leistung.update/leistung.setProzess. ProzessDTO um status, ProzessSchrittDTO um dauerOverrideMin erweitert. Client: „Prozesse"-Workspace mit Tab-Umschalter (Teilschritte ↔ Leistungen); Leistungen-Tab = Karte je Leistung mit Stammfeld-Inputs + Kompositions-Editor (Reorder/Picker/Abhängigkeit-Segmente/Override/+−), Service updateLeistung/setLeistungProzess. Self-Test test:prozess um Leistungs-Stammfelder + Komposition (Reihenfolge/Filter/Override) erweitert. Entscheidungen: (1) leistung.setProzess ersetzt die ganze prozess-Liste (ein Pfad für Reorder/Add/Remove/Edit) statt feingranularer Schritt-Messages — einfacher, atomar; (2) Scope = Editieren bestehender Leistungen (Anlegen/Löschen ganzer Leistungen als kleiner Folgepunkt offen); (3) bestehende Aufträge bleiben unverändert (Komposition wird bei Materialisierung gesnapshottet) → Edits gelten für neue Aufträge. Damit ist der OP-R3-3-Editor komplett; offen bleibt nur die Optimierer-Wirkung (Soft-Penalty vermeiden + Übernahme-Durchsetzung, Solver + Redeploy). Server-Typecheck + test:prozess/operativ/spike/solve/eligibility grün · ng build (prod) grün · No-Hex grün. Kein Solver-Redeploy.
  • #176Prozessschritt-Eigenschaften editierbar (R3b; weitere OP-R3-3-Auflösung, baut auf #175 auf). Neben der Skill-Anforderung sind je Teilschritt jetzt auch die Schritt-Eigenschaften admin-editierbar: Dauer (F02) · Cool-down + Indoor-Pflicht (F07/F07a) · optional (F05) · parallel möglich (F04) · mehrtägig erlaubt (F06) · Bucht-Typen (F10) · Unterbrechung/Übernahme-Regel (F15/F16, erlaubt/vermeiden/verboten). Server: pure setzeTeilschrittFelder (Patch-Semantik; Dauer ≥1 / Cool-down ≥0 normalisiert, Bucht-Typen gegen die arbeitsplatz_typ-Taxonomie gefiltert+dedupliziert, Regel-Enum validiert) + Handler teilschritt.update. Da nun Bucht-Typen/optional/Unterbrechung editierbar sind, lesen die restlichen seed-statischen Teilschritt-Maps den persistierten Stand: TS_REQUIRED_TYPES entfällt (→ toAuftragDTO(reqTypesByTs)-Parameter), die optional-Map der Auftrags-Materialisierung und die Preemption-tsById (für istUnterbrechbar) kommen aus this.state.teilschritte. ProzessSchrittDTO um standarddauerMin/parallelMoeglich/mehrtaegigErlaubt/arbeitsplatzTypIds erweitert; neue Taxonomie-Liste ARBEITSPLATZ_TYPEN (Parkplatz-Typen via /parkplatz/i ausgeblendet) im State/Broadcast. Client: „Prozesse"-Workspace um den Block Schritt-Eigenschaften erweitert (Zahl-Inputs, Toggle-Pills, Bucht-Typ-Checkboxen, 3-Wege-Regel-Segmente); Service updateTeilschritt(patch) + arbeitsplatzTypen-Accessor. Self-Test test:prozess um Feld-Normalisierung/-Validierung erweitert. Entscheidungen: (1) Patch-Handler (teilschritt.update mit partiellem Patch) statt Voll-Payload — erweiterbar, weniger Daten je Edit; (2) Abhängigkeit/Dauer-Override bleiben außen vor (per-Leistung, nicht per-Teilschritt → eigener „Leistungs-Prozess-Editor", OP-R3-3); (3) Parkplatz-Typen als Bucht-Anforderung ausgeblendet (Label-Heuristik wie im Scheduler), serverseitig jede gültige arbeitsplatz_typ-ID akzeptiert; (4) Soft-Penalty vermeiden + Übernahme-Durchsetzung im Optimierer weiter OP-R3-3 (reine Stammdaten-Pflege hier, kein Solver-Verhalten geändert). Server-Typecheck + test:prozess/operativ/replan/eligibility grün · ng build (prod) grün · No-Hex grün. Kein Solver-Redeploy.
  • #175Prozessschritt-Skill-Anforderungen editierbar (R3b; Teil-Auflösung OP-R3-3). Der geforderte Skill · das Mindest-Niveau · die Personenzahl je Teilschritt (F11/F11a/F12) sind jetzt admin-editierbar statt read-only aus dem Seed. Persistenz (User-Wahl: Voll-Persist wie OP-R1-1): Teilschritt[] in den DO-State geklont (structuredClone), onStart-Backfill (saved.teilschritte ?? Seed), SCHEMA_VERSION 8→9; schedulerInput() speist die persistierten Teilschritte ein → Edits wirken hart auf Eignung/Machbarkeit (identischer Pfad wie die OP-R1-1-Skills: CP-SAT buildProblem.eligible + TS-Scheduler). Die zuvor seed-statischen Maps (TS_SKILL, tsById in buildProzessKatalog/engpassSkills) lesen jetzt den persistierten Stand (neue Methode teilschrittSkill). Pure Logik server/src/operativ/prozess.ts (setzeSkillAnforderung: genau ein Skill, Niveau 1–3 geklemmt, Personen ≥1) + Self-Test npm run test:prozess (CI): Validierung + End-to-End-Beweis, dass ein Edit die eligible-Menge ändert (Folie-Niveau 1 wird für Super-Premium geeignet, nachdem das Mindest-Niveau 3→1 gesenkt wird). Client: neuer Workspace „Prozesse" (pages/processes.component.ts + Route + Rail) — je eindeutigem Teilschritt (geteilter Baustein) Skill-Picker · ★-Niveau · Personen-Stepper; ProzessSchrittDTO um teilschrittId+benoetigteSkillId erweitert; Service setProzessSkillAnforderung. Design: 9. Workspace-Signaturfarbe --tk-ws-processes (orange #fb923c / light #ea580c) in tokens.jsontokens.css regeneriert (+ build.mjs NAME-Map); WORKSPACES.md (§6, „Eight→Nine") + DESIGN_TOKENS.md-Tabelle gepflegt. Entscheidungen: (1) Voll-Persist (Konsistenz mit Skills/Mitarbeiter) statt Override-Layer — Nachteil „persistierter Stand überschattet künftige Seed-Verbesserungen am ganzen Schritt" bewusst akzeptiert; (2) Scope strikt = die 3 Skill-Felder (Dauer/Cool-down/Abhängigkeit bleiben OP-R3-3); (3) nur teilschritte persistiert (nicht leistungen — nicht editiert, lösen gegen persistierte Teilschritte auf); (4) eigener Workspace statt Unterbringung in bestehender Seite (es gab bislang keine Katalog-UI — die HANDOFF-Notiz „read-only in leitstand.component.ts" war veraltet); (5) Teilschritte als geteilte Bausteine dedupliziert (ein Editor je Teilschritt, Edit wirkt auf alle verwendenden Leistungen). Server-Typecheck + test:prozess/test:eligibility/spike/solve grün · ng build (prod) grün · No-Hex grün · tokens.css-Staleness grün. Kein Solver-Redeploy.
  • #174 — Skill-Katalog: Beschreibung (F02) editierbar (rundet den OP-R1-1-Phase-C-Editor ab). Der „Skill-Katalog"-Dialog auf der Mitarbeiter-Seite konnte bisher nur Name + aktiv/inaktiv, obwohl Skill.beschreibung im Datenmodell steht und skill.create/skill.update sie server- und service-seitig (inkl. SkillDTO + Snapshot-Broadcast) längst durchreichen. Ergänzt im UI (pages/staff.component.ts): je Katalog-Eintrag ein Beschreibungs-Feld (neuer Handler setzeSkillBeschreibung, change-getriggert, getrimmt; leerer Text löscht die Beschreibung) + ein Beschreibungs-Feld im Anlege-Formular (createSkill(name, beschreibung) statt nur name). Entscheidungen: (1) reiner Client-Pfad — keine Server-/Service-/DTO-Änderung nötig (Feld war end-to-end schon vorhanden, nur ohne Oberfläche); (2) change + Trim konsistent mit dem vorhandenen Umbenennen (benenneSkillUm); leerer Text räumt das Feld (Server: beschreibung.trim() || undefined); (3) kein Hard-Delete unverändert (Deaktivieren statt Löschen, Verlaufsdaten bleiben gültig). ng build (prod) grün, No-Hex-Gate grün (nur --tk-*-Tokens); kein Solver-Redeploy.
  • #173 — Abwesenheiten/Soft-Blocks + Schicht-Art (R1-S2/S3; erfüllt OP-R8-11 Mitarbeiter-Teil, neuer Folge-OP OP-OPT-7). Abwesenheits-Editor neu gebaut: Härtegrad (feste Abwesenheit Urlaub/Krank ↔ Wunschfrei/Soft-Block) × Reichweite (ganzer Tag ↔ bestimmte Schichten) mit Von/Bis-Datum. Datenmodell: Abwesenheit um ganzerTag/schichtIds/hart erweitert, SchichtKatalog um art (regulaer/standard/ueberlauf = Bereitschaft). Derived: harte Abwesenheiten reduzieren die Verfügbarkeit schicht-granular (neuer Helper abwesenheitIntervalle, geteilt von availability.ts + ausfall.ts); Soft-Blocks reduzieren nicht, erscheinen als eigenes „Wunschfrei"-Gantt-Band (cyan). Schicht-Art als Badge in der Zuweisung. Self-Test test:ausfall um Schicht-granular + Wunschfrei erweitert (CI). Entscheidungen: (1) Scope = Erfassen + Sichtbar jetzt, Solver-Pönale (Soft-Block meiden, Überlauf nur bei Bedarf) + Bereitschafts-UX als Folge-OP OP-OPT-7 (User-Wahl); (2) Soft-Block defaultet die Verfügbarkeit nicht herunter (nur Band/Pönale-Kandidat); (3) ganzerTag (Default) blockt exakt [von,bis] → abwärtskompatibel zu Alt-Abwesenheiten (kein Schema-Bump nötig, Reader defaulten). Reiner Server-/Client-Pfad, kein Solver-Redeploy. Way-of-Working: neue Guideline „Feature-Branches regelmäßig gegen main aktualisieren" (CLAUDE.md + agents.md §7). Design-Entscheidungen OP-OPT-7 geklärt (23.06., Bau folgt): (1) Bereitschaft = Hybrid (Optimierer rechnet, übernimmt aber nie still → bestätigungspflichtiger Vorschlag mit Effekt-Vorschau); (2) Pönale-Reihenfolge erst Wunschfrei, dann Bereitschaft (Bereitschaft = letzte Reserve); (3) Wunschfrei abgestuft (einfacher Wunsch vs. vorgesetzten-genehmigt = quasi-hart); (4) Verteilung „Block erst vollmachen", beim Block-Anbruch Verteil-Optionen zur Nutzer-Wahl mit Wunschfrei-Historie der letzten 3 Monate (Zeitraum konfigurierbar; Historie hängt an OP-AUDIT-1).
  • #172 — Detail-Fly-in workspace-übergreifend geteilt + auf der Aufträge-Fortschritts-Leiste verdrahtet (Folge zu #171, OP-R8-16): Die Komponente gantt-task-panel.component.tsauftrag-detail-panel.component.ts umbenannt (Selector app-auftrag-detail-panel, Klasse AuftragDetailPanelComponent) — sie ist kein Gantt-Widget mehr, sondern eine geteilte Auftrags-Detail-Fläche. Im Aufträge-Detail wird die Fortschritts-Leiste klickbar: Klick auf einen Schritt öffnet dasselbe rechts einschwebende Panel, fokussiert auf diesen Teilschritt (cyan-Ring), inkl. Aktions-Hub. Entscheidungen: (1) Umbenennen statt Wiederverwenden unter Gantt-Namen — „Selbsterklärbarkeit" (das Panel ist workspace-übergreifend; <app-gantt-task-panel> im Aufträge-Raum wäre irreführend); aktiv geteilte Komponente → keine ungefragte Fremd-Refaktorisierung. (2) Ein Signal (panelInstanzId) steuert Öffnen+Fokus; Panel bindet sel() (live) → schließt automatisch, wenn der Auftrag den aktiven Set verlässt. (3) Schritt-Dots werden echte <button> (Tastatur/A11y) mit Hover-Affordanz; das Inline-Detail bleibt, das Fly-in ergänzt fokussierte Schritt-Sicht + Hebel. Nur --tk-*-Tokens (No-Hex grün), ng build dev+prod grün. Reiner Client-Pfad, kein Server-/Solver-Change. Docs: COMPONENTS.md + WORKSPACES.md (Aufträge §4) + HANDOFF.
  • #171 — Gantt-Task Tooltip + Detail-Fly-in (OP-R8-16): Hover über einen Gantt-Block zeigt einen Schnell-Tooltip (Auftragsnr. · Schritt · Status · Zeit + Cool-down), der Termin-Konflikte hervorhebt (quantifizierter Verzug via formatDauer, Wunsch- vs. geplante Zeit); Klick/Enter öffnet ein rechts einschwebendes Detail-Panel (client/.../gantt-task-panel.component.ts) mit vollen Details (Status-/Terminklasse-Badges, Konflikt-Banner + „Konflikt lösen →" /conflicts, Fakten-Grid Fertigstellung/Wunsch-Abholung/Reserve/Standort, alle Teilschritte mit Zeit/Bucht/MA — der angeklickte cyan hervorgehoben) plus einem Aktions-Hub (in-place Hebel): Lifecycle-Aktionen (erlaubteAktionen, starten → Belegung für Bucht-Wahl), „✦ Vorziehen vorschlagen" (geplant → Vorschlag), „⏱ Verzögerung melden" (Inline-Preset-Picker +15 min … +4 h + Grund → meldeVerzoegerungwar bislang ohne UI im Service), „📍 Umparken" (globales Umpark-Modal), „Im Hofplan zeigen →". Entscheidungen: (1) Hover-Tooltip + Klick-Fly-in statt nur nativem title; der title bleibt als aria-label, Block wird role=button/tabindex=0 + Enter (A11y). (2) Panel self-contained im Gantt (rendert <app-gantt-task-panel>, bindet den live-Auftrag → bleibt aktuell, schließt automatisch, wenn der Auftrag den Plan verlässt) statt Output an die Planungs-Seite. (3) Aktions-Hub statt read-only (auf Wunsch): „propose-not-execute" gewahrt — Plan-Änderungen nur als Vorschlag (Vorziehen) oder expliziter operativer Fakt (Verzögerung/Lifecycle/Umparken), jede Aktion quittiert per Toast; Aktionen spiegeln die kanonische Aufträge-Detail-Leiste + reaktivieren das verwaiste „Verzögerung melden". (4) Im Entwurfs-/Drag-Modus (✎ Plan ändern) unterdrückt — der Block ist dort nur Zieh-Griff; Touch zeigt keinen Hover (direkt Klick). (5) Slide-in via komponenten-lokalem @keyframes (translateX 100%→0, --tk-ease) über Fog-Scrim, prefers-reduced-motion respektiert. Nur --tk-*-Tokens (No-Hex-Gate grün). Scope: app-gantt wird nur auf der Planung verwendet (kein Mini-Gantt im aktuellen Code) → Feature wirkt dort. Reiner Client-Pfad, kein Server-/Solver-Change; ng build grün. Docs: COMPONENTS.md + WORKSPACES.md + HANDOFF-Gantt-Zeile + Timesheet (Session 7).
  • #170 — Helfer-Vorschlag: echte Verfügbarkeitsprüfung zur Schritt-Zeit (OP-R1-2 #6). Die Ausbildungs-Helfer-Vorschläge prüfen jetzt nicht mehr nur das Stammdatum (aktiv + nicht beschäftigt), sondern auch, ob der Auszubildende zum geplanten Schritt-Beginn tatsächlich verfügbar ist (Schicht aktiv + keine Abwesenheit) — über den bestehenden mitarbeiterAvailability (D-2, nichts gespeichert). ausbildungsVorschlaege bekommt dafür einen optionalen verfuegbarBei(mitarbeiterId, start)-Callback (server-seitig verdrahtet); test:leistung um diesen Fall erweitert. Entscheidung: Prüfung am Schritt-Beginn (Näherung; Schicht-Wechsel mitten im Schritt wird nicht zerlegt) — bewusst einfach, Vorschlag bleibt unverbindlich. Reiner Server-Pfad, DTO unverändert → kein Client-Change, kein Solver-Redeploy. Weiter auf diesem Branch (OP-R1-2 + neue OP-R3-3): (1) Güteklassen-gewichtete XP — schwerere Fahrzeuge zählen mehr (Faktor 1/1,25/1,5 für Güteklasse 1/2/3); Leistungsnachweis.gueteklasse. (2) Anteilige Helfer-XP — ein Helfer-Einsatz, der unterbrochen wird oder verspätet beginnt, gibt nur anteilige Erfahrung (lernanteil; Verspätung mindert ab Toleranz proportional, Unterbrechung halbiert); produktive Einsätze unverändert. Dafür TeilschrittInstanz.unterbrochen (beim Pausieren/Preempten gesetzt). (3) Niveau-Aufstieg-Vorschlag — genug produktive, fehlerarme Praxis (≥5 Ausführungen, niedrige Nacharbeit, hohe Bewertung) → Vorschlag „Skill-Niveau anheben" auf der Karte (niveauVorschlaege, Ein-Klick). (4) Neue OP-R3-3 — Unterbrechung/Übernahme in der Prozessdefinition: Teilschritt.unterbrechung + uebernahme je erlaubt/vermeiden/verboten (§4.6 F15/F16); verboten-Unterbrechung wirkt hart auf die Preemption (istUnterbrechbar/unterbrechungsRegel), Katalog-DTO zeigt beide Regeln. Entscheidungen: XP-Parameter konfigurierbar (Güteklasse-Faktor, Verspätungs-Toleranz 15 min, Unterbrochen-Faktor 0,5) · proportionale Minderung nur für Helfer (Ausbildungswert) · Soft-Goal vermeiden im Optimierer + Übernahme-Enforcement + Prozess-Editor-UI geparkt als OP-R3-3 · Team-/Zeitraum-Vergleich bleibt offener OP-R1-2-Punkt. test:leistung um Anteil/Güteklasse/Niveau erweitert. Kein Solver-Redeploy.
  • #169 — Neuer geparkter OP OP-SEC-1: autorisierte Penetration-/Sicherheitstests vor produktivem Mehr-Mandanten-/Kunden-Betrieb (Auth/Mandanten-Isolation · Audit-Log-„nicht-reverse-engineerbar" · Assistenten-Berechtigung/Prompt-Injection · zahlungs-gesteuerter Zugang server-seitig · API/WS/DO · Solver · PII/DSGVO · Secrets/Supply-Chain · Client). Findings git-nah, automatisiert+manuell. Reine Doku.
  • #168 — Wrap-up: Timesheet Session 5 (06-23, ~3.3 h; Σ ~59.5 h) — parallele Vorarbeit (#152–#158/#161) im Wall-Clock paralleler Sessions nicht doppelt gezählt (Untergrenze) — + HANDOFF §4 „Aktueller Stand" auf 06-23/#167 aktualisiert (Verweis auf CHANGELOG als chronologische Quelle). Reine Doku.
  • #167 — Way-of-Working (agents.md §7) geschärft: Branch laufend auf main aktuell halten — zu Beginn (vor inhaltlichen Änderungen), in Abständen, vor PR und vor Merge. Entscheidung: früh + regelmäßig statt nur am Ende → Divergenz/Konflikte bleiben klein und lokal. Erweitert #166. Reine Doku.
  • #166 — Way-of-Working (agents.md §7): Branch vor PR auf aktuellen main aktualisieren (fetch + rebase/merge origin/main). Entscheidung: behebt die wiederholten „base branch was modified"/Merge-Konflikte durch parallele Merges — Konflikte entstehen lokal beim Autor statt im PR. Reine Doku.
  • #165 — Sequenzierung: SevDesk-Integration zurückgestellt (kommt später, nicht nächste Iteration) — damit auch der abhängige zahlungs-gesteuerte Zugang (OP-ACCESS-1). Entscheidungen aus #164 bleiben gültig, nur der Bau wartet. Reine Doku.
  • #164 — Strategie-Session festgehalten (Markteintritt EU, reines B2B): docs/Billing-Zugang.md + OP-AUTH-1/2 erweitert + OP-BILLING-1 · OP-ACCESS-1 · OP-I18N-1. Entscheidungen: Rechnung+Mahnwesen = SevDesk (SoR, erfüllt DE-E-Rechnung XRechnung/ZUGFeRD); keine eigene Abo-Plattform (Stripe Billing/Clerk Billing/RevenueCat/MoR verworfen) · PSP optional · B2B-Reverse-Charge/VIES; Auth = Better Auth (self-host, EU-D1; Clerk/WorkOS Fallback); zahlungs-gesteuerter Zugang Stufenmodell Banner→eingeschränkt→gesperrt, server-seitig, fail-open, Admin-Override, Audit. Reine Doku.
  • #163 — Mitarbeiter-Leistung & Erfahrung + Ausbildung als Helfer-Leistung + QS-Mangelerfassung (OP-R1-2, OP-QS-1). Fakten-Modell: neuer Leistungsnachweis je Schritt-Ausführung (persistiert: Auftrag/Teilschritt/Skill, produktiv vs. Helfer, Vorgabe- vs. Ist-Dauer aus tatsächlichen Start/Ende-Stempeln) + Mangel am Auftrag (worauf bezogen = Teilschritt-Instanz → Skill + ausführende MA; Kategorie/Schwere/Beschreibung; Nacharbeit-Aufwand in min; §4.9.1). Abgeleitet (nie gespeichert, D-2): Mitarbeiter-Statistik je Teilschritt/Skill (Anzahl, Helfer-Anteil, Dauer min/avg/median/max, Ø-Abweichung von der Vorgabe, Nacharbeit-Quote + Ø-Aufwand, Bewertung 0–100) + Erfahrungspunkte. Ausbildung: Helfer/Auszubildende je Schritt (helferIds) — reduzieren die Zeit NICHT (rein operativ, nicht im Solver), sammeln beim Abschluss aber Erfahrung. UI: Mitarbeiter-Karte zeigt ⚡ XP + aufklappbare Statistik; Aufträge-Detail weist Helfer je Schritt zu; QS erfasst Mängel (Bezug + Aufwand) statt nur Client-Marker. Reines Modul operativ/leistung.ts + Self-Test test:leistung (CI). Entscheidungen: Leistungsnachweise/Mängel = gespeicherte Fakten, Statistik/XP immer abgeleitet (CLAUDE.md „Derived State nie speichern") · Helfer ohne Scheduling-Effekt (Ausbildung ≠ Kapazität) · produktive Zuteilung gewinnt über Helfer (kein Doppel-Nachweis) · XP konfigurierbar (produktiv 10 / Helfer 5 / im-Plan +2 / Nacharbeit-Malus 6×Schwere) · Mangel-Kategorien v1 als feste Liste (G-1: künftig admin-editierbar) · Demo-Leistungshistorie nur, wenn leer (sofort sichtbare Karte). Kein Solver-Redeploy. Nachtrag (gleicher Branch): Ausbildungsziele je Mitarbeiter (Mitarbeiter.ausbildungsZiele, Editor in der Karte) → abgeleitete Helfer-Vorschläge (ausbildungsVorschlaege): freie/verfügbare Auszubildende werden auf passende offene Schritte mit dem Ziel-Skill als Helfer vorgeschlagen (Karte „+ Helfer" Ein-Klick · 🎓-Markierung in der Auftrags-Helferauswahl). Penaltyfreies Abziehen (G-2-Ausnahme): Helfer-/Ausbildungs-Tätigkeit ist kein produktiver Kontext → jederzeitiges Abziehen für echte Aufträge ohne Wechsel-Pönale (dokumentiert in §6.4.1 + G-2; Helfer sind nicht im Solver). Seed: Marco→Keramik, Tom→Vollfolierung als Demo-Ziele. Self-Test test:leistung um die Vorschlags-Logik erweitert.
  • #162 — Doku-Nachtrag + neue OP: OP-REPORT-1 (tägliche Management-Zusammenfassung DE in zwei Fassungen — nicht-technisch + technisch — per Mail + WhatsApp; geparkt mit offenen Designfragen, u. a. WhatsApp-„Status" nicht via offizieller API) · CHANGELOG-Eintrag für #160 nachgetragen · Timesheet Session 3 (~1.3 h aktiv, Leerlauf exkl.; Σ ~55.0 h). Reine Doku.
  • #160 — Mitarbeiter- & Skills-CRUD + Modell-Zusammenführung (OP-R1-1, Phasen A–E + Schicht-/Abwesenheits-Editor): Mitarbeiter wird kanonische Single Source für UI und Solver (persistiert statt Seed; schedulerInput()); Karten via toEmployeeDTO abgeleitet, currentTask/recommendation transient. Voller CRUD: Identität, Abteilung + Freitext-Rolle, editierbare Verfügbarkeit→abgeleiteter Status, Skill-Qualifikationsmatrix (skillId+Niveau), Skill-Katalog (G-1 Soft-Deaktivieren), Schicht-Zuweisung + Abwesenheits-Editor. Self-Test test:eligibility (CI) + live verifiziert (Skill-Edit kippt Auftrags-Feasibility). Entscheidungen: Mitarbeiter kanonisch, Karten abgeleitet (die zwei Demo-Datensätze waren disjunkt) · Abteilung-Taxonomie + Freitext-Rolle · Verfügbarkeit editieren, „Frei"/„Aktiv" ableiten · Phase C fokussiert (Schichten/Abwesenheiten als Folge-Slice, jetzt enthalten). Reiner Server-/Client-Pfad, kein Solver-Redeploy. Merge-Konflikte mit der parallel gemergten Insights-Arbeit (#157) aufgelöst (mitarbeiterGesamt auf persistierten State umgestellt).

2026-06-22

  • #159 — Light/Dark-Mode (OP-R9-9): Cockpit jederzeit zwischen Hell/Dunkel/System umschaltbar. Zweites Token-Set (Light) wird aus tokens.json generiert (Hell-Wert je theme-abhängigem Token unter $extensions.taktano.light; build.mjs:root[data-theme="light"] + @media (prefers-color-scheme: light) für „System"). ThemeService (Signal mode, isLight/isDark) setzt data-theme am <html>, persistiert je Gerät (localStorage), folgt bei „System" live der OS-Wahl; No-Flash-Inline-Skript in index.html; Toggle im Sidebar-Fuß (Ein-Klick-Zyklus System→Hell→Dunkel). Entscheidungen: Tokens bleiben einzige Farbquelle → Light als generierter Override statt zweiter Hand-Palette; Default system; Komponenten-Reste text-white/bg-white/x → Tokens (text-tk-heading/bg-tk-soft/hover:bg-tk-hover), damit sie mitschalten; Gantt über vorhandenen [dark]-Pfad an theme.isDark() gebunden; Token-Staleness-Check block-bewusst (Dark- und Light-Wert getrennt geprüft). Folgepunkte OP-DESIGN-2 (A11y-Kontrast Hellmodus) + OP-DESIGN-3 (Gantt-Light auf --tk-*).
  • #158 — Icon-Rail leichter verständlich (OP-R9-12): klappt bei Maus-Nähe/Tastatur-Fokus auf und zeigt Labels neben allen Icons; Workspaces in Cluster gruppiert (Überblick·Operativ·Steuerung·Qualität). Entscheidung: Overlay statt Push (kein Reflow); ein Aufklapp-Reveal ersetzt die per-Icon-Tooltips. (Ersetzt das beim Stack-Merge versehentlich geschlossene #154 — gleicher Inhalt/Branch.)
  • #157 — In-App-Assistent (OP-AI-4) Slices 1–3 + Way-of-Working. Assistent: erweitert die Chatbot-Idee (OP-DOCS-2) zu drei Säulen — Doku-Q&A · App-Feedback · Insights (True-North-nah); gebaut: Insights-Engine (read-only) → DO-Broadcast → Angular-Panel „Lage auf einen Blick". Way-of-Working: Branch nach Merge löschen (agents.md §7/CLAUDE.md) + Doku-Pflicht (HANDOFF/Timesheet) je PR. Entscheidung: Assistent ist vorschlagend, nicht ausführend (simuliert Konsequenzen, führt nicht aus).
  • #156 — 30-s-Solver-Status-Ping bricht eine laufende Optimierung nicht mehr ab: neuer server-seitiger rechenStempel (+1 nur bei echten Läufen), der Client beendet „Optimierung läuft…" erst bei dessen Vorrücken (Routine-Broadcasts lassen ihn unverändert). Entscheidung: Ursache behoben statt den Ping leiser zu machen → fixt die ganze Klasse (Ping · onConnect · Mehrbenutzer); test:optimizing in CI.
  • #155 — „Plan ändern"-Fokus-Modus (OP-R8-15): im Entwurfs-Modus liegt ein Nebel über den übrigen Bedienelementen (fängt Klicks ab = deaktiviert), die relevanten (Toggle·Entwurf·Gantt) bleiben darüber; Klick auf den Nebel/Escape beendet — bei offenen Pins mit Rückfrage „Entwurf verwerfen?". Entscheidung: region-basierter Scrim statt per-Button-disabled (robust + Nebel + Außerhalb-Klick in einem); Rückfrage nur bei offenen Pins.
  • #153 — Audit-Trail etabliert: CHANGELOG.md (je-PR-Eintrag, Backfill #122–#151) + Audit-Trail als Repo-Prinzip (CLAUDE.md/agents.md) + OP-R9-12 (Sidebar verständlicher) & OP-R8-15 („Plan ändern"-Fokus-Modus) festgehalten. Entscheidung: Changelog je PR (nicht je Commit); ältere Stände bleiben in HANDOFF/Git, ab hier je PR; die zwei UX-OPs nur dokumentiert, nicht gebaut (Optionen zuerst).
  • #152 — Konflikt-Navigation auf der Planung (OP-R8-14 Slice 1): Toolbar-Chip „⚡ N Konflikte" zeigt, dass es Konflikte gibt, und springt per Klick zum nächsten ⚡ im Gantt (scrollt hin + hebt kurz hervor). Entscheidung: Sprung-Reihenfolge nach Gantt-Position (links→rechts), eine Stelle je Auftrag; der Konflikte-Workspace bleibt die systematische Triage (Slice 1 = nur sichtbar/anspringbar).
  • #151 — OP-R8-14 festgehalten (Konflikte auf der Planung: auffindbar · springen · in-place lösen). Entscheidung: Hybrid — in-place lösen am ⚡-Balken, der Konflikte-Raum bleibt die systematische Triage-Queue (nicht auflösen).
  • #150 — Docusaurus-Build-Log aufgeräumt: onBrokenMarkdownLinksmarkdown.hooks, Search-docsDir gesetzt, 1 broken link/anchor gefixt. Entscheidung: onBrokenLinks/onBrokenAnchors bleiben warn (echte Brüche weiter melden).
  • #149 — OpenTelemetry-Logging als Prinzip (CLAUDE.md/agents.md) + OP-OBS-1. Entscheidung: Logs via OTel-SDK je Laufzeit, kein rohes console.log/print im Produktivpfad (CLI-Demos/Tests ausgenommen).
  • #148 — CP-SAT-Status aktualisiert sich automatisch (30-s-/health-Ping + onConnect) + „· vor X s"-Stempel. Behebt den zwischen Optimierungen festhängenden Hinweis.
  • #147 — Docs-Deploy triggert jetzt auch bei docs/** (die Haupt-Docs werden gerendert, waren aber nicht im Trigger → Timesheet-Push deployte die Site nicht neu).
  • #146 — Szenario-Konvergenz geprüft (kein Bug — identische Profile = eindeutiges Optimum bei knappen Ressourcen) + Banner „Alle Profile ergeben denselben Plan" + Tests (plaeneIdentisch, profile-distinct). Entscheidung: Vergleich auf echter Zuweisung, nicht gerundeten Zahlen.
  • #145 — Timesheet: Session 1 (06-22) abgeschlossen, ~11.8 h.
  • #144 — CP-SAT: Folierbucht-als-Überlauf-Parkplatz (OP-OPT-5 Slice 2) — Park-Intervalle teilen die Bucht-No-Overlap. Bewusst offen: Präferenz „dedizierte vor Überlauf" als Pönale.
  • #143 — CP-SAT: Indoor-Trocknung-Pflicht (F07a, OP-OPT-5 Slice 1) — allowedBays-Verengung, Parität zum TS-Scheduler.
  • #142 — OP-OPT-4 festgehalten: neuer Auftrag joint-optimal einlasten (Default-Strategie konfigurierbar).
  • #141 — 3. Zielprofil „Termintreue" (OP-OPT-1 P5): minimiert die Anzahl gerissener Termine. Entscheidung: zählt gegen den Wunsch-Abholtermin (ziel); garantiert ist schon hart.
  • #140 — Pin-Konflikt-Feedback korrigiert (OP-R8-13): kein falscher „Erfolg" mehr; gestempelter pinErgebnis-Kanal statt solverInfo.
  • #139 — Solver-Version/Build-Zeit + Fallback-Anzeige im Cockpit (OP-DEPLOY-2).
  • #138 — Solver-Auto-Deploy auf Fly.io (OP-DEPLOY-1). Entscheidung: strikt, fehlt FLY_API_TOKEN → expliziter Guard bricht rot ab (kein stiller Skip).
  • #137 — Gantt-Ausfallzeiten markiert (Pause/Geschlossen/Krank/Urlaub/Wartung), abgeleitet, nichts gespeichert.
  • #136 — CI-Action-Versionen auf Node-24-Majors (Node-20-Deprecation behoben).
  • #135 — App-CD live + Token verifiziert (HANDOFF-Korrektur).
  • #134 — App-Worker-Deploy bei push-to-main (CD).
  • #133Entscheidung: Doku-Plattform = Docusaurus statt GitBook (mit Re-Eval-Triggern) + OP-DOCS-7.
  • #132 — Doku-Footer-SHA aus github.sha (robuster Build).
  • #131 — Doku-Deploy strikt: Build/Deploy-Fehler bricht die Action ab.
  • #130 — Version + Build-Zeit im Doku-Footer (OP-DOCS-6).
  • #129 — Doku-Auto-Deploy + OP-DOCS-2..5 geparkt (Chatbot/MCP/Anwender-Doku/Login-Sichtbarkeit).
  • #128 — Gantt-Drag-UI (3b-2b): Direktverschiebung per Drag → Pin.
  • #127 — Timesheet in den Doku-Index aufgenommen.
  • #126 — OPs geparkt (STANDORT-2 · R9-11 · KIOSK-1) + R9-10 ergänzt.
  • #125 — Pin-Vorschlag + Orchestrierung (3b-2a).
  • #124 — Pin-Constraint im Solver-Backend (3b-1); mehrere Pins pro Durchgang.
  • #123 — Timesheet (Repo-Spiegel) + Way-of-Working in agents.md.
  • #122 — Zahlen-/Dauer-Konsistenz (Slice A): Dauer in W+T+h+min, Singular/Plural automatisch, Termin-Überzug.

Ältere Stände (vor 06-22) sind in HANDOFF.md §2/§4 und der Git-History dokumentiert; der Changelog wird ab hier je PR weitergeführt.