HANDOFF — Werkstatt-Betriebssystem (Neuentwicklung automotivo.de)
Kernaussage. Kompakter aktueller Projektstand + die offenen Punkte (§4) — bei neuer Session zuerst lesen. Die Tiefe steht in den verlinkten Quellen (
Lastenheft.md,CHANGELOG.md,design/); §4 ist das lebende OP-Log.
Lies dieses Dokument zuerst, wenn du auf einem anderen Gerät weiterarbeitest oder eine neue Cowork-Session beginnst. Es spiegelt den Stand kompakt wider und verweist auf die Originalquellen.
1. Projektziel
Vollständige Neuentwicklung des Werkstatt-Betriebssystems für Fahrzeug-Veredelungsbetriebe — fachlich angelehnt an die analysierte Plattform automotivo.de, technisch frei. Auftraggeber: Dr. K (m.kirchhof@drkv.com). Beispiel-Tenant in der Analyse: Vest Automotive GmbH.
1.1 Produktname / Branding — Taktano (16.06.2026)
Der frühere Codename folie2000 wurde durch den Produktnamen Taktano ersetzt. „Folie“ verengte fälschlich auf ein Gewerk (Wrapping), während das Produkt Lack, Detailing, Keramik usw. mit plant; das Suffix „2000“ wirkte altbacken. „Takt“ trifft den Kern — die Taktung/Reihenfolge-Optimierung (Scheduler + CP-SAT) ist das Herz des Systems; „-ano“ macht daraus einen eigenständigen, schützbaren Markennamen.
- Domains:
taktano.com+taktano.dezum Zeitpunkt der Prüfung (RDAP) frei → sichern..com= Primär,.de= DE-Markt/Defensive. - Marken-Vorabprüfung: Keine Firmen-/Marken-Kollision gefunden (DPMA/EUIPO-Sinn, USPTO-Web-Recherche), „taktano“ hat null Web-Präsenz. Kein Rechtsrat — vor Anmeldung formale DPMA/EUIPO-Recherche bzw. Anwalt.
- Verworfene Kandidaten (Domain und/oder Marke belegt): Taktum (Software-GmbH), Taktora (Marke + Inc.), Veredo/Veredia/Veredio (Domain belegt), Veloxa, Arvio, Pylon, Novexa, Kadenzo.
- Naming-Konvention im Code: Anzeigename „Taktano“ (Title-Case), technische Identifier
taktano(lowercase: Worker-Name, Hostnames,taktano-solver,taktano-docs). - Offen (manuell, außerhalb dieses Repos): als OP-BRAND-1 (§4) getrackt — Domains registrieren · GitHub-Repo
drkv-com/folie2000→taktanoumbenennen (alle Code-/Doku-Referenzen sind hier bereits umgezogen) · App-Produktiv-Domainapp.taktano.com: Route ist inserver/wrangler.tomlkonfiguriert (custom_domain=true) — beim Deploy legt CF DNS+Cert an, setzt die Zonetaktano.comim Cloudflare-Account voraus; Access-App-Hostname aufapp.taktano.comsetzen.
2. Was bereits da ist
Erzeugt aus handoff.d/ — nie von Hand editieren (drkv-Standard, drkv-com/everything-as-code-template docs/GitHub-Arbeitsweise.md BP-2, TKT-D-861). Ein PR legt seine Zeile dieser Tabelle als
handoff.d/<YYYY-MM-DD>-<branch-slug>.md an (genau eine Tabellenzeile | Artefakt | Pfad | Status |, PR als
{PR}; neueste zuerst). Alles ab §3 steht in handoff.d/_fuss.md und wird nur geändert, wenn sich der Stand
wirklich ändert; offene Punkte stehen in ops/*.md (gespiegelt als GitHub-Issues), nicht hier.
| Artefakt | Pfad | Status |
|---|---|---|
| GitHub-Arbeitsweise, Stufe 2: Issues als Quelle + Hot-Files abgeleitet (TKT-D-862 · TKT-D-865) | scripts/gen-ops.mjs · scripts/timesheet_summen.py · scripts/funktionsumfang_bauen.py · tests.d/ · feature.d/ · dokumente-nachziehen.yml · agents.md §6.2/§6.6 | ✅ #927 — offene Punkte + Features = Issues, ops/ eingefroren, sync-ops entfernt; Tests.md/Funktionsumfang/Timesheet-Summen erzeugt; offen: #863, #866 |
CI: Pflicht-Check checks (#863, BP-5, TKT-D-863) | .github/workflows/ci.yml (Job ci-gate, name: checks) | ✅ #931 — drkv-einheitlicher Sammel-Check; offen: Admin stellt Ruleset-Pflicht-Check von CI Gate auf checks um |
CI: merge_group-Trigger (#863, BP-5) | .github/workflows/ci.yml | ✅ #929 — CI meldet jetzt im Merge-Queue-Lauf; offen: Admin-Einstellungen aus #863 |
| GitHub-Arbeitsweise, Stufe 2: Glätt-Werkzeuge abgebaut (#864) | scripts/check-doc-consistency.sh §3 · server/package.json · agents.md §6.6 | ✅ #873 — smooth-logs, sync-pr-logs.yml, Dubletten-Checks entfernt; offen: #862, #863, #865, #866 |
| GitHub-Arbeitsweise (drkv-Standard), Stufe 1 (TKT-D-861) | fragmente.json · scripts/fragmente_bauen.py · changelog.d/ · handoff.d/ · timesheet.d/ · .github/workflows/dokumente-nachziehen.yml · labels.yml · .github/ISSUE_TEMPLATE/ · ci.yml (timeouts) · agents.md §6.6 | 🟡 #867 — Logs aus Fragmenten, Bau nach dem Merge; offen: ops/ → Issues (#862), BP-5-Einstellungen/AUTOMATION_PAT (#863), Altwerkzeuge (#864), restliche Hot-Files (#865), Claude-Freigaben (#866) |
| Radius-Ausnahme bleibt bei einer (O-1a) + Farb-Inventur eröffnet (TKT-OP-FARBE-1 / OP-REDESIGN-1 · OP-A11Y-1) | design/CLAUDE.md (Radius-Kontrakt) · ops/TKT-OP-FARBE-1.md (neu) | ✅ Entschieden (PO): der Live-Punkt in der Kopfzeile bleibt eckig — tk-allow-radius behält genau eine Ausnahme (Lade-Ring = Form, keine Ecke). Dabei gefunden: derselbe Indikator unterscheidet „live/getrennt" nur über Grün/Rot + title, obwohl Rot seit OP-REDESIGN-1 auch Primärfarbe ist. Daraufhin vollständig gezählt statt einzeln geflickt: 11 Kandidaten, jeder Fundort angesehen → 3 echte Funde, 1 schwacher, 7 unkritisch. Remediation als Slices F-1…F-4 offen. |
| TKT-OP-CI-3 abgeschlossen (Build-Minuten) | ops/TKT-OP-CI-3.md | ✅ BM-2/3/5/6 gebaut (#854/#856/#857), BM-1 abgelehnt (PO: bleibt ubuntu-latest); Required Checks main = "CI Gate" + "CodeRabbit" |
| Draft-PRs ohne CI (TKT-OP-CI-3 BM-6) | .github/workflows/ci.yml · docs/konventionen/agents.md §6.8 | ✅ PR #856 — alle CI-Jobs skippen auf Drafts, ready_for_review startet den Lauf. Offen: BM-1 CI_RUNNER zurück auf self-hosted (PO) |
| Build-Minuten sparen, Teil 2 (TKT-OP-CI-3 / OP-CI-1 · OP-CI-2) | .github/workflows/ci.yml · scripts/check-security-setup.sh · docs/konventionen/agents.md §6.8 · ops/TKT-OP-CI-3.md | ✅ PR #854 — 5 Kleinst-/Doppel-Jobs zu 2 zusammengelegt (checks = Doku-Konsistenz + Security-Audit; client = Selbsttests + Build + E2E; Persistenz-Gate im server-Job). Deploy wartet jetzt auch auf E2E. Offen: BM-1 CI_RUNNER zurück auf self-hosted (PO) · Branch-Protection: nur „CI Gate“ required? |
| Konflikte & Klärfälle entwirrt (TKT-OP-UX-9 / OP-R8-1 · OP-UX-6 · OP-REDESIGN-1) | client/src/app/leitstand/gruppen-kopf.component.ts (neu) · pages/conflicts.component.ts · services/leitstand.service.ts (weitereKonflikteCount) · shell.component.ts · pages/overview.component.ts · entscheiden.component.ts · onboarding-hinweis.component.ts · client/e2e/konflikte-klaerfaelle.spec.ts (neu) · ops/TKT-OP-UX-9.md (neu) | ✅ Der dichteste Screen im Produkt, auf ein Muster gezogen. Die zwei Warn-Achsen sind jetzt die zwei Tabs: Konflikte = der Plan geht nicht auf (Hebel), Klärfälle = jemand muss ran — „Standort unbekannt" steht dort, wo der Service ihn führt. Jede Gruppe trägt denselben Kopf (Icon · Titel · Anzahl · ein Pflicht-Satz), die Tab-Zahl ist ihre Summe und wird aufgeschlüsselt. Gleichartige Konflikte stehen als EINE Zeile je Art — gemessen: aus 45 wortgleichen Absätzen wird eine Zeile, der Tab passt wieder auf einen Bildschirm. Dazu: ein Wortlaut je Zustand, Primäraktion in --tk-brand statt Grün, „…"-Regel festgeschrieben. Ungesucht gefunden: das Sidebar-Badge zählte weitereKonflikte nicht mit. Nachzug (#852-Review, Folge-PR): eine alleinstehende Konfliktzeile hatte ihr Direkt-Umparken verloren (der Knopf stand nur im aufgeklappten Block) — behoben; und der Summen-Test bekam ein Seed-Bereitschafts-Tor, weil er vor dem Broadcast mit 0 === 0 leer grün laufen konnte. |
Zeitpunkt-Feld: datetime-local vollständig abgelöst (TKT-OP-UX-8 UI-11 / O-3) | client/src/app/util/zeit-eingabe.ts (neu, geteilt) · zeit-eingabe.demo.ts (Selbsttest) · client/src/app/leitstand/zeitpunkt-feld.component.ts (neu) · gantt.component.ts · pages/administration.component.ts · baustein-picker.component.ts · client/e2e/zeitpunkt-feld.spec.ts (neu) | ✅ Ein Feld TT.MM.JJJJ HH:MM für die zwei Stellen ohne Kalender daneben (Gantt „Schritt verschieben", Verwaltung „Sperrzeiten"). Nachsichtig gelesen, Unbrauchbares wird gemeldet statt verworfen. Die Lesart liegt geteilt in util/zeit-eingabe.ts — der Picker nutzt dieselbe Funktion. Dabei gefunden: der 31.02. wäre ohne echte Kalenderprüfung still zum 03.03. geworden. Im Code steht kein type="datetime-local" mehr. |
| Termin-Feld ohne Browser-Locale + Popup-Richtung (TKT-OP-UX-8 Etappe 6 / UI-11 · UI-12) | client/src/app/leitstand/baustein-picker.component.ts · annahme-overlay.component.ts · client/e2e/termin-feld.spec.ts (neu) · docs/konventionen/agents.md §7 · CLAUDE.md | ✅ Der Kalender liefert den Tag, ein Textfeld nur die Uhrzeit — 8 · 08 · 8:30 · 830 · 0830 · 8.30 werden alle gelesen; unbrauchbare Eingabe bleibt sichtbar statt still verworfen. Das Popup klappt im Annahme-Overlay nach oben und verdeckt Slot/Preis/„Annehmen" nicht mehr. UI-10 war eine Fehl-Messung (alle acht echten Lade-Zustände zeigen sich bereits) — dritte dieses OP. Dazu: „immer automerge" als Regel festgeschrieben. TKT-OP-UX-8 ist abgeschlossen. |
| Dialog-Semantik für sechs Overlays + Seiten-Anatomie + Einheiten (TKT-OP-UX-8 Etappe 5 / UI-8 · UI-9) | repark-modal · feedback-form · pages/occupancy · pages/staff (3 Dialoge) · chat-panel (Landmarke) · shell.component.ts (OHNE_NAV) · pages/team.component.ts (<h2>) · pages/costs.component.ts · design/COMPONENTS.md | ✅ Sechs Overlays tragen jetzt role="dialog" + aria-modal + Fokus-Falle + Esc (vorher nur Schleier-Klick = ohne Maus keine Tür); der Chat-Drawer bewusst role="complementary", weil er nichts sperrt. Zwei eigene Messungen korrigiert: doppelter Seitentitel nur auf Team (nicht drei Seiten), und die Einheiten-Zählung hatte Bezeichner mitgezählt — sichtbar waren es zwei Abweichungen von W · T · h · min, die Regel steht jetzt ausgeschrieben. Ungesucht gefunden: die Kopfzeile log auf /verwaltung/* und /bild-schutz über die eigene Seite. Offen: UI-10/11/12 → Etappe 6. |
| Touch-Ziele 24 px + Tastatur im Kalender (TKT-OP-UX-8 Etappe 4 / UI-6 · UI-7) | client/src/styles.css (.tk-ziel, Kontrollkästchen app-weit) · gantt.component.ts · kalender-monat.component.ts (Pfeiltasten) · baustein-picker.component.ts (Klick-Fänger + Esc) · pages/orders.component.ts · client/e2e/touch-tastatur.spec.ts (neu) | ✅ Über zehn Screens gemessen: Zoom-Segmente 20 px, Monatspfeile 22×22, Chips 21 px, Kontrollkästchen 13×13 — alle auf 24 px (WCAG 2.2 2.5.8). Drei Ausnahmen begründet im Wächter-Test statt im Code versteckt (Gantt-Blöcke „Essential“, Inline-Links „Inline“, kompakte Fortschritts-Kette „Equivalent“ — 24 px gebaut, angesehen, verworfen: sprengt die Annahme-Spalte). Kalender: ←/→ Tag, ↑/↓ Woche, Pos1/Ende, Bild↑/Bild↓ mit Monatswechsel; Klick-Fänger nicht mehr fokussierbar, Esc am Popup. Offen: Dialog-Semantik der sieben Overlays → Etappe 5. |
| Overlay-Grundlage: eine Dialog-Anatomie statt vier (TKT-OP-UX-8 Etappe 3 / UI-4 · UI-5) | client/src/styles.css (.tk-overlay-fog · .tk-overlay-flaeche) · client/src/app/leitstand/overlay-fokus.directive.ts (neu) · design/tokens/tokens.json (--tk-z-*) · sechs Dialoge (Quality-Check · Rückfrage · Annahme · Drawer · Gantt · Planung) · client/e2e/dialog-fokus.spec.ts (neu) | ✅ Sechs Flächen behaupteten aria-modal="true", keine hielt den Fokus oder gab ihn zurück — die Direktive tkOverlayFokus liefert Erst-Fokus, Tab-Falle und Rückgabe. Zentrierung über inset+margin:auto statt transform (die Clipping-Ursache aus dem Kalender-PR ist damit strukturell weg). z-Index kommt aus der Token-Leiter --tk-z-schleier/dialog/popup/meldung/werkzeug (löst 50/51 · 55/56 · 60/61 · 62/63 · 70 · 80/90 ab). Neuer E2E-Wächter schlägt ohne die Direktive nachweislich fehl. Nachzug: die Falle war nach einem @if-Inhalts-Wechsel im offenen Dialog blind (Fokus fiel auf <body>, Tab lief dahinter) — behoben über afterEveryRender + Overlay-Stapel; zweiter E2E-Fall, negativ gegengeprüft. Offen: sieben Overlays ohne Dialog-Semantik → Etappe 4. |
| Typo-Skala: zehn Stufen statt 29 freier Pixelwerte (TKT-OP-UX-8 Etappe 2) | design/tokens/tokens.json + tokens.css · client/src/styles.css (tk-fs-*) · 46 Client-Dateien · scripts/check-type-scale.sh (neu) | PATCH: 1.277 text-[Npx] + 30 rohe font-size auf die Skala gezogen (nächste Stufe, kein Neuentwurf); nichts liegt mehr unter 10 px (vorher bis 7 px). Neues Gate hält den Stand. Etappen 3–5 (Dialog-Baustein + Fokus-Trap, Touch-Ziele, Einheiten) bleiben offen. |
| radius 0 durchgesetzt — Gate + Sweep (TKT-OP-UX-8 Etappe 1 / OP-REDESIGN-1) | scripts/check-no-radius.sh (neu) · .github/workflows/ci.yml (Design-Job) · 40 Client-Dateien · client/src/styles.css | PATCH: 610 rohe rounded-* entfernt (Design-Kontrakt: alle --tk-radius-* = 0), drei lokale Neutralisierer damit gegenstandslos; neues Gate hält den Stand, Formen (Lade-Ring) über Marker. Etappen 2–5 (Typo-Skala, Dialog-Baustein + Fokus-Trap, Touch-Ziele, Einheiten) bleiben offen. |
| UI/UX-Durchgang: fünf Kanten behoben, Systemisches als OP eröffnet (TKT-OP-UX-8 neu / OP-A11Y-1) | client/src/app/leitstand/pages/team.component.ts · pages/konten.component.ts · pages/quality.component.ts · pages/staff.component.ts · toasts.component.ts · repark-modal.component.ts · ops/TKT-OP-UX-8.md | PATCH: Numerus „1 arbeitet gerade“ · fehlendes Leerzeichen (Angular entfernt Leerraum zwischen Elementen) · sechs Icon-Buttons ohne Namen · nativer confirm() → token-gestylter Dialog · „QS“ → „Quality-Check“. Systemisch (591 rohe rounded-* bei Radius-Token 0px, 29 Schriftgrößen, vier Dialog-Anatomien, kein Fokus-Trap) als TKT-OP-UX-8 mit Etappenplan + Gate-Vorschlag eröffnet. |
| Abholtermin per Monatskalender — mit Auslastung je Tag (OP-UX-4 / True-North-Frage 3) | server/src/insights/insights.ts (tagesKapazitaet) · server/party/leitstand.ts (ressourcenZeit · insights.kapazitaetTage) · client/src/app/leitstand/kalender-monat.component.ts (neu) · baustein-picker.component.ts · server/src/insights/tageskapazitaet-demo.ts (neu) | MINOR: Der Termin-Chip öffnet einen Monatskalender, dessen Felder die Tages-Auslastung tragen (Farbe + Zeichen + Tooltip, Legende darunter); gesperrt sind Tage vor der Anlieferung und Tage ohne Schicht. Die Zahlen kommen aus derselben Rechnung wie die Auslastungs-Kachel — kein zweiter Rechenweg, abgesichert per Selbsttest (Tagessummen = Fenstersumme). |
| Termin-Bausteine im Annahme-Picker repariert (OP-UX-4, Review-Nachzug F-1…F-5) | client/src/app/leitstand/baustein-picker.component.ts (Zeit-Entwurf · eigener Tastatur-Handler · fixed-Popup) · client/src/app/leitstand/annahme-overlay.component.ts (Abhol-Anker · Jetzt-Tick · Modal ohne transform) · client/e2e/annahme.spec.ts (3. Test) | PATCH: datetime-local übernahm bei jedem change (Eingabe brach ab), ↑/↓ verstellten die Liste statt des Datums, Abhol-Vorschläge lagen vor der Anlieferung, das Dropdown wurde vom Modal abgeschnitten (Ursache: transform-Zentrierung ⇒ Containing Block), und der Zeitbezug fror ein. Alle fünf behoben + E2E-Wächter. |
Abmelden repariert (415 am sign-out) (OP-AUTH-1) | client/src/app/services/anmeldung.service.ts (abmelden) · client/src/app/leitstand/shell.component.ts (Fehlermeldung am Knopf) | PATCH: POST /api/auth/sign-out ohne content-type liefert 415 (in Prod gemessen) — das Cookie blieb stehen, der Client lud trotzdem neu und der Nutzer war wieder drin. Jetzt JSON-Header + Body {}, Reload nur bei Erfolg, sonst sichtbare Meldung (Icon + Text, nicht nur Farbe). |
| Merge-Konflikte an den „jeder-PR-Dateien“ beseitigt (TKT-OP-PM-4) | scripts/stamp-version.mjs · server/src/app-version.ts · server/src/version.ts · .github/workflows/ci.yml · scripts/check-doc-consistency.sh · HANDOFF.md/README.md-Footer | kein Bump (Tooling): die zwei verbliebenen Konfliktherde nach OP-PM-2 sind weg. (1) Version gestempelt statt gepflegt: APP_VERSION wandert nach app-version.ts und wird beim Deploy aus höchstem Git-Tag v<semver> + PR-Label version:patch|minor|major gestempelt (ohne Label = kein Bump); die CI setzt danach den Tag (best-effort, contents: write nur dafür). Kein Feature-Branch schreibt die Version mehr. (2) Footer ohne Handpflege: kein „Letztes Update“-Datum/keine Version in HANDOFF/README — Datum = Git-Log, Version = Stempel; Doku-Gate §8 ist jetzt Rückfall-Wächter. Verifiziert: Stempel-Kette end-to-end, tsc + ng build + 12 E2E + alle Gates grün. Bedienung: PR-Label setzen, sonst nichts. |
| Aufräumen nach dem Verbindungsausfall (RISK-27/28, OP-AUTH-1) | shell.component.ts (Banner) · leitstand.service.ts · ws-token.ts/router.ts/leitstand.ts (Kommentare) · Risikoregister.md (RISK-27) · Access-WebSocket.md | PATCH (Label): falsche Ursachen (Cookie/veralteter Shell) aus Banner, Kommentaren und RISK-27 genommen — belegt ist das CPU-Limit (RISK-28); WS-Token bleibt als vorsorglicher Pfad. |
| Auslastung/Kalender ohne stornierte Aufträge (F2) (True North 1/3) | server/src/insights/insights.ts (schritteFuerAuslastung) · server/party/leitstand.ts (bestandsEingabe) · docs/betrieb/Tests.md (F1 Tabelle) | PATCH (Label): alle Aufträge außer abgebrochen zählen; fertiggestellt zählt weiter (Quality-Check bindet Zeit). |
| Auslastungs-Quote über heute + 14 Tage (Z1) (True North 1 / RISK-28) | server/src/insights/insights.ts (auslastungsFenster) · server/party/leitstand.ts (berechneAuslastungsQuote) · server/src/scheduler/schedule.ts (HORIZON_DAYS exportiert) | MINOR (Label): Kopfzeilen-Auslastung + Tages-Metrik zeigen jetzt die kommenden 14 Tage statt eines Lebensdurchschnitts; Rechenlast wächst nicht mehr mit der Historie. Nachtrag: Gantt-Ausfall-Bänder (ressourcenDTO, ganttAusfallFenster in ausfall.ts) auf die Gantt-Aufträge ± 7 Tage Puffer begrenzt. Last-Selbsttest test:last-altbestand (3 Jahre Altbestand, CI-Gate) sichert beides ab. |
| „Diagnose öffnen" in allen Fehler-Anzeigen (OP-AUTH-1 / OP-OBS-1) | client/src/app/leitstand/diagnose-link.component.ts + Einbindung in Shell (Offline-/Verbindungs-Banner, Abmelden), Anmeldung, Zugänge, Feedback | PATCH (Label): PO-Wunsch — jede Server-/Verbindungs-Fehleranzeige bietet /api/diagnose an. |
| CPU-Limit des Live-Servers behoben (RISK-28 / OP-OBS-1) | server/src/scheduler/time.ts (subtract linear) · server/src/scheduler/subtract-demo.ts (test:subtract) · server/party/leitstand.ts (broadcastState/onConnect/diagnose) | v0.169.5 (PATCH): Workers Logs zeigten „DO exceeded its CPU time limit" beim WS-Aufbau. Quadratischer subtract in der Auslastungs-Quote über die ganze Historie + bis zu 5 Stand-Aufbauten je Kaltstart. Jetzt linear (bit-identisch, 20 000 Zufallsfälle) und ein Aufbau je Verbindung. Nächster Schritt: nach Deploy /api/diagnose (historieTage, teilschritte) + Workers Logs prüfen. |
| Cloudflare Workers Logs eingeschaltet (F3) (OP-OBS-1 / RISK-25) | server/wrangler.toml ([observability]) | v0.169.4 (PATCH): Prod-DO antwortet nicht (liveVerbindung.ok:false nach 15 s); Abbrüche wie CPU-Limit/blockConcurrencyWhile-Timeout erreichen Grafana nie → Workers Logs als Zweitsicht (7 Tage). Nächster Schritt: Dashboard → Workers & Pages → taktano → Logs, Abbruchgrund ablesen, dann Fix (F4). Speicherort der Logs unbelegt (Compliance C-07). |
Verbindungs-Diagnose: Banner + /api/diagnose nennen die gemessene Ursache (E3) (OP-AUTH-1 / RISK-27) | server/src/auth/router.ts (messeLiveVerbindung, liveVerbindung) · server/party/leitstand.ts (diagnose()-RPC) · client/src/app/services/leitstand.service.ts (verbindungsDiagnose) · client/src/app/leitstand/shell.component.ts | v0.169.3 (PATCH): WS-Aufbau bricht in Prod nach 4 s ab (Browser-Konsole: closed before the connection is established), obwohl der Token kommt; lokal alles grün → Verdacht DO zu langsam. Statt weiter zu raten: /api/diagnose misst den DO (Dauer vs. 4-s-Limit, Größe, Verbindungen), das Banner zeigt die gemessene Ursache. Nächster Schritt: nach Deploy /api/diagnose eingeloggt öffnen, dann gezielt fixen. |
| iPhone-Login repariert: SW kaperte die Magic-Link-Bestätigungsseite (OP-AUTH-1 / OP-OFFLINE-1) | client/ngsw-config.json (navigationUrls +!/anmelden/bestaetigen) · server/src/auth/bestaetigung.ts (Abhängigkeit dokumentiert) | v0.169.2 (PATCH): Auf iPhone schlug die Anmeldung fehl, URL stand auf …/overview?token=<roh>&callbackURL=/ — der Token lag ununterlöst auf der SPA-Route. Ursache: der PWA-Service-Worker fing die Navigation zur server-gerenderten Zwischenseite /anmelden/bestaetigen ab und lieferte die gecachte SPA-Shell; die SPA kennt den Pfad nicht → Wildcard-Redirect auf /overview mit Query → Verify läuft nie. Fix: /anmelden/bestaetigen aus navigationUrls ausgeschlossen → SW lässt die Navigation zum Server durch. Serverseitig war alles korrekt (Live gegengeprüft). Verifiziert: JSON valid + server tsc. Deploy nötig. Sofort-Workaround bis der neue SW geladen ist: Magic-Link im privaten Tab öffnen / iOS-Website-Daten löschen. |
| „Neu laden"-Button gehärtet: auch Cache-Storage leeren (OP-OFFLINE-1 / RISK-27) | client/src/app/services/verbindung.service.ts (hartNeuLaden) | v0.169.1 (PATCH): Nach #822 blieb der WS-Banner bei einem Bediener trotzdem stehen — bewiesen per /api/ws-token (liefert eingeloggt gültigen Token → Server ok), also läuft im Browser noch der alte SW-gecachte Client. Der „↻ Neu laden"-Button meldete nur den SW ab, leerte aber die Cache-Storage nicht (ngsw legt die Shell dort ab) → Reload bediente teils weiter den alten Shell. Fix: hartNeuLaden() löscht jetzt zusätzlich alle caches → ein Klick startet verlässlich frisch. Automatik-Pfad (activateUpdate) unverändert. Greift für den Bediener erst ab dem ersten neuen Bundle (bis dahin: Doppel-Reload/„Clear site data"/Inkognito). Verifiziert: client tsc grün. Deploy nötig. |
| Docs-Deploy repariert (Docusaurus-Broken-Links) (OP-DOCS-9) | docs/architektur/Fahrzeug-3D.md · docs/architektur/Fahrzeug-Modelle-V1b.md · docs/konventionen/IDs.md · CHANGELOG.md | kein Bump (nur Doku/CI): Der docs-deploy-Workflow brach bei jedem main-Push (Docusaurus found broken links!, onBrokenLinks: 'throw') → docs.taktano.com veraltete. Ursache: 4 Doku-Links auf Repo-Dateien außerhalb der Site (scripts/·ops/·client/src/) als relative Pfade. Fix: auf GitHub-URLs umgestellt (Konvention wie Offene-Punkte.md/gen-ops). Verifiziert: docs-site lokal gebaut → [SUCCESS], keine Broken-Links mehr. Deploy: automatisch beim nächsten main-Push. |
| Live-Daten-Selbstheilung (veralteter PWA-Shell) + Login-Seite im Marken-Design (OP-OFFLINE-1 / OP-AUTH-1 / RISK-27) | client/src/app/services/verbindung.service.ts (selbstheileVeralteteShell) · client/src/app/leitstand/shell.component.ts (effect + Banner-Text) · server/src/auth/bestaetigung.ts (Marken-Design) | v0.169.0 (MINOR): Der rote „Keine Verbindung"-Banner blieb trotz deployter #818/#820-Fixes — Ursache: PWA-Service-Worker liefert nach Deploy den alten, gecachten Client (ohne ?wsauth= → Gate 401't). Fix: bei gescheiterter Verbindung + Netz prüft die App einmal pro Sitzung proaktiv auf eine neue Version und lädt sie automatisch (checkForUpdate→activateUpdate; sessionStorage-Guard gegen Schleifen) → Tablet heilt sich nach Deploy selbst. Banner-Text korrigiert (kein „Access" mehr — Taktano hat eigene Anmeldung). Login-Bestätigungsseite jetzt im Taktano-Design (Wortmarke, Rot-Primär, ⚠-markierter Ungültig-Hinweis). Verifiziert: client+server tsc + test:auth + No-Hex grün. Deploy nötig. |
Landing-Page unter taktano.com/www.taktano.com (OP-VERTRIEB) | server/src/landing.ts (neu) · server/party/leitstand.ts (Host-Weiche ganz oben im fetch) · server/wrangler.toml (2 neue custom_domain-Routen) · server/src/auth/auth-demo.ts (Selbsttest) | v0.168.0 (MINOR): Die Wurzeldomain war leer — jetzt eine einfache, server-gerenderte Landing-Page (kein Client-Bundle): Wortmarke „Taktano." (Marken-Rot), Tagline, die drei True-North-Fragen als Nutzenversprechen, Buttons „Zur App →" (app.taktano.com) + „Dokumentation" (docs.taktano.com). Host-Weiche istLandingHost ganz oben im DO-fetch (nur taktano.com/www., case-insensitiv) → app. bleibt die App. GET/HEAD, cache-control: public, max-age=300, noindex-frei (soll indexiert werden). Verifiziert: tsc+test:auth (Landing-Host-Weiche). Deploy nötig. |
Magic-Link: Bestätigungs-Zwischenseite (Scanner-Schutz, INVALID_TOKEN behoben) (OP-AUTH-1) | server/src/auth/bestaetigung.ts (neu) · server/src/auth/auth.ts (sendMagicLink → zuBestaetigungsUrl) · server/party/leitstand.ts (GET /anmelden/bestaetigen) | v0.167.1 (PATCH): Der per Mail zugestellte Magic-Link warf INVALID_TOKEN — E-Mail-Scanner (Safe Links) rufen Links vorab auf und verbrauchen den Einmal-Token (Beleg: Sitzung entstand, während Nutzer den Fehler sah). Fix: Mail verlinkt eine Zwischenseite, die den Token nicht verbraucht; der Verify läuft erst per JS-Klick (Scanner führen kein JS aus). Server-gerendert, öffentlich, noindex. Verifiziert: tsc+test:auth. Deploy nötig. SPF gesetzt (cf-bounce, mit DKIM/DMARC) → schnellere Zustellung. |
| WebSocket-Auth cookie-unabhängig (Query-Token-Handshake) (OP-AUTH-1) | server/src/auth/ws-token.ts (neu) · server/src/auth/router.ts (GET /api/ws-token) · server/party/leitstand.ts (Gate akzeptiert ?wsauth=) · client/src/app/services/leitstand.service.ts (holeWsToken + async query) | v0.167.0 (MINOR): Login+Mail liefen, aber der WS verband nicht — /api/diagnose sieht die Sitzung, der WS//parties/* bekommt 401; der Set-Cookie ist korrekt (__Secure-…; Secure; SameSite=Lax), der Browser schickt das Cookie am WS-Upgrade aber nicht mit (Privacy-Extensions/Kiosk). Fix: Client holt über den cookie-tragenden /api/ws-token einen kurzlebigen signierten Token (HMAC/AUTH_SECRET, TTL 120 s) und hängt ihn als ?wsauth= an die WS-URL (bei jedem Reconnect frisch); das Gate akzeptiert ihn gleichwertig zum Cookie → cookie-unabhängiger Handshake, keine Rechteausweitung. Verifiziert: tsc+test:auth(Round-Trip)+client-tsc. Deploy nötig. |
| Betriebs-Diagnose: Mail-Ergebnis + WS-Gate-Grund ohne Grafana (OP-AUTH-1 / OP-OBS-1) | server/src/auth/router.ts (GET /api/diagnose + cookieNamenAus) · server/party/leitstand.ts (Gate-Grund) · server/src/auth/auth-demo.ts | v0.166.1 (PATCH, rein additiv): Nach der #806-Anmeldung waren zwei Prod-Rätsel opak (Signal nur im OTLP-Log). Jetzt sichtbar ohne Grafana: GET /api/diagnose (vor dem Gate erreichbar) zeigt als Browser-JSON, ob die Anfrage ein Sitzungs-Cookie trägt (nur Namen, nie Werte), die eigene Sitzung, die Versand-Konfig — und für Verwaltung/chef einen Live-Mailtest an die eigene Adresse mit dem rohen env.EMAIL.send()-Ergebnis (messageId oder Cloudflare-Fehler). Das Gate legt bei jeder Ablehnung den Grund offen: OTel-auth.gate.abgelehnt + Header X-Taktano-Auth-Grund → ein WS-Upgrade-401 ist nicht mehr blind. Bisektiert Mail-Ausfall und WS-401. Keine PII/Token-Werte (OP-LOG-1). Verifiziert: tsc+test:auth+--strict. Deploy nötig, dann /api/diagnose im eingeloggten Browser öffnen. |
| Annahme-Overlay: Bausteine per Dropdown mit Suche (OP-UX-4) | client/src/app/leitstand/baustein-picker.component.ts · client/src/app/leitstand/annahme-overlay.component.ts · client/e2e/annahme.spec.ts · design/WORKSPACES.md · server/src/version.ts | v0.166.0 (MINOR): die Chips im Annahme-Overlay sind nicht mehr nur Anzeige — jeder öffnet ein Dropdown mit Suche (app-baustein-picker): Kunde (bekannte Kunden + freier Name) · Leistung (echter Katalog mit Kategorie/Standzeit/Preis) · Anlieferung (neuer Chip, Default „jetzt“) · Abholung (14-Tage-Vorschläge + exaktes datetime-local). Tastatur ↑/↓/Enter, Esc schließt nur das Dropdown. Entscheidung: Auswahl = overrides über dem Geparsten, Weitertippen setzt zurück — der Satz bleibt die eine Quelle. Mit-Fix (Parsing): der Wochentag der Abholung wird jetzt ab der Anlieferung gezählt — „kommt Montag, bis Freitag“ ergab an einem Dienstag eine Abholung vor der Anlieferung (Server lehnte ab; der bestehende Annahme-E2E fiel dadurch an 5 von 7 Wochentagen). Rein Client, kein DTO/Server. Verifiziert: tsc + ng build + No-Hex + No-Console + --strict + alle 12 E2E grün. Deploy für die UI nötig (Client). |
DO-onStart fail-soft — Prod-Totalausfall (1101) behoben (RISK-25 / OP-DATA-1 / OP-OBS-1) | server/party/leitstand.ts · docs/betrieb/Risikoregister.md · server/src/version.ts | v0.165.1 (PATCH): Nach dem Weg-1-Revert zeigte die App weiter „keine Verbindung". Ursache live diagnostiziert: die leitstand-DO liefert auf jeder Route (WS und HTTP /audit/liste) Cloudflare-1101 → onStart crasht auf dem realen Prod-State (Fresh-Seed-E2E übt ihn nie → CI grün). Weg-1-Gate hatte den 1101 maskiert. Fix: onStart fail-soft — Saved-State-Load hart, Nachverarbeitung in try/catch (mit structuredClone-Snapshot + Rollback bei Fehler, damit kein Teil-Stand persistiert wird); scheitert sie, bootet die DO trotzdem + loggt die exakte Ausnahme (Message+Stack) in den OTel-Sink. Deploy nötig. Verifiziert: tsc+test:do-migrations+operativ+--strict. Auf #806 (0.165.0) rebased → Risiko RISK-22→RISK-25 umnummeriert (Kollision mit #806). Offen (RISK-25): Wurzel aus dem Log gezielt fixen + Selbsttest mit realistischem Alt-State. |
| Konflikt-Liste: eine Ursache = ein Eintrag; kein technischer Key mehr in der UI (K-1/K-2, OP-R3-1 / OP-DATA-1) | server/src/operativ/konflikte.ts · server/party/leitstand.ts · server/src/persistence/do-state-migrations.ts (v25) | PATCH. K-1: Eine Krankmeldung erzeugte je betroffenem Schritt eine eigene Zeile — sieben „Konflikte" für drei Probleme mit einer Ursache. Jetzt ein Eintrag je Auftrag, Mitarbeiter und Ausfall-Art (die Art bleibt im Schlüssel: krank und Urlaub sind zwei Aussagen), der die betroffenen Schritte deutsch aufzählt. K-2: „skill-klaerung" in der UI war kein Anzeigefehler, sondern ein Datenfehler — DO-Migration v19 zog den Schritt ts-klaerung nach, aber nicht seinen Skill in den Katalog (v20 macht es für skill-umparken richtig). v25 holt das nach; zusätzlich ist der Id-Fallback an allen vier Fundstellen durch einen sprechenden Platzhalter ersetzt. Neue Gegenprobe im Migrations-Test: kein Teilschritt darf auf einen Skill außerhalb des Katalogs zeigen. Review-Nachzug (CodeRabbit, 3 Funde): das break in der Crew-Schleife ließ ab dem zweiten fehlenden Crew-Mitglied eines Schritts den Konflikt lautlos verschwinden, und bands[0] warf weitere harte Ausfall-Arten desselben Schritts weg — jetzt zählt jedes Crew-Mitglied und jede Art; gruppiert werden Schritte, nie Menschen. Dazu die benannte Testlücke geschlossen (v25 auf einem Blob mit Skill-Katalog, zweimal migriert). Offen: die Überschrift „7 weitere Konflikte" (Reiter zählt 7, Box zeigt 7) — separat zu klären. |
| Konflikt-Liste nennt den Lösungsweg — und die Überschrift stimmt (K-3b, OP-R8-1) | client/src/app/leitstand/pages/conflicts.component.ts | PATCH. Die Box hieß „N weitere Konflikte“ — relativ zur Termin-Liste darunter und damit unwahr, sobald diese leer ist (Reiter 7 = 0 Termin + 7 weitere). Jetzt „N Konflikte außerhalb der Termin-Achse“: ohne Bedingung immer wahr. Neu je Eintrag eine Zeile „→ wie lösen · Ort“ mit Link auf den Editor, der das Feld wirklich ändert (Belegung · Team & Skills · Leistungen & Abläufe · Takt · Planung · Buchten & Hof) — alle acht Ziele im Code gegengeprüft. Kein fehlender Block, keine falsche Zahl — der Befund war reines Wording. |
| Server-Abhängigkeiten aufgefrischt — #424 aufgelöst, vier High-Befunde weg (RISK-4 / OP-SEC-1) | server/package.json · server/package-lock.json | PATCH. #424 hing an einer Kette: wrangler verlangt @cloudflare/workers-types@^5, das kollidierte mit dem harten Peer von partyserver@0.0.66; erst partyserver 0.5.9 erlaubt beide. Kette aufgelöst: partyserver 0.0.66 → 0.5.10, workers-types ^4 → ^5, wrangler 4.107 → 4.137, dazu partysocket/tsx/drizzle. npm audit 8 → 4 — alle vier High weg (undici, sharp, miniflare, wrangler); CI sah sie nicht, weil der Audit-Job --omit=dev high+ prüft und wrangler devDependency ist. Verifiziert: tsc · 48 Server-Selbsttests · Persistenz · No-Console · 14/14 E2E inkl. WS-Upgrade · wrangler deploy --dry-run. Offen im Blick zu behalten: partyserver 0.5.x ändert WS-Close-Verhalten; miniflare kommt als 5.x-alpha (nur lokale Laufzeit). |
| Client-Abhängigkeiten aufgefrischt — neun Dependabot-PRs in einem (RISK-4 / OP-SEC-1) | client/package-lock.json | PATCH. npm update in client/, package.json unverändert (alle Versionen innerhalb der deklarierten Ranges). Deckt alle neun offenen Dependabot-PRs ab: Angular → 22.2.0, fast-uri/browserslist/baseline-browser-mapping auf Zielversion, hono/brace-expansion/ip-address fallen aus dem Baum. Umfang: 315 geändert · 185 entfernt · 78 neu, inkl. Toolchain-Wechsel (rolldown/oxc, sass-embedded) und transitiver Majors (express 5, vite 8, webpack-dev-server 6, @babel 8). Verifiziert: Build + 3 Client-Tests + 14/14 E2E + npm audit 0. |
Mail-Deckel je Konto: /api/anmelden kann nicht mehr beliebig Mails auslösen (RL-2, OP-AUTH-1 / RISK-23) | server/src/auth/deckel.ts (neu) · server/src/db/schema.ts · server/migrations/0003_anmelde_deckel.sql · server/src/auth/router.ts · docs/architektur/Anmeldung.md §6a | PATCH (Label version:patch — seit TKT-OP-PM-4 stempelt die CI die Version): höchstens 3 Magic-Link-Mails je Konto und Stunde, Prüfen und Zählen in einer D1-Anweisung (gleichzeitige Anfragen kämen sonst beide durch). Schlüssel ist die Konto-Id, nicht die Adresse → kein zweiter PII-Ort, ON DELETE CASCADE räumt mit ab. Still: gedeckelt sieht von außen aus wie gesendet — sonst wäre der Deckel selbst die Auskunft, dass das Konto existiert. Verworfen nach Prüfung im Paket: die verification-Tabelle mitzuzählen geht nicht, Better Auth speichert dort den Token als identifier, nicht die Adresse. Warum nicht die Cloudflare-Regel allein: die zählt je IP und sieht die Adresse gar nicht (Body-Felder erst ab Enterprise); die Zone läuft auf Free (1 Regel, 10-s-Fenster/-Sperre, nur Pfad im Ausdruck). Rest-Risiko benannt: 3 Mails je Konto und Zählfenster, an der Fixed-Window-Grenze kurzzeitig bis zu 6. Review-Nachzug (3 valide): der Deckel stand zuerst vor der Antwort und hätte über die Schreib-Laufzeit ein aktives Konto verraten — jetzt läuft alles Adressabhängige in ctx.waitUntil, was auch den Stand vor diesem PR verbessert; dazu zwei Doku-Korrekturen (§8 widersprach §6a; Worst-Case-Zahl galt nicht für gleitende Intervalle). Offen beim Betreiber: RL-1 im Dashboard anlegen, Werte in Anmeldung.md §6a. |
workflow_dispatch: Deploy ohne Code-Änderung (OP-CI-1 / OP-AUTH-1 / RISK-26) | .github/workflows/ci.yml · docs/architektur/Anmeldung.md §6 · docs/betrieb/Risikoregister.md | kein Bump (nur CI). Ein GitHub-Secret wirkt erst, wenn ein Lauf es nach Cloudflare spiegelt — für die Secret-Aktivierung und jede spätere AUTH_SECRET-Rotation fehlte der Auslöser. Jetzt Actions → CI → Run workflow auf main; der manuelle Lauf zählt überall wie ein main-Push, überspringt also keine Gates (einzige Ausnahme: die Bereichs-Erkennung wird übersprungen statt geraten — beim Dispatch gibt es keinen Vergleichsstand). Anlass war ein eingetretener Vorfall (RISK-26): der Re-Run eines älteren Laufs deployte am 09-23 den alten Commit und nahm den Prod-1101-Fix aus #807 für 3½ Minuten wieder aus der Produktion (07:24:38–07:28:12). Re-Run = Commit, Dispatch = Ref. |
| Anmeldung per E-Mail-Magic-Link: eigenes Login je Mitarbeiter + verifizierte Rollen (OP-AUTH-1 A-2…A-5) | server/src/auth/* (neu) · server/src/db/schema.ts · server/migrations/0002_auth.sql · server/party/leitstand.ts · client/src/app/services/anmeldung.service.ts · client/src/app/leitstand/pages/anmeldung.component.ts · client/src/app/leitstand/pages/konten.component.ts · docs/architektur/Anmeldung.md (neu) | v0.165.0 (MINOR): Jeder Mitarbeiter meldet sich mit seiner E-Mail per Magic Link an (kein Passwort); Konten und Rollen entstehen unter Verwaltung → Zugänge. Unterbau Better Auth self-host, Identität in der EU-D1, Versand über Cloudflare Email Sending. PO-Entscheidungen: AU-2 (Taktano-Sitzung ist das Gate, Access weicht — begründete Golden-Rule-Ausnahme) · MV-CF · UB-2 (Spike vorab: Bundle 255→637 KiB gzip) · AC-1. Schließt RISK-12 (Rolle verifiziert statt selbst-deklariert) und den A-1-Gap (13 Stammdaten-Handler gegatet; setVerfuegbarkeit bewusst offen). Produktiv dormant ohne AUTH_SECRET/DB — vier Operator-Schritte + Rollback: docs/architektur/Anmeldung.md §6. Neu: RISK-22/23/24, C-20/C-21. Scharfschaltung (PO 09-22): Mail-Binding + MAIL_ABSENDER aktiv; AUTH_SECRET/BOOTSTRAP_EMAIL werden aus GitHub-Secrets gespiegelt; D1-Migrationen laufen jetzt im Deploy (fehlten komplett — 0001 war handangewandt). Offen beim Betreiber: die zwei GitHub-Secrets setzen, dann Rate-Limiting (RISK-23), dann Access lösen. Review-Nachzug (CodeRabbit, 7/7 behoben): Rollen-Eskalation geschlossen (chef vergeben/antasten verlangt selbst chef — sonst hätte sich die Werkstattleitung befördern können), 2 weitere Stammdaten-Handler gegatet (15 statt 13), Worker-Secret wird beim Entfernen des GitHub-Secrets gelöscht (Widerruf wirkt), UNIQUE-Race + verschluckte Fehlermeldung + Rollen-<select> gefixt, ungenutzte jwks-Tabelle entfernt (Doku behauptete ein nie registriertes jwt-Plugin). 8. Finding (selbst gefunden, Thread war fälschlich als erledigt markiert): /api/anmelden prüfte aktiv nicht — ein gesperrtes Konto hätte weiter Anmelde-Mails bekommen; jetzt Prüfung vor dem Versand. Review-Runde 2 (13 Findings): Enumeration über Status und Laufzeit geschlossen (Konfigurations-503 adressunabhängig und zuerst, Versand über ctx.waitUntil neben der Antwort, eine identische 200 für alle) · TOCTOU im Aussperr-Schutz geschlossen (die Prüfung, ob noch ein anderer aktiver Chef da ist, steckt jetzt als EXISTS im WHERE derselben Schreib-Anweisung) · Eskalations-Riegel an das Schreiben gebunden (die Bedingung, dass das Ziel kein Chef ist, steckt in derselben Anweisung — vorher hätte eine Beförderung dazwischen die Autorisierung entwertet) · offener WebSocket verliert seine Rechte jetzt sofort (entzieheZugang per DO-RPC bei Sperren/Degradieren/Löschen — vorher behielt der Socket seine beim Verbinden eingefrorenen Fähigkeiten bis zum Reload) · Doku auf gebaut ≠ scharf korrigiert + /api/auth/magic-link/verify als öffentlicher Pfad dokumentiert · KontenService statt fetch in der Komponente (Service-Grenze aus client/CLAUDE.md). Damit wirkt Sperren an drei Enden: kein neuer Link · Sitzung endet beim nächsten Request · offene Verbindung wird geschlossen. |
| „Weg 1" (#799) zurückgezogen — Worker-JWT-Gate deaktiviert (Prod-WS-Regression) (OP-AUTH-1 / RISK-21) | server/wrangler.toml · docs/architektur/Access-WebSocket.md · ops/OP-AUTH-1.md · docs/betrieb/Risikoregister.md · server/src/version.ts | v0.164.1 (PATCH): Der WS lief monatelang hinter der Allow-Access-App; „Weg 1" war eine Fehldiagnose (die 302 kam nur von unauth Edge-Probes). Der Weg-1-Worker-Gate auf /parties/* lehnte den authentifizierten WS mit 401 ab → nach dem 13.09.-Deploy keine Live-Daten mehr. Fix: ACCESS_TEAM_DOMAIN/ACCESS_AUD geleert → Gate aus; Access bleibt an (Allow = Netz-Gate, Golden Rule); kein Bypass, kein Gate. Deploy nötig. Lehre → RISK-21 (am authentifizierten Pfad verifizieren, nie an unauth-Probes; Gate darf WS-Upgrades nie ablehnen). |
| CodeRabbit-Nachzug #800: Doku-Konsistenz E2E Stufe 2 (OP-E2E-1 / OP-A11Y-1 / OP-DOCS-9) | ops/OP-E2E-1.md · docs/betrieb/Tests.md · ops/OP-A11Y-1.md | kein Bump (nur Doku): 3 valide Minor-Findings. (1, Doku↔Code) OP-E2E-1 behauptete den Launcher-FAB-Fix (--tk-brand-deep) als erledigt — er wurde verworfen (Code = var(--tk-brand)/text-tk-bg); korrigiert → zurückgestellter OP-A11Y-1-Befund, Gate-Beschreibung nennt das DEFERRED-Set. (2) Tests.md Annahme-Abdeckung von „im Worker/DO angelegt" auf „Server bestätigt die Anlage (kein Reload/Persistenz-Check)" eingegrenzt. (3, Governance) OP-A11Y-1 True-North-Verknüpfung ergänzt. Verifiziert: --strict grün. |
| E2E-Tests Stufe 2: Annahme-Kern-Fluss + a11y-Gate (axe) (OP-E2E-1 / OP-A11Y-1) | client/e2e/annahme.spec.ts · client/e2e/a11y.spec.ts · client/package.json · ops/OP-A11Y-1.md · docs/betrieb/Tests.md · docs/betrieb/Risikoregister.md · server/src/version.ts | v0.164.0 (MINOR): (1) Annahme „Auftrag in einem Satz" end-to-end — Overlay → Beispiel → Server-Dry-Run → Annehmen → „…ist im Takt." (robust: regulärer oder Klärfall-Weg). (2) a11y-Gate axe/WCAG A+AA über die 4 Workspaces (Dev-Dep @axe-core/playwright, kein Prod-Impact). Erst-Lauf fand systemischen Alt-Bestand (kein critical; ~130 color-contrast + nested-interactive/no-focusable-content) → als OP-A11Y-1 (neu) erfasst und im Gate transparent zurückgestellt (DEFERRED, protokolliert); jede andere/neue serious/critical-Regel blockt. BFSG/EN 301 549 geflaggt (RISK-20). Klärfall/QS-Flüsse bewusst als Folge-Slice (Seed = 0 aktive Aufträge). Verifiziert: 11 E2E grün (CI-Modus) + No-Hex + --strict. Kein Deploy nötig (Test-Infra CI-seitig; nur Version). |
| WebSocket hinter Cloudflare Access: Worker-JWT statt Login-302 („Weg 1") (OP-AUTH-1) | server/party/leitstand.ts · server/wrangler.toml · docs/architektur/Access-WebSocket.md · ops/OP-AUTH-1.md · server/src/version.ts | v0.163.0 (MINOR): Der WS unter /parties/* stirbt hinter der interaktiven Access-App am 302→Login (WS folgt keinem Redirect → „closed before established" → leere App; per Edge-Probe bestätigt). Weg 1: /parties/* am Edge per Bypass freigeben + Access-JWT im Worker prüfen (verifyAccessJwt RS256 gegen Team-JWKS, exp/aud/iss; nur produktiv, erkannt am cf-ray-Header — lokal/E2E übersprungen; ohne gültiges JWT → 401). Pfad-begrenzt (kleiner Blast-Radius); Golden Rule gewahrt. Code ist No-Op bis Operator (zwingende Reihenfolge) erst npm run deploy, dann Edge-Bypass im CF-Dashboard setzt (Runbook Access-WebSocket.md §3). Verifiziert: 6 E2E (WS 101 lokal) + tsc + No-Console + spike/operativ + --strict grün. Deploy + Edge-Bypass nötig. Naht für A-3 (verifizierte statt selbst-deklarierte Rolle). |
| CodeRabbit-Nachzug #794: E2E-Härtung (Chromium-Pfad + e2e:headed) (OP-E2E-1) | client/playwright.config.ts · .github/workflows/ci.yml · client/package.json · server/src/version.ts | v0.162.1 (PATCH): 2 valide Findings. (1, Major) Chromium-Pfad-Prüfung fordert jetzt ausführbare Datei statt „existiert" (isFile+X_OK / -f+-x) — ein Verzeichnis hätte alle E2E beim Browser-Start gebrochen. (2) e2e:headed baut jetzt den Client (ng build &&). Übersprungen (Major): „unabhängige QS-Freigabe" — G-4 ist die Fahrzeug-QS-Regel, nicht der Dev-Prozess; unabhängige Verifikation = CI-Lauf + PO-Merge. Verifiziert: Smoke grün mit gehärteter Config + --strict grün. |
| Automatische E2E-/UI-Tests (Playwright, echter Full-Stack) (OP-E2E-1) | client/playwright.config.ts · client/e2e/{smoke,navigation,rolle}.spec.ts · client/package.json · .github/workflows/ci.yml · ops/OP-E2E-1.md · docs/betrieb/Tests.md · server/src/version.ts | v0.162.0 (MINOR): Bis dato keine UI/E2E-Tests (nur kopflose Domänen-Selbsttests). Neu: Playwright fährt Chromium gegen den echten lokalen Full-Stack (wrangler dev = Client+Worker+DO+WS+Seed, lokal ohne Access → WS 101). 3 Specs: Smoke (WS-live + Seed + kein „Nicht verbunden"-Banner) · Navigation (4 Workspaces) · Rollen-Gate (werker gesperrt→chef frei). CI-Job e2e am ci-gate (blockt Merge, bei Client-/Server-Änderung); lokal npm run e2e. Alle 6 grün (lokal + CI-Modus). Deploy nötig (nur Version; Test-Infra ist CI-seitig). Offen: Ausbau (Annahme/Klärfall/QS-Flüsse · visuelle Regression · a11y). |
| CodeRabbit-Nachzug #775: Banner-a11y + Cache-Race (OP-OFFLINE-1) | client/src/app/leitstand/shell.component.ts · client/src/app/services/leitstand.service.ts · server/src/version.ts | v0.161.5 (PATCH): 2 valide Findings behoben. (1) „Nicht verbunden"-Banner role="alert" (Screenreader). (2) State-Race: WS-Fehler setzt verbindungGescheitert vor dem async hydrateFromCache() → Cache-Hydrierung setzt es jetzt zurück (mit Alt-Stand greift offlineStale). Übersprungen: Zeilen-Kürzung der Logs (bewusst 1 Zeile/Eintrag). Verifiziert: ng build + No-Hex + --strict grün. Deploy nötig. |
| „Nicht verbunden"-Banner (gescheiterter WebSocket sichtbar) (OP-OFFLINE-1 / Access) | client/src/app/services/leitstand.service.ts · client/src/app/leitstand/shell.component.ts · server/src/version.ts | v0.161.4 (PATCH): PO-Support — App zeigte „0 Fahrzeuge" + gesperrte Admin bei still scheiterndem WS (Access-Login-302 auf den WS-Handshake, dem ein WS nicht folgen kann; per Edge-Probe bestätigt). Lücke: offlineStale-Banner nur bei vorhandenem Stand. Fix: neues Signal verbindungGescheitert + deutliches rotes Banner „Keine Verbindung — bei Cloudflare Access neu anmelden" mit „Neu anmelden" (SW-umgehender Neustart). Verifiziert: ng build + No-Hex + --strict grün. Deploy nötig. Offen (Infra, separat): WS hinter Access via Service-Token/Worker-JWT absichern statt interaktivem Login-302. |
| CodeRabbit-Nachzug #773: Rollenwechsel bei Persistenz-Fehler nicht neu laden (OP-AUTH-1) | client/src/app/services/rolle.service.ts · server/src/version.ts | v0.161.3 (PATCH): 1 valides Major-Finding. Bug: setzeRolle setzte das Signal vor localStorage.setItem, der catch stoppte den Reload nicht → bei setItem-Wurf (Privat-Modus/Storage voll) Reload trotzdem → aktuelleRolle()→werker, gewählte Rolle verloren + weniger Rechte. Fix: Persistenz zuerst; bei Fehler Signal auf VERBUNDENE_ROLLE zurücksetzen + ohne Reload return. Verifiziert: ng build + No-Hex + --strict grün. Deploy nötig (npm run deploy). |
| Rollenwechsel härten: Reconnect an real verbundener Rolle + Validierung (OP-AUTH-1) | client/src/app/services/rolle.service.ts · server/src/version.ts | v0.161.2 (PATCH): PO-Bug — „Inhaber/Chef" gewählt, Administration blieb gesperrt. Ursache: setzeRolle stieg mit if (r === this.rolle()) return vor dem Reload aus → bei stale Socket (Menü „Chef", Verbindung „Werker" nach Access-Reconnect) ein No-op, kein frischer ?rolle=-Connect. Fix: Reload an der tatsächlich verbundenen Rolle (VERBUNDENE_ROLLE, beim Laden fixiert) statt am UI-Signal + Härtung gegen unbekannte Rolle (IST_ROLLE-Validierung → Fallback werker; der <select> reicht $any(...).value roh durch). Verifiziert: ng build + No-Hex + --strict grün. Deploy nötig (npm run deploy); Sofort-Workaround: harter Reload als „Chef". |
| CodeRabbit-Nachzug #769: Doku-Konsistenz-Restfixes (OP-R6-2 / OP-DOCS-9) | HANDOFF.md · docs/architektur/Fahrzeug-3D.md · ops/OP-R6-2.md | kein Bump (nur Doku): 6 #769-Findings — 4 valide behoben, 1 mitgezogen, 1 begründet übersprungen. Selbstwidersprüche in den mit #769 angefassten Docs: HANDOFF-„0 vulns"→0 High findings (Major), Fahrzeug-3D.md stale „loadComponent-Route/Lazy-Route"→Lazy-Chunk + V-1b-Route GET /models/*→Allowlist (karosserie/·mediapipe/·nsfwjs/→404), „dormant/blockiert"→historisch (HANDOFF+ops). Übersprungen: Timesheet-append-only-Revert des #767-Eintrags (der korrigierte Stand ist richtig; Revert bringt keinen Nutzen, union-Merge-Konflikt nach Merge gegenstandslos). Verifiziert: doc-consistency --strict grün. |
| OP-R6-2 V-2: sichtbarer Fahrzeug-3D-Viewer (drehbar) + Binding aktiv (OP-R6-2) | client/src/app/leitstand/fahrzeug-viewer.component.ts · client/src/app/leitstand/auftrag-detail-panel.component.ts · client/package.json · server/wrangler.toml · server/src/version.ts · docs/architektur/Fahrzeug-3D.md · ops/OP-R6-2.md | v0.161.0 (MINOR): Nach V-1b-Deploy (Bucket + 7 GLBs bereitgestellt) das Fahrzeug sichtbar & drehbar. Neue Standalone-Komponente fahrzeug-viewer (<model-viewer>, CUSTOM_ELEMENTS_SCHEMA) lädt /models/karosserie/<typ>.glb, drehen/zoomen; @google/model-viewer lazy per dynamic import() (eigener Chunk, nicht im Initial-Bundle); im Auftrag-Detail per Toggle; Fallback bei fehlendem Typ/404. MODELLE_BUCKET-Binding in wrangler.toml aktiviert. Verifiziert: ng build (Lazy-Chunk) + No-Hex + Client-Prod-Audit: 0 High findings (npm audit --omit=dev --audit-level=high) + tsc + --strict grün. Deploy nötig (npm run deploy). Offen: V-3 (Markieren-per-Klick, Datenmodell steht). |
| CodeRabbit-Nachzug #758: Datums-Validierung + Runbook-Korrektheit (OP-R6-2) | scripts/build-fahrzeug-modelle.mjs · docs/architektur/Fahrzeug-Modelle-V1b.md | kein Bump (Tooling+Doku): 5 Findings, alle behoben. Skript: --retrieved kalender-validiert (isCalendarDate(), weist fehlend/2026-02-31 ab — kein falsches Provenienz-Datum). Runbook: Verifikation Access-authentifiziert (Service-Token, curl -I allein trifft nur den Login-Redirect) · Bucket verifizieren (bucket list + check-r2-private.mjs) statt blind create · MODELLE_BASIS_URL für Fahrzeug-only nicht setzen (aktiviert sonst ML-Adapter) · Vier-Augen (G-4) hart statt „idealerweise". Verifiziert: node --check + Datums-Tests + doc-consistency --strict grün. Erledigt (2026-08-08): V-1b-Deploy + V-2 — s. oberste OP-R6-2-V-2-Zeile. |
| CodeRabbit-Nachzug #757: Modelle-Skript + Runbook gehärtet (OP-R6-2) | scripts/build-fahrzeug-modelle.mjs · docs/architektur/Fahrzeug-Modelle-V1b.md | kein Bump (Tooling+Doku): 6 Findings, 5 behoben + 1 leicht. Skript: @gltf-transform/cli exakt gepinnt (@4.4.2) · geladen=Abrufdatum (--retrieved, sonst Platzhalter) · Dry-Run ohne npx (lazy CLI-Check) · --file-Pfade shell-gequotet · JSDoc. Runbook: Bucket-existiert-Formulierung korrigiert (Bucket muss ggf. erst angelegt/verifiziert werden, nur Route/Gate/Binding-Konfig existieren) + Vier-Augen-Note (G-4) + MD-Tidy. Verifiziert: node --check + Funktionstest (7/7, Leerzeichen-Pfad, Dry-Run npx-frei) + doc-consistency --strict grün. Erledigt (2026-08-08): V-1b-Deploy + V-2 — s. oberste OP-R6-2-V-2-Zeile. |
| OP-R6-2 V-1b-Tooling: Fahrzeug-Modelle-Aufbereitung + Runbook (OP-R6-2) | scripts/build-fahrzeug-modelle.mjs · docs/architektur/Fahrzeug-Modelle-V1b.md · docs/architektur/Fahrzeug-3D.md · docs/README.md · .gitignore | kein Bump (Tooling+Doku): Skript bereitet die 7 CC0-Karosserie-GLBs auf (glTF→.glb, karosserie/<key>.glb, LICENSE.md, Upload-Befehle; Ausgabe gitignored) + Runbook (Beschaffen→Aufbereiten→privat hochladen→verifizieren). Bucket/Binding MODELLE_BUCKET, /models/*-Route, Privat-Gate existieren bereits (aktiv seit dem PO-Deploy 2026-08-08 — Stand dieser Tooling-PR war die Binding noch dormant; geteilt mit Bildbewertung §7b) → Runbook verweist dorthin, kein Duplikat. Verifiziert: node --check + --help + --dry-run + Funktionstest (7/7) grün. Erledigt (2026-08-08): V-1b-Deploy + V-2 — s. oberste OP-R6-2-V-2-Zeile. |
| CodeRabbit-Nachzug #755: Broadcast-Allow-List + Scrub-Härtung (OP-R6-2) | server/party/leitstand.ts · server/src/persistence/do-state-migrations.ts · server/src/persistence/do-migrations-demo.ts · server/src/version.ts | v0.160.3 (PATCH): 3 von 4 #755-Findings behoben, 1 übersprungen. (1, Major/Security): DTO reichte das rohe Markierungs-Objekt durch → Typ-Entfernung ≠ Runtime-Entfernung → Allow-List-Projektion an der Broadcast-Boundary (nur erlaubte Felder), migrations-unabhängig. (2, Minor): v24-Scrub via hasOwnProperty+delete (auch erstelltVon: null weg). (3, Minor): Idempotenz-Selbsttest gehärtet (null-Marker + Doppel-Lauf). (4, übersprungen): d1Audit durabel machen — by design best-effort/dormant (alle ~25 Sites; CLAUDE.md §Observability), repo-weiter Audit-Umbau = eigener OP, kein Markierungs-Fix. Verifiziert: tsc + operativ + test:do-migrations + No-Console + ng build + No-Hex + --strict grün. |
| CodeRabbit-Nachzug #754: PII-at-rest + Runtime-Guards für Markierungen (OP-R6-2) | server/src/operativ/auftrag.ts · server/party/leitstand.ts · server/src/persistence/do-state-migrations.ts · server/src/persistence/do-migrations-demo.ts · client/src/app/services/leitstand.service.ts · server/src/version.ts · docs/architektur/Fahrzeug-3D.md | v0.160.2 (PATCH): 3 Major-Findings zu #754. (1, PII-at-rest): erstelltVon (Aktor-E-Mail) wurde trotz #754-Broadcast-Fix weiter im DO-State persistiert → Feld ganz aus FahrzeugMarkierung entfernt (Server+Client) + idempotente Migration v24 scrubbt Alt-Blobs; Aktor bleibt nur im D1-Audit. (2, Stability): Runtime-Typ-Guard für kommentar/mangelId (non-string aus WS-Payload riss .trim() ab). (3, Data-Integrity): Ownership-Guard — mangelId muss zu auf.maengel dieses Auftrags gehören (kein dangling/Cross-Auftrag). Neuer do-migrations-demo-§4-Assert (v24-Scrub). Verifiziert: tsc + operativ + test:do-migrations (v0→v24) + No-Console + ng build + No-Hex + doc-consistency --strict grün. |
| OP-R6-2 V-1: Fahrzeug-3D-Datenmodell (Karosserietyp + Markierungen am Auftrag) (OP-R6-2) | server/src/operativ/auftrag.ts · server/party/leitstand.ts · server/src/persistence/do-state-migrations.ts · client/src/app/services/leitstand.service.ts · client/src/app/leitstand/pages/annahme.component.ts · client/src/app/leitstand/auftrag-detail-panel.component.ts · server/src/version.ts · docs/architektur/Fahrzeug-3D.md · ops/OP-R6-2.md | v0.160.0 (MINOR): Fundament der drehbaren 3D-Fahrzeug-Sicht mit nummerierten Markierungen (Vorschaden/Annahme und Mangel/QS gemeinsam) — ohne die Asset-/Bucket-Abhängigkeit des Viewers. karosserieTyp (Katalog, 7 generische Typen) + markierungen: FahrzeugMarkierung[] am Auftrag (renderer-neutral §5: nummer/position/normal/art/kommentar/mangelId?/fotoIds?); auftrag.create nimmt validierten Typ; markierung.setzen/entfernen-Handler (stabile Nummer, Chronik+Audit, nicht re-opt-relevant); Schema-Migration v23. Client: Karosserietyp-Dropdown im Annahme-Formular + Anzeige am Detail; setzeMarkierung/entferneMarkierung. Offen (V-2, PO-Deploy): sichtbarer Lazy-<model-viewer> + Markieren-per-Klick — braucht CC0-GLBs + R2-Bucket taktano-models/Binding. Verifiziert: tsc + test:operativ (neuer Assert) + test:do-migrations (v0→v23) + No-Console + ng build + No-Hex grün. |
OP-R4-3-Slice: dokuAspekte-Editor im Prozess-Schritt-Editor (OP-R4-3 / F16) | client/src/app/leitstand/pages/processes.component.ts · server/src/version.ts · ops/OP-R4-3.md | v0.159.0 (MINOR): die inhaltlichen Doku-Vorgaben je Teilschritt (dokuAspekte, „Worauf eingehen?") waren end-to-end gebaut (Server-Normalisierung + Patch + DTO + Service + test:prozess), nur im Admin-Editor nicht bedienbar. Jetzt „📝 Worauf eingehen?"-Block im Prozesse-Editor (Chips + Hinzufügen/Entfernen, updateTeilschritt({ dokuAspekte }), bestehende Präsenz-Verdrahtung). Reiner Client (1 Datei). Bewusst offen/geparkt: KI-Vision-Plausibilität (OP-AI-2, DSGVO — externe Vision-API für Fahrzeugfotos/Kennzeichen, PO-Go nötig) · Diktat/Improve/i18n (OP-AI-3). fotoPflicht-Editor bereits vorhanden → nicht neu gebaut. Verifiziert: ng build prod + No-Hex grün; Patch-Pfad via test:prozess abgedeckt. |
CodeRabbit-Nachzug #749: einlastung in der Vorschlags-Identität (OP-OPT-4) | server/party/leitstand.ts · server/src/version.ts · ops/OP-OPT-4.md | v0.158.2 (PATCH): 1 Major-Finding zu #749 + 2 Doku-Link-Nachträge. (Major/Data-Integrity): die stabile Vorschlags-ID in baueVorschlaege keyte auf s.key (objective) + betroffene Aufträge, nicht auf einlastung → flow/asap und flow/jit teilten vorschlagStatus/vorschlagStempel; ein verworfener Vorschlag bliebe nach Profilwechsel fälschlich unterdrückt. Fix: einlastung in die ID (`${s.key}:${einlastung}`). Doku: [PR folgt]-Platzhalter der #749-Einträge auf #749-Link gesetzt. Verifiziert: tsc + spike/replan + No-Console grün. Reiner Server. |
| CodeRabbit-Nachzug #748: Auto-Vorschlag-Profil-Konsistenz (OP-OPT-4) | server/party/leitstand.ts · server/src/version.ts · ops/OP-OPT-4.md | v0.158.1 (PATCH): 2 Findings zu #748. (1, Major/Correctness): aktualisiereVorschlaegeAuto rechnete die Feed-Vorschau mit dem admin-profil, baute das Szenario aber hartkodiert flow/"Termine retten"/asap → „Übernehmen" (uebernehmeVorschlag→berechnePlaene(aktion.objective, aktion.einlastung)) hätte einen anderen Plan als die Vorschau angewendet. Fix: key/label/einlastung aus profil (OPT_OBJECTIVE_LABEL, konsistent mit Client-Selektor). (2, Trivial): Default-Literal in eine Konstante DEFAULT_OPT_PROFIL extrahiert (4 Sites). Verifiziert: tsc + spike/replan + No-Console grün. Reiner Server. |
OP-OPT-4-Slice: admin-konfigurierbare Default-Optimierungs-Strategie (OptProfil) (OP-OPT-4) | server/party/leitstand.ts · client/src/app/services/leitstand.service.ts · client/src/app/leitstand/pages/planning.component.ts · server/src/version.ts · ops/OP-OPT-4.md | v0.158.0 (MINOR): Teil-Slice (Policy-Kern bleibt offen). Die Event-Re-Opt (aktualisiereVorschlaegeAuto, ausgelöst u. a. von auftrag.create) lastete neue Aufträge hartkodiert flow/asap ein. Neues Live-State-Feld OptProfil (objective: flow/termintreue/makespan · einlastung: asap/jit) — im DO persistiert (Blob + onStart-Backfill + snapshot), pro Verbindung auf verwaltung gegatet (ClientMsg opt.setProfil, auditiert plan.optprofil.konfiguriert, in REOPT_EVENTS), im Planung-Toolbar als zwei Selektoren neben „Auto-Nachführung" (nur mit Verwaltungs-Rolle). aktualisiereVorschlaegeAuto nutzt jetzt this.state.optProfil → neu angenommene Aufträge werden nach der eingestellten Default-Strategie gemeinsam eingelastet (Auto-Anwenden termin-neutral, OP-OPT-9). Bewusst offen: die vier OP-OPT-4-Design-Forks + Störungs-/Stabilitäts-Policy → OP-OPT-4 bleibt offen. Verifiziert: tsc + ng build prod + No-Hex grün; Live-WS-Probe: Chef setzt termintreue/jit → persistiert; Werker-Setzversuch abgelehnt (Gate greift). Server + Client, kein Schema-Change. |
| WebSocket-Hibernation: Server-Deploys wirken sofort (DO nicht mehr dauerwarm) (OP-HIBERNATE-1) | server/party/leitstand.ts · server/src/version.ts · ops/OP-HIBERNATE-1.md (neu) | v0.157.0 (MINOR): Ursache-Fix zu #742 — ein CF-DO mit offenen WebSockets evakuiert nicht → deployter Code greift erst nach „alle Tabs ~10 s zu" (Symptom „bin Chef, sehe Administration nicht": deployte Rollen-Logik lief im dauerwarmen Vor-Deploy-DO nicht). static options = { hibernate: true } → DO schläft trotz Sockets, wacht mit frischem Code → Deploys wirken sofort. Kein Datenverlust: state bleibt (Storage); Pro-Verbindung-Zustand (Rollen · Audit-Actor · Präsenz) → Verbindungs-State (conn.setState, hibernation-fest); Optimierer-Live-Zustand → in broadcastState nach Storage gespiegelt (TRANSIENT_KEY) + onStart-Reload; Caches/OTel dürfen resetten. Reiner Server. Verifiziert: tsc + 6 Selbsttests + No-Console + Live-WS-Rollen-Probe grün. Grenze: echte Hibernation lokal nicht deterministisch auslösbar → Schlaf-Pfad ruht auf partyserver/CF-Vertrag, Logik verifiziert. |
Rollen-Auswahl im Menü (interim self-declared roles, A-1.5) + KOSTEN_ADMIN_EMAILS-Allowlist entfernt (OP-AUTH-1/OP-COST-1/OP-COST-3) | client/src/app/services/rolle.service.ts (neu) · client/src/app/leitstand/shell.component.ts · client/src/app/services/leitstand.service.ts · client/src/app/leitstand/pages/{administration,chronik}.component.ts · server/party/leitstand.ts · server/wrangler.toml · server/src/version.ts | v0.156.0 (MINOR): PO parkte A-2 (Better Auth) → einfacher Interim. Im ⚙-Menü Rolle wählen (Werker · Buchhaltung · Werkstattleitung · Inhaber/Chef) → ?rolle=-Query beim Verbinden → Server leitet A-1-Fähigkeiten ab (capsAusRolle, darf()-Seam live): Werker=keine · Buchhaltung=kosten · Werkstattleitung=verwaltung · Chef=alle. kostenAdmin-Flag um verwaltung-Flag gespalten (Admin/Chronik/Nav→verwaltung, Kosten→kosten). Altlast KOSTEN_ADMIN_EMAILS/kostenAdminFuer entfernt; Access bleibt Netz-Gate (Golden Rule) + Audit-Actor. OP-COST-3 hinfällig→erledigt. ⚠ interim self-declared (Rolle selbst gewählt → kein echtes Gate; verifizierte Durchsetzung mit A-3, RISK-12). Live-DO-verifiziert (WS-Probe alle Rollen + end-to-end Admin-Gate). Verifiziert: ng build/No-Hex/tsc/No-Console grün + Screenshots. |
| ⚙-Menü: „Auf Kurs %"-Statuszeile entfernt (OP-REDESIGN-1) | client/src/app/leitstand/shell.component.ts · server/src/version.ts | v0.155.2 (PATCH): PO-Feedback — die „Auf Kurs 100 %"-Zeile (+ „N gefährdet") aus dem ⚙-Zahnrad-Popover raus; die Info lebt bereits im TN-Strip der Top-Bar (Auslastung/Fahrzeuge/verortet) + Entscheiden-/Fluss-Sichten → im Status-Popover redundant (Einfachheit). Popover trägt jetzt nur Einstellungen · Foto-Queue (bei Uploads) · Verbindung. Ungenutzte aufKursProzent-Computed mitentfernt. Live-DO-verifiziert (Hell). Reiner Client (1 Datei). Verifiziert: ng build + No-Hex grün + Screenshot. |
Scope-Entscheidung Offline: Voll-Offline-Write kategorisch ausgeschlossen + OP-OFFLINE-2 (Background Sync) angelegt (OP-OFFLINE-1/OP-OFFLINE-2) | ops/OP-OFFLINE-2.md (neu) · ops/OP-OFFLINE-1.md · docs/architektur/Offline-PWA.md · docs/konventionen/IDs.md · docs/betrieb/Offene-Punkte.md (gen-ops) | reine Doku, kein Version-Bump (PO 2026-07-26). Voll-Offline-Write (beliebige Aktionen offline) ist kategorisch ausgeschlossen — außerhalb des Produkt-Scopes, nicht „Backlog": DO = live-verbundene Single Source of Truth; Idempotenz-/Replay-/Konflikt-Komplexität widerspricht Einfachheit und zahlt auf keine True-North-Frage ein (Server-Autorität + QS/Vier-Augen/Live-Taktung ohnehin vorausgesetzt); einziger Offline-Write bleibt der enge, idempotente Foto-Upload. Background Sync (Uploads nach Tab-Schließen) → neuer offener OP-OFFLINE-2 (prio: spaeter, betrifft nur den bestehenden Foto-Upload, klar getrennt vom ausgeschlossenen Voll-Offline-Write). Verifiziert: gen-ops + doc-consistency --strict grün. |
| Offline-Resilienz Härtung (CodeRabbit-Nachzug zu #737) (OP-OFFLINE-1) | client/src/app/services/state-cache.service.ts · client/src/app/services/verbindung.service.ts · client/src/app/leitstand/shell.component.ts · server/src/version.ts · ops/OP-OFFLINE-1.md · docs/architektur/Offline-PWA.md | v0.155.1 (PATCH): 3 valide CodeRabbit-Findings zu #737 (nach Merge → Follow-up). (1, echter Bug): Cache-SCHEMA blieb 1, obwohl schemaVersion in #737 Pflichtfeld wurde → vor-0.155.0-Snapshots [ohne Feld] würden hydriert; SCHEMA 1→2 verwirft sie beim load() [der in #737 dokumentierte stille Selbstheilungs-Mechanismus, nur nicht ausgelöst]. (2): clear() schluckte IndexedDB-Fehler → gibt jetzt boolean zurück [OP-LOG-1], bei false kein Reload [kein Schein-Resync]. (3): neuSynchronisieren() verwarf Cache allein auf navigator.onLine → neue Same-Origin-Erreichbarkeits-Probe [HEAD/no-store, 3xx/4xx=erreichbar] + ehrlicher Toast bei Nicht-Erreichbarkeit [Offline-Stand bleibt]. Bewusst NICHT der schwere in-page-Resync-Umbau. Timesheet/CHANGELOG-Konsistenz mitgezogen. Verifiziert: ng build prod + No-Hex + tsc + doc-consistency --strict grün. Reiner Client (3 Dateien) + version.ts. |
| Offline-Resilienz: Schema-Broadcast + „↻ Neu synchronisieren" (Offline-Stand verwerfen + Voll-Resync) (OP-OFFLINE-1) | server/party/leitstand.ts (DTO+snapshot() schemaVersion) · client/src/app/services/state-cache.service.ts (serverSchema-Stempel + clear()) · client/src/app/services/verbindung.service.ts (neuSynchronisieren()) · client/src/app/services/leitstand.service.ts (DTO+cache.save) · client/src/app/leitstand/shell.component.ts (Banner-Link + ⚙-Eintrag) · ops/OP-OFFLINE-1.md · docs/architektur/Offline-PWA.md · server/src/version.ts | v0.155.0 (MINOR): PO-Fall „Server erreichbar, aber Datenmodell lässt sich nicht synchronisieren" / „lokale Offline-Variante passt nicht mehr zum Server-Build → alles neu laden". (1) Schema-Broadcast — Server sendet schemaVersion (SCHEMA_VERSION, DO-Persistenz) im State; Client stempelt Snapshots mit serverSchema → Cache selbstbeschreibend. (2) Stiller Selbstschutz — Cache-SCHEMA-Konstante verwirft inkompatible Alt-Snapshots beim load(); DO schickt bei Connect immer vollen autoritativen State → Reconnect heilt Daten automatisch. (3) Bewusste Aktion — neuSynchronisieren() = View-Cache verwerfen (clear()) + hartNeuLaden(); zwei Zugänge (Offline-Banner-Link + ⚙-Menü „Verbindung"). Leitplanken: nie automatisch/still (immer nur anbieten), an Netz gebunden (sonst Toast), Foto-Upload-Queue unberührt (clear() nur View-State-Key). Live-DO-verifiziert: schemaVersion=22 im Broadcast, ⚙-Eintrag rendert (Hell). Reiner Client + 1 Server-Feld. Verifiziert: ng build/No-Hex/tsc grün + Screenshot. |
| Governance: A-1 als Zwischenstand + interim-Betreiber/Admin (OP-AUTH-1) | ops/OP-AUTH-1.md | kein Version-Bump (reine Governance-Doku): PO-Entscheidung 07-25 — OP-AUTH-1 A-1 bleibt Zwischenstand; interim-Betreiber = PO. ⚠ Abgelöst durch A-1.5 (v0.156.0): die damals genannte KOSTEN_ADMIN_EMAILS-Deploy-Voraussetzung ist hinfällig — der interim-Admin-Zugang läuft jetzt über die Rollen-Auswahl im ⚙-Menü (kein Secret/Deploy nötig, „Inhaber/Chef" wählen). Access bleibt Netz-Gate. Details: neue Zeile oben + OP-AUTH-1 A-1.5. |
| A-1 CodeRabbit-Nachzug (Doku-Konsistenz + Coverage-Ehrlichkeit) (OP-AUTH-1) | server/party/leitstand.ts (darf-Kommentar) · ops/OP-AUTH-1.md · docs/fachlich/Lastenheft.md · docs/betrieb/Timesheet.md · server/src/version.ts | v0.154.2 (PATCH): 4 valide CodeRabbit-Findings zu #734 (nach Merge → Follow-up). (1) Timesheet-Summe stimmig gemacht (100.6+152.9=253.5). (2) Lastenheft §11.5 IdP-Wortlaut auf OP-AUTH-1 (Clerk/WorkOS = Fallback, nicht verworfen) angeglichen. (3) HANDOFF Rollen-Mapping Inhaber/Chef=alle. (4, Major/Security): der darf-Doc-Kommentar überzeichnete die verwaltung-Abdeckung → ehrlich gemacht: mehrere Stammdaten-Handler (employee.create/update, Skill-CRUD, teilschritt/leistung.update, Verfügbarkeit/Abwesenheit) sind ungegatet — vorbestehend (nicht durch A-1 eingeführt), bewusst kein Gate ergänzt (Gate ohne besetzte Admin-Rolle → Prod-Aussperrung bei leerer Allowlist), als bekannter A-1-Gap dokumentiert, Schließung mit A-3 (+ Rollen-Zuweisung). Verifiziert: tsc/No-Console/doc-consistency --strict grün. Reine Doku + 1 Kommentar. |
OP-AUTH-1 A-1: Rollen-/Fähigkeits-Naht — istKostenAdmin → darf(conn, faehigkeit) (OP-AUTH-1) | server/party/leitstand.ts · ops/OP-AUTH-1.md · docs/fachlich/Lastenheft.md (§11.5) · server/src/version.ts | v0.154.1 (PATCH, verhaltensgleich): erster Schritt Richtung User-Management (PO „nur a-1"). Das überladene Interim-Gate istKostenAdmin (trug 3 Bedeutungen) → neue darf(conn, faehigkeit) mit benannten Fähigkeiten kosten · verwaltung (Stammdaten/System/Konfig) · chef (G-4 Vier-Augen + Notfall). 28 Call-Sites umgestellt (7/19/2). Interim lösen alle auf denselben Betreiber-Gate auf → kein Verhaltens-Change; darf ist die Naht, an der A-3 (Better Auth) je Fähigkeit die rollenbasierte Projektion einsetzt. Rollen→Fähigkeit-Mapping als Design festgehalten (Inhaber/Chef=alle drei · Werkstattleitung=verwaltung · Buchhaltung=kosten · Werker=keine). Doku: OP-AUTH-1 (A-1 ✅ + Slices A-1…A-5), Lastenheft §11.5 (Zitadel/Ory→Better Auth nachgezogen). Verifiziert: tsc/No-Console/spike-Self-Test/doc-consistency --strict grün. Reiner Server. Offen (A-2+): Better Auth self-host + Mitarbeiter↔User-Modell (PO-Entscheidung). |
| Top-Bar-Menü prototype-treu: „⋯" → Verwaltung direkt + Zahnrad-Popover (OP-REDESIGN-1) | client/src/app/leitstand/shell.component.ts · design/WORKSPACES.md · design/CLAUDE.md · server/src/version.ts | v0.154.0 (MINOR): PO-Feedback „Menü nicht wie im Prototyp". Der Flusslinie-Prototyp hat eine minimale Top-Bar (Logo · Orte-Tabs + „⋯"=Verwaltung direkt · TN-Strip · Segment · Uhr; kein Dropdown). Mein 4A-Übergang hatte „···" als großes Overflow-Menü (alle Bereiche + Einstellungen + Status) — nach IA-komplett (4A–4E) überflüssig. Umbau: „⋯" → direkter Verwaltung-Link (Bereichs-Dropdown entfernt); die realen App-Steuerungen (Ansicht · Feedback · Alarm-Ton · Auf-Kurs · Foto-Queue), die der Prototyp nicht führt, in ein kompaktes ⚙-Zahnrad-Popover (rechts, begründete Abweichung). navGroups bleibt nur noch Routen-Titel-Registry für den Sub-Header. Live-DO-verifiziert (Hell+Dunkel: „⋯"→/verwaltung, ⚙-Popover nur Einstellungen+Status, keine Nav-Gruppen, keine Errors). Reiner Client. Verifiziert: No-Hex/ng build/doc-consistency --strict grün + Screenshots. |
| Metrik-Trends: Termintreue + Ø Durchlaufzeit (2 neue Review-KPIs) (OP-AUDIT-1/OP-COST-1 · OP-DATA-1) | server/party/leitstand.ts · server/src/db/schema.ts · server/drizzle/0002_*.sql · client/src/app/leitstand/lage-review.component.ts · client/src/app/services/leitstand.service.ts · docs/architektur/Persistenz.md · server/src/version.ts | v0.153.0 (MINOR): schließt die letzten beiden bei #722 als „nachgelagert" markierten Trend-KPIs → 5 Tages-Snapshot-KPIs. Termintreue = % fertiger Aufträge mit tatsaechlicheFertigstellung ≤ urspruenglicherAbholtermin; Ø Durchlaufzeit = Ø tatsaechlicheFertigstellung − tatsaechlicheAnlieferung (Minuten, Client zeigt Tage). Beide NULL ohne Basis (ehrlich). Datenlücke: tatsaechlicheAnlieferung war nie gestempelt → jetzt beim Fahrzeug-Check-in (angeliefert) gesetzt + im Demo-Seed (≈ Bringtermin). Drizzle-Schema += 2 Spalten (gen. Migration 0002), Runtime-Tabelle um additive Spalten-Auto-Migration (PRAGMA table_info → ALTER) erweitert. Client: 2 Sparklines, Trend-Reihe kann jetzt nicht-Prozent-Einheiten (Dauer/Tage: eigene Einheit, Fenster-Max-Skalierung, Delta in Einheit), Grid 3→5. Live-DO-verifiziert (Hell+Dunkel: Review zeigt Termintreue 100 % · Ø Durchlaufzeit 2.0 Tage + 3 bestehende, Sparklines korrekt). Client + Server + DO-SQLite. Verifiziert: No-Hex/tsc/ng build/db:check/No-Console/doc-consistency --strict grün + Screenshots. Review-Trend-KPIs damit vollständig. |
| Redesign „Flusslinie" Phase 4E — Aufräumen: Verwaltung 3-Wege-Split + Chronik (Audit-Panel) → „IA-komplett" (OP-REDESIGN-1 / OP-AUDIT-1) | client/src/app/leitstand/pages/administration.component.ts · chronik.component.ts (neu) · verwaltung.component.ts · app.routes.ts · services/leitstand.service.ts · server/party/leitstand.ts · server/src/assistant/types.ts · docs/architektur/Audit-Log.md · server/src/version.ts | v0.152.0 (MINOR): letzter Voll-IA-Schritt. (1) 3-Wege-Split: „Stammdaten & System" → drei Ort-Sub-Tabs Buchten & Hof · Schichten · System (Taxonomien ganz auf System, PO 07-25). Einfachheit: eine route-parametrisierte Komponente (data.bereich via toSignal, Template @if) statt drei Dateien → geteilte OP-EDIT-1-editResult/Präsenz-Verdrahtung bleibt ungeteilt; jeder Bereich hat genau eine Edit-Domäne. Routen plaetze/schichten/system (+stammdaten→plaetze); Sub-Sidebar 7 Tabs. (2) Chronik (OP-AUDIT-1 Slice 3): „folgt"-Tab gebaut mit echtem Server-Lesepfad — GET /audit/liste (DO-onRequest, admin-gegated kostenAdminFuer, eigenes Gate) liest audit_entries (D1, war write-only) server-seitig (SELECT … ORDER BY ts DESC, (tenant,ts)-Index, nur summary PII-arm); neuer AuditEintragDTO/AuditListe, svc.ladeAuditVerlauf(), read-only chronik.component.ts (Zeitachse, ehrlicher Leer-/Dormant-Zustand). 4-Orte-IA komplett (kein „folgt" mehr). Live-DO-verifiziert (Hell+Dunkel: 7-Tab-Split, System nur Taxonomien+Purge, Chronik rendert 3 echte D1-Zeilen; kein Schema-Change, db:check grün). Client + Server. Verifiziert: No-Hex/tsc/ng build/No-Console/doc-consistency --strict grün + Screenshots. Damit ist OP-REDESIGN-1 IA-komplett (Token→Shell/IA→Screens→Farbe→Layout-Features→4A–4E). |
| Redesign „Flusslinie" Phase 4D — Team-Seite (lesender Karten-Überblick) (OP-REDESIGN-1) | client/src/app/leitstand/pages/team.component.ts (neu) · client/src/app/app.routes.ts · client/src/app/leitstand/{shell,onboarding-hinweis}.component.ts · ops/OP-REDESIGN-1.md · server/src/version.ts | v0.151.0 (MINOR): der Team-Ort (/staff) war bisher direkt der volle Editor (StaffComponent, 1037 Z.) — der Prototyp macht daraus einen lesenden Überblick „wer kann was, wer macht was". Neuer TeamComponent = Karten-Grid: Avatar · Name/Rolle · Status-Pille (arbeitet · Frei · Pause · krank · Urlaub) · Aktuell (currentTask) · Als Nächstes (frühester geplanter Teilschritt des Mitarbeiters aus den Live-Aufträgen, Queue-Semantik wie Tafel/OP-OPT-9, computed) · Skill-Chips · read-only Status-Filter. Editor deflektiert, NICHT dupliziert: volle Pflege bleibt StaffComponent unter Verwaltung → Team & Skills (/verwaltung/team, 4B); Team-Ort trägt Deflektor-Link. /staff-Route auf TeamComponent repointet (Alt-Deep-Links → Überblick, Editieren 1 Klick weiter); Onboarding-/„···"-Label mitgezogen. Live-DO-verifiziert (Hell+Dunkel: Team-Tab aktiv, 4 Karten mit Pillen/Aktuell/Als-Nächstes/Skills, Filter mit Zählern, Deflektor; body-bg Ink im Dark). Reiner Client (1 neue Komponente + Route-Repoint + Label), kein Server/DTO/Schema — alle Kartendaten schon auf den DTOs. Verifiziert: No-Hex/ng build grün + Screenshots. Offen: 4E Aufräumen (admin-Split + Chronik) → „IA-komplett". |
| Redesign „Flusslinie" Phase 4C — Fluss konsolidieren (OP-REDESIGN-1) | client/src/app/leitstand/pages/orders.component.ts · client/src/app/leitstand/shell.component.ts · ops/OP-REDESIGN-1.md · design/WORKSPACES.md · server/src/version.ts | v0.150.0 (MINOR): Fluss war schon ~90% konsolidiert (Linie · Karte=<app-occupancy/> · Risiko · Entscheiden-Spalte · Auswahl-Panel · QS-Modal). 4C = Lücke + Nav falten: (a) Annahme-Einstieg aus dem Fluss — „+ Neuer Auftrag" öffnet das geteilte 720px-Annahme-Overlay (bisher Lage-only); (b) /occupancy (=Fluss·Karte) + /tafel von Lage → Fluss (orte-paths + „···"-Gruppe) → Fluss-Tab aktiv darauf. Bewusst NICHT gelöscht: conflicts (Hebel-Engine) · recommendations · quality bleiben Drill-downs hinter Entscheiden/QS-Modal (Triage routet dorthin). Live-DO-verifiziert (Hell+Dunkel: Annahme-Button+Overlay im Fluss, /occupancy→Fluss-Tab, keine Errors). Reiner Client. Verifiziert: No-Hex/ng build/doc-consistency --strict grün + Screenshots. Offen: 4D Team · 4E Aufräumen (admin-Split + Chronik) → „IA-komplett". |
| Phase 4B — CodeRabbit-Nachzug (OP-REDESIGN-1) | client/src/app/leitstand/pages/verwaltung.component.ts · client/src/app/leitstand/shell.component.ts · design/WORKSPACES.md · docs/betrieb/Funktionsumfang.md · docs/betrieb/Timesheet.md · server/src/version.ts | v0.149.1 (PATCH): 6 valide CodeRabbit-Findings zu #727 (nach Merge → Follow-up). A11y: ariaCurrentWhenActive="page" am Verwaltungs-Sub-Tab. Major (Doku↔Code): stale Crystal-Bar-Region-Tabelle in WORKSPACES entfernt (widersprach der Top-Bar) → knappe „Archiv"-Notiz. Label: „···"-Verwaltung-Untertitel um Prozesse·Team ergänzt. True-North (Critical): als PO-freigegebene Ausnahme dokumentiert (IA-Umstellung + Stammdaten→Taktung; kein Widget). Doku: Chronik[folgt]→Chronik (folgt); Kernaussage 4B–4E→4C–4E offen. Verifiziert: No-Hex/ng build/doc-consistency --strict grün. Reiner Client + Doku. |
| Redesign „Flusslinie" Phase 4B — Verwaltung-Seite (Sub-Sidebar + nested Routing) (OP-REDESIGN-1) | client/src/app/leitstand/pages/verwaltung.component.ts (neu) · client/src/app/app.routes.ts · client/src/app/leitstand/shell.component.ts · ops/OP-REDESIGN-1.md · design/WORKSPACES.md · server/src/version.ts | v0.149.0 (MINOR): das „···" bekommt eine echte Verwaltung-Heimat. Neue VerwaltungComponent = linke Sub-Tab-Sidebar + verschachteltes <router-outlet> (erstes nested Routing der App), hostet bestehende Editoren (reuse): Leistungen&Abläufe (processes) · Team&Skills (staff) · Stammdaten&System (administration) · Kosten (costs) · Chronik = „folgt" (net-new, OP-AUDIT-1). verwaltung Redirect→Component+Children; Alt-Deep-Links /administration→/verwaltung/stammdaten, /costs→/verwaltung/kosten; Shell-„···" Verwaltung-Gruppe → ein Eintrag. Minimal + reuse: kein Aufspalten der 869-Zeilen-administration, kein Chronik-Neubau — beides Nachzug (4E/OP-AUDIT-1). Live-DO-verifiziert (Hell+Dunkel: Sub-Sidebar 5 Einträge, Aktiv-Wechsel, Editoren im Outlet, keine Errors). Reiner Client. Verifiziert: No-Hex/ng build + doc-consistency --strict grün + Screenshots. Offen: 4C Fluss · 4D Team · 4E Aufräumen → „IA-komplett". |
| Redesign „Flusslinie" Phase 4A — Shell Rail → 62px-Top-Bar (OP-REDESIGN-1) | client/src/app/leitstand/shell.component.ts · ops/OP-REDESIGN-1.md · design/CLAUDE.md · design/WORKSPACES.md · server/src/version.ts | v0.148.0 (MINOR): PO-Hinweis „Design hat Top-Bar statt Sidebar" → frühere „UI-komplett"-Aussage (#721) war auf der Shell-/IA-Dimension zu optimistisch (4 Orte nur als Rail-Gruppen). Prototyp konsolidiert 15 Workspaces in 4 Orte → PO: Voll-IA nach Prototyp, phasiert (OP-REDESIGN-1 Phase 4). Diese PR = 4A: linke Icon-Rail → 62px-Top-Bar (Logo · Lage·Fluss·Takt·Team-Tabs [roter Aktiv-Underline, Fluss-Badge] · „···"-Overflow [alle Bereiche + Einstellungen + Status] · True-North-Strip · Leitstand|Werkstatt-Segment · Uhr) + schlanker Workspace-Sub-Header. Alle 15 Screens erreichbar (Tabs→Ort-Hauptfläche, Rest über „···"). Rail-Code raus, Foto-Queue/Toggles ins „···" (kein Funktionsverlust). Live-DO-verifiziert (Hell+Dunkel, keine Rail mehr, keine Errors). Reiner Client. Verifiziert: No-Hex/ng build grün + Screenshots. Offen: 4B Verwaltung-Seite · 4C Fluss konsolidieren · 4D Team · 4E Aufräumen → „IA-komplett". |
| Verbindungs-Wiederherstellung + Auto-Update (Offline-PWA) (OP-OFFLINE-1) | client/src/app/services/verbindung.service.ts (neu) · client/src/app/leitstand/shell.component.ts · ops/OP-OFFLINE-1.md · docs/architektur/Offline-PWA.md · server/src/version.ts | v0.147.0 (MINOR): schließt „Reload verbindet nicht neu". Ursache: der PWA-SW cached die App-Shell (navigationUrls "/**") → normaler Reload lädt aus dem Cache, geht nicht zum Server → abgelaufene Access-Session (Zero-Trust-gated) oder neuer Client werden nicht eingespielt, WS hängt (Cache verdeckt die Access-Umleitung). Neuer VerbindungService: (1) Offline-Banner „↻ Erneut verbinden" → hartNeuLaden() = SW deregistrieren + reload → Dokument frisch vom Server → Re-Login/neuer Client → WS verbindet (nur bei Netz; sonst Toast, PartySocket reconnectet selbst). (2) SwUpdate-Auto-Update: checkForUpdate() bei online/Fokus → VERSION_READY → Banner „Neue Version — neu laden". Live-DO-verifiziert (WS-Abriss → Banner+Button, keine Errors). Reiner Client. Verifiziert: No-Hex/ng build grün + Screenshot. |
| Metrik-Persistenz — CodeRabbit-Nachzug zu #722 (OP-AUDIT-1/OP-COST-1 · OP-DATA-1) | client/src/app/leitstand/lage-review.component.ts · server/party/leitstand.ts · docs/architektur/Persistenz.md · ops/OP-COST-1.md · CHANGELOG.md · docs/betrieb/Timesheet.md · server/src/version.ts | v0.146.1 (PATCH): 6 valide CodeRabbit-Findings zu #722 (kamen nach dem Merge → Follow-up-PR). Fix (Major): Review-Trend-Fenster — tagVor() jetzt Europe/Berlin (deckungsgleich zum Server-lokalerTag, sonst 1-Tag-Verschiebung) + trendReihen baut die explizite Kalendertag-Liste → fehlende Tage = null-Lücke (statt weggelassen; behebt Widerspruch zum Doc-Kommentar). Perf: metrikVerlaufDTO() Tages-Cache (metrikVerlaufCache, wie kapazitaetCache; lief je Broadcast inkl. 30-s-Solver-Ping neu), invalidiert beim neuen Snapshot. Doku: #722-PR-Links in CHANGELOG/Timesheet klickbar, OP-COST-1 bezug += OP-DATA-1, Persistenz.md D5-3-Status „angelaufen" (Mechanik live validiert) + Stand 0.146.0. Verifiziert: No-Hex/tsc/ng build + Persistenz-Gate + No-Console + doc-consistency --strict grün. |
| Metrik-Persistenz — Review-Trend-KPIs (erste DO-SQLite-Runtime-Tabelle) (OP-AUDIT-1/OP-COST-1 · OP-DATA-1) | server/src/db/schema.ts · server/drizzle/0001_*.sql · server/party/leitstand.ts · client/src/app/services/leitstand.service.ts · client/src/app/leitstand/lage-review.component.ts · docs/architektur/Persistenz.md · ops/OP-COST-1.md · server/src/version.ts | v0.146.0 (MINOR): schaltet die deferred Trend-Kennzahlen der Review-Sicht (3d-26 hatte eine ehrliche Hinweis-Karte) mit echter Verlaufs-Persistenz frei. Speicher (PO): direkt DO-SQLite (die entschiedene Snapshot-Heimat, Persistenz.md §3), nicht der Blob → erste DO-SQLite-Runtime-Tabelle metrik_snapshots (tenant-lokal, ctx.storage.sql). Drizzle-Schema = Single Source (db:check, gen. Migration); Runtime CREATE TABLE IF NOT EXISTS in onStart (analog Audit). Producer: ein Tages-Snapshot/Tag (Europe/Berlin, guarded + PK-idempotent, kein Alarm) bei Boot/erster Persistenz; nur Fakten, Prozent NULL ohne Basis (keine Fake-0, D-2). KPIs (PO): 3 heute ableitbare — Auslastung (Buchten-Quote, auslastungsQuote in geteilte Methode extrahiert) · First-Pass-Yield · Nacharbeitsquote (server-SoT aus fertigen Aufträgen). Broadcast metrikVerlauf (90 T), Retention 400 T; Client rendert je KPI eine Sparkline über Woche/Monat (Hinweis-Karte ersetzt, honester Leer-/Ein-Tag-Zustand). Best-effort (bricht Laufzeit nie). Live-DO-verifiziert (Hell+Dunkel: DO legt Tabelle an + schreibt Boot-Snapshot [1 %/33 %/67 % aus Seed], Review zeigt „1 Tag erfasst" + 3 KPIs + Sparkline). Client + Server + DO-SQLite. Verifiziert: No-Hex/tsc/ng build + Persistenz-Gate (Schema↔Migration sync) + No-Console grün. Offen (nachgelagert): Termintreue + Ø Durchlaufzeit (brauchen abgeleitete Auftrags-Historie). |
| Redesign „Flusslinie/Modernist" — 3d-28: Quality-Check-Modal (OP-REDESIGN-1 UI-komplett) (OP-REDESIGN-1) | client/src/app/leitstand/qs-modal.component.ts (neu) · services/qs-checkliste.service.ts · pages/orders.component.ts · pages/quality.component.ts · design/WORKSPACES.md · server/src/version.ts | v0.145.0 (MINOR): der letzte Redesign-Baustein. Endkontrolle in-context als 720px-Modernist-Modal (qs-modal.component.ts), geöffnet aus dem Fluss-Auswahl-Panel via „✓ Quality-Check" (zeigt sich bei Auftrag in QS-Queue, imQs). Reiner View über den geteilten QsChecklisteService: Sichtprüfungs-Checkliste + server-hartes QS-Gate (offenePunkte/abnahmebereit in diesem Slice ebenfalls in den Service hochgezogen) — kein Duplikat-State. Freigabe server-bestätigt (auftragAktion 'abholen'); Mängel/Nacharbeit → „→ Volle Endkontrolle". Live-DO-verifiziert (Hell+Dunkel: Modal öffnet, echte offene Punkte, Checkliste toggelt, Freigeben disabled; Seed hat kein QS-Auto → temporäre Gate-Lockerung für Screenshot, danach zurückgesetzt). OP-REDESIGN-1 UI-komplett (3d-20…3d-28 gebaut+gemergt); nachgelagert nur Review-Trend-KPIs nach Metrik-Persistenz. Reiner Client. Verifiziert: No-Hex/tsc/ng build grün + Screenshots. |
| Redesign „Flusslinie/Modernist" — 3d-27: QS-Checklisten-State in Service hochgezogen (OP-REDESIGN-1) | client/src/app/services/qs-checkliste.service.ts (neu) · pages/quality.component.ts · server/src/version.ts | v0.144.1 (PATCH, verhaltensgleicher Refactor): Fundament fürs QS-Modal (PO-Freigabe Option A). Der client-ephemere Sichtprüfungs-Scratchpad (✓/✕ je Prüfpunkt, keyed per QS-Runde id:runde) aus quality.component.ts → neuer QsChecklisteService (providedIn:'root'): checkState + state/setzePruef/markiereBehoben/reset/allePass/anyFail/ckey + QS_CHECKS/Pruef. Component delegiert (gleiche Signaturen → kein Template-/Verhaltens-Change); server-hartes QS-Gate bleibt getrennt. Zweck: Workspace + künftiges QS-Modal teilen einen Prüf-Stand. Bewusst isolierter Slice (QS trägt den Vier-Augen-Gate G-4). Verifiziert: No-Hex/tsc/ng build grün + Live-DO-Render-Smoke; ✓/✕-Pfad = byte-gleiche Delegation (Demo-Seed hat kein QS-Auto → tsc/build-verifiziert). Reiner Client. Offen: QS-Modal-UI + Einstiegspunkt (auf dem Service). |
| Redesign „Flusslinie/Modernist" — 3d-26: Lage · Review-Sicht (Woche/Monat) (OP-REDESIGN-1) | client/src/app/leitstand/lage-review.component.ts (neu) · pages/overview.component.ts · design/WORKSPACES.md · server/src/version.ts | v0.144.0 (MINOR): die Lage bekommt einen Heute/Woche/Monat-Umschalter (DD: Review = eigener Zustand der Lage). Heute = operativer Loop (unverändert), Woche/Monat = Rückblick (neuer lage-review.component.ts). Entscheidung (PO „ehrlicher Client-Teil"): nur echt ableitbare Daten — Team-Entwicklung (Ausbildungsziele Skill aktuell★→ziel★ + Beförderungen im Fenster aus befoerderungen[].ts, echte Historie) + Klärfall-Ursachen (aktuell offen nach Grund). Die Trend-KPIs (Termintreue/Durchlaufzeit/Auslastungs-Verlauf) brauchen persistierte Verlaufsdaten (Live-Stand hält nur den aktuellen Zustand) → ehrliche Hinweis-Karte statt Fake-Zahlen (Prototype nie gebunden); folgen mit Metrik-Persistenz (OP-AUDIT-1/OP-COST-1). Fenster: Woche=7 T, Monat=30 T. Live-DO-verifiziert (Hell+Dunkel: Umschalter · Rückblick-Header · Team-Entwicklung · Ursachen; Heute stellt den operativen Loop wieder her). Reiner Client (1 neue Datei + Wiring). Verifiziert: No-Hex/tsc/ng build grün + Screenshots. Offen: QS-Modal (State-Refactor) · Review-Trend-KPIs (nach Metrik-Persistenz). |
| Redesign „Flusslinie/Modernist" — 3d-25: Warn-Entkopplung screen-by-screen (OP-REDESIGN-1) | client/src/app/leitstand/pages/{orders,occupancy,costs}.component.ts · entscheiden.component.ts · repark-modal.component.ts · server/src/version.ts | v0.143.1 (PATCH): weil Rot in Taktano jetzt Primär- und Warnfarbe ist (DD-003), dürfen Warnungen nicht rein farblich kodiert sein. Nach vollständigem Audit (alle Screens/geteilte Komponenten, Kat. A „schon entkoppelt" vs. B „nur Farbe") die farb-nur Warnungen mit ⚠-Glyph+Wort/title versehen: Fluss „⚠ spät" (statt pulsierendem Punkt, der unter prefers-reduced-motion unsichtbar war) · „⚠" WIP-Limit-Zähler · „⚠" Entscheiden-Danger-Badge · „⚠ überbelegt"-Chip + „⚠"-Präfix im Umpark-Picker · „⚠" OTLP-Export-fehlgeschlagen. Bewusst NICHT geändert: rote Zähl-Badges an Nav/Tabs — Benachrichtigungs-Badge mit Zahl neben Domänen-Wort („Risiko"/„Konflikte") ist selbst Nicht-Farb-Signal, ⚠ im 15-px-Kreis wäre Clutter. Live-DO-verifiziert (Hell+Dunkel: „⚠ spät" 4× + „⚠"-Entscheiden-Badge; B2/B6 stellt der Seed nicht her → tsc/build-verifiziert). Reiner Client (5 Dateien). Verifiziert: No-Hex/tsc/ng build grün + Screenshots. Offen: Review-Sicht · QS-Modal. |
| Redesign „Flusslinie/Modernist" — 3d-24: Fluss inline-Auswahl-Panel (OP-REDESIGN-1) | client/src/app/leitstand/pages/orders.component.ts · server/src/version.ts | v0.143.0 (MINOR): das volle-Breite-Auswahl-Panel unter dem Fluss-Board auf die Modernist-Flusslinie-Sprache (DD-002/008): runde Punkt-/Cyan-Puls-Phasen-Leiste → 5-Stationen-Strip (Phase = Position: 9×9-Quadrat je Station — vorbei=Tinte+Konnektor · aktuell=Akzent · kommend=leer), konsistent mit dem Akten-Cockpit-Drawer (3d-22). Neuer „Alle Details →"-Knopf öffnet den geteilten 620px-Akten-Cockpit-Drawer ohne Teilschritt-Fokus (neues detailOffen-Signal; Mount panelInstanzId() || detailOffen(), Close räumt beide). Helfer stufen(a) aus stage(a); die klickbare 🚗-Fortschritts-Kette bleibt daneben. Kein Refactor des reichen Panels (Aktionen/Ausbildung erhalten). Live-DO-verifiziert (wrangler dev + Client + Seed + Playwright, Hell+Dunkel: quadratischer Stationen-Strip [rotes „Annahme" aktuell], „Alle Details →" öffnet den 620px-Drawer). Reiner Client (1 Datei). Verifiziert: No-Hex/tsc/ng build grün + Screenshots. Offen: Warn-/Dark-Durchlauf · Review-Sicht · QS-Modal. |
| Annahme-Overlay 3d-23a: CodeRabbit-Review-Nachzug (OP-REDESIGN-1) | client/src/app/leitstand/annahme-overlay.component.ts · server/src/version.ts | v0.142.1 (PATCH): Nacharbeit valider CodeRabbit-Findings zu #712 (kam als das PR schon durch war). (1) Timer-Cleanup — Dry-Run-Timer wird beim Nicht-mehr-bereit und via DestroyRef.onDestroy abgebrochen (keine stale pruefeAuftrag nach Schließen/Ungültig-werden). (2) Autofokus — Cursor beim Öffnen per viewChild+afterNextRender in den Satz-Input. (3) Toter Code — ungenutzter TERMINKLASSE_LABEL-Import + TK-Feld raus. (4) Motion-Token — .18s/.25s → var(--tk-dur-fast)/var(--tk-dur-card). Bewusst nicht: „#711-Bullet"-Fund (False-Positive, Eintrag intakt), Zeitzonen (geteilte Helper, pre-existing), OpenGrep-exec (False-Positive). Reiner Client (1 Datei). Verifiziert: No-Hex/tsc/ng build grün. |
| Redesign „Flusslinie/Modernist" — 3d-23: Annahme-Overlay „ein Satz genügt" (OP-REDESIGN-1) | client/src/app/leitstand/annahme-overlay.component.ts (neu) · pages/overview.component.ts · design/WORKSPACES.md · server/src/version.ts | v0.142.0 (MINOR): der Schnell-Intake als 720px-Modernist-Modal aus der Lage (Primärbutton „+ Neuer Auftrag", DD-001). Satz → 3 Tags (Kunde·Leistung·Abholung, Ink-gefüllt/Outline) via geteilte parseAnnahmeSatz → echter Server-Dry-Run (pruefeAuftrag→auftragPruefResult, seq-gated: Machbarkeit·Slot·Reserve·Preis) → ✓ Annehmen (createAuftrag); Fehlerfall mit 2 Auswegen (Alt-Anlieferung · ⚠ Trotzdem→Klärfall). Reiner View über geteilte Logik — keine Duplikation der Fachlogik, kein Refactor; /annahme-Vollfläche bleibt. Modernist: radius 0, 2px-Kante, rote Primär-Aktion. Live-DO-verifiziert (wrangler dev + Playwright, Hell+Dunkel: Beispiel → „✓ passt in den Takt · Slot Mo 27.07. Waschplatz 1 · +3 T · 3.200 € · ✓ Annehmen"). Reiner Client (1 neue Datei + Wiring). Verifiziert: No-Hex/tsc/ng build grün + Screenshots. Offen: Warn-/Dark-Durchlauf · Review · inline-Auswahl-Panel · QS-Modal. |
| Redesign „Flusslinie/Modernist" — 3d-22: Auftrag-Detail „Akten-Cockpit" (620px-Drawer) + Design-Handoff-Import (OP-REDESIGN-1) | client/src/app/leitstand/auftrag-detail-panel.component.ts · docs/produkt/Design-Entscheidungen.md · design/prototype/flusslinie/ · design/COMPONENTS.md · server/src/version.ts | v0.141.0 (MINOR): der geteilte Auftrag-Detail-Drawer auf die Modernist-„Akten-Cockpit"-Sprache (Flusslinie Screenshot 09, DD-002/003/008): 420 → 620px, 2px-Tinte-Kante, radius 0 (Drawer-scoped-Regel), 🚗-Kette → 5-Stationen-Strip (Phase = Position: vorbei=Tinte · aktuell=Akzent · kommend=leer), runde Status-Chips → Lifecycle-Marken als Form (■◪□, 10×10, 2px). Helfer stationen/markeBg/markeBorder. Alle Funktionen erhalten (Kunde/Fahrzeug/Foto/Doku-Gate/Vier-Augen/Klärfall/Notfall/Verzögerung/Notiz/Aktions-Hub/Verlauf). Live-DO-verifiziert (wrangler dev + injizierter Auftrag + Playwright, Hell+Dunkel: rotes „Annahme"-Aktuell, quadratische Marken, scharfe Kanten, 620px). Import: Design-Decision-Log DD-001…008 → docs/produkt/Design-Entscheidungen.md (Landkarte+Footer); Flusslinie-Prototyp (.dc.html + Wording + 22 Screenshots) → design/prototype/flusslinie/. Reiner Client (1 Datei) + Doku-Import. Verifiziert: No-Hex/tsc/ng build grün + Screenshots. Offen: Warn-/Dark-Durchlauf · Review · Annahme-Overlay · QS-Modal. |
| Redesign „Flusslinie/Modernist" — 3d-21: Lage · „Heute kommt/geht"-Streifen (OP-REDESIGN-1) | client/src/app/leitstand/pages/overview.component.ts · design/WORKSPACES.md · docs/betrieb/Funktionsumfang.md · server/src/version.ts | v0.140.0 (MINOR): zweiter net-new Layout-Schnitt (Live-DO). Unter den 3-TN-Karten ein zweispaltiger Tages-Digest — ↓ Kommt heute (Anlieferungen: geplant · bringtermin heute · nicht angeliefert) · ↑ Geht heute (Abholungen: abholtermin heute), je Uhrzeit · AU-Nr · Kunde, Klick fokussiert im Radar; ⚠ spät (rot) bei geplanteFertigstellung > abholtermin. Max 5/Spalte, Leer-Zustände. Helfer kommtHeute/gehtHeute/heuteFenster/istSpaet — kein neuer State. Live-DO-verifiziert (wrangler dev + 2 via WS injizierte Heute-Aufträge + Playwright, Hell+Dunkel: Kommt 2 · Geht 2 [⚠ spät], konsistent in „Braucht dich"). Mit-Fix: 2 CodeRabbit-Nits aus #709 (quoteFarbe-Schwellen 60–<90/≥90 · Funktionsumfang 0.139.0). Reiner Client (1 Datei). Verifiziert: No-Hex/tsc/ng build grün + Screenshots. Offen: Warn-/Dark-Durchlauf · Review · Annahme-Overlay · 620px-Drawer · QS-Modal. |
| Redesign „Flusslinie/Modernist" — 3d-20: Lage · 3-True-North-Karten-Reihe (OP-REDESIGN-1) | client/src/app/leitstand/pages/overview.component.ts · design/WORKSPACES.md · server/src/version.ts | v0.139.0 (MINOR): erster net-new Layout-Schnitt (Live-DO). Die Lage-Landing führt oben über Board+Sidebar mit drei flachen Antwort-Karten (answer-first) für die drei Leitfragen — Frage 1 Auslastung (Engpass-Quote Mitarbeiter/Buchten, Farbe via quoteFarbe) · Frage 2 Fahrzeuge (aktiv; „✓ alle verortet" / „⚠ N ohne Standort →") · Frage 3 Nächste Kapazität („ab tnAuslastung/tnKapNext, Frage 2 aus aktiveAuftraege/ohneStandortCount — kein neuer State; Sidebar-Panels bleiben Drill-down. Live-DO-verifiziert (wrangler dev + Client + Seed + Playwright, Hell+Dunkel: Q1 1 % · Q2 5 ✓ · Q3 „ab heute 14:42 · Vollfolierung Premium"). Reiner Client (1 Datei). Verifiziert: No-Hex/tsc/ng build grün + Screenshots. Offen: Warn-/Dark-Durchlauf · „Heute kommt/geht" · Review · Annahme-Overlay · 620px-Drawer · QS-Modal. |
| Redesign „Flusslinie/Modernist" — 3d-19: Design-Doku Prosa-Modernisierung (WORKSPACES/COMPONENTS ↔ Code) (OP-REDESIGN-1) | design/WORKSPACES.md · design/COMPONENTS.md · design/CLAUDE.md · ops/OP-REDESIGN-1.md | kein Version-Bump (reine Doku, selber PR wie 3d-18): die Design-Doku trug noch v3-Prototyp-Sprache, die der Code seit 3d-1..3d-18 nicht mehr abbildet (aktive Doku↔Code-Widersprüche, OP-DOCS-9). Bereinigt: JETZT-Linie „cyan/Glow" → rot (--tk-brand); Selektion (Kachel/Ghost/geklickter Schritt/Drop-Ziel/Standort/Master-Detail) → Ink (--tk-text); 12 Workspace-Signaturfarben (— #hex-Überschriften · Nav-Glow-Bar · Header-Dot · Empty-Glyph · Segmented-Hex) → entfernt/Ink; Glass/Glow/radius-hero/Gradient-CTA → flach/radius 0/Rot-CTA; Konflikte/Klärfälle-Rohhex → --tk-red/--tk-amber; Ink-Gantt-Block-Encoding im Gantt-Rezept ergänzt. Behalten: .tk-pchip-Cyan-Puls (Live/Präsenz) + funktionale Status-Hues. Nur hoch-sichere, dokumentierte Korrekturen; unverifizierbare Farbdetails unangetastet. Reine Doku (2 Design- + 2 Status-Docs). Offen: Warn-/Dark-Mode-Durchlauf · net-new Layout-Features. |
| Redesign „Flusslinie/Modernist" — 3d-18: Ink-Gantt (Dual-Theme → Token + Block-Stil, Live-DO-verifiziert) (OP-REDESIGN-1) | client/src/app/leitstand/gantt.component.ts · pages/planning.component.ts · server/src/version.ts | v0.138.0: Teil B Block-Stil — die Gantt-Block-Füll-Optik trägt den Teilschritt-Stand (Hue = Auftrags-Status): Outline=geplant (wartet) · gefüllt=in_arbeit/erledigt · grau=pausiert (Helfer blockBg/blockBorder/blockText, live-verifiziert Hell+Dunkel). Teil A Dual-Theme: der Gantt trug als letzte Komponente die Vor-Modernist-Dual-Theme-Logik (~22 slate/white-!dark()-Paare + 5 @if(dark())-gegatete Features, im Hell-Modus unsichtbar); Optik hing am dark-Input statt an Tokens. Fix: alles → --tk-*-Tokens (dark byte-identisch, Hell = Modernist-Neutrale), Features in beiden Themes; dark-Input + Binding + ThemeService-Injection entfernt. Bug behoben: Dark-Gantt war weißes Grid auf dunklem Cockpit. Verifiziert am laufenden Stack (wrangler dev + Client + Seed + Playwright, Hell+Dunkel). Funktionale Block-/Ausfall-Farben unverändert. Reiner Client (2 Dateien). Verifiziert: No-Hex/tsc/ng build grün. Offen: vollständiger Warn-Sicht- und Dark-Mode-Durchlauf · Layout-Features. |
| Redesign „Flusslinie/Modernist" — 3d-17: Warn-Entkopplung Toasts (OP-REDESIGN-1) | client/src/app/leitstand/toasts.component.ts · design/COMPONENTS.md · server/src/version.ts | v0.137.1 (PATCH): erster Warn-Entkopplungs-Baustein — der Toast-Ton war rein farblich kodiert (Default-Glyph fix ✓, so war danger rot ununterscheidbar vom roten brand). Fix: TONE_ICON je Ton (ok ✓·brand ✦·warn ⚠·danger ⚠·info ℹ) → die Glyph-Form trägt den Ton. Aufrufer-t.icon gewinnt. Audit: übrige rote Stellen haben schon Label/Icon/role=alert/Satz oder sind Aktionen. Reiner Client (1 Datei). Verifiziert: No-Hex/tsc/ng build grün. Offen (Live-DO): screen-by-screen Warn-Durchlauf + Dark-Mode · Ink-Gantt · Layout-Features. |
| Redesign „Flusslinie/Modernist" — 3d-16: Token-Hygiene (OP-REDESIGN-1) | design/tokens/{tokens.json,build.mjs,tokens.css} · design/{DESIGN_TOKENS,CLAUDE,WORKSPACES,COMPONENTS}.md · client/src/app/leitstand/pages/{costs,processes,staff,conflicts}.component.ts · server/src/version.ts | v0.137.0: Aufräum nach Rainbow-Ablösung — 14 ungenutzte --tk-ws-*-Tokens entfernt (tokens.json/build.mjs/tokens.css, 98→84, Round-Trip grün); 23× hover:bg-white/[.03] → hover:bg-tk-hover (theme-aware); Klärfälle-Badge zurück auf Amber (war in 3d-15 versehentlich Rot — Zwei-Achsen: Termin/Konflikte=Rot, Störung/Klärfälle=Amber); Design-Docs synchronisiert (tote Token-Refs raus). Verifiziert: No-Hex/tokens:check/ng build grün. Offen: Ink-Gantt-Refactor (Live-DO) · Layout-Features · WORKSPACES/COMPONENTS Prosa-Modernisierung. |
| Redesign „Flusslinie/Modernist" — Phase 3d-15: ws-Signaturfarben — Screens (Rainbow abgelöst) (OP-REDESIGN-1) | client/src/app/leitstand/pages/{costs,recommendations,conflicts,processes,orders,quality,planning,annahme,staff,overview}.component.ts · server/src/version.ts | v0.136.0: alle 10 Screens von der --tk-ws-*-Rainbow befreit (kein ws-Token mehr in einem Screen). Tabs/Selektion/Dekor/Chips/Balken/Badges → Ink; solide Primär-CTAs (Übernehmen/Starten/+Posten/Freigeben/Annehmen) → Rot; Konflikt-/Klärfall-Alarm-Badges → Rot (Gefahr, 3d-2). Rainbow-IA endgültig durch Ink+Rot ersetzt. Reiner Client (10 Dateien). Verifiziert: No-Hex/ng build grün. Offen: Ink-Gantt-Block-Refactor (Live-DO) · 3-TN-Karten/Overlays/Drawer/QS-Modal · ws-Token-Defs ungenutzt (optionaler Cleanup). |
| Redesign „Flusslinie/Modernist" — Phase 3d-14: ws-Signaturfarben — geteilte Komponenten (OP-REDESIGN-1) | client/src/app/leitstand/{auftrag-detail-panel,shell,naechste-aufgaben,klaerung-einplanen,klaerfall-loesen}.component.ts · pages/tafel.component.ts · server/src/version.ts | v0.135.0: Start des ws-Rainbow→Ink/Rot-Feinschliffs (14-farbige --tk-ws-* → Modernist) auf die geteilten Komponenten — Detail-Panel „Speichern" (ws-Vollfläche) → Rot, CRM-Link/„✦ Vorziehen"-Outline → Ink; Shell Werker-⬣ → Rot (wie 3d-5), 3 Nav-Badge-Farben → Ink (Badge-Feinschliff aus 3d-2); Tafel/Klärung/Klärfall/Nächste-Aufgaben → Ink. Regel: ws-Vollfläche-Primär → Rot · ws-Dekor/Outline → Ink. Reiner Client (6 Dateien). Verifiziert: No-Hex/ng build grün. Offen: ws-Farben in den Screens (costs/recommendations/conflicts/processes/orders/quality/planning/annahme/staff/overview) · Ink-Gantt-Block-Refactor (Live-DO) · 3-TN-Karten/Overlays/Drawer/QS-Modal. |
| Redesign „Flusslinie/Modernist" — Phase 3d-13: Takt/Gantt-Chrome & Klärfall — Cyan-Feinschliff abgeschlossen (OP-REDESIGN-1) | client/src/app/leitstand/pages/planning.component.ts · gantt.component.ts · klaerfall-loesen.component.ts · server/src/version.ts | v0.134.0: letzter Cyan-Durchgang — Planung Info/Metrik → Ink, „✎ Entwurf"-Banner + Testdaten-Checkbox → Rot; Gantt Preset-Toggle/„→ Details"/Drag-Ghost-gültig → Ink (ungültig=Rot); Klärfall QS/Schritt-Routen → Ink (Zurück=Grün/Abbruch=Rot bleiben). Cyan-Feinschliff des ganzen Cockpits abgeschlossen. Bewusst Cyan (dokumentiert): funktionale Lifecycle-Status-Hues (labels/phase/artFarbe/gantt-wunschfrei — Brief bewahrt Status-Hues) + Live-Signale (✎/⏺/Spinner/istUmparken). Reiner Client (3 Dateien). Verifiziert: No-Hex/ng build grün. Offen (OP-REDESIGN-1): Gantt-Block-Stil-Refactor (braucht Live-DO) · ws-Farben-Reste · 3-TN-Karten/Overlays/Drawer/QS-Modal. |
| Redesign „Flusslinie/Modernist" — Phase 3d-12: Bild-Gate & Shell-Reste (OP-REDESIGN-1) | client/src/app/leitstand/bild/bild-upload-gate.component.ts · pages/bild-schutz.component.ts · shell.component.ts · server/src/version.ts | v0.133.0: Foto-Gate (Personen/Kennzeichen vor Upload, OP-QS-2) + Shell — Prüf-Emphase/Hover/Auto-Punkt/Markier-Toggle → Ink; Marker-Badges + ins Bild gebrannte Marker-Kreise + „Hochladen"-Primär → Rot; Shell Theme-Glyph + Auf-Kurs-Ring → Ink. Manuell=Amber bleibt. Reiner Client (3 Dateien). Verifiziert: No-Hex/ng build grün. Offen (3d-Rest): Klärfall-Palette · ws-Farben · labels/phase-Helfer · Ink-Gantt · 3-TN-Karten. |
| Redesign „Flusslinie/Modernist" — Phase 3d-11: Annahme & Prozesse (OP-REDESIGN-1) | client/src/app/leitstand/pages/{annahme,processes}.component.ts · server/src/version.ts | v0.132.0: Cyan-Feinschliff auf Annahme („Takt-Kommando"-Intake — Kommandozeilen-Glow entfernt, Alternativ-Button + Info-Chips → Ink, „Radar zeigen"-CTA-Glow → Rot) + Prozesse (Info-Tint/Mindest-Niveau-★/Abhängigkeits-Toggle/Foto-Vorgabe-Outline/.tk-flag.tk-on → Ink, Typ-Checkbox → Rot). Cyan behalten: ⏺-Live-Puls („tippt/parst") + Lade-Spinner = Live-/Processing-Signale. Reiner Client (2 Dateien). Verifiziert: No-Hex/ng build grün. Offen (3d-Rest): Bild-Gate/Bild-Schutz/Shell · Klärfall-Palette · ws-Farben · labels/phase · Ink-Gantt. |
| Redesign „Flusslinie/Modernist" — Phase 3d-10: Belegung & Fluss-Gruppe (OP-REDESIGN-1) | client/src/app/leitstand/pages/{occupancy,conflicts,quality}.component.ts · server/src/version.ts | v0.131.0: Cyan-Feinschliff auf Belegung/Karte (Q2 „wo stehen die Fahrzeuge" — Drag&Drop-Hinweis, Wareneingang-Zone, Drag-Ziel-Highlight, ✓da/📍/🅿️-Icons → Ink), Konflikte (Info-Box/Notiz/Standort/Avatar-Rotation → Ink), Qualität (KPI + Mangel in_nacharbeit → Ink; offen=Amber/behoben=Grün bleiben). Drop-Ziel bewusst Ink (kein Alarm); funktionale Status-Hues + Rot-Doppelbelegung bleiben. Reiner Client (3 Dateien). Verifiziert: No-Hex/ng build grün. Offen (3d-Rest): Annahme/Prozesse/Bild-Gate/Shell · Klärfall-Palette · ws-Farben · labels/phase-Helfer · Ink-Gantt. |
| Redesign „Flusslinie/Modernist" — Phase 3d-9: Detail-Panel & geteilte Modals/Overlays (OP-REDESIGN-1) | client/src/app/leitstand/{auftrag-detail-panel,repark-modal,chat-panel,feedback-form,feedback-pin-overlay,modal-dialog,toasts,screenshot-region-overlay,fortschritts-indikator}.component.ts · pages/meine-arbeit.component.ts · server/src/version.ts | v0.130.0: Cyan-Feinschliff auf die überall geteilten Komponenten — Detail-Panel (Teilschritt-Fokus/Notiz-Toggle/Produktion-Outline), Umparken-Modal (Slot-Auswahl/„✓ passt"), Feedback-Formular, Pin-/Screenshot-Overlays, Fortschritts-Ring, Terminal-Umpark-Karten → Ink; Chat-User-Sprechblase + Modal-Bestätigen + Toast brand → Rot. Glyphen (✅/✓) tragen die Bedeutung. Offen: Klärfall-Lösen-Palette (semantisches 4-Farbset, eigene Entscheidung). Reiner Client (10 Dateien). Verifiziert: No-Hex/ng build grün. Offen (3d-Rest): occupancy/Annahme/Prozesse/Konflikte/Qualität/Bild-Gate · ws-Farben · Ink-Gantt. |
| Redesign „Flusslinie/Modernist" — Phase 3d-8: Fluss & Lage Modernist (OP-REDESIGN-1) | client/src/app/leitstand/pages/orders.component.ts · client/src/app/leitstand/pages/overview.component.ts · server/src/version.ts | v0.129.0: die zwei zentralen True-North-Sicht-Screens (Fluss „wo & wann" · Lage/Hof-Radar) — Auswahl (Card/Slot/Avatar/Nav-Fokus/aktueller Schritt/Standort) → Ink (--tk-text); „Flusslinie" (Radar-Sweep) → Rot (--tk-brand) + Glow entfernt (flach); Selektions-Glows entfernt; „Produktion starten"-Outline → Ink. Unberührt: tk-cyan2 (schon rot) + funktionale Status-Hues. Reiner Client (2 Dateien). Verifiziert: No-Hex/ng build grün. Offen (3d-Rest): Ink-Gantt · Overlays/Drawer/QS-Modal · Cyan-Feinschliff Terminal/Modals/Detail-Panel/Konflikte/Qualität/Prozesse · ws-Signaturfarben. |
| Redesign „Flusslinie/Modernist" — Phase 3d-7: Team-Editor Modernist (OP-REDESIGN-1) | client/src/app/leitstand/pages/staff.component.ts · server/src/version.ts | v0.128.0: Team-Screen + Mitarbeiter-Editor nach Feinschliff-Regel — Vertrauens-★/Skill-Niveau-★/Abwesenheits-Toggles gewählt → Ink (--tk-text, 15 Bindungen); Schicht-Checkboxen → Rot; XP-Badge/Fairness-Zähler/Info-Tint → Ink; weiches Abwesenheits-Label → Ink (hart bleibt Rot). Cyan behalten: ✎-Präsenz + istUmparken-Live-Status + artFarbe-Schicht-Farbe (→ Gantt/Schedule-Slice). Reiner Client. Verifiziert: No-Hex/ng build grün. Offen (3d-Rest): Ink-Gantt · Overlays/Drawer/QS-Modal · Lage-Rest · Cyan-Feinschliff Fluss/Lage/Terminal/Modals. |
| Redesign „Flusslinie/Modernist" — Phase 3d-6: Verwaltung Modernist (OP-REDESIGN-1) | client/src/app/leitstand/pages/administration.component.ts · server/src/version.ts | v0.127.0: Verwaltungs-Screen entfärbt — Config-Auswahl-Chips (Taxonomie-Art · Skill-Eignung · Wochentage · Nachbar-Buchten) gewählt → gefüllte Ink-Chips (--tk-text); „+ Arbeitsplatz"/„+ Schicht" (waren --tk-ws-*) → Rot (--tk-brand); Sekundär-Outline „+ Sperre"/„Neu laden" → Ink; „aktiv"-Checkboxen → Rot. Cyan behalten: die drei „✎ wird gerade bearbeitet"-Badges = reserviertes Live-/Präsenz-Signal. Feinschliff-Regel (3d-1/3d-3): Selektion/Config → Ink · Primär → Rot · Live → Cyan. Reiner Client. Verifiziert: No-Hex/ng build grün. Offen (3d-Rest): Ink-Gantt · Overlays/Drawer/QS-Modal · Lage-Rest · restlicher Cyan/Badge-Feinschliff (Fluss/Lage/Team/Terminal/Modals). |
| Redesign „Flusslinie/Modernist" — Phase 3d-5: Werkstatt-Terminal Modernist-Akzent (OP-REDESIGN-1) | client/src/app/leitstand/pages/meine-arbeit.component.ts · server/src/version.ts | v0.126.0: Werker-Fläche „Meine Arbeit" — einziger Akzent --tk-ws-werker (Indigo) → Rot (--tk-brand): Werker-Auswahl aktiv, Avatar, Offen-Zähler, Leer-Glyph ⬢, Status-Pille. Terminal durchgängig monochrom+rot. Reiner Client. Verifiziert: No-Hex/ng build grün + Live-Screenshot. Offen (3d-Rest): Ink-Gantt · Verwaltung · Overlays/Drawer/QS-Modal · Lage-Rest · restlicher Cyan/Badge-Feinschliff. |
| Redesign „Flusslinie/Modernist" — Phase 3d-4: Team · Kann-was-Matrix (OP-REDESIGN-1) | client/src/app/leitstand/pages/staff.component.ts · server/src/version.ts | v0.125.0: Team-Screen führt oben eine Kann-was-Matrix — Mitarbeiter × Skills, Zellen = ★-Könner-Stufe (1–3) + Ausbildungsziel-Spalte; ganze Zeile klickbar → Mitarbeiter-Editor (Reuse). Rein aus Live-Signalen (employees/skills), Leer-Guard. True-North: „wer kann was" auf einen Blick. Reiner Client. Verifiziert: No-Hex/tsc/ng build grün (visuell mit Daten = braucht laufendes DO, wie Gantt). Offen (3d-Rest): Ink-Gantt · Verwaltung · Werkstatt-Terminal · Overlays/Drawer/QS-Modal · Lage-Rest · Cyan/Badge-Feinschliff. |
| Redesign „Flusslinie/Modernist" — Phase 3d-3: Takt-Controls Modernist (OP-REDESIGN-1) | client/src/app/leitstand/pages/planning.component.ts · server/src/version.ts | v0.124.0: Takt/Planung-Toolbar entfärbt — asap/jit + Auto-Nachführung aktiv → Ink (--tk-text); Plan ändern (Entwurf) → Rot (--tk-brand). Reiner Client. Verifiziert: No-Hex/tsc/ng build grün + Live-Screenshot. Offen: der Gantt selbst (gantt.component.ts) — Vor-Token-Dual-Theme (dark()→slate/white, ~24 Bindungen) + Ink-Gantt-Block-Stil = eigene größere Slice (braucht Live-Daten). Ferner 3d-Rest: Team-Matrix/Verwaltung/Terminal · Overlays/Drawer/QS-Modal · restl. Cyan/Badge-Feinschliff. |
| Redesign „Flusslinie/Modernist" — Phase 3d-2: Monochrome Ort-Chips (Nav) (OP-REDESIGN-1) | client/src/app/leitstand/shell.component.ts · server/src/version.ts | v0.123.0 (erledigt deferrten Teil von Phase 2b): Rail-Chips/Stripes von Rainbow---tk-ws-* → Ink (--tk-text-dim); aktiver Ort rot (--tk-brand via .tk-nav.tk-active); Header-Platz-Punkt + Logo-Kachel cyan→rot; Stripe-Glow entfernt (flach). Badges bleiben (rot=Gefahr). Reiner Client. Verifiziert: No-Hex/tsc/ng build grün + Live-Screenshot (Ink-Chips, aktiver Ort rot). Offen (3d-Rest): Toggle/Selektion-Cyan → Ink · restliche Badge-Farben · 3-TN-Karten-Reihe · Heute kommt/geht · Review · Overlays/Drawer/QS-Modal · Takt-Ink-Gantt/Team-Matrix/Verwaltung/Terminal. |
| Redesign „Flusslinie/Modernist" — Phase 3d-1: Accent-Sweep (Primär-Aktionen → Rot) (OP-REDESIGN-1) | client/src/app/leitstand/** (13 Component-Templates) · server/src/version.ts | v0.122.0: solide background: var(--tk-cyan)-Füllungen (27 Stellen) → var(--tk-brand) (Rot): Primär-Aktions-Buttons (Assistent-FAB, „Optimierung vorschlagen", „Pin/Notiz", Bestätigungen), JETZT/Now-Linien (Brief: rote JETZT-Linie), Highlight-Badges + zugehörige Glows. Brief-konform „Rot = Primäraktion". Bewusst offen (Feinschliff): Toggle-Aktiv/Selektion-Cyan (~63) + --tk-green/--tk-ws-* → Ink/Rot. Reiner Client. Verifiziert: No-Hex/tsc/ng build grün + Live-Screenshot (rote CTAs + FAB). Offen (3d-Rest): Toggle/Selektion-Cyan · 3-TN-Karten-Reihe · Heute kommt/geht · Review · Overlays/Drawer/QS-Modal · Takt-Ink-Gantt/Team-Matrix/Verwaltung/Terminal. |
| Redesign „Flusslinie/Modernist" — Phase 3c: Lage · „Braucht dich"-Digest (OP-REDESIGN-1) | client/src/app/leitstand/pages/overview.component.ts (Digest-Karte + brauchtDich/brauchtDichGesamt) · server/src/version.ts | v0.121.0: Lage-Sidebar führt oben einen „Braucht dich"-Digest — die dringendsten Entscheiden-Einträge (max 4: Klärfälle/Notfälle · Termin-Konflikte · Ortung, Typ-Label + Ton-Kante), Zähler „N → Entscheiden", Klick → Fluss. Rein aus Live-Signalen, Leer „Alles im Takt.". Reiner Client. Verifiziert: No-Hex/tsc/ng build grün + Live-Screenshot. Offen (3c-Rest/3d): 3 TN-Karten-Reihe · Heute kommt/geht · Review-Sicht · Annahme-Overlay · 620px-Drawer · QS-Modal · Takt/Team/Verwaltung/Terminal. |
| Redesign „Flusslinie/Modernist" — Phase 3b: Fluss · Linie/Karte-Toggle (OP-REDESIGN-1) | client/src/app/leitstand/pages/orders.component.ts (Toggle + app-occupancy eingebettet) · server/src/version.ts | v0.120.0: Fluss-Screen mit Sicht-Umschaltung Linie · Karte · Risiko. Linie = 5-Stationen-Pipeline; Karte = bestehende app-occupancy eingebettet (Buchten/Hof, Umparken per Drag&Drop); Risiko = Timeline. „Entscheiden"-Spalte bleibt in allen Sichten rechts. Reuse statt Neubau (Einfachheit), reiner Client. Verifiziert: No-Hex/tsc/ng build grün + Live-Screenshot. Offen (3c+): inline-Auswahl-Panel · 620px-Auftrag-Drawer · Quality-Check-Modal · Lage/Takt/Team/Verwaltung/Terminal. |
| Redesign „Flusslinie/Modernist" — Phase 2b: True-North-Strip im Header (OP-REDESIGN-1) | client/src/app/leitstand/shell.component.ts (trueNorth computed + Header-Strip) · server/src/version.ts | v0.119.0: die 3 True-North-Leitfragen immer sichtbar in der Kopfzeile — „Auslastung X % · N Fzg · alle verortet / N ohne Standort · frei ‹Leistung›". Rein aus Live-Insights abgeleitet (insights().auslastungsQuote/kapazitaet, aktiveAuftraege, ohneStandortCount), kein neuer State/Server. Fehlende Ortung rot. Ab lg-Breite. Verifiziert: No-Hex/tsc/ng build grün + Live-Screenshot. Offen in 2b: strukturelle Rail→62px-Top-Tab-Bar + monochrome Ort-Chips (eigener Schnitt; gruppierte Rail liefert 4-Orte-IA schon Modernist). |
| Redesign „Flusslinie/Modernist" — Phase 3a: Fluss · „Entscheiden"-Spalte (OP-REDESIGN-1) | client/src/app/leitstand/entscheiden.component.ts (neu) · client/src/app/leitstand/pages/orders.component.ts (mount) · design/COMPONENTS.md · design/WORKSPACES.md · server/src/version.ts | v0.118.0: die konzeptionelle Mitte — „System entscheidet, Mensch bestätigt". Geteilte EntscheidenComponent (rechte Spalte 360px, xl+, auf dem Fluss-Screen) sammelt nur Live-Signale (klaerfaelle/konflikte/ohneStandort/vorschlaege, keine Fixtures) zu Vorschlagskarten (3px-Topline nach Ton · Typ-Label · Titel/Body · „Vorschlag"-Block · „✓ So machen"/„Später" · Leer „Alles im Takt."). „So machen" wendet echte Mutation an (vorschlagVorziehen) bzw. springt in die zuständige Ansicht; „Später" blendet je Sitzung aus. Reiner Client, kein Server/DTO/Migration. Verifiziert: No-Hex/tsc/ng build grün + Live-Screenshot (Linie + Entscheiden-Spalte). Offen (Phase 3b+): Linie/Karte-Toggle + Umparken-D&D · Auswahl-Panel · 620px-Auftrag-Drawer · Quality-Check-Modal · Lage/Takt/Team/Verwaltung/Terminal-Screens. |
| Redesign „Flusslinie/Modernist" — Phase 2: IA auf 4 „Orte" (OP-REDESIGN-1) | client/src/app/leitstand/shell.component.ts (navGroups()) · client/src/app/app.routes.ts (Alias-Routen) · server/src/version.ts | v0.117.0: Navigation von „Kern-Loop/Weitere" auf die 4 „Orte" Lage · Fluss · Takt · Team + Verwaltung (admin-gegated) + Werkstatt-Terminal umgestellt. Alle 16 Workspaces in genau einen Ort einsortiert (nichts verwaist), Views unverändert, Deep-Links intakt; Alias-Routen /lage /fluss /takt /team /verwaltung /terminal. True-North-Badges erhalten. Additive IA-Umstellung (Rail-Rendering bleibt). Verifiziert: tsc/ng build grün + Live-Screenshot (Header „Lage · Hof-Radar"). Offen (Phase 2b/3): Rail→62px-Top-Tab-Bar-Optik, monochrome Ort-Chips, zusammengeführte Ort-Screens (Fluss „Entscheiden"-Spalte, Ink-Gantt, Drawer, Overlays). |
| Redesign „Flusslinie/Modernist" — Phase 1: Token-Layer (OP-REDESIGN-1) | design/tokens/tokens.json (Modernist, LIGHT-first) · design/tokens/build.mjs (invertiert) · design/tokens/tokens.css (generiert) · client/src/app/services/theme.service.ts · client/src/index.html (Archivo) · client/src/styles.css · server/src/version.ts | v0.116.0: --tk-*-Token-Layer auf Modernist umgestellt, LIGHT-first — Basis-$value = Hell (→ :root), Dunkel unter $extensions.taktano.dark → [data-theme="dark"] (Dark-Mode mitgeneriert, PO 07-23; OP-R9-9 gewahrt). Marke = Rot #ec3013 (--tk-brand/--tk-red), BG #f3f2f2/Text #201e1d, radius 0 durchgehend, Font Archivo (Daten via .font-mono + tabular-nums), kein Ambient-Glow. Funktionale Status-/Gantt-Hues erhalten (Hell-Werte → Basis, Dunkel → Override). ThemeService/index.html/styles.css auf Light-first + Archivo nachgezogen. Reiner Token-/Theming-Change (kein Server/DTO/Migration). Verifiziert: tokens:check/no-hex/tsc/ng build grün + Live-Screenshot. Offen (Phase 2/3): 4-Orte-Shell/IA, Workspace-Signaturfarben, Glass/Glow-Reste, Assistent-FAB-Cyan, Wordmark-Assets. |
| Redesign „Flusslinie/Modernist" — Phase 0: Entscheidung + Roadmap (OP-REDESIGN-1) | ops/OP-REDESIGN-1.md · Root-CLAUDE.md (§Design-Prinzipien, Rot-Ausnahme) · design/CLAUDE.md (Umbau-Banner + Brand-Kopf) · server/src/version.ts | v0.115.0 (docs-only): PO-Entscheidung 07-23 — das Claude-Design-Projekt „Taktano Neu v2 – Flusslinie" (DS „Modernist") löst Design-System und Marke vollständig ab, phasiert (Tokens → Shell/IA → Screens), jede Phase grün+mergebar. Bewusste Konflikt-Auflösungen: Cyan→Rot #ec3013 (Primär/Marke), Dark→Light (#f3f2f2/#201e1d), 12 Workspaces→4 Orte (Lage·Fluss·Takt·Team + Verwaltung + Werkstatt-Terminal), Radius-Skala→radius 0, Space Grotesk/JetBrains→Archivo, Glass/Glow→flache 2px-Linien. Golden-Rule-Ausnahme (begründet): „Rot nur Warnung" bleibt drkv-Default + Schwester-Repos (MED-/SERA-) unverändert; Taktano = dokumentierte Ausnahme → Warnungen brauchen nicht-rein-farbliche Kennzeichnung. Phase 0 = nur Doku, kein Screen-Umbau. Nächster Schritt: Phase 1 = Token-Layer (Modernist) als eigener PR. |
| Taktano-Cockpit (Dark-Redesign) — Fundament | client/src/index.html (Tokens als Tailwind-Config + Fonts) · client/src/styles.css (Animationen) · client/src/app/leitstand/shell.component.ts · pages/overview.component.ts · pages/placeholder.component.ts · app.routes.ts | PR 1: Dark Mission-Control-Shell (Sidebar 7 Workspaces mit Signaturfarben + Live-Badges + Logo, Header mit Signatur-Punkt/Titel/Uhr/Sweep, „Auf-Kurs“-Box) + Überblick-Raum voll nach Spec (Hero, KPI-Ring, 2 Spalten). Routing pro Raum (/overview, /planning, …). Tokens/Spec: design/DESIGN_TOKENS.md + DESIGN_SPEC.md. Alle 7 Räume umgesetzt (pages/): Überblick · Planung (Gantt [dark] + Optimierer-Banner) · Belegung (Board + Drag&Drop-Umparken + Park-Dialog + geparkt-Marker) · Aufträge (Master-Detail) · Mitarbeiter (Filter+Karten) · Konflikte (Triage + Folgen-Sim + Crumple-Auflösung) · Qualität (Endkontrolle-Queue + Checkliste + Freigabe). Default-Route → /overview; /classic bleibt als Fallback. Offen: maßstäbliches Hofplan-Layout, Umpark-Auftrag mit Puls/Round-Robin, Foto-Upload, eigene Icon-Library; /classic vorgezogen entfernen (INTEGRATION_PLAN Phase 0). |
| UX-Review-Zyklus 07-11 (Review + alle 6 Empfehlungen) + Klärungs-Engine | docs/betrieb/UX-Review-2026-07.md (Urteil S1–S6/B1–B7/E1–E6) · client/.../labels.ts, modal-dialog.component.ts, onboarding-hinweis.component.ts+onboarding.service.ts, klaerfall-loesen.component.ts · server/src/operativ/auftrag.ts (loeseKlaerfallMitRoute) · server/src/insights/insights.ts (naechsteKapazitaeten) | auf main, v0.70.0→0.74.0 (PRs #434/#436–#440): UX-/Prozess-Review als Doku-Artefakt; E1–E3 Werker-Terminal-Modus · Klärfall am Schritt · zentrale Label-Sprache (OP-UX-7 ✅); E5 app-modal-dialog statt nativer Dialoge + tote Komponenten raus; E6 Onboarding „Kurz erklärt“ (OP-ONBOARD-1 Slice 1); E4 True-North-Kacheln (Kapazität je Leistung + Standorte → Sanity-Frage 3 ✅); Klärungs-Engine (OP-R3-1-Folge ✅): geroutetes Lösen zurück/QS/anderer-Schritt/Abbruch, Melden pausiert + erfasst Auslöser, D1-Audit + Reopt. Review-Befunde B2–B5, B7 geschlossen; größter offener Hebel: OP-AUTH-1 (B1). |
| Auslastungs-Quote-Kachel (zeitbasiert, True-North-Frage 1) | server/src/insights/insights.ts (auslastungsQuote) + insights-demo.ts · server/party/leitstand.ts (insights.auslastungsQuote) · client/.../services/leitstand.service.ts + pages/overview.component.ts | auf main (v0.70.0, #433); % verplante vs. verfügbare Zeit je Gruppe (Mitarbeiter · Buchten) über den Planungszeitraum — ergänzt den physischen Snapshot auslastung() um die Zeit-Achse (Sanity-Checkliste Frage 1). Reine, testbare Funktion (belegt ∩ verfügbar gekappt, merge/subtract); DO leitet MA-Verfügbarkeit via mitarbeiterAvailability, Bucht-Verfügbarkeit = offene Werkstattzeit (Schicht-Envelope) − Sperre/Wartung (Buchten sonst 24/7 → als Nenner irreführend). KPI-Kachel oben in der Überblick-Sidebar (Mini-Balken, Ampel ohne Rot). Nichts gespeichert (D-2). Self-Test in test:insights. Offen: wählbarer Zeitraum (heute/Woche) + Trend-Sicht (Sanity-Checkliste Frage 1). |
| Initial-Bundle Lazy-Loading (OP-PERF-1 ✅) | client/src/app/app.routes.ts (loadComponent je Workspace außer Shell + Überblick) · client/angular.json (Budget gestrafft) | v0.98.0: Route-Level-Lazy-Loading — 14 Workspaces je eigener Chunk, erst beim Öffnen geladen. Initial-Chunk 935,7 → 558,8 kB (Total 1,02 MB → 643 kB, −37 %). Budget maximumWarning 1 mb→750 kb / maximumError 1,25 mb→900 kb. Landing-Raum eager (kein Lazy-Flash), Deep-Links unverändert. Reiner Client. Optional/später: Prefetch-Strategie · SW/PWA-Cache (OP-OFFLINE-1). |
| OP-EDIT-1 KOMPLETT: Leistungen/Teilschritte (Ko-Bearbeiter-Präsenz; Slice A N/A ✅) | client/.../pages/processes.component.ts (editEnter('prozesse','config') im Constructor + editLeave via DestroyRef + Ko-Bearbeiter-Banner) · ops/OP-EDIT-1.md (status erledigt) | v0.114.0: letzter OP-EDIT-1-Editor abgeschlossen. Befund: Prozesse-Editor ist durchgängig sofort-anwendend inline (jede Feld-Änderung feuert sofort teilschritt.update/leistung.update, kein Formular/Speichern/baseRev) → Slice A (rev-Optimistik) architektonisch N/A (kein last-write-wins-auf-Save-Fenster; jede Mutation atomar + broadcastet); Force-Fit bewusst abgelehnt (Einfachheit). Slice B adaptiert: Ko-Bearbeiter-Banner „wird gerade auch bearbeitet — Änderungen wirken sofort" für die geteilte taktungs-harte Live-Konfig. Reiner Client, kein Server/DTO/Migration. OP-EDIT-1-Rollout über ALLE Editoren abgeschlossen (Arbeitsplatz·Schicht·Mitarbeiter·Taxonomie mit A+B; Leistungen/Teilschritte mit B). |
| OP-EDIT-1 Rollout: Taxonomie-Editor (rev-Optimistik + Präsenz ✅) | server/src/model/types.ts (TaxonomyValue.rev) · server/party/leitstand.ts (taxonomie.update baseRev/revVeraltet/naechsteRev + edit.result, TaxonomieDTO.rev) · client/.../services/leitstand.service.ts (TaxonomieDTO.rev, taxonomieUpdate(…, baseRev)) · .../pages/administration.component.ts (inline: startTaxEdit/taxRename/schliesseTaxEdit-Ack-Flow + Konflikt-Banner + ✎-Badge) | v0.113.0: OP-EDIT-1-Muster auf den inline Taxonomie-Editor („Umbenennen") ausgerollt — veraltete Basis abgelehnt (edit.result{ok:false}), Erfolg quittiert; Präsenz via generischer editEnter('taxonomie',id) (kein Server-Change). Inline-Konflikt-UX: schließt + Banner oben (Liste zeigt Gewinner via Broadcast), Aktiv-Quick-Toggle bewusst ohne baseRev. rev optional → keine Migration. Rollout jetzt auf 4/5 Editor-Gruppen. Offen (Rollout-Rest): Leistungen/Teilschritte. |
| OP-EDIT-1 Rollout: Mitarbeiter-Editor (rev-Optimistik + Präsenz ✅) | server/src/model/types.ts (Mitarbeiter.rev) · server/party/leitstand.ts (employee.update baseRev/revVeraltet/naechsteRev + edit.result, Employee-DTO rev) · client/.../services/leitstand.service.ts (Employee.rev, updateEmployee(…, baseRev)) · .../pages/staff.component.ts (Präsenz-Banner + Konflikt-Hinweis + ✎-Badge + schliesseBearbeiten()-Ack-Flow) | v0.112.0: OP-EDIT-1-Muster (Slice A + Slice B) auf den Mitarbeiter-Bearbeiten-Dialog ausgerollt — veraltete Basis abgelehnt (edit.result{ok:false}, Dialog offen), Erfolg schließt; Präsenz via generischer editEnter('mitarbeiter',id) (kein Server-Change). rev guardt gezielt das Stammdaten-Speichern (additive Sub-Aktionen Skill/Ausbildung/Abwesenheit heben rev nicht). view-first schon (Karte + „✎"-Knopf). rev optional → keine Migration. Offen (Rollout-Rest): Taxonomien ✅ (v0.113.0) · Leistungen/Teilschritte. |
| OP-EDIT-1 Rollout: Schicht-Editor (rev-Optimistik + Präsenz ✅) | server/src/model/types.ts (SchichtKatalog.rev) · server/party/leitstand.ts (schicht.update baseRev/revVeraltet/naechsteRev + edit.result, DTO rev) · client/.../services/leitstand.service.ts (SchichtKatalogDTO.rev, schichtUpdate(…, baseRev)) · .../pages/administration.component.ts (Präsenz-Banner + Konflikt-Hinweis + ✎-Badge + Ack-Flow) | v0.111.0: OP-EDIT-1-Muster (Slice A optimistische Nebenläufigkeit + Slice B Präsenz-Warnung) auf den Schicht-Editor ausgerollt — veraltete Basis abgelehnt (edit.result{ok:false}, Formular offen), Erfolg schließt; Präsenz via generischer editEnter('schicht',id) (kein Server-Change). view-first schon durch „Bearbeiten"-Knopf. rev optional → keine Migration. |
| Schicht-Ende-Aufräum-Checkliste (OP-SCHICHT-1 Slice 4 ✅) | client/.../pages/overview.component.ts (aufraeumCheckliste/aufraeumOffenCount + Karte „🧹 Schicht-Ende-Aufräumen") | v0.110.0: konsolidierte To-do-Liste vor Feierabend — 📍 ohne Standort (ohneStandortCount, Link) · 🌙 nicht in der Halle (nachtHalle.reste) · 🅿️ Umparken offen (umparkAuftraege); grün „bereit fürs Schichtende" bei 0. Reine Client-Komposition bestehender Signale (D-2, kein Server/DTO, keine Persistenz — auto-klärend). Offen: Nacht-Zustand als Scheduler-Planungsziel. |
| Nacht-Halle-Konfig (OP-SCHICHT-1 Slice 3 ✅) | server/src/insights/insights.ts (NachtHalleKonfig + nachtHalleKonfigEffektiv/istNachtHalleSlot) · server/party/leitstand.ts (PersistedState.nachtHalleKonfig + onStart, Projektion, nachtHalleKonfig.update-Handler, DTO) · client/.../services/leitstand.service.ts (NachtHalleKonfig + nachtHalleKonfigUpdate) · .../pages/administration.component.ts (Karte „🌙 Nacht-Halle (Schicht-Ende)") | v0.109.0: Schwelle „hochwertig" (Güteklasse 1–3, Default 2) + Nacht-Hallen-Buchten admin-editierbar. istNachtHalleSlot: buchtIds-Allowlist ODER Indoor-Typ-Fallback (leer). Optionales persistiertes Feld → keine Migration. Admin-Message istKostenAdmin-gated, validiert/klemmt/filtert. Offen: Aufräum-Checkliste, Nacht-Zustand als Planungsziel. |
| Nacht-Halle-Check (OP-SCHICHT-1 Slice 2 ✅) | server/src/insights/insights.ts (nachtHalleReste + InsightAuftrag.standortIndoor/gueteklasse) · server/party/leitstand.ts (Projektion standortIndoor je Auftrag via Bucht-Zugehörigkeit + INDOOR_TYP_RE, Insights-DTO nachtHalle) · client/.../services/leitstand.service.ts (NachtHalleInsight) · .../pages/overview.component.ts (Karte „🌙 Nacht-Halle") · server/src/insights/insights-demo.ts (test:insights) | v0.108.0: abgeleiteter Schicht-Ende-Check — hochwertige Fahrzeuge (Güteklasse ≥ Schwelle, Default 2) nicht in Halle/Indoor (oder Standort unbekannt) → Überblick-Karte (grün „alle drinnen"/amber „N nicht in der Halle" + Liste). Indoor-Status pro Auftrag über die tatsächliche Bucht (robust gegen doppelte Namen); „Halle" via bestehendes Bucht-Typ-Label (INDOOR_TYP_RE), rein D-2, kein neues Modell/Migration. Schwelle + Nacht-Hallen-Buchten ab v0.109.0 admin-konfigurierbar (Slice 3, Zeile oben). |
| Schichtende-Aufräum-Reserve (OP-SCHICHT-1 Slice 1 ✅) | server/src/model/types.ts (aufraeumReserveMin) · server/src/scheduler/availability.ts (aufraeumReserveMin-Helper + Abzug am spätesten Slot) · .../scheduler/ausfall.ts (Band art:'aufraeumen') · server/party/leitstand.ts (Patch/Handler/DTO, klemmeReserve) · client/.../services/leitstand.service.ts · .../pages/administration.component.ts (Editor) · .../gantt.component.ts (Farbe/Label) · server/src/scheduler/schicht-reserve-demo.ts (test:schicht-reserve) | v0.107.0: jede Schicht reserviert die letzten X Min (Default 30, admin-editierbar pro Schicht, 0…120) fürs Aufräumen → Scheduler plant dort keine Arbeit. Abzug an einer Stelle (mitarbeiterAvailability, spätester Slot) → paritätisch TS-Scheduler + CP-SAT-Solver (via vorab-expandierte avail). Grünes „Aufräumen"-Gantt-Band. Default 30 via ?? 30 (keine Migration). Fixtures test:ausfall/test:bereitschaft auf 0 gepinnt. Offen: hochwertige Fahrzeuge→Halle, Aufräum-Checkliste, Nacht-Zustand als Planungsziel. |
| Umpark-Empfehlung nach Skill (OP-UMPARK-3 Slice 2 ✅) | client/.../leitstand/repark-modal.component.ts (geforderterSkillId/geforderterSkillName/buchtBietetSkill; Zwei-Stufen-Sort im empfohlen) | v0.106.0: Empfehlung rankt zuerst nach Skill-Eignung der Bucht (Arbeitsplatz.skillIds ⊇ {geforderter Skill}, §6.1 — typ-gleiche Bucht ohne Skill ist gar kein gültiges Ziel), dann Kapazität; „🎯 teilschritteKatalog.benoetigteSkillId, Bucht-Skills aus arbeitsplaetze().skillIds → rein Client, kein Server/DTO. Fallback = Typ-Empfehlung bei fehlenden Skill-Tags. Offen: Ausstattung (kein Schritt-Anforderungsfeld) + Nähe/G-4 (kein Standort-/Zonen-Modell) — ehrlich vertagt. |
| Schritt-Abschluss: Server-Backstop (OP-STEP-1 Slice 4 ✅ → OP-STEP-1 erledigt) | server/src/operativ/auftrag.ts (istAktuellerSchritt/istOffenerSchritt) · server/party/leitstand.ts (teilschritt.aktion 'erledigen'-Gate) · server/src/operativ/step-gate-demo.ts (test:step-gate) · .github/workflows/ci.yml · docs/betrieb/Tests.md | v0.105.0: Sequenz-Gating jetzt serverseitig — out-of-order-Abschluss wird abgelehnt (Defense-in-Depth zum Client-Gating aus Slice 1). Nur der aktuelle Schritt der Reihenfolge (Front = früheste Startzeit der offenen; laufende immer aktuell; echte Parallel-Schritte teilen die Startzeit) ist abschließbar; Gate greift vor Doku-/Foto-Gate. Reine, testbare Prädikate; Selbsttest 20 Prüfungen (CI-Gate). Rein Server, keine DTO-/Schema-Änderung. OP-STEP-1 damit komplett (4/4 Slices); offen nur bedingte „feinere Parallelität" (G-1-Abhängigkeit explizit ins DTO). |
| Umparken-Sichtbarkeit geklärt (OP-UMPARK-4 ✅) | ops/OP-UMPARK-4.md (Ist-Tabelle 8 Auslöse-Stellen + Entscheidung) · client/.../pages/occupancy.component.ts (Label „📍 Standort" → „📍 Standort zuweisen") | v0.104.1: Ist-Bestandsaufnahme aller Umpark-Trigger; Grundgerüst sauber (1 ReparkService + 1 globales Modal), Verteilung kontextrichtig → bleibt. Entscheidung: 2 Begriffe („Standort zuweisen" vs. „Umparken"), 2 Direkt-Pfade (Drag&Drop + Freiräumen) bleiben bewusst, Sichtbarkeits-Referenztabelle im OP. Nur Wortlaut-Angleich, keine Verhaltensänderung. |
| Umpark-Empfehlung nach Schritt (OP-UMPARK-3 Slice 1) | client/.../leitstand/repark-modal.component.ts (aktuellerSchritt/geforderteTypen/empfohlen; Empfehlungs-Gruppe im Modal) | v0.104.0: Repark-Modal empfiehlt oben die zum aktuellen/nächsten Schritt passenden Buchten (geforderter Typ + freie Kapazität, freieste zuerst, mit Begründung); Rest darunter. Match über vorhandene Label-Felder (benoetigteBuchtTypen = typLabel) → rein Client, kein Server/DTO. Pause (Teil B) weitgehend via OP-UMPARK-1 modus:'pausieren'. Offen: Skill/Ausstattung/Nähe-Gewichtung (G-4), Transit-Pause Bucht→Bucht. |
| Foto-Vorgaben pflegen (OP-STEP-1 Slice 3) | client/.../pages/processes.component.ts (fotoAdd/fotoSetAnzahl/fotoRemove, Foto-Vorgabe-Editor + Doku-Pflicht-Toggle) · services/leitstand.service.ts (ProzessSchrittDTO.{dokuPflicht,fotoPflicht,dokuAspekte} + updateTeilschritt-Patch) | v0.103.0: je Teilschritt Pflicht-Foto-Perspektiven + Mindestanzahl im Prozesse-Workspace editierbar (datalist-Vorschläge + freier String G-1) + Doku-Pflicht-Toggle → speist Abschluss-Checkliste (Slice 2). Rein Client — Server nahm den Patch längst an (setzeTeilschrittFelder) + emittierte die Werte im DTO; nur Client-DTO+Editor fehlten. Damit OP-STEP-1 Slices 1–3 gebaut; offen nur optionaler Server-Backstop. |
| Geführter Foto-/Doku-Abschluss (OP-STEP-1 Slice 2) | client/.../leitstand/auftrag-detail-panel.component.ts (abschlussReste/ohneNachweisVorgabe; Restliste + „Alles erfasst" + Leere-Vorgabe-Hinweis; Foto-Block-Überschrift) | v0.102.0: Abschluss-Dialog zeigt sprechende Restliste der fehlenden Pflicht-Fotos (je Perspektive) + Pflicht-Doku, live; „✓ Fertig" gesperrt bis alles da; leere Vorgabe klar benannt (Slice-3-Hook). Spiegelt das bestehende Disabled-Gate (keine zweite Wahrheitsquelle). Reiner Client. Offen: Slice 3 (Vorgabe-Pflege), Server-Backstop. |
| Nur aktueller Schritt fertigmeldbar (OP-STEP-1 Slice 1) | client/.../leitstand/auftrag-detail-panel.component.ts (istAktuellerSchritt/istGesperrterSchritt/aktuellerSchrittName/istOffen, kannSchrittErledigen verschärft; „▶ jetzt dran"-Marker + „🔒 kommt später"-Hinweis) | v0.101.0: nur der aktuelle Schritt (laufend oder frühester offener per Startzeit-Frontier) ist fertigmeldbar + hervorgehoben; spätere gesperrt. Parallelität über Scheduler-Startzeiten. Reiner Client, kein Server/Schema. Offen: Server-Backstop (out-of-order), Vorgabe-Pflege (Slice 3). Erfasst zugleich OP-UMPARK-3/-4. |
| View-first Detailansicht (OP-EDIT-1 Slice C, Referenz) | client/.../pages/administration.component.ts (ansichtId/ansichtOffen/ansichtBay · anzeigen/ansichtSchliessen · read-only Detail-Panel · Liste „Anzeigen"+✎-Badge · skillName/ausstattungName/hatBearbeiter) | v0.100.0: Stammdaten öffnen zuerst read-only (Detailansicht: Kapazität, Status, Skills/Ausstattung als Namen, Sperren, rev), Bearbeiten erst per „✎ Bearbeiten" von dort (→ Slice-B-Präsenz). Präsenz-Warnung schon in der Anzeige, ✎-Live-Badge in der Liste. Abbrechen/Speichern kehrt in die Anzeige zurück. Reiner Client. Damit A/B/C gebaut; offen: Muster-Rollout auf die übrigen Editoren (Taxonomien/Schichten/Mitarbeiter/Leistungen). |
| Edit-Präsenz (OP-EDIT-1 Slice B) | server/party/leitstand.ts (editPraesenz-Map · edit.enter/edit.leave · bearbeitungen im Snapshot · onClose-Cleanup · EditPraesenzDTO) · client/.../services/leitstand.service.ts (fensterId, editEnter/editLeave, fremdeBearbeiter, EditPraesenz) · pages/administration.component.ts (Präsenz-Warn-Banner · editEnter bei Bearbeiten · editLeave bei Abbrechen/Destroy) | v0.99.0: „wer bearbeitet gerade welchen Datensatz" als transienter DO-Live-State (nicht persistiert), live gebroadcastet. Betreten/Verlassen via edit.enter/edit.leave mit stabiler fensterId (interim, OP-AUTH-1); onClose räumt verwaiste Präsenz. Oranges Warn-Banner im Arbeitsplatz-Editor bei fremden Bearbeitern — blockt nicht (erster Speichervorgang gewinnt via Slice A). edit.enter admin-gegated. Kein Migrations-Aufwand. Slice C ✅ (View-first-Referenz am Arbeitsplatz-Editor); offen: Muster-Rollout auf die übrigen Editoren. |
| Optimistische Nebenläufigkeit (OP-EDIT-1 Slice A) | server/src/operativ/edit-parallel.ts (revVeraltet/naechsteRev) + edit-parallel-demo.ts (test:edit) · server/src/model/types.ts (Arbeitsplatz.rev?) · party/leitstand.ts (DTO rev · arbeitsplatz.update baseRev-Prüfung + edit.result-Quittung + rev-Bump) · client/.../services/leitstand.service.ts (ArbeitsplatzDTO.rev, arbeitsplatzUpdate(…, baseRev), editResult-Signal) · pages/administration.component.ts (baseRev merken · auf Quittung warten · Konflikt-Banner + „Neu laden") | v0.97.0: erster Baustein gegen stilles last-write-wins (Auslöser OP-UMPARK-2 Slice B). Monotoner rev je Bucht (nur serverseitig erhöht); Speichern schickt baseRev mit → veraltete Basis wird abgelehnt (nicht angewendet/gebroadcastet), per-Verbindungs-Quittung edit.result {ok} schließt das Formular (ok) bzw. zeigt Konflikt-Hinweis + „Neu laden" (abgelehnt). Ack-basiert statt Broadcast-Heuristik (kein Race). Rückwärtskompatibel (ohne baseRev = altes Verhalten), kein Migrations-Aufwand. Slice B ✅ (Edit-Präsenz) · Slice C ✅ (View-first-Referenz); offen: Muster-Rollout auf die übrigen Editoren. |
| Geplante Sperre zur Laufzeit + Vorlauf (OP-UMPARK-2 Slice B) | server/src/operativ/sperre.ts (validiereSperren/sperreGueltig) · operativ/konflikte.ts (konflikteGeparktVorSperre, Typ geparkt_vor_sperre) · party/leitstand.ts (ArbeitsplatzPatch.sperren + Handler + sperreGrundIds + DTO sperren) · client/.../pages/administration.component.ts (Sperren-Editor) · conflicts.component.ts (Label + Repark-Knopf) | v0.96.0: Bucht-Sperren (Zeitfenster) zur Laufzeit anleg-/entfernbar (Admin-Editor: Grund-Dropdown + Von/Bis + Beschreibung), server-validiert (beginn<ende, gültiger Grund). Vorlauf-Konflikt geparkt_vor_sperre: parkendes Auto in aktiver Bucht mit kommender Sperre → rechtzeitig umparken. Kein Migrations-Aufwand. |
| Bucht freiräumen (OP-UMPARK-2 Slice C, OP-UMPARK-2 ✅) | client/.../pages/occupancy.component.ts (freiraeumen/kannFreiraeumen/freierParkplatz, „🅿️ Freiräumen"-Knopf) | v0.96.0: wartendes Auto (kein laufender Prozess) in einer Bucht → per Klick auf ersten freien Parkplatz umparken (bestehender G-4-Umpark-Auftrag OP-UMPARK-1). Reiner Client. Ausblick: CP-SAT-Abwägung „warten vs. ausparken" bleibt spätere Solver-Optimierung. Damit OP-UMPARK-2 abgeschlossen (Slices A/B/C). |
| Alarm-Ton am Leit-Bildschirm (OP-ALERT-1 Slice 6, OP-ALERT-1 ✅) | client/.../services/alarmton.service.ts (Web-Audio-Ton, Autoplay-Unlock, Stummschaltung) · leitstand/shell.component.ts (Rail-Toggle 🔔/🔕 + Service injiziert) | v0.95.0: neuer Notfall → akustisches Signal (Web-Audio-Oszillator, kein Binär-Asset), zusätzlich zur Alarm-Optik (Slice 2). AudioContext erst nach User-Geste (Autoplay-Policy), stummschaltbar (localStorage), kein Ton beim ersten Laden. Damit ist OP-ALERT-1 rund → erledigt. Video-Erfassung ausgegliedert → OP-ALERT-2 (neu, offen). Reiner Client. |
| Freigabe-Workflow der Leitung (OP-ALERT-1 Slice 5) | server/party/leitstand.ts (klaerfall.loesen-Chef-Gate für Notfall + Audit notfall.freigabe.abgelehnt) · client/.../auftrag-detail-panel.component.ts + pages/conflicts.component.ts (notfallFreigabeBlockiert/istChef, Freigabe-Knopf geblockt mit Grund) | v0.94.0: nur die Leitung/der Chef darf die Notfall-Sperre aufheben (server-hart, interim Chef-Gate wie OP-QS-6 bis OP-AUTH-1); Beweisfoto bleibt für alle Pflicht. Client spiegelt den Gate (🔒 nur Leitung / 📷 Foto nötig) statt stiller Ablehnung; „✓ Sperre aufheben" für Notfälle. |
| Alert-Knopf im Werker-Modus (OP-ALERT-1 Slice 4) | client/.../pages/meine-arbeit.component.ts (🚨-Notfall-Knopf + Mini-Formular je Schritt-Karte · Presets · kannNotfallMelden/notfallMelden · inline 📷-Beweisfoto wenn gesperrt) | v0.93.0: der Werker löst den Notfall/Schaden-Alarm direkt in „Meine Arbeit" aus (nicht nur im Leitstand-Panel) — gleicher Server-Pfad (auftrag.klaerfall art=notfall, Auslöser-Schritt wandert mit, nichts dupliziert); solange gesperrt ist das Beweisfoto (Slice 3) inline erfassbar. Reiner Client, voll verifizierbar. |
| Foto-Pflicht am Alarm (OP-ALERT-1 Slice 3) | server/src/model/types.ts (FotoAttachment.notfall = Ziel C) · operativ/auftrag.ts (notfallBeweisfotoErfuellt) · party/leitstand.ts (Upload ?notfall=1 · foto.registriert-Notfall-Ziel · klaerfall.loesen-Gate · AuftragDTO.notfallFotos) · client/.../services/leitstand.service.ts (uploadNotfallFoto) · auftrag-detail-panel.component.ts (📷-Erfassung + Pflicht-Hinweis) · client/angular.json (Bundle-Budget) | v0.92.0: Kern von OP-ALERT-1 — Notfall/Schaden braucht ≥1 Beweisfoto, Fahrzeug-Sperre erst danach aufhebbar (server-hart). Neues Foto-Ziel C notfall (bewusst getrennt vom QS-Mangel → verfälscht die Mangel-Auswertung nicht). Direkt-Upload im Detail-Panel solange gesperrt. Selbsttest test:notfall erweitert. R2-Roundtrip dormant (kein FOTOS-Binding) → Live-R2 nachziehen. Bundle-Budget angehoben → Folge OP-PERF-1 (Lazy-Loading). |
| Alarm-Sichtbarkeit (OP-ALERT-1 Slice 2) | client/.../services/leitstand.service.ts (gesperrteFahrzeuge/gesperrteCount) · leitstand/shell.component.ts (globaler Alarm-Chip in der Kopfzeile) · pages/conflicts.component.ts (🚨-Badge in Klärfälle-Liste+Detail · klaerfaelleSortiert priorisiert Notfall) | v0.91.0 (Branch claude/next-steps-8vmq5d): der Notfall-Alarm „darf nicht verschwinden" → globaler, immer sichtbarer Alarm-Indikator in der Kopfzeile (rot/pulsierend „🚨 N gesperrt", Klick → Klärfälle-Tab, aus jedem Workspace) + eigenes 🚨-„Fahrzeug gesperrt"-Badge in der Klärfälle-Liste+Detail (unterscheidbar vom „⚠ eskaliert") + Notfall ganz oben einsortiert. Rein abgeleitet (D-2), bleibt bis der Notfall-Klärfall gelöst wird. Reiner Client, kein Server/Schema. Deckt Teil der „Alarm-Optik" (OP-KOMM-1). |
| Fahrzeug in gesperrter Bucht → Umparken (OP-UMPARK-2 Slice A) | server/src/operativ/konflikte.ts (konflikteGeparktInGesperrt + Typ geparkt_gesperrt) · server/party/leitstand.ts (Wiring in weitereKonflikte) · client/.../services/leitstand.service.ts (KonfliktTyp) · pages/conflicts.component.ts (Label + „📍 Umparken"-Knopf, reparkZiel) · ops/OP-UMPARK-2.md | v0.90.0 (Branch claude/next-steps-8vmq5d): schließt die Lücke, dass eine Bucht-Sperre still über ein physisch geparktes Auto hinweggehen konnte — die alten Typen (sperre_kollidiert/arbeitsplatz_fehlt) prüfen nur geplante Arbeit, nicht die belegung. Neuer Konflikt geparkt_gesperrt (Hoch) rein abgeleitet (D-2, kein State/Migration), erscheint automatisch bei jedem Broadcast einer belegten nicht-aktiven Bucht; Direkt-Knopf „📍 Umparken" (Repark-Modal OP-UMPARK-1) bei eindeutigem Fahrzeug. Selbsttest test:konflikte erweitert. Policy (PO 07-17): Bucht mit Auto nicht still sperrbar; sofort→sofort umparken (G-4), geplant→vor beginn. Offen: Slice B (geplante Sperre zur Laufzeit + Vor-Umparken) · Slice C (Bucht freiräumen — Hebel, später CP-SAT). Getrennt: OP-SCHICHT-1 (Schicht-Ende-Aufräumen: hochwertige Fahrzeuge in die Halle · nächste Schicht vorbereiten · wenig über Nacht in Arbeit außer Cool-down). |
| Notfall-/Schaden-Alert (OP-ALERT-1 Slice 1) | server/src/operativ/auftrag.ts (KlaerfallArt/art, meldeNotfall, fahrzeugGesperrt) · server/party/leitstand.ts (Notfall-Zweig + Audit notfall.gemeldet) · do-state-migrations.ts (v21) · client/.../services/leitstand.service.ts (auftragNotfall) · client/.../auftrag-detail-panel.component.ts (🚨-Knopf + gesperrt-Badge) · docs/architektur/Notfall-Alert.md | v0.85.0 (Branch claude/next-steps-8vmq5d): Notfall = Klärfall-Variante (art:'notfall'), keine Parallel-Mechanik (Einfachheit). Hard-Stop laufender Schritte + erzwungene Eskalation + Fahrzeug gesperrt (fahrzeugGesperrt, D-2). Auffälliger 🚨-Knopf im geteilten Detail-Panel (Grund pflicht); Audit notfall.gemeldet; Selbsttest test:notfall (CI-Gate). Offen (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. |
| Mangel-Status-Workflow (OP-QS-1 Slice 1) | server/src/operativ/leistung.ts (MangelStatus 3-stufig) · auftrag.ts (markiereMangelInNacharbeit, Abnahme-Gate + erledige-Behoben-Logik) · party/leitstand.ts (Übergänge in nacharbeitEinplanen/nacharbeitErfassen) · do-state-migrations.ts (v22) · client/.../services/leitstand.service.ts + pages/quality.component.ts (Status-Badges) | v0.86.0: M06 offen → in_nacharbeit → behoben (zuvor nur 2). Mangel bekommt Nacharbeitsschritt → in_nacharbeit; Schritt fertig → behoben; QS-Abnahme-Gate blockt bis behoben. QS-Workspace-Badges (offen=amber · in Nacharbeit=cyan · behoben=grün). Migration v22 · Selbsttest test:mangel-status (CI-Gate). Offen (Folge-Slices): Foto-Beweismittel am Mangel (M05, speist OP-ALERT-1) · manuelles „behoben"+Vier-Augen (G-4) · Auswertung je Kategorie/Skill/MA · admin-editierbare Kategorien (G-1). |
| Beweisfotos am Mangel (OP-QS-1 Slice 2 / M05) | server/src/operativ/auftrag.ts (beweisfotosZuMangel) · party/leitstand.ts (FotoRefDTO/toFotoRef/MangelDTO, Mangel-Fotos im DTO) · client/.../services/leitstand.service.ts (Mangel.fotos) · pages/quality.component.ts (Thumbnails) | v0.87.0: Jeder Mangel trägt in der QS-Sicht die Beweisfotos des Teilschritts, an dem er entdeckt wurde (abgeleitet/D-2). Bestehende Teilschritt-Fotos wiederverwendet statt zweitem Upload-Pfad (Einfachheit). Selbsttest test:beweisfoto (CI-Gate). Slice 3 ✅ v0.88.0: Pflicht-Beweisfoto für schwere/kritische Mängel (Abnahme-Gate blockt bis dokumentiert). Offen (nach Slice 4 ✅ v0.89.0): Video-Erfassung · manuelles „behoben"+Vier-Augen. |
| Pflicht-Beweisfoto für schwere Mängel (OP-QS-1 Slice 3) | server/src/operativ/auftrag.ts (mangelBrauchtBeweisfoto + istAbnahmebereit-Regel) · client/.../pages/quality.component.ts (Gate-Spiegel offenePunkte + „📷 Beweisfoto nötig"-Hinweis) | v0.88.0: schwerer/kritischer Mangel (M03) braucht ≥1 Beweisfoto → QS-Abnahme-Gate blockt die Abholung bis dokumentiert, auch nach Behebung (Beweislage). Leicht/mittel ohne Zwang. Selbsttest-Erweiterung test:beweisfoto. Offen (mangel-eigene R2-Erfassung ✅ Slice 4 v0.89.0): Video-Erfassung · manuelles „behoben"+Vier-Augen. |
| Dedizierte Mangel-Foto-Erfassung (OP-QS-1 Slice 4 / M05) | server/src/model/types.ts (FotoAttachment polymorphes Ziel teilschrittInstanzId|mangelId) · party/leitstand.ts (Upload-Endpoint ?mangel= · foto.registriert Mangel-Ziel · fotosByMangel-Merge im DTO + Gate) · auftrag.ts (istAbnahmebereit zählt mangel-eigene Fotos) · client/.../services/leitstand.service.ts (uploadMangelFoto) · pages/quality.component.ts (📷-Knopf je Mangel) | v0.89.0: Beweisfoto direkt am Mangel erfassbar (nicht nur am Schritt) — schließt die Lücke „Mangel an Schritt ohne Foto-Pflicht". Direkt-Upload (verbundener QS-Kontext, nicht durch die Offline-Queue). Liefert die Beweismittel-Mechanik auch für OP-ALERT-1. Selbsttest test:beweisfoto. R2-Roundtrip dormant (kein FOTOS-Binding) → via Typecheck/Build/Selbsttest verifiziert, Live-R2 nachziehen. |
| Lastenheft (Fachkonzept, Master) | docs/fachlich/Lastenheft.md (Markdown + Mermaid) | abgenommen, IDs stabil |
| Produkt & Marketing (nicht-technisch: Automotivo-Marktbeobachtung, Vorteilsrechner/ROI, Nutzenversprechen) | docs/produkt/Produkt-und-Marketing.md | auf main |
| Vorteilsrechner-Tool (Quick-ROI-Rechner für Interessenten, Marketing-Landingpage — OP-VERTRIEB-1 ✅ v1) | docs-site/src/pages/vorteilsrechner.js | v1 auf Branch claude/vorteilsrechner-prospects-0hm08a; rein client-seitig, konservative Bandbreite (8–22 %, Formel aus Produkt-und-Marketing.md §3.1); Lead-Erfassung (Hubspot o. ä.) bewusst noch nicht verdrahtet — hängt an der Build-vs-Buy-Entscheidung OP-VERTRIEB-2 |
| OP-Management (Offene-Punkte-Format + GitHub-Issues-Spiegel, Gold-Standard für drkv-Projekte — OP-DOCS-11 ✅ v1) | ops/*.md · scripts/gen-ops.mjs · scripts/sync-ops-issues.mjs · .github/workflows/sync-ops.yml · docs/konventionen/OP-Management-Gold-Standard.md | v1 auf Branch claude/op-management-gold-standard; ein Markdown-File je OP (Frontmatter) als Quelle, generierte Übersicht docs/betrieb/Offene-Punkte.md, einseitiger Spiegel nach GitHub Issues (Label op-sync) für Stakeholder-Diskussion; auf main, vollständig (OP-DOCS-11 v3, 12.07.2026): alle ~166 Alt-OPs migriert (ops/<ID>.md = alleinige Quelle, §4 = Pointer, Lastenheft §11 = fachliches Detail); Board vollständig gespiegelt (~142 offene OPs, prio:/status:/bereich:/audience:-Filter); Grooming + Diskussions-Zusammenfassung als agentgetriebene on-demand-Tasks (agents.md §6.2a); Sync skaliert (Core-List-Index + Rate-Limit-Backoff) |
| Wettbewerbsanalyse (nicht-technisch: 4-Kategorien-Landschaft, Differenzierungsmatrix, SWOT — OP-COMPETE-1) | docs/produkt/Wettbewerbsanalyse.md | Entwurf v1 (Branch claude/competitive-analysis-market-entry-vb79s4); Zahlen/Einschätzungen als Annahme markiert, zu validieren |
| Markt & Markteintritt (nicht-technisch: Marktabschätzung TAM/SAM/SOM, Beachhead, Go-to-Market-Phasen, Pricing-Hypothese — OP-MARKET-1) | docs/produkt/Markt-und-Markteintritt.md | Entwurf v1 (Branch claude/competitive-analysis-market-entry-vb79s4); alle Marktzahlen Arbeitshypothesen, mit Pilot/Verbandsstatistik zu kalibrieren |
| Sanity-Checkliste (North Star: Top‑3-Leitfragen — Auslastung · Standort phys.+Bearbeitung · nächste freie Kapazität) | docs/betrieb/Sanity-Checkliste.md | lebend, bei größeren Änderungen Status pflegen |
Besprechungs-Protokolle (Meeting-Minutes — Everything-as-Code: Index + Vorlage, eine Datei je Termin JJJJ-MM-TT-thema-slug.md; Beschlüsse zusätzlich am verbindlichen Ort spiegeln) | docs/betrieb/meetings/ (README.md · _Vorlage.md) | Struktur angelegt (0.17.1); erstes Protokoll: 2026-07-12-produktiv-launch-app-review.md (Produktiv-Launch-Fahrplan & App-Review; Beschlüsse gespiegelt in OP-VERTRIEB-3/-5/-6 · OP-PILOT-1 · OP-ORTUNG-1 · OP-ALERT-1 · OP-BRAND-2 · OP-I18N-1) |
| Konventionen für Agenten | docs/konventionen/agents.md | verbindlich für jede neue Session |
Notion-Anbindung (MCP) für Claude — eingecheckte .mcp.json (Server notion via npx @notionhq/notion-mcp-server, Token via ${NOTION_TOKEN}, kein Secret im Repo) + Setup-Doku (Claude Code lokal+Cloud, Claude Desktop; Bereichs-Freigabe least-privilege) | .mcp.json, docs/konventionen/Notion-Integration.md | Branch claude/notion-claude-code-integration-4yxtzf; Token muss als Env/Secret bereitstehen (lokal Shell export NOTION_TOKEN, Cloud Umgebungs-Secret). Kein Versions-Bump (Contributor-Tooling). |
| Datenmodell (Stammdaten = Solver-Eingabe) | server/src/model/, docs/fachlich/datamodel.md | auf main |
| Scheduler (Greedy: Angebotsmodus §5.2.2, Parkplätze, Indoor-Trocknung, Nacht-Scheduling, Mehrauftrag) | server/src/scheduler/, npm run spike | auf main |
| TS-Optimierer (globale Reihenfolge-Suche, Ziel §6.2) | server/src/solver/, npm run solve | auf main |
| Operatives Modell (Auftrag R7 + Teilschritt-Instanz, Lifecycle S-6, Reservierung §6.3) | server/src/operativ/, docs/fachlich/operativmodell.md, npm run operativ | auf main |
| Re-Planung (Eilauftrag-Verdrängung OP-R7-3) | server/src/operativ/replan.ts, npm run replan | auf main |
| CP-SAT-Solver-Service (A-5, OR-Tools, Python) | solver-service/, docs/fachlich/solver.md | auf main; Auto-Deploy auf Fly.io bei Push auf main (Pfad solver-service/**) via .github/workflows/fly-deploy.yml — strikt, Selbsttest gatet (OP-DEPLOY-1). Prod-Worker zeigt auf SOLVER_URL=https://solver-service.fly.dev (TS-Fallback bei Nichterreichbarkeit). /health+/solve liefern Version+Build-Zeit → Solver-Status-Hinweis im Cockpit (CP-SAT v… / ⚠ Fallback, OP-DEPLOY-2). |
| Persistenz + Leitstand-Anbindung (R9) | server/party/leitstand.ts + Angular | auf main, DO ruft CP-SAT mit Fallback |
| Planungs-Gantt + Auftrags-UI (R8 §5.2.1, read-only) | client/src/app/leitstand/gantt.component.ts + leitstand.component.ts | auf main; Gesamt-Gantt (MA↔Bucht, statusfarbig + Legende); Optimierungs-Vorschau (R8-G2: Diff je Auftrag früher/später + Σ/Makespan-Δ + regelbasiertes Narrativ + Anwenden/Verwerfen); Planungskonflikt-Feed + ⚡ am Auftrag (Termin-Konflikt v1); Auftrags-Karten mit relativer Fertig-Zeit („morgen 08:00“) + Mini-Gantt; abgeschlossene/archivierte Aufträge nicht im Gantt; Ausfall-Bänder (hinter den Blöcken, schraffiert) zeigen je Zeile warum eine Ressource nicht arbeitet — MA: Pause (Slot-Lücke) · Geschlossen (außerhalb Schicht) · Krank/Urlaub (rot/violett); Bucht: Wartung/Gesperrt (amber/rot). Abgeleitet aus denselben Schicht-/Abwesenheits-/Sperr-Stammdaten wie der Optimierer (server/src/scheduler/ausfall.ts, nichts gespeichert; Selbsttest npm run test:ausfall). Band-Text = konkreter Grund, Legende = Kategorie. Task-Tooltip + Detail-Fly-in (OP-R8-16): Hover über einen Block zeigt Schnell-Details (Auftrag/Schritt/Zeit, betont Termin-Konflikte mit quantifiziertem Verzug); Klick (oder Enter) öffnet ein rechts einschwebendes Detail-Panel (auftrag-detail-panel.component.ts, workspace-übergreifend geteilt) mit allen Auftrags-Details (Termine/Reserve/Standort + alle Teilschritte, der angeklickte hervorgehoben) plus einem Aktions-Hub: Lifecycle-Aktionen (erlaubteAktionen), „✦ Vorziehen vorschlagen“, „⏱ Verzögerung melden“ (Inline-Preset-Picker + Grund → meldeVerzoegerung, war bislang ohne UI), „📍 Umparken“ (globales Umpark-Modal), „Konflikt lösen →“ (/conflicts) und „Im Hofplan zeigen →“. Tooltip ersetzt den nativen title (bleibt als aria-label); im Entwurfs-/Drag-Modus ist der Block nur Zieh-Griff (kein Tooltip/Panel). „Propose-not-execute“ gewahrt (Plan-Änderungen nur als Vorschlag/expliziter Fakt). Dasselbe Panel öffnet auch aus der Fortschritts-Leiste im Aufträge-Detail (pages/orders.component.ts, Schritt anklicken → Fly-in fokussiert den Schritt). |
| Belegung / Inventur (R2, physische Ist-Belegung) | server/party/leitstand.ts + leitstand.component.ts | auf main; Auftrag „parken“ (freier Parkplatz), Belegung korrigieren (entfernen/verschieben), Doppelbelegung rot. OP-R2-2 Hallen-/Hofplan (v1): grafische Slot-Tiles gruppiert Halle/Hof, Kapazitäts-Zellen, Drag&Drop-Umparken (typLabel im BelegungSlotDTO). |
| Plan-Ist & Termintreue + Standort (R7) | server/src/operativ/auftrag.ts + leitstand.ts + leitstand.component.ts | Auftrag speichert urspruenglichePlanFertigstellung + urspruenglicheWunschAbholung (separat, nicht überschrieben) + tatsaechlicheFertigstellung (bei Abschluss = floor(Date.now()/60000)); abgeschlossene Karten zeigen tatsächliche statt geplanter Fertigstellung (+ „Plan war …“); jede Karte zeigt 📍 Standort (Slot aus Ist-Belegung). Migration backfillt Altdaten. |
| Reserve-Indikator + Kunden-Anspruch (R7/R5) | operativ/auftrag.ts + leitstand.* | Karte zeigt Reserve in Tagen (Wunsch-Abholung ↔ geplante Fertigstellung, grün/rot) + Kunden-Anspruchs-Score (anspruch 1–3, AnspruchScore). Eil-Hebel zeigt je verschobenem Auftrag, ob der Abholtermin noch einhaltbar ist. |
| Teilschritt-Tracking + Bucht-Typ-Bindung (R7/R3b) | operativ/auftrag.ts (TeilschrittStatus +in_arbeit/+pausiert, starteTeilschritt/pausiereTeilschritt) + leitstand.ts (teilschritt.aktion, TS_REQUIRED_TYPES, umparkenNoetig/instanzId im DTO) + leitstand.component.ts | Pro Schritt Status geplant→in_arbeit⇄pausiert→erledigt mit Start/Pause/Fortsetzen/Fertig; Schritt an Bucht-Typ gebunden → Start blockiert + „⚠ Umparken nötig“, wenn Fahrzeug nicht im passenden Bucht-Typ; Chronik-Einträge. |
| Bucht-Belegung nur via Auftrag/Umparken + „geparkt“-Markierung (R2/R7) | leitstand.component.ts (+ bay.toggleOccupy entfernt) | Manuelles „+ Test-Fahrzeug“ entfernt; Buchten werden nur über starten/Bucht-Wechsel/Umparken belegt. Im Hallenplan markiert „⏸ geparkt“ jedes Bucht-Fahrzeug, dessen Auftrag nicht „in Arbeit“ ist (keine produktive Nutzung, gestrichelt). KPI „Bays belegt“ aus realer Belegung. |
| Verzögerungen melden (R7, OP-R7-10) | operativ/auftrag.ts (meldeVerzoegerung, verzoegerungMin) + leitstand.ts (auftrag.verzoegerung) + leitstand.component.ts (Dialog+Badge) | „Verzögerung melden“ (Dauer-Presets + Grund) verschiebt geplante Schritte + geplante Fertigstellung; urspr. Plan bleibt (Termintreue); Chronik-Eintrag; Reserve/⚡ reagieren sofort; Badge „⏱ +X verzögert“. |
| Produktion ↔ Bucht ↔ Parken + Chronik (R7/R2) | operativ/auftrag.ts (protokoll) + leitstand.ts (auftrag.starten/buchtwechsel/parken-Modus) + leitstand.component.ts (Dialoge + Drag-Routing) | „Produktion starten“ = Fahrzeug in eine Bucht (belegt sie, Bucht-Picker/Drag&Drop); Bucht-Wechsel (Select/Drag&Drop); Parken auf Parkplatz eines laufenden Auftrags → Dialog Pausieren/Beenden + Grund (beenden=fertiggestellt, pausieren=pausiert), alles in Chronik (protokoll) je Auftrag (Karte). |
| Prozesse-Workspace — Prozess-Editor: Teilschritte + Leistungen (R3b/R3a, OP-R3-3 Editor) | server/party/leitstand.ts (buildProzessKatalog aus persistierten Teilschritten · teilschritt.setSkillAnforderung · teilschrittSkill-Methode) + server/src/operativ/prozess.ts (pure setzeSkillAnforderung, npm run test:prozess) + services/leitstand.service.ts (setProzessSkillAnforderung, DTO +teilschrittId/benoetigteSkillId) + pages/processes.component.ts (+ Route + Rail-Eintrag, Workspace-Farbe --tk-ws-processes) | Eigener Workspace „Prozesse“: je eindeutigem Teilschritt (geteilter Baustein → Edit wirkt auf alle verwendenden Leistungen) die Skill-Anforderung editierbar — geforderter Skill (Picker) · Mindest-Niveau (★1–3) · Personenzahl (Stepper), F11/F11a/F12. Schritt-Eigenschaften editierbar: Dauer · Cool-down (+indoor) · optional · parallel · mehrtägig · Bucht-Typen · Unterbrechung/Übernahme-Regel (setzeTeilschrittFelder/teilschritt.update; Bucht-Typ-Taxonomie ARBEITSPLATZ_TYPEN). Leistungen-Tab: Stammfelder (Name/Standzeit/Status) + Prozess-Komposition (Reihenfolge · Teilschritt · Abhängigkeit · Dauer-Override · +−) via setzeLeistungFelder/setzeLeistungProzess (leistung.update/leistung.setProzess). Teilschritte und Leistungen persistiert im DO (schemaVersion 10, OP-R1-1-Muster) → Edits fließen über schedulerInput hart in Eignung/Machbarkeit/Taktung (CP-SAT + TS-Scheduler). Self-Test beweist Edit→buildProblem.eligible. (Früher als read-only LeitstandState.prozesse geplant, aber nie gerendert — jetzt editierbarer Workspace.) |
| Kosten-Workspace — Infra-/Cloud-Kosten (R9, OP-COST-1 Sicht B Slice B1) | server/src/kosten/infra.ts (pure Aggregation + test:kosten) + server/party/leitstand.ts (infraKostenPosten State/schemaVersion 13 · infraKosten.*-Actions · per-Connection-Gate) + services/leitstand.service.ts + pages/costs.component.ts (+ Route /costs + Nav, Farbe --tk-ws-costs) | Owner/Betreiber-only Workspace „Kosten“ (gegated über kostenAdmin; Nicht-Berechtigte sehen ihn nicht und erhalten keine Kosten-Daten). Tab Infra gebaut: manuell erfasste Posten (Dienst×Monat, Cent) → abgeleitete (D-2) KPI · Spend je Dienst · Monats-Trend · größte Posten + CRUD-Erfassung (Mono, nur --tk-*); Tab Betrieb (Sicht A) vorgemerkt. Gate (kein Leak) — seit v0.156.0 rollenbasiert: der DO filtert die Infra-Kosten je Verbindung über die Fähigkeit kosten der im Menü gewählten Rolle (Buchhaltung/Inhaber-Chef; capsAusRolle, ?rolle=-Query) — die frühere KOSTEN_ADMIN_EMAILS-Allowlist ist entfernt; Access bleibt Netz-Gate + Audit-Actor. Mehrwährung → ungewichtete Summe + Hinweis (FX = OP-I18N-1). Self-Test test:kosten (+ CI). |
| Eingriffsregeln am Preemption-Hebel (R3b F15/F16, OP-R3-3 server-seitig) | server/src/operativ/preemption.ts (preemptionHinweis/preemptionUnterbrechungsRang, npm run test:preemption) + server/party/leitstand.ts (Hebel-Reihung + HebelDTO.warnung) + services/leitstand.service.ts + pages/conflicts.component.ts | Am manuellen Konflikt-/Preemption-Hebel: unterbrechung: vermeiden wird „erlaubt vor vermeiden“ gereiht + trägt einen ⚠-Soft-Hinweis; uebernahme verboten/vermeiden als Hinweis sichtbar (das Resume behält die Crew → verboten gewahrt). verboten-Unterbrechung bleibt ganz aus der Kandidatenliste (istUnterbrechbar). Server-seitig, kein Solver-Redeploy — der Optimierer splittet/preemptet Schritte nicht, also nichts im CP-SAT zu pönalisieren (integrierte Pönale = Zukunfts-Option erst bei Step-Splitting). |
| Auftrags-Lifecycle (S-6, 3 Phasen) (R7) | operativ/auftrag.ts (Status/Transitions) + leitstand.ts (Migration/Auto-Archiv) + leitstand.component.ts/gantt.component.ts (Badges/Farben/FAQ) + docs/fachlich/Lastenheft.md §5.1 (Mermaid) | geplant→angeliefert→in_arbeit⇄pausiert→fertiggestellt→abgeschlossen→kontrolliert→archiviert; Auto-Archiv 7 Tage; schemaVersion-Migration; UI-FAQ/Howto-Panel + Status-Diagramm. Zuweisungs-Invariante (R7): „ohne Zuweisung kein in_arbeit“ — transition lässt starten/fortsetzen (Ziel in_arbeit) nur zu, wenn ≥1 produktiver Mitarbeiter an einem (Nicht-Annahme-)Teilschritt zugeteilt ist (hatZuweisung; Helfer zählen nicht). erlaubteAktionen(status, auftrag?) blendet die Start-Aktion ohne Zuweisung aus; DTO hatZuweisung; UI-Badge „⚠ Zuweisung nötig“ (Orders/Detail-Panel/Belegungs-Wareneingang, „▶ Aufbereiten starten“ deaktiviert). Self-Test in npm run operativ. |
| Reserve-Optimierungskriterium (§6.2) | solver/problem.ts (deadline+wertigkeit je Order) + solver-service/model.py (Zielterme) + scheduler/multi.ts (Fallback-Ordering) | CP-SAT-Ziel += w_tight·Σtight (Aufträge mit <1 Tag Reserve) + Σ wertigkeit·shortfall (Reserve-Defizit ggü. 2-Tage-Ziel, gewichtet mit max(Güteklasse,Anspruch)). model.py-Self-Test: höherwertiger Auftrag wird vorgezogen. |
| Skill-Niveau / Vertrauensstufe / Güteklasse (R1/R3b/R7) | server/src/model/{types,seed}.ts + scheduler/schedule.ts + solver/problem.ts + solver-service/model.py + operativ/auftrag.ts + leitstand.* | Mitarbeiter-Skills mit Niveau 1–3 (MitarbeiterSkill) + Vertrauensstufe 1–3; Teilschritt mindestSkillNiveau; Auftrag/Fahrzeug gueteklasse 1–3. Harte Regel: Skill ≥ gefordertem Niveau und vertrauensstufe >= gueteklasse — identisch in TS-Scheduler & CP-SAT (vorab aufgelöste eligible je Schritt). Seed: Super-Premium-Leistung (Folie Niveau 3). UI: ★-Badge je Auftrag + „Super-Premium“-Demo-Button. |
| Mitarbeiter-Stammpflege (CRUD) (R1) | server/party/leitstand.ts (employee.create/update/addSkill/editSkill/removeSkill) + services/leitstand.service.ts + pages/staff.component.ts | Mitarbeiter-Seite: + Mitarbeiter (Anlegen-Dialog: Name/Rolle/Skills) und ✎ Bearbeiten je Karte (Name/Rolle/Status + Skills add/edit/remove live). Server vergibt kollisionsfreie ID, trimmt/dedupliziert Skills, persistiert im DO-Blob (Broadcast an alle). Pflegt das anzeige-/Empfehlungs-Modell Employee; die solver-seitigen Mitarbeiter-Stammdaten (Niveau/Vertrauensstufe) bleiben Seed-basiert (künftige Zusammenführung offen). Skill-Katalog (gleiche Seite, skill.create/skill.update): Skills anlegen · umbenennen · (de)aktivieren + Beschreibung (F02) editierbar (end-to-end inkl. SkillDTO, #174) — Deaktivieren statt Löschen. |
| Abwesenheiten/Soft-Blocks + Schicht-Art (R1-S2/S3) | server/src/model/{types,seed}.ts · server/src/scheduler/{availability,ausfall}.ts (+ausfall-demo) · server/party/leitstand.ts · services/leitstand.service.ts · pages/staff.component.ts · gantt.component.ts · docs/fachlich/Lastenheft.md §4.4/§4.4a | Erfassung + Sichtbarkeit (Solver-Pönale = OP-OPT-7): Abwesenheits-Editor neu — Härtegrad (feste Abwesenheit Urlaub/Krank ↔ Wunschfrei/Soft-Block) × Reichweite (ganzer Tag ↔ bestimmte Schichten) mit Von/Bis-Datum. Harte Abwesenheiten reduzieren die Verfügbarkeit schicht-granular (abwesenheitIntervalle); Soft-Blocks reduzieren nicht, erscheinen als eigenes „Wunschfrei“-Gantt-Band (cyan). Schicht-Katalog trägt Art regulaer/standard/ueberlauf (Bereitschaft, Badge in der Schicht-Zuweisung); Seed mit Beispiel-Bereitschaftsschicht + Soft-Block. Self-Test npm run test:ausfall (Schicht-granular + Wunschfrei) in CI. Erfüllt OP-R8-11 (Mitarbeiter-Teil). |
| Mitarbeiter-Leistung & Erfahrung + Ausbildung (Helfer) + QS-Mangel (R1/R7/§4.9.1, OP-R1-2/OP-QS-1) | server/src/operativ/leistung.ts (+leistung-demo.ts, npm run test:leistung) · operativ/auftrag.ts (helferIds, tatsaechlichStart/Ende, maengel, setzeHelfer, Zeit-Stempel) · server/party/leitstand.ts (teilschritt.setHelfer/qs.mangelErfassen, Leistungsnachweise, toEmployeeDTO-Statistik/XP, Demo-Historie) · services/leitstand.service.ts · pages/{staff,orders,quality}.component.ts | Fakten: je Schritt-Abschluss ein Leistungsnachweis (Auftrag/Teilschritt/Skill, produktiv vs. Helfer, Vorgabe- vs. Ist-Dauer) + Mangel am Auftrag (Bezug=Teilschritt → Skill+MA, Kategorie/Schwere, Nacharbeit-Aufwand min). Abgeleitet (nie gespeichert): Karte zeigt ⚡ Erfahrungspunkte + Statistik je Schritt/Skill (Anzahl, Helfer-Anteil, Dauer min/avg/median/max, Ø-Abweichung Vorgabe, Nacharbeit-Quote+Ø-Aufwand, Bewertung 0–100). XP: güteklassen-gewichtet (schwerere Fahrzeuge zählen mehr) · Helfer anteilig bei Unterbrechung/Verspätung (lernanteil, TeilschrittInstanz.unterbrochen). Niveau-Aufstieg-Vorschlag (niveauVorschlaege): genug fehlerarme Praxis → „Niveau anheben“ auf der Karte. Ausbildung: Helfer je Schritt — reduzieren die Zeit nicht (nicht im Solver), sammeln aber Erfahrung. Ausbildungsziele (ausbildungsZiele) → Helfer-Vorschläge (ausbildungsVorschlaege, frei × passender offener Schritt; Verfügbarkeit zur Schritt-Zeit hart via mitarbeiterAvailability); penaltyfreies Abziehen (G-2-Ausnahme). QS erfasst Mängel (Bezug+Aufwand). Prozessdefinition: Teilschritt.unterbrechung/uebernahme (erlaubt/vermeiden/verboten, §4.6 F15/F16; verboten-Unterbrechung wirkt hart auf Preemption). Offen: Foto-Doku am Mangel (M05) + „behoben“-Workflow (OP-QS-1) · Team-/Zeitraum-Vergleich, niveau-gewichtete XP (OP-R1-2) · Eingriffsregeln vermeiden/uebernahme seit #178 server-seitig am Preemption-Hebel durchgesetzt → OP-R3-3 server-seitig abgeschlossen (Editor + Eingriffsregeln, eigene Zeilen); CP-SAT-integrierte Pönale offen (erst bei Step-Splitting). |
| Konflikt-Lösen-Wizard (R8 §5.2.3, OP-R8-2/3) | server/party/leitstand.ts (konfliktHebel/loeseKonflikt) + schedule.ts/problem.ts (skipTeilschrittIds) + leitstand.component.ts | „Konflikt lösen“ pro Konflikt → volle Hebel-Liste aus der Prozess-Definition mit berechneter Auswirkung: Wunsch-Abholtermin anpassen · optionalen Schritt überspringen (Skip-Propagation durch Scheduler+CP-SAT, applyPlanung übersprungen-robust) · als Eilauftrag priorisieren (zeigt konkret welche Aufträge verschoben werden: Nr., vorher→nachher, Verzögerung) · Engpass-Hinweis (Skill mit ≤1 Halter). |
| Zugangsschutz (Cloudflare Access, Zero Trust) | edge-seitig + §6.4 + optionales JWT-Check im Worker | auf main; Client-Soft-Gate entfernt |
| CI (server: typecheck/spike/operativ/replan/solve · client: build · solver-service: CP-SAT-Selbsttest) | .github/workflows/ci.yml | auf main, Node 22 |
| Live-Leitstand-Prototyp (PartyServer + Angular) | server/party/ + client/ | lauffähig lokal, deployt via Wrangler |
Doku-Site (Docusaurus, rendert docs/ + HANDOFF/README inkl. Mermaid) | docs-site/ (Build+Deploy: npm run build && npm run deploy) | live auf https://docs.taktano.com (Cloudflare Pages taktano-docs, Custom-Domain aktiv + TLS), via Access geschützt; Build warnungsfrei. Offen nur noch: Auto-Deploy bei Push → OP-DOCS-1 (§4) |
| Doku-Navigation / Findability-Layer (Frontmatter-Lesereihenfolge · Kategorie-Index · Glossar · ID-/OP-Index · Lesepfade · Drift-Checks) | alle docs/**-Frontmatter, docs/konventionen/{Glossar,IDs}.md, docs/*/_category_.json, docs/README.md, docs/konventionen/agents.md §2.1, scripts/check-doc-consistency.sh, docs-site/docusaurus.config.js | Branch claude/docs-navigation-structure-wf696m (PR folgt). sidebar_position (10er-Schritte) gibt jeder Kategorie eine sinnvolle Lesereihenfolge; generated-index je Kategorie; Glossar (Begriff → Definition, Master Lastenheft §13) + ID-/OP-Index (OP → Owning-Doc; volle Liste = §4 hier); Lesepfade nach Aufgabe in der Landkarte; check-doc-consistency.sh prüft jetzt Landkarte-Vollständigkeit/Frontmatter/_category_.json (warnt). Entscheidung: keine Datei-Renames (Label statt Umbenennen), Lastenheft nicht gesplittet. Folge-Commit: Doku-Site rendert eine Staging-Kopie (docs-site/prepare-content.mjs statt copy-projekt, gitignored) und schreibt Cross-Instance-Links resolve-basiert auf Site-Routen um → Build ohne Broken-Link-Warnungen (7→0); CHANGELOG/CLAUDE jetzt auch auf der Site. |
Doku-Landkarte + Unterordner-Struktur (docs/ gegliedert) | docs/README.md + docs/{fachlich,architektur,betrieb,konventionen,produkt}/ | auf main (PR #205 gemergt 06-27); alle 17 Docs per git mv in 5 thematische Unterordner (je _category_.json → Docusaurus-Sidebar gruppiert) + docs/README.md als Index (GitHub-Browse und Site-Startseite); alle klickbaren Links (49) + aktiven docs/<name>.md-Pfade in HANDOFF/CLAUDE/README/design//Code nachgezogen, append-only Logs unverändert. Docusaurus-Build live verifiziert (docs-deploy #75 grün) → OP-DOCS-8 (§4) |
| Doku-Site Start-Seite (Produkt-Übersicht) + Team-Seite | docs-site/src/pages/{index,team}.js · docusaurus.config.js (Navbar) · static/img/team/ | auf Branch claude/docs-startseite-produktuebersicht; Start-Seite kurze Produkt-Übersicht (Positionierung · Herzstück Taktung-Optimierung · True-North-Leitfragen · Werthebel) + Reorg-Link-Regression gefixt; neue Team-Seite (Navbar „Team“) mit Rollen/Schwerpunkten + Portrait-Avataren (Platzhalter, foto-Slot static/img/team/) + To-dos (Rollen/Titel schärfen · Fotos · Name ergänzen). npm run build grün verifiziert |
| Doku-Site Start-Seite (Produkt-Übersicht) + Team-Seite | docs-site/src/pages/{index,team}.js · docusaurus.config.js (Navbar) · static/img/team/ | auf main (PR #206 gemergt 06-27); Start-Seite kurze Produkt-Übersicht (Positionierung · Herzstück Taktung-Optimierung · True-North-Leitfragen · Werthebel) + Reorg-Link-Regression gefixt; neue Team-Seite (Navbar „Team“) mit Rollen/Schwerpunkten + Portrait-Avataren (Platzhalter, foto-Slot static/img/team/) + To-dos (Rollen/Titel schärfen · Fotos · Name ergänzen). npm run build grün + docs-deploy verifiziert. Offen (To-dos auf der Team-Seite): echte Portrait-Fotos nach docs-site/static/img/team/ + foto-Feld setzen · Name des Mitarbeiters von Dominik · Rollen/Titel final schärfen |
| Glossar + Begriffs-Sprechblasen + Lesepfade nach Zielgruppe (OP-DOCS-10 neu; OP-DOCS-4 Schritt 1) | docs-site/src/glossar/glossar.mjs (Quelle, 50 Begriffe inkl. CP-SAT) · docs-site/scripts/gen-glossar.mjs → docs/glossar/Glossar.md (generiert, npm run glossar/prebuild) · docs-site/src/remark/glossarTooltips.mjs (Remark, beide Docs-Instanzen) · docs-site/src/clientModules/glossarTooltip.js + src/css/custom.css · docs/zielgruppen/Lesepfade.md | auf Branch claude/cp-sat-glossary-docs-myrvyv (PR folgt). Eine Quelle, drei Verbraucher: strukturierte Begriffe (kurz/zielgruppen/siehe) speisen (1) die generierte Glossar-Seite, (2) das Remark-Plugin, das je Doku-Seite die erste Fundstelle jedes Begriffs mit <span class="tk-term"> umschließt (überspringt Headings/Links/Code/Glossar-Seite, Wortgrenzen, Longest-Match), und (3) das Client-Modul, das bei Mouse-over und Klick die Kurz-Erklärung + „Im Glossar öffnen →“ zeigt (tastatur-zugänglich). Lesepfade als nicht-invasiver Überbau: vier Zielgruppen-Pfade (Anwender · Fach/Management · IT-Arch&Dev · IT-Operations), verlinkt nur bestehende Docs. Verifiziert: npm run build grün, Sprechblasen in 21 Seiten (CP-SAT auf 8). Doku-Site-only → kein App-Version-/Build-Bump (Präzedenz #205/#206). Offen: echte Ordner-/Login-Trennung Anwender↔intern = OP-DOCS-4/-5; optionales CI-Staleness-Gate für die generierte .md. |
| In-App-Assistent — Chatbot + Feedback (OP-AI-4 / OP-DOCS-2/-7) | server/src/assistant/* (retrieval · llm · tools · handler · feedback · doku-index.generated + 3 Demos) · server/party/leitstand.ts (onRequest /assistant, dormant-guarded) · client/.../{chat.service,feedback-pin.service,chat-panel.component,feedback-pin-overlay.component} · docs/architektur/In-App-Assistent.md | Slices 1–3 (Insights read-only, 06-22) + Slices 4–6 (07-01): LLM-Tool-Calling-Endpoint (7 Werkzeuge auf Insights/konfliktHebel-Simulation/Doku-RAG), Feedback→GitHub-Issue (+Audit assistent.feedback), Angular-Panel (Drawer) + Element-Feedback-Pin. Entscheidungen (07-01): EU-LLM · RAG (Vectorize + Keyword-Fallback) · Issue-Ablage · App-first. Dormant ohne ASSISTENT_LLM_KEY (503). Self-Tests test:assistant-retrieval|-tools|-feedback (CI); v0.41.0. RAG aktiviert (07-02, v0.51.0, Nutzer „Implement RAG“ — überstimmt die zunächst beschlossene kriteriengebundene Zurückstellung): scripts/push-doku-index.mjs (npm run doku-index:push) = Index-Self-Provisioning (taktano-doku, 1024/cosine) + mistral-embed-Batch-Embedding + NDJSON-Upsert; [[vectorize]]-Binding DOKU_INDEX aktiv; CI deploy pusht VOR wrangler deploy, docs-deploy re-indext Doku-only (OP-DOCS-1 d); dormant-sicher, Laufzeit-Ausfall → Keyword-Fallback; Residenz: RISK-17 + C-19 (Vectorize ohne EU-Jurisdiktion, kein PII im Index). Detail In-App-Assistent.md §8.1/§9. Doku-Widget gebaut (07-02, Slice 11) + Fix (07-03, v0.53.1, Slice 12): das Widget scheiterte produktiv an Cloudflare Access vor app.taktano.com (Preflight/Cookie → Login-Redirect → „Server nicht erreichbar“); jetzt Same-Origin-Proxy docs-site/functions/parties/[[pfad]].js + Service-Binding APP_WORKER (docs-site/wrangler.toml) — kein CORS/zweites Access-Cookie, Doku-Frontend-Erkennung (Origin-Header) + eng begrenzte Endpunkte bleiben. Feedback-Übersicht (07-03, v0.54.0, Slice 13): GET /feedback/liste (read-only, offen+geschlossen) → App-Formular-Sektion „Bisheriges Feedback“ + Doku-Widget-Tab „Issues“. Markdown-Rendering + Issue-Tooltip (07-03, v0.57.0, Slice 15): Widget rendert Assistent-Antworten als Markdown (mdHtml, escaped, Link-Allowlist); Issue-Liste mit Detail-Tooltip inkl. Screenshot-/Bild-Vorschau (details/bilder am FeedbackIssue) in Doku + App. „🗂 Issues“-Umschalter im App-Assistent-Panel (Liste direkt im Chat-Drawer; gemeinsame Komponente feedback-issues-liste.component.ts mit dem Formular). Offen (Folge-PR): externe Doku-Sicht (OP-DOCS-5) · WS-Streaming · Docs-AUD, sobald Worker-JWT-Prüfung scharf (OP-COST-3). Details: OP-AI-4 (§4). |
| In-App-Assistent — Chatbot + Feedback (OP-AI-4 / OP-DOCS-2/-7) | server/src/assistant/* (retrieval · llm · tools · handler · feedback · doku-index.generated + 3 Demos) · server/party/leitstand.ts (onRequest /assistant, dormant-guarded) · client/.../{chat.service,feedback-pin.service,chat-panel.component,feedback-pin-overlay.component} · docs/architektur/In-App-Assistent.md | Slices 1–3 (Insights read-only, 06-22) + Slices 4–6 (07-01): LLM-Tool-Calling-Endpoint (7 Werkzeuge auf Insights/konfliktHebel-Simulation/Doku-RAG), Feedback→GitHub-Issue (+Audit assistent.feedback), Angular-Panel (Drawer) + Element-Feedback-Pin. Entscheidungen (07-01): EU-LLM · RAG (Vectorize + Keyword-Fallback) · Issue-Ablage · App-first. Dormant ohne ASSISTENT_LLM_KEY (503). Self-Tests test:assistant-retrieval|-tools|-feedback (CI); v0.41.0. RAG aktiviert (07-02, v0.51.0, Nutzer „Implement RAG“ — überstimmt die zunächst beschlossene kriteriengebundene Zurückstellung): scripts/push-doku-index.mjs (npm run doku-index:push) = Index-Self-Provisioning (taktano-doku, 1024/cosine) + mistral-embed-Batch-Embedding + NDJSON-Upsert; [[vectorize]]-Binding DOKU_INDEX aktiv; CI deploy pusht VOR wrangler deploy, docs-deploy re-indext Doku-only (OP-DOCS-1 d); dormant-sicher, Laufzeit-Ausfall → Keyword-Fallback; Residenz: RISK-17 + C-19 (Vectorize ohne EU-Jurisdiktion, kein PII im Index). Detail In-App-Assistent.md §8.1/§9. Doku-Widget gebaut (07-02, Slice 11) + Fix (07-03, v0.53.1, Slice 12): das Widget scheiterte produktiv an Cloudflare Access vor app.taktano.com (Preflight/Cookie → Login-Redirect → „Server nicht erreichbar“); jetzt Same-Origin-Proxy docs-site/functions/parties/[[pfad]].js + Service-Binding APP_WORKER (docs-site/wrangler.toml) — kein CORS/zweites Access-Cookie, Doku-Frontend-Erkennung (Origin-Header) + eng begrenzte Endpunkte bleiben. Feedback-Übersicht (07-03, v0.54.0, Slice 13): GET /feedback/liste (read-only, offen+geschlossen) → Doku-Widget-Tab „Issues“. Feedback-UX-Umbau (07-03, v0.55.0, Slice 14): Ein-Schritt-Screenshot (Editor-Overlay, Pin erfasst Element automatisch) + Feedback-Overlay in App (Element-Marker/Seiten-Chip) & Doku (Navbar-Toggle + Seiten-Chip) statt Dialog-Liste; globaler Toggle wie Light/Dark. Offen (Folge-PR): externe Doku-Sicht (OP-DOCS-5) · WS-Streaming · Docs-AUD, sobald Worker-JWT-Prüfung scharf (OP-COST-3). Details: OP-AI-4 (§4). |
| Werkstatt-Tafel — durchgängige Auftragszeile (OP-UX-1 / U1) | client/src/app/leitstand/pages/tafel.component.ts (+ Route /tafel + Nav „Tafel“, Cluster Überblick, Farbe --tk-ws-tafel) · design/tokens/tokens.json (+ --tk-ws-tafel) | auf Branch; eigener Workspace „Tafel“: je aktivem Auftrag eine Zeile mit Status · Phase · aktuellem Schritt (wer · Bucht) · 📍 Standort · Fortschritt · Reserve · Warn-Flags. Reine Projektion des Live-States (kein neues Schema, S-2); dringlichkeits-sortiert; Klick → geteiltes Detail-Panel. Beantwortet True-North-Frage 2 (Standort phys.+Bearbeitung) auf einen Blick. |
| Werker-Sicht „Meine Arbeit“ (OP-UX-1 / U2) | client/src/app/leitstand/pages/meine-arbeit.component.ts (+ Route /meine-arbeit + Nav, Cluster Operativ, Farbe --tk-ws-werker) · design/tokens/tokens.json (+ --tk-ws-werker) | auf Branch; eigener touch-Workspace: Mitarbeiter-Picker (Schichtterminal, kein Login nötig) → nur seine offenen/laufenden Schritte (produktiv + 🎓 Helfer); große Aktionen ⏸ Pause / ▶ Weiter / ✓ Fertig (über teilschrittAktion); Doku-/Foto-Pflicht via geteiltes Detail-Panel (kein zweites Gate). Reine Projektion (kein Schema/Server/Solver). |
| Annahme — „Auto kommt → Auftrag anlegen“ (OP-UX-1 / U3) | client/src/app/leitstand/pages/annahme.component.ts (+ Route /annahme + Nav, Cluster Operativ erster Eintrag, Farbe --tk-ws-annahme) · server/src/operativ/auftrag.ts + server/party/leitstand.ts (Kunde v1 {name, crmLink?} am Auftrag) · design/tokens/tokens.json (+ --tk-ws-annahme) | auf Branch; Vordertür des Flows (ersetzt die Demo-Buttons): Formular Kunde (Name + CRM-Link, R5-v1) · Leistung · Güteklasse/Anspruch · Anlieferung + Wunsch-Abholung · Termin-Härte → auftrag.create (Machbarkeitsprüfung Angebotsmodus). Kunde v1 neu im Datenmodell (war spezifiziert, nicht gebaut; optional, keine Migration). |
| Annahme — Termin-Vorschlag (frühestmögliche Abholung) + Sonderwünsche (OP-UX-1 / U9, R7-F10) | client/src/app/leitstand/pages/annahme.component.ts · client/src/app/leitstand/pages/orders.component.ts (Sonderwünsche-Karte) · client/src/app/util/time.ts (minToInput/nowInput) · server/party/leitstand.ts (auftrag.terminvorschlag + .result, auftrag.create.sonderwuensche) · server/src/operativ/auftrag.ts (Auftrag.sonderwuensche) | auf Branch claude/pickup-date-special-requests-6hrlnc (v0.58.0, 07-03, PR folgt); die Annahme bietet den frühestmöglichen Abholtermin basierend auf der gewählten Leistung direkt an (TS-Scheduler-Dry-Run scheduleLeistung(...).abholbereit inkl. Standzeit; leeres/auto-befülltes Feld wird vorbefüllt, Hand-Wert bleibt + „Übernehmen“); Sonderwünsche (R7-F10) als optionales Freitext-Feld → Auftrag.sonderwuensche (additiv, keine Migration) → Bestätigungs-Dialog + Aufträge-Detail. Detail: docs/architektur/Operative-Durchgaengigkeit.md §U9 |
Einheitliche Leere-Zustände (app-empty-state, Flow-Audit-Folge / OP-UX-1-Backlog) | client/src/app/leitstand/empty-state.component.ts (neu) + ~12 Workspaces migriert · design/COMPONENTS.md (## Empty state) | auf Branch; eine wiederverwendbare Komponente ersetzt die zuvor 25 ad-hoc „Keine …“-Platzhalter. 3 Varianten: card (Voll-Raum, dashed=wartet), bare (in bestehender Karte), inline (verschachtelte Unterliste); optionaler CTA-Slot (<ng-content>). CTAs ergänzt, wo der Flow es trägt (Tafel/Aufträge leer → „+ Auftrag annehmen“ → /annahme, Überblick „keine Produktion“ → /annahme, Vorschläge → /planning, Annahme ohne Leistung → /processes). Nur --tk-*-Tokens. |
| Nächste-Aufgaben-Queues + Auto-Re-Opt (OP-OPT-9) | client/src/app/leitstand/naechste-aufgaben.component.ts (+ Einbettung pages/planning.component.ts) · server/src/operativ/autoopt.ts (+ autoopt-demo.ts, npm run test:autoopt) · server/party/leitstand.ts (aktualisiereVorschlaegeAuto) | auf Branch claude/planning-queue-optimization-iniw7z (v0.59.0, PR folgt); (1) priorisierte „Nächste Aufgaben“-Queue je Mitarbeiter/Arbeitsplatz in der Planung — reine Projektion des Plans (S-2): läuft jetzt ▸ / pausiert ⏸ / als Nächstes 1…n, je Ressource „frei ab“/„jetzt frei“ (True North 3), Klick → geteiltes Detail-Panel; (2) Event-Re-Opt wendet terminneutrale Pareto-Verbesserungen (keiner später, ≥1 früher — autoAnwendbar) automatisch an (Chronik je Auftrag + Audit plan.auto); Trade-offs bleiben Vorschlag („Vorschlag statt Zwang“). Entscheidung: Architektur bleibt globaler Plan, Queues sind seine Ressourcen-Projektion (keine lokalen Dispatch-Queues). (3) „Meine Arbeit“ = persönliche Queue in Plan-Reihenfolge (geplante nach Optimierer-Startzeit statt Auftragsnummer, Positions-Badge 1…n, „ab autoOptAktiv, Default an; Toggle in der Planung-Toolbar, Audit plan.autoopt.konfiguriert) + Broadcast plan.autoAngewendet → Toast an alle Verbindungen bei Auto-Anwendung (Queue springt nicht mehr kommentarlos). (5, v0.61.0) Tafel-Zeile zeigt „→ als Nächstes: queueVergleich-Helfer). |
| v3-Kern-Loop-Redesign (Claude-Design-Handoff) + Ein-Satz-Annahme „Takt-Kommando“ (OP-UX-4) | design/prototype/ (v3-Prototyp + HANDOFF-Kernloop-Slice1.md + Screenshots) · client/src/app/leitstand/shell.component.ts + pages/{annahme,overview,orders,conflicts,recommendations,staff,quality}.component.ts · client/src/app/util/annahme-parse.ts · server/src/annahme/parse.ts (+parse-demo.ts, npm run test:annahme-parse) · server/party/leitstand.ts (/annahme/parse-Endpoint · auftrag.pruefen +startMin/slotName · AuftragDTO.leistungIds · qs.mangelErfassen +sofortBehoben) · design/WORKSPACES.md | gemergt (#397 ff., v0.62.0–0.65.0, 07-04); alle 8 Kern-Workspaces nach v3-Prototyp mit echten Daten: Shell (Kern-Loop+Weitere-Nav, Badge-Farben je Kontext) · Annahme = Ein-Satz-Intake (Heuristik live + LLM-Verfeinerung [dormant-fähig], Machbarkeits-Panel = echter Dry-Run mit Slot/Reserve/Preis, ein Klick) · Überblick = Hof-Radar (Ist-Belegung, Avatare aus dem Plan, ehrlich beschriftet; ?fokus=/?mitarbeiter=-Cross-Links) · Aufträge Fluss/Risiko + Vollbreiten-Detail · Konflikte & Klärfälle als Tabs (/klaerfaelle→Redirect, Pixel-Dissolve) · Vorschläge-Karten-Feed · Mitarbeiter-Karten (Aktionen + 📍 Radar) · Qualität mit Zwei-Wege-Nacharbeit (QS-Fix mit Pflicht-Kommentar + Aufwand-Chips bucht via sofortBehoben auf den Auftrag; Nacharbeit→Produktion = OP-QS-4). Planung war bereits v3-konform (Detail-Strip bewusst = geteiltes Fly-in OP-R8-16). Nachschärfungen (gleicher Branch): Dauer-Parsing + Quellen-Anzeige (v0.63.0, #398) · Kunde/CRM-Nachtrag im geteilten Detail-Panel (v0.64.0, #399) · Alternativen statt Sackgasse + „⚠ Trotzdem annehmen“ (→ Klärfall) + Leistungs-Schnellauswahl + Kunden-Lookup mit Auto-CRM-Link (v0.65.0, Details §4 OP-UX-4). Offen (OP-UX-4-Rest): LLM-Parse-Qualität mit echtem Key verproben · Out-of-Scope Slice 2+ laut Handoff (Cluster-Crystal-Bar, Tablet-Layouts). |
| Trennung Auftragsannahme / Fahrzeugannahme (Check-in) (OP-UX-5) | server/src/operativ/auftrag.ts (fahrzeugAnnahme) · server/party/leitstand.ts (auftrag.checkin + .result, DTO +bringtermin) · client/src/app/leitstand/pages/annahme.component.ts (Tabs „⌨ Auftrag anlegen“ / „🚗 Fahrzeug da“) · server/src/operativ/demo.ts (Selbsttest) | auf Branch (v0.66.0, 07-04, PR folgt); Annahme-Workspace mit zwei Modi: Buchung (Ein-Satz-Intake, Fahrzeug muss nicht da sein) getrennt vom Check-in bei Ankunft — Liste erwarteter Anlieferungen (überfällige markiert) → Pflicht-Zustandskommentar (Car-Check) erledigt den Standard-Annahme-Schritt und stellt atomar auf „angeliefert“ (Ist-Stempel, harte Reservierung). Details §4 OP-UX-5. |
| Überfällige Anlieferung = Klärfall + Auftragsstorno (OP-UX-6) | server/src/operativ/auftrag.ts (stornieren) · server/party/leitstand.ts (auftrag.stornieren + .result) · client/src/app/services/leitstand.service.ts (ueberfaelligeAnlieferung, stornoAuftrag) · client/src/app/leitstand/pages/conflicts.component.ts (Sektion + Storno-UI) · server/src/operativ/demo.ts (Selbsttest) | auf Branch (v0.67.0, 07-04, PR folgt); überfällige Anlieferungen erscheinen abgeleitet (kein State, D-2) im Klärfälle-Workspace, plus Auftragsstorno mit Pflicht-Grund (nutzt abbrechen→abgebrochen). Details §4 OP-UX-6. |
| Diese HANDOFF.md | repo-root | gerade gelesen |
3. Wichtige Entscheidungen (alle Lastenheft-IDs)
Globale Prinzipien
- G-1 Alle taxonomie-artigen Enums sind admin-editierbar. Logik-tragende Enums (z. B. Abhängigkeit
Nach vorherigem / Parallel / Frei) bleiben fix. - G-2 Scheduler rechnet 5 Min Pönale bei Mitarbeiter-Kontextwechsel (konfigurierbar).
- G-3 Auto-Scheduler plant keine Arbeit in Fenster < 15 Min.
Module — fachliche Festlegungen
- R1 Mitarbeiter: Personal-Nr. auto-generiert. Status manuell setzbar (Admin + Self). Skills sind first-class Stammdaten (siehe unten), free-text Qualifikationen entfallen. Urlaubstage/Überstunden/Krankheitstage = derived. Arbeitszeiten als Referenzen auf einen unternehmensweiten Schicht-Katalog. Mitarbeiter-QR = Login-Alternative zu User/Pass. Zwei Notiz-Sichtbarkeiten: Manager-only und Nachricht an Mitarbeiter.
- R2 Arbeitsplätze: Typ und Ausstattung beide admin-erweiterbar. Live-Status (Frei/Belegt/Überbucht/Gesperrt) derived aus Auftrag-Zuweisungen + Sperren + Config-Status. Sperre = Zeitraum-Blockierung (Beginn, Ende, Grund-Enum, Beschreibung).
- R3 Leistungen & Prozesse: Standzeit in Stunden (nicht Werktage). Teilschritte haben Cool-down/Settle-Time in Minuten (Bay belegt, kein Mitarbeiter). Skill ist eigene erste-Klasse-Entität; ein Teilschritt fordert genau einen Skill + Personenanzahl (N Personen mit diesem Skill) und läuft nur in einer Bucht, die den Skill anbietet (Arbeitsplatz-Skills). Abhängigkeit bezieht sich auf alle vorherigen Schritte.
- R4 Formulare: Feldtypen fix (Checkbox, Kurz-/Langtext, Zahl, Auswahl, Foto-Upload, Unterschrift). Auswahl-Options admin-managed je Feld. Unterschrift mit konfigurierbarer Signer-Rolle (Kunde oder Mitarbeiter). Protokolle nach Submit unveränderlich, statischer Snapshot. Version = reiner Zähler, kein echtes Versioning.
- Datenmodell-Definition v1 (verbindlich, Lastenheft §4.9): Für jedes Fahrzeug (= was ein Kunde bringt) besteht immer ein Auftrag; das Fahrzeug ist kein eigenständiges Datenobjekt, sondern wird am Auftrag und nur während des Auftrags getrackt. Kunde = nur Name + CRM-Link am Auftrag (Verwaltung extern). R5/R6-Vollmodelle unten sind Future; FR-1, OP-R6-1 und der Fahrzeug-Teil von OP-R7-11 dadurch für v1 gegenstandslos.
- R5 Kunden (Future-Vollmodell; v1 = nur Name + CRM-Link): Status-Enum Aktiv/Blockiert/Archiviert. Tabs filtern nach Auftragsstatus, nicht Kundenstatus. PRIVAT + B2B als eine Entität mit Variantenfeldern (B2B: Firmenname, Abweichende Rechnungsadresse → +USt-IdNr). Anlegen + Bearbeiten = einheitliches Single-Modal (kein Wizard).
- R6 Fahrzeuge (Future-Vollmodell; v1 = Attribute am Auftrag): Status und Standort beide derived aus aktuellem Auftrag. Single-Modal. Mangel mit Kategorie/Schwere/Status (Offen/Behoben). Dokumente sind generisches Attachment-Modell mit Dokumenttyp + polymorpher Ziel-Referenz (Auftrag/Fahrzeug/Kunde). Fahrzeug-Besitzerwechsel = Future Release (FR-1).
- R7 Aufträge (Lifecycle S-6, 3 Phasen Anlieferung·Produktion·Abholung): Status-Enum geplant → angeliefert → in_arbeit ⇄ pausiert → fertiggestellt → abgeschlossen → kontrolliert → archiviert (Aktionen: liefern/starten/pausieren/fortsetzen/fertigstellen/abholen/kontrollieren/archivieren). Reservierung: geplant=weich · angeliefert/in_arbeit/pausiert=hart · ab fertiggestellt=keine. Fertigstellen schließt offene Teilschritte ab (→ erledigt) + setzt tatsächliche Fertigstellung; abholen setzt
abgeschlossenAm; Auto-Archiv 7 Tage nach Abholung (autoArchiviere()), oder manuell. Migration:schemaVersion2 remappt Alt-Status (unbestaetigt→geplant, aktiv→in_arbeit, blockiert→pausiert, altes abgeschlossen→fertiggestellt), v3 Status-Key reserviert→angeliefert. UI: Phasen-FAQ-Panel + statusabhängige Badges/Gantt-Farben. Auftrag endet nach dem letzten Prozessschritt; Annahme/Endausgabe sind keine Teilschritte, belegen Parkplätze. Zuweisungs-Invariante: „ohne Zuweisung kein in_arbeit“ — der Übergang nachin_arbeit(starten/fortsetzen) verlangt ≥1 zugeteilten produktiven Mitarbeiter (hatZuweisung; Helfer/Annahme zählen nicht). - R8 Planung: Tag-/Wochen-/Monatsansicht, Angebotsmodus (Feasibility-Check), Planungs-Konflikte mit Auto/Wizard-Resolution.
- R9 Leitstand: EMPFEHLUNG-Engine — hartes Constraint Skill-Match, danach durchsatz-optimale Globaloptimierung. Zusätzlich Überstunden-Vorschläge mit quantifiziertem Effekt.
Architektur-Empfehlung (A-1 bis A-5)
Dreischichtig:
- A-3 Constraint Solver (OR-Tools CP-SAT / OptaPlanner) für die harte Planung
- A-2 Workflow- oder State-Machine-Layer für Lifecycle (Auftrag, Teilschritt)
- A-4 LLM für Empfehlungstexte, Konflikt-Wizards, Kunden-Kommunikation, "Was-wäre-wenn"
A-5 Pragma für v1: OR-Tools + XState + LLM-API; Workflow-Engine erst bei wachsender Komplexität.
Vereinfachungen gegenüber Altsystem (S-1 bis S-10)
Single-Modal überall, Single-Source-of-Truth für derived state, zentrale Taxonomie-Verwaltung, Skill als Rückgrat, Schicht-Katalog statt freier Intervalle, ein Auftrags-Lifecycle ohne Anlege-Modus-Radio, Recommender als zentrales Nervensystem, generisches Template-Bibliothek-Pattern (plattform-curated + tenant-eigen, Snapshot-Import), vereinheitlichte Konflikt-Engine, generisches Attachment-Modell.
4. Offene Punkte — Archiv/Bestand (neue OPs: GitHub-Issue, TKT-D-862)
✅ Vollständig migriert (12.07.2026). Dieser Abschnitt war das OP-Archiv; sein kompletter Bestand (~166 Alt-OPs) wurde am 12.07.2026 in
ops/<ID>.mdüberführt (Big-Bang, OP-DOCS-11, PO-Auftrag „überführe das OP-Archiv ins neue Modell“). Die verbindliche, vollständige OP-Liste steht generiert indocs/betrieb/Offene-Punkte.md(Quelle:ops/*.md) — inkl. Status-Statistik + Grafik.Lastenheft.md§11 bleibt die fachliche Detailbeschreibung. Seit 26.09.2026 (TKT-D-862) ist das GitHub-Issue die Quelle (offener-punkt;ops/*.mdeingefroren,issue:im Frontmatter), neue OPs entstehen als Issue (agents.md§6.2). Der Stand-Schnappschuss unten bleibt als datierte Historie erhalten.
Stand-Schnappschuss 2026-06-23 (Historie).
maindurch #167 (PRs #107–#167 gemergt). Chronologischer Detail-Stand:CHANGELOG.md(je PR, immer aktuell); offene Punkte unten in §4. Highlights seit #123: 3b Gantt-Direktverschiebung + Politur · App-/Solver-CD (Fly) · Zielprofil „Termintreue“ · CP-SAT-Vertiefung (Indoor/Überlauf) · Szenario-Konvergenz · Audit-Trail +CHANGELOG.md· Sidebar-Aufklappen+Gruppierung · „Plan ändern“-Fokus-Modus · 30-s-Ping-Bugfix · In-App-Assistent OP-AI-4 (Insights live) · Mitarbeiter-/Skill-CRUD · Light/Dark-Mode · Mitarbeiter-Leistung/XP+Ausbildung · Strategie EU-Markteintritt (reines B2B: SevDesk-SoR · Better Auth · zahlungs-gesteuerter Zugang —docs/architektur/Billing-Zugang.md, OP-BILLING-1/ACCESS-1/I18N-1). Way-of-Working: Branch nach Merge löschen · Doku-Pflicht je PR (HANDOFF/Timesheet) · Branch laufend aufmainaktuell halten · Doku-Fast-Track (reine Doku-PRs überspringen die schwere CI viachanges-Job + aggregiertemCI Gateals einzigem Required-Check und dürfen per Auto-Merge durch —agents.md§7; Repo-Voraussetzung: Branch-Protection aufmainnurCI Gate+ „Allow auto-merge“). Die folgenden Detail-Bullets sind der #123-Schnappschuss (06-22 früh) — als Historie belassen; der aktuelle Stand steht imCHANGELOG.md.
- Fertig: OP-OPT-1 Phasen 1–4 (Terminklassen-Modell · lexikografische Zielfunktion mit asap/jit + best_effort-in-Slack + Plan-Stabilität · schritt-granulare Reservierung + Vorschlags-Feed + event-getriggerte Re-Opt · Preemption-Fundament +
unterbrechen-Hebel) und OP-OPT-3 Vorschlags-Modell Schnitt 1 (Rename Empfehlung→Vorschlag) + Schnitt 2 (Veraltung/Wiedervorlage) + Schnitt 3a (Mensch-Vorschlag „Vorziehen“). Details je Eintrag unten +design/OPTIMIERER_TERMINKLASSEN.md(§6 Preemption, §7 Vorschläge: Plan-gegen-Plan).- Begriffe (Stand jetzt): Vorschlag · Idee (= früher „Tweak“) · Konflikt · Aktionen Übernehmen/Verwerfen. Code:
server/src/operativ/vorschlag.ts,vorschlagId, Messagesvorschlag.{gesehen,verwerfen,uebernehmen,neuberechnen}, persistiertvorschlagStatus/vorschlagStempel(schemaVersion v8). Achtung: ältere Log-Einträge unten nennen nochEmpfehlung*/empfehlung.ts/--tk-ws-recommendations— das ist der Stand vor Schnitt 1; Route/Komponente/Token heißen intern bewusst weiterrecommendations.- Nächster Schritt: OP-OPT-3 3a + Politur Slice A + 3b-1 + 3b-2a ✅ gemergt (#121/#122/#124/#125). Schnitt 3b-2b (Gantt-Drag-UI) ✅ gebaut (Branch
design-gantt-drag-3b2b, PR offen): „✎ Plan ändern“-Toggle →geplant-Blöcke im Gantt ziehbar (Bucht/Zeit, 15-min-Raster) → vorgemerkte Pins (Geist-Block) → „Konsequenzen berechnen“ → Pin-Vorschlag inline (Planung) + im Feed → Übernehmen; stepId clientseitig exakt (${auftragId}-${teilschrittId}-${k}, k=Index untergeplant= Solver-Indexierung → kein Server-Change); live verifiziert (Drag→Pin +300min/15-gerastert → Karte → Übernehmen verschiebt #002 qm exakt auf Pin). ➡ Schnitt 3b komplett (3b-1+3b-2a+3b-2b). Offen: fly.dev-Redeploy des neuenmodel.pyfür LIVE-Pins; Slice B (Auftragsnummer-Tooltip, 2 Entscheidungen offen) + 3a-Folge. Siehe OP-OPT-3.- Neue OPs dieser Session: OP-OPT-3 (Vorschlags-Modell, Fakt vs. Plan), OP-AUDIT-1 (Audit-Log).
- Goldene Regel (neu, verankert in
design/CLAUDE.md+ Memorydokumentation-pflicht): jedes Feature wird auch in der Doku beschrieben + Docs↔Code-Konsistenz prüfen.- Dev-Gotcha: Client-Build/
ng servebraucht Node ≥ 22 (export PATH="/opt/homebrew/opt/node@22/bin:$PATH"); das aktive Shell-nodewar zuletzt v20.10 (zu alt → „Angular CLI requires Node ≥20.19“). CI läuft auf Node 22. Lokale Dev-Server (wrangler :8787 / ng :4200) waren am Session-Ende unten.
Volle OP-Liste (verbindlich): docs/betrieb/Offene-Punkte.md
— erzeugt aus den GitHub-Issues (TKT-D-862), mit Status je OP + 📊-Statistik. Fachliche Detailbeschreibung je OP:
Lastenheft §11 (per-OP-Anker #op-<id>). Der frühere hier eingebettete Bullet-Bestand ist
vollständig dorthin migriert (Audit-Trail: Git-Historie dieses Abschnitts + je ops/<ID>.md).
5. Prototyp — Architektur
┌───────────────┐ WebSocket ┌─────────────────────────────┐ HTTP ┌──────────────────┐
│ Angular 22 │ <───────────── │ Cloudflare Worker │ ───────▶ │ CP-SAT-Service │
│ - Signals │ │ Durable Object │ (SOLVER │ (Python/OR-Tools,│
│ - partysocket │ │ (partyserver lib) │ _URL) │ Fly.io/Container)│
└───────────────┘ │ + statische Assets │ ◀─────── └──────────────────┘
└─────────────────────────────┘ Plan / Fallback: TS-Solver
(Zugang via Cloudflare Access vor dem Worker)
Live-Leitstand: Mitarbeiter-Karten (Status/Empfehlung) + Bay-Belegung + Aufträge mit Planungs-Gantt. Änderungen propagieren live an alle Clients (mehrere Tabs → Aha-Effekt). „Offene optimieren“ plant via CP-SAT (Fallback: TS-Optimierer).
6. Prototyp — Aktueller technischer Stand
6.1 Stack
- Node: ab Plattform-Upgrade Node 22 erforderlich (
.nvmrc= 22). Grund: Wrangler 4 verlangt Node ≥ 22. Lokal z. B.nvm useoderbrew install node@22+ als Default linken. - Server: Cloudflare Workers + Durable Object via
partyserver-Library, TypeScript, Wrangler 4, kein Bundler. - Client: Angular 22 Standalone-Komponenten, Signals, neue Control-Flow-Syntax (
@if/@for), Tailwind v4 auf den--tk-*-Design-Tokens (design/tokens/tokens.json→ generiertetokens.css). - Verbindung:
partysocketClient-Library, automatische Host-Detection (lokal:8787= wrangler-Default, deployed =window.location.host).
6.2 Migrationsstand PartyKit → Wrangler ✅
Wegen Plattformlimit Workers custom domains exceeded on zone 'partykit.dev' (10.000-Cap erreicht) ist Deploy auf der gehosteten PartyKit-Plattform NICHT mehr möglich. Migration auf eigenen Cloudflare-Account via wrangler ist abgeschlossen:
| Datei | Status |
|---|---|
server/party/leitstand.ts | ✅ Nutzt partyserver, exportiert LeitstandServer Durable Object + Worker-fetch-Handler. |
server/wrangler.toml | ✅ Angelegt — Bindings für Durable Object + Static-Assets. |
server/package.json | ✅ Scripts auf wrangler dev / wrangler deploy umgestellt; wrangler + @cloudflare/workers-types als devDeps; partykit Dep entfernt. |
server/partykit.json | ✅ Entfernt (obsolet). |
README.md Deploy-Abschnitt | ✅ Auf Wrangler-Workflow umgestellt. |
6.3 So startest du den Prototyp lokal
node --version # muss v22.x sein (sonst: nvm use / brew node@22 linken)
cd server
npm install
npm run dev # = wrangler dev (Default-Port 8787)
# in einem zweiten Terminal:
cd client
npm install
npm start # → http://localhost:4200
Client und Server müssen beide laufen. Tab duplizieren → Status oder Bay-Belegung ändern → live in allen Tabs.
Falls
wrangler devüber fehlendesclient/dist/leitstand/browsermeckert (wegen[assets]-Block): einmalmkdir -p client/dist/leitstand/browser && touch client/dist/leitstand/browser/.keepausführen.
6.4 Deploy
cd server
npx wrangler login # einmalig
npm run deploy # baut Client + ruft wrangler deploy
# Produktiv-URL: https://app.taktano.com (Custom-Domain-Route in wrangler.toml: routes + custom_domain=true; setzt Zone taktano.com im CF-Account voraus)
# Fallback/Default: https://taktano.<dein-cf-subdomain>.workers.dev
Voraussetzungen: kostenloser Cloudflare-Account.
Automatischer Deploy (CD): Jeder Push auf main baut den Client und deployt den Worker automatisch (.github/workflows/ci.yml, Job deploy — läuft nur nach grünem server/client/solver-service und nur auf main). SOLVER_URL ist kein Secret — öffentliche URL, steht versioniert in wrangler.toml [vars] (= https://solver-service.fly.dev). Der CP-SAT-Service (Fly.io) wird separat deployt (solver-service/, fly deploy); ist er nicht erreichbar, nutzt der DO automatisch den TS-Fallback.
CD App-Worker — ✅ LIVE (06-22, ersetzt PR #21):
deploy-Job inci.yml(push-to-main, NUR nach grünen Test-Gates server/client/solver-service/design-gate; strikt — Deploy-Fehler bricht den main-Lauf rot ab) →npm run deploy(build:client +wrangler deploy→ Worker + DO). Secrets gesetzt + end-to-end verifiziert:
CLOUDFLARE_ACCOUNT_ID(dasselbe Secret wie die Doku-Pipeline).CLOUDFLARE_API_TOKEN— kann Workers (der erste main-Deploy beim Merge #134 lief grün; die frühere „nur Pages:Edit“-Annahme war falsch → kein Handlungsbedarf).Seit #134 deployt jeder Merge auf
maindie App (Worker + Durable Object) automatisch. (Alt-Branchci-cd-deploy/#21 war 6 Tage veraltet + ci.yml-Konflikt → neu aufgesetzt, #21 geschlossen.)
Zugangsschutz — Cloudflare Access (Zero Trust): Der frühere client-seitige Zugangscode-Soft-Gate ist entfernt; geschützt wird edge-seitig vor dem Worker. Einrichtung im Dashboard (einmalig):
- Zero Trust → Access → Applications → Add → Self-hosted für
app.taktano.com(Produktiv-Domain; ggf. zusätzlich die*.workers.dev-Subdomain). Deckt SPA und die/parties/...-WebSocket-Route ab, da derselbe Worker. - Policy: Allow für die Vest-/Demo-Nutzer. Login-Methode genügt zunächst One-Time-PIN (E-Mail) oder Google-IdP — kein eigener IdP nötig (produktiver IdP = OP-AUTH-1).
- Bypass-Falle: Bei Custom-Domain die
*.workers.dev-Route deaktivieren (oder ebenfalls per Access-Policy gaten), sonst umgeht man das Gate über die workers.dev-URL.
Optionale Härtung (Defense-in-Depth, schon im Code): Der Worker prüft das von Access injizierte JWT (Cf-Access-Jwt-Assertion) gegen die Team-JWKS. Aktivieren über ACCESS_TEAM_DOMAIN (z. B. dein-team.cloudflareaccess.com) und ACCESS_AUD (Application-AUD-Tag) in wrangler.toml bzw. via wrangler deploy --var. Beide leer (Default, lokal) = Prüfung aus.
6.5 Planungs-Engine (Scheduler + Solver)
Dreistufig, alles reines TS außer dem CP-SAT-Service:
- Greedy-Scheduler (
server/src/scheduler/): plant einen Auftrag §6.1-zulässig (Skill-Match (1 Skill + N Personen), Bucht-Skill, Schichten−Abwesenheiten, Sperren, Cool-down, Abhängigkeit, Standzeit), inkl. Angebotsmodus (früheste/späteste Anlieferung), getypter Parkplätze mit Kapazität/Luxus-Restriktion/Umparken, Indoor-Trocknung, Nacht-Scheduling und Mehrauftrag (scheduleMulti, Eil-Priorität). Demos:npm run spike/npm run replan. - TS-Optimierer (
server/src/solver/): exakte Suche über die Einplan-Reihenfolge gegen die Zielfunktion §6.2 (Σ Durchlaufzeit, Makespan, G-2, G-3). Schlägt den festen Priority-Greedy.npm run solve. - CP-SAT-Service (
solver-service/, Python + OR-Tools, A-5): voller Entscheidungsraum (Startzeiten + Zuweisungen). Läuft nicht in Workers → separater Container (Dockerfile, Fly.io/Cloud Run). Der DO ruft ihn per HTTP (SOLVER_URL); ohne erreichbaren Service automatischer TS-Fallback. Lokal:cd solver-service && pip install -r requirements.txt && python app.py, dannnpm run solve:cpsatbzw.SOLVER_URLinserver/.dev.varsfürwrangler dev. Modell deckt §6.1 + getypte Parkplätze + G-2-Ziel + G-3-Kennzahl ab; Self-Testpython model.py.
Im Leitstand: Button „Offene optimieren (CP-SAT)“ → optimiereOffene() plant die unbestätigten Aufträge gemeinsam (harte Reservierungen bleiben fix, §6.3), CP-SAT mit Fallback; solverInfo zeigt den genutzten Pfad.
7. Nächste Schritte (Priorität von oben)
Erledigt (auf main): Datenmodell · Scheduler (Angebotsmodus, getypte Parkplätze, Indoor-Trocknung, Nacht-Scheduling, Mehrauftrag) · TS-Optimierer (§6.2) · operatives Modell (Lifecycle S-6) · Re-Planung/Eil-Verdrängung (OP-R7-3) · CP-SAT-Service (A-5, getypte Parkplätze/G-2/G-3) inkl. DO-Anbindung + Deploy-Config · Persistenz + Leitstand-Auftragsanzeige · Planungs-Gantt (read-only) + Optimieren-Button mit Lauf-Feedback · Zugangsschutz Cloudflare Access · Plattform-Upgrade (Node 22 / Wrangler 4 / Angular 20) · CI.
- UI-Slices (Lastenheft §5.2–5.3): Gantt ✅ (statusfarbig) + Optimierungs-Vorschau ✅ (R8-G2) + Karten-Mini-Gantt/relative Zeit ✅ + Plan-Ist/Standort ✅ + Konflikt-Lösen-Wizard ✅ (OP-R8-2/3, volle Hebel-Liste aus Prozess-Definition); R8-G1 animierte Plan-Änderungen ✅ (CSS-Transitions auf Gantt-Balken + Karten-Mini-Gantt, stabile Track-IDs → Element-Reuse); Gantt-Drag&Drop-Validierung Slice 1 ✅ (OP-R8-4: geometrisches Sofort-Feedback beim Ziehen — Überlappung/Schicht, rot/⚠ statt Solver-Roundtrip; Skill-Match/Cool-down bleiben Solver-geprüft); R7-P1 Auftrags-Fortschritts-Indikator ✅ (07-14, v0.84.0: 🚗-Kette Annahme→Teilschritte→Ausgabe,
geteilte
FortschrittsIndikatorComponent— kompakt auf Fluss-Karte + Fly-in-Header, ausführlich im Aufträge-Detailpanel); offen: Mitarbeiter-Ansicht „dein nächster Schritt“ (§7.3, OP-R9-4), Konflikt-Typ-Enum ✅ komplett (OP-R8-1: alle 7 Typen —termin/ueberbuchung/skill_luecke/standzeit[Slice 1] +mitarbeiter_fehlt/arbeitsplatz_fehlt/sperre_kollidiert[Slice 2, Wiederverwendung vonmitarbeiterAusfall/bayAusfall]; Typ-Filter im Feed + Hebel-Wizard-Integration offen); „Alle automatisch lösen" Slice 1 ✅ (OP-R8-7: Header-Aktion wählt je Termin-Konflikt den sichersten Hebel aus der Wizard-Hebel-Liste, Garantie gegen neu verursachte Konflikte; Überstunden-/Kapazitäts-Hebel als Folge-Slice offen), OP-R9-6 Kapazitäts-Angebote. - CP-SAT-Modell erweitern: Folierbucht-als-Überlauf-Parkplatz, G-3 als harte/penalisierte Bedingung (aktuell nur gemeldet), Indoor-Trocknung/Nacht-Scheduling (aktuell nur im TS).
- Browser-Live-Test des Leitstands (zwei Tabs, „Optimieren“ →
solverInfo). - Offene Punkte abarbeiten — Quelle: GitHub-Issues
offener-punkt(TKT-D-862; Live-Übersichtdocs/betrieb/Offene-Punkte.md); §4/Lastenheft §11 sind Archiv/Bestand. Typischerweise 30–60 min pro OP-Cluster. In Arbeit: OP-ALERT-1 Notfall-/Schaden-Alert ✅ abgeschlossen (v0.95.0, Slices 1–6): Klärfall-Varianteart:'notfall'+ Hard-Stop/Eskalation/Sperre + 🚨-Knopf · Alarm-Sichtbarkeit (globaler Indikator/Badge) · Foto-Pflicht (Sperre erst mit Beweisfoto) · Werker-Alert-Knopf · Leitungs-Freigabe (Chef-Gate) · Alarm-Ton (Web-Audio). Video-Beweiserfassung → eigener OP-ALERT-2 (offen). OP-QS-1 QS-Mangel vertiefen (Slice 1 ✅ v0.86.0 — Mangel-Statusoffen→in_nacharbeit→behoben, Abnahme-Gate + QS-Badges; Slice 2 ✅ v0.87.0 — Beweisfotos am Mangel M05 [Teilschritt-Fotos projiziert, QS-Thumbnails]; Slice 3 ✅ v0.88.0 — Pflicht-Beweisfoto für schwere/kritische Mängel [Abnahme-Gate blockt bis dokumentiert]; Slice 4 ✅ v0.89.0 — dedizierte mangel-eigene Foto-Erfassung [Beweisfoto direkt am Mangel, polymorphes Foto-Ziel; liefert Beweismittel-Mechanik für OP-ALERT-1]; Folge-Slices: Video-Erfassung · manuelles „behoben"+Vier-Augen · Auswertung je Kategorie/Skill/MA · admin-Kategorien G-1).
Arbeitsweise dieser Phase: pro Slice ein Branch + PR gegen
main, gemergt nach grünem typecheck/Build.ghist eingeloggt; Wrangler nur vianpx wrangler/npm run …(keinbrew install wrangler— falsches Paket).
8. Wichtige Dateien (Repo-Root, GitHub: drkv-com/taktano) — Stand 07-12
.
├── README.md ← Vordertür: Überblick, Quick-Start, Tests-Einstieg
├── HANDOFF.md ← dieses Dokument: Stand + Archiv/Bestand offener Punkte (§4)
├── CLAUDE.md · CHANGELOG.md ← Leitplanken (verbindlich) · Audit-Trail je PR
├── docs/ ← Doku in Themen-Ordnern (Landkarte: docs/README.md)
│ ├── anwender/ ← Anwender-Handbuch (Werkstatt-Team, 4 Seiten)
│ ├── zielgruppen/Lesepfade.md ← Einstieg nach Rolle (7 Leserkreise)
│ ├── fachlich/ ← Lastenheft (Master) · datamodel · operativmodell · solver · Flow-*
│ ├── architektur/ ← 16 Design-Docs je offenem Punkt (Audit-Log, Kosten, Tenant …)
│ ├── betrieb/ ← Governance: Compliance · Risiko · Roadmap · Tests · Timesheet · Reviews
│ ├── konventionen/ ← agents.md (Way-of-Working) · IDs · Register · Entwicklungsansatz
│ ├── produkt/ ← Markt · Wettbewerb · Produkt/Marketing (nicht-technisch)
│ └── glossar/Glossar.md ← generiert aus docs-site/src/glossar/glossar.mjs
├── ops/ ← eingefrorener OP-Altbestand (`issue:` → Issue ist Quelle, TKT-D-862)
├── design/ ← Design-System-Verträge (CLAUDE.md · DESIGN_TOKENS · COMPONENTS · WORKSPACES) + tokens/
├── scripts/ ← Gates & Generatoren (check-doc-consistency, gen-ops, gen-glossar, stamp-build …)
├── .github/workflows/ ← ci.yml (Pflicht-Check `checks`) · docs-deploy · fly-deploy · dokumente-nachziehen · labels · weekly-audit
├── solver-service/ ← Python OR-Tools CP-SAT (A-5): model.py · app.py · Dockerfile · fly.toml
├── server/ ← Cloudflare Worker + Durable Object (partyserver)
│ ├── party/leitstand.ts ← Worker fetch + LeitstandServer DO (ruft CP-SAT, Fallback TS)
│ ├── src/model/ · scheduler/ · solver/ · operativ/ · insights/ · kosten/ · assistant/ · tenants/
│ ├── src/app-version.ts ← APP_VERSION (Single Source, beim Deploy gestempelt) · build-number.ts (ebenso) · version.ts führt beide zusammen
│ └── wrangler.toml · package.json ← Scripts: dev/deploy/typecheck + 36 test:*-Selbsttests (docs/betrieb/Tests.md)
├── client/ ← Angular 22 (Standalone + Signals), Tailwind v4 auf --tk-*-Tokens
│ └── src/app/leitstand/ ← Shell + ~35 Komponenten (pages/ je Workspace, geteilte Panels/Dialoge)
├── docs-site/ ← Docusaurus (docs.taktano.com): Glossar-Generator, Sprechblasen, Vorteilsrechner
└── .nvmrc · .node-version ← Node 22 (Pflicht für Wrangler 4)
9. Konventionen für die nächste Claude-Session
- Sprache: Antworten kurz und präzise. Empfehlungen mit eindeutigen IDs versehen (z. B. S-, OP-, FR-).
- IDs respektieren: Alle Entscheidungen aus dem Lastenheft sind durch IDs referenziert. Beim Verweis bitte ID nennen.
- HANDOFF immer aktuell halten (kein Informationsverlust): Nach jeder inhaltlichen Änderung (Code-Slice, Architektur-/Stack-Entscheidung, neuer OP, Deploy-Schritt) HANDOFF im selben PR/Commit mitpflegen — §2 Artefakte, §4 Offene Punkte, §6 technischer Stand, §7 Nächste Schritte, §8 Dateibaum. Nicht den Footer: Datum und Version stehen dort nicht mehr von Hand (Git-Log + Stempel, TKT-OP-PM-4). Lastenheft = fachliche Quelle der Wahrheit; HANDOFF = Stand/Übergabe zwischen Sessions.
- Keine ungefragten Änderungen an Lastenheft oder Prototyp — erst klären, dann tun.
- Wenn read-only Analyse einer Drittsystem-UI nötig: User loggt selbst in seinem Browser ein, Claude navigiert per Claude-in-Chrome Extension. Nichts ändern, im Zweifel fragen.
- Tasks tracken via TaskCreate/Update für mehr-Step-Arbeit.
- Vor jeder größeren Aktion offene Punkte im Auge behalten — Issues
offener-punkt/docs/betrieb/Offene-Punkte.md; §4 ist Archiv/Bestand.
10. Setup auf einem zweiten Gerät („Everything as Code“)
- Klonen statt syncen:
git clone https://github.com/drkv-com/taktano.gitcd taktano
- Claude/Cowork-App auf dem zweiten Gerät installieren, Anthropic-Login.
- In Cowork den geklonten Ordner als Working-Folder wählen.
- Browser-Logins pro Gerät separat (Cloudflare via
wrangler login, GitHub viagh auth loginoder SSH-Key, etc.). - Neue Konversation mit „Lies
HANDOFF.md“ starten — Claude hat damit Stand + Konventionen. - Arbeiten: Änderungen committen + pushen.
HANDOFF.mdist die Quelle der Wahrheit zwischen Sessions — wichtige Entscheidungen direkt dort einpflegen. - Wenn du an automotivo.de weiterforschen willst: Claude-in-Chrome-Extension einmal verbinden, dann wie gehabt (siehe §9, read-only).
Stand (Datum = letzter Commit dieser Datei, git log -1 HANDOFF.md; Version = gestempelt, server/src/app-version.ts — beides nicht mehr von Hand gepflegt, TKT-OP-PM-4) · Stack: Node 22 / Wrangler 4 / Angular 22 (Signals, Tailwind v4) / Python 3.12 (CP-SAT auf Fly.io, Auto-Deploy) · alle 15 Workspaces gebaut, CI/CD + Doku-Site live · aktueller Fokus: POC-Vorbereitung Pilotkunde Vest Automotive (Meilensteine → ops/OP-VERTRIEB-3.md) + technische §7-Slices (R7-P1 Fortschritts-Indikator ✅, Gantt-Drag&Drop-Validierung Slice 1 ✅ OP-R8-4, Konflikt-Typ-Enum ✅ OP-R8-1 (alle 7 Typen), „Alle automatisch lösen" Slice 1 ✅ OP-R8-7) · größter Produkt-Hebel: OP-AUTH-1 (Identität/Rollen, UX-Review B1). Stand im Detail: §2 (Artefakte) · Issues offener-punkt/Offene-Punkte.md (offene Punkte, Quelle = Issue seit TKT-D-862; §4 = Pointer) · CHANGELOG.md (je PR). (Kein handgepflegtes Datum mehr — TKT-OP-PM-4.)
Governance-Nachtrag (13.07.2026): Projekt-Kürzel TKT bei neuen IDs jetzt verbindlich (bisher fehlte
die Klausel ganz) — repo-übergreifend mit MED/SERA vereinheitlicht, CLAUDE.md ID-System.