Decision Log — Medidentas (lebend)
Append-only Entscheidungsprotokoll (ADR-artig): jede Design-/Architektur-/Prozess-Entscheidung und
jedes wesentliche Diskussionsergebnis wird hier als D-n festgehalten — kurz, mit Begründung und
Referenz. Pflege (verbindlich): je PR mitführen — neue Entscheidungen als neue Zeile ergänzen (analog
CHANGELOG.md / Feature-Liste.md / Test-Uebersicht.md). Bestehende Zeilen nicht umschreiben; wird
eine Entscheidung revidiert, neue D-n-Zeile mit "ersetzt D-x" anlegen.
Bezug zum ID-System: Entscheidungen referenzieren die bestehenden IDs (G-n Prinzipien · A-n
Architektur · S-n Vereinfachungen · R-n Module · OP-<Thema>-n offene Punkte · RISK-n). Die Details
stehen weiterhin in Lastenheft.md / HANDOFF.md / CHANGELOG.md; dieser Log ist die schnelle,
chronologische Entscheidungssicht.
| ID | Datum | Bereich | Entscheidung | Begründung (kurz) | Referenz |
|---|---|---|---|---|---|
| D-1 | 2026-06-27 | Architektur | Stack = Cloudflare (Workers · D1 · Queues · Cron · Angular · Access) | In-House-Know-how (Taktano), EU-Datenresidenz, integrierte Plattform | A-4, Stack.md |
| D-2 | 2026-06-27 | Prinzip | Integrate-before-build: Standardwerkzeuge anbinden statt nachbauen (NextCloud · DocuSign/PandaDoc · CRM · SevDesk) | Eigenwert liegt in der Orchestrierung, nicht im Nachbau | G-1 |
| D-3 | 2026-06-27 | Prinzip | Everything-as-Code: Repo = Single Source; Entscheidungen als .md-Commit; Derived State nie speichern | Nachvollziehbarkeit, keine Doppel-Wahrheit | G-2 |
| D-4 | 2026-06-27 | Prinzip | Append-only, hash-verkettetes Audit-Log; Retention definiert | Rechtssicherheit, Manipulationssicherheit | G-4, OP-AUDIT-1 |
| D-5 | 2026-06-27 | Datenschutz | EU-/CH-Datenresidenz + PII-Minimierung by design; Kundenstamm extern (CRM) | DSGVO/revDSG, Datenminimierung | G-5, RISK-17 |
| D-6 | 2026-06-27 | Versionierung | SemVer manuell je PR + Build-Nummer automatisch aus Commit-Count | bewusste Versionsstufen, kollisionsfreie Builds | version.ts |
| D-7 | 2026-06-27 | E-Signatur | eIDAS-Niveau je Dokumenttyp (SES/AES/QES); Provider-Abstraktion (DocuSign/PandaDoc) | Rechtswirkung muss zum Dokument passen; CH = ZertES | A-2, OP-SIGN-1, RISK-2 |
| D-8 | 2026-06-28 | Identität | Auth = Cloudflare Access + RBAC (berater/backoffice/admin); Audit-Actor = echte Identität | Standardwerkzeug (G-1), kein Eigenbau-Login | R7, OP-AUTH-1 |
| D-9 | 2026-06-28 | Onboarding | Self-Service-Onboarding: Einwilligung als SES erfasst | rechtssicherer, niedrigschwelliger Formular-Flow | R2 §4.5 |
| D-10 | 2026-06-28 | Deploy | Live auf app.medidentas.com — 1 Worker (UI + /api via Static Assets), hinter Access, D1 EU weur | eine Subdomain, EU-Residenz, Access schützt keine *.workers.dev | OP-DEPLOY-1, Deploy.md |
| D-11 | 2026-07-01 | Zeiterfassung | Ansatz A: dünnes Ledger + Export (R13) statt reiner Tool-Anbindung; ArbZG getrennt als OP-TIME-2 | differenzierender Wert = Zeit×Mandant×Beratung; ArbZG = anderes Datenmodell/PII | R13, OP-TIME-1, RISK-21 |
| D-12 | 2026-07-02 | Zeiterfassung | Leistungszeit bezahlt = Andockpunkt für SevDesk/OP-INVOICE-1 (= 0 bis Anbindung) | kein Doppel-Pflegen des Zahlstatus (G-2) | #30, OP-INVOICE-1 |
| D-13 | 2026-07-02 | CI/CD | App-Auto-Deploy bei Push auf main (server/**/client/**) + concurrency; manuell bleibt | "auf main gemergt" soll "live" bedeuten (analog Doku-Auto-Deploy) | #31, Deploy.md |
| D-14 | 2026-07-02 | UI-Architektur | Cockpit-Sichten rein abgeleitet (Board · aggregiertes Cockpit · Mandantenakte) — kein neuer Store | G-2, integrationsfrei, weniger Zustand | #32–#34 |
| D-15 | 2026-07-02 | Governance | Lebende Feature-Liste + Test-Übersicht, je PR gepflegt | "was kann die App / was ist getestet" jederzeit aktuell | #34, #37 |
| D-16 | 2026-07-02 | Orchestrierung | Phasen-Engine: Übergangs-Guards abgeleitet (G-2); Playbooks erzeugen idempotente Folge-Wiedervorlagen | aktiver Prozess-Kern (G-1), nichts fällt durch | #35, §5.1 |
| D-17 | 2026-07-02 | Orchestrierung | Playbooks admin-editierbar: Store = Single Source, Seed erhält Bestandsverhalten (Migration v13) | fachliche Pflege ohne Deploy; unveränderter Start | #36 |
| D-18 | 2026-07-02 | UI | Board wahlweise nach Lifecycle oder Phase; Phasenwechsel bleibt im Detail (Guards) | Überblick ohne die geführte Logik zu duplizieren | #38, §5.2 |
| D-19 | 2026-07-02 | Governance | Decision Log eingeführt — getroffene Entscheidungen je PR hier festhalten | schnelle chronologische Entscheidungssicht, Audit-Trail (G-2/G-4) | #39 |
| D-20 | 2026-07-02 | UX | UX-Polish P1 aus dem Usability-Review: dezente Toast-Bestätigungen (app-weiter Service, aria-live), Lade-Zustände, Bestätigung vor Löschen (einheitlich). Rest-Findings als OP-UX-1 | Systemrückmeldung + Fehlervermeidung (Nielsen #1/#5) bei kleinem Aufwand | #40, OP-UX-1 |
| D-21 | 2026-07-02 | UX | UX-Polish P2 aus OP-UX-1: Access-Logout im Header, Abschnitts-Navigation (Sprungmarken, sticky) im langen Mandant-Detail, Typ-Klartext (Praxis/MVZ/Sonstige) statt Rohwert, Bestätigung vor Archivieren, A11y-Grundgerüst (aria-label an Selects, <main>-Landmarke) | Wiedererkennung/Freiheit + Fehlervermeidung (Nielsen #3/#5/#7) ohne Backend-Änderung | #41, OP-UX-1 |
| D-22 | 2026-07-02 | UX/A11y | UX-Polish P3a — A11y-Vertiefung (erster von drei P3-Slices): Skip-Link "Zum Inhalt springen", durchgängiger Fokusring (:focus-visible), Fokus-Management bei Routenwechsel (Fokus → <main>), aria-pressed an Toggle-Buttons, aria-label an Filter-Controls, role="progressbar" an Fortschrittsbalken | Tastatur-/Screenreader-Zugänglichkeit (WCAG 2.4.1/2.4.7), client-only | #42, OP-UX-1 |
| D-23 | 2026-07-02 | UX/R5 | UX-Polish P3b — Bulk-Aktionen Wiedervorlagen (zweiter P3-Slice): Mehrfachauswahl in "Meine Wiedervorlagen" + Sammel-Erledigen/-Verschieben über neuen Endpunkt POST /api/wiedervorlagen/sammelaktion. Teilfehler-tolerant (je ID verbucht, kein Alles-oder-nichts); jede Einzeländerung läuft über die bestehenden Service-Methoden → einzeln auditiert (G-4). Verschieben setzt erinnertAm zurück. UI zeigt Erledigen/Verschieben; API kann zusätzlich zuweisen | Zeitgewinn im Tagesgeschäft ohne Audit-Lücke; Wiederverwendung statt Sonderpfad | #43, OP-UX-1 |
| D-24 | 2026-07-02 | UX/G-4 | UX-Polish P3c — Undo bei Lifecycle-Wechseln (dritter, letzter P3-Slice; schließt OP-UX-1 ab): ToastService.mitAktion() (Aktions-Toast mit "Rückgängig"-Button, ~6 s) + Undo im Mandant-Detail und Board. Kernentscheidung: Undo ist eine kompensierende Rückbuchung (setzt den vorherigen Status erneut) → erscheint als eigener mandant.geaendert-Audit-Eintrag, kein Rewrite → append-only-Audit (G-4) bleibt unverletzt. Client-only | Nutzerkontrolle/Fehlerbehebung (Nielsen #3) ohne Kompromiss beim Audit-Trail | #44, OP-UX-1 |
| D-25 | 2026-07-03 | Dexman | Dexman-Fachmodell aus dem Excel-Altbestand abgeleitet (Dexman-Fachmodell.md, DEX-8..13): Analyse der Kunden-Excels DexMan v41 · Personal Manager v2 · Darlehensübersicht v25; Darlehen erhalten eine Pflicht-Klassifikation geschäftlich/privat/vermietet mit Zuordnung geschäftlich→Praxis (R1), privat→Inhaber; Beispieldaten nur anonymisiert ins Repo (feste Scrubbing-Regeln §9; Originale nie committen) | Fachlichkeit ist im Altbestand vollständig kodifiziert (integrate-before-build-Analyse statt Neuerfindung); PII-Schutz (G-5, RISK-22) | Dexman-Fachmodell.md, OP-DEX-6..9, RISK-22 |
| D-26 | 2026-07-03 | Spezial-Tools | Dentmarking wird als Plattform-Spezial-Tool neu implementiert (statt Weiterbetrieb des Alt-Excel Dentmarking_v1.xlsm): Detail-Lastenheft spezialtools/Dentmarking.md (DM-1..DM-8) + vollständige Logik-Extraktion Dentmarking-Excel-Logik.md als Referenz. Kernpunkte: Kennzahlen/Potentiale abgeleitet, nie gespeichert (G-2); Benchmarks als versionierte Stammdaten mit Stand/Quelle (Gutachten referenziert Benchmark-Version); Excel-Rechenfehler werden nicht 1:1 nachgebaut, sondern fachlich korrigiert (Befunde B-1..B-4, Bestätigung OP-DM-1); PII aus Alt-Dateien bleibt außerhalb des Repos (G-5) → Alt-Bestand als RISK-23 | Reverse-Engineering belegt Fehler + DSGVO-Schwächen des Datei-Prozesses; Plattform liefert Audit (G-4), Rollen (R7), Mandanten-Kopplung (R1/R5/R6) | OP-DENTMARK-1, OP-DM-1..6, RISK-23 |
| D-27 | 2026-07-03 | Spezial-Tools/Datenmodell | Dentmarking-Umsetzungspfad: (1) Modul im bestehenden Worker/D1 (Routen /api/praxen/… + /api/dentmarking/…, Aktivierung per Tool-Flag je Mandant; R10-Isolation zunächst nur logisch via Manifest — echter eigener Worker erst, wenn ein weiteres Tool den Vertrag braucht). (2) Neue Kern-Entität praxis (Objekt/Betriebsstätte) unter dem Mandanten (1:n) — Dentmarking und später Dexman setzen auf derselben Entität auf. (3) Geschäftsjahr-bezogene Faktentabelle praxis_jahreswert je (Praxis × Periode × Feldschlüssel) mit Quelle (fragebogen heute, bwa/pvs unter Dexman) und generischem Periodenmodell (Geschäftsjahr ≠ Kalenderjahr zulässig; Dentmarking nutzt Typ jahr, Dexman später Monat/Quartal ohne Schemabruch); qualitative Angaben katalog-versioniert an der Erhebung. (4) Benchmarks optional Geschäftsjahr-bezogen (gilt_fuer_geschaeftsjahr, vorerst leer — Klärung OP-DM-2/OP-DM-7). (5) Fragebogen-Kanal: eigenes öffentliches R2-Formular + xlsx-Übergangsimport (WordPress-Webhook verworfen). Slices T1–T5 (Praxis → Erhebung/Jahreswerte → Engine/Benchmarks/Potential → Gutachten/Befunde → öffentl. Fragebogen) | ein Datenmodell für beide Tools (kein späterer Umbau), Quellen-Vorrang statt Doppelpflege (G-2), früher interner Nutzen vor öffentlichem Kanal (RISK-19-Analogie) | OP-DENTMARK-1, OP-DM-2/7, DM-1..8, ersetzt nichts |
| D-28 | 2026-07-04 | Architektur | PDF-Erzeugung im Worker via pdf-lib (OP-DOCGEN-1): dünne eigene Layout-Schicht (server/src/pdf/pdf-dokument.ts, Blockmodell Titel/Überschrift/Absatz/Tabelle/Liste) als gemeinsame Basis für Gutachten (DM-6) und R12-Standarddokumente; deterministisch (Zeit vom Aufrufer). | Bewährte Pure-JS-Bibliothek (G-1) statt Eigenbau des PDF-Formats oder externem Rendering-Dienst — läuft ohne Binärabhängigkeit im Cloudflare Worker, keine Daten verlassen die Plattform (G-5/EU-Residenz). Verworfen: Cloudflare Browser Rendering (Kosten/Latenz/Abhängigkeit), externes HTML/LaTeX-Rendering (PII-Abfluss). | PR #52 · Lastenheft.md §11 OP-DOCGEN-1 |
| D-29 | 2026-07-04 | Betrieb/CI | CI + Deploys laufen per Default auf dem self-hosted Runner der Org (runs-on: ${{ vars.CI_RUNNER || 'self-hosted' }} in ci.yml/app-deploy.yml/docs-deploy.yml); Umschalten auf GitHub-Runner jederzeit ohne Commit über die Repo-Variable CI_RUNNER | GitHub-gehostete Runner starteten am 2026-07-04 org-weit keine Jobs mehr (Billing/Limit) — CI-Gate und Auto-Deploy hingen; lokaler Runner macht die Pipeline davon unabhängig (Kosten ↓, Kontrolle ↑); Risiko Verfügbarkeit/Sicherheit → RISK-24 | PR #57 · Deploy.md §7b · RISK-24 |
| D-30 | 2026-07-04 | Compliance/R4 | Signatur & Identifikation im Selfservice-Onboarding (Dreischichten-Abgrenzung): (1) Die DSGVO-Einwilligung im öffentlichen Onboarding-Formular bleibt Checkbox + auditierte Erfassung (SES-Fall der Niveau-Matrix) — kein E-Signatur-Provider im öffentlichen Formular. (2) DocuSign/PandaDoc gehört an den Onboarding-Abschluss (Maklervertrag → AES, Vollmacht → QES, konservativ); die Anbieterwahl (OP-SIGN-1-Rest) wird an der Niveau-Akzeptanz der wichtigsten Produktgeber + EU-Datenresidenz festgemacht (Abfrage bei Top-Produktgebern; AES reicht → PandaDoc-Tendenz, QES nötig → DocuSign+EU-CSP). (3) Identitätsverifikation (PostIdent/VideoIdent) ist ein separater Baustein, kein Unterschrift-Ersatz — nur relevant bei GwG-Pflicht (→ OP-GWG-1); Normalfall = Vor-Ort-Identifizierung durch den Berater im Termin (dokumentiert in Akte/Audit), VideoIdent nur für terminlose Digitalstrecke; ein QES-Flow enthält die Identifizierung implizit | Einwilligung ist formfrei (Art. 7 DSGVO, Nachweisbarkeit genügt) — Provider dort = Aufwand + Hürde ohne Rechtswert; Unterschrift/Ident sind verschiedene Rechtsschichten; Zielgruppe Praxisinhaber mit persönlichem Termin macht Berater-Ident zum günstigsten GwG-Weg | PR #58 · Unterschriften.md · OP-SIGN-1 · OP-GWG-1 · RISK-25 |
| D-31 | 2026-07-04 | Datenmodell R1/Ablage R3 | Mandanten-Anzeigename strukturiert + NextCloud-Ablage restrukturiert: (1) R1 erhält strukturierte Namensfelder nachname/titel/vorname (R1-F08..F10); anzeigename (R1-F02) wird daraus abgeleitet (G-2, Schema "Nachname Titel Vorname"), typ-abhängig — natürliche Person = Namensschema, Praxis/MVZ = Einrichtungsname. (2) NextCloud bekommt eine Anfangsbuchstaben-Ebene: Medidentas/Mandanten/<Buchstabe>/<Anzeigename> (<id-kurz>)/…; Buchstabe = 1. Buchstabe des Nachnamens/Einrichtungsnamens, Umlaute→Grundbuchstabe (Ä→A/Ö→O/Ü→U/ß→S), nicht-alphabetisch→Sammelordner #, Großbuchstabe. (3) Migration bestehender Mandantenordner einmalig per WebDAV MOVE. | Zuverlässige Sortierung/Gruppierung/Bucketing braucht strukturierte Namen statt Freitext (G-2 abgeleitet statt doppelt gespeichert); Buchstaben-Ebene hält große Mandantenzahlen navigierbar (Kundenwunsch) | noch nicht implementiert (eigener Slice) · Dokumentenverwaltung-NextCloud.md · OP-MANDGRP-1 |
| D-35 | 2026-07-05 | R1 / Cockpit-UX | Betreuungsmodell als neue Mandant-Dimension + Cockpit-Neugestaltung "Fokus/Leitstand": (1) R1 erhält ein Feld betreuungsmodell (R1-F11) mit Werten Intensiv/Standard/Basis — bewusst als internes Leistungsversprechen der Kanzlei formuliert, nicht als Kundenwert. Rein intern (nur Cockpit/Detail, nie in Kundendokumenten/Onboarding, G-5) und neutraler Graphit-Ton statt Ampel (Rot/Amber/Grün bleibt der Aktenreife vorbehalten). Additiv, Default standard, Migration v21, eigenes Audit-Event mandant.betreuungsmodell.geaendert. (2) Das Cockpit wird auf zwei komplementäre Blickwinkel in einer Ansicht umgestellt — Fokus (eine priorisierte Bahn aller offenen Punkte, tastaturgetrieben) und Leitstand (Portfolio-Band + Zeitstrahl) — mit Theming Hell/Dunkel/System und Command-Palette (⌘K); Verwaltungs-Funktionen (Neuer Mandant, Benutzer/Rollen, Playbooks, Fragebogen-Statistik/-Einstellungen) unter /verwaltung. Aktenreife im Leitstand-Band ist ein client-seitiger Proxy (aus Offen-Zahl + Onboarding-Fortschritt), nicht die autoritative Detail-Aktenreife. | Löst die bisher fragmentierte Orientierung (Lifecycle-Status und Prozessphase getrennt) durch eine handlungsorientierte, aggregierte Sicht ab (True North #1/#2); Betreuungsmodell beantwortet "wie intensiv betreuen wir?" ohne die rechtssichere Aktenreife-Semantik zu verwässern | gebaut (0.37.0) · Handoff "AppFlowVerbesserung" · Betreuungsmodell-Optionen: gewählt 1a (Intensiv/Standard/Basis) |
| D-36 | 2026-07-05 | Betrieb/CI | CI-Pipeline entstört (Concurrency + Trigger-Hygiene + npm-Cache), Konvention agents.md §6.6: (1) Concurrency-Block in ci.yml (group: ci-${{ github.workflow }}-${{ github.ref }}, cancel-in-progress außer auf main) — überholte Läufe abbrechen (Deploy in app-deploy.yml hatte das schon). (2) Trigger push nur auf main statt alle Branches → kein doppelter push+pull_request-Lauf. (3) cache: npm entfernt aus allen setup-node-Steps. D-29-Runner-Setup unverändert. | (1)+(2) sparen Runner-Minuten + schnelleres Feedback; nicht auf main canceln, damit ein Deploy nie mitten im Lauf abbricht. (3) Auf dem persistenten self-hosted Runner ist ~/.npm warm — cache: npm (für ephemere Runner gedacht) lud nur ein großes Archiv langsam durch den Cache-Service = Ursache der ~885-MB-setup-node-Downloads/Timeouts | .github/workflows/ci.yml · agents.md §6.6 · taktano agents.md §6.8 (Gegenstück) |
| D-37 | 2026-07-05 | Betrieb/CI | CI-Pipeline schneller (Pfad-Filter + schnelle Installs + shallow Checkout), agents.md §6.6: (1) Pfad-Filter changes-Job (dorny/paths-filter) → schwere Jobs (server/client/docs) laufen nur bei betroffenem Bereich; geteilte Dateien triggern alles, main-Push immer voll; CI Gate wertet skipped als bestanden. (2) npm ci --prefer-offline --no-audit --fund=false in allen Jobs (docs-build von npm install → npm ci). (3) fetch-depth nur auf main-Push 0, auf PRs 1 (shallow). | Doku-only-PRs überspringen Server/Client, Code-only die Doku-Site → deutlich kürzere PR-Läufe; Offline-Installs + shallow Checkout sparen Netz-Roundtrips (robuster bei flakiger Runner-Anbindung); volle Validierung + korrekte Build-Nummer bleiben auf main-Push erhalten | .github/workflows/ci.yml · agents.md §6.6 · Test-Uebersicht.md |
| D-38 | 2026-07-05 | Betrieb/CI | Persistenter Angular-Build-Cache + hot-Runner-Pinning, agents.md §6.6: (1) angular.json cli.cache.environment: "all" + actions/checkout clean: false im Client-Job → .angular/cache überlebt den git clean = inkrementeller Angular-Build. (2) Alle CI-Jobs `runs-on: … | 'hot'(persistente self-hosted Runner; ephemere tragenephemeral) statt generisch self-hosted. Fork-Gate (ubuntu-latest) + CI_RUNNER`-Override unverändert. | |
| D-39 | 2026-07-05 | Betrieb/CI | GitHub-Actions auf node24-native Majors gehoben: actions/checkout@v4 → @v7, actions/setup-node@v4 → @v6 (an taktano angeglichen) in allen Workflows (ci/app-deploy/docs-deploy). | Die @v4-Actions sind node20-Actions → der Runner zwingt sie auf node24 und warnt "Node 20 is being deprecated" (+ transitive punycode-DEP0040-Warnung). Die node24-nativen Majors entfernen beide Warnungen; Versionsgleichheit mit taktano reduziert Cross-Repo-Drift. ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION wäre das Gegenteil (verworfen). | .github/workflows/*.yml |
| D-34 | 2026-07-05 | Dentmarking DM-9/T7 · Datenschutz | TTL für zwischengespeicherte Fragebögen + Ablauf-Hook + Statistik. (1) Per Link ohne Auth erreichbare Entwürfe erhalten eine TTL von maximal 30 Tagen (DSGVO-Datenminimierung, G-5) — konfigurierbar in den Tenant-Einstellungen (neue einstellung-Key/Value-Tabelle, fragebogen_entwurf_ttl_tage, admin-editierbar, auf 1..30 geklemmt). (2) Bei Ablauf ein Cron-Hook, der den Entwurf als abgelaufen markiert und den Benachrichtigungs-Seam auslöst — Versand des Zwischenstands per Mail bleibt bewusst offen (OP-DM-8), hier nur Seam + Audit; Entwurf bleibt für späteren Versand erhalten. (3) Statistik/Completion-Flow über alle Fragebögen (Trichter erstellt→begonnen→eingereicht + aktive Entwürfe) im Cockpit. Tenant = aktuell single-tenant (org-weite Einstellungen), Store für spätere Mandanten-Trennung geschnitten. | 30-Tage-Cap begrenzt PII-Liegezeit ungeschützt erreichbarer Daten; Konfigurierbarkeit gibt dem Betrieb Spielraum nach unten; Ablauf-Mail (tbd) verhindert stillen Datenverlust; Completion-Sicht beantwortet True North #2 ("was ist offen/fällig?") für die Lead-Strecke | gebaut 0.36.0 · spezialtools/Dentmarking.md §5 f/g · §12 T7 · OP-DM-8 · Migration v20 |
| D-33 | 2026-07-05 | Dentmarking DM-9/T6 | Fragebogen: wiederaufnehmbar + Feld-Datenmodell mit Wichtigkeits-Klassen, Ausfüll-Score & Feld-Markierungen. (1) Wiederaufnahme: Antworten + Markierungen werden als Entwurf am Einladungs-Token zwischengespeichert (fragebogen_einladung.entwurf, Migration v19) und beim erneuten Öffnen rehydriert; Einreichen verwirft den Entwurf. (2) Drei Wichtigkeits-Klassen essenziell/wichtig/nice_to_have je Katalogfeld — aus der Kennzahlen-Analyse abgeleitet (Excel-Logik §5: Nenner/Zähler der Leit-KZ = essenziell). (3) Ausfüll-Score gewichtet (3/2/1), rein abgeleitet (G-2). (4) Feld-Markierung "weiß ich nicht"/"wird nachgeliefert" (an der Erhebung, liefert keinen Wert). (5) Feld-Metadaten Wertebereich (weiche Grenzen, z. B. Behandler 1–500) + Struktur-Typ oeffnungszeiten — kein neuer Katalog-Stand (Antwortfelder unverändert, nur Metadaten). | Ausfüllen zieht sich (111 Felder) → Fortsetzen senkt Abbruch; Score/Klassen lenken auf die kennzahl-relevanten Angaben (True North: aussagekräftiges Gutachten); Markierung unterscheidet "übersehen" von "bewusst offen" (Nachfassen); Metadaten ersetzen die stumme 0-Rechnerei des Alt-Tools (Plausibilisierung §9) | gebaut 0.35.0 · spezialtools/Dentmarking.md §5/§7/§12/§13 · OP-DM-7 |
| D-32 | 2026-07-04 | R1/R3 | Mandanten-Gruppierung — Ablage-Variante A (vorläufig, Bestätigungsvorbehalt): Gruppen ("Eheleute Müller") werden flach + referenziell abgebildet — jede Person behält ihren eigenen Mandantenordner unter ihrem Buchstaben; die Gruppe ist eine logische Entität mit Querverweisen im UI plus ein gemeinsamer Gruppenordner für geteilte Dokumente (…/<Buchstabe>/<Gruppenname> (grp<id>)/Gemeinsames/). Nicht physisch verschachtelt (Variante B verworfen). ⚠️ Weicht von der Kunden-Vorgabe ab ("Klammer wirkt auf die Ablage" war eher als Verschachtelung gemeint) → vor Umsetzung mit dem Kunden bestätigen. | Personen werden einzeln betreut (A hält die Einzelbetreuung unabhängig; Mitgliederwechsel erzwingt kein Verschieben); Ablage-Klammer via gemeinsamen Gruppenordner + Querverweise statt Vergraben der Einzelordner | vorläufig — Kundenbestätigung offen · OP-MANDGRP-1 |
| D-40 | 2026-07-05 | Betrieb/CI | Auto-Rerun bei flakigem self-hosted Runner (auto-rerun.yml): separater workflow_run-getriggerter Workflow stößt bei einem fehlgeschlagenen CI-Lauf die fehlgeschlagenen Jobs genau einmal neu an (run_attempt < 2, kein Loop). Nicht neugestartet: abgebrochene Läufe (Concurrency-Cancel = cancelled ≠ failure) und Fork-PRs (head_repository ≠ repository, RISK-24 gewahrt); Deploys ausgenommen. Dependency-frei via curl/rerun-failed-jobs (actions: write) — kein gh/Node-Action, keine node20-Warnung. | Heilt die typische self-hosted-Flakiness (github.com:443-Timeout, Runner mitten im Job gestorben) automatisch statt manuellem "Re-run failed jobs"; 1-Retry-Cap verhindert Endlos-Reruns; permanent hängender Runner = echter Ausfall, kein Flake (nicht durch Retry heilbar) | .github/workflows/auto-rerun.yml · agents.md §6.6 · taktano §6.8 (Gegenstück) · RISK-24 |
| D-41 | 2026-07-05 | Akte / R1 / UX | Prozessgegliederte Mandantenakte + strukturierte Aktenreife: (1) Die Akte (UC-6) wird von einem Modul-Stapel (10 gleichrangige Karten) auf ein prozessgegliedertes Dossier umgestellt — fester Aktendeckel (drei True-North-Kennzahlen Phase/Offen/Aktenreife + Phasen-Zeitstrahl) und Register = Prozessphasen (Erstkontakt→Onboarding→Beratung→Unterschrift→Betreuung) + Audit-Trail quer; jede Phase trägt ihre eigene Aktenreife-Teilbilanz; Druckansicht klappt alle Register auf. (2) Aktenreife wird von offenePunkte: string[] auf ein strukturiertes, phasen-zugeordnetes Modell (domain/aktenreife.ts: AktenreifePunkt{kategorie,phase,schwere,text,anzahl,sprungziel} + PhaseReife + score, rein abgeleitet G-2) gehoben. Kernentscheidung: nur schwere: 'blockierend' verhindert die Aktenreife — offene Wiedervorlagen sind hinweis (Verhaltensänderung: behebt das "nie aktenreif"-Problem der 365-Tage-Playbook-Wiedervorlage). score ist eine transparente Heuristik (100 − gewichtete Abzüge 25/10/4); reif bleibt autoritativ. | Ordnungsachse "wo im Mandat gehört das hin?" statt "welches Feature hat das erzeugt?" beantwortet True North #1 auf einen Blick (G-3); nutzt die vorhandene Phasen-Engine wieder; jePhase ist ein echtes Server-Aggregat, das den Cockpit-Leitstand-Proxy ablösen kann (OP-AKTE-1) | gebaut (0.38.0) · docs/architektur/Akte-Struktur.md · OP-AKTE-1 · Mockup-Freigabe durch Nutzer |
| D-42 | 2026-07-05 | R5 | Wiedervorlagen nachträglich editierbar + append-only Kommentar-Verlauf (R5-F12): (1) Betreff und Fälligkeit einer bestehenden Wiedervorlage sind nachträglich bearbeitbar (PATCH /api/wiedervorlagen/:id { betreff?, faelligAm? }, Service bearbeiten) — eine geänderte Fälligkeit reaktiviert die Erinnerung (erinnertAm: null, analog "verschieben"). (2) Jede Wiedervorlage trägt einen Kommentar-Verlauf — eigene Entität WiedervorlageKommentar / Tabelle wiedervorlage_kommentar (Migration v22, 1:n), je Eintrag Autor (aktuelle Identität R7) + Zeitstempel, umgekehrt chronologisch angezeigt, append-only & nicht editier-/löschbar (Nachvollziehbarkeit, G-4). POST /api/wiedervorlagen/:id/kommentare { text }; Audit wiedervorlage.kommentiert PII-arm (nur Autor + Länge, kein Text, G-5). Kommentare werden nur in den Detail-Listen (get/listByMandant) mitgeliefert, nicht in Cockpit-/Cron-Listen (Performance). | Tagesgeschäft braucht Korrektur bestehender Aufgaben ohne Neuanlage; ein knapper Verlauf hält den Bearbeitungsstand an der Aufgabe selbst (True North #2), ohne die Beratungsdoku (R6) zu vermischen; append-only + PII-armes Audit halten die Rechtssicherheit (G-4/G-5) | gebaut (0.39.0) · Nutzer-Anforderung (Folge-Slice zu D-41) · Migration v22 |
| D-43 | 2026-07-06 | Cockpit / Akte | Leitstand-Band nutzt das autoritative Aktenreife-Aggregat (schließt OP-AKTE-1): Neuer Endpunkt GET /api/aktenreife liefert je Mandant { reif, score, blockierend } — rein abgeleitet (G-2) über denselben Helper baueAktenreifeInput wie Service.detail() (eine Wahrheit, kein Doppel-Code). Das Cockpit-Leitstand-Band (leitReifeStufe) nutzt jetzt dieses Aggregat statt des bisherigen client-seitigen Proxys (Offen-Zahl + Onboarding-Fortschritt); grau ("in Anbahnung") bleibt für noch nicht begonnene Leads (kein Onboarding, Phase Erstkontakt), sonst gruen/amber/rot aus reif/Blocker-Zahl. | Der Proxy konnte von der echten Aktenreife (Detail) abweichen → widersprüchliche Ampeln im Portfolio-Band; das Aggregat macht Band und Detail deckungsgleich (True North #3). Kosten: je Mandant dieselben Sub-Entitäten-Queries wie offenePunkte() (nebenläufig), bewusst als eigener Endpunkt statt Kopplung an /offene-punkte. | gebaut (0.40.0) · schließt OP-AKTE-1 (D-41) · GET /api/aktenreife |
| D-47 | 2026-07-06 | Betrieb / Deploy | Build-/Deploy-Status in der App (Variante B — Push vom Deploy): Die App zeigt dezent im Header den letzten Deploy-Status ("✓/✗ Deploy vor Xm", Link auf den GitHub-Run). Kernentscheidung Push statt Pull: der Deploy-Workflow (app-deploy.yml) schreibt nach dem Lauf (if: always(), Ausgang aus job.status) ein kompaktes JSON {status,sha,runUrl,ranAt} direkt in D1 (einstellung-Store, Schlüssel deploy_status) via wrangler d1 execute --remote — mit dem ohnehin vorhandenen Cloudflare-Token (D1:Edit). Kein GitHub-Token im Worker, kein Access-Bypass, keine Rate-Limits (verworfen: Variante A = Worker→GitHub-API mit PAT; Variante C = Badge-Embed, scheitert an privatem Repo + CSP). Read-only-Endpoint GET /api/deploy-status (parst defensiv, domain/deploy-status.ts); Sichtbarkeit: alle eingeloggten Access-Nutzer (kein PII, reine Ops-Telemetrie). Bewusst kein True-North-Feature — Betriebs-Transparenz, admin-nah gehalten (nicht im Kunden-Cockpit, nur Header). | Integrate-before-build (G-1): nutzt den vorhandenen Deploy-Credential statt neuer Secret-/API-Kopplung; minimale Daten (G-5); "auf main gemergt = live" wird auch in der App sichtbar | gebaut (0.45.0) · Nutzer-Anforderung · OP-DEPLOY-1/Deploy.md · app-deploy.yml |
| D-46 | 2026-07-06 | Akte / UX / R1 | "Meaningful actions" — abgeleitete nächste Schritte (OP-NEXTSTEP-1): Die Akte zeigt nicht nur was fehlt (Aktenreife-Mängel), sondern was als Nächstes zu tun ist — eine geordnete Liste nächster sinnvoller Schritte als klickbare Buttons im Aktendeckel. Rein abgeleitet (G-2) aus demselben AktenreifeInput wie die Aktenreife (neue reine Funktion domain/naechste-schritte.ts, kein neuer Zustand, keine Persistenz): je offenem Zustand eine Handlungsempfehlung im Imperativ (G-3) mit Phase, Dringlichkeit (aus der Schwere) und Sprungziel; blockierend zuerst. Im MandantDetail mitgeliefert (naechsteSchritte); der Klick springt ins Register der Schritt-Phase und scrollt zum Ausführungs-Abschnitt (nutzt die bestehenden Register/Anker der prozessgegliederten Akte, D-44). Kernentscheidung: Erst-Slice = Navigation zum Ausführungsort (dort sitzt die eigentliche Aktion, z. B. "Onboarding starten"); ausführbare Ein-Klick-Aktionen (Self-Service-Link direkt senden etc.) bleiben Folge-Increment (OP-NEXTSTEP-1-Rest). | Beantwortet True North #2 ("was ist offen/fällig?") als Handlung statt nur als Diagnose (der Nutzer-Schmerz: "Onboarding kann hier nicht abgeschlossen werden"); nutzt das vorhandene Aktenreife-Modell + die Register-Navigation wieder (kein Doppel-Code, G-2); Navigation-first hält den Slice klein/robust und ohne Endpunkt-Kopplung | gebaut (0.44.0) · Nutzer-Anforderung (Screenshot Fokus-Karte) · domain/naechste-schritte.ts · OP-NEXTSTEP-1 |
| D-45 | 2026-07-06 | Datenmodell / R1 | Mandant = natürliche Person; "Praxis" → "Praxis/Gesellschaft" mit objektart: (1) Der Mandant ist konsequent eine natürliche Person und hält 0..n Praxen/Gesellschaften (Praxis.mandantId, 1:n bestand bereits). Das bisherige Feld Mandant.typ (praxis/mvz/sonstige) — das die Person mit der Organisation vermischte — entfällt (Migration v23 DROP COLUMN mandant.typ). (2) Die Objekt-Entität wird verallgemeinert: neues Feld Praxis.objektart (praxis · mvz · gesellschaft, R1-F28, Migration v23 additiv NOT NULL Default 'praxis', MVZ-Standorte auf 'mvz' zurückgesetzt) deckt Praxen und Gesellschaften/Beteiligungen ab. (3) Onboarding-Default-Vorlage wird jetzt aus der Objektart der (ersten) Praxis/Gesellschaft abgeleitet (vorlageFuerObjektart), ohne Praxis greift gesellschaft (Basis-Vorlage) — vorher war der (entfallene) Mandanten-Typ der Schlüssel. (4) UI-Folgen (client-only): Typ-Wahl aus dem Anlage-Formular entfernt, Objektart-Select je Praxis/Gesellschaft im Detail, Typ-Pille aus Cockpit/Detail/Akte entfernt, generiertes Dokument ohne "Mandantentyp"-Feld. Entität behält den technischen Namen Praxis (Tabellen-/Klassenname), Label wird "Praxis/Gesellschaft" — kein risikoreicher Tabellen-Rename. | Trennt sauber Person (Träger) von Organisation (Praxis/Gesellschaft) und löst die Doppelrolle des Mandanten (G-3); die geschäftliche Einordnung sitzt dort, wo sie hingehört und mehrfach vorkommen kann (0..n); Onboarding-Vorlage folgt der tatsächlichen Objektart statt eines person-fremden Typs. Vorwärts-kompatibel zur geplanten Personen-Gruppierung (D-32/OP-MANDGRP-1, noch nicht gebaut): die Gruppe ist eine referenzielle Klammer über Personen und ändert diese Struktur nicht; offene Feinheit dort: eine gemeinsam gehaltene Gesellschaft (BAG/MVZ-GmbH) könnte auf Gruppen-Ebene bzw. als m:n-Beteiligung hängen statt an einer einzelnen Person (Praxis.mandantId). | gebaut (0.42.0) · Nutzer-Anforderung · Migration v23 · Lastenheft §4.1 R1-F28 · vgl. D-32/OP-MANDGRP-1 |
| D-50 | 2026-07-06 | Datenschutz / Audit | Datensparsamkeit (G-6) + Zugriffs-(Lese-)Protokollierung sensibler Entitäten festgezurrt: (1) Neues Leitprinzip G-6 "Datensparsamkeit & Scrubbing-at-Source (ingress)" — so wenig PII wie möglich; Reduktion/Pseudonymisierung/Verwerfen am Eingang (API-Grenze, Import, Transkription, Webhook, Logger), Default "nicht speichern", jede neue PII-Persistenz begründet (schärft G-5; Anker RISK-1/22/23). (2) Lesezugriffe werden nicht pauschal protokolliert (wäre selbst PII-/Rausch-Risiko + G-6-Verstoß), sondern gezielt auf einer Whitelist sensibler Entitäten (Beratungsdoku/Beratungsprotokoll R6 · Gesundheitsbogen R6-F18 · signierte Dokumente/Verträge/Vollmachten R4 · vollständige Mandantenakte · Dexman/PVS-nahe Art.-9-Daten) als append-only, PII-armes Audit-Event aktion=eingesehen (nur Actor/Entity-ID/ts/trace_id — kein Inhalt, kein Diff) in der bestehenden R8-Hash-Kette + verify. Cockpit-/Listen-/Leitstand-/Navigations-Ansichten bewusst nicht einzeln (Datenminimierung). (3) Nebenbedingung Mitarbeiterschutz: das Zugriffslog darf nicht zur verdeckten Leistungs-/Verhaltenskontrolle eigener Mitarbeiter zweckentfremdet werden (§87 Abs.1 Nr.6 BetrVG, Nähe RISK-11/21/26) → strikte Zweckbindung (Missbrauchserkennung + Breach-Aufklärung + Betroffenenauskunft Art.15), Betriebsrat beteiligen (KB-3). Enum-Wert eingesehen (G-3-konform, statt zugriff). | Reine Änderungs-Protokollierung (Slice 6) deckt "wer hat was getan" ab, nicht "wer hat sensible Daten gesehen" — für Art.-9-/rechtsrelevante Daten ist Zugriffs-Nachvollziehbarkeit State of the Art (Art. 5(2)/24/32/33 DSGVO, revDSG, ISO 27001 A.12.4) und Grundlage für Missbrauchs-/Breach-Erkennung; Whitelist statt Alles-Loggen hält G-6/Datenminimierung; Wiederverwendung der vorhandenen Audit-Kette statt Sonderpfad | gebaut (0.46.0): domain/zugriff.ts (Whitelist), AuditLog.protokolliereZugriff(), verdrahtet an GET /api/mandanten/:id · …/beratungsdoku · …/dokumente/:id/datei; +7 Vitest · G-6, RISK-27, KB-3 · docs/architektur/Audit-Log.md · Compliance-Tracker #6 · Nutzer-Anforderung |
| D-44 | 2026-07-06 | Akte / UX | Arbeitssicht (Mandant-Detail) auf dieselbe prozessgegliederte Dossier-Struktur wie die Akte umgestellt: Die Hauptseite /mandant/:id bekommt den Aktendeckel (3 True-North-Kennzahlen Phase/Offen/Aktenreife-Ring + klickbarer Phasen-Zeitstrahl) und Register = Prozessphasen (Erstkontakt/Onboarding/Beratung/Unterschrift/Betreuung + Verlauf) statt des langen Scrolls mit Sprungmarken-Navigation — alle Editier-Controls bleiben (Sektionen werden nur je Register ein-/ausgeblendet, [hidden]). Startregister = aktuelle Prozessphase (nur beim ersten Laden). Rein Client (mandant-detail.component.ts), nutzt die vorhandenen Akte-CSS-Klassen (md-kpis/md-stepper/md-regnav). | Nutzer erwartete die neue Akten-Optik auf der Arbeitsseite, nicht nur in der separaten "Akte/Druckansicht" — die Detailseite ist die primäre Arbeitsfläche; Deckel + Register machen True North #1/#3 auch dort auf einen Blick sichtbar (G-3), ohne die Editierbarkeit zu verlieren. | gebaut (0.41.0) · Nutzer-Anforderung (Folge zu D-41) · live via Playwright verifiziert |
| D-48 | 2026-07-06 | R7 / RBAC | RBAC je Mandant + zentrale Rechte-Matrix (OP-AUTH-1-Rest): (1) Neue reine Domänenfunktion domain/rechte.ts — Rolle×Fähigkeit-Matrix (darf, eine Wahrheit G-2) ersetzt die bisherige binäre admin-Prüfung (istAdmin), macht berater/backoffice unterscheidbar (Fähigkeiten benutzer_/einstellungen_/playbooks_verwalten, mandant_sehen_alle/_bearbeiten/_zuweisen). (2) Mandant-Scope über verantwortlich (R1-F06): ein berater sieht/bearbeitet nur eigene + unzugeordnete Mandanten (verantwortlich = null → gemeinsamer Lead-Pool), backoffice/admin alle. Durchsetzung an zwei Chokepoints — service.sichtbareMandanten(akteur) für die Aggregate + Middleware auf /api/mandanten/:id* (Fremd-Mandant → 404 statt 403, kein Existenz-Leak; Schreiben verlangt mandant_bearbeiten). (3) Zuweisung POST /api/mandanten/:id/zuweisen { email|null } (Guard mandant_zuweisen, validierte R7-Referenz, Audit mandant.zugewiesen); PATCH verantwortlich verlangt dieselbe Fähigkeit. (4) Feature-Flag rbac_mandant_scope_aktiv (Tenant-Einstellung, Default aus) — bei aus liefert der Scope unverändert alle. Kein Schema-Migration (Feld existierte). Client: Zuweisen-Select im Aktendeckel (backoffice/admin, mit Bestätigung), api.mandantZuweisen; lesende Liste GET /api/benutzer/zuweisbar (Guard mandant_zuweisen), damit backoffice die admin-only Benutzer-Verwaltung nicht braucht. | Löst die bisher zu grobe RBAC (nur admin/nicht-admin) auf und beantwortet den Nutzer-Bedarf "feingranulares User-Management". Kernentscheidung gegen "Mandanten verschwinden": null-sichtbar-Default + Feature-Flag + Rollout "erst zuweisen, dann scharfschalten" — Bestandsdaten (verantwortlich meist null) bleiben nach Aktivierung sichtbar; 404 statt 403 verhindert Existenz-Leaks; zwei Chokepoints statt Route-für-Route senken das Risiko einer vergessenen Route (Sub-Entitäts-Routen mit eigener Objekt-ID = OP-AUTH-1-Rest/RISK-10). | gebaut (0.46.0) · Nutzer-Anforderung · domain/rechte.ts · Lastenheft §4.8a · vgl. OP-AUTH-1 · D-47 = #77 (Deploy-Status) |
| D-49 | 2026-07-06 | Akte / R13 / UX | Prominente Live-Zeiterfassung auf der Mandantenakte + "Zeiten & Abrechnung"-Register: (1) Die Arbeitssicht /mandant/:id bekommt oben einen prominenten Live-Timer, der beim Öffnen der Akte sofort startet (Stoppuhr HH:MM:SS), darunter ein Kommentar-Feld "Was wurde getan?". Der Timer ist pausierbar/fortsetzbar und überschreibbar (erfasste Zeit manuell auf X Minuten setzen). "Zeit buchen" schreibt gerundete Minuten über das bestehende Leistungszeit-Ledger (leistungszeitErfassen, R13) — Kommentar Pflicht — und lässt danach einen frischen Timer weiterlaufen. (2) Beim Verlassen der Akte fragt ein CanDeactivate-Guard (zeiterfassung.guard.ts) die erfasste Zeit ab: ab der Schwelle öffnet ein Modal, das Buchen (mit Pflicht-Kommentar) oder Verwerfen verlangt, bevor navigiert wird; "Zurück zur Akte" setzt den Timer fort; beforeunload warnt beim Browser-Schließen. (3) Die bisher erfasste Zeit samt Abrechnung (geleistet/abgerechnet/offen/bezahlt + "Als abgerechnet markieren" + Rechnungen/Mahnungen via SevDesk) zieht aus dem Beratung-Register in ein eigenes Register "Zeiten & Abrechnung" neben "Verlauf". (4) Nachfrage-Schwelle (zeiterfassung_schwelle_minuten, Default 1/0..240) + Buchungs-Rundung (zeiterfassung_rundung_minuten, Default 0/0..60, Aufrunden auf Vielfache, z. B. 15) sind admin-konfigurierbar über den einstellung-Katalog; die Rundungsregel domain/einstellungen.ts#buchungsminuten ist server-getestet (Single Source), der Client spiegelt sie. Kernentscheidung: Der Timer läuft rein im Client — kein neuer Timer-Zustand auf dem Server, keine Timer-Persistenz (Zeit wird geleistet und einmal gebucht, G-2); die Konfiguration (Schwelle/Rundung) nutzt bewusst den vorhandenen einstellung-Store (kein neuer Persistenzpfad). Rechnungen/Mahnungen bleiben extern (SevDesk, OP-INVOICE-1), Medidentas dupliziert sie nicht (G-1). | Macht die Zeiterfassung zur beiläufigen Standard-Handlung statt zur vergessenen Nacharbeit (True North #3: lückenlose, abrechenbare Leistungsdoku) — "öffnen = Uhr läuft", "verlassen = bestätigen" schließt die häufigste Erfassungslücke; kein Doppel-Speicher/kein Nachbau des Fakturierens (G-1/G-2). | gebaut (0.47.0) · Nutzer-Anforderung · zeiterfassung.guard.ts · R13/OP-TIME-1 · OP-INVOICE-1 |
| MED-D-51 | 2026-07-06 | Governance / IDs | Projekt-Kürzel MED für neue IDs & Chat-/Session-Namen: Ab dieser Entscheidung tragen neu vergebene IDs (Entscheidungen, offene Punkte etc.) sowie Chat-/Session-Namen das Präfix MED- (z. B. MED-D-51, MED-OP-<Thema>-n, Session MED-<Datum>-<branch-slug>). Bestehende IDs bleiben unverändert (kein retroaktiver Massen-Umbau) — Alt-/Neu-Bestand koexistiert; Alt-IDs werden erst beim nächsten inhaltlichen Anfassen mitgezogen. Diese Zeile ist selbst die erste MED-präfixierte ID. | Ein Projekt-Kürzel macht IDs global (repo-/toolübergreifend) eindeutig und projektzuordenbar; "nur ab jetzt" vermeidet einen risikoreichen, konfliktträchtigen Sweep über hunderte Bestandsreferenzen (G-2-Nutzen ohne G-2-Risiko). | Nutzer-Anforderung · CLAUDE.md §ID-System · docs/konventionen/agents.md §4 |
| MED-D-52 | 2026-07-06 | Governance / Tooling | CodeRabbit-Review konfiguriert + Empfehlung "Required Check": Neue .coderabbit.yaml (repo-lokal statt nur Org-UI) trimmt Reviews auf das Wesentliche — Poem/Sequenzdiagramm/Changed-Files-Summary aus, knowledge_base.issues.scope: local (stoppt die fehlschlagenden externen Issue-Fetches, die unsere OP-*-IDs fälschlich als Tracker-Keys interpretierten), path_filters schließen generierte Dateien (Lockfile, build-number.ts, client/dist) aus. Doku bleibt bewusst im Review-Scope. Zusätzlich Empfehlung (Admin-Schritt, nicht per Code): den Status-Context CodeRabbit als Required Check auf main aufnehmen — dann wartet der Merge auf das abgeschlossene Review (Gate = "Review lief", nicht "keine Findings"). | Schnellere, rauschärmere Reviews (Config, nicht CodeRabbits Serverzeit); der lokale Issue-Scope beseitigt echte Fehlversuche. Required-Check bewusst als Empfehlung dokumentiert, weil er ohne die Beschleunigung zum Flaschenhals würde und Branch-Protection Admin-Rechte braucht (nicht via API/MCP in der Session verfügbar). | Nutzer-Anforderung · .coderabbit.yaml · vgl. agents.md §6.5 (nicht-automatisierbare Repo-Settings) |
| MED-D-66 | 2026-07-06 | Stack / Backlog | Angular 22 bewusst aufgeschoben — Trigger + Kriterien festgehalten (MED-OP-NG22-1): Kein Sprung auf Angular 22 "nur wegen aktuell". Inhaltlicher Treiber, der 22 rechtfertigt = Signal Forms (in 22 stable), dazu @angular/aria (GA, A11y-Track D-22) und httpResource (stabile Signal-Datenschicht). 22 ist zudem ein Sicherheits-Release (Sanitization; SSRF-Schutz aber v. a. platform-server/SSR → für die reine SPA irrelevant). Aufschub-Grund: TypeScript 6 wird Pflicht (5.9 raus) und @angular/cli@22 verlangt Node ≥ 22.22.3 (CI/Umgebung 22.22.2) → 22 zieht zwingend ein Node-/Toolchain-Upgrade nach, das nicht in einen reinen Versions-Bump gehört. Entscheidung: 22 beim nächsten größeren Formular-/Fragebogen-Increment als bewusst geplanten PR "Node-Bump + Angular 22 + erstes Signal-Form" umsetzen (Nutzen wird dann real genutzt), nicht als Selbstzweck. Webpack-Deprecation in 22 unkritisch (App nutzt esbuild-Builder). | "Recent" ohne genutzten Mehrwert rechtfertigt kein Toolchain-Risiko; der Umstieg lohnt erst, wenn Signal Forms/@angular/aria tatsächlich eingesetzt werden — dann Node-Bump + Migration + Feature in einem geplanten Schritt statt blind. | Nutzer-Frage "welche Angular-22-Features interessant?" · Folge zu MED-D-53 · MED-OP-NG22-1 · Angular-v22-Release-Notes (05.06.2026) · umnummeriert von doppelt vergebenem MED-D-54 (Log-Hygiene OP-PM-1 — die parallele Ablage-Entscheidung behält MED-D-54; kein inhaltlicher Change) |
| MED-D-53 | 2026-07-06 | Wartung / Stack | Dependency-Bump Angular 19 → 21 (Client) + React 18 → 19 (Doku-Site): client/ @angular/* ^19 → ^21.0.0 (LTS 21.2.x) + typescript ~5.6.3 → ~5.9.0 (Angular-21-Peer >=5.9 <6.0); docs-site/ react/react-dom ^18 → ^19.0.0, @docusaurus/* ^3.6 → ^3.10.1 (React-19-Peer erst ab 3.10) und @easyops-cn/docusaurus-search-local ^0.45 → ^0.55 (React-19-Peer; ^0.45 cappt bei React 18). Beide Lockfiles neu erzeugt. | Kernentscheidung Angular 21 statt 22 (latest): @angular/cli@22 verlangt Node `^22.22.3 | |
| MED-D-54 | 2026-07-06 | A-1-Revision / Ablage | Geschlossene Ablage — Verzicht auf NextCloud (vorläufig, Kundenbestätigung offen → MED-KB-4): Dateien werden eigenverwahrt (Variante V2 "R2 + App-UI": Cloudflare R2, EU-Jurisdiction, Bucket Locks/WORM als GoBD-Anker) und sind ausschließlich über die Medidentas-UI zugänglich — keine Nutzer-Eingriffe an der App vorbei (kein Sync, keine fremde Web-UI). Eine NextCloud-Anbindung kann später als "read-only"-Sicht ergänzt werden (Spiegel/Export der Ablage zum Stöbern; schreibend bleibt die App der einzige Pfad). Der bestehende NextCloudClient-Vertrag bleibt als Storage-Abstraktion (R2-Treiber dahinter, FakeNextCloud-Tests weiter gültig). Dokumentierte Nebenwirkung: auch eine Read-only-Sicht umgeht das Lese-Zugriffslog (D-50) — Umfang bei Aktivierung klären. | "Keine Nutzer-Eingriffe" (Nutzer-Vorgabe 06.07.) entwertet den NextCloud-Funktionsumfang (Sharing/Sync/Web-UI unerwünscht); G-1-Eigenbau begründet: jeder zweite Zugriffspfad an der App vorbei untergräbt die lückenlose, rechtssichere Dokumentation (G-4) und das Zugriffslog (D-50); RBAC (D-48) wird by design lückenlos; R2 ist schon im Stack (A-4) | MED-OP-FILES-1 · MED-KB-4 · A-1/A-4 · D-48/D-50 · Dokumentenverwaltung-NextCloud.md §Nachtrag |
| MED-D-55 | 2026-07-06 | R3/R9 NextCloud | NextCloud "besser per API": öffentlicher Upload-Link + Webhook + Auth-Entscheidung (Phase 2, OP-DOC-1-Rest): (1) Öffentlicher Upload-Link ("File Drop") je Dokument über die OCS Sharing API (shareType=3, permissions=4, publicUpload=true) auf einen dokument-eigenen Ordner …/Eingang/<dokumentId> — der Kunde lädt ohne NextCloud-Account hoch. Vertrag NextCloudClient.erstelleUploadLink() (+ Fake), persistiert Link + Share-Token am Dokument (R3-F10/F11, Migration v25), Route POST /api/dokumente/:id/upload-link (idempotent), UI-Button. (2) Webhook (Push statt Polling, RISK-6): öffentlicher Endpunkt POST /oeffentlich/nextcloud/webhook (außerhalb Access, wie /oeffentlich/*), Shared-Secret-Header (NEXTCLOUD_WEBHOOK_SECRET); der gemeldete Datei-Pfad wird über Eingang/<dokumentId> exakt aufs Dokument zurückgeführt und angefordert → erhalten gehoben (idempotent). Quelle = Webhook Listeners App (NC ≥ 30, NodeCreatedEvent); notify_push/WebSocket verworfen (Worker-untauglich). Pull-abgleich bleibt Fallback. (3) Auth: OAuth2 verworfen (NextCloud-OAuth2 kann kein client_credentials/kein Scoping) → App-Passwort auf einem technischen Service-User (nicht je Benutzer ein Account); Deploy-Workflow synchronisiert NEXTCLOUD_* aus GitHub-Secrets in den Worker (idempotent, leere übersprungen). WebDAV bleibt die kanonische Datei-API (Stub war schon fertig). | "Besser per API" heißt nicht WebDAV ersetzen, sondern komplementäre OCS-/Webhook-APIs ergänzen, die echten Prozess-Mehrwert bringen (True North "was fehlt?" — Kunde lädt selbst hoch; Push statt Polling). Service-User statt per-User: Audit lebt in Medidentas (G-4), per-User = doppeltes Lifecycle/Seat-Kosten + OAuth2 trägt Maschinen-Zugriff ohnehin nicht. | gebaut (0.49.0) · PR #? · Dokumentenverwaltung-NextCloud.md · Migration v25 · RISK-6/RISK-16 · Nutzer: "NextCloud besser per API + Zugang liegt bereit" |
| MED-D-56 | 2026-07-06 | R3/R9 NextCloud | Sandbox-fähige Ablage-Wurzel + Invariante "nie löschen": (1) Der Ablage-Basisordner (Wurzel aller Mandanten-Ordner) ist konfigurierbar über die Var NEXTCLOUD_BASIS_ORDNER (Default Medidentas/Mandanten) — für eine Sandbox/Test-Trennung (Nutzer-Vorgabe medidentas-digital-test) liegen Test-Dateien sichtbar getrennt von der Produktion. Umsetzung: domain/ablage.ts setzeBasisOrdner()/basisOrdner(), einmal aus dem Env gesetzt (Deployment-immutabel); mandantOrdner ist der einzige Chokepoint → alle Pfade (Datei/Upload/signiert/Eingang) folgen automatisch. (2) Invariante "nie löschen" (verbindlich): die NextCloud-Anbindung löscht niemals (keine delete()/DELETE-Methode im NextCloudClient-Vertrag — per Test abgesichert); erlaubt sind nur Anlegen (MKCOL/PUT/OCS-Share), Lesen (HEAD/PROPFIND/GET) und Umbenennen/Verschieben (WebDAV MOVE). put()-Überschreiben ist durch NextCloud-Versionierung verlustfrei; Retention/Löschung ist ein separater, bewusst manueller Prozess außerhalb der Integration. | Sandbox schützt Produktivdaten beim Erproben; ein umgebungsgetrennter, sichtbar benannter Ordner ist die einfachste sichere Trennung (eine Var, kein Fork). "Nie löschen" wahrt Rechtssicherheit/Aufbewahrung (G-4, GoBD/§147 AO) und verhindert, dass ein Secret-Leak am geteilten Service-User zum Massen-Löschen führt (Nähe RISK-8/16). | gebaut (0.49.0) · domain/ablage.ts · nextcloud/client.ts (Invarianten-Kommentar) · Nutzer: "Sandbox medidentas-digital-test" + "darf niemals löschen, nur anlegen/umbenennen" |
| MED-D-57 | 2026-07-06 | Konvention/Doku | Repo-übergreifendes ID-Schema (Repo-Key-Registry MED/TKT/GRM): Für repo-übergreifende Referenzen wird eine ID mit dem Repo-Key qualifiziert (analog GitHubs owner/repo#123) — medidentas→MED, taktano→TKT, gh-self-hosted-runners-director (gh-runner-manager)→GRM (z. B. TKT-OP-CI-2, GRM-OP-2). Verhältnis zu MED-D-51: medidentas hat den Key MED inzwischen (MED-D-51) zum stehenden Präfix neuer IDs erhoben — neue medidentas-IDs sind ohnehin MED-…; diese Registry ergänzt die Fremd-Repo-Keys TKT/GRM und hält die drei Keys projektweit konsistent. Bestehende bare Alt-IDs bleiben unverändert (kein Massen-Umbau). | Repo-übergreifende Eindeutigkeit ohne Massen-Umbenennung (Einfachheit/YAGNI); die Registry MED/TKT/GRM ist die gemeinsame Klammer über die Repos, MED-D-51 ist ihre medidentas-lokale Anwendung. | beschlossen · verankert in agents.md §3 (+ taktano IDs.md, GRM open-points.md) · vgl. MED-D-51 · ehem. D-33 (umnummeriert wg. Kollision mit Dentmarking-D-33) |
| MED-D-58 | 2026-07-06 | A-1-Revision / Ablage | Geschlossene Ablage V2 "R2 + App-UI" gebaut (setzt MED-D-54 um; umschaltbar, Default aus): Neuer Storage-Treiber server/src/ablage/r2.ts (R2Ablage) implementiert den bestehenden NextCloudClient-Vertrag gegen Cloudflare R2 — Ordner = Marker-Objekte (R2 kennt keine Ordner), put() sichert die Vorfassung unter _versionen/<pfad>/<ts> (verlustfreies Überschreiben; R2 hat keine eingebaute Versionierung), keine Lösch-Operation (Invariante MED-D-56 gilt weiter, per Test). Upload-Link = App-eigene öffentliche Route GET/POST /oeffentlich/ablage/upload/:token (selbst ausgeliefertes HTML-Formular, Token-Marker _uploadlinks/<token>.json mit optionalem Ablaufdatum; Status-Hub angefordert→erhalten + Audit über denselben Pfad-Mechanismus wie der NextCloud-Webhook) → auch der Kunden-Upload läuft durch die App. Umschaltung: ABLAGE_BACKEND=r2 + R2-Binding ABLAGE_BUCKET (wrangler.toml auskommentiert + Aktivierungs-Runbook: Bucket --jurisdiction eu, optional Bucket Lock/WORM); Default bleibt NextCloud/Fake. Dienste R3/R12/R4 unverändert (Storage-Abstraktion). | Setzt die vorläufige Entscheidung MED-D-54 technisch um, ohne die ausstehende Kundenbestätigung zu präjudizieren (Schalter-Muster wie rbac_mandant_scope_aktiv, D-48): Code produktionsreif, Aktivierung = bewusster Config-Schritt nach Bestätigung (MED-KB-4 Punkt 0). Ein Zugriffsweg → RBAC (D-48) + Zugriffslog (D-50) by design lückenlos. | gebaut (0.50.0) · +10 Vitest (300/31) · end-to-end via wrangler dev + lokalem R2 verifiziert · MED-D-54 · MED-KB-4 · Dokumentenverwaltung-NextCloud.md §Nachtrag |
| MED-D-59 | 2026-07-06 | Governance / Tooling | CodeRabbit auto-merge-tauglich & rate-limit-sicher (schärft MED-D-52): (1) Required Check — der Commit-Status-Context CodeRabbit (commit_status: true) wird in der Branch-Protection von main neben CI Gate als Required Check hinterlegt (Admin-/UI-/gh api-Schritt, nicht via MCP), sodass Auto-Merge erst nach abgeschlossenem Review greift. (2) Rate-Limit-Schutz: fail_commit_status: false — ein rate-limitierter/nicht durchführbarer Review setzt kein failure, sondern bleibt pending und löst sich beim Zurücksetzen des Limits bzw. per @coderabbitai review auf → kein Dauer-Deadlock des Auto-Merge (ein failure würde hart blocken). (3) auto_incremental_review: true bleibt an — Voraussetzung für den Required Check: jeder Head-Commit muss einen eigenen CodeRabbit-Status bekommen (sonst blockt ein statusloser Folge-Commit dauerhaft). (4) Nur bei offenem PR: CodeRabbit reagiert ausschließlich auf pull_request-Events (Branches ohne PR werden nie reviewt), drafts: false schließt zusätzlich Entwürfe aus. (5) Kompakter: collapse_walkthrough: true + erweiterte path_filters (docs-site/build, *.min.js) — Walkthrough/Summary-Doku bleibt erhalten. | Auto-Merge braucht einen deterministischen, nicht selbst-blockierenden Gate; fail_commit_status:false + pending ist der einzige Weg, "Review muss gelaufen sein" zu erzwingen, ohne dass ein transientes Rate-Limit den Merge tötet. Bewusster Trade-off: per-Commit-Pflichtcheck ⇒ incremental review AN ⇒ mehr Review-Kommentare (Alternative "nur CI Gate required + einmaliges Review" dokumentiert). Tooling-Config ⇒ keine Versionsänderung (analog MED-D-52). | Nutzer-Anforderung (Required Check · Rate-Limit · kompakter · nur bei PR) · PR #86 · .coderabbit.yaml · agents.md §6.5 (Branch-Protection = nicht-automatisierbar) |
| MED-D-60 | 2026-07-06 | Governance / Prozess | Rate-Limit-Schutz auf der Demand-Seite: Draft-PR-Workflow für alle Agenten (ergänzt MED-D-59). Reframing: CodeRabbit-Rate-Limits sind ein Volumen-Problem (# PRs × # gereviewte Pushes × Dateien) — viele parallele Agenten-Sessions, die WIP wiederholt pushen, feuern bei auto_incremental_review je Push ein Review. Höchster Hebel ist daher das Agenten-Verhalten, nicht die CodeRabbit-Config. Verbindliche Konvention (agents.md §7): Feature-PRs werden als Draft geöffnet und im Draft frei bepusht (CodeRabbit reviewt Drafts nicht → drafts: false → 0 Reviews im WIP), erst bei "ready for review" reviewt CodeRabbit einmal den Endstand + Auto-Merge scharf → "Reviews/PR" von N auf ~1. Gate implizit = allein der Draft-Status (kein Extra-review:ready-Label, weniger Reibung für Agenten). Wirkt org-weit, weil alle Sessions agents.md/CLAUDE.md zu Beginn lesen (SessionStart-Hook). Bewusst KEINE ignore_usernames-Bot-Ausnahme (ursprünglich für dependabot[bot] erwogen): da CodeRabbit Required Check ist, würde ein vom Review ausgenommener Bot-PR den Status nie erzeugen und dauerhaft am Gate hängen (CodeRabbit-Review-Finding, PR #86) — Dependabot-PRs (geringes Volumen) werden daher mitreviewt. | Symptom-Bekämpfung (fail_commit_status:false) mildert nur; die Ursache ist Volumen. Draft-until-ready eliminiert den Incremental-Review-Burst UND löst zugleich "kompaktere Ausgabe" (1 Walkthrough statt je Push) UND behält den per-Commit-Required-Check (der "ready"-Head-Commit trägt den Status). Implizit statt Label = kein vergessbarer Handgriff; Bot-Ausnahme verworfen, weil sie mit dem Required Check kollidiert. | Nutzer-Anforderung "controlling Claude and other agents better · label gate implicit" · PR #86 · .coderabbit.yaml · agents.md §7 · schärft MED-D-59 |
| MED-D-61 | 2026-07-06 | A-1-Revision / Ablage | Geschlossene Ablage R2 scharfgeschaltet (setzt MED-D-54/58 aktiv): Der R2-Bucket medidentas-ablage (EU-Jurisdiction, G-5) ist angelegt; in server/wrangler.toml sind ABLAGE_BACKEND = "r2" + das [[r2_buckets]]-Binding ABLAGE_BUCKET einkommentiert. Ab dem Merge/Deploy läuft die Datei-Ablage (R3 Dokumente · R12 PDF · R4 signierte Fassungen · Kunden-Upload) ausschließlich über R2 hinter dem NextCloudClient-Vertrag — ein Zugriffsweg (App), RBAC (D-48) + Zugriffslog (D-50) ohne Bypass. NextCloud wird nicht mehr benutzt (Secrets dürfen gesetzt bleiben, werden ignoriert). Keine Code-Änderung, keine Versionsänderung (Config/Aktivierung, APP_VERSION bleibt 0.50.0). | Betreiber hat den Bucket angelegt und die Scharfschaltung angewiesen (setzt die Kundenbestätigung MED-KB-4 Punkt 0 voraus). Upload-Route /oeffentlich/ablage/upload/* liegt bereits im bestehenden /oeffentlich*-Access-Bypass (kein neuer manueller Schritt). Offen/Flag: Ablage-Wurzel NEXTCLOUD_BASIS_ORDNER steht weiterhin auf der Sandbox medidentas-digital-test (bewusst für die Erst-Aktivierung; vor echtem Produktivbetrieb auf Medidentas/Mandanten bzw. [env.production] umstellen); WORM/Bucket-Lock optional per CLI. | MED-D-54/58 · MED-KB-4 · D-48/D-50 · wrangler.toml · Deploy.md |
| MED-D-62 | 2026-07-06 | Prinzip / Betriebskosten | Neues Leitprinzip G-7 "Betriebskosten automatisch ziehen" (cost-pull-at-source): Laufende Infrastruktur-/Cloud-/API-Kosten (Cloudflare, LLM/KI, Domain, Signatur-/Ablage-Hosting) werden je Dienst direkt aus dessen Billing-/Usage-API gezogen (periodisch per Cron + on-demand), nicht von Hand gepflegt; manuelle Erfassung nur als Fallback/Bootstrap. Provider-Keys als Secrets (G-5), dormant ohne Secret; Idempotenz-Key je Dienst×Monat; Pull = Audit-Event (G-4); Kosten = abgeleitete Cent-Sicht, nie doppelt persistiert (G-2). Abzugrenzen von SevDesk/OP-INVOICE-1 (ausgehende Mandanten-Rechnung) — G-7 zählt die eingehenden Betriebskosten. Übernommen aus Taktano OP-COST-2 (dort gebaut). Design als docs/architektur/Kosten.md, Bau als MED-OP-COST-2 (Slices) geparkt. | Nutzer-Vorgabe "alle Kosten durch Infrastruktur automatisch ziehen (sh. taktano); das auch in medidentas einbauen". Die Zahl an der Quelle abholen statt abtippen = weniger Fehler, immer aktuell, Everything-as-Code (Secrets/CI-Sync); Entscheidung landet erst als .md, Bau folgt als Slice. | beschlossen (Guidance) · Bau offen (MED-OP-COST-2) · G-7 · docs/architektur/Kosten.md · CLAUDE.md §Leitprinzipien · Taktano OP-COST-1/2 |
| MED-D-63 | 2026-07-06 | R12 / R4 / Formulare | Ausfüll-Formulare mit rechtsverbindlicher Einreichung (Phase 1 vor der echten E-Signatur): Ein Dokument wird aus dem Stammsatz vorausgefüllt (gesperrte Fest-Felder), der Kunde ergänzt die offenen Felder über einen öffentlichen Token-Link (ohne Login, wie Onboarding), seine Angaben werden strukturiert erfasst (kundenWerte, in der Akte auswertbar — nicht nur ins PDF gebrannt, G-2). Statt einer Unterschrift zeigt er eine Vorschau und reicht rechtsverbindlich ein: Willenserklärung + Beleg-Nr. + Prüfsumme (Inhalts-Hash, G-4) + Audit formular.eingereicht (PII-arm) + Beleg-PDF in der Ablage (R3). Niveau = SES (einfache elektronische Signatur) — genügt für formfreie/Textform-Dokumente; formgebundene Verträge brauchen weiterhin Phase 2 (echte E-Signatur DocuSign, AES/QES). Neu: domain/ausfuellformular.ts (Vorlagen-Katalog fest+offen, Scrubbing G-6), api/ausfuellformular-service.ts, Entität Ausfuellformular + Tabelle (Migration v26), Routen intern (/api/mandanten/:id/ausfuellformulare, /api/ausfuellformular-vorlagen) + öffentlich (GET/PUT /oeffentlich/formular/:token, POST …/einreichen), Client formular-public.component.ts (Route /formular/:token) + interne Sektion in der Akte. | Der differenzierende Kern ist die Erhebung strukturierter Kundenangaben + rechtssicherer Beleg — DocuSign/PandaDoc liefern Signatur, nicht dieses Mapping (G-1-Eigenbau begründet, wie R12). Phase 1 liefert sofort Nutzen (vollständige Daten im System) ohne die Signatur-Integration abzuwarten; "rechtsverbindlich" ≠ "unterschrieben" wird bewusst getrennt (Rechtssicherheit). Bestätigungstext juristisch abnehmen (RISK-18). | gebaut (0.51.0) · +17 Vitest (317/32) · end-to-end via wrangler dev + D1 verifiziert · MED-KB-5 · R12/R4 · OP-SIGN-1 |
| MED-D-64 | 2026-07-06 | Security / RBAC | OP-DM-9 behoben — Fragebogen-Statistik-Endpoint admin-gated: GET /api/fragebogen/statistik gab aktiveEntwuerfe[] inkl. Einladungs-token (auth-loser Zugang zum Fragebogen-Entwurf) an jede authentifizierte Rolle aus — nur die Anzeige war seit 0.37.0 admin-beschränkt, der Endpoint nicht (Defense-in-Depth-Lücke). Umsetzung: neue admin-exklusive Fähigkeit fragebogen_statistik_sehen in der Rechte-Matrix (domain/rechte.ts), Route via guard(c, …) → 403 gegated. | Bewusst über die RBAC-Matrix (MED-D-48, "eine Wahrheit" G-2) statt eines inline-rolle==='admin', wie es der ursprüngliche OP-DM-9-Vorschlag (vor MED-D-48) andachte — konsistent zu allen anderen Verwaltungs-Routen; dedizierte Fähigkeit (statt einstellungen_verwalten mitzubenutzen) ist selbsterklärend (G-3). Token-Leak = G-5-Verstoß, daher PATCH-Sicherheitsfix. | gebaut (0.51.1) · +2 Vitest (319/32) · rbac.test.ts + rechte.test.ts + app.ts + rechte.ts · schließt OP-DM-9 · Ursprung Review PR #65 |
| MED-D-65 | 2026-07-07 | Konvention / Branching | Stacked/Child-Branches + Squash-Rebase-Konvention (+ Cross-Repo-Best-Practice-Kandidat): Getrennt reviewbare Teilschritte komplexer Changes dürfen als Stack laufen (main ← feature-basis ← feature-child). Regeln: bottom-up mergen (GitHub retargetet offene Child-PRs automatisch auf main; Child-Branch überlebt), nach jedem Parent-Merge das Child git rebase --onto main <alte-basis> <child> + --force-with-lease (nötig, weil Squash-only einen neuen Commit erzeugt ≠ Original-Basis-Commits), Child bis rebased als Draft (MED-D-60 → CodeRabbit reviewt nur den finalen Diff). Default bleibt "ein Branch, mehrere Commits, ein PR". Klarstellung: "Automatically delete head branches" löscht nur den Head gemergter PRs → stört Stacking nicht. | Bei Squash-only + Stacking ist die Rebase-Reibung real und wiederkehrt — als Konvention festgehalten, damit komplexere Changes planbar sind (nicht ad hoc). "Ein Branch" als Default hält die einfache Mehrheit reibungsfrei; Stacking nur wo getrennte Review-/Merge-Einheiten wirklich nötig sind (YAGNI). | Cross-Repo-Kandidat (TKT/GRM): Best Practice, in taktano & gh-runner-manager übernehmen (analog Repo-Key-Registry MED-D-57; nur hier editierbar → dort beim nächsten Anfassen mitziehen) · docs/konventionen/agents.md §7 · MED-D-60/OP-PM-1 · MED-OP-CROSS-1 |
| MED-D-67 | 2026-07-07 | R2/R12/DM / Formulare | Fragebogen-/Formular-Vorgänge — Parallel-Limit · Öffnungs-Tracking · Ausfüllgrad · SLA · Sichtungs-Wiedervorlage: Gemeinsames Vorgangs-Modell über die drei öffentlichen Token-Strecken (Onboarding-Einladung R2 · Dentmarking-Fragebogen T5 · Ausfüll-Formular MED-D-63) in domain/formular-vorgaenge.ts (Typ-Katalog FORMULAR_TYPEN). (1) Parallel-Limit je Typ (angebbar im Katalog): nur EIN offener Onboarding-Fragebogen je Mandant (fachliche Vorgabe), ein Ausfüll-Formular je Mandant×Vorlage, ein Dentmarking-Fragebogen je Praxis×GJ — durchgesetzt idempotent (bestehender offener Vorgang wird wiederverwendet statt 409, Muster von fragebogenEinladungErstellen). (2) Öffnungs-Tracking: geoeffnetAm wird beim ersten Öffnen des öffentlichen Links einmalig gesetzt (+ PII-armes Audit *.geoeffnet) — sichtbar als Status-Pille "noch nicht geöffnet / geöffnet / eingereicht" in der Akte. (3) Ausfüllgrad: der Dentmarking-Score verallgemeinert auf Pflicht (Gewicht 2)/optional (Gewicht 1), 0–100, rein abgeleitet (G-2) — für Ausfüll-Formulare in Liste + Pille ("geöffnet · 33 %"). (4) SLA im Cron: mandantenseitig "weich" = einmalige Erinnerung über den Benachrichtigungs-Seam (Marke slaErinnertAm; echter Mail-Versand offen wie OP-DM-8; abgelaufene Links erhalten keine weiche Erinnerung — toter Link), medidentas-seitig "hart" = überfällig → idempotente Wiedervorlage an die/den Verantwortliche:n (quelleRef = formular_sla:<token>); Fristen je Typ im Katalog (Einladungen 7/14 Tage, Ausfüll-Formular 5/10). (5) Sichtungs-Wiedervorlage bei Abschluss: jede Einreichung legt idempotent (formular_sichtung:<token>) eine sofort fällige Wiedervorlage "Antworten sichten: …" an — die Antworten werden garantiert gesichtet (True North #2). Migration v27 (+geoeffnet_am/sla_erinnert_am auf allen drei Tabellen), neue Quelle formular im Wiedervorlage-Enum. | Drei gewachsene Strecken, ein Lebenszyklus-Problem ("verschickt ≠ geöffnet ≠ ausgefüllt ≠ gesichtet") → EIN gemeinsames, deklaratives Modell statt drei Sonderlocken (G-2/G-3); Limits idempotent statt Fehler = kein Duplikat-Risiko (Befund B-5) und keine UI-Sonderfälle; SLA-Fristen als Katalog-Konstanten (bewusst ohne neue Tenant-Einstellung — YAGNI, bei Bedarf nachziehbar). | gebaut (0.52.0) · +13 Vitest (332/33) · Migration v27 · end-to-end via wrangler dev + D1 verifiziert · domain/formular-vorgaenge.ts · api/formular-vorgaenge-service.ts · Nutzer-Anforderung 07.07. Nachtrag (gleiche PR, Nutzer 07.07.): Ausfüllgrad unterscheidet jetzt drei Wichtigkeits-Stufen Pflicht (Gewicht 3) · wichtig (2) · optional (1) statt nur Pflicht/optional; jedes offene Feld bietet die Markierungen "weiß ich nicht" und "wird nachgeliefert" (DM-9-Muster verallgemeinert) — markierte Felder sind bewusst offen (zählen nicht zum Ausfüllgrad), eine Markierung erfüllt ein Pflichtfeld (blockiert die Einreichung nicht). "wird nachgeliefert" erzeugt bei Einreichung eine eigene idempotente Reminder-Wiedervorlage formular_nachlieferung:<token> (True North #2). Persistenz kundenMarkierungen (Migration v28), Vorschau/Beleg zeigen den Markierungs-Text. Review-Fixes (CodeRabbit): Dentmarking-Fragebogen erzeugt bei "wird nachgeliefert" ebenfalls die Nachlieferungs-Wiedervorlage; speichern lässt Markierungen bei werte-only-Save unangetastet (undefined=unverändert); Routen lehnen Nicht-Objekte ab (400); weiche SLA-Erinnerung nur bei vorhandenem Kanal markiert; einreichen prüft Persistenz vor Audit/WV; Client verwirft Feldwert beim Markieren (G-6) + aria-pressed. Umnummeriert von MED-D-65 → MED-D-67 (ID-Kollision mit parallelem Stacking-Beschluss #93, Log-Hygiene OP-PM-1). +6 Vitest gesamt (338/33). |
| MED-D-68 | 2026-07-07 | R2 / Onboarding | Onboarding-Fragebogen: Zwischenspeichern + Fertigstellungsgrad. Der öffentliche Onboarding-Fragebogen (/onboarding/:token) war die einzige der drei Token-Strecken ohne Entwurf-Zwischenspeichern und ohne angezeigten Ausfüllgrad. Nachgezogen nach dem etablierten Muster (Dentmarking-Fragebogen DM-9 · Ausfüll-Formular MED-D-67): (1) Zwischenspeichern — Entwurf-Zustand am onboarding_einladung (entwurf JSON + entwurf_gespeichert_am, Migration v29), öffentliche Route PUT /oeffentlich/onboarding/:token (bewusst ohne Turnstile — reiner Draft ohne Willenserklärung; die POST-Einreichung bleibt bot-geschützt), Ingress-Scrubbing auf bekannte Stammdaten-Schlüssel (G-6), Audit onboarding.zwischengespeichert (PII-arm), Entwurf wird bei Einreichung verworfen (G-6). (2) Fertigstellungsgrad — der gemeinsame ausfuellgrad() (MED-D-67) auf die Stammdaten (Pflichtfeld Gewicht 3 / optional 1), im kontext geliefert + im Formular als Fortschrittsbalken/"%", live beim Tippen; Client rehydriert den Zwischenstand. | Konsistenz der drei öffentlichen Formular-Strecken (G-3): dieselbe Wiederaufnahme + derselbe Fortschritts-Indikator überall, kein Sonderweg für Onboarding; Wiederaufnahme senkt Abbruch, der sichtbare Grad beantwortet True North #1/#2 schon beim Ausfüllen. Kein neues Modell — bestehende Bausteine (ausfuellgrad, Entwurf-Muster) wiederverwendet. | gebaut (0.53.0) · +2 Vitest (340/33) · Migration v29 · end-to-end via wrangler dev + D1 verifiziert (Ausfüllgrad 19→75, Scrubbing bestätigt) · onboarding-formular-service.ts · domain/einwilligung.ts (stammdatenFelderGewichtet/bereinigeStammdaten) · onboarding-public.component.ts · Nutzer-Bug 07.07. |
| MED-D-69 | 2026-07-07 | Doku / Governance | Entwicklungsansatz als eigene Übersichtsseite (docs/konventionen/Entwicklungsansatz.md): True North (3 Leitfragen) · Leitprinzipien G-1…G-7 · Way-of-Working (Everything-as-Code, Audit-Trail, ID-System, Branch-first/Draft-PR, SemVer, Doku-Konsistenz) · Standard-Prozess · Compliance-Haltung — mit zwei Mermaid-Diagrammen (Warum→Wie→Prozess→Nachweis; Mandanten-Lebenszyklus). Verlinkt aus der Doku-Landkarte (docs/README.md, prominent + konventionen-Tabelle) und der CLAUDE.md-Tiefenquellen-Tabelle. | Der Ansatz war korrekt, aber nur verteilt greifbar (CLAUDE.md terse/agenten-fokussiert, Teile in System-Charakter/agents.md) — eine explizite, lesbare Übersichtsseite macht das "Warum & Wie" für Menschen auf einen Blick zugänglich (Nutzer-Wunsch). G-2-Wahrung: CLAUDE.md bleibt die verbindliche Quelle; die neue Seite ist die lesbare Spiegelung, explizit als solche markiert (kein zweiter Wahrheits-Ort, Verweise statt Wortlaut-Dopplung wo möglich). | Doku-only, keine Versionsänderung · docs-site-Build grün (Mermaid + Links validiert) · Doku-Konsistenz grün · Nutzer-Wunsch 07.07. |
| MED-D-70 | 2026-07-07 | R2 / Prozess & Datenmodell | Onboarding-Pflicht-Nachweise + Prozess-Einstieg + IBAN-Trennung. (1) Prozess: Der Mandanten-Prozess beginnt mit dem Onboarding; Dentmarking ist eine Beratungsleistung (nicht Onboarding) und dient als niedrigschwelliger Lead-Einstieg — kommt ein Kunde als Lead herein (z. B. über Dentmarking) ohne Onboarding, wird der Mandant direkt als lead angelegt (Onboarding später als eigene Phase). (2) Onboarding-Pflicht-Nachweise: Die Phase gilt erst vollständig mit Einwilligung Datenverarbeitung · Personalausweis · Kundenfragebogen · SEPA-Mandat · Dienstleistungsauftrag (alle pflicht=true) + IBAN privat. Umgesetzt in domain/onboarding-vorlagen.ts (SEPA + Dienstleistungsauftrag von optional→Pflicht, in BASIS für alle Objektarten; "Stammdaten erfasst (Kundendatenbogen)"→"Kundenfragebogen"). (3) IBAN getrennt: private IBAN (Person, BASIS) und Entitäts-IBAN je Praxis/Gesellschaft sind separate Items (statt kombiniert "IBAN privat + Praxis") — eine Person hält 0..n Entitäts-IBANs (D-45). | Der Kunde hat den Prozess-Einstieg und den Pflicht-Umfang der Onboarding-Phase präzisiert; die Checkliste bildet ihn jetzt wörtlich ab. IBAN-Trennung folgt dem Personen-/Entitäten-Modell (D-45) statt es in einem Freitext-Item zu vermischen. Bewusst nur Checklisten-Nachweis (Item + Ablage-Datei), keine strukturierte Roh-PII (IBAN/Ausweis) in der App — Bank-/Ausweis-PII-Persistenz ist compliance-gated (MED-KB-6, G-5/G-6, Default "nicht speichern"). Auto-Anlage des Leads beim Dentmarking-Einstieg ist Workflow-Ausbau (OP-LEAD-1), nicht Teil dieses Slices. | gebaut (0.54.0) · +3 Vitest (343/34, domain/onboarding-vorlagen.test.ts) · tsc + ng build grün · kein Schema-Change (Items werden bei "Onboarding starten" aus der Vorlage materialisiert, G-2 — nur neue Onboardings betroffen) · Doku: Lastenheft §4.5/§5.1, MED-KB-6, OP-LEAD-1, Feature-Liste, Test-Übersicht · Nutzer-Vorgabe 07.07. |
| MED-D-71 | 2026-07-07 | R1 / Datenmodell | IBANs explizit in den Stammdaten. Auf Nutzer-Vorgabe werden IBANs strukturiert persistiert (nicht mehr nur Checklisten-Nachweis, revidiert den Default aus MED-KB-6): private IBAN am Mandanten (mandant.iban_privat, R1-F13) und Entitäts-IBAN je Praxis/Gesellschaft (praxis.iban, R1-F29) — getrennt (MED-D-70). Migration v30; Eingabe wird normalisiert (Leerzeichen weg, Großbuchstaben) und per ISO-7064-Mod-97 validiert (domain/iban.ts; ungültig → 400), an Mandant-PATCH + Praxis-Anlage/-PATCH; Client: IBAN-privat im Aktendeckel + Entitäts-IBAN je Praxis. | Der Kunde braucht die IBANs maschinell (SEPA-Mandat/Abrechnung) → strukturierte Speicherung statt nur Datei/Checkliste. Getrennt privat/Entität folgt dem Personen-/Entitäten-Modell (D-45). IBAN-Validierung ist der erste konkrete Baustein von MED-OP-VALID-1. ⚠️ Compliance (G-5/G-6, offen in MED-KB-6): Bank-PII at rest — Verschlüsselung/Retention/Zugriff (RBAC D-48) noch zu härten; heute Klartext in D1 (Cloudflare-Storage-Encryption at rest, aber keine Feld-Verschlüsselung). | gebaut (0.55.0) · +6 Vitest (iban.test.ts +4, app.test.ts +2) · Migration v30 · end-to-end via wrangler dev + D1 verifiziert (Mod-97 + Normalisierung) · Nutzer-Vorgabe 07.07. |
| MED-D-73 | 2026-07-07 | Doku / Governance | Governance-Angleichung an den drkv-Standard: "Dokumentation als Meisterwerk" als Leitprinzip + Standard-Bausteine. CLAUDE.md bekommt (1) das aus Taktano bewährte Leitprinzip Dokumentation als Meisterwerk (pyramidal · zielgruppen-gerecht · visuell) explizit — bisher nur teilweise/verteilt; (2) einen Abschnitt Standard-Bausteine (drkv, Default): Echtzeit · moderne Frameworks · In-App-Chatbot · Feedback, kanonisch im Template everything-as-code-template/docs/Standard-Tech-Stack.md, Abweichung als MED-D-n begründen; (3) die Regel "Way-of-Working sichtbar in der Doku" (Entwicklungsansatz.md, bereits vorhanden — MED-D-69). Entwicklungsansatz.md §4.6 ergänzt. | Die Schwester-Repos teilen eine gemeinsame Governance; Medidentas zieht die noch fehlenden Stücke (Doku-als-Meisterwerk als benanntes Leitprinzip, drkv-Standard-Bausteine) nach → ein Kanon über alle drkv-Repos. | Doku-only, keine Versionsänderung · Nutzer-Wunsch 07.07. · Quelle Taktano CLAUDE.md/agents.md · Template CLAUDE.md |
| MED-D-74 | 2026-07-07 | Architektur / KI | In-App-Chatbot (LLM + RAG auf Live-Daten & Doku) als Zielarchitektur dokumentiert — löst "Medidentas-GPT" ein. Design vor Umsetzung (docs/architektur/In-App-Assistent.md): ein Assistent über App und Doku, drei Säulen (Doku-Q&A via RAG · Insights aus dem D1-Live-State abgeleitet · Feedback), vorschlagend nicht ausführend, RBAC-gebunden (D-48) + Zugriffslog (D-50), PII-frei indexiert (nur Doku im Vektor-Store, G-6), EU-LLM/-Embeddings (DSGVO), dormant ohne Secret. Feedback wird git-nah als Issue abgelegt und wieder angezeigt (Standard-Eigenschaft 4). Bau als OP-ASSIST-1 geparkt. | drkv-Standard-Baustein (CLAUDE.md → Standard-Bausteine); beantwortet die drei True-North-Leitfragen direkt und macht die Doku durchsuchbar. Architektur 1:1 aus der bewährten Taktano-Implementierung übernommen, an Medidentas' Compliance-Profil (G-5/G-6, RBAC) angepasst. | Design-only, keine Versionsänderung · OP-ASSIST-1 (Bau) · Referenz Taktano docs/architektur/In-App-Assistent.md · Template docs/In-App-Assistent.md · Nutzer-Wunsch 07.07. |
| MED-D-72 | 2026-07-07 | R2 / Prozess | Öffentliches Lead-Formular (realisiert OP-LEAD-1). Ein separates, öffentliches Self-Service-Formular (/lead + GET/POST /oeffentlich/lead, ohne Token, Turnstile-geschützt), strukturell "quasi gleich" wie das Onboarding-Formular: ein Interessent trägt sich selbst ein → der Mandant wird direkt als lead angelegt (+ Entität aus typ, Adresse an der Praxis), verantwortlich=null (Lead-Pool, D-48), Ingress-Scrubbing (G-6), Audit lead.eingegangen (PII-arm) + sofort fällige Sichtungs-Wiedervorlage "Neuen Lead sichten" (True North #2; Ansprechpartner/Telefon im Betreff). api/lead-service.ts, Client lead-public.component.ts + Route /lead. | Der Prozess beginnt mit dem Onboarding, aber Leads brauchen einen niedrigschwelligen Selbst-Eintrag vor dem Onboarding (MED-D-70); ein eigenes öffentliches Formular hält Lead-Erfassung und formale Onboarding-Strecke sauber getrennt. Zugang: öffentlich (Nutzer-Entscheidung). ⚠️ Access-Bypass für /lead + /oeffentlich/lead im Cloudflare-Dashboard nötig (wie /onboarding*, Deploy.md). Dublettencheck bleibt offen (OP-DUP-1). | gebaut (0.55.0) · +4 Vitest (lead.test.ts) · end-to-end via wrangler dev verifiziert (öffentlicher POST ohne Access-Header → Lead-Mandant + Praxis + Wiedervorlage) · Nutzer-Vorgabe 07.07. |
| MED-D-75 | 2026-07-07 | UI / Branding | Browser-Tab-Icon (Favicon) = medidentas-Logo. (umnummeriert von MED-D-73 — parallele Session #103 hatte MED-D-73/74 zeitgleich vergeben; #103 behält MED-D-73, Log-Hygiene OP-PM-1.) Die App lieferte kein Favicon aus → Browser-Tabs zeigten den generischen Buchstaben-Platzhalter. Neu: eigenständige client/src/assets/favicon.svg mit denselben SVG-Pfaden wie das Logo im App-Header (app.component.ts) — grünes Herz (#76b82a) mit weißer Puls-Linie; als Asset in den Build aufgenommen (angular.json assets-Glob → favicon.svg im Root der dist/browser) und in client/src/index.html per <link rel="icon" type="image/svg+xml" href="favicon.svg"> referenziert. | Wiedererkennbarkeit/Marke im Browser-Tab (Nutzer-Wunsch); ein SVG-Favicon aus denselben Pfaden hält Header-Logo und Tab-Icon deckungsgleich und ist skalierungsfrei (kein separater .ico-Binär-Master, G-2/"keine Binärformate"). | gebaut (0.55.1) · ng build grün (favicon.svg landet in dist/browser/, index.html referenziert es) · Nutzer-Wunsch 07.07. |
| MED-D-76 | 2026-07-07 | UI / Branding (Fix) | Favicon als inline data:-URI statt Datei-Referenz. Das mit MED-D-75 eingeführte Tab-Icon erschien nicht (auch inkognito blieb der "M"-Platzhalter). Ursache: die App liegt komplett hinter Cloudflare Access — der separate Browser-Request auf /favicon.svg wird (u. a. im Auth-Bounce vor dem Login) mit 302 → Access-Loginseite (text/html) beantwortet, das Icon lädt nie. Fix: das identische Herz-mit-Puls-SVG als inline data:image/svg+xml;base64,…-URI direkt im <link rel="icon"> von client/src/index.html. Der Standalone-favicon.svg + angular.json-Glob bleiben (liefern /favicon.svg weiterhin aus), sind aber nicht mehr im <link> referenziert. | Ein data:-URI rendert das Icon direkt aus dem bereits geladenen HTML, ganz ohne separaten (Access-geschützten) Netzwerk-Request — löst das Problem rein im Code, cache-unabhängig und ohne Infra-Änderung. Alternative verworfen: Access-Bypass für /favicon.svg im Cloudflare-Dashboard (Betreiber-Schritt, analog /oeffentlich*//lead*) — unnötige Angriffsfläche/Abhängigkeit, wenn der data:-URI dasselbe leistet. Der SPA-Fallback (serving.ts) liefert für Datei-Suffixe ohnehin kein HTML (bleibt 404), scheidet als Ursache aus. | gebaut (0.55.2) · ng build grün · Nutzer-Bug "Tab-Icon immer noch alt; inkognito auch das alte M" 07.07. |
| MED-D-77 | 2026-07-07 | UI / Branding (Fix) | Zusätzliche PNG-Favicon-Variante für iOS/iPadOS. MED-D-76 (SVG-data:-URI) behob das Problem auf Desktop nicht vollständig: auf iPad (Safari + darauf basierendes Chrome, WebKit) zeigte der Tab weiterhin kein Icon, sondern den generischen Globus-Platzhalter (kein M-Buchstabe mehr wie zuvor, sondern "kein Icon geladen") — iOS-WebKit rendert inline-SVG-data:-URI-Favicons im Tab nicht zuverlässig. Fix: zusätzliche PNG-Variante (64×64, transparent, aus demselben SVG mit cairosvg gerastert) als weiterer <link rel="icon" type="image/png"> mit data:image/png;base64,…, vor dem bestehenden SVG-Link platziert (PNG = universell unterstütztes Format, SVG bleibt als Progressive Enhancement für Browser, die es rendern). | PNG hat die breiteste Browser-/OS-Kompatibilität für Favicons; iOS/iPadOS-WebKit ist ein bekannter Sonderfall mit lückenhafter SVG-Favicon-Unterstützung im Tab (Home-Screen-apple-touch-icon ist ein getrennter Mechanismus und war nicht betroffen). Beide <link>-Varianten bleiben data:-URIs (kein Access-geschützter Fetch, G-2 "keine Binärformate als Master" bleibt gewahrt — das PNG ist eine abgeleitete Build-Ressource, keine Repo-Binärdatei). | gebaut (0.55.3) · ng build grün · Nutzer-Bug "iPad zeigt Globus statt Icon, auch in Chrome" 07.07. |
| MED-D-78 | 2026-07-07 | UI / Branding (Fix, definitiv) | Favicon über den bestehenden /oeffentlich*-Access-Bypass ausliefern statt data:-URI. MED-D-77 (PNG-data:-URI) behob das iPad-Problem ebenfalls nicht — Test zeigte weiterhin den Globus-Platzhalter. Root-Cause revidiert: nicht das Bildformat war die Ursache, sondern data:-URIs selbst — iOS/iPadOS-WebKit unterstützt inline-data:-URI-Favicons im Tab grundsätzlich nicht zuverlässig, unabhängig von SVG/PNG (bekannte WebKit-Einschränkung; bestätigt durch identisches Scheitern über zwei Formate). Fix: zurück zu echten, netzwerk-ladbaren Dateien (favicon.svg/favicon.png, WebKit-kompatibel) — aber ausgeliefert unter /oeffentlich/favicon.svg bzw. /oeffentlich/favicon.png statt direkt unter /favicon.*. Der /oeffentlich*-Präfix liegt bereits im bestehenden Cloudflare-Access-Bypass (MED-D-70ff.) — kein neuer Dashboard-Schritt nötig. Neue reine Funktion server/src/serving.ts#echterFaviconPfad() mappt die beiden Alias-Pfade auf die echten Asset-Pfade; index.ts proxied früh im fetch()-Handler (vor Migration/DB) via env.ASSETS.fetch() — kein neuer State, kein DB-Zugriff. index.html verweist jetzt auf /oeffentlich/favicon.png (zuerst) + /oeffentlich/favicon.svg. | Ein echter Datei-Fetch ist der einzige über alle Browser/Engines hinweg zuverlässige Weg für Tab-Favicons; data:-URIs sind für dieses Feature kein robuster Ersatz (WebKit-Lücke). Die Wiederverwendung des bereits bestehenden /oeffentlich*-Bypasses (statt einer neuen Bypass-Policy für /favicon.*) vermeidet einen Betreiber-Eingriff im Cloudflare-Dashboard und hält die Angriffsfläche minimal (kein zusätzlicher öffentlicher Pfad-Typ, nur zwei explizit gemappte Alias-Dateien). Rein pure/testbare Logik (echterFaviconPfad) nach demselben Muster wie zielIstAssets/istSpaNavigation (serving.ts, Vorfall 2026-07-04). | gebaut (0.55.4) · +2 Vitest (serving.test.ts, 356/36 gesamt) · tsc + ng build grün · end-to-end via wrangler dev verifiziert (GET /oeffentlich/favicon.svg → 200 image/svg+xml, GET /oeffentlich/favicon.png → 200 image/png, korrekter Inhalt) · Nutzer-Bug "Favicon wird immer noch nicht angezeigt" (nach MED-D-77) 07.07. |
| MED-D-79 | 2026-07-07 | Doku / Prozess & Architektur | Prozessmodell als autoritative Landkarte + Vokabular-Regel + Fahrplan. (umnummeriert von MED-D-76 — parallele Favicon-PRs #104/#105/#106 belegten 76/77/78 und wurden zuerst gemergt; Log-Hygiene OP-PM-1.) Neues Doc architektur/Prozessmodell.md bündelt die verstreute Prozess-Haltung (System-Charakter §1 · Lastenheft §5 · Akte-Struktur/D-41) an einer Stelle. (1) Vokabular-Regel: DIE fachliche Phase = Mandant.prozessphase; Onboarding.phase (R2-F04) ist ein Teilschritt innerhalb der Phase onboarding, keine eigene fachliche Phase (Lastenheft R2/§5.2 + MVP-Scope §4.2 nachgezogen). (2) Dokumente & Unterschriften = phasen-übergreifende Achse (nicht ein Schritt): ein Dokument-Ledger (R3+R12+R4), "an jeder Stelle" erzeugbar, lückenlose Nachverfolgung (G-4, "nie löschen" MED-D-56); Phasen-Reife-Gates bleiben phasengenau. (3) Freitext → Layout → Unterschrift über die vorhandene PDF-/Signatur-Maschinerie. Fahrplan P1 (Vokabular, jetzt) → P2 (Dokument-Ledger) → P3 (WV-Badge) → P4 (Freitext) → P5 (R11). | Der Prozess ist bereits reif abgebildet (Case-Management-Zustandsmaschine, zwei Achsen, Phasen-Engine, abgeleitete Sichten) → "am besten abbilden" = Schärfen statt Neubau; eine Quelle beseitigt die Doku↔Doku-Uneindeutigkeit "welche ist DIE fachliche Phase" (G-3, OP-DOCS-1). Dokumente/Unterschriften entstehen laut Eigentümer an jeder Stelle → Achse, nicht Schritt. | Doku-only (APP_VERSION unverändert 0.55.1). Neue OPs MED-OP-DOC-2 (Ledger) + MED-OP-REG-1 (WV-Badge); OP-DOCGEN-2 um Freitext→Unterschrift erweitert. G-3, G-4, OP-DOCS-1, OP-SIGN-1, MED-KB-5. Nutzer-Frage 07.07. "wie bilden wir die Geschäftsprozesse am besten ab/unterstützen sie" + Präzisierung "Dokumente/Unterschriften an jeder Stelle · lückenlos tracken · Freitext ins Layout → Unterschrift". |
| MED-D-80 | 2026-07-07 | R1/R3/UC-6 · Prozess-UI | Dokument-Ledger (quer-liegende Achse) + Wiedervorlagen-Badge gebaut (umnummeriert von MED-D-77 — Kollision mit Favicon-PR #105, OP-PM-1.) (realisiert MED-OP-DOC-2 + MED-OP-REG-1, Umsetzung von MED-D-79 P2/P3). (1) P2: neues quer-liegendes Register "Dokumente & Unterschriften" (phase: null, wie Zeiten/Verlauf) in Arbeitssicht + Akte — die drei Dokument-Sektionen (Ablage-Dokumente R3 · Dokumenten-Automatisierung R12 · Unterschriften R4) an einem Ort, phasen-übergreifend, jederzeit erzeugbar; Sprungziele dokumente/unterschriften biegen auf das neue Register (SPRUNGZIEL_REGISTER). Client-only, kein Server-Change, keine neuen Endpunkte (alle Ströme bereits geladen). (2) P3: PhaseReife um Feld hinweis erweitert (Summe der anzahl nicht-blockierender Punkte je Phase) → Betreuung-Tab zeigt die Anzahl offener Wiedervorlagen als neutralen Badge (nutzt die vorhandene .md-cnt-CSS). | "Unterschriften/Dokumente" wird zusammengedacht und entsteht an jeder Stelle (Eigentümer) → Anzeige quer, Reife-Gates bleiben phasengenau (aktenreife.ts unverändert getaggt); die WV-Sichtbarkeit beantwortet True North #2 direkt am Register, ohne die reif-Invariante (D-41: WV = hinweis, kein Blocker) zu berühren. Um-eltern statt Duplizieren → keine Dedup-Logik, kein neuer Zustand (G-2). | gebaut (0.55.1 → 0.56.0, MINOR) · +1 Vitest (aktenreife hinweis, 355/36) · tsc + ng build grün · end-to-end via wrangler dev + D1: Mandant mit 2 Wiedervorlagen → jePhase[betreuung].hinweis=2, offen=0, reif unberührt. Nutzer-"Ja" 07.07. auf den Slice-Vorschlag. |
| MED-D-81 | 2026-07-07 | R3/R4/R12 · OP-DOCGEN-2 | Freitext-Individualdokument → Layout → Unterschrift gebaut (umnummeriert von MED-D-78 — Kollision mit Favicon-PR #106, OP-PM-1.) (realisiert die Freitext-Hälfte von OP-DOCGEN-2; MED-D-79 P4). Neue Entität Individualdokument (Titel + frei geschriebener Korpus + explizit gewähltes eIDAS-Niveau), Status-Workflow Entwurf → freigegeben → erzeugt → abgelegt → zur_unterschrift → signiert (letzterer abgeleitet, G-2). erzeugen rendert den Freitext ins Hauslayout (pdf/pdf-dokument.ts, je Absatz ein Block) → legt es als R3-Dokument ab (landet damit im Dokument-Ledger MED-D-80 + auditiert) → zurUnterschrift übergibt an die vorhandene SignaturService-Strecke. Migration v31, neuer Service individualdokument-service.ts + domain/individualdokument.ts (rein), Client-UI "Freies Dokument" im Ledger-Register + read-only in der Akte. Signatur-Service minimal erweitert: anfordern(dokumentId, niveauOverride?) — das gewählte Niveau gewinnt gegen die Titel-Ableitung (rückwärtskompatibel). | Der Eigentümer will frei geschriebene Dokumente "im richtigen Layout gesetzt und zur Unterschrift gegeben"; R12 deckt nur Template-Mapping ab. Voll-Umfang gewählt (Nutzer): editierbarer Entwurf + Freigabe-Gate (Mensch-im-Prozess, RISK-14) + erhaltener Quelltext (G-4 "einmal erstellt, immer getrackt"). Reuse statt Neubau: PDF-/Ablage-/Signatur-Maschinerie unverändert; der R3-Umweg macht das Freitext-Dokument automatisch Teil des Ledgers. | gebaut (0.56.0 → 0.57.0, MINOR) · +10 Vitest (individualdokument.test.ts, 365/37) · tsc + ng build grün · end-to-end via wrangler dev + D1: erstellen→bearbeiten→freigeben→erzeugen (R3-Dokument + PDF im Ledger) →unterschrift mit explizitem Niveau AES. Compliance: echte E-Signatur weiter Fake bis MED-KB-5 (Niveau informativ, im UI als Demo kenntlich); eIDAS/ZertES-Formstrenge je Rechtswirkung (OP-SIGN-1). Nutzer-"P4" 07.07. |
| MED-D-82 | 2026-07-07 | R11/R5/R7 · OP-MEET-1 | Gesprächsnotizen / Meeting-Doku (R11) — Kern gebaut (realisiert den Kern von OP-MEET-1; MED-D-79 P5). Neue Entität Meeting (Titel · Art · manuell erfasstes Protokoll, mandant-scoped) im Beratung-Register; der GespraechsAuswerter-Seam (deterministischer RegelAuswerter, kein LLM) schlägt Aufgaben aus dem Protokoll vor (Mensch-im-Prozess, RISK-14); übernommene Aufgaben werden Wiedervorlagen (R5, neue quelle='aufgabe') — an R7 delegiert, idempotent (quelleRef=aufgabe:<meetingId>:<kennung>, Rücksprung R11-F16). Migration v32; neu domain/meeting.ts · ki/gespraechs-auswerter.ts · api/meeting-service.ts · Routen /api/mandanten/:id/meetings (+PATCH, aufgaben-vorschlag, aufgaben) · Client-Sektion im Beratung-Register + read-only Akte. Protokoll-Lesezugriff auditiert (meeting ∈ ZUGRIFF_SENSIBEL, D-50). | Aufgaben = Wiedervorlagen (G-2 "eine Wahrheit"): Lastenheft §4.7 "Aufgabe = auch ohne Meeting nutzbar = reine Wiedervorlage" → kein Parallel-Task-Store; Reuse der R5-Delegations-/Audit-/Cron-Maschinerie, Aufgaben erscheinen automatisch im WV-Register/Cockpit. Standard-Tool-Bias (G-1/A-8): Eigenbau = nur die Orchestrierung; echte Transkription (Notion/Plaud/Krisp) bleibt OP-MEET-1 (Tool-/EU-Residenz-/AVV-Wahl, RISK-15) → heute quelle=manuell. Auswerter als Fake-Seam analog KiPruefer (EU-sicher, austauschbar). | gebaut (0.57.0 → 0.58.0, MINOR) · +11 Vitest (meeting.test.ts, gespraechs-auswerter.test.ts, 379/39) · tsc + ng build grün · end-to-end via wrangler dev + D1: Meeting → Vorschlag (2 Aufgaben, @berater@praxis.de/bis 2026-07-20) → Übernahme → 2 Wiedervorlagen quelle=aufgabe im WV-Register (delegiert), Re-Übernahme idempotent. Compliance: RISK-15/DSGVO Art. 9 — kein Roh-Audio/keine Cloud-KI im Kern; echte Transkription erst mit EU-Residenz + AVV (OP-MEET-1). Audit PII-arm. Nutzer-"dann P5" 07.07. |
| MED-D-89 | 2026-07-11 | R12/R4 · neues MED-OP-FORM-4 | Feld-Sichtung "approve/deny" je Feld + Kunden-Feedback per Mail + Korrektur-Schleife — verbindliches Formular-Muster (zuerst Ausfüll-Formular). Neu generisch/rein domain/feld-sichtung.ts (Entscheid je Feld akzeptiert/abgelehnt, Ablehnung verlangt Grund; zuSichtendeFelder/vollstaendigGesichtet/feedbackNachricht). Flow: Einreichung → Mitarbeiter entscheidet jedes Feld (POST …/ausfuellformulare/:token/feld-sichten) → Sichtung abschließen (…/sichtung-abschliessen, nur wenn alle entschieden): Kunden-Feedback (akzeptiert/abgelehnt + Grund je Feld) über den Benachrichtigungs-Seam (Log PII-arm — nur Betreff/Kategorie/Zeilen-Anzahl; realer Mail-Adapter offen OP-DM-8) + bei Ablehnung Korrektur-Schleife (Status korrektur: nur abgelehnte Felder dem Kunden über denselben Link offen, akzeptierte server-seitig gesperrt; Re-Einreichung setzt nur die abgelehnten Entscheidungen zurück + reaktiviert die Sichtungs-WV). Migration v35 (JSON-Spalte ausfuellformular.sichtung), Status-Enum +korrektur; Seam minimal erweitert (kategorie?/zeilen?). Client: Sichtungs-Panel (Arbeitssicht) + korrektur-fähiges öffentliches Formular. | Nutzer-Vorgabe "Formulare immer so bauen". Weggabelungen (Nutzer): (1) Deny → Korrektur-Schleife (nicht nur informieren); (2) Mail über den Seam jetzt, realer Versand aufgeschoben (OP-DM-8, DSGVO/AVV-Providerwahl = Kundenpunkt); (3) generisch + 1 Strecke zuerst (Onboarding/Dentmarking Fast-Follows). G-2/G-4: approve/deny ist das Dach, die Stammdaten-Übernahme (MED-D-84) ein nachgelagerter Konsument akzeptierter Felder; jede Entscheidung append-only auditiert (PII-arm). G-5/G-6: Feedback trägt kundeneigene Angaben an den Kunden selbst (kein Dritt-Datenfluss); Seam-Aufruf empfaenger=null (Adapter löst Kontakt über Mandant-Ref). | gebaut (0.61.0 → 0.62.0, MINOR) · +14 Vitest (feld-sichtung.test.ts + Service/Loop, 417/41) · tsc + ng build grün · e2e via wrangler dev + D1 (v35): einreichen → 4× akzeptieren, plz ablehnen → abschließen status=korrektur → Kontext korrekturFelder=['plz'] + Grund sichtbar → Korrektur (ort gesperrt/ignoriert, plz korrigiert) → status=eingereicht, plz-Entscheidung zurückgesetzt, ort bleibt akzeptiert; Feedback PII-arm (Grund/Token nicht im Log). Neues MED-OP-FORM-4 (Rollout Onboarding/Dentmarking offen). Nutzer 11.07. "Formulare immer so bauen: Kunde meldet zurück → Mitarbeiter approve/deny je Feld → Kunde erhält Feedback per Mail". |
| MED-D-90 | 2026-07-12 | UX/Client · MED-OP-UX-1 | UX-Welle 1 — Verlässlichkeit & Rechtssicherheit (aus dem UX-Review, UX-Prozess-Review-2026-07.md §3/§5): /formular/ als öffentliche Route (keine interne Shell auf der Kundenstrecke) + DSGVO-Hinweis/Marken-Kopf/Fehlerdifferenzierung im Ausfüll-Formular; zentrales HTTP-Fehler-Auffangnetz (fehler.interceptor.ts, 0/5xx/403 → Toast, gemeldet-Marker gegen Doppel-Meldung) + Toast-Container global; Cockpit: Erfolgs-Toast erst nach Server-Antwort, Aktionen nur server-verankert (kein lokales Schein-"Erledigt", "Erinnern" entfernt, Zuweisen-Auswahl statt prompt()), Lade-/Fehler-/Leerzustand getrennt; Arbeitssicht-Fehler im Sichtfeld (Toast) statt im falschen Register; Google Fonts self-hosted. | Kern-Risiko aus dem Review: Toasts bestätigten Nicht-Passiertes, Fehler blieben stumm → True North #2 falsch beantwortet; DSGVO-Flags (Art.-13-Hinweis fehlte trotz IBAN/Geburtsdatum; Google-Fonts-Dritt-Abruf, LG München I 2022). Entscheidung: Cockpit bietet Erledigen/Verschieben/Zuweisen nur für aufgelöste Wiedervorlagen-IDs an — unzugewiesene WVs ehrlich "in der Akte erledigen" (API-Erweiterung offene-punkte+wvId = Folge-Idee Welle 2/3). | gebaut (0.62.0 → 0.63.0, MINOR) · rein Client, kein Schema-Change · 417 Vitest + ng build grün · e2e via wrangler dev + Playwright (Formular ohne Shell + DSGVO-Footer + 404-Zweig; Erledigen persistent nach Reload; "Erinnern" weg). |
| MED-D-91 | 2026-07-12 | UX/Client+Server · MED-OP-UX-2 | UX-Welle 2 — "eine Sprache" (G-3/G-8-Pass): zentrale client/src/app/labels.ts (eine Definition je Begriff: Status/Niveaus/Rollen/Quellen/Audit-Aktionen + datum/datumZeit + reifeStufe()/REIFE_STUFE_LABEL), alle Sichten (Druck-Akte zuerst, dann Arbeitssicht/Cockpit/Verwaltung/Header) auf gemappte Labels umgestellt, interne Doku-IDs aus UI-Texten entfernt; Feld-Sichtung: sprechende Feld-Labels (Vorlagen-Katalog liefert felder[]), Fortschritt, "Alle offenen akzeptieren" (sequenziell — parallele Writes = lost update), markierte Felder read-only sichtbar, 0-Felder-Fall erklärt; Korrektur-Schleife: abgelehnte Felder dürfen markiert werden — korrekturOffen() leitet die offenen Felder aus dem Sichtungs-Status ab, markiertes Feld verliert den abgelehnten Wert und fällt aus der nächsten Sichtung. | UX-Review §3/§4: rohe Enums/Codes/IDs ausgerechnet in Druck-Akte und dem neuen Kern-Workflow; drei Wordings für Aktenreife; Sichtungs-Sackgassen (0 Felder · Kunde kann abgelehnten Wert nicht liefern). Entscheidung: Labels leben ZUERST in labels.ts (G-8-Muster fürs UI); Korrektur-Ausweg über die bestehende Marker-Semantik statt neuem Freitext-Kanal. | gebaut (0.63.0 → 0.64.0, MINOR) · +2 Vitest (419/41) · tsc + ng build grün · e2e via wrangler dev + Playwright (Sichtung: Labels + "0→4 von 4" + Abschluss-Feedback; Akte/Cockpit ohne rohe Codes; einheitlich "fast aktenreif"). |
| MED-D-92 | 2026-07-12 | UX/Client · MED-OP-UX-3 | UX-Welle 3 — "eine Handschrift": gemeinsame Public-Form-Bausteine pub-bausteine.ts (Marken-Kopf · Fortschritt · Pflicht-Legende · Marker-Chips · DSGVO-Fußzeile · autocompleteFuer()) über alle vier Kundenstrecken; Ausfüll-Formular erhält Fortschritt + Zwischenspeichern (Muster Onboarding/DM-9); Turnstile-Gating vereinheitlicht; EIN Toast-System (Cockpit → globaler ToastService) + EIN Fehler-Rot (--md-error); sichtbare Navigation in beiden Headern + plattformgerechtes "Strg K"; Cockpit-Mobile: Rail → Chip-Leiste, Leitstand-Detail → Bottom-Sheet, Header-Umbruch (kein Quer-Overflow); Arbeitssicht: JSON hinter "Experten-Import", Stepper rein anzeigend, Timer-Guard nur nach Interaktion (input/change) + Dirty-Check ungespeicherter Beratungstexte. | UX-Review §4/§5 Welle 3: vier divergierende Kundenstrecken, zwei Toast-Systeme, Kernfunktionen nur per ⌘K, Cockpit mobil defekt, Pflicht-Modal beim bloßen Nachschlagen vs. stiller Textverlust. Entscheidung: bewusster Schnitt — Kern jetzt, Groß-Refactorings (Theme überall, Detail-Aufteilung, Utility-Klassen) als MED-OP-UX-4 nachgelagert (kein ungefragtes Mega-Refactoring). | gebaut (0.64.0 → 0.65.0, MINOR) · rein Client · 419 Vitest + ng build grün · e2e via wrangler dev + Playwright (390px ohne Overflow, Chip-Leiste + Bottom-Sheet, Formular-Fortschritt live + Zwischenspeichern-Feedback, Nur-Lese-Verlassen ohne Modal, Experten-Import zugeklappt). |
| MED-D-93 | 2026-07-12 | UX/Client · MED-OP-UX-4 | UX-Welle 4 — Feinschliff: dunkles Theme für die gesamte interne App (--md-*-Dark-Tokens am selben data-theme-Schalter wie das Cockpit, Umschalter Hell/Dunkel/Auto in der App-Shell, @media print erzwingt helle Tokens, Kundenseiten faktisch hell); EINE Primäraktion je Dokument-Zeile nach Status (+ sprechende Status-Pille) mit "…"-Menü für Sekundär-Aktionen; Zahleneingaben type=text+inputmode=decimal mit gemeinsamer toleranter Erkennung (pub-bausteine.ts#alsZahl = Client-Spiegel der Server-Normalisierung, G-2); Command-Palette als echter Dialog (role=dialog/aria-modal, Autofokus, Tab-Falle, Fokus-Rückgabe); Kontrast-Pass (--faint hell #a0aa9e→#87938a, tragende Mini-Texte ≥0.7rem). | UX-Review Rest-Befunde (M2 Theme-Bruch, "6 Controls je Dokument-Zeile", M11 type=number vs. Komma, M10-Palette, M7-Kontraste). Entscheidung: Rest von MED-OP-UX-4 (Datei-Aufteilung mandant-detail, Utility-Klassen flächig) = reines Code-Refactoring ohne UI-Wirkung → separater PR bei Bedarf, kein Misch-PR. | gebaut (0.65.0 → 0.66.0, MINOR) · rein Client · 419 Vitest + ng build grün · e2e via wrangler dev + Playwright (Shell/Akte dunkel + Druck hell; Dokument-Zeile: Pille + Primäraktion + Menü mit 6 Sekundär-Aktionen; Palette-Fokusfalle + Escape-Rückgabe; "1.020.431" akzeptiert, "abc" → Hinweis). |
| MED-D-94 | 2026-07-12 | UX/Client · MED-OP-UX-4 | Register-Sub-Komponenten + Aktendeckel-Feedback: Arbeitssicht gibt 4 Panels ab (akte-meetings · akte-einladungen · akte-formulare inkl. Feld-Sichtung · akte-stammuebernahme = EIN Review-and-apply-Bauteil für beide Quellen statt Duplikat) + geteilte akte-vorgang.ts-Pill-Helfer; Panels laden selbst, eigener Busy-Zustand, geaendert-Output nur für Querschnitts-Änderungen (mandant-detail 3.190 → 2.662 Zeilen); Utility-Klassen .md-hint/.md-m0/.md-w100. Nutzer-Feedback (Screenshots): eigener Reiter "Stammdaten" (Person/Kontakt/CRM/IBAN privat — Bank-PII raus aus dem Aktendeckel, G-5) und die zwei unbeschrifteten Umschalter aufgelöst — beschriftetes "Mandats-Status" (Lebenszyklus) oben rechts vs. beschriftetes "Prozessphase wechseln" am Zeitstrahl (aktueller Wert statt "→ Ziel") + Erklärzeile. | Nutzer 12.07.: "IBAN muss in die Stammdaten — separater Reiter" · "zwei Auswahllisten, die unterschiedliches darstellen — maximal verwirrend"; Review-Restpunkte Datei-Aufteilung/Utilities. Entscheidung: Panels besitzen ihre Daten (kein Shared-Service-Umbau); weitere Register opportunistisch beim nächsten Anfassen. | gebaut (0.66.0 → 0.67.0, MINOR) · rein Client · 419 Vitest + ng build grün · e2e via wrangler dev + Playwright (Panels + Server-Roundtrips: Meeting-Anlage, Sichtung, Vorgangs-Pills; Stammdaten-Reiter mit IBAN; Deckel beschriftet/ohne IBAN). |
| MED-D-88 | 2026-07-11 | R2 · MED-D-84/MED-OP-FORM-3 | Onboarding-Fragebogen → Stammdaten zurückschreiben (Review-and-apply) — MED-OP-FORM-3 abgeschlossen. Eingereichte Onboarding-Antworten (OnboardingEinladung.eingereichteDaten) fließen per Review-and-apply in die Mandanten-Stammdaten — E-Mail · Telefon · Anschrift (strasse/plz/ort). Neues ONBOARDING_STAMM_REGELN im regel-getriebenen domain/stammdaten-uebernahme.ts + neue email-Validierung + email als STAMM_ZIEL; OnboardingFormularService.uebernahmeVorschlag/uebernehmen (nur abgeschlossene Einladungen, mandant-scoped, Audit stammdaten.uebernommen quelle='onboarding', idempotent). Routen GET/POST /api/mandanten/:id/einladungen/:token/{uebernahme-vorschlag,uebernehmen}; Client-Review-Panel im Onboarding-Register (dasselbe Diff-Panel wie MED-D-84, über stammQuelle-Flag geteilt). Kein Schema-Change (Ziele existieren seit v33). | Direkte Wiederverwendung von MED-D-84: die Domäne war bewusst regel-getrieben angelegt → Onboarding = nur ein zweites Regel-Set + eine zweite Quelle. praxisName/typ/ansprechpartner ohne eindeutige 1:1-Heimat am Mandanten → nicht im Diff (Anzeigename wird beim Einreichen gesetzt). Konsistent mit der Nutzer-Ausgangsanforderung "Onboarding-Fragebogen ergänzt die Stammdaten des Mandanten → zurück ins System". | gebaut (0.60.0 → 0.61.0, MINOR) · +6 Vitest (Onboarding-Rückübernahme + E-Mail-Validierung, 403/40) · tsc + ng build grün · e2e via wrangler dev + D1: Onboarding einreichen → Vorschlag 5 Felder → übernehmen → Mandant email/telefon/strasse/plz/ort gesetzt; Re-Vorschlag leer = idempotent. MED-OP-FORM-3 ✅ geschlossen. Nutzer-"Med-op-form-3 bauen" 11.07. |
| MED-D-87 | 2026-07-11 | R1/R12 · G-8/MED-OP-DATA-1 | MED-OP-DATA-1 abgeschlossen: Rechnungsanschrift + Praxis-Anschrift strukturiert (Wertobjekt Anschrift). (1) dienstleistungsauftrag_ausfuellen_v1: rechnungsanschrift (einzeilig) → rechnung_strasse/rechnung_plz/rechnung_ort (eigene Schlüssel, Rechnungs- ≠ Wohnanschrift; keine Stammdaten-Rückübernahme). (2) Praxis: neue strukturierte Anschrift strasse/plz/ort (R1-F30..F32, Migration v34); Legacy-standort bleibt als Anzeige-Fallback (kein Parser, keine Datenmigration). Client-Anlage/Edit + Akte/Arbeitssicht zeigen die zusammengesetzte Anschrift (praxisAnschrift()); Lead-Formular legt die strukturiert erhobene Adresse direkt an der Praxis ab. | G-8-Angleichung der beiden verbliebenen Einzeilen-Adressen. Additiv statt Big-Bang: standort bleibt (kein Adress-Parser für Bestandsdaten, MED-D-85 "kein Verlust-Mapping"); neue Eingabe ist strukturiert, Anzeige bevorzugt strukturiert + Fallback. Rechnungs-Adresse mit eigenem rechnung_*-Präfix, um Billing- und Wohnanschrift nicht zu vermengen. | gebaut (0.59.1 → 0.60.0, MINOR) · +1 Vitest (Praxis strukturierte Anschrift, 397/40) · tsc + ng build grün · e2e via wrangler dev + D1 (v34): Praxis strasse/plz/ort verlustfrei; Dienstleistungsauftrag rechnung_* strukturiert eingereicht. MED-OP-DATA-1 ✅ geschlossen. Nutzer-"Beides direkt nachziehen" 11.07. |
| MED-D-86 | 2026-07-11 | R12 · G-8/MED-OP-DATA-1 | Anschrift im Ausfüll-Formular strukturiert (Straße · PLZ · Ort) — erste Umsetzung von MED-OP-DATA-1. Der kundendatenbogen_v1 erhebt die Adresse jetzt in drei Pflichtfeldern strasse/plz/ort statt eines einzeiligen anschrift-Feldes (domain/ausfuellformular.ts); die Stammdaten-Rückübernahme (domain/stammdaten-uebernahme.ts) bildet sie 1:1 verlustfrei ab (neue Ziele plz/ort in STAMM_ZIELE). | G-8-Angleichung (MED-D-85): das Wertobjekt Anschrift wird an der ersten Divergenz durchgesetzt → die grobe anschrift→strasse-Abbildung (MED-D-84, kein Parser) entfällt. Kein Schema-/Migrations-Change (Mandant-Felder existieren seit v33), Client rendert generisch aus dem Katalog. | gebaut (0.59.0 → 0.59.1, PATCH) · 396/40 Vitest (Assertions aktualisiert) · tsc + ng build grün · e2e via wrangler dev + D1: Kundendatenbogen strasse/plz/ort → übernehmen → Mandant verlustfrei gesetzt. Rest MED-OP-DATA-1: rechnungsanschrift + Praxis.standort weiterhin einzeilig. Nutzer-"Ja" 11.07. |
| MED-D-85 | 2026-07-11 | Architektur · G-2/G-3/G-8 | Data Dictionary / Weltmodell aufbauen — Entitäten überall gleich strukturiert; Anschrift als erstes kanonisches Wertobjekt. Neues Leitprinzip G-8 + Doc docs/architektur/Weltmodell-Data-Dictionary.md: kanonischer Katalog der Entitäten & Wertobjekte (Name · Anschrift · Bankverbindung · Kontakt), einmal definiert, überall in derselben Struktur (UI · API/DTO · Persistenz · Doku), nie zwei divergierende Formen. Anschrift = strasse (Straße inkl. Hausnummer) · plz · ort, immer getrennt (nie einzeilige Adresszeile); Anzeige-Adresse ist abgeleitete View-Logik (G-2). Bestehende Einzeilen-Adressen (Ausfüll-Formular anschrift/rechnungsanschrift, Praxis.standort) werden angeglichen. | Anlass: MED-D-84 machte die bewusst grobe anschrift→strasse-Abbildung (einzeiliges Formularfeld, kein Parser) sichtbar → Auslöser, Adressen (und weitere Wertobjekte) strukturiert & wiederverwendbar zu führen. G-2/G-3: eine Wahrheit + selbsterklärende, überall gleiche Feldnamen; strukturierte Felder sind auswert-/prüf-/löschbar (DSGVO). Kein Big-Bang: gemischter Bestand, Angleichung beim nächsten Anfassen (analog ID-System). | Doku-only (APP_VERSION unverändert 0.59.0). Neu: Doc + G-8 (CLAUDE.md) + Tiefenquellen + docs/README; MED-OP-DATA-1 (Angleichungs-Backlog: Ausfüll-Formular-anschrift/rechnungsanschrift, Praxis.standort → Anschrift). Mandant-Adresse (strasse/plz/ort, MED-D-84) + Name (nachname/titel/vorname, D-31) + IBAN (MED-D-71) sind bereits strukturiert. Nutzer-Auftrag 11.07. "Data Dictionary / Weltmodell aufbauen; Anschrift = Straße+Hausnr., separat PLZ und Ort". |
| MED-D-84 | 2026-07-11 | R1/R12 · MED-D-63 · G-6 | Formular-Antworten → Stammdaten zurückschreiben (Review-and-apply) + neue Kontakt-/Adress-PII. Eingereichte Ausfüll-Formular-Antworten (MED-D-63) fließen in die Stammdaten: AusfuellformularService.uebernahmeVorschlag(mandantId, token) baut den Diff (rein: domain/stammdaten-uebernahme.ts), uebernehmen(mandantId, token, auswahl) schreibt nur ausgewählte + gültige Felder (IBAN Mod-97/Datum erneut geprüft), Audit stammdaten.uebernommen PII-arm; idempotent + mandant-scoped. Neue Mandant-PII telefon/geburtsdatum/strasse/plz/ort (R1-F14..F18, Migration v33). Routen GET/POST /api/mandanten/:id/ausfuellformulare/:token/{uebernahme-vorschlag,uebernehmen}; Client-Review-Panel + read-only Kontakt/Anschrift in Arbeitssicht & Akte. | Umfang "B" (Nutzer): Datenmodell um neue PII erweitern (statt nur bestehende Ziele). Review-and-apply statt Auto-Übernahme (RISK-14/G-4): der Mensch prüft/wählt, nichts wird still überschrieben — spiegelt den Meeting-Aufgaben-Fluss (MED-D-82). G-1/G-2: Eigenbau = nur die Orchestrierung Formular↔Stammsatz; Werte liegen bereits strukturiert (kundenWerte, G-2) — kein zweiter Store. Einzeilige anschrift→strasse bewusst grob (kein Adress-Parser). | gebaut (0.58.1 → 0.59.0, MINOR) · +16 Vitest (stammdaten-uebernahme.test.ts + Service/HTTP, 396/40) · tsc + ng build grün · end-to-end via wrangler dev + D1 (v33; einreichen → Vorschlag 3 Felder → übernehmen → telefon/geburtsdatum/strasse gesetzt; Re-Vorschlag leer = idempotent). Compliance: neue PII-Persistenz G-6 begründet (Kontakt/Identität/Vertrag), EU-Residenz; Feld-Verschlüsselung-at-rest + Retention → MED-KB-6 offen (Risikoregister). Onboarding-Rückübernahme als Folge-Increment (Domäne regel-getrieben). Nutzer-"then b" 11.07. |
| MED-D-83 | 2026-07-08 | DM-1/DM-9 · UX | Dentmarking-Fragebogen: prominenter Hinweis oben. Auf der öffentlichen Betriebskennzahlen-Fragebogen-Seite (fragebogen-public.component.ts) steht ganz oben ein hervorgehobener Hinweis-Kasten (.md-fb-hinweis, grün akzentuiert): "Je vollständiger Ihre Angaben, desto aussagekräftiger Ihr Gutachten" (Vollständigkeit lohnt sich) und "Fragebogen in mehreren Schritten ausfüllen — jederzeit zwischenspeichern und über denselben Link fortsetzen". Der "weiß ich nicht"/"wird nachgeliefert"-Hinweis wandert in den Kasten; die Kontextzeile (Praxis · Geschäftsjahr) bleibt darüber. | Nutzerwunsch: "mehr Daten sind besser" sichtbar machen (Stammdaten/Vollständigkeit großschreiben) und das bereits gebaute Zwischenspeichern (DM-9) explizit als "Bearbeitung in Schritten" erklären — beides senkt die Abbruchquote und hebt den Ausfüllgrad (→ aussagekräftigeres Gutachten). Rein Copy/Client, kein neuer Zustand (G-2), keine neue PII. | gebaut (0.58.0 → 0.58.1, PATCH) · ng build grün · kein Server-Change/keine neuen Tests (reine UI-Copy). Nutzer-Anlass 08.07.: "auf dem Fragebogen zu Dentmarking oben anzeigen, dass mehr Daten besser sind — Bearbeitung in Schritten; Stammdaten großschreiben". |
| MED-D-97 | 2026-07-12 | Doku/Prozess · OP-DOCS-1 · G-2 | Doku-Meisterwerk-Audit erstellt + regelmäßige Meisterwerk-Audits (App + Doku) verankert. (1) Erster Doku-Audit docs/betrieb/Doku-Review-2026-07.md (Bezugspunkt v0.65.0 @ 3d625a4): 19 Befunde B1–B19 (Einstiegs-Docs erzählen falschen Stand: Sanity-Checkliste ⛔/Pre-MVP, README 0.9.1, MVP-Scope 0.9.0 · Stand-Info an 3 Orten entartet: CLAUDE.md 29,5k-Zeichen-Zeile, HANDOFF 3× §2 + 4 OP-Dubletten · Regeln 3–4× definiert mit belegter Drift: G-8 fehlt in 5 Docs) → Maßnahmen als MED-OP-DOKU-1..3 (drei Doku-Wellen) in HANDOFF §4. (2) Beide Quality-Audits laufen künftig regelmäßig ("Ist die App / die Doku ein Meisterwerk?"): Kadenz ~alle 10 Minor-Versionen oder 3 Monate + nach Meilensteinen/Wellen-Abschluss; Bezugspunkt-Pflicht (Version · Commit · Datum in der Titelzeile); Stale-Regel (Bezugspunkt ≥10 Minor oder >90 Tage alt → Agent regt aktiv Aktualisierung an, Konsistenz-Check warnt mechanisch). Kanonische Definition: agents.md §6.7 (bewusst EIN Ort — Lehre aus B17); CLAUDE.md verweist nur. | Audit-Erkenntnis: die lebenden Logs werden gepflegt, die Rahmen-/Einstiegs-Docs verrotten unbemerkt (Wurzelursache: ~10 Pflege-Docs je PR, Check zu schwach). Ein wiederkehrender, versionierter Audit mit klarem Bezugspunkt macht Drift messbar statt zufällig auffindbar; die Stale-Regel verhindert, dass ein alter Audit fälschlich als aktueller Zustand gelesen wird (G-2: eine Wahrheit gilt auch für Meta-Doku). | Doku + Skript (APP_VERSION unverändert 0.65.0): neu Doku-Review-2026-07.md, agents.md §6.7, CLAUDE.md-Bullet, HANDOFF §4 +4 OPs (MED-OP-DOKU-1..3, MED-OP-REVIEW-1), check-doc-consistency.sh Abschnitt 4 (Audit-Frische, warnt/blockt nicht). Nutzer-Auftrag + "Ja" 12.07.: "Quality-Audits regelmäßig; Bezugspunkt/Version/Build-Datum immer klar nennen; bei zu altem Stand Aktualisierung anregen". |
| MED-D-98 | 2026-07-12 | Doku · MED-OP-DOKU-1 | Doku-Welle 1 "eine Wahrheit wiederherstellen" umgesetzt. (1) HANDOFF entlogt: §2 von sechs Duplikat-Blöcken (411 Zeilen, längste Zeile 37,6k Zeichen) auf einen kompakten Stand-Absatz kollabiert (Historie lebt ausschließlich im CHANGELOG), §4-Dubletten (OP-DEX-1..5 / OP-DENTMARK-1 alt / OP-TOOLSPEC-1 alt) gemergt, §5 von Slice-1-Zeiten auf heute gezogen. (2) CLAUDE.md: 29,5k-Zeichen-Versions-Zeile auf 9-Zeilen-Stand + CHANGELOG-Verweis gekürzt. (3) Status-Sync: README (0.9.1/92→0.65.0/419, Slices 1–13), Sanity-Checkliste ehrlich neu bewertet (True North #1 ✅ · #2 ✅ · #3 🟡 statt 3× ⛔ "Pre-MVP"; Lücke #3 = Fake-E-Signatur MED-KB-5 + E-Mail OP-DM-8), MVP-Scope (Widerspruch 1–5/1–8 aufgelöst, Slices 10–13 im Backlog, R1-F04/D-45 bereinigt), Management-Summary (0.58.0→0.65.0, acht Prinzipien inkl. G-8), Test-Übersicht-Stempel, Lastenheft §3 +G-6/G-7/G-8 + §4 R1–R13. (4) G-8 nachgezogen in Entwicklungsansatz (Tabelle+Mermaid), docs/README, CLAUDE.md-Querverweise. (5) R2-Aktivierung (MED-D-61) in die vier Ablage-Docs (Dokumentenverwaltung-NextCloud-Statuskopf, System-Charakter §3-Tabelle + 2 Mermaid-Labels, Unterschriften, Dentmarking ×4) — Formulierung "Ablage (R3; produktiv R2, MED-D-61)", NextCloud = umschaltbarer Treiber. | Doku-Audit-Befunde B1–B6/B9/B10 (MED-D-97): Einstiegs-Docs erzählten einen ~40 Minor-Versionen alten Stand — jede neue Session multiplizierte den Schaden; G-2 ("eine Wahrheit") gilt auch für die Doku selbst. Historische Log-Zeilen (Decision-Log/Timesheet) bewusst nicht retro-editiert (append-only). | Doku-only (APP_VERSION unverändert 0.65.0) · check-doc-consistency.sh grün (keine toten Links) · Mermaid-Änderungen validiert · verbleibende "G-1…G-7"-Treffer nur in append-only-Historie + Audit-Zitaten. Rest: MED-OP-DOKU-2/3 offen. Nutzer-"Ja" 12.07. |
| MED-D-95 | 2026-07-12 | Produktmodell · R1/DM · MED-OP-AUFTRAG-1 | Beratungsaufträge — 3-Ebenen-Modell (Slice A): Person (ein Lifecycle) → Beratungsauftrag (0..n je Mandant: EIN Produkt aus dem Katalog Dentmarking-Gutachten · Versicherungsoptimierung · Praxisfinanzierung · Geldanlage · Dexman-Controlling (vorbereitet, verfuegbar:false), optionaler Praxis-Bezug, eigener Status anbahnung→beratung→unterschrift→laufend→abgeschlossen, laufend nur Dauer-Produkte) → Artefakte (Verknüpfung Slice B). Entität + Migration v36 + domain/beratungsauftrag.ts (Katalog, G-8) + BeratungsauftragService + neues quer-liegendes Register "Beratungsaufträge"; Dentmarking komplett aus dem Erstkontakt dorthin umgezogen (akte-dentmarking-Panel). | Nutzer 12.07.: "Ein Lead/Kunde hat verschiedene Beratungs-Produkte … Dentmarking sitzt 'zu weit vorne'." Entscheidungen (Nutzer-bestätigt): Begriff "Beratungsauftrag" statt "Mandat" (Verwechslung "Mandant") · Design-Doc + Slice A in EINEM PR · Katalog initial 5 Produkte, mit Kunde bestätigen (KB) · Slices B (auftragRef/Auftrags-Reife/Retro-Ableitung) + C (Produkt-Playbooks, Cockpit-Kontext, Lead-Auto-Anlage, Dexman) = MED-OP-AUFTRAG-1. | gebaut (0.67.0 → 0.68.0, MINOR) · Migration v36 · +6 Vitest (425/42) · ng build grün · e2e via wrangler dev + Playwright (Anlage mit Praxis-Wahl, Dexman gesperrt, Status persistent nach Reload, Dentmarking im neuen Register, Erstkontakt ohne Betriebsdaten, Verlauf sprechend) · Design: docs/architektur/Beratungsauftraege.md. |
| MED-D-99 | 2026-07-12 | Produktmodell · MED-KB-7 · G-3/G-8 | Beratungsauftrag-Produkt-Katalog finalisiert (Kundenbestätigung MED-KB-7). Katalog von 5 auf 9 Produkte erweitert: neu Investitionsberatung Erneuerbare Energien · Existenzgründung · Abrechnungsberatung · Praxisnachfolge (die drei Letztgenannten einmalig); geldanlage → kapitalanlage umbenannt (Label "Kapitalanlage"); Versicherungsoptimierung · Kapitalanlage · Investitionsberatung = Person ODER Praxis/Gesellschaft (praxisbezogen:true = Praxis optional). Datenmigration v37 (UPDATE … produkt geldanlage→kapitalanlage, idempotent, Audit-Historie unangetastet). | Nutzer/Kunde 12.07.: "Zusätzliche Produkte Existenzgründung, Abrechnungsberatung, Praxisnachfolge — alles einmalig. Versicherungsoptimierung kann Person oder Praxis sein, Geldanlage ebenso, das soll aber Kapitalanlage sein; ebenso Investitionsberatung Erneuerbare Energien." Selbst gewählte Defaults (mangels Spezifikation, transparent gemacht): Investitionsberatung EE = einmalig; Kapitalanlage behält den laufenden Charakter der bisherigen Geldanlage. Nebenwirkung: kein Produkt ist mehr praxisbezogen:false → der praxis_nicht_erlaubt-Guard (#132) ist dormant, bleibt aber als Absicherung für ein künftiges reines Personen-Produkt. | gebaut (0.68.1 → 0.69.0, MINOR) · Migration v37 · 427 Vitest (Katalog-/Status-Assertions aktualisiert) · ng build grün · e2e via wrangler dev + D1 (Migration real verifiziert: geldanlage-Zeile → kapitalanlage; 9 Produkte im Katalog; Versicherungsoptimierung optionaler Praxis-Bezug) · MED-KB-7 ✅ · Design: docs/architektur/Beratungsauftraege.md. |
| MED-D-100 | 2026-07-12 | Tooling/Prozess · MED-D-59/60 | CodeRabbit: genau EIN Review je PR, keine inkrementellen Re-Reviews. .coderabbit.yaml auto_incremental_review: false (war true) — CodeRabbit reviewt nur noch einmal beim Umschalten auf "ready for review", nicht mehr je Folge-Push. Senkt den Review-Spend (Rate-Limit/Org-Spending-Cap) deutlich. | Nutzer 12.07.: "CodeRabbit auf einmaligen Review bei ready-PR, keine inkrementellen Reviews." Wir liefen wiederholt ins Rate-Limit, weil Feature-PRs direkt als "ready" geöffnet wurden und JEDER Push re-reviewt wurde. Trade-off (dokumentiert): ein Push NACH dem Ready-Review bekommt keinen frischen CodeRabbit-Status → der Required-Check (MED-D-59) auf dem neuen Head bleibt offen, Auto-Merge wartet auf manuelles @coderabbitai review. Bewusst akzeptiert (seltener Fall; ergänzt den Draft-Workflow MED-D-60). | Config + Doku (APP_VERSION unverändert): .coderabbit.yaml (2 Kommentare + Flag), agents.md §7 neu gefasst. Kein Code-/Schema-Change. |
| MED-D-101 | 2026-07-12 | Produktmodell · R-Artefakte · MED-OP-AUFTRAG-1 | Beratungsaufträge Slice B: Artefakte binden + Auftrags-Reife + Retro-Ableitung. Ebene 3 des 3-Ebenen-Modells scharf: nullable auftrag_ref (Migration v38) an Beratungsdoku · Dokumente · Wiedervorlagen · Gutachten (bestehende Artefakte bleiben ungebunden — keine Regression). Service binden/loesen (mandant-scoped, Artefakt-Prüfung über die scoped Sammlung), reine auftragReife(status, produkt, zaehlung) (schlanke Checkliste: Dentmarking-Gutachten braucht ein Gutachten; andere Produkte ab Beratung eine Beratungsdoku, ab Unterschrift ein unterschriebenes Dokument), idempotente retroAbleitung (je Praxis mit Gutachten EIN dentmarking_gutachten-Auftrag, Status abgeschlossen, Gutachten gebunden). Routen + Client-Panel (Reife-Pille, gebundene Artefakte, Verknüpfen-Select, Retro-Button). Audit auftrag.artefakt_gebunden/_geloest/retro_abgeleitet PII-arm. | Fahrplan MED-OP-AUFTRAG-1 (Design-Doc §6). Nutzer-bestätigte Defaults: Retro-Status abgeschlossen (Deliverable existiert), schlanke Reife. Reife-Regel für das Gutachten-Produkt bewusst ohne Beratungsdoku-/Unterschrift-Anforderung (Analyse-Produkt, Deliverable = Gutachten). | gebaut (0.69.0 → 0.70.0, MINOR) · Migration v38 · +6 Vitest (433/42) · tsc + ng build grün · e2e via wrangler dev + D1 (v38; Retro idempotent 2 Gutachten→1 Auftrag, zweiter Lauf 0/0; Binding/Reife-Übergänge + Scoping-404 real geprüft) · Design: Beratungsauftraege.md §6. |
| MED-D-102 | 2026-07-12 | Slice B · Korrektheit/Review | Beratungsaufträge Slice B — CodeRabbit-Review-Nacharbeit. (1) Bindungs-Besitz-Guard: binden/loesen prüfen die aktuelle Bindung (Lösen nur am eigenen Auftrag; Binden nur eines ungebundenen Artefakts) → neuer Grund artefakt_anders_gebunden (HTTP 409). (2) Client akte-auftraege: Mandanten-Wechsel-Race per Lade-Token abgesichert. (3) ArtefaktTyp aus enums.ts importiert (G-8); sammleArtefakte Gutachten-Load parallelisiert (kein N+1); UI-Text "bestehende(s)" ausgeschrieben; Doku-Sync 0.70.1/434. | CodeRabbit-Findings auf #135 (Major: Lösen/Umhängen fremder Auftrag; Client-Race). Bewusst NICHT umgesetzt (begründet): (a) DB-UNIQUE(mandant,praxis,produkt) für Retro-Ableitung ist domänenfalsch — mehrere Aufträge desselben Produkts je Praxis sind legitim; (b) volle transaktionale Atomarität von Binden/Retro = querschnittliche Concurrency-Frage (Einzelnutzer-Tool), der Service-Besitz-Guard deckt die logische Fehlbindung ab; (c) ArtefaktTyp bleibt client-seitig gespiegelt (kein Shared-Package, wie alle Client-Typen). | gebaut (0.70.0 → 0.70.1, PATCH) · +1 Vitest (434/42) · tsc + ng build grün. |
| MED-D-103 | 2026-07-12 | Slice B · Review-Politur | #136-Review-Nachlese. 409-Konflikt-Meldung neutral formuliert (deckt "fremd gebunden" UND "beim Lösen bereits ungebunden" ab; +1 Test-Assertion); HANDOFF-Klammer geschlossen; Restrisiko der nicht-atomaren Bindung in HANDOFF §4 ehrlich benannt (gleichzeitiger Doppel-Submit → möglich ungenaues Audit). | CodeRabbit #136 (Minor: 409-Wortlaut, Doku-Klammer, Timesheet-Ehrlichkeit; Nitpick: Identifier-Sprache; Major: atomare CAS). Bewusst NICHT umgesetzt: (a) atomare Compare-and-Set-Bindung bleibt dokumentierter Deferral (MED-D-102) — querschnittlich, kein Einzel-Fix; die logische Fehlbindung ist per Service-Guard + Client-Token abgedeckt, das Restrisiko ist der oben benannte, für Einzeloperator tragbare Doppel-Submit; (b) ladeFolge/istAktuell bleiben deutsch — die ganze Codebasis nutzt deutsche technische Bezeichner (ladeVon/laden/arbeitet); ein englisches Trio wäre lokal inkonsistent. | gebaut (0.70.1 → 0.70.2, PATCH) · tsc + ng build grün · 434 Vitest. |
| MED-D-104 | 2026-07-12 | Slice C1 · MED-OP-AUFTRAG-1 | Beratungsaufträge Slice C1 — Produkt-Playbooks. Beim Anlegen eines Auftrags entstehen je Produkt Standard-Folgeaufgaben als Wiedervorlagen (quelle=playbook, an den Auftrag gebunden via auftragRef, idempotent via auftrag-playbook:<auftragId>:<schluessel>; Fälligkeit relativ zu angelegtAm). Neuer Katalog domain/auftrag-playbook.ts (2 Aufgaben je buchbarem Produkt, dexman leer), analog Phasen-Playbook; NeueWiedervorlage.auftragRef durchgereicht; Audit auftrag.playbook PII-arm. Retro-Aufträge (abgeschlossen) durchlaufen es nicht. | Fahrplan MED-OP-AUFTRAG-1. Scope-Entscheidung: Slice C ist heterogen (4 Teile) → bewusst aufgeteilt: C1 Playbooks jetzt; C2+ offen (Cockpit-Kontext; Lead-Auto-Anlage — Lead-Formular erfasst noch kein Produkt-Interesse, eigener Schnitt; Dexman R10 = separater Tool-Host-Track, verfuegbar:false). Playbook bewusst als Code-Katalog (schlank; admin-editierbar wie der Phasen-Store wäre spätere Erweiterung). | gebaut (0.70.2 → 0.71.0, MINOR) · +2 Vitest (436/42) · tsc + ng build grün · e2e via wrangler dev + D1 (Auftrag anlegen → 2 gebundene Playbook-WVs) · Design: Beratungsauftraege.md §6. |
| MED-D-105 | 2026-07-12 | Slice C1 · Stabilität/Review | Slice C1 — CodeRabbit-Review-Nacharbeit (Playbook-Fehler-Isolation). BeratungsauftragService.anlegen umschließt die Playbook-Erzeugung mit einer Fehler-Grenze: ein Repo-Fehler beim Anlegen der Standard-Folgeaufgaben lässt die bereits persistierte + auditierte Auftrags-Anlage nicht mehr scheitern (die Anlage selbst ist nicht idempotent → ein Client-Retry hätte einen zweiten Auftrag angelegt). Der Fehler wird isoliert und PII-arm als auftrag.playbook_fehler auditiert (nur Fehler-Klasse, nie -Meldung; G-4/G-6), Client-Audit-Label ergänzt. Zusätzlich Doku-Konsistenz: vier untererfasste Test-Übersicht-Zeilen auf die realen Zählungen angeglichen (Detailsumme = Kopf), HANDOFF-Teststand 434→437, Feature-Listen-Stand 0.71.1, #138-PR-Link. | CodeRabbit-Findings auf #138 (Major: Playbook-Fehler kippt die Anlage → Retry-Doppel; Minor: Doku-Zahlen/Version/PR-Link). Bewusst NICHT umgesetzt: die Fehler-Isolation ist best-effort (auch das Fehler-Audit darf die Anlage nicht scheitern lassen) — eine echte Transaktion um Auftrag+Playbook wäre querschnittlich (Read-modify-write im ganzen Code, wie MED-D-102), kein Einzel-Fix. | gebaut (0.71.0 → 0.71.1, PATCH) · +1 Vitest (437/42) · tsc + ng build grün. |
| MED-D-106 | 2026-07-12 | Slice C2a · MED-OP-AUFTRAG-1 | Beratungsaufträge Slice C2a — Lead-Auto-Anlage. Das öffentliche Lead-Formular erfasst optionales Produkt-Interesse (Mehrfachauswahl, nur buchbare Produkte — dexman verfuegbar:false ausgenommen). Bei Einreichung entsteht je gewähltem Produkt direkt ein Beratungsauftrag (Status anbahnung, an die Lead-Praxis gebunden) samt Produkt-Playbook (Slice C1). LeadService bekommt den BeratungsauftragService optional injiziert, kontext() liefert den buchbaren Katalog, einreichen nimmt interesse[] und delegiert je bekanntem+buchbarem Produkt; Ingress-Scrubbing verwirft Unbekanntes/Nicht-buchbares/Duplikate (G-6); Audit lead.eingegangen zählt die Aufträge PII-arm. Schließt den Kreis Lead → Auftrag → Folgeaufgaben (True North #1/#2 ab Erstkontakt je Auftrag). | Nutzer-Priorisierung "1" = Lead-Auto-Anlage vor Cockpit-Kontext (höchster Automatisierungswert). Default (selbst gewählt): Interesse optional (ein Lead darf auch nur allgemeinen Kontakt wünschen); Auftrag an die eine Lead-Praxis gebunden (alle Produkte praxisbezogen-optional). Wiederverwendung von BeratungsauftragService.anlegen (statt Dupl-Logik) bringt Playbook + Fehler-Isolation (MED-D-105) gratis mit. Bewusst NICHT: kein Cockpit-/Detail-Umbau (Slice C2b), keine Migration (nur Enum-Array am Ingress, keine neue Persistenz-PII). | gebaut (0.71.1 → 0.72.0, MINOR) · +5 Vitest (442/42) · tsc + ng build grün · e2e via wrangler dev + D1 (2 Interessen → 2 Aufträge anbahnung + 4 Playbook-WVs + Audit auftraege:2) · Design: Beratungsauftraege.md §6. |
| MED-D-107 | 2026-07-12 | Meisterwerk-Audit App · MED-OP-REVIEW-1 | App-UX-Audit aufgefrischt v0.62.0 → v0.72.0 (Bezugspunkt Commit 7a13ce5). Methode: vier parallele Code-Dimensions-Reviews (Feedback-Verlässlichkeit · Sprache G-3/G-8 · Kundenstrecken · Design/Mobile/A11y) mit Verdikt je Alt-Befund + Live-Begehung (wrangler dev + D1, Desktop/Mobil, scrollWidth-Messung). Ergebnis: die vier v0.62.0-Kernrisiken sind adressiert (UX-Wellen 1–5) — Feedback verlässlich (Interceptor, keine Schein-Aktionen), eine Sprache (labels.ts), Kundenstrecken mit Handschrift (pub-bausteine, K1/K4 behoben), Cockpit mobil bedienbar; Dimensions-Noten durchweg gestiegen. Neuer Backlog B1–B7 → Wellen 6/7/8 (MED-OP-UX-5/6/7): Akte mobil defekt (390px→944px Overflow, live), interne IDs/rohe Enums in sichtbaren Texten (Druck-Akte), stille 4xx-GET-Fehler, WCAG-AA-Politur, Handschrift-Restschuld. | MED-OP-REVIEW-1/MED-D-97 Stale-Regel: v0.62.0-Audit war mit v0.72.0 genau 10 Minor-Versionen alt → aufzufrischen. Entscheidung: die lebende App-Audit-Datei UX-Prozess-Review-2026-07.md in place auf v0.72.0 gehoben (Alt-Befunde als Verdikte übernommen, kein Informationsverlust; git hält die v0.62.0-Fassung); mechanischer Frische-Check greift wieder. | Doku-Audit (keine Versionsänderung) · check-doc-consistency.sh grün (Audit-Frische geklärt) · HANDOFF MED-OP-REVIEW-1 + MED-OP-UX-5/6/7. |
| MED-D-108 | 2026-07-12 | Anforderungen/Prozess · Kundenmeeting | Abstimmungstermin 12.07.2026 eingearbeitet (Bestätigungen + neue Festlegungen; keine Versionsänderung, Doku). Bereinigtes Protokoll: docs/fachlich/Anforderungen-Meeting-2026-07-12.md (M1–M20, A1–A10). Bestätigt (kein Bau nötig): (a) "Akte" = CRM (Daylite) + Ablage + Beratungsmandate plus Orchestrierung/Audit/Zeiten (3-/2-Ebenen-Modell MED-D-95); (b) Betreuungsintensität Intensiv/Standard/Basis — bewusst nicht A/B/C oder Gold/Silber/Bronze (schärft OP-ABC-1: das gebaute betreuungsmodell R1-F11/D-35 erfüllt den "diskret im Kundengespräch"-Bedarf bereits); (c) Lifecycle Lead→Onboarding→Aktiv→Ruhend→Archiviert; (d) Weltmodell Titel/Vorname/Nachname separat + Anschrift Straße(inkl. Hausnr.)/PLZ/Ort (G-8); (e) drei Signaturstufen SES/DocuSign-AES/QES-Video-Postident je Rechtswirkung (OP-SIGN-1); (f) Review-and-apply "In Stammdaten übernehmen" + Zwischenspeichern + Feldvalidierung (MED-D-84/88/89); (g) Audit-Log hashverkettet/gerichtsfest inkl. Lese-Zugriffslog auf PII (G-4/D-50); (h) Barrierefreiheit; (i) SevDesk-Abrechnung + Abschlagsrechnungen (OP-INVOICE-1); (j) NextCloud entbehrlich, nur Read-Only-Notfall-Backup (MED-KB-4). Neue Festlegungen: (k) Flat-Fee-Automatik — hat ein Kunde eine monatliche Flat-Fee (am Vertrag erkennbar), erkennt das System automatisch "nicht gesondert abrechnen", erfasst die Zeit aber weiter (Rentabilität) → OP-TIME-1-Erweiterung; (l) Dexman-Kundenportal ohne Passwort — E-Mail eingeben → Einmal-Code/Magic-Link per Mail → Zugang; Backoffice kann den Link auch selbst erzeugen/verschicken (kurz gültig, an Vorzimmer weiterleitbar) → Dexman.md; (m) Leistungsstatistik pflegt der Kunde selbst (monatlich/quartalsweise, gewollt); PVS-Direktanbindung (Dampsoft/Charly/Evident/Computer konkret) ist späterer Ausbau, nicht Phase 1 (OP-DEX-1); (n) Mahnstufen-Banner in der Akte (OP-INVOICE-1-Rest). Action-Items: Kundendatenbogen-Felder ins Onboarding (OP-DOCGEN-1), Sutor-Bankformulare beschaffen (MED-KB-8), Dexman als Produkt anlegen, Dokumenten-Baumstruktur (M19), 2–3 Beispielkunden + Onboarding durchklickbar für den Folgetermin (~2 Wochen, Taktano per Video). | Kundentermin (Inhaber + Entwickler). Meeting war überwiegend Bestätigung des live gezeigten Stands 0.72.0; neue Punkte als OP/KB/Decision verankert statt sofort gebaut (klare Weggabelungen: Flat-Fee-Automatik, Portal-Login, Baumstruktur). Betreuungsintensität-Bestätigung deckt sich mit dem bereits gebauten betreuungsmodell → kein Doppelbau. | Doku (APP_VERSION unverändert 0.72.0): neues Meeting-Protokoll, HANDOFF §3/§4, Kunden-Besprechungspunkte (MED-KB-8 + MED-KB-4-Update), Dexman.md, Beratungsauftraege.md, CHANGELOG, Timesheet. Kein Code-/Schema-Change. |
| MED-D-109 | 2026-07-12 | Governance / Tooling · CI-Gate (schärft MED-D-59) | "Require branches to be up to date before merging" auf main abgeschaltet. Die Branch-Protection verlangt weiterhin die Required Checks CI Gate + CodeRabbit (MED-D-59 unverändert), aber nicht mehr, dass der PR-Branch den allerneuesten main enthält. Ein einmal grüner PR mergt per Auto-Merge, auch wenn main inzwischen weitergezogen ist (Status behind blockt nicht mehr). | Anlass: Bei paralleler Multi-Session-Arbeit erzeugte die Kombination "Required Checks + up-to-date-Pflicht" ein Laufband: PR grün → andere Session merged → PR behind → Branch-Update nötig → CodeRabbit re-reviewt (Free-Kontingent) → Rate-Limit → ~40 Min Wartezeit; am 12.07. dreimal aufgetreten (u. a. #129/#130). Das reine "behind" abzuschalten entfernt genau die Treadmill-Zutat und lässt die Qualitätssicherung (CI + Review-Pflicht) unangetastet. Trade-off bewusst: ein PR kann mergen, ohne gegen den allerneuesten main getestet zu sein (Risiko "semantischer Merge-Konflikt"); für uns gering, weil CI nach jedem main-Merge ohnehin baut/testet und Doku-PRs keinen Laufzeit-Code anfassen. Verworfene Alternative: CodeRabbit → Copilot (kein Required-Check-Status → Review würde beratend statt blockierend, senkt Gate-Strenge — abgelehnt). | Nutzer-Entscheidung 12.07. ("3a"). Repo-Setting (Branch-Protection main, nicht via MCP/Agent — Admin-Schritt, agents.md §6.5); Doku: agents.md §6.5/§7, HANDOFF §6, Deploy.md §7c. APP_VERSION unverändert 0.72.0 (Tooling-Config, analog MED-D-52/59). |
| MED-D-110 | 2026-07-12 | Doku · MED-OP-DOKU-2 · G-2 | Doku-Welle 2 "eine Definition, ein Ort" umgesetzt. (1) Phantom-Phase behoben (B7): das Prozessmodell-§3-Diagramm zeigte "Ablage" als Zustand und mischte Lifecycle-Werte (Lead/Archiv) in die Phasen-Achse — genau die Vermischung, die §2 (MED-D-79) verbietet. Korrigiert auf die sechs echten prozessphase-Enum-Werte (erstkontakt…archiviert); Ablage als quer-liegende Achse (§6) klargestellt; System-Charakter §1 mitgezogen. (2) Kanonische Quellen (B17/B18): neue agents.md §5.4 — Tabelle "welche Regel wohnt wo" (Prinzipien→CLAUDE.md, Session-Start/ID-System/Draft-PR/CI-Gate→agents.md, Phasen-Diagramm→Prozessmodell, Weltmodell→Data-Dictionary) + Pflege-Pflichtsatz je PR einmal definiert (bedingt "nur Betroffene", mit Last-Kritik: nicht jeder PR fasst ~10 Docs an). (3) ID-Vergabe bei parallelen Sessions (agents.md §3): neue IDs aus dem höchsten main-Stand ableiten, spät festlegen; Konfliktregel First-merge-wins (gemergte ID bleibt, nicht-gemergter PR weicht nach oben). (4) README-Stale R1–R12→R1–R13. | Doku-Audit B7/B16–B18 (MED-D-97): Regeln 3–4× definiert drifteten (G-8-Lücke war der Beweis); die Phantom-Phase war ein Selbstwiderspruch im autoritativen Prozess-Doc; parallele Sessions kollidierten am 12.07. zweimal bei der ID-Vergabe (MED-D-93/94, MED-D-95) → Regel nötig. "Eine Wahrheit" (G-2) gilt auch für Meta-/Prozess-Doku. Kein Big-Bang-Umbau der Leitplanke — die kanonische Tabelle macht Eigentümerschaft eindeutig, ohne CLAUDE.md-Inhalt zu strippen. | Doku-only (APP_VERSION unverändert 0.72.0): Prozessmodell §3 (+Mermaid), System-Charakter §1 (+2 Mermaid-Labels), agents.md §3/§5.4, README; Konsistenz-Check grün; Mermaid validiert. Rest MED-OP-DOKU-3 (Check schärfen + 7 Zielgruppen) offen. Nutzer-Auftrag "Dann MED-OP-DOKU-2" 12.07. |
| MED-D-111 | 2026-07-12 | UX-Welle 6 · MED-OP-UX-5 (B1) | Arbeits-Akte mobil responsiv (App-Audit-Befund B1). Die Detail-Akte (mandant-detail) reflowte bei 390px nicht (Overflow 944px). Per Live-Overflow-Messung als Ursache eingegrenzt: die Shell-Kopfzeile .md-header ist eine einzeilige, nicht-umbrechende Flex-Zeile → zwingt die Seite auf Desktop-Breite (das Cockpit nutzt eine andere, bereits responsive Kopfzeile .mw-header). Fix: @media (max-width:640px) → .md-header { flex-wrap: wrap }, Spacer bricht die rechte Gruppe um, Nutzer-Pille mit Ellipsis. | Erster Punkt der UX-Welle 6 (MED-OP-UX-5) aus dem v0.72.0-App-Audit (MED-D-107). Diagnose statt Raten: die überlaufenden Elemente per Playwright (getBoundingClientRect gegen Viewport) bestimmt → die Kopfzeile, nicht die Inhalts-Layouts (die reflowten bereits). Regression beim Bau gefunden+behoben: die geteilte Klasse .md-grow (Kopf-Spacer + Deckel-Titel-h2) → Regel auf .md-header > .md-grow eingegrenzt, sonst kollabierte der Akten-Titel. ID-Kollision zweimal behoben (Multi-Session, First-merge-wins gemäß agents.md §3): ursprünglich als MED-D-108 verfasst (kollidierte mit dem Kundenmeeting-Eintrag), dann auf MED-D-110 umnummeriert (kollidierte erneut mit der parallel gemergten Doku-Welle-2, die just diese Konfliktregel einführte) — jetzt auf die nächste freie ID MED-D-111 gesetzt; kein Bestandstext verändert. | gebaut (0.72.0 → 0.72.1, PATCH) · nur Client-CSS · verifiziert per wrangler dev + Playwright (Akte 390px statt 944px; Cockpit/Lead/Desktop unverändert) · 442 Vitest + tsc + ng build grün. |
| MED-D-112 | 2026-07-12 | Doku · Review-Nachlese | #144-Review-Nachlese (zwei valide Funde, ein Fehlalarm geprüft+verworfen). (1) CLAUDE.md-Statuszeile ergänzt: App-Audit-Auffrischung (MED-D-107) + gestartete UX-Welle 6/B1 (MED-D-111) fehlten nach dem 0.72.1-Versionssprung. (2) Feature-Liste.md: neue Zeile "Arbeits-Akte mobil responsiv (UX-Welle 6/B1)" analog zu den bestehenden Welle-1–5-Zeilen. (3) HANDOFF.md-Finding "mismatched quotes" bei "leere Liste"/"Laden fehlgeschlagen"-Zustand geprüft: Fehlalarm — öffnendes " (U+201E) + schließendes " (U+22, gerades Anführungszeichen) ist das im gesamten Dokument etablierte Muster (hunderte Stellen); LanguageTools DE_UNPAIRED_QUOTES verlangt eine schließende Ligatur ", die hier bewusst nicht genutzt wird. Kein Bestandstext geändert. | Die drei Findings stammten aus dem allerersten #144-Review, bevor zwei parallele ID-Kollisionen (MED-D-108→110→111) den PR mehrfach neu durchlaufen ließen; sie waren bislang unbearbeitet liegen geblieben. Verifiziert gegen den aktuellen main-Stand (nicht blind übernommen) — die Versionsangabe 0.72.1/442 Vitest war durch #144 bereits korrekt, nur die Prosa ("UX-Wellen 1–5") und die Feature-Liste hinkten hinterher. | Doku-only (APP_VERSION unverändert 0.72.1): CLAUDE.md, Feature-Liste.md; Konsistenz-Check grün. |
| MED-D-113 | 2026-07-12 | Doku/Tooling · MED-OP-DOKU-3 · OP-DOCS-1 | Doku-Welle 3 "Check schärfen + Zielgruppen komplettieren" umgesetzt — Doku-Meisterwerk-Auftrag abgeschlossen. (1) check-doc-consistency.sh um 4 semantische Checks erweitert: doppelte ##-Abschnitts-Überschriften je Datei (fängt "HANDOFF §2 dreimal", B4), doppelte aktive OP-Zeilen-IDs in HANDOFF §4 (durchgestrichene = Archiv ausgenommen), veraltete G-/R-Bereichsspannen (max G-n aus CLAUDE.md / R-n aus Lastenheft vs. "G-1…G-7"/"R1–R12"; append-only Logs + Audits ausgenommen), Stand-Stempel lebender Übersichts-Docs ↔ APP_VERSION. Aufgedeckte reale Drift sofort gefixt: Sanity-Checkliste + Management-Summary auf 0.72.0/442 Tests. (2) Lesepfade auf 7 Zielgruppen (Anwender · Business/Management · IT-Dev · IT-Ops · DevOps · CISO/Security · Customer Service) + Zielgruppen×Einstieg-Matrix. (3) Glossar-Generator nachgezogen: ZIELGRUPPEN 4→7, Modul-Range R1–R12→R1–R13, +3 Begriffe (Weltmodell/Data Dictionary, Anschrift-Wertobjekt, Leistungszeit/R13) → 41 Begriffe. (4) Sammelposten B12: OP-DOMAIN-1 in Produkt-Marketing als bestätigt (statt "offen"), Feature-Listen-Waisenzeile entfernt, "erstes Tool: Dexman"→"erstes gebautes: Dentmarking" (Erweiterbarkeit), Meeting-§3 Aufgaben-Ablageort als MED-D-82-entschieden (Medidentas-Wiedervorlagen, nicht CRM), Stack-"Optionen (zu bewerten)"→"(bewertet)". | Doku-Audit B8/B11–B15/B19 (MED-D-97): der Konsistenz-Check war zu schwach (grün trotz stale Stempeln/Dubletten) → gab falsche Sicherheit; die geschärften Checks sind der einzige Baustein, der künftige Verrottung verhindert statt heilt (Wurzelursache-Fix). Lesepfade/Glossar deckten nur 4 von 7 versprochenen Rollen ab. | Doku + Tooling (APP_VERSION unverändert 0.72.0): Lesepfade, glossar.mjs (+regenerierte Glossar.md), check-doc-consistency.sh (+4 Checks, high-signal getestet: 0 False-Positives), Sanity/Management-Summary-Stempel, 5 B12-Docs. (+) MED-OP-DOKU-4-Politur (P4) in dieser PR mit erledigt: Produkt-Marketing-BLUF, zwei tragende Mermaid-Diagramme (Feld-Sichtungs-Loop MED-D-89 im Prozessmodell §5, Dexman-Liquiditätsvorschau §4, beide validiert); Dexman/NextCloud waren bereits pyramidal. Damit alle drei Doku-Wellen + Politur ✅ — Doku-Meisterwerk-Auftrag abgeschlossen. Nutzer-"Ja" 12.07. |
| MED-D-114 | 2026-07-12 | UX-Welle 6 · MED-OP-UX-5 (B3) | Audit-Verlauf-Ladefehler sichtbar machen (App-Audit-Befund B3). Der zentrale HTTP-Interceptor fängt nur 0/5xx/403 ab — ein Ladefehler des Audit-Trails sah bislang identisch aus wie "keine Historie". Neue Signale verlaufFehler (interaktive Akte) + auditFehler (Druck-Akte): bei Fehler "Verlauf konnte nicht geladen werden" + Retry (verlaufLaden()) bzw. "Nachweis unvollständig" + Kopfzeile "(?)" statt "(0)". Die 2 Abrechnungs-Mutationen (lzAbrechenbarToggle/lzAbrechnen) hatten gar keinen Error-Handler — jetzt Fehler-Toast analog zum bereits gehärteten leistungszeitAusBeratung. | Beantwortet True North #2/#3 (was ist offen/fällig · ist alles vollständig & rechtssicher dokumentiert): ein Ladefehler des Audit-Trails darf nicht wie "keine Historie" aussehen. Zweiter Punkt der UX-Welle 6 (MED-OP-UX-5) aus dem v0.72.0-App-Audit. Priorisiert nach Schweregrad: Audit-Trail ist rechtssicherheitsrelevant (G-4) und Geld-Mutationen sind bewusst zuerst dran — die übrigen Sub-Ressourcen-Listen (Meetings/Aufträge/Einladungen/Formulare) bleiben bewusst zurückgestellt (niedrigere Priorität, kein Rechtssicherheits-/Geld-Bezug), offen für eine spätere Politur-Runde. Verifiziert per wrangler dev + Playwright mit erzwungenem 500 (Route-Interception) auf GET …/audit — Fehler-Zustand rendert korrekt in beiden Akten-Ansichten, Golden Path unverändert. ID-Kollision (dritte in Folge, First-merge-wins gemäß agents.md §3): ursprünglich als MED-D-113 verfasst — kollidierte mit der parallel gemergten Doku-Welle 3; auf MED-D-114 umnummeriert, kein Bestandstext verändert. | gebaut (0.72.1 → 0.72.2, PATCH) · nur Client · 442 Vitest + tsc + ng build grün. |
| MED-D-115 | 2026-07-13 | UX-Welle 6 · MED-OP-UX-5 (B4) | A11y-Basis (App-Audit-Befund B4) — UX-Welle 6 damit komplett. (1) --faint-Textfarbe im hellen Theme lag bei ≈2,8:1 Kontrast auf --bg/--panel (unter AA 4,5:1) — betrifft überwiegend Sub-0,7rem-Text (Cockpit-Sektionslabels/-Hinweise), der keine "großer-Text"-Ausnahme (3:1) bekommt; auf #5c665f verdunkelt (jetzt ≈5,3–6,0:1). Dunkles Theme (≈5,4:1) unverändert, war bereits über AA. (2) "Verlassen"-Modal (mandant-detail.component.ts, D-49) hatte keine Fokus-Falle — Tab konnte aus dem Dialog herausspringen. Jetzt echte Dialog-Semantik analog der Command-Palette (MED-D-93): Fokus geht beim Öffnen auf das erste Feld, Tab/Shift+Tab bleiben innerhalb gefangen, Escape löst "Zurück zur Akte" aus, Fokus kehrt beim Schließen dorthin zurück, wo er herkam. | Beantwortet True North #3 (ist alles rechtssicher & barrierefrei dokumentiert/bedienbar): zu geringer Kontrast und eine offene Fokus-Falle sind AA-Verstöße, die Screenreader-/Tastatur-Nutzer strukturell benachteiligen. Dritter und letzter Punkt der UX-Welle 6 (MED-OP-UX-5) aus dem v0.72.0-App-Audit — mit B4 sind B1/B3/B4 alle umgesetzt. Verifiziert per wrangler dev + Playwright: --faint-Token live geprüft; Modal-Fokus-Falle über den echten CanDeactivate-Guard ausgelöst (Playwright-Clock fährt den Timer über die Buchungs-Schwelle statt künstlicher Test-Hooks), 8× Tab/Shift+Tab bleiben nachweislich im Dialog (kein Fokus-Leak), Escape schließt + bleibt auf der Akte; Golden Path (keine Interaktion) navigiert weiterhin ohne Modal. | gebaut (0.72.2 → 0.72.3, PATCH) · nur Client · 442 Vitest + tsc + ng build grün. |
| MED-D-116 | 2026-07-13 | Client · Review-Nachlese | CodeRabbit-Review-Nachlese zu #151 (B4) — ein echter Bug behoben. #151 wurde gemergt, bevor CodeRabbits Review durchlief. Nachgezogen: (1) Echter Bug (Major): verlassenAbbrechen() (Escape-Taste und "Zurück zur Akte") prüfte nicht timerBuchtGerade() — Escape während einer laufenden Buchung setzte den CanDeactivate-Guard sofort mit false auf; kam danach die erfolgreiche Buchungs-Antwort, rief sie verlassenAufloesen(true) ein zweites Mal auf (Doppel-Buchungs-/Timer-Renn-Risiko). Fix: früher Return, solange timerBuchtGerade() wahr ist. (2) Fokus-Selektor auf einen vollständigen Tabbable-Selektor erweitert (input/textarea/select schlossen disabled nicht aus, Links fehlten). (3) verlModal/verlFokusierbare auf das im Datei etablierte verlassen…-Präfix umbenannt (verlassenModal/verlassenFokusierbare). Dazu HANDOFF.md-§2-Kopfzeile (hing bei 0.72.2, §5 nannte MED-OP-UX-5 noch offen) und Timesheet.md ("Drei" → "Zwei A11y-Lücken") nachgezogen. | Ein echtes Verhaltens-Risiko (Doppel-Buchung durch eine Renn-Bedingung, die mein eigener Escape-Handler erst eingeführt hat) — nicht nur Politur. Da #151 bereits gemergt war, als CodeRabbits Review eintraf, greift dieselbe Nachlese-Logik wie bei MED-D-112: Findings, die den Merge nicht mehr erreichen, werden als eigener kleiner Folge-PR nachgezogen statt stillschweigend verworfen. Die Anführungszeichen-Findings ("Verlassen"-Modal etc.) sind derselbe bereits als Fehlalarm dokumentierte Fall (MED-D-112) — bewusst nicht verändert. Verifiziert per wrangler dev + Playwright: Route-Interception verzögert die Buchungs-Antwort künstlich um 2s, Escape wird währenddessen gedrückt — Modal bleibt nachweislich offen (Guard blockt), schließt erst nach der echten Antwort, kein Doppel-Zustand, Navigation danach sauber. | gebaut (0.72.3 → 0.72.4, PATCH) · nur Client · 442 Vitest + tsc + ng build grün. |
| MED-D-117 | 2026-07-13 | Client · Review-Nachlese | CodeRabbit-Review-Nachlese II zu #151/#152 — dasselbe Muster wiederholt sich. #152 wurde gemergt, bevor CodeRabbits Review durchlief (dritte Merge-vor-Review-Runde in Folge auf diesem Branch). Nachgezogen: (1) Fokus-Selektor weiter verschärft — a[href] schloss tabindex="-1"-Links nicht aus, Inputs mit type="hidden" waren nicht ausgeschlossen, der generische [tabindex]-Zweig konnte deaktivierte-aber-tabindex-versehene Elemente zurückliefern; CodeRabbits vorgeschlagener Diff (:not(:disabled)-Pseudoklassen) 1:1 übernommen — reine Verhärtung, kein Verhaltensunterschied im heutigen Modal (keine tabindex-/hidden-Elemente vorhanden). (2) CHANGELOG-Eintrag zu MED-D-116 nannte nur die Vorgänger-PR #151, kein Link auf #152 selbst — nachgetragen. (3) Feature-Liste.md-Zeile A11y-Basis hing bei 0.72.3 fest, ohne den Buchungs-Guard/die Selektor-Härtung aus #152 zu erwähnen — ergänzt. | Erneut ein reiner Timing-Zufall zwischen Auto-Merge und CodeRabbits Review-Laufzeit, kein Schema-/Prozessfehler auf unserer Seite. Alle drei Findings sind Politur, kein zweiter echter Bug — daher knapp gehalten. Da erneut ein Code-File (mandant-detail.component.ts) angefasst wird, PATCH-Bump analog MED-D-116 (nicht doku-only wie MED-D-112). Verifiziert per wrangler dev + Playwright: Fokus-Falle (8× Tab/Shift+Tab) und Buchungs-Guard (Escape während künstlich verzögerter Buchungs-Antwort) beide erneut grün mit dem geänderten Selektor. | gebaut (0.72.4 → 0.72.5, PATCH) · nur Client · 442 Vitest + tsc + ng build grün. |
| MED-D-118 | 2026-07-13 | UX-Welle 7 · MED-OP-UX-6 (B2) | Eine Sprache, zu Ende — interne IDs & rohe Enums aus sichtbaren Texten (App-Audit-Befund B2). labels.ts deckte die Enums seit UX-Welle 2 ab, aber interne Kennungen standen weiter in der Prosa. Bereinigt (Druck-Akte zuerst, Außenwirkung): Requirement-IDs R3/R4/R5/R6/R12/R13, (G-4), MED-D-56 in mandant-akte.component.ts; Feld-IDs (F12)…(F20) an den Beratungsdoku-Rahmendaten in mandant-detail.component.ts (die frühere (F11)-Bereinigung war nie auf die Geschwister übertragen worden); OP-INVOICE-1/(G-1)/(G-4) aus den Rechnungs-/Audit-Hinweisen; zwei (R7)-Reste aus Zuweisen-Fehlermeldungen; R7/§5.1 aus verwaltung.component.ts; eine rohe Prozessphase im nativen confirm() beim Playbook-Löschen → PHASE_LABEL. Zwei rohe-Enum-Stellen geschlossen: Rollen-Dropdown ({{ b.rolle }} → ROLLE_LABEL) und gebundener-Artefakt-Status auf der neuen Beratungsaufträge-Fläche (neue artefaktStatusLabel(), typ-abhängig auf PRUEFSTATUS_LABEL/DOKUMENT_STATUS_LABEL/WV_STATUS_LABEL). Stale Consent-Text "Geldanlage" → "Kapitalanlage" (domain/einwilligung.ts, seit MED-D-99/Migration v37 umbenannt, aber im Einwilligungstext übersehen). Legitim und bewusst behalten: echte Gesetzeszitate (§19 VVG, §6 Abs. 3/§61 Abs. 2 VVG) — nur die daneben stehenden internen Feld-IDs raus. | Beantwortet G-3 (Selbsterklärbarkeit: sprechende Begriffe aus der Beratungs-/Back-office-Praxis statt technischer/abstrakter Labels — in UI und Doku) sowie indirekt True North #3 (rechtssicher dokumentiert heißt auch: für den Kunden verständlich, nicht nur juristisch korrekt). Der gebundene-Artefakt-Status war der schärfste Einzelfund: eine Beratungsdoku mit Prüfstatus ki_geprüft — genau die intern als "nicht kundenreif" markierte Klasse — hätte auf der neuen Auftrags-Fläche roh durchgereicht werden können. Priorisiert nach Außenwirkung: Druck-Akte (kundenseitig) zuerst, dann interaktive Akte, dann Verwaltung (nur intern). Verifiziert per wrangler dev + Playwright: automatisierter Leak-Scan über Druck-Akte + interaktive Akte findet keine der zuvor bekannten ID-Reste mehr; Rollen-Dropdown/Artefakt-Status-Label/Playbook-Confirm sind type-check-verifiziert (tsc, alle drei Label-Maps sind vollständige Record<...>-Typen), aber ohne Admin-Rolle bzw. passende Seed-Daten in dieser Sandbox nicht zusätzlich per Screenshot geprüft — transparent so dokumentiert statt stillschweigend als "live verifiziert" behauptet. | gebaut (0.72.5 → 0.73.0, MINOR — neue, rückwärtskompatible Sprach-/Konsistenz-Politur, kein Bugfix) · Client + eine Server-Textkonstante · 442 Vitest + tsc + ng build grün. |
| MED-D-119 | 2026-07-13 | UX-Welle 7 · MED-OP-UX-6 (B6) | Rest von B6 — Neue Flächen: Feinschliff. Damit UX-Welle 7 (MED-OP-UX-6) komplett. Schließt die im B2-PR (MED-D-118) bewusst zurückgestellten Punkte ab. (1) Lead-Interesse-Picker (lead-public.component.ts): Gruppenüberschrift war ein <label> ohne for/Control statt <fieldset>/<legend> — Screenreader kündigte keinen Gruppennamen an; Checkbox-Touchziele unter 24px. Fix: echtes <fieldset>/<legend>, Checkboxen auf 24×24px. Lead-Ladefehler nicht differenziert (jede Ursache → "Formular nicht erreichbar", anders als die dreiteilige Logik der anderen Strecken) — jetzt dieselbe ladeStatus/zugriffsschutz-Unterscheidung wie Onboarding/Formular/Fragebogen (ohne 404-Fall, da Lead tokenlos ist — kein Einladungslink, der ungültig werden könnte). (2) Fragebogen ist der Handschrift-Ausreißer: eigener Fortschrittsbalken/Score statt PubFortschritt → jetzt der geteilte md-pub-fortschritt-Baustein; ESSENZIELL/WICHTIG-Badges ohne erklärende Legende (nur Hover-title, auf Touch nicht entdeckbar) → neue sichtbare Legende ergänzt; tote CSS-Reste .md-fb-marker-actions/.md-linkbtn sowie die durch den Baustein-Wechsel unbenötigten .md-fb-score/.md-fb-bar*-Regeln entfernt. (3) Tote CSS-Reste in styles.css: @keyframes mwToast + Tokens --toastBg/--toastBd/--toastInk (Relikt eines älteren Toast-Prototyps — der reale Toast läuft längst über .md-toast/var(--md-slate)) entfernt; .md-step-Regel selbst unangetastet gelassen (bleibt für die weiterhin klickbare Druck-Akte-Variante korrekt), stattdessen gezielte cursor: default-Überschreibung am jetzt rein anzeigenden Stepper der interaktiven Akte (MED-OP-UX-3). | Rundet den in MED-D-118 bewusst gescopten B2-first-Ansatz ab, statt B6 offen liegen zu lassen — "kein silent scope-narrowing" (dieselbe Transparenz-Norm wie bei B3s Sub-Ressourcen-Aufschub in UX-Welle 6). Klein genug für einen PATCH-Bump innerhalb derselben bereits mit MINOR versionierten Welle (0.73.0), statt eine weitere MINOR-Stufe zu ziehen — die Änderungen sind Politur/Konsistenz, keine neue Fähigkeit. Verifiziert per wrangler dev + Playwright: Fieldset/Legend + 24px-Checkbox-Maße programmatisch geprüft; Zugriffsschutz-Fehlerpfad per Route-Interception erzwungen und bestätigt; Fragebogen mit einem live erzeugten Einladungs-Token gerendert (Fortschrittsbalken über den geteilten Baustein, alle drei Badge-Typen sichtbar, neue Legende vorhanden) — Screenshot bestätigt, keine Konsolenfehler. | gebaut (0.73.0 → 0.73.1, PATCH) · nur Client · 442 Vitest + tsc + ng build grün. |
| MED-D-120 | 2026-07-13 | UX-Welle 8 · MED-OP-UX-7 (B5, Teil 1) | Eine Handschrift, Teil 1 — natives confirm() raus, Formate/Clipboard vereinheitlicht (App-Audit-Befund B5). Der App-Audit hatte 7 blockierende confirm()-Aufrufe, 4 divergierende Datums-Rohformate, 4 divergierende Clipboard-Stellen (eine davon mit fehlendem ?.-Schutz) und die ohne Trennung nebeneinanderstehenden Verlassen-Modal-Buttons bemängelt — beim Re-Check alle unverändert vorgefunden. (1) Neuer ConfirmService (confirm.service.ts, promise-basiert wie ToastService) + EIN gestalteter Dialog in app.component.ts mit echter Fokus-Falle (Muster aus dem Verlassen-Modal, MED-D-115) ersetzt alle 7 confirm()-Stellen (mandant-detail.component.ts ×5, verwaltung.component.ts ×2). Beim Live-Test mit Escape-Abbruch fiel ein eigenständiger, vor diesem PR bereits bestehender Bug auf: der Cancel-Pfad der Mandats-Archivierung setzte this.daten.set(this.daten()) zurück — eine identische Objekt-Referenz ist unter Angular-Signal-Standardgleichheit (Object.is) ein No-Op, das <select> blieb also optisch auf "Archiviert" stehen, obwohl der Status serverseitig unverändert war. Mitbehoben: der Cancel-Pfad schreibt den vorherigen Wert jetzt direkt auf das DOM-Element (viewChild-Referenz) zurück. (2) datum()/datumZeit() (die seit MED-D-91 kanonischen Formatierer) durchgesetzt: vier eigene Rohformate (app.component.ts Build-Zeit, onboarding-public/fragebogen-public Zwischenstand-Hinweise, formular-public Inline-Format) sowie eine tote zeitStempel()-Dopplung in mandant-detail.component.ts (duplizierte den bereits korrekten zeit()-Wrapper) entfernt. cockpit.component.tss faelligDatum() (mit Wochentag) und kurzZeit() (ohne Jahr, Audit-Feed-Widget) geprüft und bewusst nicht angeglichen — zweckgebundene Varianten, keine Kopierfehler. (3) Neuer kopiereText()-Helfer (labels.ts) ersetzt 4 divergierende navigator.clipboard-Stellen; dabei den einen echten Bug behoben (akte-dentmarking.component.ts rief navigator.clipboard.writeText ohne ?.-Schutz auf — hätte ohne Clipboard-API/ohne HTTPS mit einer ungefangenen Exception abgebrochen statt den vorhandenen Text-Fallback zu zeigen). (4) Verlassen-Modal: "Verwerfen & verlassen" von justify-content:flex-end (alle 3 Buttons in einer Reihe) auf space-between umgestellt — die destruktive Aktion steht jetzt sichtbar abgesetzt von "Zurück zur Akte"/"Buchen & verlassen". Bewusst zurückgestellt (Rest von B5, kein Teil dieses PR): ~570 Inline-Styles → Utility-Klassen (eigenes, hohes-Risiko-Epic); die zwei koexistierenden CSS-Token-Welten --md-*/.md-btn vs. Cockpit-eigene --bg/--panel/.../.mw-btn (bewusst getrennt dokumentiertes Redesign, Vereinheitlichung wäre eine Architektur-Entscheidung, kein Cleanup); Cockpit-Fokus-Kontext mobil als Bottom-Sheet (echtes neues Mobile-Feature); die 4 unterschiedlichen Absende-Button-Texte der öffentlichen Kundenstrecken (geprüft, bewusst nicht vereinheitlicht — jede Formulierung trägt eine andere rechtlich/fachliche Aussage über die jeweilige Einreichung). | Beantwortet True North #3 (rechtssicher & lückenlos dokumentiert — ein nativer confirm() ist nicht stylbar/barrierefrei und blockiert den Haupt-Thread; der jetzt gefixte Archivierungs-Bug hätte bei einem Abbruch einen falschen visuellen Eindruck vom tatsächlichen Mandats-Status hinterlassen) sowie G-3 (eine Handschrift: ein Format-Paar, ein Clipboard-Helfer, ein Dialog-Muster statt divergierender Einzellösungen). Scoping-Entscheidung bewusst getroffen und hier dokumentiert statt stillschweigend verengt (dieselbe Transparenz-Norm wie bei B3/B6): die vier zurückgestellten Punkte sind entweder ein eigenes Epic (Inline-Styles), eine Architektur-Entscheidung (Token-Welten), ein neues Feature statt Cleanup (Bottom-Sheet) oder eine geprüfte Nicht-Änderung (Button-Texte) — keiner davon passt in eine schnelle Konsistenz-Runde. Der Signal-Referenz-Bug ist ein Lehrbuchbeispiel dafür, warum Live-Verifikation (nicht nur tsc/Build) Pflicht ist: der Typcheck sah keinen Fehler, weil set() mit identischem Wert typkorrekt, aber semantisch wirkungslos ist. MINOR statt PATCH, weil ein neues, sichtbares Interaktionsmuster (gestalteter Bestätigungsdialog) hinzukommt — nicht nur Politur wie bei MED-D-119. | gebaut (0.73.1 → 0.74.0, MINOR) · nur Client · 442 Vitest + tsc + ng build grün · Doku-Konsistenz-Check grün. |
| MED-D-121 | 2026-07-13 | UX-Welle 8 · MED-OP-UX-7 (B5/B6, Teil 2) | Eine Handschrift, Teil 2 — Cockpit-Fokus-Kontext mobil als Bottom-Sheet (App-Audit-Befund B5/B6, Punkt 9). Die rechte Kontext-Spalte der Cockpit-Fokus-Ansicht (.mw-ctx in cockpit.component.ts — Aktenreife, Betreuungsmodell, Phasen-Strip, offene Punkte des Mandanten, Verlauf) war unter 820px schlicht display:none: ersatzlos verschwunden statt (wie das strukturell analoge Leitstand-Detail seit MED-OP-UX-3) über eine Bottom-Sheet-Mechanik erreichbar zu bleiben. Neuer Toggle-Button "Kontext ↑" (.mw-ctx-toggle, per CSS nur <820px sichtbar) öffnet dieselbe Kontext-Spalte als Bottom-Sheet — identische CSS wie .mw-leit-aside.offen (position:fixed;bottom:0;max-height:62vh;border-radius:14px 14px 0 0;box-shadow:...), keine zweite Bottom-Sheet-Implementierung; ein "← Schließen"-Button (ebenfalls nur mobil sichtbar) schließt sie. Bewusste Abweichung vom Leitstand-Vorbild: dort ist offen direkt aus !!selEvent() abgeleitet (initial null, Nutzer muss aktiv ein Ereignis anklicken); im Cockpit ist cur() (das aktuell fokussierte Element) praktisch immer gesetzt, sobald die Bucket-Queue nicht leer ist — eine Ableitung aus cur() hätte die Sheet auf so gut wie jedem Mobile-Aufruf sofort über den Hauptinhalt gelegt. Deshalb ein eigenes, von cur() entkoppeltes ctxOffen-Signal (rein manueller Toggle) statt Wiederverwendung des Leitstand-Musters 1:1. | Beantwortet True North #1 (Wo steht der Kunde im Prozess?): die Kontext-Spalte ist genau die Antwort auf diese Frage für den gerade fokussierten Mandanten — auf Mobile war sie bislang die einzige der drei Cockpit-Flächen (Rail/Main/Kontext) ohne Bottom-Sheet-Ersatz (Rail wurde bereits in MED-OP-UX-3 zur horizontalen Chip-Leiste, Leitstand-Detail zur Sheet). Bewusste Abweichung vom Leitstand-Vorbild dokumentiert statt stillschweigend identisch kopiert, weil die Voraussetzung (Standardzustand "nichts selektiert" vs. "fast immer etwas im Fokus") strukturell verschieden ist — ein Copy-Paste des !!selEvent()-Musters wäre ein neuer, eigener Bug gewesen (Sheet verdeckt den Inhalt beim ersten Laden). Rundet MED-D-120 ab: von den vier in Teil 1 zurückgestellten Punkten ist damit einer erledigt; Inline-Styles/Token-Welten/Absende-Button-Texte bleiben bewusst offen (siehe MED-D-120) — unterschiedliche Kategorien (Epic/Architektur-Entscheidung/geprüfte Nicht-Änderung), passen nicht in denselben Zuschnitt wie ein bounded Feature. Verifiziert per wrangler dev + Playwright bei 1400px (Toggle bleibt unsichtbar, Kontext-Spalte durchgehend sichtbar — Desktop-Verhalten unverändert) und 390px (Kontext-Spalte per Default display:none, Toggle sichtbar und öffnet die Sheet mit position:fixed/bottom:0/Klasse .offen, "Schließen" schließt sie zuverlässig wieder) — beide Zustände screenshotbestätigt, keine Konsolenfehler. | gebaut (0.74.0 → 0.75.0, MINOR — neues, bounded Mobile-Feature) · nur Client · 442 Vitest + tsc + ng build grün · Doku-Konsistenz-Check grün. |
| MED-D-125 | 2026-07-13 | Betrieb/CI | concurrency repo-übergreifend vereinheitlicht: ci.yml verlor sein ci--Präfix im Group-Key; app-deploy.yml (bisher group: app-deploy ohne github.ref), auto-rerun.yml/docs-deploy.yml (hatten gar keinen Block) auf group: ${{ github.workflow }}-${{ github.ref }} / cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} gehoben — identisch zu Taktano. | User-Auftrag "concurrency sollte immer sein: …" 07-13 (zunächst unconditional cancel-in-progress: true angefragt, dann auf die main-Ausnahme korrigiert — die bereits in ci.yml etablierte D-36-Regel bleibt damit über alle Workflows hinweg konsistent statt nur in einem). | .github/workflows/ci.yml · app-deploy.yml · auto-rerun.yml · docs-deploy.yml · MED-D-36 |
| MED-D-124 | 2026-07-13 | Betrieb/CI | runs-on repo-übergreifend vereinheitlicht: app-deploy.yml/docs-deploy.yml (bisher `${{ vars.CI_RUNNER | 'self-hosted' }}, kein Fork-Gate) und auto-rerun.yml(bisher${{ vars.CI_RUNNER | |
| MED-D-123 | 2026-07-13 | Compliance/Sicherheit | Golden Rule "Zero Trust vor Public": jedes Online-Deployment wird zunächst hinter Cloudflare Zero Trust (Access) von der Öffentlichkeit abgeschottet — offener Zugriff ist begründete Ausnahme, nie Default beim Go-Live. In CLAUDE.md unter Compliance aufgenommen, repo-übergreifend (sera/medidentas/taktano/template) vereinheitlicht. Ausdrücklich vermerkt: die vier öffentlichen Kundenstrecken (Onboarding/Formular/Fragebogen/Lead) sind bewusste, begründete Ausnahmen (token-/einladungsbasiert statt Login), kein Widerspruch zur Regel. app.medidentas.com selbst läuft bereits hinter Cloudflare Access (produktiv, s. HANDOFF §Aktueller Stand) — die Golden Rule bestätigt/schärft diese bestehende Praxis, statt sie neu einzuführen. | User-Auftrag "Golden Rule" 07-13. | CLAUDE.md §Compliance |
| MED-D-122 | 2026-07-13 | UX-Welle 8 · MED-OP-UX-7 (B5, Teil 3) | Eine Handschrift, Teil 3 — Inline-Styles konsolidiert, Runde 1 (App-Audit-Befund B5). Von den ~570 im App-Audit gezählten Inline-Styles liegt der größte Einzelposten in cockpit.component.ts (215 Stellen). Statt den gesamten Bestand in einem Rutsch anzufassen (hohes Risiko, siehe MED-D-120s Scoping-Begründung), zuerst eine Long-Tail-Analyse: von 215 Stellen sind nur 49 exakte, ≥2× identische Duplikate (19 unterschiedliche Muster) — die übrigen 166 sind echte Einzelwerte (jede Kombination aus Schriftgröße/Farbe/Abstand kommt nur einmal vor). Diese Verteilung bestätigt die ursprüngliche Einschätzung: eine vollständige Elimination würde eine Spacing-/Typografie-Skala-Entscheidung erfordern (welche Werte werden Standard, welche gerundet?) — das ist dieselbe Kategorie Entscheidung wie die noch offene CSS-Token-Welten-Vereinheitlichung, nicht mehr reines Cleanup. Für diese Runde daher bewusst nur die 49 exakten Duplikate als benannte Utility-Klassen extrahiert — eine reine 1:1-Ablöse mit byte-identischem CSS-Ergebnis (keine Werte neu interpretiert), damit ohne Visual-Risiko. Ergebnis: 215 → 166 Inline-Styles in cockpit.component.ts (-23 %). Neue Klassen: 6 generische .md-* (in styles.css neben den bestehenden .md-hint/.md-m0/.md-w100, MED-OP-UX-4 — wiederverwendbar über Cockpit hinaus) plus Wiederverwendung des bereits bestehenden .md-grow (flex:1, 6×, zuvor unentdeckt weil niemand grep't hatte); 11 Cockpit-eigene .mw-* (referenzieren die Cockpit-Farb-Tokens --mut/--faint/--red, bewusst getrennt von der .md-*-Welt gehalten, MED-D-120) plus ein .mw-sec-label.mut-Modifier. Der Modifier deckte einen kleinen Zusatzfund auf: 3 Stellen re-deklarierten letter-spacing:0.14em inline, obwohl .mw-sec-label das bereits setzt (reine Redundanz) — jetzt entfernt, nur der tatsächliche Farb-Override (--mut statt der Klassen-Farbe --faint) bleibt als Modifier-Klasse übrig. Verifiziert per wrangler dev + Playwright: Fokus- und Leitstand-Ansicht bei 1400px (hell und dunkel, da mehrere neue Klassen Cockpit-Theme-Variablen referenzieren) sowie 390px (mobil, inkl. der aus MED-D-121 stammenden Bottom-Sheet-Interaktion) gescreenshottet — keine Konsolenfehler, keine sichtbare Abweichung zum vorherigen Stand. | Beantwortet G-3 (eine Handschrift: benannte, wiederverwendbare Klassen statt an derselben Stelle wiederholt dieselben Werte abzutippen) — schärft zugleich G-2 (Single Source of Truth: eine CSS-Regel statt N identischer Inline-Kopien). Die Long-Tail-Analyse ist selbst die wichtigste Erkenntnis dieser Runde: sie zeigt objektiv, dass "alle Inline-Styles eliminieren" kein sinnvolles Ziel für eine mechanische Cleanup-Runde ist, sondern in einen Design-Entscheid übergeht, sobald man über die exakten Duplikate hinausgeht — dieselbe Grenze, die schon bei den CSS-Token-Welten gezogen wurde (MED-D-120). Bewusst kein Versuch, ähnliche-aber-nicht-identische Werte (z. B. font-size:0.8rem vs. 0.82rem, beide color:var(--mut)) zusammenzufassen — das wäre eine stille Wertänderung (0.8 oder 0.82? welches gewinnt?) und keine reine Ablöse mehr. PATCH statt MINOR, weil dies ein reiner interner Refactor ohne jede sichtbare oder verhaltensändernde Konsequenz ist (im Unterschied zu MED-D-120/121, die neues Nutzer-sichtbares Verhalten brachten). | gebaut (0.75.0 → 0.75.1, PATCH) · nur Client (styles.css + cockpit.component.ts) · 442 Vitest + tsc + ng build grün · Doku-Konsistenz-Check grün. |
| MED-D-137 | 2026-07-13 | Betrieb/CI | Self-Hosted-Runner-Fallback zurück auf hot (ci.yml/app-deploy.yml/docs-deploy.yml/auto-rerun.yml: `runs-on: ${{ … | vars.CI_RUNNER | |
| MED-D-136 | 2026-07-13 | Betrieb/CI | Self-Hosted-Runner-Fallback-Label von hot auf desktop umbenannt (ci.yml/app-deploy.yml/auto-rerun.yml/docs-deploy.yml: `runs-on: ${{ … | vars.CI_RUNNER | |
| MED-D-138 | 2026-07-13 | Betrieb/CI | actions/checkout mit clean: false auf allen node-basierten Jobs (ci.yml: server-test/docs-build, app-deploy.yml, docs-deploy.yml). client-build hatte das Muster bereits (agents.md §6.6); jetzt einheitlich auf allen weiteren npm ci-Jobs, damit deren node_modules ebenfalls den git clean auf dem persistenten Runner überleben statt bei jedem Lauf neu installiert zu werden. Umnummeriert von MED-D-129 auf MED-D-133 vor dem Merge (ID-Kollision mit dem parallel bereits gemergten MED-D-129/World-2-Rollout Schritt 2 behoben) — und ein zweites Mal am 2026-07-14 von MED-D-133 auf MED-D-138 (Kollision mit der später vergebenen Doku-Welle-4-Serie, s. MED-D-139). | User-Nachfrage zu einem langsamen Deploy in Sera (analoges Problem); Root Cause ist der Checkout-Default clean: true — Medidentas hatte das Muster für client-build bereits etabliert, aber nicht auf die übrigen node-Jobs ausgedehnt. | .github/workflows/ci.yml · .github/workflows/app-deploy.yml · .github/workflows/docs-deploy.yml |
| MED-D-135 | 2026-07-13 | Doku/Compliance | docs/architektur/Architektur-Uebersicht.md verbindlich eingeführt (grobe technische Systemstruktur als Mermaid-Grafik: Access · Worker · D1 · R2 · NextCloud · Signatur · CRM · öffentliche Kundenstrecken; ergänzt — nicht dupliziert — die fachliche Schichten-/Business-Sicht in System-Charakter.md) + neuer CI-Job sbom (Server-/Client-CycloneDX, nur main-Push) — Medidentas hatte bisher weder echte SBOM-Erzeugung noch eine SBOM-Compliance-Regel. Übernommen aus Template (dortige D-53), SBOM-CI-Muster aus Taktano (OP-SBOM-1). Umnummeriert am 2026-07-14 von MED-D-130 auf MED-D-135 (Kollision mit der später vergebenen Doku-Welle-4-Serie, s. MED-D-139). | User-Auftrag "nimm immer eine SBOM in die Doku auf sowie eine grobe Systemstruktur als Grafik" 07-13; repo-übergreifend in sera/taktano/Template umgesetzt. | docs/architektur/Architektur-Uebersicht.md · .github/workflows/ci.yml · CLAUDE.md §Compliance |
| MED-D-127 | 2026-07-13 | Doku/Way-of-Working | Instruktions-Scoping (Nested CLAUDE.md): neue Regel — Root-CLAUDE.md bleibt einzige Stelle für stack-unabhängige Governance; nested CLAUDE.md je eigenständigem Tech-Stack-Unterverzeichnis (client/, server/) nur für stack-lokale Build/Test/Lint-Details, mit festem Skelett + Pflicht-Verweis "Governance siehe Root". Übernommen aus Template (dortige D-9). | Repo-übergreifend vereinheitlicht, um Konsistenz trotz unabhängiger Weiterentwicklung zu wahren. | CLAUDE.md §Instruktions-Scoping · Template-D-9 |
| MED-D-128 | 2026-07-13 | UX-Welle 8 · MED-OP-UX-7 (B5, World-2-Pilot) | World-2-Pilot — Verwaltung + App-Shell auf Cockpit-Tokens umgestellt (App-Audit-Befund B5, CSS-Token-Welten). Die App hat zwei parallele, nicht koordinierte CSS-Token-Systeme: --md-*/.md-btn (Akte, Mandant-Detail, Verwaltung, die 4 öffentlichen Kundenstrecken) und --bg/--panel/--accent/--red/.../.mw-btn (Cockpit, bewusst getrennt seit dessen Neugestaltung, MED-D-120). Auf explizite Rückfrage entschied der Nutzer: Cockpit-Palette ("World 2") wird der EINE Standard app-weit; Rollout beginnt mit einem Pilot-Bereich statt allem auf einmal. Zweite Rückfrage zum genauen Zuschnitt: Verwaltung sitzt in derselben App-Shell (Header/Footer) wie Akte/Mandant-Detail — ein sauberer Pilot muss die Shell mitfärben, auch wenn Akte/Detail selbst noch unangetastet bleiben; Nutzer bestätigte diesen größeren (aber immer noch bounded) Zuschnitt. Umsetzung: (1) Die App-Shell (app.component.ts: .md-shell/.md-header/.md-footer/.md-skip/.md-theme-seg/.md-version/.md-deploy) direkt auf Cockpit-Tokens umgestellt — sicher, weil diese Selektoren exklusiv nur dort verwendet werden (per Grep-Inventar verifiziert); .md-header .md-btn/.md-header .md-pill für die Nav-Buttons/den Rollen-Chip descendant-gescopet, um NUR den Header umzufärben statt die geteilten .md-btn/.md-pill-Basisregeln global anzufassen. .md-brand/.md-wordmark*/.md-wm-1/.md-wm-2/.md-brand-tagline/.md-logo bewusst unverändert gelassen, da sie zusätzlich von den öffentlichen Kundenstrecken über pub-bausteine.ts genutzt werden (außerhalb des Piloten) — ein Kontrast-Check bestätigte, dass die unveränderten Markenfarben auf dem neuen Header-Hintergrund in beiden Themes weiterhin gut lesbar bleiben. (2) Verwaltungs-eigener Inhalt (verwaltung.component.ts) unter einer neuen .mw-scope-Wrapper-Klasse mit rein descendant-gescopeten CSS-Overrides (.mw-scope .md-card, .mw-scope button/.md-btn, .mw-scope input/select, .mw-scope .md-pill/.md-muted/.md-error/.md-items li/.md-status-*/.md-funnel-*, .mw-scope label) statt die geteilten Basisregeln zu ändern — ein vorheriges Klassen-Inventar zeigte, dass fast jede von Verwaltung genutzte Klasse (.md-btn, .md-card, .md-pill, .md-muted, .md-row, .md-items, .md-w100) UND mehrere bare Element-Selektoren (button, input, select, label, h2/h3) app-weit mit Akte/Mandant-Detail/Public geteilt sind — eine direkte Änderung hätte über den Piloten hinausgeleckt; nur .md-funnel-* war bereits exklusiv. Zusätzlich zwei inline var(--md-warn)-Referenzen (nicht per CSS überschreibbar) direkt auf var(--amber) umgestellt. Bewusste, dem Nutzer vorab angekündigte Konsequenz: Akte/Mandant-Detail erben die neue Header/Footer-Chrome (dieselbe Shell), behalten aber vorerst ihren eigenen --md-*-basierten Seiteninhalt — ein transitioneller zweifarbiger Look, am deutlichsten im Dunkel-Theme (Cockpit-Dunkel-Hintergrund #0d1210 spürbar dunkler als --md-bg dunkel #161b18), bis auch deren Inhalt migriert ist. Verifiziert per wrangler dev + Playwright: Verwaltung hell/dunkel/mobil sowie Mandant-Detail + Druck-Akte hell/dunkel gescreenshottet; Screenshots dem Nutzer vor dem Merge vorgelegt, Akte/Detail-Inhalt als unverändert bestätigt. | Beantwortet die in MED-D-120/122/126 wiederholt als "eigene, größere Design-Entscheidung" zurückgestellte Token-Welten-Frage — endlich angegangen, aber bewusst inkrementell (Pilot-Bereich zuerst) statt App-weit in einem Rutsch, um das Risiko eines Fehlgriffs klein zu halten (Nutzer-Präferenz, zweite Rückfrage dieser Runde). Die .mw-scope-Technik ist bewusst so gebaut, dass sie sich erweitern lässt: sobald Akte/Mandant-Detail migrieren sollen, genügt dieselbe Wrapper-Klasse an deren Wurzel-Template — die hier geschriebenen Scoped-Overrides greifen dann automatisch. Zwei echte Rückfragen in dieser Runde (Zielsystem, dann Shell-Einschluss) waren gerechtfertigt: beide sind Weggabelungen mit sichtbaren, kaum rückgängig zu machenden Konsequenzen für die gesamte interne App — genau der in agents.md vorgesehene Fall. MINOR statt PATCH, weil dies (anders als MED-D-122/126) ein echtes, für Nutzer sichtbares Verhalten/Erscheinungsbild ändert. | gebaut (0.75.2 → 0.76.0, MINOR) · nur Client (styles.css + verwaltung.component.ts — die App-Shell-Umfärbung war reines CSS, app.component.ts selbst unverändert) · 442 Vitest + tsc + ng build grün · Doku-Konsistenz-Check grün. |
| MED-D-126 | 2026-07-13 | UX-Welle 8 · MED-OP-UX-7 (B5, Teil 4) | Eine Handschrift, Teil 4 — Inline-Styles konsolidiert, Runde 2 (atomar) (App-Audit-Befund B5). Fortsetzung von MED-D-122, diesmal auf Deklarations-Ebene statt Kombinations-Ebene: eine Normalisierung der verbliebenen 166 Inline-Styles (Zahlenwerte durch Platzhalter ersetzt) zeigte, dass viele als FORM wiederkehren, auch wenn kein einzelner Wert exakt übereinstimmt (z. B. display:flex;flex-direction:column;gap:X 7× mit 7 verschiedenen Gap-Werten). Nutzerentscheidung nach expliziter Rückfrage (drei Optionen: atomare Zerlegung ohne Wertänderung / nur weitere exakte Duplikate / echte Spacing-Skala mit Rundung) — Nutzer wählte "Atomare Klassen, Werte unverändert". Umsetzung: 36 atomare Utility-Klassen für Einzel-Deklarationen mit ≥4× Häufigkeit (Schwelle bewusst gewählt — bei ≥2× wären es 91 Klassen, bei ≥3× 56, bei ≥5× nur 23; ≥4× deckt 303 von 581 Deklarations-Vorkommen ab, ein vertretbarer Mittelweg zwischen Reduktion und Klassen-Wildwuchs). Layout-Atome (mw-flex/mw-col/mw-items-center/mw-flex-none/mw-abs/mw-rel/…), 5 Cockpit-Farbtoken-Atome (mw-c-mut/mw-c-faint/mw-c-text/mw-c-text2/mw-c-accent-text), Font-Größen- und Gap-Atome (mw-fs-68…mw-fs-92, mw-gap-35…mw-gap-60) — jeweils mit dem exakten, unveränderten Ursprungswert. Automatisiert per Node-Skript (Tag-aware Regex, das Angular-Bindings wie [style.color]="…"/[attr.stroke]="…" unangetastet lässt und ein bestehendes class="…" korrekt um die neuen Atome erweitert statt es zu überschreiben) — vor dem eigentlichen Schreiben ein vollständiger Dry-Run mit Vorher/Nachher-Diff aller 145 betroffenen Stellen manuell durchgesehen. Ergebnis: 145 von 166 Stellen atomisiert (die restlichen 21 hatten ausschließlich Deklarationen unter der Schwelle) — Cockpit jetzt bei 132 Inline-Styles (215 zu Beginn von B5 → 166 nach Runde 1 → 132 nach Runde 2, -39 % kumuliert). Verifiziert per wrangler dev + Playwright: Fokus- und Leitstand-Ansicht (inkl. Timeline mit Sticky-Headern, Event-Detail-Panel, "Wartet auf andere"/"Erledigt heute"-Buckets) bei 1400px (hell + dunkel) und 390px (mobil) gescreenshottet — jede Ansicht pixelidentisch zum Stand vor der Änderung, keine Konsolenfehler. | Beantwortet G-3 (eine Handschrift) und G-2 (Single Source of Truth) auf einer feineren Ebene als Runde 1: dort mussten ganze Kombinationen exakt übereinstimmen, hier reicht eine einzelne wiederkehrende Eigenschaft — das erschließt deutlich mehr Wiederverwendung (145 vs. 49 Stellen), bleibt aber bei derselben Grundregel: kein Wert wird verändert oder gerundet, nur zerlegt und benannt. Die explizite Rückfrage vor Beginn war hier gerechtfertigt (echte Weggabelung mit drei grundverschiedenen Aufwands-/Risikoprofilen), nicht nur ein Standard-Default — genau der in agents.md vorgesehene Fall für "an echten Weggabelungen nachfragen". Die ≥4×-Schwelle ist selbst eine (kleinere, transparent dokumentierte) Abwägungsentscheidung innerhalb der vom Nutzer gewählten Option, keine weitere Rückfrage wert. Verbleibende 132 Inline-Styles sind bewusst nicht weiter angefasst — die nächste Verdichtungsstufe (ähnliche, nicht identische Werte zusammenlegen) wäre wieder die in MED-D-120/122 bereits abgegrenzte Skala-Entscheidung. PATCH, da erneut ein reiner interner Refactor ohne sichtbare Konsequenz. | gebaut (0.75.1 → 0.75.2, PATCH) · nur Client (styles.css + cockpit.component.ts) · 442 Vitest + tsc + ng build grün · Doku-Konsistenz-Check grün. |
| MED-D-129 | 2026-07-13 | UX-Welle 8 · MED-OP-UX-7 (B5, World-2-Rollout Schritt 2) | World-2-Rollout Schritt 2 — Akte/Mandant-Detail auf Cockpit-Tokens umgestellt (App-Audit-Befund B5). Schließt den in MED-D-128 bewusst angekündigten transitionellen Zweifarben-Look: mandant-detail.component.ts (interaktive Akte, 2228 Zeilen — die größte Datei der App) und mandant-akte.component.ts (Druck-Akte) bekommen denselben .mw-scope-Wrapper wie zuvor verwaltung.component.ts. Wichtiger Fund vorab: die 6 Register-Unterkomponenten (akte-auftraege/-dentmarking/-einladungen/-formulare/-meetings/-stammuebernahme) brauchen keinen eigenen Wrapper — sie rendern als Kind-Elemente direkt im Template der beiden Wurzel-Komponenten (<md-akte-auftraege ...> etc.), die CSS-Cascade des globalen Stylesheets greift automatisch über die Komponentengrenze hinweg (Angulars ViewEncapsulation.Emulated kapselt nur komponenteneigene Styles, keine Shadow-DOM-Grenze für externe globale Stylesheets) — das reduziert den nötigen Datei-Edit-Umfang von 8 auf 2 Dateien. Klassen-Inventar über alle 8 Dateien ergab 73 distinkte --md-*/.md-*-Bezüge (vs. ~15 bei Verwaltung) — deutlich größerer Umfang als der Pilot erwarten ließ: 20 neue .mw-scope-gescopete CSS-Regeln für bislang unberührte Muster (.md-kpi* KPI-Kacheln, .md-step* Prozess-Stepper inkl. .done/.active/.warn-Zustände, .md-timer* Zeiterfassungs-Widget inkl. .pausiert-Zustand, .md-modal* Verlassen-Dialog, .md-regnav/.md-regtab Register-Navigation, .md-reife/.md-reife.clean, .md-sev.blockierend/.wichtig/.hinweis Schweregrad-Badges, .md-mehr* "…"-Menü, .md-next* Nächste-Schritte-Chips, .md-bar/.md-cnt/.md-group-lbl/.md-laedt/.md-reg-note). Zusätzlich ~35 direkte Inline-Style-Fixes über alle 8 Dateien (var(--md-border)→var(--bd), var(--md-warn)→var(--amber), var(--md-ok)→var(--green), var(--md-green)→var(--accent), var(--md-muted)→var(--mut), var(--md-error)→var(--red)) — Inline-Styles sind per CSS-Scoping nicht erreichbar (höchste Spezifität), müssen direkt editiert werden; betrifft u. a. die KPI-Ring-Farben (aktenreif/nicht-aktenreif), den "Verwerfen & verlassen"-Button und mehrere Rahmenfarben in den Register-Unterkomponenten. Verifiziert per wrangler dev + Playwright: Mandant-Detail + Druck-Akte hell/dunkel gescreenshottet, alle 10 Register-Tabs einzeln durchgeklickt und gescreenshottet (bestätigt: Kind-Komponenten erben die neue Palette korrekt über die Cascade, inkl. der --amber-Warnfarbe in akte-auftraege) — keine Konsolenfehler in beiden Themes. Screenshots dem Nutzer vor dem Merge vorgelegt (wie schon bei MED-D-128). | Schließt die in MED-D-128 explizit angekündigte Konsequenz ab, statt sie offen zu lassen — kein neuer "silent scope"-Verstoß, sondern die geplante Fortsetzung. Der wichtigste technische Fund (Kind-Komponenten brauchen keinen eigenen Wrapper) bestätigt, dass die in MED-D-128 gewählte .mw-scope-Technik bewusst erweiterbar gebaut war — genau wie dort vorausgesagt ("sobald eine weitere Seite mitziehen soll, reicht dieselbe Klasse an deren Wurzel"). Die Inline-Style-Fixes sind eine notwendige Ergänzung zur reinen CSS-Scoping-Technik: ohne sie wären KPI-Ring und Verwerfen-Button beim Theme-Wechsel weiterhin auf den alten --md-*-Werten hängengeblieben, obwohl die umgebenden Klassen schon migriert waren — ein subtiler, leicht übersehbarer Rest-Bug-Typ, den die Long-Tail-Analyse aus MED-D-126 (Inline-Werte sind nie automatisch mit-migriert) hier vorausschauend adressiert. Ergebnis: kein zweifarbiger Übergangszustand mehr irgendwo in der internen App (Shell/Verwaltung/Akte/Mandant-Detail sind jetzt durchgängig World-2) — nur noch die 4 öffentlichen Kundenstrecken (bewusst außerhalb, eigene Chrome, MED-D-120) und Cockpits eigene ~132 Einzelwert-Inline-Styles (MED-D-122/126) bleiben als separate, bereits dokumentierte offene Punkte. MINOR wie MED-D-128, aus demselben Grund (sichtbares Erscheinungsbild ändert sich für Nutzer). | gebaut (0.76.0 → 0.77.0, MINOR) · nur Client (styles.css + 8 Komponenten-Dateien) · 442 Vitest + tsc + ng build grün · Doku-Konsistenz-Check grün. |
| MED-D-130 | 2026-07-14 | UX-Welle 8 · MED-OP-UX-7 (B5, World-2-Rollout Schritt 3) | World-2-Rollout Schritt 3 — die 4 öffentlichen Kundenstrecken auf Cockpit-Tokens umgestellt (App-Audit-Befund B5, letzter Rest). Onboarding (onboarding-public.component.ts), Ausfüll-Formular (formular-public.component.ts), Dentmarking-Fragebogen (fragebogen-public.component.ts) und Lead (lead-public.component.ts) bekommen dasselbe .mw-scope-Muster wie zuvor Verwaltung (Schritt 1) und Akte/Mandant-Detail (Schritt 2); die gemeinsamen Bausteine (pub-bausteine.ts: Marken-Kopf, Fortschrittsbalken, Pflicht-Legende, Marker-Chips, Fußzeile) ziehen automatisch mit, da sie als Kind-Elemente im Template der 4 Wurzel-Komponenten rendern. Neuer Fund gegenüber Schritt 1/2: diese 4 Seiten haben keine App-Shell — app.component.ts überspringt .md-shell für ihre Routen bewusst (eigene Chrome). Ohne App-Shell fehlte die einzige Stelle, die bisher implizit den World-2-Seitenhintergrund lieferte — .md-pub selbst brauchte daher direkt background: var(--bg), sonst bliebe die alte World-1-Fläche hinter der neu eingefärbten .md-pub-card sichtbar (ein Detail, das bei Verwaltung/Akte nicht auftrat, weil deren gemeinsame Shell schon in Schritt 1 umgestellt wurde). Klassen-Inventar: nur 3 neue .mw-scope-Regeln nötig (.md-pub-card, .md-pub-consent, .md-pub.mw-scope) — die übrigen von diesen Seiten genutzten geteilten Klassen (button/.primary, input/select, .md-muted/.md-error, h2/h3, label, .md-card) waren durch Schritt 1/2 bereits .mw-scope-gescopet vorhanden, keine Dopplung nötig. Zweite Neuerung: von den 31 var(--md-*)-Bezügen lagen 21 nicht in Template-Inline-Styles, sondern in component-lokalen styles:-Blöcken (PubFortschrittComponent/PubMarkerChipsComponent in pub-bausteine.ts, plus fragebogen-public.component.tss eigener .md-fb-*-Satz für die Essenziell/Wichtig/Nice-to-have-Badges) — diese sind durch Angulars ViewEncapsulation.Emulated bereits auf ihre eigene Komponente beschränkt (keine Nutzung außerhalb), konnten also direkt editiert werden statt über .mw-scope-Scoping, da kein Leck-Risiko besteht. .md-brand/.md-wordmark*/.md-brand-tagline (Marken-Kopf, Herz-Logo + Wortmarke) bewusst unverändert gelassen — wie bereits in Schritt 1 begründet: Markenidentität ist kein Theme-Element, gilt hier erstmals für den eigentlichen Ort ihrer Herkunft (pub-bausteine.ts), nicht nur für den Verweis darauf. Verifiziert per wrangler dev + Playwright mit echten Test-Datensätzen für alle 4 Strecken (Mandant+Onboarding-Einladung, Mandant+Ausfüllformular-Vorgang, Mandant+Praxis+Fragebogen-Einladung, Lead ohne Token) — nicht nur Leerzustände —, hell und dunkel, zusätzlich die 3 Ungültig-Link-Fehlerzustände; keine Konsolenfehler in allen 14 Screenshots. Ein unabhängiger, nicht dieser Migration zuzurechnender Kosmetik-Fund dabei notiert (nicht behoben, nicht Teil dieses PRs): die Consent-/Interesse-Checkboxen in lead-public.component.ts sind unstyled native <input type="checkbox"> ohne accent-color, rendern daher OS-Standard-grau statt Theme-Farbe in beiden Themes — prä-existent, kein Regressions-Risiko dieser PR. Screenshots dem Nutzer vor dem Merge vorgelegt (wie bei MED-D-128/129). | Schließt B5s Token-Welten-Teilstrang vollständig ab — nach diesem Schritt gibt es keinen Konsumenten der --md-*-Basisregeln mehr, der nicht .mw-scope-gescopet ist (Cockpit nutzt ohnehin schon nativ --bg/--panel/...); die alten button/input/.md-card/.md-muted/.md-error-Basisregeln in styles.css werden damit faktisch nur noch von der jetzt toten Alt-Kaskade referenziert — bewusst NICHT in diesem PR entfernt (Cleanup wäre Scope-Creep, eigener Punkt für eine spätere Session). Die App-Shell-Erkenntnis (Schritt 3 braucht .md-pub-Hintergrund selbst, weil keine Shell existiert) ist eine direkte, vorhersehbare Konsequenz aus Schritt 1s Architektur-Entscheidung (Shell trägt den Seitenhintergrund) — kein Fehler, sondern der erwartete Unterschied dieser einen Ausnahme-Seitengruppe. Die component-lokalen styles:-Direkt-Edits (statt .mw-scope) sind konsistent mit Angulars Kapselungsmodell, nicht eine Abkürzung: Emulated View Encapsulation stellt sicher, dass diese Regeln wortwörtlich nirgendwo sonst greifen können. MINOR wie MED-D-128/129, aus demselben Grund (sichtbares, kundenseitig sichtbares Erscheinungsbild ändert sich). | gebaut (0.77.0 → 0.78.0, MINOR) · nur Client (styles.css + 5 Komponenten-Dateien) · 442 Vitest + tsc + ng build grün · Doku-Konsistenz-Check grün. |
| MED-D-131 | 2026-07-14 | UX-Welle 8 · MED-OP-UX-7 (B5, CodeRabbit-Nachlese zu MED-D-130) | CodeRabbit-Nachlese zu MED-D-130: Doku-Präzisierung + Compliance-Wortlaut. CodeRabbits Review auf PR #171 traf erst nach dem Auto-Merge ein (Draft→Ready-for-Review-Timing: CodeRabbit überspringt Drafts per MED-D-60, das Review startete erst mit dem Ready-Umschalten und lief parallel zum bereits aktivierten Auto-Merge). Drei Befunde geprüft: (1) berechtigt, behoben: docs/betrieb/UX-Prozess-Review-2026-07.md Punkt 17 beschrieb die öffentlichen Kundenstrecken ungenau als "bekommen denselben .mw-scope-Wrapper wie Verwaltung/Akte" — tatsächlich bekommt .md-pub die Klasse direkt am bereits vorhandenen Root-Div (kein neuer Wrapper wie bei Akte, wo der Root mehrere Geschwister-Elemente hatte); Wortlaut korrigiert, damit künftige Rollout-Arbeit nicht in die Irre geführt wird. (2) berechtigt, behoben: docs/produkt/Management-Summary.md behauptete pauschal "EU-konform betrieben" — EU-Datenresidenz ist ein operativer Fakt, begründet aber für sich keine DSGVO/revDSG- oder eIDAS/ZertES-Konformität, solange externe Integrationen (E-Signatur weiterhin Fake-Adapter bis MED-KB-5, echter E-Mail-Versand offen bis OP-DM-8) Platzhalter bleiben — genau der Fall, den CLAUDE.md "Proaktives Flagging (verbindlich)" für kritische DE/AT/CH-Themen verlangt (nie still übergehen). Wortlaut auf "live in der EU mit Compliance-by-Design-Kontrollen" präzisiert + Verweis auf Compliance.md/Risikoregister.md ergänzt. (3) geprüft, bewusst NICHT umgesetzt: CodeRabbit will die Release-Historie/Feature-Stände aus CLAUDE.mds §Versionierung-Absatz ("Aktueller Stand: …") nach CHANGELOG/HANDOFF/Feature-Liste auslagern und dort nur Governance/Versionierungs-Policy belassen. Dieser Absatz folgt aber einer etablierten, in jeder der letzten ~10 PRs dieser Rollout-Serie (MED-D-120…130) identisch fortgeschriebenen Konvention — eine Restrukturierung wäre eine Way-of-Working-Entscheidung mit Tragweite über das gesamte Projekt hinaus, kein lokaler Bugfix; dem Nutzer zur Entscheidung vorgelegt statt einseitig in einem unrelated Wording-Fix-PR umgesetzt. | CodeRabbit-Reviews, die erst nach dem Merge eintreffen (Draft-Skip-Timing), verdienen dieselbe Sorgfalt wie rechtzeitige — echte Befunde werden nachgezogen statt stillschweigend verworfen, nur weil der PR schon zu ist (analog dem Nachhärtungs-Muster aus 0.71.1). Befund (2) ist besonders ernst zu nehmen: er trifft direkt G-5/die Proaktiv-Flagging-Pflicht aus CLAUDE.md — eine PR-Nachlese ist der richtige, schnelle Weg, eine potenziell irreführende Compliance-Aussage zu korrigieren, statt auf den nächsten größeren Doku-Audit zu warten. Befund (3) wird bewusst nicht in derselben PR miterledigt: die zwei anderen Fixes sind reine Wortlaut-Präzisierungen ohne Entscheidungsbedarf, Befund (3) hingegen würde die dokumentierte Arbeitsweise selbst ändern — das rechtfertigt eine eigene, bewusste Entscheidung statt Vermischung mit einem Nachlese-PATCH. | gebaut (0.78.0 → 0.78.1, PATCH) · nur Doku (2 Dateien), kein Code-/Schema-Change · 442 Vitest + tsc + ng build unverändert grün · Doku-Konsistenz-Check grün. |
| MED-D-132 | 2026-07-14 | Doku-Audit · MED-OP-REVIEW-1 · MED-OP-DOKU-5 | Doku-Review aufgefrischt v0.65.0 → v0.78.1 — Re-Audit, kein Fix-PR. Nutzer wählte "1" (Doku-Review-Audit auffrischen) aus einem vorgeschlagenen Optionen-Set. docs/betrieb/Doku-Review-2026-07.md (Bezugspunkt v0.65.0, 13 Minor-Versionen alt — per agents.md §6.7 formal veraltet) neu erstellt via 5 parallelen Recherche-Durchsichten: (1) Verifikation aller 19 Alt-Befunde B1–B19 gegen den aktuellen Code-/Doku-Stand, (2) Stand-Stempel-Sweep über alle ~40 docs/-Dateien + Root-Docs, (3) Cross-Doc-Konsistenz der Leitprinzipien/ID-System/Session-Start-Regeln, (4) Doku-Abdeckung der größten neuen Funktionen seit v0.65.0 (Beratungsaufträge-3-Ebenen-Modell MED-D-95, World-2-Token-Rollout MED-D-128…130), (5) Zielgruppen-/Pyramidal-/Diagramm-Stichprobe. Kernbefund: 10 der 19 Alt-Befunde sind vollständig gelöst (B1/B4/B7/B8/B9/B11/B13/B16/B18 + Sammelposten), aber die Wurzelursache des letzten Audits (B18: schnelle Logs bleiben aktuell, langsame Rahmen-Docs veralten) ist binnen 13 Minor-Versionen an derselben und einer schwereren Stelle zurückgekehrt: README.md/MVP-Scope.md erneut 11 Minor-Versionen veraltet (B21, Rückfall von B2/B3); Lastenheft.md — die fachliche Master-Spezifikation — wurde nie für Beratungsaufträge nachgezogen und trägt an der eigenen Quelle noch den exakten Phantom-"Ablage"-Fehler, der in den zwei abgeleiteten Docs (Prozessmodell.md/System-Charakter.md) bereits behoben wurde (B20, schwerster Einzelbefund — die Reparatur hat die zitierte Quelle nie erreicht; derselbe Fehler auch in CLAUDE.mds eigener "Standard-Prozess"-Zeile, B29); Deploy.md widerspricht der Produktionsrealität ("der erste echte Deploy steht aus", obwohl seit Wochen live, B22). Der mechanische Check selbst hat einen blinden Fleck, der B21 verdeckt: check-doc-consistency.sh §8 matcht nur "Stand" vor einer Version, nicht "Status" (README/MVP-Scope formulieren "Status") — und Lastenheft.md steht gar nicht in der geprüften Dateiliste (B23). 9 weitere neue Befunde (B24–B32): Management-Summary "Ablage=Platzhalter" widerspricht dem gelösten R2-Status + fehlende Standard-Bausteine-Zeile; Weltmodell-Data-Dictionary fehlt Beratungsauftrag als G-8-Entität; agents.md §3 (kanonische ID-System-Quelle) fehlen D-n/RISK-n/KB-n, die eine bloße Kurzform (Entwicklungsansatz.md) schon führt; docs/README.md indexiert Architektur-Uebersicht.md nicht + veralteter Produktname; Lesepfade.md verlinkt beide neuen Zentral-Docs nirgends; Compliance.md/Risikoregister.md seit Repo-Init-Tag nicht neu geprüft (Governance-Aktualität, direkt an G-4/G-5 anschließend, dasselbe Muster wie die kürzlich in MED-D-131 korrigierte "EU-konform"-Überclaim). B5 (CLAUDE.md-§Versionierung-Absatz) bleibt formal offen — verweist auf dieselbe, in MED-D-131 dem Nutzer zur Entscheidung vorgelegte Frage. Bewertung: Aktualität & Konsistenz 4→6, Bedienbarkeit der Doku-Vorgaben 5→7 (agents.md §5.4 "eine Definition, ein Ort" ist echter neuer Mechanismus, Check von 3 auf 8 Prüfungen erweitert — aber Ausführung lückenhaft). Maßnahmenplan als Doku-Welle 4 / MED-OP-DOKU-5 in 4 Teilwellen (4a Wahrheit wiederherstellen, 4b Check-Lücke schließen, 4c Governance-Aktualität, 4d Restschulden) in HANDOFF.md §4 aufgenommen — bewusst nicht in derselben PR umgesetzt, dies ist der Audit selbst, kein Fix-PR (analog MED-D-107, der App-Audit-Auffrischung: "Doku-Audit, keine Versionsänderung"). | Ein Re-Audit ohne echte Verifikation der Alt-Befunde (statt bloßer Übernahme der "Doku-Wellen 1–3 ✅"-Behauptung aus HANDOFF) hätte den Rückfall (B20–B23) nicht gefunden — genau die Art Selbstgefälligkeit, die B18/B19 im letzten Audit als Wurzelursache benannten. Der schwerste Fund (B20, Lastenheft) ist besonders lehrreich: eine Reparatur, die nur an den abgeleiteten Docs (Prozessmodell/System-Charakter) ansetzt, aber nie an der zitierten Quelle (Lastenheft), hält nicht wirklich — sie verlagert den Fehler nur, statt ihn zu beseitigen. Der Check-Lücken-Fund (B23) ist der wichtigste strukturelle Befund: er erklärt, WARUM der Rückfall unbemerkt blieb, und liefert damit den einzigen Fix (4b), der eine dritte Wiederkehr tatsächlich verhindert statt nur heilt — dieselbe Lehre wie beim letzten Audit (B19), nur diesmal am neuen, konkret benennbaren Regex/Dateiliste-Ort im Skript. Keine Versionsänderung, weil ein Audit-Dokument selbst kein Feature/Fix am Produkt ist — die eigentlichen Korrekturen (Doku-Welle 4/4a–4d) sind separate, zukünftige PRs. | Doku-Audit, keine Versionsänderung (APP_VERSION unverändert 0.78.1) · nur docs/betrieb/Doku-Review-2026-07.md neu geschrieben · HANDOFF §4/§5 + Timesheet gepflegt · kein Code-/Schema-Change · 442 Vitest + tsc + ng build unverändert grün. |
| MED-D-133 | 2026-07-14 | Doku-Welle 4 · MED-OP-DOKU-5 (Kern) | Doku-Welle 4a+4b umgesetzt — Re-Audit-Befunde B20–B23/B29/B30 behoben. Nutzer wählte "4a + 4b" aus dem in MED-D-132 vorgelegten Maßnahmenplan. 4a Wahrheit wiederherstellen: README.md/docs/fachlich/MVP-Scope.md von 0.67.0/419-Tests auf 0.78.2/442-Tests synchronisiert + Beratungsaufträge/World-2-Rollout/UX-Wellen 6-8 nachgetragen (B21). docs/fachlich/Lastenheft.md (die fachliche Master-Spezifikation) bekommt einen neuen §5.1a "Beratungsaufträge — 3-Ebenen-Modell"-Abschnitt (Kurzfassung + Verweis auf Beratungsauftraege.md) — vorher an keiner Stelle erwähnt (B20). Phantom-"Ablage"-Fehler an der Quelle behoben: Lastenheft.md §5.1 trug noch die alte 7-Zustands-Version (Unterschrift → Ablage → Wiedervorlage/Betreuung → Archiv mit eigenem Ablage-State im stateDiagram-v2) — auf die in Prozessmodell.md/System-Charakter.md bereits etablierte 6-Zustands-Version umgestellt (Ablage = quer-liegende Achse, kein Phantom-Zustand); derselbe Fehler auch in CLAUDE.mds eigener "Standard-Prozess"-Zeile behoben, dort zusätzlich um einen Hinweis auf die Beratungsauftrags-Ebene ergänzt (B29). Zugleich das veraltete OP-LEAD-1-"Workflow-Ausbau offen"-Statement in Lastenheft.md als durch Slice C2a (MED-D-106) gelöst markiert. docs/architektur/Deploy.md von "der erste echte Deploy steht aus" auf "live in Produktion" korrigiert (Banner + §8 OP-DEPLOY-1-Zeile) — das Doc widersprach der seit Wochen laufenden Produktion (B22). docs/produkt/Management-Summary.md: Ablage-Zeile der Platzhalter-Tabelle von "Standard = Platzhalter" auf "✅ produktiv aktiv" korrigiert (widersprach dem in MED-D-131/B6 bereits gelösten R2-Status); Leitprinzipien-Abschnitt um die 4 drkv-Standard-Bausteine (Echtzeit/Moderne Frameworks/In-App-Chatbot/Feedback) ergänzt, die dort komplett fehlten, obwohl Entwicklungsansatz.md sie schon führte (B24/B30). 4b Check-Lücke schließen: scripts/check-doc-consistency.sh §8-Regex von [Ss]tand[^A-Za-z]... auf ([Ss]tand|[Ss]tatus)[^A-Za-z]... erweitert — README/MVP-Scope formulierten "Status (x.y.z...)", was der alte Regex nie erkannte; docs/fachlich/Lastenheft.md zur geprüften Dateiliste hinzugefügt (fehlte komplett). Fix verifiziert: ein synthetischer Test mit dem alten "Status (0.67.0...)"-Wortlaut zeigt, dass der neue Regex ihn jetzt erkennen würde; der Live-Lauf nach dem Fix ist grün (B23). Alle Stand-Stempel (README/MVP-Scope/Lastenheft/CLAUDE.md/Feature-Liste/Test-Übersicht/Sanity-Checkliste/Management-Summary) konsistent auf 0.78.2 gebracht — inkl. Nachziehen zweier historischer Referenzen (HANDOFF-Zeile zu MED-D-131 fälschlich auf 0.78.2 statt 0.78.0→0.78.1 mitgezogen durch ein zu breites sed; sowie der MED-D-132-Audit-Bezugspunkt v0.78.1, ebenfalls versehentlich mitgezogen) — beide vor dem Commit korrigiert. Bewusst nicht in diesem PR (4c/4d, → neu MED-OP-DOKU-6): Compliance.md/Risikoregister.md-Neuprüfung, Weltmodell-Data-Dictionary-Ergänzung, agents.md-ID-System-Lücke, docs/README.md-Index/Lesepfade-Routing, agents.md-Stempel, CLAUDE.md-§Versionierung-Restrukturierung (hängt an der offenen MED-D-131-Nutzerentscheidung), Dexman.md-Pyramidal-Fix, zwei Vor-R2-Diagramme. | 4a+4b sind die beiden als "bedienungskritisch" markierten Teilwellen aus MED-D-132 — 4a behebt die sichtbaren Widersprüche, 4b verhindert, dass sie beim nächsten Fortschritts-Schub erneut unbemerkt zurückkehren; genau die Lücke, die B18/B19 (letzter Audit) und jetzt B20–B23 (dieser Re-Audit) beide als Wurzelursache benannten. Der Lastenheft-Fix ist der wichtigste Einzelfix: eine Reparatur, die nur an abgeleiteten Docs ansetzt, aber nie an der zitierten Quelle, hält nicht wirklich — sie verlagert den Fehler nur. Der Check-Regex-Fix ist bewusst mit einem Vorher/Nachher-Test verifiziert statt blind vertraut, weil genau ein ungetesteter Regex-Fix die Ursache des gefundenen blinden Flecks war. Die beim sed-Rollout entdeckte Selbstkorrektur (zwei historische Referenzen versehentlich mitgezogen) ist selbst ein Beleg für die B18-Diagnose in Miniatur — automatisierte Versions-Synchronisation ohne Nachprüfung kann genau die Art Drift erzeugen, die dieser PR beheben soll; deshalb vor dem Commit einzeln nachgeprüft statt dem sed-Ergebnis blind vertraut. | gebaut (0.78.1 → 0.78.2, PATCH) · nur Doku + 1 Skript (check-doc-consistency.sh), kein Code-/Schema-Change · 442 Vitest + tsc + ng build unverändert grün · Doku-Konsistenz-Check grün (getestet: erkennt jetzt sowohl "Stand" als auch "Status"). |
| MED-D-150 | 2026-07-19 | Feature/Formular-Datenqualität (R1/R2) | MED-OP-VALID-1 Slice 4: Onboarding-Formular an den kanonischen Feld-Typ angeglichen; Dentmarking-Fragebogen bewusst NICHT vereinheitlicht. Direkte Fortsetzung nach Slice 3 (MED-D-149) — auf eine Erklärung der drei verbliebenen Slice-2-Folgepunkte (Onboarding-/Dentmarking-Angleichung, Ausfüll-Formular-Client-UI, Adressvalidierung) wählte der Nutzer "1" (Onboarding-/Dentmarking-Angleichung). Recherche vor der Umsetzung (2 parallele Explore-Agenten statt Annahme, dass beide Ziele gleich groß sind): Onboarding (server/src/domain/einwilligung.ts) hat mit StammdatenFeld.typ (`'text' | 'email' | 'tel' |
| MED-D-149 | 2026-07-19 | Feature/Formular-Datenqualität (R1) | MED-OP-VALID-1 Slice 3: PLZ↔Ort-Plausibilitätsprüfung via OpenPLZ (Teil (b), letzter offener Bau-Rest des Themas). Direkte Fortsetzung von MED-D-146/147 — nach einer Erklärungsrunde über die drei verbliebenen Slice-2-Folgepunkte (Onboarding/Dentmarking-Angleichung, Ausfüll-Formular-Client-UI, Adressvalidierung) wählte der Nutzer explizit die Adressvalidierung. G-1-Entscheidung ("g-1: use OpenPLZ; note as a potential later improvement to use online service"): OpenPLZ (openplzapi.org) — ein öffentliches, kostenloses DACH-Postleitzahlverzeichnis ohne API-Key — statt eines bezahlten Online-Geocoding-Dienstes (HERE/Google/Post); Wechsel auf einen umfassenderen Dienst bleibt als spätere Option festgehalten, nicht verworfen. Live per WebFetch recherchiert (Endpunkt GET /{de|at|ch}/Localities?postalCode=…, leeres Array bei unbekannter PLZ) statt geraten. Umsetzung: neue PlzOrtProvider-Abstraktion (server/src/adressen/provider.ts, strukturell analog KiFeldVorschlag/SignaturProvider); OpenPlzClient (adressen/openplz.ts) sucht DE→AT→CH (Zielmärkte-Reihenfolge aus CLAUDE.md), je Land mit AbortController-3s-Timeout, fängt jeden Fehler (Netzwerk/Timeout/HTTP) intern ab und liefert dann neutral "nicht prüfbar, plausibel: true" statt zu werfen — ausschließlich weich (analog feld-typ.ts, MED-D-146): eine Unplausibilität ist immer nur Hinweis, nie Blocker, Freitext-Orte bleiben immer speicherbar. Neuer pruefePlzOrt()-Helfer in app.ts (zusätzliche Verteidigungsschicht: fängt den Provider-Aufruf selbst nochmal in try/catch, analog dem MED-D-148-Fix für kiFeldVorschlag), wired an Praxis-Anlege-/PATCH-Route (PATCH nur bei tatsächlich enthaltenem plz/ort-Feld); Client (mandant-detail.component.ts#praxisAnlegen()) zeigt bei einem Ort-Vorschlag einen zweiten Undo-Toast (bestehendes ToastService.mitAktion-Muster, wie schon beim PLZ-Vorschlag in Slice 2). Selbst gefundener und korrigierter Fehler vor jeder Nutzer-Sichtbarkeit: der erste Entwurf setzte den echten OpenPlzClient als createApp()-Default — ein Testlauf mit einem 936ms-Ausreißer (statt der üblichen 1–5ms) deckte einen echten Netzwerkaufruf in einem Unit-Test auf; korrigiert nach dem etablierten NextCloud/Signatur-Muster: test-sicherer FakePlzOrt-Default in createApp(), der echte, netzwerkrufende Client wird ausschließlich im Worker-Entrypoint index.ts verdrahtet (kein Secret nötig, daher unconditional, anders als NextCloud/Signatur mit DEMO_MODE-Gate). Gegen echten Browser UND die echte OpenPLZ-API verifiziert (wrangler dev + Playwright, kein Mock): Praxis mit PLZ "40210"/Ort "Köln" angelegt → Toast "meintest du „Düsseldorf"?" → Klick → Server-Praxis-Liste bestätigt ort: "Düsseldorf" (Screenshot gesichert). +13 Vitest (openplz.test.ts 6, fake.test.ts 3, praxis.test.ts +4). Damit ist MED-OP-VALID-1 (a)+(b) für Praxis-Felder vollständig gebaut — Onboarding/Dentmarking-Angleichung + Mandant-Stammdaten-Editierbarkeit bleiben als Folge-Slices offen (HANDOFF §4). | Der selbst gefundene Netzwerkleck-Bug ist der wichtigste Fund dieser Runde: er hätte unbemerkt jeden künftigen Testlauf um fast eine Sekunde verlangsamt und — schwerwiegender — die Testsuite von der Erreichbarkeit eines externen Dritt-Dienstes abhängig gemacht (Flakiness-Risiko bei jedem CI-Lauf ohne Internetzugriff); die Diagnose gelang nur, weil eine Laufzeit-Anomalie (936ms statt 1–5ms) aktiv hinterfragt statt als Zufallsschwankung abgetan wurde — dieselbe Disziplin wie bei den D1-/Atomizitäts-Funden in MED-D-143. Die Wahl von OpenPLZ statt eines bezahlten Geocoding-Dienstes ist eine echte G-1-Anwendung: ein öffentlicher, kredentialloser Standarddienst deckt den Bedarf (DACH-Postleitzahlen-Plausibilität) vollständig ab, ohne einen neuen AVV-pflichtigen Vertragsdienst (Kosten, Compliance-Prüfung, Secret-Verwaltung) einzuführen — die vom Nutzer selbst benannte "spätere Verbesserung" bleibt eine bewusst nicht vorweggenommene Tür, kein Kompromiss. Die doppelte Fehlerbehandlung (Provider-intern UND Aufrufer-seitig) ist bewusst redundant — genau das Muster, das die MED-D-148-Nachlese für den KI-Vorschlag bereits als notwendig identifiziert hatte, hier von Anfang an mitgebaut statt erst in einer Nachlese nachgezogen. | gebaut (0.80.0 → 0.81.0, MINOR) · server/src/adressen/provider.ts + openplz.ts + fake.ts (neu) · server/src/adressen/openplz.test.ts + fake.test.ts (neu) · server/src/api/app.ts (plzOrtProvider-Deps, pruefePlzOrt()-Helfer, Praxis-Routen) · server/src/index.ts (echter OpenPlzClient verdrahtet) · server/src/api/praxis.test.ts (+4 Tests) · client/src/app/mandant-detail.component.ts (zweiter Undo-Toast) · 479 Vitest (466→479, 46 Dateien) + tsc + ng build grün · Doku-Konsistenz-Check grün · Golden Path gegen echten Browser + echte OpenPLZ-API verifiziert. |
| MED-D-148 | 2026-07-18 | Doku/Way-of-Working | CodeRabbit-Nachlese zu MED-D-147 (PR #189): 5 von 6 Befunden echt, nachgezogen. 6 Befunde geprüft, jeder einzeln gegen den aktuellen Code verifiziert statt blind übernommen. Echt, behoben (5): (1) server/src/api/app.tss weicheHinweise() rief kiFeldVorschlag.schlageVor() ohne Fehlerbehandlung auf — ein Provider-Fehler hätte die bereits erfolgreiche POST/PATCH-Mutation mit 500 scheitern lassen (Datenintegritäts-Risiko: Nutzer könnte eine bereits angelegte Praxis erneut anlegen); auf try/catch umgestellt, die Mutation bleibt bei einem Vorschlags-Fehler erfolgreich, nur vorschlaege bleibt für dieses Feld leer. (2) mandant-detail.component.tss PLZ-Undo-Toast-Aktion hatte keinen Error-Handler am praxisAendern-PATCH — bei einem Fehlschlag hätte der Nutzer keine Rückmeldung bekommen; error: () => this.toast.fehler(...) ergänzt. (3) HANDOFF.md §4 MED-OP-TEST-1-Zeile nannte noch "446 Vitest" statt der aktuellen 466 — nachgezogen. (4) docs/produkt/Management-Summary.md §5 "Nächste Schritte"-Tabelle listete die smarten Formular-Vorschläge noch komplett als Zukunft ("Fake-Seam zuerst... echtes LLM später"), obwohl Slice 1+2 bereits gebaut sind — Zeile umformuliert auf die tatsächlich verbleibenden Folge-Slices (Onboarding/Dentmarking-Angleichung, Client-UI, Adressvalidierung). (5) docs/betrieb/Timesheet.mds MED-D-147-Zeile (Session -46) zitierte den Toast-Text mit zwei typografischen „-Anführungszeichen statt gerader " — verletzte die eigene, gerade erst in MED-D-145 verankerte Konvention (agents.md §2); auf gerade Anführungszeichen (verschachtelt: äußere '…', innere "…") korrigiert. Zusätzlich mitgenommen (im Review nicht explizit gefordert, aber derselbe Root-Cause): docs/betrieb/Test-Uebersicht.mds Intro-Absatz narrierte nur bis MED-D-143 und ließ MED-D-146/147 unerwähnt — ergänzt. Geprüft, bewusst NICHT übernommen (1): server/src/api/praxis.test.ts — CodeRabbits committable suggestion behauptete eine doppelte const body-Deklaration in Zeile 150; die Datei enthält diese Deklaration nur einmal (verifiziert per Read + tsc --noEmit + vollem Testlauf, beide grün vor UND nach diesem Fix, Testzahl unverändert 466) — CodeRabbits Diff-Analyse hat hier fälschlich dupliziert, kein echter Befund. Gegen echten Browser re-verifiziert (nicht nur Vitest): derselbe wrangler dev+Playwright-Golden-Path wie bei MED-D-147 nach den Fixes erneut durchlaufen (malformte PLZ → Toast-Vorschlag → Klick → korrigierter Wert persistiert) — bestätigt, dass die try/catch-Änderung das Verhalten im Erfolgsfall nicht verändert hat. | Der try/catch-Fund (1) ist der wichtigste: ohne ihn hätte ein künftiger echter LLM-Provider (Netzwerk-Timeout, Rate-Limit, Ausfall) eine an sich erfolgreiche Praxis-Anlage in einen 500 verwandelt — genau die Art Fehler, die in der Fake-Phase (deterministisch, wirft nie) unsichtbar bleibt und erst beim echten LLM-Rollout (OP-AI-1) zuschlagen würde; jetzt vorab abgesichert. Der False-Positive-Fund (praxis.test.ts) unterstreicht erneut die in dieser Session wiederholt angewandte Disziplin, jeden CodeRabbit-Befund gegen den tatsächlichen Code zu verifizieren statt Diff-Vorschläge blind zu committen (Präzedenz: MED-D-141s OP-LEAD-1-Fehlalarm, MED-D-143s vier bewusst nicht übernommene Befunde) — ein blind übernommener Fix hätte hier eine funktionierende Zeile gelöscht und die Datei kaputt gemacht. Die Doku-Funde (3–5) sind dieselbe Art Stempel-Drift, die schon mehrfach in dieser Session aufgetreten ist (übersehene Zahlen-Updates bei Multi-Datei-Stempel-Syncs) — hier zusätzlich bemerkenswert, weil Fund (5) exakt die Konvention verletzte, die diese Session selbst erst wenige Stunden zuvor (MED-D-145) eingeführt hatte, ein gutes Beispiel dafür, wie leicht eine frisch etablierte Konvention in der Eile eines neuen PRs wieder aufweicht, wenn sie nicht mechanisch erzwungen wird (der .coderabbit.yaml-path_instructions-Eintrag verhindert nur False-Positives, keine echten Abweichungen). | gebaut (0.80.0 unverändert, keine Versionsänderung — reine Fehlerbehandlung/Doku-Pflege, kein neues Feature) · server/src/api/app.ts (try/catch um kiFeldVorschlag.schlageVor) · client/src/app/mandant-detail.component.ts (Error-Handler am PLZ-Übernehmen-PATCH) · HANDOFF.md + docs/produkt/Management-Summary.md + docs/betrieb/Timesheet.md + docs/betrieb/Test-Uebersicht.md (Doku-Nachzug) · 466 Vitest (unverändert) + tsc + ng build grün · Doku-Konsistenz-Check grün · Golden Path erneut gegen echten Browser verifiziert. |
| MED-D-147 | 2026-07-18 | Feature/Formular-Datenqualität (R1/R12) | MED-OP-VALID-1 Slice 2: KI-Formatvorschlag erstmals in einem App-internen Eingabefeld (Praxis-PLZ). Nutzeranstoß "Die smarte Eingabe-Unterstützung (LLM + RAG?) auch für die Eingabe-Felder in der App verwenden" — die Parenthese "(LLM + RAG?)" beantwortet, bevor gebaut wurde: docs/architektur/In-App-Assistent.md (OP-ASSIST-1, weiterhin Design-only) scopet RAG strikt auf Doku-Retrieval, §5 verbietet explizit PII/Bestandsdaten im Vektor-Store — Feld-Formatvorschlag braucht keine Retrieval, sondern genau den bereits gebauten deterministischen KiFeldVorschlag-Mechanismus (Slice 1, MED-D-146); kein Zusammenhang zu OP-ASSIST-1 zu pflegen. Recherche vor Umsetzung (Explore-Agent) auf die tatsächlich Berater-editierbaren App-Felder: Mandant-Stammdaten (telefon/geburtsdatum/strasse/plz/ort) sind heute gar nicht in-app editierbar — nur über den auditierten Formular-Rückübernahme-Pfad gesetzt (ausfuellformular-service.ts); einzig Praxis strasse/plz/ort sind bereits Berater-editierbar (Anlegen + PATCH in app.ts) und dort komplett ungeprüft (nur trim()); Mandant email/ibanPrivat und Praxis iban/geschaeftsjahrBeginnMonat sind bereits hart validiert (400 bei ungültigem Wert). Zwei echte Forks proaktiv vorgelegt, nicht selbst entschieden: (1) sollen die bereits harten Felder auf "immer weich" umgestellt werden (Verhaltensänderung einer produktiven API) oder bleibt der Vorschlag nur additiver Helfer? (2) soll Mandant-Stammdaten neu Berater-editierbar werden (umgeht die auditierte Formular-Rückübernahme, G-4)? Nutzer bestätigte "yes" — beide bewusst konservativ: harte Felder bleiben hart, Mandant-Stammdaten-Editierbarkeit wird nicht neu eingeführt. Scope damit auf die einzige risikofreie additive Erweiterung reduziert: Praxis-plz. Da diese bereits hart-validierten Felder (Mandant-IBAN/E-Mail, Praxis-IBAN) beim Empfang bereits normalisiert+geprüft werden, hätte ein zusätzlicher Vorschlags-Layer dort ohnehin nie einen echten Hinweis erzeugt (der gespeicherte Wert ist per Konstruktion schon gueltig) — bewusst nicht implementiert, um keinen toten Code zu schreiben. Umsetzung: neuer weicheHinweise()-Helfer in app.ts (nutzt den bereits verdrahteten kiFeldVorschlag) an POST /api/mandanten/:id/praxen und PATCH /api/praxen/:id — Antwort um hinweise/vorschlaege erweitert (additiv, {...p, hinweise, vorschlaege}, kein Bruch der bestehenden Praxis-Antwortform, geprüft: PATCH berechnet nur, wenn plz tatsächlich im Patch enthalten war). Client: PraxisMitHinweisen-Typ in api.service.ts, mandant-detail.component.ts#praxisAnlegen() zeigt bei einem PLZ-Vorschlag einen Undo-Toast (ToastService.mitAktion, bestehendes Nielsen-#3-Muster wiederverwendet statt einer neuen Inline-Hinweis-Komponente — die Praxis-Anlegen-Felder leeren sich sofort nach Erfolg, ein Inline-Hinweis am Feld wäre sofort wieder verschwunden) — Klick löst ein echtes praxisAendern-PATCH mit dem Vorschlag aus, ohne Klick bleibt der Originalwert unverändert. Gegen echten Browser verifiziert, nicht nur Tests (wrangler dev --local mit .dev.vars AUTH_ENFORCED=false lokal, + Playwright, Chromium unter /opt/pw-browsers): Praxis mit PLZ "40 210" angelegt → Toast "PLZ „40 210" wirkt unüblich — meintest du „40210"?" erscheint → Klick auf "PLZ übernehmen" → Server-seitige Praxis-Liste bestätigt plz: "40210" → Screenshots vor/nach gesichert. .dev.vars nach der Verifikation entfernt (bereits gitignored, nie riskiert). +2 Vitest (praxis.test.ts: additiver Hinweis bei Anlegen, PATCH nur bei tatsächlich enthaltenem plz-Feld berechnet). | Die beiden proaktiv vorgelegten Forks (harte Felder softenen? Mandant-Stammdaten neu editierbar machen?) waren echte, unabhängig von "füge die Funktion hinzu" zu treffende Entscheidungen — beide hätten bestehendes, funktionierendes Verhalten geändert (API-Fehlercode-Vertrag bzw. Audit-Pfad-Umgehung), nicht nur etwas Neues addiert; genau der Unterschied, der laut CLAUDE.md vor jeder Aktion mit größerem Blast-Radius eine Bestätigung verlangt. Die Erkenntnis, dass ein Vorschlags-Layer auf bereits hart-validierten+normalisierten Feldern praktisch nie feuern würde, verhinderte totes Code-Gewicht, das nur suggeriert hätte, "überall" smarte Vorschläge zu haben, ohne je einen zu zeigen. Der Undo-Toast statt Inline-Hinweis ist eine bewusste UI-Entscheidung gegen das naheliegende (aber falsche) Copy-Paste des Ausfüllformular-Musters: die Formular-Ausfüll-Felder bleiben nach dem Absenden sichtbar (Formular-Kontext lebt fort), die Praxis-Anlegen-Felder leeren sich sofort — ein Inline-Hinweis hätte den Nutzer nie erreicht. Die echte Browser-Verifikation (nicht nur Vitest) ist bei UI-Änderungen laut eigener Konvention Pflicht (agents.md) — hier zusätzlich wertvoll, weil sie den vollen Kreis (API-Vorschlag → Toast → Klick → echtes PATCH → persistierter, korrigierter Wert) end-to-end bestätigt statt nur die einzelnen Schichten isoliert. | gebaut (0.79.0 → 0.80.0, MINOR) · server/src/api/app.ts (weicheHinweise()-Helfer + Praxis-Routen) · server/src/api/praxis.test.ts (+2 Tests) · client/src/app/api.service.ts (PraxisMitHinweisen) · client/src/app/mandant-detail.component.ts (praxisAnlegen() Undo-Toast) · 466 Vitest (464→466, 44 Dateien) + tsc + ng build grün · Doku-Konsistenz-Check grün · Golden Path gegen echten Browser verifiziert (Playwright + Screenshots, nicht nur Tests). |
| MED-D-146 | 2026-07-18 | Feature/Formular-Datenqualität (R12) | MED-OP-VALID-1 Slice 1: kanonischer Feld-Typ + immer-weiche Prüfung + KI-Formatvorschlag als USP. Nutzerfrage „Was können wir als Nächstes bauen (ohne DocuSign-Integration)" → Vorschlag OP-DOCGEN-2/MED-OP-AUFTRAG-1/MED-OP-VALID-1 vorgelegt, Nutzer wählte MED-OP-VALID-1 und schärfte den Scope direkt: „soll weich sein - Fallback ist, dass auch Freitext akzeptiert wird; optional per LLM validieren und passend zum Datentyp einen Vorschlag machen" — dann explizit „Dieses smarte Vorschlagen als USP festhalten". Vor der Umsetzung recherchiert statt neu erfunden (Explore-Agent): das Repo hatte die Bausteine bereits verstreut — stammdaten-uebernahme.ts trug ValidierungsArt/pruefeWert/normalisiereWert (schon "weich", gueltig nur ein Flag), iban.tss Kopfzeile nannte sich selbst explizit "erster konkreter Baustein von MED-OP-VALID-1", dentmarking-katalog.ts hatte mit Wertebereich/bereichsHinweis() bereits dasselbe Nie-blockierend-Prinzip für Dentmarking, und ausfuellformular.tss FeldArt-Kommentar sagte selbst "Validierung bleibt tolerant (G-3)". Umsetzung (G-8 „eine Definition, ein Ort" statt Neubau): ValidierungsArt/pruefeWert/normalisiereWert aus stammdaten-uebernahme.ts in einen neuen kanonischen domain/feld-typ.ts extrahiert (dort re-exportiert, kein Bruch bestehender Importe/Tests) + um plz/tel/zahl/betrag erweitert (bisher nur iban/datum/text/email); neue Funktion formatVorschlag() liefert deterministische, sichere Formatkorrekturen (DE-Datum→ISO, IBAN-Normalform, PLZ/Tel-Ziffernbereinigung) oder null, wenn nichts sicher ableitbar ist (z. B. E-Mail-Tippfehler — das braucht echtes Sprachverständnis). ausfuellformular.tss FeldArt wurde ein Alias von ValidierungsArt (unschädliche Typ-Erweiterung, da die bisherigen 4 Werte eine Teilmenge sind) + neue reine Funktion pruefeAlleWerte() (nie filternd/blockierend). Neuer KI-Vorschlag-Seam ki/vorschlag.ts (Interface KiFeldVorschlag + DTOs) + ki/regel-vorschlag.ts (RegelVorschlag, deterministischer Fake-Default) — exakt dieselbe Struktur wie ki/pruefer.ts/ki/regel.ts und ki/gespraechs-auswerter.ts (RISK-14-Haftungshinweis Pflichtfeld, „vorschlagend nicht ausführend", dormant-tauglich für ein echtes LLM später, OP-AI-1). In AppDeps/createApp verdrahtet (kiFeldVorschlag, Default RegelVorschlag) und in AusfuellformularService.kontext() verbraucht: liefert neu hinweise/vorschlaege je Feld. Wichtiger Design-Fix während der Umsetzung: der erste Entwurf berechnete den Formatvorschlag nur für Felder, die bereits einen Hinweis hatten — ein eigener Test (DE-Datum, gültig laut pruefeWert, aber nicht kanonisch) schlug fehl und deckte auf, dass ein bereits "gültiger" Wert trotzdem normalisierbar sein kann (DE-Format ist als Eingabe akzeptiert, ISO ist aber die kanonische Form) — Vorschlagsberechnung auf jedes ausgefüllte Feld umgestellt, formatVorschlag/schlageVor entscheiden selbst per null-Rückgabe, wann sich ein Vorschlag lohnt. Bewusst NICHT in diesem Slice: Angular-Client-UI für hinweise/vorschlaege (Fähigkeit ist API-seitig fertig, Anzeige ist Slice 2); Onboarding-Stammdaten (domain/einwilligung.ts) und Dentmarking-Fragebogen an denselben kanonischen Typ angleichen (folgt als Slice 2, nachdem der Client-UI-Teil den echten Zielschnitt zeigt); Adressvalidierung (b) bleibt offen (Provider-Entscheidung + Compliance-Klärung, unverändert). Als Produkt-USP festgehalten (Nutzeranweisung): docs/produkt/Produkt-und-Marketing.md (neue Nutzenversprechen-Zeile) + docs/produkt/Management-Summary.md §5 (neue Roadmap-Zeile). +18 Vitest (feld-typ.test.ts 13, regel-vorschlag.test.ts 3, ausfuellformular.test.ts +2), tsc --noEmit + ng build grün, Doku-Konsistenz-Check grün. | Die Recherche vor dem Bauen war der wichtigste Schritt dieser Runde: ein naiver erster Entwurf hätte einen parallelen, konkurrierenden Validierungs-Mechanismus geschaffen (Duplikat von pruefeWert/ValidierungsArt), genau das, was G-8 („eine Definition, ein Ort") und G-2 („eine Wahrheit") verbieten — stattdessen wurden drei bereits vorhandene, aber nie verbundene Bausteine (stammdaten-uebernahme.ts, iban.ts, dentmarking-katalog.ts) zu einer kanonischen Data-Dictionary-Entität zusammengeführt. Der Nutzerwunsch „ausschließlich weich" war dabei kein neuer Kompromiss, sondern deckte sich exakt mit der bereits bestehenden Code-Philosophie (gueltig war in stammdaten-uebernahme.ts schon immer „nur ein Flag, nicht blockierend") — die Entscheidung schärfte damit vor allem die HANDOFF-Formulierung („weich vs. hart wählbar" → „ausschließlich weich"), nicht die Architektur. Der während der Implementierung selbst gefundene Design-Fehler (Vorschlag nur bei Hinweis statt bei jedem Feld) zeigt erneut den Wert eines eigenen Tests, der eine echte Erwartung prüft, statt nur den bereits geschriebenen Code zu bestätigen — derselbe Vorher/Nachher-Reflex wie bei den D1-/Atomizitäts-Fixes in MED-D-143. Das explizite Festhalten als USP (statt nur als technischer OP-Fortschritt) ist bewusst: „nie blockierend, aber smart" ist ein Differenzierungsmerkmal gegenüber starren Formular-Validierungen anderswo, kein reines Implementierungsdetail. | gebaut (0.78.5 → 0.79.0, MINOR) · server/src/domain/feld-typ.ts (neu) · server/src/domain/stammdaten-uebernahme.ts (Extraktion, Re-Export) · server/src/domain/ausfuellformular.ts (FeldArt-Alias, pruefeAlleWerte) · server/src/ki/vorschlag.ts + ki/regel-vorschlag.ts (neu) · server/src/api/app.ts (AppDeps.kiFeldVorschlag) · server/src/api/ausfuellformular-service.ts (kontext() liefert hinweise/vorschlaege) · docs/produkt/Produkt-und-Marketing.md + docs/produkt/Management-Summary.md (USP) · 464 Vitest (446→464, 44 Dateien) + tsc + ng build grün · Doku-Konsistenz-Check grün. |
| MED-D-145 | 2026-07-18 | Doku/Way-of-Working | Anführungszeichen repo-weit auf gerade Zeichen ("/') vereinheitlicht + CodeRabbit angewiesen. Nutzeranstoß „coderabbit is often complaining about quotes, can we just use straight quotation marks always and instruct coderabbit to be happy about it?" — Root-Cause-Analyse: der Doku-Bestand mischte durchgängig „…" (öffnend typografisch/deutsch, schließend gerade — 1686 Fundstellen) mit vereinzelt korrektem „…" (135), ‚…‘ (7) und Ausreißern (”, ’, «») über alle 44 .md-Dateien — genau dieser Bruch (öffnend ≠ schließend) ist die plausibelste Ursache für CodeRabbits wiederholte Typografie-/„Unpaired"-Nitpicks (u. a. der zuvor beobachtete UNPAIRED_BRACKETS-Hinweis auf Test-Uebersicht.md). Scope bewusst auf Doku begrenzt (Rückfrage gestellt, Nutzer bestätigte „docs only"): ein Grep zeigte 93 zusätzliche Client-/Server-Dateien mit denselben Zeichen (UI-Labels, Fehlermeldungen, PDF-Vorlagen, ~30 Tests mit exakten String-Assertions) — ein Umbau dort wäre eine Produkttext-/UX-Entscheidung mit Test-Synchronisationsrisiko, kein reiner Formatierungs-Fix, und blieb bewusst außen vor. Umsetzung: mechanisches Zeichen-Mapping („/"/"→", ‚/'/'→') über alle 43 betroffenen .md-Dateien (reine Zeichenersetzung, keine Zeilenänderung, 850/850 Zeilen 1:1 ersetzt) — bewusst ausgenommen: die ‹Variable›/»…«-Platzhalter-Notation in docs/spezialtools/Dentmarking-Excel-Logik.md (Excel-Formel-Konvention aus dem Original, kein Zitat). Nebenfund, mitbehoben: beim Verifizieren der Mermaid-Diagramme gegen den echten Renderer (nicht nur gelesen) ein vorbestehender, unabhängiger Syntaxfehler in Dentmarking.md entdeckt — der Flowchart-Knoten F[Word "Auffälligkeiten"<br/>manuell] enthielt bereits vor dieser Änderung ein unescapetes Anführungszeichen in einem ungeklammerten Label (bestätigt: auch mit der ursprünglichen „…"-Schreibweise bereits ungültig) — auf ["Word #quot;Auffälligkeiten#quot;<br/>manuell"] korrigiert, gegen den Mermaid-Validator bestätigt grün; die beiden Sequenzdiagramme in Dokumentenverwaltung-NextCloud.md/Unterschriften.md ebenfalls einzeln validiert (dort ist ein bloßes Anführungszeichen im Nachrichtentext unproblematisch, keine Fixe nötig). Konvention verankert (eine Definition, ein Ort): neuer Absatz in agents.md §2 „Anführungszeichen: immer gerade" — Regel + Begründung + Ausnahme. .coderabbit.yaml bekommt einen neuen reviews.path_instructions-Eintrag für **/*.md, der CodeRabbit explizit anweist, gerade Anführungszeichen nicht als typografisch inkonsistent/unpaired zu markieren oder eine Ersetzung durch „…"/«…» vorzuschlagen. | Der Nutzeranstoß traf einen echten wiederkehrenden Reibungspunkt (mehrfach in dieser Session als CodeRabbit-Nitpick beobachtet) — die Root-Cause war nicht „CodeRabbit ist zu pingelig", sondern ein echter, historisch gewachsener Stilbruch im Bestand (öffnend/schließend-Mismatch), den ein einheitliches gerades Zeichen strukturell beseitigt statt nur zu kaschieren. Die Scope-Rückfrage (Doku vs. auch App-Code) war notwendig, weil beide Optionen fundamental unterschiedliche Risikoprofile haben (reine Zeichenersetzung in Prosa vs. Änderung sichtbaren Produkttexts + Test-Fixtures) — dieselbe Disziplin, vor einem großflächigen mechanischen Edit den Blast-Radius zu klären, die diese Session bereits beim Timesheet-/CHANGELOG-Merge-Verhalten angewendet hat. Der beim Verifizieren gefundene Mermaid-Syntaxfehler zeigt den Wert, Diagramme gegen den echten Renderer zu prüfen statt nur zu lesen (Präzedenzfall: die node:sqlite-Verifikation bei MED-D-143) — ein rein visuelles Reading hätte den Fehler nicht aufgedeckt, da er unabhängig vom Anführungszeichen-Stil bereits bestand. | keine Versionsänderung (APP_VERSION unverändert 0.78.5, reine Doku-/Konfig-Pflege) · 43 .md-Dateien (Zeichen-Mapping) + docs/spezialtools/Dentmarking.md (Mermaid-Fix) + docs/konventionen/agents.md §2 (neue Konvention) + .coderabbit.yaml (neuer path_instructions-Eintrag) · kein Code-/Schema-Change · 446 Vitest + tsc + ng build unverändert grün · Doku-Konsistenz-Check grün · 3 Mermaid-Diagramme einzeln gegen echten Validator geprüft (1 vorbestehender Fehler gefunden + behoben, 2 bereits gültig). |
| MED-D-144 | 2026-07-16 | Doku/Way-of-Working | CodeRabbit-Nachlese zu MED-D-143 (PR #185): 2 von 4 Restpunkten echt, nachgezogen. PR #185 mergte per Auto-Merge, bevor die zweite Review-Runde vollständig geprüft war; alle 4 Punkte einzeln verifiziert statt pauschal übernommen oder verworfen. Echt, behoben (2): (1) docs/fachlich/Feature-Liste.md fehlte — anders als docs/betrieb/Test-Uebersicht.md (bereits in Lesepfade.md Zeile 44 unter "DevOps" geroutet) — in jedem Lesepfad der docs/zielgruppen/Lesepfade.md; geprüft per Grep, kein Treffer. Fix passend zur "eine Definition, ein Ort"-Governance (agents.md §5.4/MED-D-110): nicht eine Zielgruppen-Zeile direkt in Feature-Liste.md einbauen (Duplikat der kanonischen Routing-Quelle), sondern die Datei als Schritt 2 in den bestehenden "Business / Management"-Lesepfad aufgenommen (passt zur Kernfrage "was ist tatsächlich gebaut"). (2) Der CodeRabbit-Nitpick zum Decision-Log verlangte einen benannten MED-OP-/RISK-n-Folgepunkt für die in MED-D-143 nur im Fließtext erwähnte D1-/SQLite-Testharness-Lücke, "damit sie nicht verloren geht" — neue Zeile MED-OP-TEST-1 in HANDOFF.md §4 angelegt (Beschreibung + naheliegende Lösung node:sqlite als zweiter Vitest-Testkreis), MED-D-143s Fließtext-Verweis nachträglich auf die neue ID umgestellt. Geprüft, bewusst NICHT übernommen (2): CHANGELOG.md-Zeile für MED-D-143 auf [PR #185](link)-Format statt Branch-Name umstellen — das Branch-Name-Format ist über das gesamte File hinweg die etablierte Konvention für Einträge, die im selben Commit wie der PR-Erstellung entstehen (PR-Nummer zum Zeitpunkt des Commits unbekannt); ein Einzelfall-Fix hätte nur diese eine Zeile inkonsistent zum Rest der Datei gemacht. Test-Uebersicht.md-Intro um einen benannten Zielgruppen-Satz erweitern — bereits über Lesepfade.md Zeile 44 kanonisch geroutet (DevOps-Pfad, Punkt 3); eine zusätzliche Inline-Nennung wäre eine zweite, redundante Definition derselben Zielgruppen-Zuordnung (verletzt G-8/"eine Definition, ein Ort"). | Der Feature-Liste-Fund war der einzige der vier mit einem echten, unentdeckten Lücken-Charakter (kein Lesepfad verwies auf die Datei) — die drei anderen Funde ließen sich erst durch Gegenprüfung gegen die tatsächliche Governance-Regel (G-8, agents.md §5.4) und die tatsächliche Repo-Historie (CHANGELOG-Formatkonvention) als bereits abgedeckt oder als Verstoß gegen genau die Regel entlarven, die der jeweilige Fix hätte umsetzen sollen. Dasselbe Substanz-Filter-Prinzip wie bei MED-D-143: "jeden Befund prüfen, nicht jeden Befund übernehmen". | keine Versionsänderung (APP_VERSION unverändert 0.78.5, reine Doku-Pflege) · docs/zielgruppen/Lesepfade.md (Feature-Liste.md ergänzt) · HANDOFF.md §4 (neue Zeile MED-OP-TEST-1) · docs/betrieb/Decision-Log.md (dieser Eintrag + MED-D-143-Fließtext-Verweis aktualisiert) · kein Code-/Schema-Change · 446 Vitest + tsc + ng build unverändert grün · Doku-Konsistenz-Check grün. |
| MED-D-143 | 2026-07-16 | Sicherheit/Betrieb (R7/R5) | CodeRabbit-Nachlese zu MED-D-142 (PR #181): 5 von 9 Befunden echt, nachgezogen. PR #181 mergte (Auto-Merge scharf), bevor CodeRabbits Review eintraf (Draft-Skip-Timing, analog MED-D-131) — 9 Kommentare geprüft, jeder einzeln gegen den gemergten Code verifiziert statt blind übernommen. Echt, behoben (5): (1) server/src/api/app.ts byIdMandantScopeGuard: bei aufgelöster mandantId, aber fehlendem Mandanten-Datensatz (repo.getMandant() liefert null) fiel der Guard bislang fail-open durch zu next() statt zu sperren — inkonsistent zum bestehenden mandantScopeGuard (Chokepoint B), der bei fehlendem Mandanten bereits 404 liefert; jetzt fail-closed. Heute über die App nicht erreichbar (keine Mandant-Löschroute existiert), aber Defense-in-Depth für inkonsistente Daten. (2) d1-repo.ts/memory-repo.ts: die Duplicate-Recovery prüfte quelleRef auf Truthy statt Nullish — ein expliziter leerer String hätte die Dublettenprüfung umgangen; auf !== null/!== undefined umgestellt. (3) memory-repo.ts: der Check-dann-Insert lief über das async getWiedervorlageByQuelle, dessen await an die Microtask-Queue yieldet — unter echter Nebenläufigkeit (Promise.all) hätten zwei Aufrufe beide "noch nichts da" gesehen, bevor einer schreibt (derselbe Race, den MED-D-142 im D1-Pfad schon geschlossen hatte, blieb im Memory-Pfad offen). Fix: synchroner Inline-Lookup statt async-Methodenaufruf — die gesamte createWiedervorlage-Methode hat jetzt keinen Zwischen-await mehr, damit im Single-Thread-Sinn atomar. Der bestehende Idempotenz-Test in wiedervorlage.test.ts lief bislang sequenziell (zwei awaits hintereinander) und hätte diesen Race nie aufgedeckt — auf Promise.all umgestellt, ohne anzunehmen, welche der beiden Eingaben "gewinnt". (4) migrate.ts Migration v39: CREATE UNIQUE INDEX validiert den Bestand — existierten bereits Alt-Dubletten aus der Zeit vor diesem Fix (durch den früheren Read-then-Write-Race durchaus plausibel), wäre der Index-Aufbau mit Fehler abgebrochen und die Auto-Migration bliebe bei jedem Worker-Start auf 38 hängen, auf einer live produktiven D1-Datenbank. Fix: ein UPDATE-Reconciliation-Schritt vor dem Index — behält je Dublette die älteste Zeile (kleinste ULID = früheste angelegtAm), entfernt nur die quelle_ref-Referenz der jüngeren Duplikate (kein DELETE, kein Datenverlust, G-4-sicher), idempotent (zweiter Lauf matcht 0 Zeilen). Gegen echtes node:sqlite verifiziert (nicht nur gelesen): Alt-Dubletten seeden → Migration laufen lassen → Dedup korrekt + Index erfolgreich erstellt + zweiter Lauf No-Op + ein echter neuer Duplicate-Insert wird jetzt korrekt vom Index abgelehnt. (5) docs/produkt/Management-Summary.md: ein 442-Rest in der Qualitätssicherungs-Zeile war beim vorherigen Stamp-Sync übersehen worden (4 andere Stellen in derselben Datei waren schon auf 446) — nachgezogen. Geprüft, bewusst NICHT übernommen (4): CLAUDE.md-§Versionierung weiter kürzen — widerspräche der gerade erst in MED-D-140 getroffenen Nutzerentscheidung, die genau diesen Absatz auf die jetzige Kurzform brachte. Decision-Log-Zeile ans strikte Dateiende verschieben — die eigene Kopfzeile des Logs sagt "analog CHANGELOG.md" (dort explizit "neueste zuerst"), MED-D-143 folgt also bewusst demselben Neueste-zuerst-Muster wie alle Einträge seit MED-D-139/140/141. Feature-Liste.md um granulare Detail-Zeilen für beide OPs erweitern — stattdessen die bereits bestehende RBAC-Zeile (Zeile 100) minimal um den By-ID-Guard-Verweis ergänzt, passend zur Datei-Konvention (Modul-Zeilen, keine Einzelfund-Zeilen je Sicherheits-Patch). Eine D1-/SQLite-Migrationstest-Infrastruktur neu aufbauen — das Repo hat aktuell keinerlei D1-Test-Harness (alle 446 Tests laufen gegen MemoryRepo, d1-repo.ts ist ungetestet seit Projektbeginn); das wäre eine eigene, größere Infrastruktur-Entscheidung, nicht Teil dieses Fixes — die manuelle node:sqlite-Verifikation deckt den konkreten Fall stattdessen einmalig, aber gründlich ab. Damit diese bewusst vertagte Lücke nicht im Fließtext verloren geht: als MED-OP-TEST-1 in HANDOFF.md §4 nachgetragen (MED-D-144). | Der wichtigste Einzelfund (4, Migration) ist ein echtes Produktions-Risiko: app.medidentas.com läuft live, und ein fehlschlagender Migrationsschritt hätte den Worker bei jedem Start erneut auf Version 38 zurückgeworfen, ohne dass die eigentliche Ursache (Alt-Dubletten) offensichtlich gewesen wäre. Dass CodeRabbits Review erst nach dem Auto-Merge eintraf, ändert nichts an der Sorgfaltspflicht — dieselbe Lehre wie bei MED-D-131 (verspätete Reviews verdienen dieselbe Nachlese wie rechtzeitige). Die vier bewusst NICHT übernommenen Befunde sind kein Nachlässigkeits-, sondern ein Substanz-Filter: jeder hätte entweder eine bereits getroffene Nutzerentscheidung revidiert (CLAUDE.md), auf einer falschen Prämisse über die eigene Repo-Konvention beruht (Decision-Log-Reihenfolge), das Doku-Schema der Zieldatei verletzt (Feature-Liste) oder eine unverhältnismäßig große neue Infrastruktur-Entscheidung erzwungen (Migrationstests) — "jeden Befund prüfen, nicht jeden Befund übernehmen" ist derselbe Maßstab, den diese Session bereits beim eigenen Check-Blind-Spot (MED-D-141, dort sogar ein selbst gefundener False Positive) angewendet hat. | gebaut (0.78.4 → 0.78.5, PATCH) · server/src/api/app.ts (Guard fail-closed) · server/src/db/migrate.ts (Migration v39 + Reconciliation) · server/src/repo/d1-repo.ts + memory-repo.ts (Nullish-Check + Atomizität) · server/src/api/wiedervorlage.test.ts (Promise.all-Race-Test) · docs/fachlich/Feature-Liste.md + docs/produkt/Management-Summary.md (Doku-Nachzug) · 446 Vitest (gleiche Zahl, ein Test verschärft) + tsc + ng build grün · Doku-Konsistenz-Check grün · Migration manuell gegen node:sqlite verifiziert. |
| MED-D-142 | 2026-07-15 | Sicherheit/Betrieb (R7/R5) | MED-OP-AUTH-2 (By-ID-Mandant-Scope-Lücke) + MED-OP-WV-2 (fehlender DB-Unique-Constraint) gehärtet — beide CodeRabbit-#108-Befunde (Major). Nutzerfrage "Wie können wir Mandant-Scope-Sicherheitslücke, fehlender DB-Unique-Constraint angehen" → Recherche im Code + Plan vorgelegt (inkl. einer Abweichung von der HANDOFF-Notiz: Composite-Index (quelle, quelle_ref) vs. Single-Column quelle_ref — letzteres passend zum tatsächlichen App-Level-Lookup, der quelle ignoriert) → Nutzer bestätigte "trotzdem mit handling; beide OPs in einem PR umsetzen". MED-OP-AUTH-2: Root Cause war, dass Meeting/Beratungsdoku/Individualdokument eigene Top-Level-:id-Routen haben (PATCH /api/meetings/:id + …/aufgaben*, beratungsdoku/:id, individualdokumente/:id), die den bestehenden Chokepoint (mandantScopeGuard auf /api/mandanten/:id*) nie durchlaufen. Neuer geteilter byIdMandantScopeGuard(ladeMandantId, nichtGefunden) in server/src/api/app.ts: löst Entität→mandantId auf, prüft service.darfSehen() (automatisch an denselben rbac_mandant_scope_aktiv-Flag gebunden), 404 bei "nicht sichtbar" (kein Existenz-Leak, konsistent zu Chokepoint B), 403 bei Mutation ohne mandant_bearbeiten; existiert die Entität nicht → next(), der Handler liefert seine übliche entitätsspezifische Meldung. Auf allen drei Entitäten angewandt (/api/meetings/:id*, /api/beratungsdoku/:id*, /api/individualdokumente/:id*). MED-OP-WV-2: Migration v39 (server/src/db/migrate.ts) — CREATE UNIQUE INDEX IF NOT EXISTS idx_wiedervorlage_quelle_ref ON wiedervorlage (quelle_ref); bewusst Single-Column statt Composite (Begründung oben). createWiedervorlage in d1-repo.ts fängt die Constraint-Verletzung ab (istUniqueConstraintFehler-Helfer, prüft Fehlertext auf UNIQUE constraint failed + Spaltenname, da D1/SQLite keinen typisierten Fehler liefert) und liefert die bereits vorhandene Zeile statt zu werfen — echtes Duplicate-Key-Handling, nicht nur der Index als Backstop. memory-repo.ts spiegelt dasselbe Verhalten (Check-vor-Insert statt Exception-Fang, da keine echte DB-Constraint), damit Tests ohne echtes D1 auskommen. 4 neue Tests (3× RBAC-Scope für die drei Entitäten in rbac.test.ts, 1× Idempotenz-Race-Simulation in wiedervorlage.test.ts) — jeder Test vor dem Commit gegen den ungefixten Stand verifiziert (Guard-Code temporär entfernt/Memory-Repo-Fix temporär zurückgesetzt → alle 4 schlagen exakt mit dem erwarteten Vorher-Fehler fehl, dann Fix wiederhergestellt → grün). 442→446 Vitest, tsc + ng build unverändert grün, Doku-Konsistenz-Check grün. | Beide Befunde waren CodeRabbit-Major-Findings aus PR #108, bislang als "heute unkritisch" (RBAC-Scope-Flag default aus · D1 single-writer) zurückgestellt — die Härtung schließt sie, bevor der Flag je scharfgeschaltet wird oder ein echter Race auftritt, statt reaktiv zu warten. Die Single-Column-vs-Composite-Entscheidung bei MED-OP-WV-2 ist der wichtigste fachliche Fund dieser Runde: die HANDOFF-Notiz beschrieb einen Composite-Index, aber der tatsächliche Code (getWiedervorlageByQuelle) dedupliziert nur über quelle_ref — ein Composite-Index hätte also weniger geschützt, als die App-Logik bereits voraussetzt; dieselbe Disziplin, nicht blind der Notiz zu folgen, sondern den Code zu verifizieren, wie sie diese Session bereits bei den Decision-Log-ID-Kollisionen (MED-D-139) und dem Check-Blind-Spot (MED-D-141) angewendet hat. Das explizite Vorher/Nachher-Verifizieren aller 4 neuen Tests gegen den ungefixten Stand (statt sich auf "Test ist grün" zu verlassen) ist bei einem Sicherheits-Fix besonders wichtig — ein Test, der auch ohne den Fix grün wäre, hätte nichts bewiesen. | gebaut (0.78.3 → 0.78.4, PATCH) · server/src/api/app.ts (neuer Guard + 3 Mount-Punkte) · server/src/db/migrate.ts (Migration v39) · server/src/repo/d1-repo.ts + memory-repo.ts (Duplicate-Key-Handling) · +4 Vitest (rbac.test.ts, wiedervorlage.test.ts) · 446 Vitest + tsc + ng build grün · Doku-Konsistenz-Check grün. |
| MED-D-141 | 2026-07-15 | Doku/Way-of-Working | HANDOFF §4: veraltete MED-OP-DOKU-3-Restzeile entfernt + Check-Blind-Spot geschlossen. Auf Nutzerfrage "In welchen Kategorien liegen die offenen OP?" beim Kategorisieren aller offenen OP-/MED-OP--Punkte (Lastenheft §11 + HANDOFF §4) aufgefallen: MED-OP-DOKU-3 stand zweimal in §4 — einmal als noch offene Zeile (identischer Titel "Doku-Welle 3 — "Check schärfen + Zielgruppen komplettieren"", identische Befund-Referenz B8/B11–B15/B19), einmal als bereits ✅ archivierte Zeile (MED-D-113) mit vollem Umsetzungs-Detail + explizitem Verweis auf den ausgelagerten Rest (→ MED-OP-DOKU-4). Die offene Zeile war ein Merge-Rückstand: beim Anhängen der Erledigt-Zeile wurde die alte, jetzt gegenstandslose Zeile nicht entfernt. Nutzer bestätigte "Ja" auf die vorgeschlagene Bereinigung. Behoben: Zeile entfernt (kein Informationsverlust — die archivierte Zeile trägt bereits jedes Detail inkl. Restpunkt-Verweis). Zusätzlich (Root-Cause-Fix, nicht nur Symptom): scripts/check-doc-consistency.sh §6 hatte hierfür einen blinden Fleck — die bestehende Dublette-Prüfung vergleicht nur aktive Zeilen gegeneinander (uniq -d), erkennt aber nicht den Fall "eine ID ist zugleich aktiv UND bereits archiviert" (hier: 1 aktive + 1 archivierte Zeile, kein Duplikat unter aktiven Zeilen). Neuer Check 6b ergänzt: Schnittmenge aktiver vs. archivierter IDs. Bei der ersten Implementierung ein echter False Positive gefunden und selbst korrigiert, bevor committet wurde: OP-LEAD-1 erschien ebenfalls aktiv + archiviert, aber die archivierte Zeile ist bewusst als ~~OP-LEAD-1 (Original)~~ (kein Bold, Zusatz "(Original)") erhaltener Ursprungskontext, kein echtes Duplikat — die aktive Zeile hat legitim eigenen offenen Rest. Check-Regex verschärft: verlangt jetzt das kanonische ~~**ID**~~-Bold-Muster direkt am ID-Ende für "archiviert", statt nur optionales \** — schließt annotierte Kontext-Zeilen wie (Original) korrekt aus. Verifiziert per synthetischem Vorher/Nachher-Test (künstliche Dublette eingefügt → erkannt; wieder entfernt → grün) und bestätigt, dass OP-LEAD-1 nach der Regex-Verschärfung keinen Fehlalarm mehr auslöst. | Der reine Zeilen-Fix allein hätte die dritte Wiederkehr derselben Drift-Art nicht verhindert — genau das Muster, das B18/B19/B23 in den vorangegangenen Doku-Audits wiederholt als Wurzelursache benannten ("Symptom beheben reicht nicht, der Check muss die Wiederkehr verhindern"). Der selbst gefundene False Positive (OP-LEAD-1) ist der wichtigste Teil dieser Änderung: er zeigt, dass ein naiver Aktiv-vs-Archiviert-Vergleich ohne das Bold-Kriterium sofort ungenau geworden wäre — genau die Art "ungetesteter Regex-Fix erzeugt neuen Fehlalarm", die MED-D-133 bereits einmal als Lehre dokumentierte; hier wurde sie präventiv vor dem Commit gefunden statt erst in einem späteren Review. Reine Doku-/Skript-Pflege ohne Code-/Schema-/Feature-Bezug — keine Versionsänderung, analog MED-D-139/140. | keine Versionsänderung (APP_VERSION unverändert 0.78.3) · HANDOFF.md (1 Zeile entfernt) + scripts/check-doc-consistency.sh (neuer Check 6b) · kein Code-/Schema-Change · check-doc-consistency.sh grün (0 Hinweise, synthetischer Test bestätigt Erkennung + 0 False Positives) · 442 Vitest + tsc + ng build unverändert grün. |
| MED-D-140 | 2026-07-14 | Doku/Way-of-Working | CLAUDE.md §Versionierung-Absatz restrukturiert — löst die seit MED-D-131 offene CodeRabbit-Frage. Auf explizite Nutzerfrage "Claude §versionierung" die von CodeRabbit auf PR #171/172 aufgeworfene, damals dem Nutzer vorgelegte Frage per AskUserQuestion erneut zur Entscheidung gestellt: den laufend wachsenden §Versionierung-Absatz (jede der letzten ~15 PRs hängte einen weiteren Satz Feature-Historie an — trotz eines bereits vorhandenen Disclaimers "dieser Absatz hält bewusst nur den Stand, keine Log-Kopie" faktisch eine wachsende Log-Kopie) so belassen, oder auf 1–2 Sätze Ist-Stand kürzen und die Historie auslagern. Nutzer wählte "Trim to current-state only" (die empfohlene Option). Umsetzung: CLAUDE.md §Versionierung — der ~28-zeilige Absatz (Slice-für-Slice-/MED-D-für-MED-D-Aufzählung seit 0.72.0) ersetzt durch 6 Zeilen: Version + ein knapper Ist-Stand-Satz (Module R1–R13, Beratungsaufträge, Dentmarking, live in Produktion) + 1.0.0-Bedingung (echte Integrations-Adapter) + expliziter Verweis "volle Historie → CHANGELOG.md · Feature-Stand → Feature-Liste.md · Detail-Fortschritt → HANDOFF.md §2/§4/§5". Kein Informationsverlust: jede der ausgelagerten Aussagen stand bereits mehrfach redundant in CHANGELOG.md/HANDOFF.md §2 (die CLAUDE.md-Fassung war die dritte Kopie derselben Fakten). HANDOFF.md §2/§4 (MED-OP-DOKU-6-/MED-OP-REVIEW-1-Zeilen)/§5 entsprechend nachgezogen — die dort verbliebenen Verweise auf "CLAUDE.md-§Versionierung-Restrukturierung (offene Nutzer-Entscheidung)" als erledigt markiert statt gelöscht (Audit-Trail-Transparenz: die Entscheidung IST jetzt getroffen, nicht mehr offen). | Ein Absatz, der behauptet "keine Log-Kopie" zu sein, aber bei jeder PR eine weitere Feature-Beschreibung ansammelt, ist genau die Art Selbstwiderspruch, die die Doku-Reviews wiederholt als Drift-Muster diagnostiziert haben (B18/B21) — hier allerdings nicht durch Vernachlässigung, sondern durch eine zu locker gefasste Konvention, die genau das erlaubte, was sie verbot. Die Entscheidung war bewusst dem Nutzer vorgelegt (nicht einseitig entschieden), weil sie den gesamten künftigen PR-Rhythmus betrifft (jede zukünftige PR muss diesen Absatz jetzt NICHT mehr erweitern) — eine Way-of-Working-Frage mit projektweiter Tragweite, kein lokaler Wortlaut-Fix. Kein Informationsverlust, weil CHANGELOG.md bereits explizit als "einzige Log-Quelle" deklariert war (dieser PR macht diese Erklärung endlich wahr, statt sie nur zu behaupten). Reine Governance-/Doku-Restrukturierung ohne Code-/Schema-/Feature-Bezug — keine Versionsänderung, analog MED-D-127 (Instruktions-Scoping-Regel) und MED-D-139 (beide reine CLAUDE.md-/Decision-Log-Pflege ohne SemVer-Bump). | keine Versionsänderung (APP_VERSION unverändert 0.78.3) · nur CLAUDE.md + HANDOFF.md (§2/§4/§5) · kein Code-/Schema-Change · check-doc-consistency.sh grün (Stand-Stempel 0.78.3 unverändert konsistent) · 442 Vitest + tsc + ng build unverändert grün. |
| MED-D-139 | 2026-07-14 | Doku/Way-of-Working | ID-Kollisionen im Decision-Log bereinigt — vier IDs (MED-D-130/131/132/133) waren je doppelt vergeben. Nutzerfrage "Was ist MED-D-131?" deckte auf: neben dem bekannten, dem Nutzer im Chat vorgelegten MED-D-131 (CodeRabbit-Nachlese zu MED-D-130, 2026-07-14) existierte im Log bereits ein anderer MED-D-131 (Self-Hosted-Runner-Fallback-Label hot→desktop, 2026-07-13) — Stichprobe ergab drei weitere, identische Kollisionen: MED-D-130 (Architektur-Uebersicht.md/SBOM vs. World-2-Rollout Schritt 3), MED-D-132 (CI-Runner-Revert vs. Doku-Review-Re-Audit) und MED-D-133 (actions/checkout clean:false vs. Doku-Welle 4a+4b). Ursache: zwei parallele Arbeits-Stränge desselben Tages (ein CI/Infra-Vereinheitlichungs-Batch 07-13, repo-übergreifend mit sera/taktano/Template geteilt; die UX-Welle-8/Doku-Welle-4-Serie 07-14) vergaben unabhängig voneinander fortlaufende IDs, ohne die jeweils andere Reihe zu prüfen — genau die Art Koordinations-Lücke, die das ID-System (agents.md §3) eigentlich verhindern soll. Auflösung nach Referenz-Umfang statt Chronologie: die vier UX-Welle-8/Doku-Welle-4-Einträge sind in HANDOFF.md (mehrfach, inkl. §2/§4/§5), CHANGELOG.md, docs/betrieb/Timesheet.md, CLAUDE.mds Versionierungs-Absatz, docs/konventionen/agents.md und docs/betrieb/UX-Prozess-Review-2026-07.md breit verankert — eine Umnummerierung hätte Dutzende Fundstellen berührt; die vier CI-Infra-Einträge hatten außerhalb des Decision-Log je nur eine Referenz (in CHANGELOG.md). Daher: CI-Infra-Paar umnummeriert — MED-D-130→MED-D-135 (SBOM/Architektur-Uebersicht), MED-D-131→MED-D-136 (Runner-Label-Umbenennung), MED-D-132→MED-D-137 (Runner-Revert), MED-D-133→MED-D-138 (checkout clean:false); die vier Doku-/UX-Welle-Einträge behalten ihre bekannten Nummern 130–133 unverändert. CHANGELOG.md (4 betroffene Zeilen) entsprechend nachgezogen. | Ein Decision-Log, dessen IDs nicht eindeutig sind, verletzt sein eigenes Zweck-Versprechen (agents.md §3: "D-n — Chronologische Entscheidung") und G-2 (Single Source of Truth — zwei Entscheidungen unter derselben ID sind nicht mehr eindeutig auflösbar). Die Wahl "Referenz-Umfang statt Chronologie" (nicht: älterer Eintrag behält die Nummer) ist bewusst pragmatisch: eine Neunummerierung der breiter verankerten Serie hätte Fundstellen in bereits gemergten, teils extern zitierten Docs verändert (u. a. CLAUDE.mds eigener, laufend fortgeschriebener Versionierungs-Absatz) — ein deutlich größerer, fehleranfälligerer Eingriff für denselben Nutzen. Reine Buchführungs-Korrektur ohne Code-/Schema-/Feature-Bezug — kein Fix-PR im Sinne von G-1..G-8, daher keine Versionsänderung, analog MED-D-107/MED-D-132 ("Audit-Dokument selbst kein Feature/Fix"). Nur diese vier Zeilen wurden angefasst; alle anderen Decision-Log-Einträge (inkl. der bereits zweimal korrekt umnummerierten MED-D-131→MED-D-134- und MED-D-129-Fälle aus demselben CI-Batch) bleiben unverändert. | keine Versionsänderung (APP_VERSION unverändert 0.78.3) · nur docs/betrieb/Decision-Log.md (4 ID-Relabel + dieser Eintrag) + CHANGELOG.md (4 Zeilen) · kein Code-/Schema-Change · 442 Vitest + tsc + ng build unverändert grün. |
| MED-D-134 | 2026-07-14 | Doku-Welle 4 · MED-OP-DOKU-6 | Doku-Welle 4c+4d umgesetzt — Re-Audit-Befunde B24–B28/B31/B32/B12f/B14/B15/B17 behoben. Setzt den Rest des in MED-D-132 vorgelegten Maßnahmenplans um (Nutzer "Next" nach MED-D-133). 4c Governance-Aktualität: docs/betrieb/Risikoregister.md — alle 28 Risiko-Zeilen einzeln gegen den aktuellen Code-/Doku-Stand gegengelesen (nicht blind gestempelt), "Letzte Prüfung" auf 2026-07-14 gebracht (B32); docs/betrieb/Compliance.md — Compliance-Tracker (9 Zeilen) gegengelesen, "Stand: 2026-06-27 (Repo-Init)" auf "Stand: 2026-07-14 (regelmäßige Prüfung)" korrigiert — der Kopf-Stempel widersprach dem bereits Slice-10/11-aktuellen Tabelleninhalt (B31). docs/architektur/Weltmodell-Data-Dictionary.md — Beratungsauftrag als G-8-Entität in die Entitäten-Tabelle aufgenommen (Verweis auf Beratungsauftraege.md), fehlte trotz eigener ID/Lebenszyklus komplett (B25). docs/konventionen/agents.md §3 (laut §5.4-Governance-Tabelle die kanonische ID-System-Quelle) — um D-n/RISK-n/KB-n ergänzt; diese drei Präfixe waren live im Einsatz (134/28/8 Fundstellen), aber ausgerechnet in der als maßgeblich deklarierten Quelle nicht gelistet, während eine bloße "Kurzform"-Ableitung (Entwicklungsansatz.md) sie schon führte — eine ungewöhnliche Drift-Richtung (B26). docs/README.md — Index-Zeile um Architektur-Uebersicht.md ergänzt (fehlte trotz CLAUDE.md-"verbindlich"-Markierung komplett) + Beratungsauftraege.md-Zeile "Geldanlage"→"Kapitalanlage" korrigiert (Migration v37 nicht nachgezogen). docs/zielgruppen/Lesepfade.md — Beratungsauftraege.md in die Pfade IT-Architektur und Customer Service verlinkt (Customer Service beantwortet True-North-Frage 1 jetzt je Auftrag, nicht mehr nur je Person), Architektur-Uebersicht.md in IT-Architektur (B27/B28). docs/konventionen/agents.md — toter "Letztes Update: 27.06.2026"-Stempel auf 2026-07-14 mit Änderungs-Kurzfassung gebracht, Repo-Init-Kontext als historische Fußnote erhalten (B12f). 4d Handwerk-Restschulden: docs/spezialtools/Dexman.md — §1 "Wettbewerbsanalyse" und §2 "Zweck & Leitfragen" getauscht (Zweck jetzt zuerst, pyramidal — Wettbewerbsanalyse ist Beleg/Kontext, nicht die Kernaussage), keine internen §1/§2-Querverweise betroffen (geprüft) (B14). docs/architektur/Unterschriften.md + docs/architektur/Dokumentenverwaltung-NextCloud.md — je ein Sequenzdiagramm-Participant von NextCloud auf Ablage (R2/NextCloud) umbenannt, konsistent mit der bereits in denselben Docs korrigierten Prosa (B6-Fix hatte die Diagramme übersehen); ER-Diagramm-Feld nextcloud_ref bewusst unverändert gelassen (Feldname konnte im aktuellen Server-Schema nicht verifiziert werden, Umbenennung wäre ein Code-Claim ohne Beleg) (B15). HANDOFF.md §4 — OP-DEX-Nummerierung vereinheitlicht (OP-DEX-1..5 → OP-DEX-1..9, die kürzere Fassung war ein veraltetes Shorthand neben der bereits korrekten OP-DEX-1..9-Zeile). docs/konventionen/Entwicklungsansatz.md §4.3 — expliziter Verweis "Detail: agents.md §7" ergänzt (kanonische Quelle laut §5.4), Kurzfassung selbst nicht gekürzt (dient als lesbare Übersicht, die eigene Rolle laut CLAUDE.md) (B17). Bewusst nicht umgesetzt: CLAUDE.md-§Versionierung-Restrukturierung — hängt an derselben, seit MED-D-131 offenen Nutzer-Entscheidung (Way-of-Working-Frage, keine lokale Korrektur). | Governance-Docs (Compliance/Risikoregister), die CLAUDE.md selbst als "regelmäßig zu Session-/PR-Beginn zu prüfen" vorschreibt, waren seit Repo-Init praktisch ungeprüft geblieben — genau die Art Drift, die G-4/G-5 verhindern sollen; eine echte Zeile-für-Zeile-Prüfung (statt Stempel-Only) ist hier bewusst gewählt, weil ein reiner Datums-Bump ohne Inhaltsprüfung dieselbe Selbstgefälligkeit wäre, die B18/B21 in den Doku-Reviews wiederholt gefunden haben. Der agents.md-§3-Fund (B26) ist besonders lehrreich: die als "kanonisch" deklarierte Quelle war unvollständiger als eine ihrer eigenen Kurzfassungen — ein Beleg, dass "eine Definition, ein Ort" (MED-D-110) nur hilft, wenn der eine Ort auch tatsächlich vollständig ist. Das ER-Diagramm-Feld nextcloud_ref bewusst unangetastet zu lassen (statt es "vorsichtshalber" umzubenennen) folgt derselben Disziplin, die dieser ganzen Doku-Welle zugrunde liegt: nur behaupten, was tatsächlich verifiziert wurde. Mit diesem PR sind alle 32 Befunde (B1–B32) aus MED-D-132 sowie alle 19 Alt-Befunde aus dem vorangegangenen Audit bearbeitet — bis auf die eine bewusst offene, dem Nutzer vorgelegte CLAUDE.md-Frage. | gebaut (0.78.2 → 0.78.3, PATCH) · nur Doku (10 Dateien), kein Code-/Schema-Change · 442 Vitest + tsc + ng build unverändert grün · Doku-Konsistenz-Check grün. |
| MED-D-151 | 2026-07-19 | Architektur/Prozessmodell (R1/MED-D-95) | PROZESS_PHASE retiriert — LIFECYCLE_STATUS (grob) + AUFTRAG_STATUS (fein) statt einer sechsten, kollidierenden Achse. Ausgangsfrage war nur eine Umbenennung (onboarding→vorbereitung, Namenskollision mit LIFECYCLE_STATUS), aber die Prüfung ergab: Mandant.prozessphase (erstkontakt·onboarding·beratung·unterschrift·betreuung·archiviert) ist strukturell ein Relikt — seine feine Granularität deckt Beratungsauftrag.status (anbahnung·beratung·unterschrift·laufend·abgeschlossen, MED-D-95) bereits ab, nur eben pro Auftrag statt pro Person. Auf Nutzer-Rückfrage "Es gibt separate Phasenmodelle für (1) Mandanten und (2) Beratungsmandate — korrekt?" (bestätigt) legte der Nutzer das finale Mapping fest: erstkontakt→lead, onboarding/beratung/unterschrift→onboarding, betreuung→aktiv — kein neues DB-Feld nötig, beide Ziel-Enums existierten bereits. Löst zugleich MED-D-95s dokumentiertes Mehrfach-Auftrag-Problem (eine Person mit mehreren Beratungsprodukten in unterschiedlichen Stadien konnte eine einzelne Prozessphase nie abbilden). Domain: neue domain/lifecycle.ts (ersetzt phasen.ts) mit LIFECYCLE_SPINE=['lead','onboarding','aktiv'] (Ruhend/Archiviert bleiben frei erreichbare Verwaltungszustände ohne Ordinal) und dem ersten Guard auf lifecycleStatus-Übergänge (pruefeLifecycleUebergang: Eintritt in aktiv verlangt onboardingVollstaendig && unterschriftenOffen===0 — fasst die zwei alten Phasen-Engine-Guards onboarding→beratung/unterschrift→betreuung zu einem zusammen; PATCH /api/mandanten/:id kann jetzt 409 liefern, ein reales Verhaltens-Update). Mandanten-Playbook auf 2 Einträge reduziert (nachfassen@onboarding-Eintritt, jahrescheck@aktiv-Eintritt); die zwei verwaisten Einträge (termin/ruecklauf) leben als neuer Code-Katalog AUFTRAG_STATUS_PLAYBOOK am Beratungsauftrag (Nutzerentscheidung: Code-Katalog statt admin-editierbar, kleinere Fläche), feuern neu auf Auftrags-Statuswechsel (beratungsauftrag-service.ts#statusSetzen(), vorher nur auf Anlage). aktenreife.ts/naechste-schritte.ts von phase/jePhase auf stufe/jeStufe umgestellt, laufen nur noch über die 3-wertige Spine. DB: db/migrate.ts v40 (Mandant-Reconcile per Mapping-UPDATEs + ALTER TABLE mandant DROP COLUMN prozessphase, monoton vorwärts — regressiert nie einen bereits fortgeschritteneren oder administrativ gesetzten Status; archiviert bewusst nicht automatisch übernommen) + v41 (Playbook-Tabelle remappen: betreuung→aktiv-Zeile umbenannt, beratung/unterschrift-Zeilen per aktiv=0 deaktiviert statt gelöscht, G-4-Audit-Historie bleibt erhalten). Historische DDL-Schritte (v12/v13) unverändert (append-only Migrationskonvention). Client: MandantCockpit.prozessphase → auftragStatusZusammenfassung: Partial<Record<AuftragStatus,number>> (Nutzerentscheidung: sofort mit Auftrag-Status-Chips je Cockpit-Karte statt nur grober Lane-Reduktion — löst die Mehrfach-Auftrag-Schwäche direkt in dieser Änderung); Cockpit-Leitstand-Lanes jetzt Lead·Onboarding·Aktiv·Ruhend (Archiviert ausgeblendet), löst zugleich die alte, unschöne Doppel-Achsen-Mischung in phaseOf() auf (vorher: Lifecycle für Ruhend/Archiviert, Prozessphase für den Rest). mandant-detail.component.ts/mandant-akte.component.ts verlieren das zweite Prozessphase-Select (Mandats-Status ist jetzt die EINE Kontroll-Stelle, Guard-Fehler per Toast/Inline-Fehlertext sichtbar); die vormals eigenen Register „Beratung"/„Unterschrift" falten in „Beratungsaufträge" (das die feine Ebene bereits pro Auftrag zeigt), „Betreuung" wird zu „Wiedervorlagen" (Stufe aktiv, sprechenderer Name, G-3). Verifikation: manuelles node:sqlite-Skript (Drift-Matrix inkl. ruhend-Nicht-Regression, temporärer SCHRITTE-Export nur für den Testlauf, danach zurückgesetzt) und wrangler dev gegen die reale, aus vielen Vorsessions gewachsene lokale D1 — beide bestätigen dieselbe Reconciliation. Vier Browser-Szenarien per Playwright/Screenshot bestätigt: Solo-Mandant ohne Auftrag erreicht aktiv inkl. jahrescheck-Wiedervorlage; Guard blockt bei unvollständigem Onboarding (409 + Grund im UI); Guard blockt bei offener Unterschrift, entsperrt nach Abgleich; ein Mandant mit zwei Beratungsaufträgen in unterschiedlichem Status (beratung+unterschrift) erreicht unabhängig davon aktiv, Cockpit zeigt die kombinierte Chip-Zusammenfassung ("2 Aufträge · 1 Beratung · 1 Unterschrift"). +2 Vitest (Status-Playbook-Idempotenz + Fehler-Isolation, 488→490, 46 Dateien). | Das Mapping macht die zwei Achsen endlich orthogonal, statt eine sechswertige, teils redundante dritte Achse zu pflegen — genau die Art strukturelles Relikt, die eine reine Umbenennung nur kosmetisch kaschiert hätte. Der einzige neue Guard war der bewusst schwierigste Teil: zwei bestehende, an unterschiedlichen alten Phasenübergängen hängende Bedingungen mussten korrekt auf EINEN zusammengefassten Übergang (onboarding→aktiv, der jetzt zwei frühere Zwischenstufen überspringt) verschoben werden, ohne eine der beiden fachlichen Anforderungen (Onboarding vollständig, keine offenen Unterschriften) zu verlieren — beide Fakten bleiben personenweite, unauftragsgefilterte Berechnungen wie zuvor, nur der Auslösepunkt änderte sich. Dass lifecycleStatus bislang komplett ungeguarded war, wurde vor der Umsetzung explizit verifiziert (nicht angenommen) — sonst hätte der neue Guard eine bestehende, stillschweigend genutzte Freiheit ohne Vorwarnung entzogen. Migrationssicherheit wurde bewusst doppelt geprüft (synthetische Drift-Matrix und reale, organisch gewachsene Vorsessions-Daten) statt nur eine Quelle zu vertrauen — die reale D1 bestätigte insbesondere, dass administrativ gesetzte ruhend/archiviert-Zustände durch die Migration nicht regressieren, der einzige irreversible Fehlerfall dieser Änderung. | gebaut (0.82.0 → 0.83.0, MINOR) · server/src/domain/{enums,lifecycle,auftrag-playbook,aktenreife,naechste-schritte,model}.ts (phasen.ts gelöscht) · server/src/api/{service,beratungsauftrag-service,app}.ts · server/src/repo/{repo,memory-repo,d1-repo}.ts · server/src/db/{schema,migrate}.ts (v40/v41) · server/src/domain/lifecycle.test.ts (neu, ersetzt phasen.test.ts) + aktenreife.test.ts/naechste-schritte.test.ts/stammdaten-uebernahme.test.ts/app.test.ts/audit.test.ts/beratungsauftrag.test.ts angepasst/erweitert · client/src/app/{api.service,labels,mandant-detail.component,mandant-akte.component,cockpit.component,verwaltung.component}.ts · 490 Vitest (488→490, 46 Dateien) + tsc + ng build grün · Doku-Konsistenz-Check grün · 4 Browser-Szenarien gegen echten wrangler dev + Playwright verifiziert (Screenshots gesichert). |
| MED-D-152 | 2026-07-19 | Sicherheit/Betrieb · Doku (CodeRabbit-Nachlese zu MED-D-151) | CodeRabbit-Nachlese zu MED-D-151 (PR #192): 12 von 14 Befunden echt, nachgezogen. PR #192 mergte per Auto-Merge, bevor CodeRabbits Review eintraf (Draft-Skip-Timing, bekanntes Muster seit MED-D-131/141/143/148) — alle Befunde gegen den bereits gemergten Code verifiziert statt reflexhaft übernommen. Echt, behoben (12): (1, Major, Code) service.ts#aktualisieren(): die Lifecycle-Playbook-Erzeugung (listPlaybookByPhase/getWiedervorlageByQuelle/createWiedervorlage) lief ungeschützt vor den audit.record-Aufrufen — ein Repo-Fehler dort ließ den bereits persistierten Lifecycle-Wechsel als nicht auditiertes 500 zurück, ein direkter Verstoß gegen das im selben Code kommentierte G-4-"lückenlos"-Ziel und inkonsistent zum bereits in beratungsauftrag-service.ts etablierten Best-effort-Muster. Mit try/catch isoliert (analog erzeugePlaybook/erzeugeStatusPlaybook), Fehler PII-arm als neues mandant.playbook_fehler-Event auditiert (Label ergänzt); Regressionstest vorab gegen den ungefixten Stand verifiziert (schlägt mit 500 fehl, mit Fix 200 + beide Audit-Events vorhanden). (2–12, Doku, alle Path-Instructions-Funde): CLAUDE.md/Beratungsauftraege.md-Terminologie-Konflikt (Zeile nannte fälschlich drei Achsen statt zwei — Onboarding-Teilschritt ist ein Detail innerhalb onboarding, keine eigene Achse) klargestellt; Prozessmodell.md: MD028-Leerzeile in Blockquote, eine typografische Anführungszeichen-Abweichung, "Umbau P2" widersprach dem bereits ✅ gebauten P2 im Fahrplan (klargestellt), "Wiedervorlagen" fälschlich als Lifecycle-Stufe gelistet (jetzt als eigenes Register neben den 3 echten Stufen), auftragStatus durch das kanonische Beratungsauftrag.status ersetzt; Test-Uebersicht.md: eine typografische Anführungszeichen-Abweichung + eine nie geschlossene äußere Klammer im Intro-Absatz; Feature-Liste.md: dieselbe Wiedervorlagen-als-Stufe-Ungenauigkeit; Management-Summary.md/MVP-Scope.md: Fließtext-Körper hinkte dem bereits aktualisierten Kopf-Stempel hinterher (484→490 Tests, C2a→C2b, 0.82.0→0.83.0 an mehreren Stellen) — beim ursprünglichen sed-Versions-Sync nur die "Stand"/"Status"-Zeile getroffen, nicht den restlichen Fließtext. Zusätzlich, im eigenen Nachlese-Audit gefunden (nicht von CodeRabbit gemeldet, gleicher Root Cause): docs/fachlich/Lastenheft.md — die fachliche Master-Spezifikation trug in §5.1/§5.1a/§5.2 sowie der R2-F04-Tabellenzeile und der OP-ABC-1-Zeile noch den vollständigen, mehrere Absätze langen alten prozessphase-Sechs-Zustands-Diskurs (Diagramm, "DIE fachliche Phase = Mandant.prozessphase", POST /api/mandanten/:id/phase-Route-Beschreibung) — vollständig auf das neue Zwei-Achsen-Modell umgeschrieben (Lifecycle-Diagramm analog Prozessmodell.md §3, Playbook-/Guard-Beschreibung aktualisiert); docs/betrieb/Sanity-Checkliste.md — drei Prüfpunkt-Zellen (True-North-Fragen 1–3) beschrieben noch "Lifecycle + Phase getrennt"/"Aktenreife je Phase" statt des neuen Modells. Bewusst nicht übernommen (1): CHANGELOG-PR-Link statt Branch-Name — bereits in MED-D-144 explizit geprüft und als etablierte Repo-Konvention für Einträge vor bekannter PR-Nummer verworfen, kein neuer Grund für eine andere Entscheidung. | Der Code-Fund (1) ist der wichtigste: die genau in diesem PR (MED-D-151) selbst formulierte G-4-Anforderung ("lückenlos") wurde im selben PR an einer Stelle verletzt, die die parallele, korrekt best-effort gebaute beratungsauftrag-service.ts-Variante als Gegenbeispiel direkt daneben hatte — ein Beleg dafür, dass dieselbe Sitzung dasselbe Muster nicht automatisch überall konsistent anwendet, wenn es nicht mechanisch erzwungen wird; der Vorher/Nachher-Testbeweis (500 → 200) folgt derselben Disziplin wie bei MED-D-142/143. Die Doku-Funde zeigen erneut das aus mehreren früheren Audits (B18/B21/B23) bekannte Muster: ein breiter Stand-Stempel-sed-Sync trifft nur die eine erwartete Zeile (Kopf-"Stand"), während der restliche Fließtext (Lastenheft §5, Sanity-Checkliste-Zellen, Management-Summary/MVP-Scope-Körper) unberührt bleibt — hier wurde das eigene Audit bewusst über die von CodeRabbit gemeldeten Dateien hinaus auf die als "verbindliche Master-Spec" deklarierte Lastenheft.md ausgeweitet, weil eine Retirierung dieser Größenordnung dort naturgemäß am stärksten verankert war. | 0.83.0 unverändert (keine Versionsänderung — reine Fehlerbehandlung/Doku-Nachzug innerhalb des soeben gemergten Features, analog MED-D-148) · server/src/api/service.ts (aktualisieren() Playbook-try/catch) · server/src/api/app.test.ts (+1 Regressionstest) · client/src/app/labels.ts (mandant.playbook_fehler-Label) · CLAUDE.md · docs/architektur/Prozessmodell.md · docs/fachlich/{Lastenheft,MVP-Scope,Feature-Liste}.md · docs/betrieb/{Sanity-Checkliste,Test-Uebersicht}.md · docs/produkt/Management-Summary.md · 491 Vitest (490→491, 46 Dateien), tsc + ng build grün, Doku-Konsistenz-Check grün. |
| MED-D-153 | 2026-07-19 | App-UX-Audit · MED-OP-REVIEW-1 | App-UX-Audit auf v0.83.0 aufgefrischt (docs/betrieb/UX-Prozess-Review-2026-07.md, in-place überschrieben — Vorgänger-Bezugspunkt v0.72.0 war 11 Minor-Versionen alt, über der Stale-Schwelle aus agents.md §6.7). Fünf parallele Dimensions-Reviews (Feedback-Verlässlichkeit · Sprache G-3/G-8 · Kundenstrecken · Design/Mobile/A11y · neu: Eine Handschrift/Konsistenz, eigene Dimension diese Runde wegen des Umfangs der Welle-8/World-2-Konsolidierung seit dem letzten Audit) plus Live-Begehung (wrangler dev + Playwright, Desktop 1440px + Mobil 390px, Testakten "Mustermann Dr. Max" [16 Beratungsaufträge, gezielt als Chip-Overflow-Stresstest gewählt] und "MED-D-1xx Test C (Multi-Auftrag)"). Ergebnis: alle carry-over Befunde B1–B4/B6/B7 aus v0.72.0 verifizieren als weiterhin behoben oder unverändert bestehend — keine Regression durch den MED-D-151-Zwei-Achsen-Umbau, obwohl dieser praktisch jede vorher gehärtete Fläche (Cockpit/Mandant-Detail/Akte/Verwaltung) neu anfasste. Zwei neue, genuine Befunde direkt aus dem Umbau: Cockpit-Chip-Overflow (die neue auftragChips-Zusammenfassung je Lane-Kopf hat keine Ellipsis/Truncation, live per DOM-Messung bestätigt: rowScrollWidth=190px > rowClientWidth=180px) und PHASE_LABEL-Dopplung (cockpit.component.ts reimplementiert LIFECYCLE_LABEL lokal und weicht dabei ab — aktiv:'Aktiv' vs. kanonisch 'Aktiv (betreut)', ein echter G-8-Verstoß). Dazu: der Lifecycle-Guard-Undo-Pfad (lifecycleZuruecksetzen()) hat keinen error:-Handler (True-North-#2-Risiko, Schwesterstelle zum korrekt gehärteten Hauptpfad lifecycleSetzen()), Playbook-Fehlschläge (seit MED-D-152 korrekt auditiert) haben weiterhin kein UI-Signal, plus drei Kleinbefunde. Neuer Backlog B8–B13 → Sammel-OP MED-OP-UX-8 (Welle 9). Bewusst keine Versionsänderung (reiner Audit, analog MED-D-107/132), kein Code-Fix in dieser Runde (Fixes sind Welle 9, analog wie v0.72.0s Audit-PR selbst auch keine Fixes enthielt). | Stale-Regel agents.md §6.7 (≥10 Minor-Versionen); Nutzerauftrag "Fang mit dem Audit-Refresh an". | docs/betrieb/UX-Prozess-Review-2026-07.md, HANDOFF.md §2/§4/§5, CLAUDE.md, CHANGELOG.md, docs/betrieb/Timesheet.md. |
| MED-D-154 | 2026-07-19 | Frontend/Konsistenz (G-8, MED-OP-UX-8/Welle-9 Punkt 1) | PHASE_LABEL-Dopplung in cockpit.component.ts aufgelöst (App-Audit-Befund B9). Die lokale Konstante PHASE_LABEL reimplementierte den kanonischen LIFECYCLE_LABEL (labels.ts) und war dabei abgedriftet (aktiv:'Aktiv' statt 'Aktiv (betreut)') — ein echter G-8-Verstoß, den der App-Audit v0.83.0 (MED-D-153) live bestätigt hatte. Fix: const PHASE_LABEL = LIFECYCLE_LABEL (Alias statt Kopie); die drei abhängigen Strukturen, die intern per Label-String (nicht Enum-Wert) indizieren/vergleichen — PHASE_STRIP, PIPELINE_PHASEN, PHASE_VAR — wurden auf PHASE_LABEL.<key>-Werte umgestellt statt hartcodierter deutscher Strings, damit kein zweiter manueller Abgleichspunkt entsteht. Beim gezielten Nachsuchen nach demselben Fehlerbild eine zweite, vom Audit nicht erfasste Dopplung gefunden: mandant-detail.component.ts#lifecycleLabel() hatte einen eigenen (zufällig noch wertgleichen) Hardcode-Fallback — ebenfalls auf den Import von LIFECYCLE_LABEL umgestellt. Live verifiziert (wrangler dev + Playwright, Desktop 1440px): Cockpit-Pipeline-Leiste und KPI-Kachel zeigen jetzt korrekt "Aktiv (betreut)", kein Layout-Bruch, keine Konsolenfehler. 491 Vitest unverändert grün, tsc + ng build grün. | Nutzeranstoß "PHASE_LABEL-Dopplung" (App-Audit-Befund B9, MED-D-153). | client/src/app/cockpit.component.ts, client/src/app/mandant-detail.component.ts, HANDOFF.md §2/§4, CHANGELOG.md, docs/betrieb/Timesheet.md. |
| MED-D-155 | 2026-07-19 | Doku/Way-of-Working (CodeRabbit-Nachlese zu MED-D-154) | CodeRabbit-Nachlese zu MED-D-154 (PR #195): 3 von 4 Befunden echt, nachgezogen. Der eigene Versions-Stempel-Sync (0.83.0→0.83.1) hatte nur die jeweils erste, vom Konsistenz-Check geprüfte "Stand"-Zeile je Datei getroffen — drei Dateien trugen zusätzliche, vom mechanischen Regex nicht erfasste Stellen mit dem alten Stand/Testzahl weiter: docs/betrieb/Test-Uebersicht.md (Tabellenzeile "490 Unit-/HTTP-Tests" statt 491), docs/fachlich/MVP-Scope.md (Status-Absatz "490 Vitest-Tests"), docs/produkt/Management-Summary.md (drei weitere Stellen: Fließtext-Version+Testzahl, Status-Tabelle Version+Testzahl, §4-Kopf-Version — alle noch 0.83.0/490). Alle drei korrigiert auf 0.83.1/491. Bewusst nicht übernommen (1): CHANGELOG-PR-Link statt Branch-Name — bereits MED-D-144 geprüft und als etablierte Konvention verworfen (Einträge werden vor Kenntnis der PR-Nummer verfasst), kein neuer Grund seither. Kein Code-/Schema-Change, APP_VERSION unverändert 0.83.1. | Eingehende <github-webhook-activity>-Events (CodeRabbit-Review-Kommentare) auf PR #195. | docs/betrieb/Test-Uebersicht.md, docs/fachlich/MVP-Scope.md, docs/produkt/Management-Summary.md, CHANGELOG.md, docs/betrieb/Timesheet.md. |
| MED-D-156 | 2026-07-20 | Frontend/UX · Akte (mandant-detail.component.ts) | Akten-Cockpit-Redesign — die Akte übernimmt das Cockpit-Design (.mw-*/World-2) statt der bisherigen separaten hellen Brand-Optik. Per Nutzerauftrag ein claude.ai/design-Mockup ("Akten-Cockpit 1a (Detail)", Projekt "Mandanten-Akte verbessern") über die DesignSync-MCP importiert und implementiert. Vier Weggabelungen per Rückfrage entschieden (bindend): (1) der Lebenszyklus-Pill in der linken Sidebar bleibt klickbar und öffnet den bestehenden Status-Wechsel voll funktional (Guard/409/Undo-Toast exakt erhalten) statt der rein anzeigenden Mockup-Variante; (2) der globale App-Header wird für /mandant/:id durch den Cockpit-eigenen mw-header ersetzt (app.component.tss bestehendes istVollbild-Signal — bisher nur für / — um /mandant/-Routen erweitert, kein neuer Mechanismus); (3) der Mandate-Tab wird voll verschmolzen: akte-auftraege.component.ts übernimmt sämtliche Beratungsdoku-Bearbeitungs-Signale/-Methoden (bd*/rw*, vollständig aus mandant-detail.component.ts verschoben statt kopiert) direkt inline pro Auftrag, inkl. neuer Ein-Schritt-Direktbindung "Anlegen & verknüpfen" für den häufigen Fall ohne bereits gebundene Beratungsdoku; (4) ein großer PR statt gestuftem Rollout (anders als der frühere World-2-Rollout). Struktur: Vollbild-3-Spalten-Layout (Person-Sidebar 268px · Arbeitsbereich 1fr mit neuem Standard-Tab Übersicht + 7 weiteren Registern · Zeit/Kontext-Sidebar 344px), aufgebaut aus bereits bestehenden, wiederverwendeten Cockpit-Klassen (.mw-app/-header/-body/-fokus/-rail/-ctx) statt neu erfundener Inline-Grids — erbt damit Cockpits bereits gehärtete Mobil-Mechanik (.mw-ctx-toggle/.offen-Bottom-Sheet) direkt mit. .mw-scopes bestehender CSS-Var-Remap (.md-*→World-2-Tokens) bedeutete: alle unangetasteten Register (Dokumente/Onboarding/Wiedervorlagen/Zeiterfassung/Verlauf/Stammdaten) mussten nicht umbenannt werden — nur Header/beide Sidebars/Übersicht-Tab/verschmolzenes Mandate-Register brauchten echtes .mw-*-Markup, was den Umbau-Umfang gegenüber der ursprünglichen Plan-Annahme deutlich verkleinerte. Zeiterfassungs-Timer zieht unverändert (reine Template-Verschiebung, keine Signal-/Methoden-Änderung) in die rechte Sidebar um; Aktenreife-Ring vergrößert (Cockpit-Vorbild r=34); "Letzte Aktivität" neu aus dem bereits eager geladenen Verlauf gespeist (verlaufNeuesteZuerst().slice(0,3), keine neue Lade-Strategie nötig). G-4-Dirty-Check (canDeactivate()) für ungesicherte Beratungsdoku-Entwürfe bleibt erhalten, obwohl der State ins Kind wanderte — via viewChild(AkteAuftraegeComponent)-Signal-Query + neuer hatUngespeicherteEntwuerfe()-Methode auf dem Kind (das nur [hidden], nie zerstört wird, also über Tab-Wechsel hinweg gültig bleibt). Dabei mitgeliefert: der seit MED-D-153/MED-OP-UX-8 Punkt 3 bekannte fehlende error:-Handler an lifecycleZuruecksetzen() (derselbe Trigger wurde ohnehin von <select> auf klickbaren Pill umgebaut). Zwei genuine Bugs — von tsc/vitest/ng build nicht erfasst, erst in der Playwright-Live-Verifikation gefunden: (a) eine alte Lifecycle-basierte Erst-Tab-Heuristik in laden() (REGISTER.find(x => x.stufe === d.mandant.lifecycleStatus)) überlebte den Umbau versehentlich und überschrieb den neuen Standard-Tab "Übersicht" beim ersten Laden auf die Lifecycle-Stufe des Mandanten — an "Mustermann Dr. Max" (Status Onboarding) reproduziert: Seite öffnete auf Register "Onboarding" statt "Übersicht"; Heuristik ersatzlos entfernt, nur die einmalige IBAN-Feld-Seedung blieb unter demselben Einmal-Guard. (b) die geteilte .mw-rail-CSS-Klasse trägt eine Cockpit-spezifische Mobil-Transformation (@media max-width:1100px: Rail wird horizontale Chip-Leiste mit overflow-x:auto, setzt Cockpit-eigene Unterklassen .mw-rail-ring/-buckets/-brennt zum Ausblenden/Umformen voraus) — die Akte hat diese Unterklassen nicht, wodurch ihr inhaltlich reicherer Rail bei ≤1100px einfach in eine überfüllte horizontale Leiste gepresst wurde: bei 390px intern horizontal scrollend und optisch abgeschnitten (scrollWidth=977px vs. clientWidth=390px, live per DOM-Messung bestätigt). Fix: neue, höher-spezifische Regel .mw-scope .mw-fokus > .mw-rail setzt für die Akte (erkennbar an .mw-scope, das Cockpit nicht trägt) auf normalen Blockfluss zurück — Cockpit selbst unverändert. Bewusst nicht gebaut: die im Mockup gezeigte Zeiterfassungs-"Mandat"-Zuordnung (Select am Timer) — ApiService.leistungszeitErfassen() hat keinen Auftrags-/Beratungs-Bindungsparameter, obwohl Leistungszeit.beratungRef das Feld bereits trägt; ein neuer Backend-Endpunkt hätte den reinen-Client-Umbau-Rahmen dieses PRs gesprengt — als offener Punkt in HANDOFF.md §5 vermerkt statt stillschweigend wegzulassen. | Die Nutzerentscheidungen lösten die vier größten Fallstricke einer naiven 1:1-Mockup-Übernahme vorab auf: eine rein anzeigende Status-Pille hätte eine bestehende, guard-gehärtete Funktion beschnitten; ein globaler Header-Ersatz nur für diese eine Route folgt exakt dem bereits für / etablierten Precedent statt einem neuen Sonderfall; die volle Mandate-Tab-Verschmelzung vermeidet einen optisch verschmolzenen, aber funktional weiterhin zweigeteilten Zwischenzustand. Die Wiederverwendung bestehender .mw-*-Layoutklassen statt neu erfundener Inline-Grids war eine bewusste Entscheidung, um Cockpits bereits mehrfach gehärtete Mobil-Mechanik (u. a. die in MED-D-111/MED-OP-UX-5 behobene Akte-Mobil-Überlauf-Historie) nicht ein zweites Mal unabhängig neu zu bauen und dabei dieselben Fehler zu wiederholen — der trotzdem gefundene .mw-rail-Mobil-Bug zeigt, dass "dieselbe Klasse verwenden" allein nicht ausreicht, wenn die Klasse an eine andere Sub-Struktur gekoppelte Breakpoint-Logik trägt; entscheidend war, dass die Live-Browser-Verifikation (nicht nur tsc/vitest/ng build) genau diese Lücke aufdeckte, bevor sie in Produktion sichtbar wurde — derselbe Wert, den bereits frühere PRs dieser Session (u. a. MED-D-149/150) aus der Kombination automatisierter Tests + echter Browser-Begehung gezogen haben. | gebaut (0.83.1 → 0.84.0, MINOR) · client/src/app/{app.component,mandant-detail.component,akte-auftraege.component}.ts · client/src/styles.css (.mw-rail-Mobil-Fix) · 491 Vitest (Server, unverändert — reiner Client-Umbau) + tsc + ng build grün · wrangler dev + Playwright gegen zwei reale Testakten ("MED-D-1xx Test C" [2 Aufträge] · "Mustermann Dr. Max" [16 Aufträge]) verifiziert: Übersicht-Standard-Tab, verschmolzener Mandate-Merge-Flow (Anlegen&verknüpfen + Speichern), Lifecycle-Pill-Klick inkl. Abbrechen-Pfad, Timer/Aktenreife-Ring/Letzte-Aktivität in der rechten Sidebar, keine Konsolenfehler, 390px ohne Seiten-Overflow (nach beiden o. g. Fixes). |
| MED-D-157 | 2026-07-20 | Feature/Zeiterfassung · Akte (mandant-detail.component.ts) | Zeiterfassungs-"Mandat"-Zuordnung nachgeliefert (0.84.0→0.85.0, MINOR) — der in MED-D-156 bewusst zurückgestellte Punkt: die im claude.ai/design-Mockup gezeigte Auftrags-Bindung am Timer war out of scope, weil ApiService.leistungszeitErfassen() keinen Bindungsparameter hatte. Vor der Umsetzung recherchiert, ob Leistungszeit.beratungRef wiederverwendbar ist — nein: es referenziert R6 Beratungsdoku (Auto-Seed-Herkunft, zwei Hops von Beratungsauftrag entfernt), nicht Beratungsauftrag direkt; also neues, eigenständiges Feld auftragRef (R13-F11), analog dem bereits etablierten auftragRef-Muster bei Wiedervorlage/Dokument/Beratungsdoku (MED-D-101/104). Server: erfassen() bekommt optionales auftragRef, app.ts-Route validiert Existenz + Mandanten-Zugehörigkeit via repo.getBeratungsauftrag() (sonst 400, analog bestehender Validierung); migrate.ts v42 (ALTER TABLE leistungszeit ADD COLUMN auftrag_ref + Index), Schema/Repo/Memory-Repo/D1-Repo im etablierten beratungRef-Muster mitgezogen. Client: neues Mandat-<select> am Live-Timer (Optionen aus dem bereits eager geladenen auftraege()-Signal, kein neuer Fetch) + geteiltes Signal an der "Verlassen & buchen"-Modal + eigenes Signal im retroaktiven Erfassen-Formular (beide Buchungswege nutzen leistungszeitErfassen(), beide bekommen den Picker); Historie zeigt "· Mandat: X" analog "· aus Beratung". Gegen echten Browser verifiziert (wrangler dev + Playwright, "Mustermann Dr. Max"): Auswahl → Buchen → Historie zeigt korrekte Zuordnung, retroaktives Formular ebenso, 390px ohne Overflow, keine Konsolenfehler. +2 Vitest (491→493, 46 Dateien), tsc + ng build + Doku-Konsistenz-Check grün. Mandat bleibt bewusst die in dieser Zeile verwendete Bezeichnung — das UI-facing Wort für Beratungsauftrag (identisch zum bereits bestehenden "+ Mandat"-Button/"Mandate"-Tab in mandant-detail.component.ts, G-3), keine Terminologie-Abweichung von MED-D-95s technischem Beratungsauftrag. | R13, MED-D-101/104, HANDOFF.md §2/§5 |
| MED-D-158 | 2026-07-20 | Doku/Way-of-Working · Frontend/Korrektheit (CodeRabbit-Nachlese zu MED-D-157) | CodeRabbit-Nachlese zu MED-D-157 (PR #197): 6 von 8 Befunden echt. PR #197 mergte per Auto-Merge, bevor CodeRabbits Review eintraf (Draft-Skip-Timing, analog MED-D-131/143/152). Jeder Befund einzeln gegen den bereits gemergten Code verifiziert. Echt, behoben: typografische Anführungszeichen in 4 selbst hinzugefügten Zeilen (CHANGELOG/Timesheet/HANDOFF/Decision-Log) auf gerade Zeichen korrigiert + CHANGELOG-Zeile bekommt den PR-Link nachgezogen; README.md "UX-Wellen 1–9" (Überclaim, Welle 9 laut HANDOFF weiterhin 🟡) zurück auf "1–8"; mandant-detail.component.ts#auftragLabelVon() zeigte nur produktLabel — bei mehreren Beratungsaufträgen desselben Produkts (in der eigenen Live-Verifikation von PR #197 bereits sichtbar: zwei "Dentmarking-Gutachten"-Einträge) identisch in der Historie, jetzt mit Status ergänzt; app.tss auftragRef-Validierung akzeptierte nicht-string/nicht-null-Werte stillschweigend als "kein Mandat" — jetzt expliziter Typ-Check (400) + .trim(), neuer Regressionstest. Bewusst nicht wörtlich übernommen: Umbenennung "Mandat"→"Beratungsauftrag" im Decision-Log — "Mandat" ist das bewusst gewählte UI-facing Wort (identisch zum bestehenden "+ Mandat"-Button/"Mandate"-Tab, G-3), keine Terminologie-Abweichung von MED-D-95; nur der Anführungszeichen-Stil korrigiert. Real, aber nicht isoliert gepatcht: migrate.tss fehlende Restart-Sicherheit ist systemisch seit v1 (nicht spezifisch für v42) — als neuer, benannter offener Punkt MED-OP-MIGRATE-1 in HANDOFF.md §4 festgehalten statt isoliert für nur einen Schritt gepatcht (analog MED-OP-TEST-1). +1 Vitest (493→494, 46 Dateien), tsc + ng build + Doku-Konsistenz-Check grün, wrangler dev + Playwright erneut gegen "Mustermann Dr. Max" verifiziert. | MED-D-157, MED-OP-TEST-1, HANDOFF.md §4 |
| MED-D-159 | 2026-07-20 | Frontend/Layout (Nutzerfund) | Register-Tableiste + Timer-Kopf: Überlauf hinter der Kontext-Spalte behoben (0.85.0→0.85.1, PATCH). Nutzerfund per Screenshot ("Die Schrift überlappt … kam mit der Übernahme des neuen Designs") — Reproduktion vor Annahme: lokal per wrangler dev + Playwright nachgestellt statt spekuliert. Root-Cause: .mw-seg (Cockpit-Segmented-Control für 2–3-Optionen-Umschalter, flex: none, kein Wrap/Scroll) wurde vom Akten-Cockpit-Redesign (MED-D-156) für die jetzt 8-teilige Register-Leiste der Akte weiterverwendet — ein Anwendungsfall, für den die Klasse nie ausgelegt war (verifiziert: .mw-seg wird in cockpit.component.ts nur für 2–3-Item-Umschalter benutzt). Sie überlief die schmale Mittelspalte (CSS-Grid 268px 1fr 344px) und verschwand nicht durch echtes DOM-Overlap (Bounding-Box-Check zeigte overlapArea: 0), sondern weil die rechte Kontext-Spalte (später im DOM, opaker Hintergrund) den überlaufenden Text übermalte — sichtbar als abgeschnittenes "Zeiterfa" statt "Zeiterfassung". Fix: neue, eng gescopte Modifier-Klasse .mw-seg-scroll (flex: 1 1 0; min-width: 0; overflow-x: auto, Kind-Buttons flex: none; white-space: nowrap) — nur an der Akte-Registerleiste angewandt, Cockpits Basis-.mw-seg bleibt unverändert (kein Risiko für die 2–3-Optionen-Umschalter). Live per Playwright verifiziert: scrollWidth (934px) > clientWidth (777px), "Verlauf"-Tab bleibt per Scroll erreichbar und klickbar. Zweiter, verwandter Fund im selben Screenshot: .md-timer-head war ebenso flex: none ohne Wrap — die stets 8-stellige HH:MM:SS-Anzeige (timerAnzeige() zeigt Stunden immer) lief über die Timer-Karte hinaus, sobald das Label ("Zeiterfassung läuft/pausiert") in der schmalen Karte auf zwei Zeilen umbrach. flex-wrap: wrap ergänzt — Uhr fällt jetzt in eine eigene Zeile statt zu überlaufen (Bounding-Box vorher/nachher gemessen: Überlauf +10px → 0px). Kein Server-/Schema-Change; 494 Vitest unverändert grün, tsc + ng build + Doku-Konsistenz-Check grün. | MED-D-156, styles.css, mandant-detail.component.ts |
| MED-D-160 | 2026-07-20 | Fachlich/Dexman (Nutzeranstoß) | VEM (Vermögensmanagement) + eigenständige Darlehensübersicht als neuer offener Punkt (OP-DEX-10) (keine Versionsänderung, Doku-only). Nutzeranstoß "OP: DAM (Darlehensübersicht) und VEM (Vermögensmanagement) auch abbilden" — Recherche zeigte: DAM ist bereits als Zuliefer-Quelle im Fachmodell erfasst (§3 Fachmodell Darlehen, speist DEX-9 Darlehensspiegel), aber nur als Rohdaten-Import in DexMans Darlehen-Blatt, nicht als eigenständige Sicht. VEM ist komplett neu — in keinem der drei bisher analysierten Excel-Bestandstools (Dexman-Fachmodell.md §0) erwähnt. Da weder Excel-Datei noch Feldkatalog für VEM vorliegen (analog dem Analyse-Stand von DAM/PM vor der Session 2026-07-03), wurde bewusst kein Fachmodell-Abschnitt spekulativ verfasst — stattdessen neuer, offen formulierter Punkt OP-DEX-10 in Dexman.md §10 + Dexman-Fachmodell.md §10 (Quellsystem-Tabelle um VEM-Zeile "noch nicht analysiert" ergänzt): (1) Analyse-Session für VEM nachholen; (2) Integrationspfad klären (VBA-Import wie DAM/PM, oder eigenständiges Modul mit eigener Oberfläche?); (3) ob DAM zusätzlich eine eigenständige Darlehensübersicht-Sicht braucht (nicht nur als DexMan-Importquelle). OP-DEX-6..9 → OP-DEX-6..10 in allen Range-Referenzen (Dexman.md, Dexman-Fachmodell.md, HANDOFF.md §4/§5) nachgezogen. Kein Code-/Schema-Change, Doku-Konsistenz-Check grün. | Dexman.md §10, Dexman-Fachmodell.md §0/§10 |
| MED-D-161 | 2026-07-20 | Fachlich/Produkt-Katalog · Beratungsdoku (Nutzeranstöße) | Zwei weitere Nutzeranstöße doku-only festgehalten (keine Versionsänderung). (1) "OP: Beratungsmandate: Immobilienfinanzierung, Dexpansion (Dentale Expansion)" → neue Zeile MED-KB-9 in docs/betrieb/Kunden-Besprechungspunkte.md (nicht direkt gebaut, da beide Vorschläge Abgrenzungsfragen zum bestehenden 9-Produkt-Katalog (MED-KB-7/MED-D-99) aufwerfen: Immobilienfinanzierung vs. dem bestehenden Produkt Praxisfinanzierung (das Praxis-Erwerb/-Ausstattung adressiert, nicht privaten/gewerblichen Immobilienerwerb) und Dexpansion vs. dem vorbereiteten Dexman-Controlling (Dexpansion klingt nach einmaliger Strategieberatung, Dexman-Controlling nach Dauer-Betreuung) — beides braucht Kundenbestätigung vor dem Bau, analog dem MED-KB-7-Prozess). (2) "OP: Textbausteine für Beratungsdoku" → neuer Punkt MED-OP-BAUSTEIN-1 in HANDOFF.md §4 (kein Kundenklärungsbedarf, da FR-2/R6-F04/F05 bereits spezifizieren, was gebaut werden soll — reiner Bau-Rückstand). Vor dem Eintrag recherchiert: Beratungsdoku.bausteine[] (R6-F05) existiert bereits, aber nur als vier hartcodierte Themen-Überschriften-Sets je Themenbereich (domain/beratung-themen.ts), die (a) den Vollständigkeits-Check speisen und (b) als reiner Platzhalter-Hinweis im Protokolltext-Feld erscheinen — keine wiederverwendbare Textbaustein-Bibliothek mit Einfügen-Aktion, keine Admin-Editierbarkeit (der Code-Kommentar markiert das selbst als "Admin-editierbar gedacht; hier als Code-Default", also bewusst Platzhalter). FR-2 ("Vorlagen-/Textbaustein-Bibliothek") und der Glossar-Eintrag Glossar.md#textbaustein beschreiben die Zielvision bereits, ohne dass sie je als benannter, verfolgbarer Punkt in HANDOFF.md §4 aufgetaucht war. Kein Code-/Schema-Change, Doku-Konsistenz-Check grün. Branch-Hygiene: PR #200 (MED-D-160) mergte während dieser Arbeit — Branch wurde vor dem Commit dieser Zeile per git checkout -B … origin/main frisch aufgesetzt (etablierte Konvention, verhindert mergeable_state: dirty). | MED-KB-7, MED-D-99, HANDOFF.md §4, Kunden-Besprechungspunkte.md, Lastenheft.md §4.6/FR-2 |
| MED-D-162 | 2026-07-20 | Frontend/Design-Konformität · Akte (mandant-detail.component.ts) | Akten-Cockpit auf strikte Mockup-Konformität nachgezogen (0.85.1→0.86.0, MINOR). Nutzerauftrag "Use the claude_design MCP … Implement: Implement this strictly according to this design" — das Original-Mockup ("Akten-Cockpit 1a (Detail)", Projekt "Mandanten-Akte verbessern", MED-D-156) erneut über die DesignSync-MCP importiert (get_project/list_files/get_file) statt aus der Erinnerung zu arbeiten, dann ein dedizierter Recherche-Agent gegen die aktuelle Implementierung gegengeprüft (Section-für-Section-Diff über Header/beide Sidebars/alle Tabs). Ergebnis: 26 konkrete, reale Abweichungen (reine Fake-Daten-vs-Live-Daten-Unterschiede wurden bewusst nicht gezählt). Behoben: (1) Register-Leiste von 8 auf die im Mockup vorgesehenen 6 Tabs reduziert — REGISTER-Array verschmilzt "Onboarding" + "Stammdaten" zu einem Tab-Schlüssel stammdaten ("Stammdaten & Onboarding"), "Verlauf" aus der sichtbaren Nav entfernt (bleibt über waehleReg('audit')/den Sidebar-Link "Ganzen Verlauf öffnen →" erreichbar — aktiv ist ein freies String-Signal, keine Funktionseinbuße); SPRUNGZIEL_REGISTER entsprechend nachgezogen. (2) neue tabBadge()-Methode zeigt auf jedem Tab eine reale Zahl (offene Aufträge/Dokumente/Onboarding-Items) statt nur auf den zwei Lifecycle-stufengebundenen Tabs. (3) Mandats-Status-Widget: von der Lebenszyklus-Breadcrumb ("Lead → Onboarding → …") auf klickbare Pill + "Schritt X von 5" + 5-Segment-Fortschrittsbalken umgebaut — der bestehende Klick-öffnet-Select-Guard (409/Undo-Toast, aus MED-D-156 Entscheidung 1) bleibt exakt erhalten, nur der Anzeige-Trigger ändert sich. (4) ⌘K-Tastenkürzel-Chip im Header ergänzt (.mw-kbd, bereits bestehende Klasse aus dem Cockpit). (5) Kontext-Chip an den "Jetzt dran"-Zeilen — aus der bereits vorhandenen NaechsterSchritt.kategorie abgeleitet (G-2, kein neues Server-Feld), z. B. "Querschnitt · Dokumente"/"Beratung". (6) situative Primäraktion (erster offener Punkt) statt generischem "Details" auf den Beratungsmandate-Vorschaukarten — die im Mockup gezeigte Fortschritts-Prozentleiste bewusst nicht nachgebaut, da AuftragReife (bewusst schlank, auftrag-reife.ts) keine echte Prozentzahl führt; eine erfundene Zahl hätte G-2 verletzt. (7) "⚠ Offen in diesem Mandat"-Kasten mit md-sev-Schweregrad-Chips im Mandate-Tab — ehrlich, da jeder Eintrag in AuftragReife.offen bereits ein echter Blocker ist (die Reife-Regel kennt keine feinere Stufe, keine erfundene "wichtig"-Abstufung wie im Mockup-Fake). (8) neuer leistungszeit-Input an akte-auftraege.component.ts (bereits vom Elternteil geladen, kein neuer Fetch) speist den ehrlichen "noch keine Leistungszeit gebucht"-Hinweis. (9) Wortlaut-Angleichungen: "Ablage (NextCloud)" (war "Dokumente (NextCloud)"), "Fristen & Aufgaben" als Sektionsüberschrift (war "Wiedervorlagen"), "+ Mandat anlegen" (war "Auftrag anlegen"), interne ID "UC-8 —" aus einem Hinweistext entfernt (G-3), "(R1-F05)" aus dem Status-Pill-Tooltip entfernt. (10) Zeiterfassungs-Kennzahlkacheln auf die bereits bestehende geteilte .mw-stat-Klasse umgestellt statt Ad-hoc-Inline-Styles. (11) persistenter Bestätigungshinweis nach Zeitbuchung ("✓ X Min gebucht — im Reiter "Zeiterfassung" sichtbar.") ergänzt den bisherigen, flüchtigen Toast — löscht sich, sobald der Nutzer den Kommentar für die nächste Buchung antippt (timerKommentarSetzen()). (12) Akteur-Kürzel in der kompakten "Letzte Aktivität"-Vorschau ergänzt (Daten waren bereits geladen, nur nicht gerendert). Bewusst nicht verändert (2, mit Begründung): <md-akte-dentmarking> bleibt eine eigenständige Karte statt pro-Auftrag-Verschmelzung — bereits in der ursprünglichen MED-D-156-Planung explizit begründet (Dentmarking hängt an der Praxis, nicht an einem konkreten Beratungsauftrag); "Freies Dokument" bleibt eine eigene Karte statt inline in "Unterschriften" — die Sektions-Reihenfolge entspricht bereits dem Mockup, eine echte strukturelle Verschmelzung hätte die bestehende volle CRUD-Funktionalität (Entwurf/Freigabe/Signatur-Niveau) riskiert, ohne einen echten Nutzen zu stiften. Verifikation: tsc + ng build grün (ein Zwischenfehler durch ein Backtick-Zeichen in einem neu hinzugefügten Template-Kommentar, das den TS-Template-Literal-String sprengte, sofort gefunden und korrigiert); 494 Vitest unverändert grün (reiner Client-Umbau); gegen echten Browser verifiziert (wrangler dev + Playwright, "Mustermann Dr. Max", 1440px + 390px): alle 6 Tabs mit realen Badge-Zahlen, Pill-Klick öffnet weiterhin den Guard-Select, Zeitbuchung zeigt den persistenten Hinweis und löscht ihn beim Weitertippen, kein horizontaler Overflow bei 390px, keine Konsolenfehler. Kein Server-/Schema-Change. | Nutzerauftrag "Implement this strictly according to this design" (Re-Import des Original-Mockups), MED-D-156 | mandant-detail.component.ts, akte-auftraege.component.ts, HANDOFF.md §2, docs/fachlich/Feature-Liste.md |
| MED-D-163 | 2026-07-20 | Doku/Way-of-Working · Frontend/Korrektheit (CodeRabbit-Nachlese zu MED-D-162) | CodeRabbit-Review zu MED-D-162 (PR #202): 3 von 5 Befunden echt. Jeder Befund einzeln gegen den tatsächlichen Code/die Konvention verifiziert, nicht blind übernommen. Echt, behoben: akte-auftraege.component.ts — die Erfolgs-Toast nach anlegen() sagte weiterhin "Beratungsauftrag angelegt.", obwohl der Button bereits in MED-D-162 zu "+ Mandat anlegen" umbenannt wurde — auf "Mandat angelegt." vereinheitlicht (Mandat ist das bereits in MED-D-158 etablierte UI-facing Wort für Beratungsauftrag). mandant-detail.component.ts — die neue situative Primäraktion {{ a.reife.offen[0] }} → hätte theoretisch "undefined →" gerendert, falls !a.reife.reif, aber offen leer wäre; laut auftrag-reife.ts ist reif direkt als offen.length === 0 definiert, der Fall ist also nach heutigem Domain-Invariant unmöglich — trotzdem ein günstiger ?? 'Details'-Fallback ergänzt, härtet gegen künftige Entkopplung von reif/offen ab (Angular meldet dafür einen harmlosen NG8102-Hinweis, konsistent mit zwei bereits bestehenden Stellen im selben Muster in derselben Datei). docs/fachlich/Feature-Liste.md + docs/betrieb/Decision-Log.md — eine typografische „Zeiterfassung"-Anführung (offenes „, schließendes gerades ") in der neuen MED-D-162-Prosa korrigiert auf durchgängig gerade Anführungszeichen, wie in .coderabbit.yaml/agents.md §2 (MED-D-145) für **/*.md verbindlich festgelegt — die identische Formulierung als tatsächlicher UI-Text im .ts-Template bleibt bewusst bei typografischen deutschen Anführungszeichen „…" (die Konvention gilt nur für Markdown-Prosa, nicht für zitierten App-Text). Geprüft, bewusst nicht übernommen (2): CHANGELOG-Absatz in Bullet-Punkte auftrennen — widerspricht der in dieser Session etablierten, bewusst gewählten dichten Absatz-Konvention für Changelog-Einträge (kein neuer Grund seither, kein isolierter Stilwechsel für einen einzelnen Eintrag). "Ablage (NextCloud)" im Kartentitel auf "Ablage (R2)" ändern — echter, aber vorbestehender Befund (der Titel hieß schon vor diesem PR "Dokumente (NextCloud)"; MED-D-162 änderte nur "Dokumente"→"Ablage", ließ "(NextCloud)" unverändert; das Mockup selbst spezifiziert exakt denselben Wortlaut) — eine Doku-Korrektur allein hätte Doku und tatsächlichen UI-Text auseinanderlaufen lassen; stattdessen als kleiner Rest an der bereits bestehenden MED-OP-FILES-1-Zeile in HANDOFF.md §4 vermerkt statt isoliert gepatcht. tsc + ng build + 494 Vitest (unverändert) + Doku-Konsistenz-Check grün. | CodeRabbit-Review zu PR #202 | mandant-detail.component.ts, akte-auftraege.component.ts, docs/fachlich/Feature-Liste.md, HANDOFF.md §4 |
| MED-D-164 | 2026-07-20 | Frontend/Scope · Architektur/Ablage · Branding (drei Nutzeranstöße) | Drei Nutzeranstöße in einem PR umgesetzt (0.86.0→0.87.0, MINOR). (1) Aktenreife-Ring explizit descoped: Nutzeranstoß "Nimm die Aktenreife erstmal raus - halte das als OP für später" — Rückfrage zum Umfang ergab: nur der 62px-Ring + Score + klickbare Punkte-Liste in der rechten Sidebar der Akte raus (mandant-detail.component.ts), nicht die davon abgeleiteten Tab-Badges/die "Jetzt dran"-Karte (nutzen dieselbe AktenreifeInput-Berechnung, gelten aber nicht als "der Ring") und nicht das Cockpit (out of scope, andere Seite). Totes Markup + die dadurch verwaisten Methoden/Properties entfernt (zuPunkt, offenGesamt, reifeLabel, ringOffset, ringUmfang, zugehörige REIFE_STUFE_LABEL/reifeStufe/AktenreifePunkt-Importe) — tsc bestätigt sauber (keine toten Referenzen). Als OP festgehalten für später: Wiedereinführung der Ring-Visualisierung (oder eines Ersatzes) ist bewusst nicht spezifiziert, Rückbau war eine reine Entfernung ohne Platzhalter. (2) NextCloud-Rolle final entschieden: Nutzeraussage "NextCloud ist rein read-only-Sicht auf die Dokumente in der App" bestätigt formal den seit MED-KB-4 (12.07., Meeting M20) skizzierten, bislang nur "vorläufig"/"ggf. später" formulierten Plan — R2 bleibt der einzige Schreibpfad, NextCloud wird (sobald gebaut) eine reine Read-Only-Sicht (Notfall-/Katastrophenfall-Zugriff, kein zweiter Schreibpfad). Aktualisiert: HANDOFF.md MED-OP-FILES-1 (vorläufig→final), docs/architektur/Dokumentenverwaltung-NextCloud.md §Nachtrag, docs/betrieb/Kunden-Besprechungspunkte.md MED-KB-4 (formale Kundenbestätigung jetzt erhalten, offen bleibt nur noch der Bau/Action-Item A8). Im selben Zug den an MED-D-163 vertagten CodeRabbit-Fund behoben — Akte-Kartentitel "Ablage (NextCloud)" → "Ablage (R2)" — sowie fünf weitere, dieselbe Aussage treffende UI-Texte korrigiert (Dokumenten-Automatisierung-Hinweis, Cockpit-Hinweistext, Verwaltung-Hilfetext, drei generische "NextCloud ist nicht konfiguriert."-Fehlermeldungen → "Ablage ist nicht konfiguriert."). Bewusst nicht gesweept: die tieferen technischen Spec-Stellen (Lastenheft.md R3-Feldtabelle/S-2, Architektur-Uebersicht.md-Diagramm, System-Charakter.md/Stack.md/Kosten.md/Deploy.md/Unterschriften.md/Audit-Log.md) nennen NextCloud weiterhin als R3-Backend-Spalte — ein vollständiger Sweep aller ca. 27 Dateien mit NextCloud-Erwähnungen ging über den Anstoß hinaus; die architektonisch führenden Quellen (HANDOFF/Dokumentenverwaltung-NextCloud.md/Kunden-Besprechungspunkte) sind aktuell. (3) Marke umbenannt zu "Medidentas Digital": Rückfrage zum Umfang ergab "Identität + UI-Oberflächen" (nicht jede beiläufige Doku-Erwähnung, nicht die technischen Identifier). Geändert: Identitäts-Sätze in CLAUDE.md/README.md/docs/README.md/docs/produkt/{Management-Summary,Produkt-und-Marketing}.md/docs/konventionen/Entwicklungsansatz.md/docs/betrieb/Sanity-Checkliste.md; die In-App-Wortmarke (.mw-brand in cockpit.component.ts+mandant-detail.component.ts, neue .mw-brand-suffix-Klasse) und der Marken-Kopf der 4 öffentlichen Kundenstrecken (pub-bausteine.ts#PubKopfComponent, neue .md-wordmark-suffix-Klasse) zeigen jetzt einen kleinen, gedämpften "Digital"-Zusatz neben der bestehenden zweifarbigen "medi"+"dentas"-Wortmarke statt eines invasiven Wortmarken-Umbaus; Browser-Tab-Titel (index.html); Fließtext-Erwähnungen in den 4 öffentlichen Kundenformularen ("bei/von medidentas" → "bei/von Medidentas Digital"). Bewusst unverändert: app.medidentas.com (Domain), medidentas-client/medidentas-server (Package-Namen), drkv-com/medidentas (Git-Repo), Branch-Namensschema, und © medidentas GmbH in der DSGVO-Fußzeile (PubFussComponent) — das ist der wahrscheinliche Rechtsträger-Name, ein anderer Namensraum als die Produktmarke; eine Umbenennung ohne explizite Bestätigung, dass Rechtsträger- und Produktname identisch umbenannt werden sollen, wäre eine unbegründete Tatsachenbehauptung gewesen. Verifikation: tsc + ng build grün, 494 Vitest unverändert grün (reiner Client-/Doku-Umbau), Doku-Konsistenz-Check grün, gegen echten Browser verifiziert (wrangler dev + Playwright, "Mustermann Dr. Max" + Cockpit + öffentliche Onboarding-Seite): Aktenreife-Ring weg (SVG-Count 0), "Letzte Aktivität"/Tab-Badges/"Jetzt dran" unverändert sichtbar, "Ablage (R2)" statt "(NextCloud)", Wortmarke zeigt "medidentas Digital" in Cockpit/Akte/öffentlicher Seite, keine verwaisten "bei medidentas"-Reste, keine Konsolenfehler. | Nutzeranstöße "NextCloud ist rein read-only-Sicht auf die Dokumente in der App", "Nenne die App 'Medidentas Digital'", "Nimm die Aktenreife erstmal raus - halte das als OP für später" | mandant-detail.component.ts, cockpit.component.ts, akte-auftraege.component.ts, verwaltung.component.ts, pub-bausteine.ts, styles.css, index.html, 4 öffentliche *-public.component.ts, CLAUDE.md, README.md, HANDOFF.md §4, docs/architektur/Dokumentenverwaltung-NextCloud.md, docs/betrieb/Kunden-Besprechungspunkte.md MED-KB-4 |
| MED-D-165 | 2026-07-20 | Doku/Way-of-Working · Frontend/CSS (CodeRabbit-Nachlese zu MED-D-164) | CodeRabbit-Review zu MED-D-164 (PR #203, bereits gemerged): 11 von 13 Befunden echt und behoben, 2 bewusst nicht übernommen (keine Versionsänderung; PR #203 mergte per Auto-Merge, bevor alle Befunde nachgezogen waren — dieser Fix landet als eigenständiger Folge-PR auf frisch aufgesetztem Branch, analog MED-D-131/143/152/158/163). Echt, behoben (11): .md-wordmark-suffix (styles.css) fehlte white-space: nowrap, anders als das analoge .mw-brand-suffix — ergänzt, verhindert Umbruch des "Digital"-Zusatzes im öffentlichen Marken-Kopf. Rest-Vorkommen von unrenamed "Medidentas" in den bereits für die Identitäts-Umbenennung vorgesehenen Dateien nachgezogen: README.md ("Eigenwert von Medidentas" → "Medidentas Digital"; Status-Zeile "Dokumente / NextCloud + R2-Ablage" → "Dokumente / R2-Ablage (NextCloud read-only)"), docs/produkt/Management-Summary.md (§"Warum Medidentas?"-Fließtext), docs/produkt/Produkt-und-Marketing.md ("## Die Lösung"/"## Abgrenzung"-Absätze + die dort noch aktiv klingende "Dokumente in NextCloud"-Bullet auf "R2-Ablage, NextCloud nur Read-Only-Notfallsicht" korrigiert), docs/konventionen/Entwicklungsansatz.md (zwei Fließtext-Stellen). docs/produkt/Management-Summary.md zusätzlich: BLUF-Absatz + Status-Tabellen-Zeile "Reifegrad Integrationen" listeten Dokumentenablage weiterhin als "Platzhalter", obwohl dieselbe Datei zwei Abschnitte weiter unten bereits korrekt "✅ produktiv aktiv (kein Platzhalter mehr)" für R2 zeigt — auf "Ablage ✅, externe Anbieter (Signatur/E-Mail/KI) weiter Platzhalter" korrigiert. docs/fachlich/Feature-Liste.md — die zusammenfassende "Dokumenten-Verwaltung"-Zeile stand noch auf 🟡 mit "NextCloud-Client = Fake/WebDAV", obwohl die R2-Ablage seit MED-D-61 produktiv ist (die spätere Detailzeile "Geschlossene Ablage V2" zeigt das bereits korrekt) — auf ✅ mit Verweis auf die Detailzeile umgestellt. Der MED-OP-REIFE-1-Folgepunkt ist bereits in diesem Eintrag selbst wörtlich enthalten (Auffindbarkeits-/Grep-Ziel erreicht) — die bestehende MED-D-164-Zeile bleibt bewusst unangetastet (Decision-Log ist append-only, kein Umschreiben bestehender Zeilen). docs/architektur/Dokumentenverwaltung-NextCloud.md — der "Final entschieden"-Absatz behauptete "offen bleibt ausschließlich der Bau", widersprach sich aber im selben Absatz selbst (die Read-only-Sicht umgeht das Lese-Zugriffslog D-50, Rollen-/Ordner-Scope explizit "beim Bau gesondert zu klären") — umformuliert: final ist nur die Rolle (read-only, kein zweiter Schreibpfad), das Zugriffskonzept (Rollen-/Ordner-Scope, Umgang mit der Zugriffslog-Lücke) bleibt ausdrücklich ein zweiter, noch offener Punkt neben dem reinen Bau — keine Sicherheitsentscheidung stillschweigend als bereits getroffen hingestellt. docs/betrieb/Kunden-Besprechungspunkte.md — die MED-KB-4-Zeile behielt den kompletten alten "Zu bestätigen (0)/Falls unbestätigt (1)-(3)"-Absatz unverändert neben der neuen "✅ Update 20.07."-Zeile stehen, was wie ein noch offener Klärungsbedarf aussah — als überholt markiert (Annotation vorangestellt, Text selbst append-only stehengelassen, G-4), nicht gelöscht. Bewusst nicht übernommen (2): CHANGELOG-Eintrag um einen PR-Link ergänzen — Einträge werden vor Kenntnis der PR-Nummer verfasst, branch-benannte Referenz ist die seit MED-D-144/155/163 etablierte Konvention. docs/README.mds Tabellenzeilen zu System-Charakter.md/Prozessmodell.md/In-App-Assistent.md zitieren wörtlich deren eigene (bewusst nicht umbenannte) Überschriften — eine Umbenennung nur in der zitierenden Tabelle hätte eine neue Doku↔Doku-Inkonsistenz erzeugt (OP-DOCS-1), da die Zieldokumente selbst außerhalb des mit dem Nutzer abgestimmten Umbenennungs-Scopes liegen ("~30 andere Dokumente" laut MED-D-164). Branch-Hygiene: PR #203 mergte, während diese Befunde noch offen waren — Branch vor dieser Zeile per git fetch origin main && git checkout -B … origin/main frisch aufgesetzt (etablierte Konvention, verhindert mergeable_state: dirty), da die alten MED-D-164-Commits bereits per Squash in main sind. tsc + ng build + 494 Vitest (unverändert) + Doku-Konsistenz-Check grün. | CodeRabbit-Review zu PR #203 | styles.css, README.md, docs/produkt/Management-Summary.md, docs/produkt/Produkt-und-Marketing.md, docs/konventionen/Entwicklungsansatz.md, docs/fachlich/Feature-Liste.md, docs/architektur/Dokumentenverwaltung-NextCloud.md, docs/betrieb/Kunden-Besprechungspunkte.md |
| MED-D-166 | 2026-07-20 | Doku/Way-of-Working · Betrieb/Fachlich (CodeRabbit-Nachlese zu MED-D-165) | CodeRabbit-Review zu MED-D-165 (PR #204, bereits gemerged): 6 von 7 Befunden echt (keine Versionsänderung; PR #204 mergte per Auto-Merge, bevor alle Befunde nachgezogen waren — Branch erneut frisch von origin/main aufgesetzt). Echt, behoben (6): docs/betrieb/Decision-Log.md — die MED-D-165-Zeile hatte selbst das append-only-Prinzip verletzt, das sie an anderer Stelle in dieser Session korrekt befolgte: statt nur die neue MED-D-165-Zeile zu ergänzen, wurde die bestehende MED-D-164-Zeile direkt editiert (MED-OP-REIFE-1 als Inline-Code in den bestehenden Text eingefügt) — Verstoß gegen die eigene Kopfzeile "Bestehende Zeilen nicht umschreiben"; Edit zurückgenommen, MED-D-164 wieder im Original-Wortlaut, die ID bleibt über den MED-D-165-Text selbst auffindbar. Dieselbe Zeile hatte zudem eine falsche Fund-Bilanz: "12 von 13 Befunden echt" nannte, aber im selben Text zwei separate "bewusst nicht übernommen"-Punkte auflistete (CHANGELOG-PR-Link + docs/README.md-Zitate) — korrekt sind 11 behoben + 2 bewusst nicht übernommen = 13, Zahlen und Aufzählung jetzt deckungsgleich. docs/betrieb/Kunden-Besprechungspunkte.md — MED-KB-4-Status stand weiterhin auf 🟡 offen, obwohl derselbe Zeilentext bereits "keine offene Kundenklärung mehr" bestätigt (nur der Bau/A8 bleibt offen) — auf ✅ geklärt umgestellt; zusätzlich "Read-Only-Notfall-Backup" konsequent auf "Read-Only-Notfall-Sicht" präzisiert (ein reiner Blick auf dieselben R2-Dokumente ist kein unabhängiges Backup mit eigener Wiederherstellungs-Semantik — überzogenes Sicherheitsversprechen vermieden). docs/fachlich/Feature-Liste.md — die beiden Detailzeilen "NextCloud öffentlicher Upload-Link + Webhook" und "NextCloud Sandbox-Wurzel" standen weiterhin ohne jede Einschränkung neben der jetzt auf ✅/R2 umgestellten Zusammenfassungszeile, obwohl Dokumentenverwaltung-NextCloud.md Zeile 231 explizit festhält, dass diese Pfade bei aktivem R2-Backend "schlicht nicht mehr benutzt" werden — beide Zeilen um "(seit R2-Aktivierung MED-D-61 ungenutzt, Code bleibt als Fallback-Pfad bestehen)" ergänzt. docs/produkt/Management-Summary.md — §5 "Nächste Schritte" listete weiterhin "Echte Dokumentenablage & E-Mail" als offenen Schritt, obwohl BLUF und Status-Tabelle in derselben Datei die Ablage bereits als produktiv bestätigen — Zeile auf den tatsächlich noch offenen Rest ("Echter E-Mail-Versand") reduziert, Dopplung mit der bereits bestehenden separaten E-Mail-Zeile vermieden (die Ablage-Hälfte ersatzlos gestrichen statt umformuliert, da bereits eine eigene "Echter E-Mail-Versand"-Zeile existiert). README.md — Zeile 33s "R2-Ablage (NextCloud read-only)" konnte so gelesen werden, als sei die NextCloud-Read-Only-Sicht bereits ausgeliefert, obwohl laut Dokumentenverwaltung-NextCloud.md nur die Rolle final entschieden, der Bau aber offen ist (MED-OP-FILES-1) — auf "R2-Ablage (NextCloud künftig read-only, Sicht selbst offen — MED-OP-FILES-1)" präzisiert, damit die Statuszeile nicht mehr Gebautes suggeriert. Bewusst nicht übernommen (1): CodeRabbits Vorschlag, den Feature-Liste-Zeilen ein hartes "retired/legacy" zuzuweisen — der NextCloudClient-Vertrag bleibt eine aktive Storage-Abstraktion (R2-Treiber dahinter, Dokumentenverwaltung-NextCloud.md), nur der konkrete NextCloud-Webhook-Pfad ist bei R2-Backend ungenutzt; "retired" hätte fälschlich nahegelegt, der gesamte NextCloud-Code sei tot. tsc + ng build + 494 Vitest (unverändert) + Doku-Konsistenz-Check grün. | CodeRabbit-Review zu PR #204 | docs/betrieb/Decision-Log.md, docs/betrieb/Kunden-Besprechungspunkte.md, docs/fachlich/Feature-Liste.md, docs/produkt/Management-Summary.md, README.md |
| MED-D-167 | 2026-07-20 | Doku/Way-of-Working (CodeRabbit-Nachlese zu MED-D-166) | CodeRabbit-Review zu MED-D-166 (PR #205, bereits gemerged): 2 von 3 Befunden echt (keine Versionsänderung; PR #205 mergte per Auto-Merge, bevor alle Befunde nachgezogen waren — Branch dritte Runde in Folge frisch von origin/main aufgesetzt). Echt, behoben (2): README.md — die MED-D-166-Formulierung "R2-Ablage (NextCloud künftig read-only, Sicht selbst offen — MED-OP-FILES-1)" stand im Widerspruch zur eigenen Kopfzeile der Datei (Zeile 5: "NextCloud ausschließlich als Read-Only-Sicht"), die die Rolle bereits im Präsens als final beschreibt — "künftig" ließ es wie eine noch offene Rollen-Entscheidung statt eine bereits final entschiedene, aber noch nicht gebaute Sicht lesen; auf "R2-Ablage (NextCloud read-only, Sicht noch offen — MED-OP-FILES-1)" präzisiert (Rolle im Präsens final, nur der Bau bleibt referenziert offen). docs/betrieb/Kunden-Besprechungspunkte.md — die MED-KB-4-Zeile bestätigte an einer Stelle "kein Finder-Sync" als finale Entscheidung, ließ aber davor (außerhalb des "Überholt"-Blocks) unqualifiziert im Präsens stehen "der Mac-Sync-Wunsch ist mit dem offiziellen Desktop-Client erfüllt" — las sich wie ein aktiv angebotener Sync-Weg und widersprach der eigenen Endaussage; der Satz in den bestehenden "Überholt"-Block verschoben + ins Präteritum gesetzt ("wäre erfüllbar gewesen — überholt"), Sprung zur nun eindeutigen Endaussage "kein Finder-/Mac-Sync" im Überholt-Marker selbst ergänzt. Bewusst nicht übernommen (1): CHANGELOG-Einträge um PR-Links ergänzen (#203/#204) — dieselbe, seit MED-D-144/155/163/165 wiederholt geprüfte und bewusst beibehaltene Konvention (Einträge entstehen vor Kenntnis der eigenen PR-Nummer; ein nachträglicher nicht-append-only-Edit historischer CHANGELOG-Zeilen allein für einen Link wäre zudem dieselbe Art Eingriff, die MED-D-166 im Decision-Log gerade als Fehler identifiziert und korrigiert hat). Beobachtung (kein Fix, informativ): dies ist die dritte aufeinanderfolgende reine Doku-Nachlese-PR (#203→#204→#205→dieser PR), bei der Auto-Merge griff, bevor CodeRabbits Review eintraf — das Draft-Skip-Timing-Muster (MED-D-60) betrifft offenbar auch schnelle, rein dokumentarische Folge-PRs; kein Änderungsbedarf am Workflow selbst, da jede Runde sauber nachgezogen wurde, nur als Beobachtung festgehalten. tsc + ng build + 494 Vitest (unverändert) + Doku-Konsistenz-Check grün. | CodeRabbit-Review zu PR #205 | README.md, docs/betrieb/Kunden-Besprechungspunkte.md |
| MED-D-168 | 2026-07-20 | Doku/Way-of-Working (CodeRabbit-Nachlese zu MED-D-167) | CodeRabbit-Review zu MED-D-167 (PR #206, bereits gemerged): 2 von 4 Befunden echt (keine Versionsänderung). Die Review traf zwar erstmals in dieser Serie ein, während PR #206 noch offen war — doch bevor der Fix-Commit gepusht werden konnte, mergte auch #206 per Auto-Merge (vierte Runde in Folge desselben Timings, MED-D-131/143/152/158/163/165/166/167). Branch erneut frisch von origin/main aufgesetzt. Echt, behoben (2): README.md — "R2-Ablage (NextCloud read-only, Sicht noch offen — MED-OP-FILES-1)" konnte weiterhin als offene Produktentscheidung statt als offener Bau gelesen werden (die Rolle selbst ist längst final) — auf "NextCloud read-only-Sicht: fachlich entschieden, Umsetzung offen — MED-OP-FILES-1" präzisiert. CHANGELOG.md — die eigene Formatzeile ("Format je Eintrag: [#PR](link) …") behauptete einen strikten PR-Link-Zwang für jeden Eintrag, während die tatsächliche Praxis seit MED-D-144 wiederholt (MED-D-152/155/165/166/167) Branch-Namen für Einträge ohne bekannte PR-Nummer nutzt — ein echter Doku↔Praxis-Widerspruch (die Ausnahme stand bislang nur verstreut in Decision-Log-Einträgen, nie in der Formatzeile selbst), den CodeRabbit deshalb bei jeder Runde erneut als "Verstoß gegen die eigene Kopfzeile" markierte; jetzt als explizite Ausnahme direkt in der CHANGELOG-Kopfzeile dokumentiert (G-2/OP-DOCS-1 — eine Wahrheit statt wiederholter Einzelfall-Diskussion in jeder Nachlese-Runde). Bewusst nicht übernommen (1): die historischen #203/#204-CHANGELOG-Einträge nachträglich um PR-Links ergänzen — derselbe append-only-Verstoß, den MED-D-166 im Decision-Log bereits als Fehler identifiziert hat, jetzt in der neuen CHANGELOG-Ausnahme ausdrücklich als Nicht-Praxis benannt. Zurückgestellt (1, Nitpick): docs/betrieb/Kunden-Besprechungspunkte.md MED-KB-4 in eine separate, chronologisch geordnete Historie-Sektion umstrukturieren — von CodeRabbit selbst als "🔵 Trivial"-Befund mit "🏗️ Heavy lift"-Aufwand eingestuft; unverhältnismäßig für einen Doku-Quick-Fix, aber eine echte Verbesserung für einen künftigen dedizierten Doku-Strukturier-Durchgang (kein neuer OP nötig — die Zeile selbst bleibt per Grep über MED-KB-4 auffindbar). tsc (client, kein Code-Change) + Doku-Konsistenz-Check grün. | CodeRabbit-Review zu PR #206 | README.md, CHANGELOG.md |
| MED-D-170 | 2026-07-20 | Frontend/UX (Akten-Cockpit-Detail, Design-Import) | Umsetzung von zwei Elementen aus dem Design-Mockup „Akten-Cockpit 1a (Detail)" (0.87.0 → 0.88.0, MINOR): (1) Self-Service-Link-Kurzfassung in der linken Rail von mandant-detail.component.ts — liest das bestehende Signal von <md-akte-einladungen> per viewChild (G-8, eine Datenquelle, kein Zweit-Fetch), zeigt Status-Pill + Link + Kopieren/In-Stammdaten-übernehmen/Neuen-Link-Buttons, delegiert die eigentlichen Aktionen an die bestehende Komponente. (2) 4-Tasten-Umschalter (Geprüft/Da/Nötig/Später) für Onboarding-Items im Register „Stammdaten & Onboarding" statt des bisherigen 5-wertigen Dropdowns — frontend-only über dem bestehenden ItemStatus-Feld (offen/angefordert teilen sich die Taste „Nötig"), keine Schema-/Backend-Änderung. Bewusst nicht übernommen (aus demselben Mockup): Aufsplitten des Tabs „Stammdaten & Onboarding" in separate Tabs „Basis-Informationen"/„Praxen" — hätte eine frühere, im Code dokumentierte Merge-Entscheidung ("Mockup-Konformität") revidiert, ohne dass dafür ein neuer, explizit bestätigter Grund vorliegt. Mandate-Detail als Modal/Overlay statt der bestehenden Inline-Darstellung in <md-akte-auftraege> — größere, eigenständig zu entscheidende UX-Änderung, hier nicht mitgezogen. Der im Mockup enthaltene, aber selbst display:none gesetzte Aktenreife-Ring — kein sichtbarer Unterschied, hätte nur totes Markup für ein bereits in MED-D-164 descoptes Feature hinzugefügt. Restliche Register (Praxen, Dokumente, Fristen & Aufgaben, Zeiterfassung, Verlauf) unverändert gelassen — ihre md-*-Klassen werden bereits über den .mw-scope-Cascade (styles.css Zeilen 144–235) auf dieselben Design-Tokens abgebildet wie die neuen mw-*-Klassen; ein Rewrite hätte nur Code-Kirchen ohne visuellen Unterschied erzeugt. | Design-Import via claude_design-MCP (Akten-Cockpit 1a (Detail).dc.html, Projekt „Mandanten-Akte verbessern") | client/src/app/mandant-detail.component.ts, server/src/version.ts, CLAUDE.md |
| MED-D-171 | 2026-07-21 | Frontend/UX (CodeRabbit-Nachlese zu MED-D-170) | CodeRabbit-Review zu MED-D-170/MED-D-169 (PR #208, noch offen): 6 von 8 Befunden echt (keine Versionsänderung). Echt, behoben (6): typografische „…"-Anführungszeichen in den neuen MED-D-170-Zeilen (CHANGELOG.md, docs/betrieb/Decision-Log.md, HANDOFF.md) auf gerade Zeichen korrigiert (MED-D-145-Konvention) — nur die eigenen neuen Zeilen, keine vorbestehenden Historie-Zeilen angefasst. CLAUDE.mds Status-Absatz ordnete "Self-Service-Link-Kurzfassung + Onboarding-4-Tasten-Umschalter" pauschal "in der linken Rail" zu, obwohl nur die Self-Service-Karte dort sitzt — der Onboarding-Umschalter lebt in der Onboarding-Item-Liste; präzisiert. mandant-detail.component.tss 4-Tasten-Umschalter bekam [attr.aria-pressed] (an denselben itemTasteAktiv()-Ausdruck gebunden) für Screenreader-Zugänglichkeit, sowie einen No-op-Guard (it.status === t.ziel ? null : statusSetzen(...)) gegen unnötige API-Requests/Reloads/Toasts beim Klick auf einen bereits aktiven Zustand — der Übergang offen→angefordert über "Nötig" bleibt bewusst weiterhin möglich (offen !== 'angefordert'), gegen echten Browser verifiziert (wrangler dev + Playwright: aria-pressed korrekt, zweiter Klick auf bereits aktives "Nötig" löst keinen API-Call mehr aus). docs/fachlich/Feature-Liste.mds MED-D-170-Zeile stand fälschlich unter Abschnitt 3 ("Ist alles vollständig & rechtssicher dokumentiert?") statt Abschnitt 1 ("Wo steht der Kunde im Prozess?", zu dem Onboarding-/Self-Service-Status-Sichtbarkeit tatsächlich gehört) — verschoben. Bewusst nicht übernommen (2): die beiden neuen CHANGELOG-Zeilen (MED-D-169/MED-D-170) zu einem einzigen PR-#208-Eintrag zusammenführen — beide sind eigenständige, unterschiedliche Entscheidungen (ein Doku-Fix vs. ein echtes UI-Feature), die zufällig im selben PR landeten; eine Zusammenführung hätte die Ein-Eintrag-je-Entscheidung-Nachvollziehbarkeit verringert, die auch das Decision-Log für dieselben zwei Entscheidungen bewusst als getrennte Zeilen führt. Die fehlende PR-#208-Verlinkung selbst ist kein neuer Befund — beide Zeilen entstanden vor Kenntnis der PR-Nummer, exakt die seit MED-D-144 etablierte und seit MED-D-168 in der CHANGELOG-Kopfzeile selbst dokumentierte Ausnahme. tsc + ng build grün (kein Server-Change) + Doku-Konsistenz-Check grün; gegen echte Seed-Daten via wrangler dev + Playwright erneut verifiziert. | CodeRabbit-Review zu PR #208 | CHANGELOG.md, CLAUDE.md, HANDOFF.md, client/src/app/mandant-detail.component.ts, docs/fachlich/Feature-Liste.md |
| MED-D-169 | 2026-07-20 | Doku/Way-of-Working (CodeRabbit-Nachlese zu MED-D-168) | CodeRabbit-Review zu MED-D-168 (PR #207, bereits gemerged): 1 von 1 Befund echt (keine Versionsänderung). PR #207 mergte per Auto-Merge, bevor der Fix gepusht war (fünfte Runde in Folge desselben Timings) — Branch erneut frisch von origin/main aufgesetzt. Echt, behoben: HANDOFF.mds MED-D-167/168-Eintrag sagte "2 von 4 Befunden echt", erklärte im Fließtext aber nur die 2 Fixes + 1 zurückgestellten Nitpick (3 von 4) — der vierte Befund (CHANGELOG-PR-Link für #203/#204, bereits im Decision-Log/CHANGELOG als bewusst nicht übernommen dokumentiert) fehlte in der HANDOFF-Kurzfassung; ergänzt. tsc (client, kein Code-Change) + Doku-Konsistenz-Check grün. | CodeRabbit-Review zu PR #207 | HANDOFF.md |
| MED-D-172 | 2026-07-21 | Backend/Frontend (Zeiterfassung, OP-TIME-3) | Aktiver Timer — ein Timer je Benutzer statt je Browser-Tab. Nutzer-Bugreport "mehrere Akten gleichzeitig offen, dann Zeiterfassung nur auf dem aktiven Kunden, der vorne ist — verlassen und schließen nicht möglich"; Code-Recherche fand keinen echten Deadlock im Verlassen-Guard, sondern eine architektonische Ursache: der Live-Timer lebte rein lokal je Komponenteninstanz (= je Browser-Tab unabhängig). Auf explizite Nutzervorgabe "ich will nur einen Timer pro eingeloggtem Nutzer" umgebaut: neue serverseitige Entität AktiverTimer (Erweiterung von R13 Leistungszeit, R13-F12..F17, Tabelle aktiver_timer, Migration v43) — eine Zeile je Benutzer (G-2), ephemer bis zum Buchen. starten() überschreibt nie einen bereits für einen anderen Mandanten laufenden Timer (liefert konflikt:true); die betroffene Akte zeigt dann nur einen Hinweis "läuft in einer anderen Akte" mit Link statt eigener Bedienelemente. beforeUnload warnt nicht mehr wegen des Timers (er geht durchs Schließen/Neuladen nicht mehr verloren) — nur noch bei ungespeicherten Beratungsdoku-Texten. 0.88.0 → 0.89.0 (MINOR). | Ein pro Tab unabhängiger Timer widerspricht dem mentalen Modell "ich erfasse gerade meine Arbeitszeit" — die Zeit gehört dem Benutzer, nicht dem Tab; Datenverlust wird vermieden, indem ein Konflikt nie still überschreibt. | server/src/domain/model.ts, server/src/api/timer-service.ts, server/src/api/app.ts, server/src/db/schema.ts, server/src/db/migrate.ts, client/src/app/mandant-detail.component.ts, client/src/app/api.service.ts |
| MED-D-173 | 2026-07-21 | Doku/Way-of-Working (append-only-Nachlese zu MED-D-171) | Zweiter append-only-Verstoß am MED-D-171-Eintrag entdeckt und korrigiert. CodeRabbit-Review von PR #210 (Aktiver Timer) fand, dass die MED-D-171-Zeile in Decision-Log.md/CHANGELOG.md/docs/betrieb/Timesheet.md nicht nur (wie in MED-D-171 selbst dokumentiert) die Anführungszeichen-Reverts erhielt, sondern in einem lokal committeten, ungepushten Zwischenschritt komplett durch einen anderen Text ersetzt wurde — die neue Fassung beschrieb eine spätere, eigenständige Korrekturrunde (Revert der eigenen Anführungszeichen-Änderung an MED-D-170, "PR #208 noch offen"→"bereits gemergt", zwei abgelehnte Vorschläge), überschrieb dabei aber vollständig, was MED-D-171 selbst ursprünglich dokumentiert hatte (die PR-#209-Runde). Alle drei Dateien auf den exakten Original-Wortlaut von MED-D-171 zurückgesetzt (verifiziert: git diff gegen den Merge-Commit vor PR #210 zeigt keine Abweichung mehr an dieser Zeile); diese Zeile dokumentiert nun die zweite Runde eigenständig. Was diese zweite Runde tatsächlich tat (jetzt korrekt hier verzeichnet): die typografischen „…"-Anführungszeichen, die eine vorherige Runde versehentlich direkt in die bestehenden MED-D-170-Zeilen von CHANGELOG.md/Decision-Log.md geschrieben hatte, wieder auf den echten Original-Wortlaut von MED-D-170 zurückgesetzt (die Anführungszeichen-Inkonsistenz in MED-D-170 selbst bleibt bewusst dauerhaft bestehen, s. o.); die zum Schreibzeitpunkt korrekte, aber durch das wiederkehrende Auto-Merge-vor-Push-Timing überholte Formulierung "PR #208, noch offen" in CHANGELOG/HANDOFF/Timesheet auf "bereits gemergt" aktualisiert; zwei weitere CodeRabbit-Vorschläge bewusst abgelehnt (MED-D-171 vor MED-D-170 einsortieren — widerspricht der MED-D-143-Anhänge-Konvention; CLAUDE.mds Status-Absatz auf einen reinen Governance-Verweis kürzen — der Absatz ist seit MED-D-140 explizit für Ist-Stand-Stichworte vorgesehen). Diese zweite Runde landete, weil sie lokal ungepusht blieb, nicht als eigener Follow-up-PR, sondern gebündelt im nächsten PR (#210, Aktiver Timer) — daher trägt sie hier dessen Referenz statt einer eigenen PR-Nummer. | Zwei verschiedene Korrekturrunden teilten sich versehentlich dieselbe MED-D-171-ID, wodurch die zweite Runde die erste beim Schreiben vollständig überschrieb, statt sie anzuhängen — genau der append-only-Fehlertyp, den MED-D-166 und MED-D-171 selbst schon einmal je einzeln behoben haben, hier aber unbemerkt ein drittes Mal auftrat, weil die zweite Runde ihre eigene eben erst begangene Korrektur nicht noch einmal gegen das append-only-Prinzip prüfte. | docs/betrieb/Decision-Log.md, CHANGELOG.md, docs/betrieb/Timesheet.md |
| MED-D-174 | 2026-07-21 | Backend/Frontend (CodeRabbit-Nachlese zu MED-D-172) | CodeRabbit-Review zu MED-D-172 (PR #210, bereits gemergt): 4 von 9 Befunden echt (0.89.0 → 0.89.1, PATCH). PR #210 mergte per Auto-Merge, bevor der Fix gepusht war — Branch erneut frisch von origin/main aufgesetzt. Echt, behoben (4): mandant-detail.component.ts#canDeactivate() pausierte den Server-Timer bereits vor der Schwellen-/Interaktions-Prüfung — verließ man die Akte schnell (unter Schwelle oder ohne Interaktion), blieb der Timer danach still pausiert stehen, ohne dass je ein verlassenAbbrechen() ihn fortsetzt (widersprach dem eigenen Ziel "der Timer läuft über Akten/Tabs hinweg weiter"); Pausieren jetzt hinter die Schwellen-Prüfung gezogen, nur wenn das Modal tatsächlich erscheint. Echter Sicherheitsfund: /api/timer/start und /api/timer/buchen liegen außerhalb des /api/mandanten/:id*-Chokepoints (mandantScopeGuard) und hatten keine service.darfSehen()/mandant_bearbeiten-Prüfung — ein Berater ohne Sichtbarkeit auf einen fremden Mandanten hätte dort dennoch einen Timer starten und Leistungszeit buchen können, analog dem bereits einmal (MED-OP-AUTH-2) für Meeting/Beratungsdoku/Individualdokument gefixten Lückentyp; beide Routen bekamen dieselbe darfSehen+mandant_bearbeiten-Prüfung wie der bestehende byIdMandantScopeGuard (+3 RBAC-Tests, fremder Mandant → 404 kein Existenz-Leak, eigener → 201 Regression). docs/fachlich/Lastenheft.mds neuer Aktiver-Timer-Abschnitt hatte zwei typografische „…"-Anführungszeichen (MED-D-145-Verstoß, aber lebendes Dokument — direkt korrigierbar, kein append-only-Konflikt) — auf gerade Zeichen umgestellt. timer.test.tss Konflikt-Test prüfte nur timer.mandantId, nicht das laut Contract erforderliche konflikt: true-Feld — Assertion ergänzt, dabei festgestellt, dass die /api/timer/start-409-Antwort dieses Feld bislang gar nicht sendete (nur fehler + timer) — konflikt: true in der Antwort ergänzt. Bewusst nicht übernommen (3): CLAUDE.mds Versions-Status-Absatz auf einen reinen Governance-Verweis kürzen — dieselbe, bereits mehrfach (MED-D-140/171) geprüfte und bestätigte Konvention, kein neuer Grund. docs/betrieb/Test-Uebersicht.md um eine explizite "Zielgruppe:"-Zeile ergänzen — die Datei ist bereits über docs/zielgruppen/Lesepfade.md geroutet (dieselbe Begründung wie beim identischen, bereits einmal abgelehnten Vorschlag zu MED-D-144). HANDOFF.mds MED-D-172-Absatz um eine explizite Zielgruppen-/Ergebnis-Zusammenfassung voranstellen — kein einziger der ~170 vorherigen Einträge in diesem fortlaufenden §2-Fließtext folgt diesem Muster, die Datei selbst benennt ihre Zielgruppe bereits einmal am Dateikopf ("Zuerst lesen... für jede neue Session"); eine Einzelfall-Restrukturierung hier wäre inkonsistent. Bereits vor dieser Runde behoben: derselbe CodeRabbit-Lauf fand außerdem, dass die MED-D-171-Zeile in Decision-Log.md/CHANGELOG.md/docs/betrieb/Timesheet.md versehentlich überschrieben statt ergänzt wurde — s. eigener Eintrag MED-D-173. Zur Einordnung: MED-D-172 revidiert/ersetzt D-49 (dort war der Live-Timer als bewusst rein clientseitig ohne Serverpersistenz entschieden — hier nachträglich vermerkt, da MED-D-172 selbst per append-only nicht mehr direkt editiert werden darf). +3 Vitest (522 gesamt), tsc + ng build grün, gegen echten Browser verifiziert (wrangler dev: schnelles Verlassen ohne Interaktion lässt den Timer nachweislich weiterlaufen statt still zu pausieren). | CodeRabbit-Review zu PR #210 | client/src/app/mandant-detail.component.ts, server/src/api/app.ts, server/src/api/timer.test.ts, docs/fachlich/Lastenheft.md |
| MED-D-175 | 2026-07-21 | Doku (CodeRabbit-Nachlese zu MED-D-174) | CodeRabbit-Review zu MED-D-174 (PR #211, während der Review noch offen): 1 von 2 Befunden echt (keine Versionsänderung). Echt, behoben: MVP-Scope.mds Status-Absatz behauptete pauschal "Slices 1–13 sind feature-complete", während dieselbe Datei Slice 9 in ihrer eigenen Backlog-Tabelle als 🟡 "Kern gebaut" mit weiterhin offener echter Transkription (OP-MEET-1) führt — ein Selbstwiderspruch, den der bloße Versions-Stempel-Sync dieser PR unbeabsichtigt mitgetragen hätte; auf "Slices 1–13 sind umgesetzt … Slice 9 ist im Kern gebaut, echte Transkription bleibt offen" präzisiert. Bewusst nicht übernommen: timer.test.ts um einen Test für die mandant_bearbeiten-403-Verzweigung ergänzen — verifiziert, dass aktuell keine der drei Rollen (admin/backoffice/berater, domain/rechte.ts) mandant_bearbeiten fehlt; ein solcher Test müsste eine nicht-existente Rolle erfinden, um einen Pfad zu testen, der mit dem heutigen Rechte-Modell nie erreicht wird — dieselbe, bereits heute unabgedeckte Situation wie beim bestehenden mandantScopeGuard/byIdMandantScopeGuard (rbac.test.ts deckt deren 403-Fälle ebenfalls nur für andere Fähigkeiten wie mandant_zuweisen/benutzer_verwalten ab, nie für mandant_bearbeiten selbst) — kein neuer, durch diese PR eingeführter Testlücken-Typ. tsc + ng build grün (reiner Doku-Fix) + Doku-Konsistenz-Check grün. | CodeRabbit-Review zu PR #211 | docs/fachlich/MVP-Scope.md |
| MED-D-176 | 2026-07-22 | Frontend/UX · Akte (mandant-detail.component.ts, Fristen & Aufgaben) | Akten-Cockpit 1a (Detail): Mockup-Abgleich per DesignSync-MCP — 2 echte Kleinigkeiten nachgezogen, große Struktur-Abweichungen bewusst NICHT zurückgebaut. Auf Nutzerauftrag das aktuelle Akten-Cockpit 1a (Detail).dc.html erneut aus dem claude.ai/design-Projekt "Mandanten-Akte verbessern" gezogen und Zeile für Zeile gegen die Implementierung geprüft (MED-D-156/159/162/164/170 hatten dieses Mockup bereits mehrfach umgesetzt/nachgezogen). Ergebnis: die meisten scheinbaren Abweichungen sind bereits bewusst getroffene, dokumentierte Entscheidungen, kein Drift — Beratungsdoku bleibt inline im Mandate-Tab statt im Mockup-Modal-Overlay (MED-D-156 Punkt 3, "volle Verschmelzung"), das "Jetzt dran" liegt konsolidiert im Übersicht-Tab statt zusätzlich dupliziert in der Sidebar. Der Aktenreife-Ring in der rechten Sidebar wurde nicht nachgebaut, weil das Mockup selbst diesen Abschnitt hart auf display:none gesetzt hat (auch der Referenzentwurf zeigt ihn aktuell nicht). Zwei echte, risikoarme Lücken behoben: Das "Fristen & Aufgaben"-Anlage-Formular ist jetzt per + Aufgabe-Button ein-/ausklappbar (wvFormOffen-Signal, wvFormToggle()) statt dauerhaft sichtbar; erledigte Wiedervorlagen lassen sich jetzt per neuem "Wieder öffnen"-Button (wvOeffnen(), nutzt die bereits bestehende wiedervorlageStatus(id,'offen')-API) reaktivieren statt endgültig erledigt zu bleiben. Reine Client-Änderung, keine Version-Bump-pflichtige Server-API-Änderung. tsc + ng build grün, vitest (522 Tests) unverändert grün, Playwright-Verifikation der Toggle-/Reopen-Interaktion erfolgreich. | Nutzerauftrag "Implement Akten-Cockpit 1a (Detail).dc.html" — Re-Sync gegen den aktuellen Mockup-Stand statt Neubau | client/src/app/mandant-detail.component.ts |
| MED-D-177 | 2026-07-22 | Backend (CodeRabbit-Nachlese zu MED-D-176) | CodeRabbit-Review zu MED-D-176 (PR #212, während der Review noch offen): 1 von 7 gemeldeten Befunden echt (keine Versionsänderung). Sechs der sieben gemeldeten Befunde erwiesen sich beim Nachprüfen als Artefakte eines falschen Diff-Vergleichspunkts: der Feature-Branch hatte seit PR #210 einen eigenen, inhaltlich identischen aber commit-different Verlauf zu origin/main (dieselben MED-D-172/173/174/175-Änderungen als eigene statt gesquashte Commits) — dadurch berechnete GitHub den Merge-Base fälschlich auf einen Stand vor PR #210 statt auf den echten aktuellen main-Kopf, wodurch CodeRabbit u. a. server/src/api/app.ts/timer.test.ts als "geändert" listete (obwohl byte-identisch zu main, per git diff origin/main HEAD verifiziert) und zwei bereits vor Monaten korrekt behobene, historische Einträge (MED-D-171-Zeile in Decision-Log.md, Timesheet-Zeile -70) fälschlich als in diesem PR neu überschrieben meldete. Branch per git checkout -B … origin/main + Cherry-Pick des eigenen Commits sauber neu aufgesetzt (verifiziert: Diff zu origin/main zeigt jetzt ausschließlich die tatsächlich beabsichtigten 13 Dateien dieser Runde) — löst alle sechs Fehlmeldungen an der Wurzel. Echt, behoben: PATCH /api/wiedervorlagen/:id (Status setzen/erledigen/wieder öffnen, D-42-Bearbeiten) sowie die Nachbarrouten POST …/kommentare und …/zuweisen hatten keinen darfSehen/mandant_bearbeiten-Scope-Guard — derselbe Lückentyp wie zuvor bei Meeting/Beratungsdoku/Individualdokument (MED-OP-AUTH-2) und /api/timer/* (MED-D-174), hier aber schon vor MED-D-176 bestehend (nicht durch diese PR neu eingeführt; MED-D-176s neuer "Wieder öffnen"-Button macht die Lücke lediglich über eine zweite Zustandsrichtung erreichbar). Neuer geteilter wiedervorlageScopeGuard (byIdMandantScopeGuard-Fabrik, analog den drei bestehenden) auf /api/wiedervorlagen/:id + /api/wiedervorlagen/:id/* — deckt PATCH/Kommentare/Zuweisen in einem Griff ab; +1 RBAC-Test (rbac.test.ts, fremder Mandant → 404 für erledigen und wieder-öffnen, eigener → 200-Regression), vorab gegen den ungefixten Stand verifiziert (schlägt ohne Fix nachweislich fehl). Grammatikfehler "reaktivieren statt endgültig sind" in der MED-D-176-Zeile (Decision-Log.md, HANDOFF.md) auf "reaktivieren statt endgültig erledigt zu bleiben" korrigiert (CHANGELOG.md/Timesheet.md hatten den Fehler nicht). Bewusst nicht übernommen: CHANGELOG.md-Eintrag um einen expliziten PR-Link ergänzen — dieselbe, mehrfach bestätigte Konvention (MED-D-144): Einträge, die im selben Commit wie die PR-Erstellung entstehen, kennen die eigene PR-Nummer noch nicht und nutzen bewusst den Branch-Namen statt eines nachträglich ergänzten Links. +1 Vitest (523 gesamt), tsc + ng build grün, Doku-Konsistenz-Check grün. | CodeRabbit-Review zu PR #212 | server/src/api/app.ts, server/src/api/rbac.test.ts |
| MED-D-178 | 2026-07-22 | Frontend/Doku (zweiter CodeRabbit-Lauf zu PR #212) | Zweiter CodeRabbit-Lauf gegen PR #212 (bereits gemergt): 8 gemeldete Befunde — 4 behoben, 3 aus Konventionsgründen bewusst nicht übernommen, 1 nicht reproduzierbar (keine Versionsänderung). PR #212 mergte per Auto-Merge, bevor dieser zweite Nachlese-Fix gepusht war — derselbe wiederkehrende Auto-Merge-vor-Push-Timing-Fehler wie bei MED-D-152/158/163/165/166/167/168/171/173/174 — Branch erneut frisch von origin/main aufgesetzt, dieser Fix landet als eigene Folge-PR. Echt, behoben: wvErledigen/wvOeffnen (mandant-detail.component.ts) setzten nie das arbeitet()-Signal — der [disabled]="arbeitet()"-Doppelklick-Schutz an beiden Buttons griff dadurch nie, schnelle Wiederholklicks konnten parallele Status-Requests auslösen; Busy-Flag vor dem Request gesetzt, in beiden Callbacks (Erfolg/Fehler) zurückgesetzt, analog dem bereits bestehenden Muster in wvAnlegen(). Veraltete 522-Testzahlen in Test-Uebersicht.md/Management-Summary.md/MVP-Scope.md (waren bei der MED-D-176/177-Runde übersehen worden) auf 523 nachgezogen. Durch die Auto-Merge-Race unanwendbar geworden (1): die von CodeRabbit vorgeschlagene Zusammenführung der zwei CHANGELOG-Einträge von PR #212 (MED-D-176+177) zu einem — ein erster Versuch, dies rückwirkend in der bereits gemergten MED-D-177-Zeile selbst zu korrigieren, war ein eigener append-only-Fehler dieser Runde (sofort erkannt, bevor gepusht, und zurückgesetzt: MED-D-177/CHANGELOG/Timesheet exakt auf den Original-Wortlaut von origin/main zurückgesetzt statt einer weiteren, in dieser Zeile still korrigierten Fassung) — genau der append-only-Fehlertyp, den MED-D-166/171/173 bereits einzeln behoben haben; die Ausnahme "PR-Nummer beim Schreiben unbekannt → Branch-Name" gilt nur, solange die PR noch offen ist, nicht rückwirkend nach dem Merge. Aus Konventionsgründen bewusst nicht übernommen (2): dieser Eintrag selbst um den Link auf die aktuelle Folge-PR ergänzen — dieselbe MED-D-144-Ausnahme (PR-Nummer beim Schreiben unbekannt → Branch-Name). CLAUDE.md-Status-Absatz kürzen — dieselbe, bereits mehrfach (MED-D-140/171/174) geprüfte und bestätigte Konvention, kein neuer Grund. Nicht reproduzierbar (1): Lastenheft.md-Testzahl korrigieren — verifiziert, dass diese Datei an keiner Stelle eine Testzahl nennt. +0 Vitest (523 unverändert, reiner Robustheits-/Doku-Fix), tsc + ng build grün, Doku-Konsistenz-Check grün. | Zweiter CodeRabbit-Review-Lauf auf PR #212 (nach dem Merge-Base-Fix) | client/src/app/mandant-detail.component.ts |
| MED-D-179 | 2026-07-22 | Datenmodell/Backend/Frontend · Akte (Stammdaten-Versionierung, Slice 1) | Alle Mandant-Stammdaten werden append-only + per-Mandant hash-verkettet versioniert (0.90.0→0.91.0, MINOR). Nutzer-Vorgabe aus der Design-Durchsicht des überarbeiteten Mockups "Akten-Cockpit 1a (Detail)": "Alle Stammdaten sollen immer versioniert sein, z. B. alte Anschriften — jede Aktualisierung erzeugt eine neue Version des Felds/Datensatzes" + "Erstmal alle Felder, dann konkrete Auswahl später". Umsetzung (Slice 1 = Mandant): neue append-only Entität StammdatenVersion (domain/model.ts) — vollständiger snapshot der versionierten Felder je Version, quelle/actor/angelegtAm + eigene per-Mandant Hash-Kette (vorherHash→hash, reine Funktionen in domain/stammdaten-version.ts, wiederverwenden domain/audit.ts#hashe); reines Modul mit snapshotVon/snapshotGleich/baueNaechsteVersion/pruefeVersionsKette/feldHistorie. Drei bewusste Architektur-Entscheidungen: (1) Dedizierte Struktur statt der Audit-Tabelle — api/audit-log.ts trägt die verbindliche Systemregel "details PII-arm, nur IDs/Status/Enums"; alte Anschriften/IBAN/Telefon dort einzutragen bräche diese Invariante für alle Konsumenten. Die neue Tabelle ist der eine sanktionierte PII-Ausnahmefall, sauber abgegrenzt; Verschlüsselung/Retention bleibt MED-KB-6. (2) Versionierung im Repo-Chokepoint updateMandant/createMandant, nicht je Service — alle 5 Schreibpfade (Berater-PATCH via service.aktualisieren, zwei Self-Service-/Formular-Rückübernahmen, Onboarding-Rücklauf, Neuanlage) laufen dort durch → lückenlose Erfassung (G-4) ohne Gap-Risiko; herkunft?: {actor,quelle} optional durchgereicht (Default berater/system, Self-Service-Pfade setzen self_service/onboarding). Reine lifecycleStatus/verantwortlich-Änderung erzeugt keine Version (Snapshot-Diff-Guard, kein Rausch-Bump). (3) Erst Mandant, dann Praxis + neue Felder Steuernummer/Steuer-ID — Steuer-IDs sind neue sensible PII (G-5/G-6/MED-KB-6); nicht unbemerkt in den Versionierungs-Slice geschmuggelt, sondern als begründeter Folgeschritt. Migration v44 (nur Tabelle + Index) + idempotenter App-Level-Backfill repo.backfillStammdatenV1() (in index.ts nach migrate, modul-flag-gated) seedet v1 für Bestands-Mandanten — bewusst App-Level statt SQL, weil die Hash-Kette SHA-256 verlangt. Neue Route GET /api/mandanten/:id/stammdaten-versionen (unter dem mandantScopeGuard). Client (mandant-detail.component.ts): "Stand: vN"-Pille + ein-/ausklappbarer Verlauf im Stammdaten-Rail (Feld-Änderungen je Version + Herkunfts-Label, G-3). Live gegen echtes (persistiertes) D1 verifiziert (wrangler dev): Migration meldet schema_version 44, Backfill geseedet: 20; PATCH einer E-Mail → v2 mit quelle=berater, actor=<dev-user>, v2.vorherHash == v1.hash (Kette intakt); lifecycle-only-PATCH erzeugt nachweislich keine v3. Design-Entscheidung im selben Zug (auf Nutzer-Rückfrage bestätigt): die IA des überarbeiteten Mockups (5 Tabs, "Basis-Informationen" als Default statt "Übersicht") wird übernommen — kehrt die MED-D-156-Übersicht-Konsolidierung bewusst um; Umsetzung der IA + der Modal-/Bankkonten-/Steuerfeld-Teile als eigene Folge-Slices (Konten-1:n mit SEPA-je-Konto ausdrücklich zurückgestellt). +12 Vitest (523→535, 47→49 Dateien), tsc + ng build grün, Doku-Konsistenz-Check grün. Nachlese CodeRabbit (PR #214, selber PR): (a) snapshotGleich faltet ''↔null korrekt (verhindert Rausch-v2 bei leer↔leer), (b) UNIQUE-Index (mandant_id, version) + Catch-Retry-Schleife gegen die TOCTOU-Race beim Versionsnummern-Vergabe (Muster wie createWiedervorlage/istUniqueConstraintFehler), (c) atomarer db.batch([update, insert]) — Mandant-Update und Versions-Insert können nicht mehr auseinanderlaufen, (d) Backfill markiert bei Fehler nicht als erledigt (Retry beim nächsten Request), (e) v1-Seed trägt den echten actor statt leer, (f) stammdaten_version-Lesezugriff auditiert (∈ ZUGRIFF_SENSIBEL, D-50) + Historie lazy geladen (G-6), (g) Lastenheft/MED-KB-6 um Zugriffs-/Retention-Klärung der Historie geschärft. | Nutzer-Vorgabe "Alle Stammdaten immer versioniert" (Design-Durchsicht "Mandanten-Akte verbessern") | server/src/domain/model.ts, server/src/domain/enums.ts, server/src/domain/stammdaten-version.ts, server/src/repo/repo.ts, server/src/repo/memory-repo.ts, server/src/repo/d1-repo.ts, server/src/db/schema.ts, server/src/db/migrate.ts, server/src/index.ts, server/src/api/service.ts, server/src/api/app.ts, server/src/api/onboarding-formular-service.ts, server/src/api/ausfuellformular-service.ts, client/src/app/api.service.ts, client/src/app/mandant-detail.component.ts |
| MED-D-180 | 2026-07-22 | Doku/Governance · Meisterwerk-Audit (MED-OP-REVIEW-1) | Doku-Meisterwerk-Audit auf v0.91.0 aufgefrischt (reines Doku-Dokument, keine Versionsänderung — Audit ist eine Momentaufnahme am aktuellen Stand, wie MED-D-132 beim Vorgänger). Anlass: die Stale-Regel (agents.md §6.7) — der bisherige Doku-Review stand auf Bezugspunkt v0.78.1, 13 Minor-Versionen zurück (≥10-Schwelle überschritten), mechanischer Check meldete ihn als veraltet; Nutzer beauftragte die Aktualisierung. Methode: vier parallele Verifikations-Durchsichten (17 offene Alt-Befunde B20–B32/B5/B14/B15/B17 gegen den aktuellen Stand; Stand-Stempel-/Testzahl-Sweep über ~40 Docs gegen die Grundwahrheit 0.91.0/535-Tests; Feature-Doku-Abdeckung der 6 größten Features seit v0.78.1 + ID-System-/Weltmodell-Konsistenz; Pyramidal-/Diagramm-/Landkarten-Stichprobe) + erneuter check-doc-consistency.sh. Kernbefund (positiv, Wirksamkeits-Kontrolle von Doku-Welle 4): 15/17 offene Alt-Befunde gelöst, keiner regressiv; die Wurzelursache (B18) schrumpfte von 5 gleichzeitig veralteten Einstiegs-Docs auf genau 1 (README.md) — die Versions-Stempel-Disziplin + der erweiterte Check haben über 13 Minor gehalten; alle 6 neuen Features vollständig dokumentiert (kein built-but-undocumented). Wichtige methodische Korrektur: ein Verifikations-Agent meldete fälschlich "MED-D-179 gar nicht dokumentiert" — per direktem grep widerlegt (Lastenheft §4.4, Feature-Liste, Test-Übersicht, Decision-Log, MED-KB-6 belegen die Doku); Befund verworfen, nur der bestätigte Rest (kein Weltmodell-Eintrag, kein Hash-Ketten-Diagramm) übernommen. Neuer Backlog B33–B40 → MED-OP-DOKU-7 (Doku-Welle 5, in HANDOFF §4). Gemäß agents.md §6.7.4 bleibt der Audit ein unverändertes Zeitdokument; die Befunde werden als OP überführt, nicht im Audit abgearbeitet. Vorgänger-Audits (v0.65.0, v0.78.1) bleiben über die Git-Historie der Datei als Zeitzeugen erhalten. | Stale-Regel MED-OP-REVIEW-1 (agents.md §6.7) + Nutzer-Auftrag "Doku-Review-Audit aktualisieren" | docs/betrieb/Doku-Review-2026-07.md, HANDOFF.md, CHANGELOG.md, docs/betrieb/Timesheet.md |
| MED-D-181 | 2026-07-22 | Doku/Tooling · Doku-Welle 5a (MED-OP-DOKU-7) | Doku-Welle 5a — Wahrheit wiederherstellen + Check-Loch schließen (B33/B34 aus dem Doku-Audit v0.91.0; keine Versionsänderung). B33: README.md trug als einziges Einstiegs-Doc noch einen veralteten Stand — Status 0.87.0→0.91.0, Frontier-Features nachgetragen (Akten-Cockpit MED-D-156, Mandat-Zeit MED-D-157, aktiver Timer MED-D-172, Wiedervorlagen MED-D-176, Stammdaten-Versionierung MED-D-179), Testzahl 442 Vitest in 42 Dateien→535/49; zusätzlich docs/README.md-Landkartenzeile zu Prozessmodell.md auf die aktuelle Achsen-Beschreibung korrigiert (die stillgelegte "Prozessphase"-Achse durch "Auftrag-Status je Beratungsauftrag" ersetzt, MED-D-151). B34: die Wurzelursache, warum README durchrutschte — scripts/check-doc-consistency.sh §8 verlangte "Stand/Status" und SemVer auf derselben Zeile, README trägt den Stempel aber als Überschrift ## Status + Prosa auf zwei Zeilen. §8 um Prong B (Überschriften-Stempel: ## Status/## Stand + erste back-quotierte SemVer in den Folgezeilen) und einen Testzahl-Abgleich (lebende Übersichten ↔ kanonische Zahl aus Test-Uebersicht.md, erste Nennung je Doc) erweitert. Regressionstest bestätigt (temporär README auf 0.87.0/442 zurückgesetzt): der gehärtete Check meldet jetzt beide Drifts (Stand-Stempel und Test-Zahl), die er zuvor nicht sah — dieselbe "grüner Check gibt falsche Sicherheit"-Lehre wie B19/B23, diesmal geschlossen. Kein Versions-Bump: reine Doku-/Tooling-Korrektur am Stand 0.91.0; ein PATCH-Bump würde einen Stempel-Cascade über ~9 lebende Docs erzwingen — genau die Drift-Fläche, die der Audit adressiert. Nachlese CodeRabbit (PR #216): neue Drift B41 gefunden — Akte-Struktur.md beschreibt noch die prozessgegliederte Vor-Cockpit-Akte (überholt durch MED-D-151/156); Landkartenzeile in docs/README.md entschärft + B41 als Currency-Pass-OP unter MED-OP-DOKU-7 aufgenommen (Doc-Überarbeitung eigener Slice). Zwei CodeRabbit-Findings bewusst nicht übernommen: CHANGELOG-PR-Link (MED-D-144-Konvention) und README-„live"→„deployed" (spiegelt CLAUDE.mds kanonisches „live in Produktion"; README allein zu qualifizieren erzeugte Doku-Inkonsistenz — projektweite Wortwahl ist Nutzer-Entscheidung). Doku: Decision-Log MED-D-181, HANDOFF §4 (MED-OP-DOKU-7 5a ✅ + B41), CHANGELOG, Timesheet. | Doku-Audit v0.91.0 B33/B34 (MED-D-180) | README.md, docs/README.md, scripts/check-doc-consistency.sh, HANDOFF.md, CHANGELOG.md, docs/betrieb/Timesheet.md |
| MED-D-182 | 2026-07-22 | Doku · Doku-Welle 5b (MED-OP-DOKU-7) | Doku-Welle 5b — Feature-Nachzieharbeit (B35/B36 aus dem Doku-Audit v0.91.0; keine Versionsänderung). B35 (G-8): StammdatenVersion (MED-D-179) war in Lastenheft/Feature-Liste/Test-Übersicht dokumentiert, fehlte aber im Weltmodell/Data-Dictionary — nachgetragen als Entität in der §2-Tabelle (append-only, per-Mandant hash-verkettet, eigene Identität version je Mandant), womit G-8 ("neue Entität zuerst ins Dictionary") auch für die jüngste Entität erfüllt ist. B36 (Landkarte): docs/architektur/Kosten.md (G-7/MED-OP-COST-1) war CLAUDE-Tiefenquelle, fehlte aber im docs/README.md-Architektur-Index — ergänzt (cost-pull-at-source-Kurzbeschreibung). Kein Versions-Bump (reine Doku-Nachzieharbeit am Stand 0.91.0). Doku: Decision-Log MED-D-182, HANDOFF §4 (MED-OP-DOKU-7 5b ✅), CHANGELOG, Timesheet. | Doku-Audit v0.91.0 B35/B36 (MED-D-180) | docs/architektur/Weltmodell-Data-Dictionary.md, docs/README.md, HANDOFF.md, CHANGELOG.md, docs/betrieb/Timesheet.md |
| MED-D-183 | 2026-07-22 | Doku · Doku-Welle 5c (MED-OP-DOKU-7) | Doku-Welle 5c — Diagramm-/BLUF-/Handwerks-Rest (B37–B40 aus dem Doku-Audit v0.91.0; keine Versionsänderung). B37 (doc↔code): ER-Diagramm-Feld in Dokumentenverwaltung-NextCloud.md von nextcloud_ref auf den echten Code-Feldnamen nextcloud_pfad (R3-F06, schema.ts) korrigiert + R2-Bezug (MED-D-61); Architektur-Uebersicht.md-Kante NextCloud von Schreib-"Fallback" auf "read-only-Sicht" (MED-D-58/61). B38 (pyramidal): BLUF-Zeile vor Compliance.md (DSGVO/revDSG · eIDAS/ZertES · GoBD/§147 AO + offene Härtung MED-KB-6/KB-3) und Risikoregister.md (28 Risiken, 18 vorrangig ≥6, Höchst-Score-9 = RISK-15 PII in US-KI-Diensten). B39 (ID-Kanon): <TOOL>-n-Präfix in Entwicklungsansatz.md §4.2 ergänzt (war in agents.md §3 vorhanden, in der Kurzform nicht). B40 (Visualisierung): Hash-Ketten-Diagramm (Mermaid flowchart, gegen den Mermaid-Validator geprüft) in Lastenheft.md §4.4 — GENESIS→v1→v2→v3, vorherHash→hash, analog Audit-Log.md. Mitgezogene Reparatur (forward, kein retroaktiver Log-Umschrieb): die Timesheet-Zeile 24 war durch den 5b-Edit als 7-Spalten-Zeile (5a+5b gemerged, fehlender Zeilenumbruch → MD056) gemergt; in zwei saubere 6-Spalten-Zeilen gesplittet (Inhalt verbatim), analog MED-D-178. Kein Versions-Bump (reine Doku am Stand 0.91.0). Rest von MED-OP-DOKU-7: nur noch B41 (Akte-Struktur.md Vor-Cockpit-Currency-Pass, eigener Slice). Doku: Decision-Log MED-D-183, HANDOFF §4 (MED-OP-DOKU-7 5c ✅), CHANGELOG, Timesheet. | Doku-Audit v0.91.0 B37–B40 (MED-D-180) + CodeRabbit-Nachlese PR #217 (Timesheet-Reparatur) | docs/architektur/Dokumentenverwaltung-NextCloud.md, docs/architektur/Architektur-Uebersicht.md, docs/betrieb/Compliance.md, docs/betrieb/Risikoregister.md, docs/konventionen/Entwicklungsansatz.md, docs/fachlich/Lastenheft.md, docs/betrieb/Timesheet.md, HANDOFF.md, CHANGELOG.md |
| MED-D-184 | 2026-07-22 | Doku · CodeRabbit-Nachlese Doku-Welle 5c (PR #218) | Vier echte Nachlese-Fixes (#218 mergte per Auto-Merge, bevor die Findings adressiert waren → forward-Fix, keine Versionsänderung): (1) Compliance-Overclaim behoben (Security) — die 5c-BLUF nannte "Retention" als Teil des implementierten Audit-Trails; Retention/Löschkonzept ist aber offen (OP-AUDIT-1) → umformuliert auf "hash-verkettet; Retention/Löschkonzept noch offen"; (2) Lastenheft-Hash-Ketten-Diagramm vorherHash→vorher_hash (snake_case, konsistent mit §4.4-Prosa Z.182 + R8-F10, Mermaid neu validiert); (3) Dokumentenverwaltung-NextCloud.md Z.14 "Dokumente werden in NextCloud abgelegt" → "Ablage produktiv auf R2 (MED-D-61); NextCloud nur read-only-Treiber" (konsistent mit dem ⚠️-Banner + ER-Diagramm desselben Docs); (4) HANDOFF MED-OP-DOKU-7 "Empfohlen: 5a zuerst" (nach 5a/5b/5c-Abschluss obsolet) auf rückblickende Lehre umformuliert. Alle vier auf lebenden Docs (kein append-only-Log). Rest MED-OP-DOKU-7: weiterhin nur B41. | CodeRabbit-Review PR #218 | docs/betrieb/Compliance.md, docs/fachlich/Lastenheft.md, docs/architektur/Dokumentenverwaltung-NextCloud.md, HANDOFF.md, CHANGELOG.md, docs/betrieb/Timesheet.md |
| MED-D-185 | 2026-07-22 | CI/Infra (Everything-as-Code-Record einer GitHub-Settings-Entscheidung) | CI läuft auf GitHub-hosted Runnern (CI_RUNNER=ubuntu-latest) — bewusst so belassen. Während Doku-Welle 5a verklemmte der self-hosted hot-Runner-Pool: ein pull_request-Run (#216) blieb 30+ min in queued ohne Runner-Zuweisung (0 Jobs dispatcht), war weder per API-cancel (2× HTTP 202, wirkungslos) noch per PR-close/reopen tötbar und hielt die Concurrency-Gruppe CI-refs/pull/216/merge → keine PR mergebar (RISK-29). Der Workflow wählt den Runner via runs-on: ${{ … || vars.CI_RUNNER || 'hot' }}; auf Nutzervorgabe wurde die Repo-Variable CI_RUNNER=ubuntu-latest gesetzt (GitHub-Settings, nicht im Repo — daher dieser Record, G-2/Audit-Trail), womit CI auf GitHub-hosted Runner umzog und sofort sauber durchlief (5a–5c + Nachlese, PRs #216–#219). Entscheidung (Nutzer, 2026-07-22): ubuntu-latest belassen — der Workflow ist voll cross-platform (Node 22, actions/setup-node, keine macOS-Abhängigkeit; Fork-Pfad nutzt ohnehin ubuntu-latest), und der self-hosted Wedge ist ein reales Blocker-Risiko. Rückweg zu hot (self-hosted) nur bei Kosten-/Policy-Grund: CI_RUNNER entfernen oder auf hot setzen. Hinweis: ein verklemmter Run braucht den Admin-force-cancel-Endpoint (regulärer cancel reicht nicht). Keine Repo-/Versionsänderung (die Variable lebt in GitHub-Settings). | Nutzerentscheidung "keep" (2026-07-22) nach dem self-hosted-Wedge in Doku-Welle 5a | docs/betrieb/Decision-Log.md, docs/betrieb/Risikoregister.md (RISK-29), HANDOFF.md, CHANGELOG.md, docs/betrieb/Timesheet.md |
| MED-D-186 | 2026-07-23 | Doku · B41 Akte-Struktur-Currency-Pass (MED-OP-DOKU-7) | docs/architektur/Akte-Struktur.md auf die aktuelle Cockpit-Akte umgeschrieben (letzter offener MED-OP-DOKU-7-Punkt B41; keine Versionsänderung). Das Doc beschrieb noch die Vor-Cockpit-prozessgegliederte Akte (§3 "Register = Prozessphasen", Phasen-Zeitstrahl, Aktendeckel mit mandant.prozessphase; §4-Datenmodell phase: ProzessPhase/PhaseReife/jePhase) — überholt durch MED-D-151 (Prozessphase-Achse + PROZESS_PHASE entfernt) + MED-D-156 (Akten-Cockpit-Redesign, tab-basiert). Komplett neu gefasst auf das Vollbild-3-Spalten-Cockpit, direkt aus client/src/app/mandant-detail.component.ts abgelesen: Person-Rail (Lebenszyklus-Pill + Sprung-Navigation) · Arbeitsbereich mit 6 arbeits-gegliederten Registern (Übersicht [uebersicht, Standard-Tab] · Mandate [auftraege] · Dokumente · Fristen & Aufgaben [wiedervorlagen, Stufe aktiv] · Stammdaten & Onboarding [stammdaten, Stufe onboarding] · Zeiterfassung [leistung]) · Kontext-Rail (Live-Timer · Aktenreife · letzte Aktivität); Verlauf/Audit (audit) ist kein Nav-Reiter, nur über den "Ganzen Verlauf öffnen →"-Link erreichbar. Kritische Korrektur zur teed-up Vorgabe (die von "5 Tabs, Basis-default" ausging): die live-IA sind 6 Tabs mit uebersicht-Default, nicht die in MED-D-179 entschiedene, aber nicht gebaute 5-Tab-"Basis"-Default-IA — deren Umsetzung ist der offene Punkt MED-OP-AKTE-2. Die Doku beschreibt bewusst den gebauten Stand, um keine Doku↔Code-Drift einzuführen (das war der Ursprung von B41). §4-Aktenreife-Datenmodell auf den echten Code (domain/aktenreife.ts) nachgezogen: AktenreifePunkt.stufe: LifecycleStatus (war phase: ProzessPhase), StufeReife/jeStufe (war PhaseReife/jePhase), AktenreifeKategorie-Alias ergänzt. Reife-Ring-Wegfall (MED-D-164/MED-OP-REIFE-1) als Anzeige-Hinweis vermerkt — das Datenmodell bleibt unberührt, nur die visuelle Ring-Darstellung ist raus. Querverlinkt auf MED-D-151/156/95/172/80. Danach den "Vor-Cockpit"-Hinweis in der docs/README.md-Akte-Struktur-Landkartenzeile entfernt (durch die jetzt aktuelle Beschreibung ersetzt). MED-OP-DOKU-7 damit vollständig geschlossen (B33–B41). check-doc-consistency.sh grün. | Teed-up B41 aus MED-D-185; behebt die durch MED-D-151/156 entstandene Doku↔Code-Drift der Akten-Struktur-Doku | docs/architektur/Akte-Struktur.md, docs/README.md, HANDOFF.md, CHANGELOG.md, docs/betrieb/Timesheet.md |
| MED-D-187 | 2026-07-23 | Doku · CodeRabbit-Nachlese B41 (PR #222) | CodeRabbit-Review zu PR #222 (B41/MED-D-186): 4 von 8 Befunden echt und forward behoben (#222 mergte per Auto-Merge, bevor die Findings adressiert waren — dasselbe Timing wie MED-D-158/178/184; forward-Fix als eigene Folge-PR, keine Versionsänderung). Echt behoben: (1) MED-D-145-Verstoss (gerade Anfuehrungszeichen) — meine Akte-Struktur.md-Neufassung und 4 eigene, im selben PR ergaenzte Log-Zeilen (Decision-Log/HANDOFF/CHANGELOG/Timesheet) nutzten deutsche typografische Oeffner statt gerader ASCII-Quotes; normalisiert. Bei den bereits gemergten Log-Zeilen ausschliesslich exakt-Match auf meine eigenen #222-Zeilen, inhaltserhaltend (nur das Quote-Zeichen), keine Alt-Zeile angefasst — genau das inhaltserhaltende Muster aus MED-D-158, abgegrenzt vom verbotenen substanziellen Log-Umschrieb (MED-D-166/171/173/178). (2) MD028 (Leerzeile in Blockquote) in Akte-Struktur.md — benachbarte Blockquotes mit >-Zeile ueberbrueckt (Kopf-Block + §3 Dokumente/Zeiterfassung-Block). (3) Audit-Navigations-Widerspruch (§3): der Einleitungstext liess audit als Aktenreife-Sprungziel erscheinen — real ist audit nicht in SPRUNGZIEL_REGISTER, sondern wird nur ueber den Kontext-Rail-Link per waehleReg('audit') gesetzt; Text entwidersprochen (Sprungziele → einer der sechs Reiter; audit = Sidebar-Link, gleicher Mechanismus). (4) SBOM/Runtime-Topologie-Querverweis auf Architektur-Uebersicht.md in den Kopf-Block ergaenzt (Verweis statt Duplikat; dieses Doc = UX-/IA-Struktur, jenes = Laufzeit-Topologie). Bewusst nicht uebernommen: Timesheet-Wochenaggregat KW30 — das Wochen-Rollup ist explizit "vorlaeufig"/aufgeschoben (OP-PM-1 Log-Hygiene, glaettet nach Merge-Staus), und meine Session-Zeile folgt derselben Konvention wie die Nachbarzeilen derselben Woche (inkl. der 07-23-risk-count-fix-Zeile); kein durch diesen PR eingefuehrter Befund. Die uebrigen Sammel-/Autofix-Vorschlaege sind Teilmengen der vier behobenen. check-doc-consistency.sh gruen. | CodeRabbit-Review PR #222 (nach Auto-Merge → forward-Fix) | docs/architektur/Akte-Struktur.md, docs/betrieb/Decision-Log.md, HANDOFF.md, CHANGELOG.md, docs/betrieb/Timesheet.md |
| MED-D-188 | 2026-07-23 | Architektur/Plan · Akten-Cockpit-Redesign (MED-OP-AKTE-2) | Voller Slice-Plan fuer das Akten-Cockpit-Redesign angelegt (docs/architektur/Akten-Cockpit-Redesign.md; reines Plan-/Doku-Dokument, keine Versionsaenderung). Der High-Fidelity-Handoff "Akten-Cockpit 1a (Detail)" (via DesignSync-MCP aus dem Projekt "Mandanten-Akte verbessern" gezogen; verbindliche Spec = akte-patterns.md, 10 Komponenten mit Massen/Tokens/Zustaenden) baut die interne Akte zu einem fokussierten Cockpit um: 5 Reiter (Basis-Informationen [Default] · Mandate · Alle Dokumente · Fristen & Aufgaben · Praxen) + 4 Overlays (Mandat · Zeiten · Stammdaten · Unterschriften-Assistent) statt der heutigen 6 Reiter. Da das ein Mehr-PR-Programm ist, vorab drei Weggabelungen per AskUserQuestion entschieden (Nutzer, 2026-07-23): (1) voller Slice-Plan zuerst (dieses Dokument), dann top-down; (2) Unterschriften-Assistent jetzt gegen die bestehenden Fake-Provider bauen (echte DocuSign/E-Mail-Adapter, MED-KB-5/OP-DM-8, spaeter eingehaengt; Versand sichtbar als Attrappe halten); (3) 1:n-Bankkonten-Modell jetzt bauen (kehrt die Zurueckstellung aus MED-D-179 bewusst um). Slice-Reihenfolge (je PR, Abhaengigkeit): S1 IA-Fundament & Overlay-Shell (Client-only, loest MED-OP-AKTE-2 ein, LifecycleRing) → S2 Dokument-Zustandsmaschine (StatusSlider/RequirementCheckbox/DocumentRow, Ablauf-Auto-Rueckfall, Fortschritt nur Erforderliches; Enum-Flags versendet/nicht_erforderlich) → S3 1:n Bankkonten + SEPA (neue Entitaet, Migration/Repo/Service/Routen/Tests, BankRow + Swipe-to-Archive) → S4 VersionedField-Ausbau + Self-Service-Karte → S5 Unterschriften-Assistent (3 Schritte + Vor-Ort-Strecke, SES/AES/QES, Write-back gegen die Fakes) → S6 Feinschliff/Abnahme (TaskCard, Wording zentral, Motion/reduced-motion, Screens 01-17). Compliance vermerkt: eIDAS SES/AES/QES je Dokumenttyp begruenden (OP-SIGN-1), Bank-PII G-5/G-6/MED-KB-6, Zero-Trust unveraendert. Mermaid-IA-Diagramm gegen den Validator geprueft (valid). Keine Code-/Schema-Aenderung in diesem PR. | Nutzer-Auftrag "Implement Akten-Cockpit 1a (Detail).dc.html" + Vorgabe "bei Abweichungen entscheiden lassen"; drei AskUserQuestion-Entscheidungen | docs/architektur/Akten-Cockpit-Redesign.md, docs/README.md, docs/architektur/Akte-Struktur.md, HANDOFF.md, CHANGELOG.md, docs/betrieb/Timesheet.md |
| MED-D-189 | 2026-07-23 | Doku · CodeRabbit-Nachlese Slice-Plan (PR #224) | CodeRabbit-Review zu PR #224 (Akten-Cockpit-Slice-Plan/MED-D-188): 4 von 5 Befunden echt, forward behoben (#224 mergte per Auto-Merge vor den Findings — Timing wie MED-D-158/178/184/187; eigene Folge-PR, keine Versionsaenderung). Alle Fixes auf lebenden Docs (Plan-Doc + HANDOFF-Statuszeile), kein append-only-Log-Umschrieb. Echt behoben: (1) MD028 (Leerzeile im Einleitungs-Blockquote von Akten-Cockpit-Redesign.md) — die drei Kopf-Notizen mit >-Zeile zu einem Block ueberbrueckt. (2) HANDOFF MED-OP-AKTE-2 veraltet (Major): die Zeile behauptete "Slice 1 gebaut" und Bankkonten "bewusst zurueckgestellt" — beides widersprach dem neuen Plan (Plan-S1 = IA-Fundament, noch offen; Bank jetzt S3). Umformuliert: nur der MED-D-179-Baustein ist gebaut, Plan-Slices S1-S6 offen; Bank-Zurueckstellung aufgehoben → S3. (3) SBOM/Runtime-Topologie-Querverweis (Major) auf Architektur-Uebersicht.md in den Kopf-Block ergaenzt (Verweis statt Duplikat, analog Akte-Struktur.md). (4) S3-Backfill/Kompatibilitaet (Major): neuer Abschnitt "S3-Backfill & Rueckwaerts-Kompatibilitaet" — verlustfreies, zwei-phasiges Mapping ibanPrivat/iban → je ein Bankkonto (Inhaber/Kontext aus Quelle, leere Felder erzeugen kein Konto), Alt-Felder bleiben lesbar bis bestaetigter Umstellung (kein sofortiger DROP), idempotenter App-Level-Backfill (MED-OP-MIGRATE-1), Abnahmekriterien (keine Waise). Bewusst nicht uebernommen: CHANGELOG-PR-Link #224 — MED-D-144-Konvention (Eintraege bei PR-Erstellung nutzen den Branch-Namen, Link nicht nachtraeglich ergaenzt; der Rest der Datei folgt dem). check-doc-consistency.sh gruen. | CodeRabbit-Review PR #224 (nach Auto-Merge → forward-Fix) | docs/architektur/Akten-Cockpit-Redesign.md, HANDOFF.md, docs/betrieb/Decision-Log.md, CHANGELOG.md, docs/betrieb/Timesheet.md |
| MED-D-190 | 2026-07-23 | Doku · CodeRabbit-Nachlese Slice-Plan (PR #225) | CodeRabbit-Review zu PR #225 (Slice-Plan-Nachlese/MED-D-189): 2 echte Migrations-Praezisierungen, forward behoben (#225 mergte per Auto-Merge vor den Findings; eigene Folge-PR, keine Versionsaenderung, reines Plan-Doc). Beide Befunde schaerfen den in MED-D-189 ergaenzten S3-Backfill-Abschnitt von Akten-Cockpit-Redesign.md — die richtige Stelle, da S3 daraus gebaut wird. (1) Backfill crash-/concurrency-sicher (Major): mein Entwurf markierte den Traeger "erst nach Erfolg als erledigt" — ein Absturz zwischen Insert und Markierung oder zwei parallele Laeufe koennten doppelte Bankkonto-Zeilen erzeugen. Umgestellt auf DB-erzwungene Eindeutigkeit ueber einen stabilen Herkunfts-Schluessel (traeger_typ+traeger_id+quelle='backfill') + UNIQUE-Index + ON CONFLICT DO NOTHING/Upsert bzw. transaktionaler Claim (Muster des MED-D-179-Backfills: UNIQUE + Catch-Retry + atomarer db.batch); Tests fuer abgebrochenen und nebenlaeufigen Lauf gefordert. ID-Konsistenz: MED-OP-MIGRATE-1 gilt hier ausdruecklich nur fuer die Deploy-Ordnung (nicht fuer die Backfill-Idempotenz) — der frueher missverstaendliche Verweis ist entwidersprochen (CodeRabbit-Hinweis: MED-OP-MIGRATE-1 beschreibt den Schema-Runner). (2) Abnahme-Matrix erweitert (Major): +leere Felder erzeugen kein Konto, +Initialzustand neu/sepa_gueltig=false, +identische IBANs an verschiedenen Traegern bleiben getrennt, +Doppel-/Crash-Lauf ohne Duplikate. check-doc-consistency.sh gruen. | CodeRabbit-Review PR #225 (nach Auto-Merge → forward-Fix) | docs/architektur/Akten-Cockpit-Redesign.md, docs/betrieb/Decision-Log.md, CHANGELOG.md, docs/betrieb/Timesheet.md |
| MED-D-191 | 2026-07-23 | Frontend/UX · Akten-Cockpit-Redesign Slice S1 (MED-OP-AKTE-2) | S1 IA-Fundament & Overlay-Shell gebaut (0.91.0→0.92.0, MINOR; erster Bau-Slice des Akten-Cockpit-Redesign-Programms MED-D-188). Reine Client-Aenderung an mandant-detail.component.ts + styles.css. Reiter 6→5: Basis-Informationen (Standard-Tab, aktiv-Default 'basis'; buendelt Jetzt-dran + Onboarding + Self-Service) · Mandate · Alle Dokumente · Fristen & Aufgaben · Praxen (eigener Reiter, aus dem alten "Stammdaten & Onboarding"-Tab geloest). Generische Overlay-Shell (.mw-scrim/.mw-overlay-panel/.mw-overlay-head, akte-patterns §2.4: Scrim + backdrop-filter, Panel min(760px,100%), Radius 16px; ESC via HostListener + Scrim-Klick schliessen): die vormaligen Reiter Stammdaten und Zeiterfassung sind jetzt Overlays (overlay-Signal 'stammdaten'|'zeiten'|null), geoeffnet ueber den Rail-Link "bearbeiten →" bzw. den Timer-Link "Erfasste Zeiten oeffnen →". LifecycleRing (akte-patterns §2.10): der Person-Avatar traegt jetzt einen 5-Segment-Conic-Ring (ab 6-Uhr im Uhrzeigersinn, erledigt=gruen/aktuell=accent/offen=bd2, ringGradient()) — die alte flache 5-Segment-Leiste entfaellt. Bewusst innerhalb S1 zurueckgestellt: Mandat-Overlay (haengt am Rework der Mandate-Ansicht) und Assistent-Overlay (= Slice S5) — Mandate bleibt vorerst ein Reiter; im Plan vermerkt. tsc + ng build gruen (nur der vorbestehende NG8102-Hinweis an mandant-detail.component.ts:362, nicht angefasst); check-doc-consistency.sh gruen. Umsetzung: die mechanischen Template-Edits via Coding-Subagent gegen eine praezise Spec (Erfolgskriterium Build-gruen), Design-kritische Teile (REGISTER/Overlay-Shell/Ring) direkt; Diff reviewt. Naechster Slice: S2 (Dokument-Zustandsmaschine). | Nutzer-Startsignal "go" fuer S1 (aus dem Plan MED-D-188); drei Vorentscheidungen aus MED-D-188 gelten weiter | client/src/app/mandant-detail.component.ts, client/src/styles.css, server/src/version.ts, docs/architektur/Akten-Cockpit-Redesign.md, Feature-Liste, HANDOFF, CHANGELOG, Timesheet, Stand-Stempel (9 Dateien) |
| MED-D-192 | 2026-07-23 | Frontend/UX · Akten-Cockpit-Redesign Slice S2 (MED-OP-AKTE-2) | S2 Dokument-Zustandsmaschine gebaut (0.92.0→0.93.0, MINOR; zweiter Bau-Slice, auf S1 gestapelt). Reine Client-Aenderung / UI-Mapping — keine Server-/Enum-/Schema-Aenderung (Nutzer-Default aus der Design-Konflikt-Klaerung: Server-Enums angefordert/erhalten/geprueft/abgelaufen/entfaellt bleiben, das Design-Wording wird clientseitig darueber abgebildet). Neue wiederverwendbare Komponente AkteStatusSliderComponent (md-status-slider, akte-patterns §2.1): dreiwertiger Pillenschalter Fehlt·Erhalten·Geprueft — ersetzt die vom Design verbotenen Woerter "Noetig"/"Da" (§1). Eingesetzt (a) an den Onboarding-Items (ersetzt den 4-Tasten-Umschalter) + neue RequirementCheckbox (mw-reqbox, §2.2): erforderlich ↔ entfaellt, "vorerst nicht erforderliche" Items ans Ende unter den Trenner "Vorerst nicht erforderlich", Slider ausgeblendet; und (b) an den Ablage-Dokumenten (ersetzt das Status-<select>), plus Ablauf-Chip: abgelaufen → roter Chip, Slider zeigt "Fehlt". Fortschritt zaehlt nur Erforderliches — bereits serverseitig erfuellt (domain/progress.ts schliesst entfaellt aus, verifiziert, kein Server-Change). Toter Code entfernt (ITEM_TASTEN, DOKUMENT_STATI, itemTasteAktiv, dokStati). Bewusst zu S5 verschoben (Assistent-abhaengig): das "versendet/wartet auf Signatur"-Pill, "Zur Unterschrift →" und Fremdformular-Zustaende der DocumentRow-Zustandsmaschine (§2.3). tsc + ng build gruen (nur vorbestehender NG8102-Hinweis), Server-Vitest 535/535 unveraendert (kein Server-Change), check-doc-consistency.sh gruen. Bau: StatusSlider-Komponente + CSS direkt, die zwei Integrationen via Coding-Subagent gegen Build-gruen-Spec, Diff reviewt. Naechster Slice: S3 (1:n-Bankkonten + SEPA). | Nutzer "Weiter geht es mit der Design-Uebernahme"; Design-Konflikt (Wording/Enum) per Default UI-Mapping aufgeloest (reversibel) | client/src/app/akte-status-slider.component.ts (neu), client/src/app/mandant-detail.component.ts, client/src/styles.css, server/src/version.ts, Feature-Liste, HANDOFF, CHANGELOG, Timesheet, Stand-Stempel (9 Dateien) |
| MED-D-193 | 2026-07-23 | Governance/Way-of-Working · Design-Sync-Konvention | Stehende Regel verankert: bei Uebernahme eines Designs aus Claude Design werden Diskrepanzen/Konflikte mit frueheren Entscheidungen dem Nutzer zur Klaerung vorgelegt, nicht einseitig aufgeloest. Nutzer-Vorgabe 2026-07-23 ("In case of discrepancies or conflicts with earlier decisions, please ask me to clarify"). Als Konvention in docs/konventionen/agents.md (Design-Sync-Abschnitt) festgehalten (Everything-as-Code, G-2) — gilt sessionuebergreifend. Praezedenz: die drei MED-D-188-Weggabelungen + die S2-Enum/Wording-Frage wurden so entschieden. Auf Nutzerwunsch in den S2-PR gefaltet (kein Extra-PR). | Nutzer-Vorgabe "ask me to clarify on design conflicts" + Wahl (a) "an den naechsten Slice-PR haengen" | docs/konventionen/agents.md, docs/betrieb/Decision-Log.md |
| MED-D-194 | 2026-07-23 | Frontend/Doku · CodeRabbit-Nachlese S2 (PR #228) | CodeRabbit-Review zu PR #228 (S2/MED-D-192): 8 Befunde, alle behoben (#228 mergte per Auto-Merge, bevor die Findings adressiert waren — dasselbe Timing wie MED-D-158/178/184/187/189; forward-Fix als Folge-PR, keine Versionsaenderung). Echt behoben — Code (2 Major): (1) Race bei Status-Schreibvorgaengen — statusSetzen/dokStatusSetzen setzten arbeitet() nicht, obwohl Slider/Checkbox [disabled]="arbeitet()" sind; schnelle Wiederholklicks konnten ueberlappende Writes + veraltete laden()-Refreshes ausloesen. Busy-Guard ergaenzt (Set vor dem Request, Reset in Erfolg UND Fehler; Re-Entry-Guard) — Muster wie MED-D-178. (2) Erforderlich-Pille aus dem mutablen Status — die "Pflicht"/"optional"-Pille kam aus dem immutablen it.pflicht; ein per RequirementCheckbox auf entfaellt gesetztes Item zeigte weiter "Pflicht". Behoben, ohne optionale Items faelschlich als "Pflicht" zu labeln (CodeRabbits woertlicher Fix haette das getan): die Katalog-Pille wird nur noch solange erforderlich gezeigt; bei "vorerst nicht erforderlich" traegt das der Ersatztext. A11y/CSS: (3) aria-label an der RequirementCheckbox (nur aria-pressed + ✓ gab keinen Namen). (4) .mw-reqbox-Klickflaeche auf ≥24×24 vergroessert (visueller Kasten bleibt 16×16 via ::before), MED-D-119-Touch-Target. Doku: (5) Plan-Doc S2-Zeile Backend ja→nein (Client/UI-Mapping) + RequirementCheckbox/Trenner als onboarding-only praezisiert. (6) agents.md-Footer "Letztes Update" auf 2026-07-23. (7) Management-Summary.md Z.113 Rest-Stempel 0.91.0→0.93.0. (8) HANDOFF MED-OP-AKTE-2-Kopf "S1–S6 noch offen"→"S3–S6 noch offen". tsc+ng build gruen, check-doc-consistency.sh gruen. | CodeRabbit-Review PR #228 (nach Auto-Merge → forward-Fix) | client/src/app/mandant-detail.component.ts, client/src/styles.css, docs/architektur/Akten-Cockpit-Redesign.md, docs/konventionen/agents.md, docs/produkt/Management-Summary.md, HANDOFF.md, docs/betrieb/Decision-Log.md, CHANGELOG.md, docs/betrieb/Timesheet.md |
| MED-D-195 | 2026-07-23 | Backend/Datenmodell · Akten-Cockpit-Redesign Slice S3a (MED-OP-AKTE-2) | S3a (Backend-Haelfte von S3) gebaut: 1:n-Bankkonto-Entitaet + crash-/nebenlaeufigkeitssicherer Backfill (0.93.0->0.94.0, MINOR; dritter Bau-Slice, hebt die frueher zurueckgestellte 1:n-Bank-Entscheidung MED-D-179 auf — beschlossen in MED-D-188). Neue Entitaet Bankkonto (R1-F33): inhaber · iban (normalisiert, domain/iban.ts) · zeichnungsberechtigt · zwei getrennte Achsen pruefstatus (KONTO_PRUEFSTATUS = neu/geprueft/archiviert, berater-getrieben) und sepaGueltig · praxisId (Kontext Gesellschaft oder null=privat) · quelle/quellSchluessel. Kein Loeschen — Archivieren via pruefstatus (append-only, G-4). Domain (model.ts/enums.ts) + Schema (bankkonto-Tabelle) + Migration v45 (Tabelle + UNIQUE-Index auf quell_schluessel) + Repo (Interface + memory + d1, CRUD) + BankkontoService (audit, PII-arm) + Routen (GET/POST /api/mandanten/:id/bankkonten scope-guarded, PATCH /api/bankkonten/:id). Verlustfreier, zwei-phasiger Backfill (repo.backfillBankkonten, App-Level nach migrate in index.ts, Muster MED-D-179): je nicht-leerem Alt-Feld mandant.ibanPrivat/praxis.iban genau ein Konto mit stabilem quellSchluessel (mandant:<id>/praxis:<id>); Idempotenz + Crash-/Concurrency-Sicherheit traegt der DB-UNIQUE-Index + ON CONFLICT DO NOTHING + .returning()-Zaehlung (nicht ein "erledigt"-Flag); Alt-Felder bleiben lesbar erhalten (kein DROP in v45 — Phase 2 spaeter). +12 Vitest (CRUD + Validierung + Idempotenz/Concurrency/Crash-Backfill + identische-IBAN-kein-Dedup); voller Server-Lauf 535->547 gruen. Live gegen wrangler dev/miniflare verifiziert: Migration bootet, Backfill angelegt:2, Zweit-Boot idempotent (0), manuelle CRUD-Routen + 400-Validierung, Alt-Felder lesbar. Bewusst als S3a abgetrennt: die BankRow-UI (Swipe-to-Archive, akte-patterns §2.6) folgt als S3b (reine Client-Anbindung). MED-KB-6 (Verschluesselung/Retention Bank-PII) offen. | Nutzer "weiter mit s3"; 1:n-Bankmodell bereits via MED-D-188 nutzerentschieden; Backfill-Spec Akten-Cockpit-Redesign.md §S3 (MED-D-189/190) | server/src/domain/model.ts, server/src/domain/enums.ts, server/src/db/schema.ts, server/src/db/migrate.ts, server/src/repo/repo.ts, server/src/repo/memory-repo.ts, server/src/repo/d1-repo.ts, server/src/index.ts, server/src/api/bankkonto-service.ts (neu), server/src/api/app.ts, server/src/api/bankkonto.test.ts (neu), server/src/version.ts, Feature-Liste, Test-Uebersicht, HANDOFF, CHANGELOG, Timesheet, Stand-Stempel |
| MED-D-196 | 2026-07-23 | Frontend/UX · Akten-Cockpit-Redesign Slice S3b (MED-OP-AKTE-2) | S3b (UI-Haelfte von S3) gebaut: BankRow-UI mit Swipe-to-Archive (0.94.0->0.95.0, MINOR; schliesst S3 ab). Reine Client-Anbindung an die S3a-Routen — kein Server-Change. Neue wiederverwendbare AkteBankrowComponent (md-bankrow, akte-patterns §2.6): je Bankkonto eine Zeile mit Inhaber · Kontext (privat/Praxis, aus praxisId aufgeloest) · IBAN in 4er-Gruppen · Zeichnungsberechtigung; zwei getrennte Bedien-Achsen als direkte Controls: Pruefstatus-Slider (Neu/Geprueft — Archiviert laeuft NICHT ueber den Slider) + SEPA-Toggle. Swipe-to-Archive: Pointer-Drag der Zeilenflaeche nach links; jenseits der Schwelle (halbe Breite) committet die Geste direkt das Archivieren (Undo-Toast des Aufrufers als Sicherheitsnetz) — kein Zwei-Schritt-Reveal. Design-Anpassung (MED-D-193, dokumentiert): da die interne Akte ein Desktop-/Maus-Workflow ist und ein rein hinter der Zeile verstecktes Archivieren-Button fuer Maus/Tastatur unerreichbar waere, ergaenzt ein dezenter, immer sichtbarer Desktop-/Tastatur-Archivieren-Button die Wisch-Geste (beide Pfade → archiviere); die rote Flaeche hinter der Zeile bleibt als visuelles Wisch-Feedback. Peek-Teach deutet die Geste einmalig beim Oeffnen des Stammdaten-Overlays an (nicht bei jedem laden()-Reload — sonst nudgte die Zeile bei jedem Toggle; als echter Bug gefunden+behoben). Archivierte Konten rendern schreibgeschuetzt/gedimmt unter einem "Archiviert"-Trenner (append-only, kein Loeschen, G-4). ApiService um bankkonten/bankkontoAnlegen/bankkontoAendern + Bankkonto/KontoPruefstatus-Typen erweitert. Die Alt-IBAN-Felder (privat/je Praxis) bleiben im Overlay mit Hinweis auf die neue gefuehrte Liste (zwei-phasig, MED-D-195). ng build gruen (nur vorbestehende NG8102-Hinweise), Server-Vitest 547/547 unveraendert (kein Server-Change), check-doc-consistency.sh gruen. Live gegen wrangler dev + Playwright verifiziert (11/11): 2 BankRows, IBAN-4er-Format, SEPA-Toggle→server, Pruefstatus→server, Anlegen→3 Konten, Desktop-Archiv + Swipe-Geste je 1 Konto archiviert, append-only (kein DELETE, weiter 3 Datensaetze), 0 Konsolenfehler. Bezug akte-patterns.md §2.6: das Handoff-Projekt "Mandanten-Akte verbessern" war in dieser Session nicht in der beschreibbaren DesignSync-Projektliste; BankRow wurde getreu aus dem in Akten-Cockpit-Redesign.md §4/§5 festgehaltenen Spec + dem Schwester-Muster S2-StatusSlider + World-2-Tokens gebaut. S3 damit vollstaendig; naechster Slice S4. | Nutzer "3b - baue sukzessive weiter, pr und merge automatisch bis das Design vollstaendig umgesetzt ist"; Desktop-Archiv-Ergaenzung als begruendete Design-Anpassung (MED-D-193) | client/src/app/akte-bankrow.component.ts (neu), client/src/app/mandant-detail.component.ts, client/src/app/api.service.ts, client/src/styles.css, server/src/version.ts, Feature-Liste, HANDOFF, CHANGELOG, Timesheet, Akten-Cockpit-Redesign.md, Stand-Stempel |
| MED-D-197 | 2026-07-23 | Frontend/UX · Akten-Cockpit-Redesign Slice S4 (MED-OP-AKTE-2) | S4 gebaut: VersionedField mit Feld-Historie (0.95.0->0.96.0, MINOR). Reine Client-Anbindung, kein Server-Change. Kritische Recherche vorab (True North): §2.7/§2.8 waren groesstenteils schon gebaut (MED-D-179 Stammdaten-Versionierung inkl. flacher Versionsliste + Stand: vN-Pille in der Rail; MED-D-170 Self-Service-Link-Karte kopieren/uebernehmen/neu). Der genuine Delta ist die per-Feld-Historie (das eigentliche VersionedField aus §2.7) + die Versions-Pille im Overlay-Kopf — also gezielt nur das Fehlende gebaut, nicht Bestehendes nachgebaut. Neue wiederverwendbare AkteVersionedFieldComponent (md-versioned-field, akte-patterns §2.7): je versioniertes Feld (Anzeigename · E-Mail · Telefon · Geburtsdatum · Strasse/PLZ/Ort atomar (G-8) · CRM) aktueller Wert + vN-Pille (Version der letzten Aenderung dieses Feldes, keine Pille wenn nur v1) → aufklappbare Feld-Historie genau dieses Feldes (jede Version, in der sich der Wert aenderte, mit Wert/Zeit/Herkunft). Die Historie wird client-seitig aus den bereits geladenen, hash-verketteten MED-D-179-Snapshots abgeleitet (kein zusaetzlicher Server-Aufruf, G-2, kein Doppel-State); stammVersionen wird dafuer eager in laden() geladen (vorher lazy beim Rail-Toggle → Pille erschien erst nach Klick). Versions-Pille jetzt auch im Overlay-Kopf (Stand: vN). Das alte Read-only-Feld-Grid im Overlay durch die VersionedFields ersetzt; die Alt-IBAN-Felder + Bankverbindungen (S3b) bleiben unveraendert. §2.8 Self-Service-Karte: als erfuellt bewertet — die Link-Verwaltung (kopieren/uebernehmen/neu) ist MED-D-170 (Rail-Karte + md-akte-einladungen), customer-hochgeladene Dokumente erscheinen im Reiter "Alle Dokumente" (S2); eine Duplizierung in die Stammdaten-Karte waere Redundanz (G-2) → bewusst nicht dupliziert, in der Doku begruendet. Bug gefunden+behoben: ein title-Attribut mit einem literalen " (in "vN") schloss das HTML-Attribut vorzeitig → NG5002-Build-Fehler; entfernt (auch eine HTML-Attribut-Variante der MED-D-145-Quote-Disziplin). ng build gruen, Server-Vitest 547/547 unveraendert (kein Server-Change), check-doc-consistency.sh gruen. Live gegen wrangler dev + Playwright verifiziert (9/9): Kopf-Pille Stand: v4, 8 VersionedFields, E-Mail zeigt aktuellen Wert + v3-Pille, Klick → Feldhistorie zeigt v3/v2-Werte, CRM v4-Pille, nie geaendertes Telefon ohne Pille, 0 Konsolenfehler. S5 (Unterschriften-Assistent) als naechstes. | Nutzer "baue sukzessive weiter, pr und merge automatisch bis das Design vollstaendig umgesetzt ist"; §2.8-als-erfuellt + §2.7-Delta-Scoping kritisch begruendet (True North) | client/src/app/akte-versioned-field.component.ts (neu), client/src/app/mandant-detail.component.ts, client/src/styles.css, server/src/version.ts, Feature-Liste, HANDOFF, CHANGELOG, Timesheet, Akten-Cockpit-Redesign.md, Stand-Stempel |
| MED-D-198 | 2026-07-23 | Frontend+Backend/UX · Akten-Cockpit-Redesign Slice S5 (MED-OP-AKTE-2) | S5 gebaut: Unterschriften-Assistent gegen die Fake-Provider (0.96.0->0.97.0, MINOR; groesster verbleibender Slice, Server+Client). Kritische Bestandsaufnahme vorab (Explore-Subagent, True North): die Signatur-Basis existiert (SignaturVorgang, SES/AES/QES-Niveau + Rechtsmatrix, SignaturService.anfordern/abgleich, Fake-Provider + markiereSigniert, Routen, Write-back Dokument->unterschrieben) -> nur den Delta gebaut. Neue AkteUnterschriftenAssistentComponent (md-unterschriften-assistent, §2.5) als Overlay (neuer Key signatur): 3 Schritte Pruefen/Versenden/Verfolgen + Vor-Ort-Strecke; eIDAS-Slider SES/AES/QES (automatisch aus der Rechtsmatrix je Dokumenttyp oder manuell; AES/QES verlangen Ident-Check, CH: ZertES); Sammel-Umschlag als client-seitige Buendelung mehrerer anfordern-Aufrufe (redesign §7, kein Envelope-Modell im Backend); Frist -> bestehende Wiedervorlage; durchgehend sichtbarer Attrappe-Banner (MED-KB-5, kein Echt-Eindruck, OP-SIGN-1). Einstiege: DocumentRow, Dokumente-Tab, BankRow "SEPA einholen" (setzt bei Abschluss sepaGueltig). Server-Delta (minimal+sicher): optionaler SignaturProvider.abschliessenDemo?-Seam (nur der Fake) + SignaturService.vorOrtAbschluss (Riegel: echter Provider -> nicht_verfuegbar, echter Vorgang nie faelschbar) + Route POST /api/signaturen/:id/vor-ort-abschluss (409 bei echtem Provider) + Niveau-Override an der Anfordern-Route. Write-back laeuft in den bestehenden abgleich-Pfad (Dokument->unterschrieben, Item->geprueft, Ablage, Audit). +5 Vitest (547->552). Live gegen wrangler dev + Playwright verifiziert (9/9): Banner, 3 Schritte, 2 unterschriftsreife Dokumente, Vor-Ort-Abschluss, Verfolgen=signiert, Write-back Dokument unterschrieben, SEPA-Einstieg, 0 Konsolenfehler. Bewusst deferiert (True North, dokumentiert): (1) Enum-Flags versendet/nicht_erforderlich (konsistent zu S2/MED-D-192: "wartet auf Signatur" aus dem Signatur-Status abgeleitet statt DOKUMENT_STATUS zu erweitern); (2) automatische SEPA-/Wiedervorlage-Doc-Verknuepfung (kein Link im Modell -> manueller Bestaetigungs-Schritt). Echte DocuSign/PandaDoc + E-Mail (MED-KB-5/OP-DM-8) bleiben spaeterer realer Einbau (OP-SIGN-1). tsc+ng build+vitest+check-doc-consistency.sh gruen. Nur noch S6 offen. | Nutzer "baue sukzessive weiter, pr und merge automatisch bis das Design vollstaendig umgesetzt ist"; Scope/Defer kritisch begruendet; Vor-Ort-Seam faelschungssicher | server/src/signatur/provider.ts, server/src/signatur/fake.ts, server/src/api/signatur-service.ts, server/src/api/app.ts, server/src/api/signatur.test.ts, client/src/app/akte-unterschriften-assistent.component.ts (neu), client/src/app/mandant-detail.component.ts, client/src/app/akte-bankrow.component.ts, client/src/app/api.service.ts, client/src/styles.css, server/src/version.ts, Feature-Liste, Test-Uebersicht, HANDOFF, CHANGELOG, Timesheet, Akten-Cockpit-Redesign.md, Stand-Stempel |
| MED-D-199 | 2026-07-23 | Frontend/UX · Akten-Cockpit-Redesign Slice S6 (MED-OP-AKTE-2) | S6 (Feinschliff) gebaut: TaskCard mit Faelligkeits-Dringlichkeit -> Redesign vollstaendig (0.97.0->0.98.0, MINOR; letzter Slice, schliesst MED-OP-AKTE-2 ab). Reine Client-Praesentation, kein Server-Change. TaskCard (§2.9): die Fristen-&-Aufgaben-Zeilen sind jetzt Karten mit Faelligkeits-Akzent an der linken Kante (rot=ueberfaellig · amber=bald ≤7 Tage · neutral=spaeter · gruen=erledigt) + ueberfaellig/bald faellig-Badge; signatur-/SEPA-/ruecklauf-bezogene offene Aufgaben bekommen einen "Im Unterschriften-Assistenten ->"-Einstieg (schliesst die letzte offene TaskCard->ovSig-Kante aus dem §2-Diagramm). Helfer wvDringlichkeit/wvDringlichkeitFarbe/wvIstSignaturAufgabe (client, Date.now()-basiert). Bewusst KEIN eigener Sub-Komponent (die bestehende Aufgaben-Zeile traegt viel inline-State: Edit/Zuweisen/Kommentare; eine Extraktion waere Churn ohne Wiederverwendungs-Nutzen — dieselbe Abwaegung wie die S1-Sidebar-Entscheidung): reiner Praesentations-Feinschliff, alle Bedienelemente erhalten (Append-only-Funktionalitaet). ng build gruen, Server-Vitest 552/552 unveraendert (kein Server-Change), check-doc-consistency.sh gruen. Live gegen wrangler dev + Playwright verifiziert (9/9): 3 TaskCards, ueberfaellige/bald-Badges korrekt, ferne Aufgabe ohne Badge, Signatur-Aufgabe mit Assistent-Einstieg (oeffnet das Overlay), farbige Akzent-Kante (rot rgb(192,80,63)), 0 Konsolenfehler. Damit sind alle 10 akte-patterns-Komponenten gebaut -> das Akten-Cockpit-Redesign (MED-D-188) ist vollstaendig, MED-OP-AKTE-2 ✅ geschlossen. Bewusst NICHT im Feinschliff (dokumentiert, kein Teil der 10 Kern-Komponenten): globale Motion-Kurve/weitere Wording-Zentralisierung (niedrigprioritaere Politur); Mandat-Overlay (S1-Rueckstellung = eigener Mandate-Rework, kein Feinschliff); realer DocuSign/PandaDoc-/E-Mail-Adapter (MED-KB-5/OP-DM-8/OP-SIGN-1); MED-KB-6 (Bank-PII-Verschluesselung/Retention). Folge-Empfehlung: der App-Audit (UX-Prozess-Review, v0.83.0) ist ueberfaellig (MED-OP-REVIEW-1, jetzt 0.98.0) -> bewertet nun das fertige Redesign. | Nutzer "baue sukzessive weiter, pr und merge automatisch bis das Design vollstaendig umgesetzt ist"; Scope/Nicht-Scope kritisch begruendet (True North) | client/src/app/mandant-detail.component.ts, client/src/styles.css, client/src/app/api.service.ts (Wiedervorlage-Import), server/src/version.ts, Feature-Liste, HANDOFF, CHANGELOG, Timesheet, Akten-Cockpit-Redesign.md, CLAUDE.md, Stand-Stempel |
| MED-D-200 | 2026-07-23 | Frontend/UX · Akten-Cockpit-Redesign Nachzug (MED-OP-AKTE-2) | Mandat-Overlay gebaut (0.98.0->0.99.0, MINOR) — der in S1 bewusst zurueckgestellte 4. Design-Overlay (akte-patterns "Mandat-Overlay"). Der Mandate-Reiter zeigte bisher jeden Beratungsauftrag als voll ausgeklappte, lange Karte (Stand-Select + Reife-Box + inline-Beratungsdoku + Rahmendaten-Grid + Artefakte + Meta) untereinander -> bei mehreren Auftraegen unuebersichtlich. Jetzt: kompakte eine Zeile je Auftrag (Produkt · Praxis · Reife-Pille · Status-Pille · "Oeffnen ->"); Klick auf Zeile/Button oeffnet die vollstaendige Auftrags-Akte im Scrim-Overlay (.mw-scrim/.mw-overlay-panel/.mw-overlay-head, global in styles.css, gleiches Muster wie Stammdaten-/Zeiten-/Signatur-Overlay). Reine Client-Restrukturierung in akte-auftraege.component.ts (kein Server-Change, keine Extraktion — alle Logik/Signale/Methoden bleiben in der einen Komponente, nur das Template wird umgehaengt): neues offen-Signal + offenerAuftrag-computed, oeffnen/schliessen, ESC via @HostListener. Kniff (kein Flackern): der Overlay-Container haengt an offen() (der Signal-ID), der Inhalt an offenerAuftrag() — und laden() macht jetzt einen In-Place-Reload (ladeVon(id, leeren=false)), setzt die Liste also nach einer Mutation nicht kurz auf [], sonst schloesse das Overlay bei jedem Speichern; beim Mandantenwechsel (effect) wird weiterhin geleert und offen zurueckgesetzt (kein Fremd-Auftrag-Overlay). tsc+ng build gruen (nur vorbestehende NG8102-Warnungen), Server unveraendert. Live gegen wrangler dev + Playwright verifiziert (9/9): 2 Oeffnen-Buttons/kompakte Liste, kein Scrim initial, Klick oeffnet Overlay (Kopf+Stand-Select+Beratungsdoku), ESC schliesst, Scrim-Klick schliesst, Overlay bleibt ueber eine Mutation (Beratungsdoku anlegen&verknuepfen) + Reload offen, 0 Konsolenfehler. Bug gefunden+behoben: ein HTML-Kommentar im Template mit Backticks um offen()/offenerAuftrag() beendete das Template-Literal (TS1005) -> Backticks entfernt (Template-Literal-Variante der MED-D-145-Disziplin). Damit ist auch der letzte der 4 Design-Overlays gebaut. | Nutzer "Ja" (verbleibende Design-Arbeit abschliessen: Mandat-Overlay + App-Audit); kein Server-Change/keine Extraktion (minimal-invasiv, True North) | client/src/app/akte-auftraege.component.ts, server/src/version.ts, Feature-Liste, HANDOFF, CHANGELOG, Timesheet, Akten-Cockpit-Redesign.md, CLAUDE.md, Stand-Stempel |
| MED-D-201 | 2026-07-23 | Betrieb/Qualitaet · App-Audit-Refresh (MED-OP-REVIEW-1) | App-UX-Audit aufgefrischt auf v0.99.0 (keine Versionsaenderung; Bezugspunkt war seit v0.83.0/MED-D-153 16 Minor-Versionen alt, ueber der Stale-Schwelle). Anlass: Abschluss des Akten-Cockpit-Redesign-Programms (S1-S6 + Mandat-Overlay, MED-D-191..200) — der Audit bewertet jetzt die fertige interne Akte. Methode: fuenf parallele Dimensions-Reviews (Feedback-Verlaesslichkeit · Sprache G-3/G-8 · Kundenstrecken · Design/Mobile/A11y · Eine Handschrift/Konsistenz) + Live-Begehung (wrangler dev + Playwright, Desktop 1440px + Mobil 390px). Ergebnis: die zwei konkreten Alt-Befunde des Vorgaengers sind behoben (B9 PHASE_LABEL-Dopplung → Alias auf LIFECYCLE_LABEL, MED-D-154; B10 Lifecycle-Undo-Fehlerhandler, MED-D-156); die 5-Reiter-IA + 4 Overlays stehen, 0 Konsolenfehler, kein Body-Overflow auf 390px. Neuer Backlog B14-B26, Sammel-OP MED-OP-UX-9 (Welle 10, absorbiert die offenen Reste von MED-OP-UX-8): hoch — die 4 Overlays sind keine echten Dialoge (kein role=dialog/Fokus-Falle/Fokus-Rueckgabe, B14) + Playbook-Teilfehlschlag vom Erfolgs-Toast ueberdeckt (B15, True North #2); mittel — Touch-Ziele <24px in neuen Bedienelementen (B16), Mandat-Overlay laeuft auf Mobile horizontal ueber/Schliessen-Button abgeschnitten (B17, live bestaetigt: Panel scrollWidth 528 vs clientWidth 340), Ladefehler weiter als "keine Daten" getarnt (B18), aria-describedby 0x im Client (B19); niedrig — Overlay-Shell dupliziert statt geteiltes Bauteil inkl. Mandat-Overlay-Kopf-Divergenz/ESC-Bypass (B20), zwei Pill-Vokabeln + fehlende md-status-erhalten-Regel (B21), rohe Enums Onboarding-Kategorie/Dok-Status (B22), Label-Drift-Haertung (B23), Kundenstrecken-Kleinbefunde inkl. Fragebogen-Legende/Turnstile (B24), stale In-Code-Kommentare (B25). Selbst-gefunden im eigenen Audit: der frisch gebaute Mandat-Overlay (MED-D-200) traegt zwei kleine Konsistenz-Kanten (Kopf-Typografie <strong> statt mw-sec-label, Schliessen-Button ohne mw-btn ghost; B20) und die Mobile-Reflow-Luecke (B17) — ehrlich als Befund erfasst statt geschoent. check-doc-consistency.sh Stale-Warnung damit geloescht. | Nutzer "Ja" (verbleibende Design-Arbeit: Mandat-Overlay + App-Audit); Stale-Regel MED-OP-REVIEW-1/agents.md §6.7; Befunde inkl. eigener Overlay-Arbeit selbstkritisch erfasst (True North) | docs/betrieb/UX-Prozess-Review-2026-07.md (neu geschrieben), HANDOFF (MED-OP-UX-8→9, MED-OP-REVIEW-1), CHANGELOG, Timesheet |
| MED-D-202 | 2026-07-23 | Frontend/UX+A11y · UX-Welle 10 Slice 1 (MED-OP-UX-9) | Geteilte Overlay-Shell + echte Dialog-Barrierefreiheit (0.99.0->0.99.1, PATCH). Erster Slice der Welle 10 aus dem App-Audit-Refresh (MED-D-201) — schliesst B14 (hoch) + B20 und faltet B2/B3/B17 mit ein. Neue wiederverwendbare AkteOverlayComponent (md-overlay): buendelt Scrim + Panel + Kopf + Schliessen-Knopf + echte Dialog-Semantik an EINER Stelle — role="dialog"/aria-modal="true"/aria-label (Titel), Initial-Fokus ins Panel, Fokus-Falle (Tab wandert nicht mehr hinter das Overlay) und Fokus-Rueckgabe an den ausloesenden Button beim Schliessen; ESC + Fokus-Falle nach dem Muster des Verlassen-Modals. Alle vier Akte-Overlays (Stammdaten · Zeiten · Signatur · Mandat) auf die Shell migriert -> statt 4x dupliziertem mw-scrim/mw-overlay-panel/mw-overlay-head-Markup jetzt EIN Bauteil (B20). Damit geloest: B2 (Mandat-Overlay-Kopf-Divergenz — Titel/Schliessen-Knopf kommen jetzt aus der Shell, identisch zu den anderen), B3 (zwei ESC-Mechaniken + Shell-ESC-Bypass — der eigene HostListener in akte-auftraege und der Overlay-ESC-Zweig in mandant-detail#onVerlassenKey sind entfernt; ESC laeuft nun ueber die Shell -> schliesseOverlay(), raeumt bankPeek mit auf). B17 (Mandat-Overlay Mobile-Overflow): Overlay-Titel darf schrumpfen/ellipsieren (.mw-overlay-head .mw-sec-label), Stand-/Themenbereich-Zeilen flex-wrap -> der Schliessen-Knopf ist auf 390px wieder erreichbar (live: Panel-scrollWidth 528->371, Body 390 ohne Overflow). Reine Client-Aenderung, kein Server-Change. tsc+ng build gruen (nur vorbestehende NG8102-Warnungen; ein NG8011 beim Kopf-Slot durch Aufteilen in zwei @if-Bloecke behoben). Live gegen wrangler dev + Playwright verifiziert (A11y, 6/6): Stammdaten-Overlay role=dialog/aria-modal/aria-label + Fokus landet im Panel; ESC schliesst + Fokus kehrt zum Ausloeser zurueck; Tab-Falle haelt (40x Tab, Fokus bleibt im Panel); Mandat-Overlay ebenso + Scrim-Klick schliesst; Mobile-Schliessen erreichbar; 0 Konsolenfehler. Naechste Slices: B15 (Playbook-Teilfehlschlag ehrlich melden) + B18/B19 (Ladefehler sichtbar, aria-Fehlertexte); danach B16/B21-B25 (Politur). | Nutzer "Welle 10"; Audit-Empfehlung MED-D-201 (B14 hoechste Prioritaet); geteilte Shell als Vehikel (B20) statt Inline-A11y je Overlay (True North, eine Handschrift) | client/src/app/akte-overlay.component.ts (neu), client/src/app/mandant-detail.component.ts, client/src/app/akte-auftraege.component.ts, client/src/styles.css, server/src/version.ts, Feature-Liste, HANDOFF, CHANGELOG, Timesheet, Stand-Stempel |
| MED-D-203 | 2026-07-23 | Frontend/UX+A11y · CodeRabbit-Nachlese zu PR #238 (MED-OP-UX-9) | Nachlese zu MED-D-202 (keine Versionsaenderung; PR #238 mergte per Auto-Merge, bevor das CodeRabbit-Review eintraf). 4 Befunde, 1 echt (Code) + 2 Doku-Konsistenz uebernommen, 1 bewusst nicht: (Code, Functional Correctness) AkteOverlayComponent.onKey reagierte auf JEDES document:keydown, auch wenn der Fokus ausserhalb des Panels lag — oeffnet das Verlassen-Modal ueber einem noch gemounteten Overlay, schloesse ESC zuerst dieses Overlay (document:keydown feuert vor dem window:keydown der Eltern-Komponente). Jetzt Fokus-Ownership-Gate (panel.contains(document.activeElement)) vor ESC/Tab-Behandlung. Live A11y 6/6 unveraendert gruen (Fokus liegt beim Oeffnen im Panel -> ESC/Tab arbeiten wie zuvor). (Doku) README + MVP-Scope „UX-Wellen 1–8" -> „1–10" (Redesign + Overlay-A11y ergaenzt); Feature-Liste Mandat-Overlay-Zeile praezisiert („Redesign-Slice S1" statt mehrdeutigem „S1", + Verweis auf die geteilte Shell). Bewusst nicht (mit Begruendung): der geforderte PR-Link in der CHANGELOG-Zeile — die Repo-Konvention (MED-D-144) nutzt fuer im-selben-Commit-wie-PR entstandene Eintraege bewusst den Branch-Namen und ergaenzt den Link nicht nachtraeglich (haette genau diese eine Zeile inkonsistent gemacht); CHANGELOG ist append-only. tsc+ng build+check-doc-consistency.sh gruen. | CodeRabbit-Review PR #238; Code-Befund echt uebernommen, Doku-Konsistenz nachgezogen, Konventions-Konflikt begruendet abgelehnt | client/src/app/akte-overlay.component.ts, README.md, docs/fachlich/MVP-Scope.md, docs/fachlich/Feature-Liste.md, CHANGELOG, Timesheet |
| MED-D-204 | 2026-07-23 | Frontend+Backend/UX · UX-Welle 10 Slice 2 (MED-OP-UX-9) | Playbook-Teilfehlschlag ehrlich melden (0.99.1->0.99.2, PATCH; App-Audit-Befund B15, hoch, True North #2). Problem: nach einem Lifecycle-Wechsel erschien immer ein Erfolgs-/Undo-Toast — auch wenn der Server die zugehoerige Standard-Wiedervorlage nicht anlegen konnte (mandant.playbook_fehler, seit MED-D-152 best-effort + auditiert, aber dem Client nie gemeldet). Der Anwender glaubte, die Folgeaufgabe stehe, obwohl sie fehlte — die Frage "was ist offen und faellig?" wurde aktiv falsch beantwortet. Server (minimal): MandantService.aktualisieren fuehrt jetzt ein transientes playbookFehler-Flag (true, wenn der best-effort-catch griff) und gibt es im Erfolgs-Ergebnis zurueck; die PATCH-Route haengt playbookFehler an die Antwort (nicht Teil der Mandant-Entitaet). Client: lifecycleSetzen liest das Flag; bei true zeigt der Toast ... — ⚠ Standard-Aufgabe konnte nicht angelegt werden (im Undo-Fall bleibt "Rueckgaengig" erhalten, im No-Undo-Fall Fehler-Toast). Zusaetzlich tragen die beiden Verlaufs-Labels mandant.playbook_fehler/auftrag.playbook_fehler jetzt ein ⚠-Praefix (wie mandant.manipuliert) — der Fehlschlag hebt sich im Audit-Trail sichtbar ab. +1 Vitest (erfolgreicher Wechsel -> playbookFehler:false) + bestehender Fehler-Test um die playbookFehler:true-Antwort-Assertion ergaenzt (552->553). tsc+vitest (553/553) + ng build + check-doc-consistency.sh gruen. Live gegen wrangler dev verifiziert: PATCH-Antwort traegt playbookFehler (Happy-Path false), Wechsel unregressiert; der Fehler-Pfad ist am Server-Vertrag unit-getestet (erzwungener createWiedervorlage-Throw -> Antwort true + Audit-Event). Bewusst als eigener Slice (statt B15+B18+B19 zusammen): B15 ist der einzige "hoch"-Befund, self-contained (Server+Client+Test); B18 (Ladefehler sichtbar) + B19 (aria-Fehlertexte) folgen als Slice 3 (breiter gestreut). | Nutzer "Welle 10"; Audit-Befund B15 (hoch/True North #2); Slice-Schnitt B15-allein begruendet | server/src/api/service.ts, server/src/api/app.ts, server/src/api/app.test.ts, client/src/app/api.service.ts, client/src/app/mandant-detail.component.ts, client/src/app/labels.ts, server/src/version.ts, Feature-Liste, Test-Uebersicht, HANDOFF, CHANGELOG, Timesheet, Stand-Stempel |
| MED-D-205 | 2026-07-23 | Frontend/UX+A11y · UX-Welle 10 Slice 3 (MED-OP-UX-9) | Ladefehler in den Akte-Panels sichtbar machen (0.99.2->0.99.3, PATCH; App-Audit-Befund B18). Problem: die self-contained Register-Panels schluckten Ladefehler still (error: () => set([])) — ein gescheiterter GET war von echtem Leerstand nicht unterscheidbar ("keine Daten" statt "konnte nicht laden"). Fix (einheitliches Muster, Vorbild verlaufFehler/stammHistFehler): je Panel ein ladeFehler-Signal (im Loader-error-Zweig gesetzt, bei jedem frischen Load zurueckgesetzt) + ein barrierefreies Banner <p class="md-error" role="alert">… konnte nicht geladen werden. [Erneut versuchen]</p> vor dem Leerstand-Text; der Retry-Button ruft den Loader erneut. Umgesetzt in akte-einladungen, akte-meetings, akte-formulare (Formular-Liste) und akte-auftraege (Auftrags-Liste; das ladeFehler respektiert das monotone Folge-Token + den leeren=false-In-Place-Reload). Das role="alert" macht die neuen Banner nebenbei zur Down-Payment auf B19 (aria/A11y-Fehlertexte). Reine Client-Aenderung, kein Server-Change. tsc+ng build+check-doc-consistency.sh gruen. Live gegen wrangler dev + Playwright verifiziert: erzwungenes 500 auf /api/mandanten/:id/auftraege -> Banner + role="alert" + Retry-Button erscheinen (statt "kein Beratungsauftrag"); nach Deaktivieren des Fehlers + Retry ist das Banner weg und die Auftrags-Zeile geladen; 0 nicht-HTTP-Konsolenfehler. Bewusst als Folgepunkt (dokumentiert): die Sub-Ressourcen-Loader in mandant-detail.component.ts (bankkonten/praxen/auftraege-Vorschau/generierungen/individualdokumente, Zeilen ~1483-1490) sind mit dem grossen detail()-Load verzahnt und bleiben vorerst still — eigener kleiner Nachzug. B19 (volle aria-describedby/role=alert-Abdeckung der ~15 md-error) + B16 (Touch-Ziele) + B21-B25 (Politur) folgen. | Nutzer "Welle 10"/"weiter"; Audit-Befund B18 (mittel/True North); einheitliches Retry-Muster (eine Handschrift) | client/src/app/akte-einladungen.component.ts, akte-meetings.component.ts, akte-formulare.component.ts, akte-auftraege.component.ts, server/src/version.ts, Feature-Liste, HANDOFF, CHANGELOG, Timesheet, Stand-Stempel |
| MED-D-206 | 2026-07-23 | Frontend/UX+A11y · UX-Welle 10 Slice 4 (MED-OP-UX-9) | A11y-Abschluss: Touch-Ziele >=24px (B16) + Fehlertexte als Live-Region (B19) (0.99.3->0.99.4, PATCH). B16 (WCAG 2.5.8): die neuen Bedienelemente lagen unter dem 24x24-Ziel — .mw-slider-seg (StatusSlider), .mw-sepa (SEPA-Toggle), .mw-bankrow-archbtn (Tastatur-Archivieren) und .mw-vfield-pill (vN-Historien-Pille) bekommen min-height:24px + inline-flex-Zentrierung (Optik bleibt kompakt, nur die Trefferflaeche waechst). B19 (Screenreader-Ansage): aria-describedby kam im ganzen Client 0x vor — der Lifecycle-<select> referenziert jetzt seinen Fehlertext (aria-describedby="lcstatus-fehler", nur wenn ein Fehler anliegt), und alle 14 dynamischen <p class="md-error">-Feedback-Absaetze in mandant-detail tragen role="alert" (werden also beim Erscheinen vorgelesen; die S3-Ladefehler-Banner hatten es bereits). Reine Client-Aenderung (CSS + Template-Attribute), kein Server-Change. tsc+ng build+check-doc-consistency.sh gruen. Live gegen wrangler dev + Playwright verifiziert: B16 — SliderSeg/SEPA/Archiv messen exakt 24px hoch (23 Slider-Segmente, 1 SEPA, 2 Archiv-Buttons; vN-Pille rendert nur bei Feld-Historie, CSS greift dennoch); B19 — Lifecycle-Pill oeffnen -> aktiv bei unvollstaendigem Onboarding -> Guard-409 -> Fehler-<p> mit role="alert" + Text "Onboarding ist noch nicht vollstaendig …", der Select traegt danach aria-describedby="lcstatus-fehler" (vorher null); 1 role=alert im DOM, 0 nicht-HTTP-Konsolenfehler. Damit sind B14-B20 der Welle 10 erledigt (alle hoch/mittel-Befunde); offen bleibt nur die niedrig-Politur B21-B25 + der mandant-detail-Sub-Loader-Nachzug (B18-Rest). | Nutzer "weiter"; Audit-Befunde B16/B19 (A11y-Abschluss); min-height-Ansatz statt ::before (einfacher, gleiche WCAG-Wirkung) | client/src/styles.css, client/src/app/mandant-detail.component.ts, server/src/version.ts, Feature-Liste, HANDOFF, CHANGELOG, Timesheet, Stand-Stempel |
| MED-D-207 | 2026-07-23 | Frontend/UX+Doku · UX-Welle 10 Slice 5 (MED-OP-UX-9) | Welle-10-Abschluss: die niedrig-Politur B21-B25 (0.99.4->0.99.5, PATCH). B21 (fehlende Farbregel): md-status-erhalten/-fehlt hatten keine CSS-Regel -> farblos-graue Pillen neben farbigen Nachbarstufen; .mw-scope .md-status-erhalten=blau (--blue), .md-status-fehlt=rot ergaenzt (mw-scope + base). B22 (rohe Enums, G-3): Onboarding-Item-Kategorie zeigte roh stammdatum/dokument/aufgabe -> neues ONBOARDING_KATEGORIE_LABEL (Klartext); der Unterschriften-Assistent zeigte den Dok-Status am Label-Kanal vorbei -> DOKUMENT_STATUS_LABEL importiert. B23 (Label-Drift): fehlendes Audit-Label beratungsdoku.geprüft in AKTION_LABEL ergaenzt (Verlauf zeigte es roh); MODELL_LABEL (cockpit) war eine wertgleiche Kopie von BETREUUNG_LABEL -> aliasiert (eine Quelle, kein Drift). B24 (Kundenstrecken): Fragebogen-Consent-Stern ohne Legende -> Klartext "(Pflicht)"; Turnstile-Callback-Cleanup (ngOnDestroy loescht window.onTurnstile) in onboarding-/fragebogen-public nachgezogen (Muster lead-public). B25 (stale Kommentare): Overlay-Key-/S5-Kommentare in mandant-detail auf den Ist-Stand nachgezogen. Reine Client-/Doku-Aenderung, kein Server-Change. tsc+ng build+check-doc-consistency.sh gruen; live gegen wrangler dev + Playwright verifiziert (B22a: Kategorie-Pillen = "Dokument"/"Stammdatum" Klartext; B21: md-status-erhalten blau rgb(63,124,158) / -fehlt rot, klar getrennt von gruen; 0 Konsolenfehler). Damit ist die Welle 10 (MED-OP-UX-9) B14-B25 vollstaendig abgearbeitet (B26 bleibt bewusst zurueckgestellt). | Nutzer "weiter"; Audit-Befunde B21-B25. formular-public-Turnstile bewusst NICHT ergaenzt (B24): die Ausfuell-Strecke ist nur ueber einen personengebundenen Feld-Korrektur-Link einer bereits gesichteten Einreichung erreichbar (minimale Bot-Flaeche ggue. dem offenen Lead-Formular) — Ausnahme statt Nachbau. md-status-erhalten=blau statt ::before-Technik (einfacher). | client/src/styles.css, client/src/app/labels.ts, client/src/app/mandant-detail.component.ts, client/src/app/akte-unterschriften-assistent.component.ts, client/src/app/cockpit.component.ts, client/src/app/fragebogen-public.component.ts, client/src/app/onboarding-public.component.ts, server/src/version.ts, Feature-Liste, HANDOFF, CHANGELOG, Timesheet, Stand-Stempel |
| MED-D-208 | 2026-07-23 | Frontend/UX · B26-Aufraeum (App-Audit v0.99.0) | B26-Restbefunde (konkrete Teilmenge) aufgeraeumt (0.99.5->0.99.6, PATCH). Nutzer "B26". B8 (Cockpit-Chip-Overflow, aeltester offener UX-Befund): die Auftrag-Status-Chip-Zusammenfassung im 208px-Lane-Kopf (cockpit.component.ts) lief bei langem Text aus dem sticky Kopf; jetzt kappen Phase+Chips in EINEM Ellipsis-Container (md-grow+mw-oh+min-width:0), das offen-Label bleibt rechts sichtbar, [title] traegt den Volltext. Live: injizierter 392px-Chip -> Lane-Kopf-Overflow 0 (scrollWidth==clientWidth), Ellipsis greift. B18-Rest (die namentlich genannte Falle): der Bankkonten-/Praxen-Load in mandant-detail#laden() schluckte Fehler still (error: () => set([])) -> "keine Konten" statt Ladefehler; jetzt setzt ein gescheiterter Load ein nebendatenFehler-Signal, und die Bank-Sektion im Stammdaten-Overlay zeigt ein barrierefreies Banner (role="alert") mit "Erneut versuchen" (re-run laden()) statt Leerstand. Live gegen wrangler dev + Playwright (Route-500) verifiziert (Banner+Retry statt "keine Konten"; nach Retry weg). bdAnlegenUndBinden (Waisen-Schutz): scheitert das Binden nach erfolgreichem Anlegen, wird jetzt neu geladen (die ungebundene Doku erscheint im "Verknuepfen"-Picker) + ehrlicher Hinweis, statt einer stillen Waise (append-only, kein Delete). Reine Client-Aenderung, kein Server-Change. tsc+ng build+check-doc-consistency.sh gruen. | Nutzer "B26". Scope-Entscheidung: die konkreten, True-North-relevanten B26-Teile gebaut (B8 Leitstand-Lesbarkeit, B18-Rest-Falle, Waisen-Schutz); bewusst weiter zurueckgestellt (bekannt/akzeptiert, kein Regress): Sub-0,7rem-Schrift (B4-Rest), ~132 Einzelwert-Inline-Styles je Cockpit (B5-Rest), die uebrigen mandant-detail-Sub-Loader (generierungen/individualdokumente/lzUeb/auftraege-Vorschau, eigene Falle je Render-Ort). | client/src/app/cockpit.component.ts, client/src/app/mandant-detail.component.ts, client/src/app/akte-auftraege.component.ts, server/src/version.ts, Feature-Liste, HANDOFF, CHANGELOG, Timesheet, Stand-Stempel |
| MED-D-209 | 2026-07-23 | Frontend/UX+A11y · B26-Restschuld (App-Audit v0.99.0) | B26-Restschuld (substanzielle Teilmenge) aufgeraeumt (0.99.6->0.99.7, PATCH). Nutzer "B26 Restschuld", Scope-Rueckfrage: "Substanzielle Reste". Verbleibende Sub-Loader sichtbar machen (Rest von B18): die vier noch stillen Loader in mandant-detail#laden() (generierungen/individualdokumente/leistungszeit-Uebersicht/auftraege) schluckten Fehler still (error: () => set([])); jetzt setzt jeder Fehlschlag das geteilte nebendatenFehler-Signal, und ein tab-uebergreifendes barrierefreies Banner (role="alert", oben im <main>, sichtbar auf allen Reitern) zeigt "Einige Akten-Nebendaten konnten nicht vollstaendig geladen werden. [Erneut versuchen]" statt still unvollstaendiger Daten; die Bank-Sektion im Stammdaten-Overlay traegt dasselbe Banner (Overlay verdeckt das Haupt-Banner). Banner-Wortlaut generalisiert (nicht mehr nur "Bankverbindungen/Praxen"). Live gegen wrangler dev + Playwright (Route-500 auf /auftraege) verifiziert: Haupt-Banner + Retry statt Leerstand, nach Retry weg, 0 Nicht-500-Konsolenfehler. Sub-0,7rem-Lesetext auf 0,7rem-Floor (Rest von B4): sechs echte Lesetext-Regeln (.md-kpi-q/.md-step-st/.md-group-lbl/.md-sev/.mw-next .typ/.mw-vfield-pill, 0,6-0,66rem) auf 0.7rem (>=11px) gehoben; Glyphen in fixen Boxen (.mw-sq/.mw-token .sq 0,56rem, .mw-avatar 0,62rem, .mw-assist-step-n 0,66rem) und dekoratives Brand-Micro-Type (Taglines/Wortmarken-Suffixe) bewusst unangetastet (dort ist die Groesse Geometrie, kein Lesetext). Live: .mw-next .typ = 11,2px (0,62->0,7), Avatar-Glyph bleibt 9,9px, 0 Body-Overflow auf 1440/390 (Akte) + 1440 (Cockpit). Reine Client-Aenderung, kein Server-Change. tsc+ng build+check-doc-consistency.sh gruen. | Nutzer "B26 Restschuld" + AskUserQuestion "Substanzielle Reste". Bewusst weiter zurueckgestellt (Nutzer-Wahl): die ~134 Cockpit-Einzelwert-Inline-Styles (B5-Rest) — reiner Churn ohne sichtbaren Effekt, Repo-Governance "keine ungefragten Refactorings"; .mw-fs-68/.mw-badge (0,68rem ~= Floor, Rename-Churn wg. Klassenname vermieden). | client/src/app/mandant-detail.component.ts, client/src/styles.css, server/src/version.ts, Feature-Liste, HANDOFF, CHANGELOG, Timesheet, Stand-Stempel |
| MED-D-210 | 2026-07-24 | Frontend/Doku · Nachlese PR #245 (CodeRabbit) | CodeRabbit-Nachlese zu #245 (0.99.7->0.99.8, PATCH). Drei Post-Merge-Befunde bewertet: (1) Race in mandant-detail#laden() [Major, valide]: laden() feuert bei jeder Mutation neu; ein spaet eintreffender Alt-Batch konnte frische Arrays ueberschreiben oder nebendatenFehler nach erfolgreichem Retry wieder auf true setzen. Fix: Latest-Load-Guard via ladeGeneration-Zaehler — jeder der 6 Sekundaer-Loader (generierungen/individualdokumente/lzUeb/praxen/bankkonten/auftraege) wirkt nur, wenn seine Generation die juengste ist (if (aktuell()) um next+error). Deterministisch live verifiziert: Alt-Batch-500-Straggler nach erfolgreichem Retry laesst das Banner korrekt weg (ohne Guard waere es faelschlich wieder erschienen). (2)+(3) Typografische Anfuehrungszeichen [Minor, valide]: die diese Session eingefuehrten deutschen Quotes in CHANGELOG.md + Feature-Liste.md verletzten MED-D-145 (nur ASCII-Quotes in Markdown); komplett-Sweep beider Dateien („/“/”->", 34+7 Vorkommen -> 0). Abgelehnt: CodeRabbits Vorschlag, im CHANGELOG den PR-Link statt des Branch-Namens zu nutzen — MED-D-144 (Eintraege, die im selben Commit wie die PR-Erstellung entstehen, kennen die Nummer noch nicht und nutzen bewusst den Branch-Namen). Reine Client-/Doku-Aenderung. tsc+ng build+check-doc-consistency.sh gruen. | CodeRabbit-Review #245 (3 Befunde); 2 valide umgesetzt, 1 mit MED-D-144-Begruendung abgelehnt. Quote-Sweep statt Einzelzeilen-Fix (loest die Befundklasse, verhindert Wiederkehr). | client/src/app/mandant-detail.component.ts, CHANGELOG.md, docs/fachlich/Feature-Liste.md, server/src/version.ts, HANDOFF, Timesheet, Stand-Stempel |
| MED-D-211 | 2026-07-24 | Betrieb/Qualitaet · App- + Doku-Audit-Refresh (MED-OP-REVIEW-1) | Beide Meisterwerk-Audits aufgefrischt auf v0.99.8 (keine Versionsaenderung; Bezugspunkt Commit caa33d0). Anlass: Nutzer "Meisterwerk Audit fuer App und Doku" + Wirksamkeits-Kontrolle nach Akten-Cockpit-Programm/Welle 10/B26/Nachlese. Methode: 8 parallele Dimensions-Reviews (App: Feedback · Sprache G-3/G-8 · Kundenstrecken · Design/Mobile/A11y · Konsistenz; Doku: Doku↔Doku · Doku↔Code · Qualitaet/Governance) + Live-Begehung (wrangler dev + Playwright, 1440/390px). App-Ergebnis: alle 12 Befunde B14–B26 behoben, kein Regress; Mobile 6→8, A11y 6→8 (echte Overlay-Dialog-Semantik + Fokus-Falle live bestaetigt, 0 Konsolenfehler, 0 Overflow); neuer Backlog B27–B34 → MED-OP-UX-10 (Peripherie-Ehrlichkeit: Signatur-Teilfehlschlag/stille Rand-Loads; A11y-Restmeile: Tab-ARIA/role=alert-Abdeckung/--mut-Kontrast; Konsistenz + G-8-Katalog). Doku-Ergebnis: alle 8 Alt-Befunde B33–B40 geschlossen, Stempel/Testzahl deckungsgleich 0.99.8/553, Check grün; neuer Backlog B41–B48 → MED-OP-DOKU-8 (Governance einholen: Compliance/Risiko stale 2026-07-14, 1:n-Bankkonto-PII + Vor-Ort-eSignatur nicht abgedeckt, Bankkonto fehlt in Lastenheft-Feldspec; + mechanische Drifts R1–R12/Test-Tabelle/nextcloud_ref). | Nutzer "Meisterwerk Audit App+Doku". Audit-Refresh = Zeitdokument OHNE Versions-Bump (analog MED-D-201/180); Befunde -> MED-OP-Punkte (agents.md §6.7 Regel 4), nicht im Audit abgearbeitet. Bezugs-Commit auf caa33d0 korrigiert (war irrtuemlich d7f87d7, Pre-Squash-Merge-Branch-Head #246). | docs/betrieb/UX-Prozess-Review-2026-07.md, docs/betrieb/Doku-Review-2026-07.md, HANDOFF (MED-OP-REVIEW-1 + neue MED-OP-UX-10/MED-OP-DOKU-8), CHANGELOG, Timesheet |
| MED-D-212 | 2026-07-24 | Doku · Doku-Welle 6 (MED-OP-DOKU-8) | Doku-Welle 6: Governance einholen + Rahmen-Docs nachziehen (keine Versionsaenderung; reine Doku, Backlog aus Doku-Audit-Refresh v0.99.8/MED-D-211). B41 Compliance.md + Risikoregister-Stand auf 2026-07-24 gezogen + Gesamtsichtungs-Note (gegen MED-D-188…210 gegengeprueft; Substanz DSGVO/eIDAS/ZertES stimmig). B42 RISK-28 um den 1:n-Bankkonto-PII-Ausbau (MED-D-195: Inhaber-Name/mehrere IBANs/Zeichnungsberechtigung, append-only) erweitert. B43 Unterschriften.md: Status auf MED-D-198 aktualisiert + neuer §"Unterschriften-Assistent + Vor-Ort-/Demo-Abschluss" (3-Schritt-Flow, Sicherheitsriegel abschliessenDemo nur am Fake → 409 gegen echt, Write-back R4→R3→R2) + sequenceDiagram (B49.1) + vor-ort-abschluss-Route ergaenzt. B44 Bankkonto-Feldtabelle (R1-F33..F43) + Pruefstatus-stateDiagram (B49.2) in Lastenheft.md §4.4 (Dictionary verwies dorthin). B45 Modul-Range R1–R12→R1–R13 (docs/README + CLAUDE). B46 Test-Uebersicht-Tabelle auf 553/50 rekonziliert (3 fehlende Zeilen adressen/fake+openplz+api/bankkonto ergaenzt, 6 stale Zaehlungen per vitest run korrigiert; Summe = Header). B47 Weltmodell-classDiagram um die 1:n-Bankkonto-Entitaet + Hinweis. B48 nextcloud_ref-Prosa-Rest → nextcloud_pfad. Alle 3 neuen Mermaid-Diagramme validiert (valid=true). | Nutzer "weiter 1" (MED-OP-DOKU-8). Doku-Welle = keine Versions-Aenderung (Doku holt gebauten Code ein, analog Doku-Welle 5); Governance-Register bewusst nur dort neu gestempelt, wo real gegengeprueft (RISK-28 + Gesamtsichtungs-Note), keine falsche Pauschal-Restempelung aller Zeilen. B49.3 (Dokument-Zustandsmaschine) optional offen. | docs/betrieb/Compliance.md, docs/betrieb/Risikoregister.md, docs/architektur/Unterschriften.md, docs/fachlich/Lastenheft.md, docs/architektur/Weltmodell-Data-Dictionary.md, docs/architektur/Dokumentenverwaltung-NextCloud.md, docs/README.md, CLAUDE.md, docs/betrieb/Test-Uebersicht.md, HANDOFF, CHANGELOG, Timesheet |
| MED-D-213 | 2026-07-24 | Frontend/UX · UX-Welle 11 Slice 1 (MED-OP-UX-10) | Welle 11 S1 — Peripherie-Ehrlichkeit (Band A, App-Audit v0.99.8, B27+B28) (0.99.8->0.99.9, PATCH). Nutzer "weiter 2". B27 (Signatur-Sammel-Versand, True North #2): die versenden()-Schleife im Unterschriften-Assistenten brach bei Fehler von Dokument N ab und meldete Totalausfall, obwohl Dok 1..N-1 bereits serverseitige Vorgaenge hatten. Fix: jedes Dokument einzeln try/catch, bereits angelegte Vorgaenge auch im Fehlerfall in die Sitzung ueberfuehren (Schritt 3), Frist-WV best-effort, Meldung "X von Y versendet — Rest fehlgeschlagen" statt pauschal. B28 (stille Rand-Loads, B18 fortgeschrieben): drei Flaechen ausserhalb des Akten-Kerns schluckten Ladefehler still — jetzt je ein Fehler-Signal + barrierefreies Banner (role="alert"): mandant-akte (Druck-/Export-Akte, True North #3: "Ausdruck moeglicherweise unvollstaendig"-Warnung, kritischste), verwaltung (Admin-Daten: "Listen moeglicherweise unvollstaendig"), akte-dentmarking (Betriebsdaten je Praxis: Inline-Hinweis + "Erneut versuchen"). Reine Client-Aenderung. tsc+ng build+check-doc-consistency.sh gruen; live gegen wrangler dev + Playwright verifiziert (Druck-Akte + Verwaltung: Route-500 -> Banner, sauberer Load ohne Banner, 0 nicht-500-Konsolenfehler). | Nutzer "weiter 2" (MED-OP-UX-10). Slice-Schnitt: Band A (B27+B28) getrennt von Band B (A11y, B29-B31 -> S2) und niedrig (B32-B34 -> S3), damit jede PR reviewbar bleibt. Druck-Akte-Banner ohne Retry-Button (Konstruktor-Load, kein laden(); "Seite neu laden"-Hinweis stattdessen). | client/src/app/akte-unterschriften-assistent.component.ts, client/src/app/mandant-akte.component.ts, client/src/app/verwaltung.component.ts, client/src/app/akte-dentmarking.component.ts, server/src/version.ts, Feature-Liste, HANDOFF, CHANGELOG, Timesheet, Stand-Stempel |
| MED-D-214 | 2026-07-24 | Frontend/UX · CodeRabbit-Nachlese PR #249 | Nachlese zu Welle 11 S1 (#249) (0.99.9->0.99.10, PATCH). CodeRabbit-Review = 5/5 Pre-Merge-Checks gruen, aber 3 valide Korrektheits-Befunde auf dem S1-Code + 2 Doku-Scope-Nits. (1, Major, valide) Vor-Ort-Vorgang-Verlust: scheiterte im Assistenten signaturVorOrtAbschluss(), verwarf die Schleife den bereits serverseitig angelegten signaturAnfordern-Vorgang (die B27-Klasse, eine Ebene tiefer) — jetzt inner try/catch: der angeforderte Vorgang bleibt in der Sitzung (Verfolgen nachholbar), zaehlt als Teil-Fehlschlag; separater erfolg-Zaehler statt vorgaenge.length fuer die "X von Y"-Meldung (kein Ueberzaehlen). (2, Minor, valide) Dentmarking-Stale-Response: praxisDatenLaden hatte keinen Latest-Load-Guard — ein spaeter Alt-Response nach Retry konnte frische Daten ueberschreiben / das Banner wieder einblenden (die MED-D-210-Klasse). Fix: per-Praxis pxLadeGen-Zaehler, nur die juengste Ladung wirkt. (3, Minor, valide) Verwaltung-Latch: das globale ladeFehler-Flag wurde nur auf true gesetzt, ein erfolgreicher Reload konnte es nie loeschen. Fix: Record<loader,boolean>-Signal + hatLadeFehler-computed; jeder Loader loescht nur seinen eigenen Fehler bei Erfolg. **(4+5, Doku-Scope) ** README/MVP-Scope-Status um "laufende Welle-11-Politur" ergaenzt; CLAUDE-§Versionierung 0.2.0 als historischer Startwert klargestellt. Reine Client-/Doku-Aenderung. tsc+ng build+check-doc-consistency.sh gruen; verwaltung-Banner (computed) live verifiziert (Route-500 -> Banner, sauber ohne Banner, 0 nicht-500-Fehler); (1)/(2) per tsc + Logik-Review (Klassen wie B27/MED-D-210). | CodeRabbit-Review #249 (5 Befunde, alle valide/berechtigt). Alle umgesetzt (kein Skip) — die 3 Code-Befunde sind echte Korrektheits-Kanten derselben Klassen, die die Welle adressiert. erfolg-Zaehler statt Doppelzaehlung. | client/src/app/akte-unterschriften-assistent.component.ts, client/src/app/akte-dentmarking.component.ts, client/src/app/verwaltung.component.ts, README.md, docs/fachlich/MVP-Scope.md, CLAUDE.md, server/src/version.ts, HANDOFF, CHANGELOG, Timesheet, Stand-Stempel |
| MED-D-215 | 2026-07-24 | Frontend/UX+A11y · UX-Welle 11 Slice 2 (MED-OP-UX-10) | Welle 11 S2 — A11y-Restmeile (Band B, App-Audit v0.99.8, B29+B30+B31) (0.99.10->0.99.11, PATCH). Zweite Slice der Welle 11 (Barrierefreiheit ausserhalb des in W10 gehaerteten Overlay-Kerns). B29 (Reiter-ARIA): die 5 Akten-Reiter in mandant-detail trugen role="tab"/aria-selected, aber die Leiste kein role="tablist" und es gab keine Tastatur-Navigation. Fix: role="tablist"+aria-label an die Leiste, roving tabindex (nur der aktive Reiter fokussierbar, Rest -1), neue registerTaste()-Methode fuer Pfeil-links/rechts/hoch/runter + Pos1/Ende (aktiviert + fokussiert den Ziel-Reiter), id je Reiter. role="tabpanel"/aria-controls bewusst NICHT gesetzt: der Inhalt jedes Reiters ist ueber mehrere [hidden]-Geschwister-Sektionen in <main> verstreut (basis an 3 Stellen, dokumente an 5) -- es gibt kein 1 Panel je Reiter, ein einzelnes tabpanel waere falsche ARIA; ein Wrap-Refactor waere eine eigene Slice, der Tastatur-/SR-Kern-Gewinn ist mit tablist+roving-tabindex realisiert. B30 (role="alert" ausserhalb des Kerns, B19 fortgeschrieben): die oeffentlichen Submit-Fehler (lead-public/onboarding-public/fragebogen-public/formular-public -- ein fehlgeschlagener rechtsverbindlicher Absende-Versuch war fuer Screenreader stumm), der Audit-Trail-"Nachweis unvollstaendig"-Hinweis (mandant-akte) und die Dentmarking-/Verwaltungs-Fehler bekommen role="alert". B31 (--mut-Kontrast): Light-Theme --mut:#7c8a7e (~3,6:1 auf Weiss, unter WCAG-AA) -> #5f6d62 (5,45:1, computed live bestaetigt); dunkles Theme unveraendert. Reine Client-Aenderung, kein Server-Change. tsc+ng build+check-doc-consistency.sh gruen; live gegen wrangler dev + Playwright verifiziert (tablist praesent, roving tabindex 1x0/4x-1, ArrowRight wechselt Auswahl+Fokus auf akte-tab-auftraege, Home zurueck; --mut computed 5,45:1 AA; 0 Konsolenfehler). | Nutzer "weiter 1, dann 2" (Teil 2 = MED-OP-UX-10). Slice-Schnitt: Band B (A11y B29-B31) getrennt von Band C/D (B32-B34 -> S3). role="tabpanel" bewusst ausgelassen statt gefaked -- verstreute [hidden]-Sektionen ergeben kein sauberes 1-Panel-je-Reiter, ARIA-Korrektheit vor Vollstaendigkeit; Wrap-Refactor als eigene Slice offen. Audit-Doc bleibt v0.99.8-Zeitdokument (nicht umgeschrieben); Fortschritt in HANDOFF MED-OP-UX-10. | client/src/app/mandant-detail.component.ts, client/src/app/lead-public.component.ts, client/src/app/onboarding-public.component.ts, client/src/app/fragebogen-public.component.ts, client/src/app/formular-public.component.ts, client/src/app/verwaltung.component.ts, client/src/app/akte-dentmarking.component.ts, client/src/app/mandant-akte.component.ts, client/src/styles.css, server/src/version.ts, Feature-Liste, HANDOFF, CHANGELOG, Timesheet, Stand-Stempel |
| MED-D-216 | 2026-07-24 | Frontend/UX+G-8 · UX-Welle 11 Slice 3 (MED-OP-UX-10 ✅) | Welle 11 S3 — Konsistenz & Kundenstrecken-Politur (Band C/D, App-Audit v0.99.8, B33+B34+B32a) (0.99.11->0.99.12, PATCH). Letzte Slice der Welle 11; schliesst MED-OP-UX-10 vollstaendig ab. B33 (G-8): vier lokale Enum-Label-Maps nach labels.ts gehoben — StammdatenQuelle (mandant-detail), ArtefaktTyp (akte-auftraege), OffenKategorie (cockpit KAT_LABEL), KontoPruefstatus (akte-bankrow); staerkste Drift war der AuftragStatus-Doppelvokabel (Akte-Langform vs. Cockpit-AUFTRAG_CHIP_LABEL-Kurzform) -> als EINE Quelle mit zwei benannten Sichten aufgeloest: AUFTRAG_STATUS_LABEL (Lang) + AUFTRAG_STATUS_KURZ_LABEL (Kurz). Farb-Zuordnungen (KAT_VAR) blieben lokal (Praesentation, kein Label). B34 (Kundenstrecken): (a) 4 Consent-Checkboxen -> .md-consent-check 24x24px (WCAG 2.5.8, live 24x24 bestaetigt); (b) formular-public Fehler var(--amber)->md-error-rot; onboarding/fragebogen Speicher-Fehlschlag vom neutralen gespeichertHinweis in den roten fehler-Kanal (role=alert) umgeleitet (gespeichertHinweis dabei geloescht, kein Stale); (c) ladeTurnstile 3x wortgleich -> geteilte ladeTurnstileScript() in pub-bausteine.ts (nur Script-Laden geteilt, namespaced onTurnstile-Callback bleibt je Komponente lokal). B32(a): Basis-.md-status-*-Satz um erhalten ergaenzt (B21-Drift ausserhalb .mw-scope behoben, gleiche Status-Abdeckung wie mw-scope-Satz; Token-System bewusst getrennt). Turnstile-Ausnahme (B34c) hier festgehalten: das Ausfuell-Formular (formular-public) ist die einzige oeffentliche Strecke OHNE Turnstile — bewusst, weil token-gebunden (kein offener Endpunkt) und rechtsverbindliche SES-Abgabe, fuer die eine Bot-Challenge weder Rechtswirkung noch Missbrauchsschutz erhoeht (der Token IST die Zugangskontrolle); Code-Kommentar in formular-public#absenden verweist auf MED-D-216. Reine Client-Aenderung, kein Server-Change. tsc+ng build+check-doc-consistency.sh gruen; live gegen wrangler dev + Playwright verifiziert (Leitstand-Chip "1 Auftrag . 1 Anbahnung" via zentrales AUFTRAG_STATUS_KURZ_LABEL, Consent-Checkbox 24x24px, mandant-detail sauber, 0 Konsolenfehler). | Nutzer "weiter 1, dann 2" (Teil 2 = MED-OP-UX-10), Fortsetzung nach S1/S2. Scope-Entscheidung: S3 deckt B33+B34 voll + B32(a) CSS-Dedup; die hoeher-riskanten B32-Refactors (B32(b) 3-Modal-Fokus-Falle-Konsolidierung, Pill-Render-Vereinheitlichung, ~300 Inline-Styles) bewusst zurueckgestellt (B35/Carry-over) — die 3 Fokus-Fallen funktionieren bereits (live in W10 bestaetigt), reine DRY/Churn ohne sichtbaren Effekt, Governance "keine ungefragten Refactorings". Turnstile-Ausnahme als Decision-Log-Zeile statt Seam-Nachzug (die Ausnahme ist korrekt, nur undokumentiert gewesen). | client/src/app/labels.ts, client/src/app/cockpit.component.ts, client/src/app/akte-auftraege.component.ts, client/src/app/akte-bankrow.component.ts, client/src/app/mandant-detail.component.ts, client/src/app/lead-public.component.ts, client/src/app/onboarding-public.component.ts, client/src/app/fragebogen-public.component.ts, client/src/app/formular-public.component.ts, client/src/app/pub-bausteine.ts, client/src/styles.css, server/src/version.ts, Feature-Liste, HANDOFF, CHANGELOG, Timesheet, Stand-Stempel |
| MED-D-217 | 2026-07-24 | Betrieb/Qualitaet · App- + Doku-Audit-Refresh + Design-Abnahme (MED-OP-REVIEW-1) | Beide Meisterwerk-Audits aufgefrischt auf v0.99.12 (keine Versionsaenderung; Bezugspunkt Commit 4a3a018, 2026-07-24). Anlass: Nutzer "Refresh beide Meisterwerk-Audits. Dann pruefe, ob das Design-System und alle Screenshots uebernommen wurden." Methode: 4 parallele Dimensions-Reviews (App: Welle-11-Verifikation B27-B34 + Regress B14-B26 · Mobile/A11y/Kundenstrecken · Design-System-Fidelity 10 Komponenten; Doku: Doku-Doku + Doku-Code) + Live-Begehung (wrangler dev + Playwright, 1440/390px). App-Ergebnis: alle 8 Befunde B27-B34 im Code (nicht nur Doku) behoben, kein Regress in B14-B26; Sprache/G-8 8->9 (B33 Label-Zentralisierung + AuftragStatus-Doppelvokabel aufgeloest), Feedback 8->8,5 (B27/B28), Kundenstrecken 8->8,5 (B34), A11y 8->8,5 (B29/B30/B31), Konsistenz 7,5->8 (B32a). Design-System-Abnahme BESTANDEN: alle 10 akte-patterns-Komponenten existieren mit Fidelity "voll" (StatusSlider/RequirementCheckbox/DocumentRow/Overlay-Shell/UnterschriftenAssistent/BankRow/VersionedField/Self-Service/TaskCard/LifecycleRing+TimerCard), 5-Reiter-IA + 4 Overlays via geteilter md-overlay-Shell, World-2-Tokens ausschliesslich (kein eingeschleuster Hex), Zustandsmodelle §5 erfuellt (Slider-Mapping, Pruefstatus getrennt von SEPA, append-only), alle Screen-01-17-Intents funktional abgedeckt; live 0 Overflow (1440/390) + 0 Konsolenfehler, LifecycleRing/Tastatur-Reiternavigation/Overlays live bestaetigt. Ehrliche Abnahme-Grenze: die verbindlichen Design-Rohartefakte (akte-patterns.md, .dc.html, Screenshots 01-17) liegen NUR im claude.ai/design-Projekt (DesignSync-MCP in dieser Session getrennt) -> Abnahme ist strukturell/funktional, kein Pixel-Diff gegen die Original-Masse moeglich; Empfehlung: Rohartefakte dem Repo beilegen fuer echte Pixel-Abnahme. Neuer kleiner App-Backlog B36-B40 -> MED-OP-UX-11 (Badge-Kontrast <AA · 16px-Touch-Ziel · Tabs-aria-controls · 2 role=alert-Restluecken · Cockpit-Falsch-Leere). Doku-Ergebnis: alle 8 B41-B48 geschlossen, Test-Tabelle rekonziliert 553/50 (vitest run bestaetigt), alle Einstiegs-Stempel deckungsgleich 0.99.12; Konsistenz-Dimension 8->9,5 (kein Zahl-ungleich-Zahl-Rest mehr); kein neuer Doku-Backlog — nur 2 Bagatellen (A-1 HANDOFF-Strikethrough an MED-OP-UX-10 in diesem Zug mitgezogen; A-2 B-Nummern-Ueberlappung zwischen Audit-Spuren by-design). | Nutzer "Refresh beide Audits + Design/Screenshot-Abnahme". Audit-Refresh = Zeitdokument OHNE Versions-Bump (agents.md §6.7, analog MED-D-211/201/180); Befunde -> MED-OP-UX-11, nicht im Audit abgearbeitet. Design-Abnahme in den App-Audit integriert (MED-OP-REVIEW-1 nennt App + Screens 01-17 als Abnahme-Referenz). A-1 als triviale Doku-Hygiene im selben Zug behoben (kein eigener OP). Pixel-Diff ehrlich als nicht-durchfuehrbar deklariert statt vorgetaeuscht. | docs/betrieb/UX-Prozess-Review-2026-07.md, docs/betrieb/Doku-Review-2026-07.md, HANDOFF (MED-OP-REVIEW-1 + MED-OP-UX-11 + A-1-Fix), CHANGELOG, Timesheet |
| MED-D-218 | 2026-07-24 | Design/Doku · Akten-Cockpit Design-Handoff-Import | Der claude.ai/design-Handoff "Akten-Cockpit 1a (Detail)" ist ins Repo importiert (Nutzer lieferte das zuvor fehlende Design-Paket nach — schliesst die Pixel-Abnahme-Luecke aus dem App-Audit v0.99.12/MED-D-217). Reine Doku/Referenz. Import nach docs/design/akten-cockpit-handoff/: akte-patterns.md (verbindliche Masse/Tokens), Akten-Cockpit-1a-Detail.dc.html (Pixel-Prototyp), design-decisions.md, screenshots/01-17 (Soll-Zustaende, 496K), README mit Repo-Kontext-Banner — eingefrorene Quelle der Wahrheit. Einarbeitung design-decisions.md -> neue docs/produkt/Design-Entscheidungen-Akte.md: AD-001..AD-015 in die Produktdoku-Struktur (BLUF/pyramidal), je Entscheidung mit Umsetzung im Repo (MED-D-ID · Komponente · ehrlicher Status ✅/🟡/💡). Doku-Landkarte + Akten-Cockpit-Redesign.md auf die jetzt in-repo liegenden Quellen umgestellt (vorher "im Design-Projekt"). | Nutzer "Import zip + Implement .dc.html + design-decisions.md in docs/produkt/ einarbeiten". Scope-Rueckfrage (README verlangt Ambiguitaets-Klaerung): Nutzer waehlte "Pixel-Fidelity-Pass + Doku" statt Neu-Aufbau (Cockpit ist bereits gebaut/live, 2669 Zeilen > Handoff-Snapshot 2257). Screenshots (496K PNG) als Referenz-Renderings bewusst committet (kein Binaer-Master i.S.v. CLAUDE.md). | docs/design/akten-cockpit-handoff/*, docs/produkt/Design-Entscheidungen-Akte.md, docs/README.md, docs/architektur/Akten-Cockpit-Redesign.md |
| MED-D-219 | 2026-07-24 | Frontend/Design · Pixel-Fidelity-Pass Akten-Cockpit | Pixel-Fidelity-Abgleich der Akte gegen die Design-Quelle (.dc.html + akte-patterns.md §2 + Screenshots 01-17; 0.99.12->0.99.13, PATCH). Ein Fidelity-Agent verglich alle 10 Komponenten; 8 echte Abweichungen behoben: (1) BankRow-Swipe-Transition ease->cubic-bezier(.22,1,.36,1) (§2.6/§3 Motion-Regel); (4) Peek-Animation Kurve+Delay .4s->.6s+Amplitude -28->-26px+Plateau-Keyframe; (12) IBAN .82->.8rem + dezentes "‹"-Wisch-Chevron am Zeilenende; (7) SEPA-Pill "ohne SEPA" grau -> "ohne gueltiges SEPA" amber; (3) Signaturniveau-Default AES->SES (§2.5 "SES vorausgewaehlt"); (2) Assistent-Overlay 760->720px + Scrim z-60->z-70 (neue [breite]/[erhoeht]-Inputs der geteilten md-overlay-Shell); (6) VersionedField-Toggle "vN"-Pille -> "⟲ N fruehere Werte anzeigen/ausblenden"-Text-Link (§2.7, --accentText, 24px Touch-Hoehe erhalten). Bewusst NICHT geaendert (dokumentierte Divergenzen): Scrim nutzt Token --overlay statt Prototyp-Literal (Token-Disziplin im Handoff vorgeschrieben); BankRow direkt-commit statt Zwei-Stufen-Swipe (bewusste, tastaturfaehige UX); DocumentRow-Send-Aktionen + AD-008/009-Formular-Ruecklauf kommen mit der echten DocuSign-Anbindung (heute UI-Mapping); "(Demo)"-Wortlaut bewusst (MED-KB-5); Stammdaten read-only (Formular-Rueckuebernahme). Reine Client-Aenderung. tsc+ng build gruen; live gegen wrangler dev + Playwright verifiziert (Computed-Styles: SEPA #b07a00 amber, vfield-toggle #4e8a1c accentText, bankrow-face cubic-bezier(.22,1,.36,1), Chevron praesent, Scrim-erhoeht z-70, 0 Konsolenfehler). | Nutzer "Pixel-Fidelity-Pass". Agent-gestuetzter Abgleich (12 Befunde), 8 Pixel-Fixes umgesetzt, 5 als bewusste Architektur-/Demo-Divergenzen dokumentiert statt blind angepasst; die funktionale Tiefe (DocumentRow-Envelope-Zustaende) ist an die DocuSign-Anbindung gekoppelt, kein Pixel-Thema. | client/src/styles.css, client/src/app/akte-bankrow.component.ts, client/src/app/akte-versioned-field.component.ts, client/src/app/akte-overlay.component.ts, client/src/app/akte-unterschriften-assistent.component.ts, client/src/app/mandant-detail.component.ts, server/src/version.ts, docs/architektur/Akten-Cockpit-Redesign.md, HANDOFF, CHANGELOG, Feature-Liste, Timesheet, Stand-Stempel |
| MED-D-220 | 2026-07-24 | Architektur/Integration · DocuSign-HTTP-Adapter | Erster echter E-Signatur-Provider hinter der SignaturProvider-Abstraktion (server/src/signatur/docusign.ts; 0.99.13->0.100.0, MINOR). Auth via JWT Grant (RS256 in-Worker ueber WebCrypto/crypto.subtle, PKCS#8-Key erzwungen — das Node-SDK docusign-esign laeuft nicht auf Workers, daher hand-gerollter REST-Zugriff via fetch, Token-Cache). Envelope-Flow: anfordern laedt Dokument-Bytes aus der Ablage (R4->R3 via signatur-service.ts), base64 -> Envelope (status:sent, Signer = Mandant-E-Mail/-Name, signHere-Tab), eventNotification = Connect-Webhook. Status/Download ueber /documents/combined (signierte Fassung -> bestehender abgleich-Write-back R4->R3->R2). Connect-Webhook POST /oeffentlich/signatur/docusign-webhook (im /oeffentlich*-Access-Bypass; X-DocuSign-Signature-1 per HMAC-SHA256 konstant-zeit verifiziert, fail-closed ohne DOCUSIGN_WEBHOOK_HMAC -> 401); Pull-abgleich bleibt Fallback (RISK-6). Sicherheitsriegel: kein abschliessenDemo -> vorOrtAbschluss liefert 409 (echte Vorgaenge nie faelschbar, MED-D-198). Dormant ohne Secret (docuSignKonfigAusEnv->null -> Provider faellt auf fake / API 503; deploy-sicher, G-5). +10 Vitest gegen gemocktes fetch (JWT/Envelope/Status/Download/Webhook-HMAC/Bytes-Aufloesung; 553->563/51 Dateien). tsc+vitest gruen. Bewusst NICHT live verifiziert: kein Dev-Secret + kein Netz-Egress in der Build-Sandbox -> Unit-Test gegen Mock; Scharfschalt-Runbook Deploy.md §7d. | Nutzer "integriere jetzt docusign - es liegt ein developer account vor". Zwei Weggabelungen per Rueckfrage entschieden: QES-Behandlung = "Als AES senden + sichtbarer Hinweis" (Dev-Account kann keine echte QES; echte QES erst mit CSP -> RISK-2); Slice-Zuschnitt = "Adapter + Connect-Webhook". Adapter statt SDK, weil Workers kein Node; dormant-ohne-Secret als Deploy-Sicherheit (G-5); Live-Betrieb setzt AVV + US-Transfer-Mechanismus voraus (RISK-4, DPF/SCC). | server/src/signatur/docusign.ts, server/src/signatur/provider.ts, server/src/signatur/docusign.test.ts, server/src/api/signatur-service.ts, server/src/api/app.ts, server/src/index.ts, server/src/repo/*.ts, server/src/version.ts, docs/architektur/Unterschriften.md, docs/architektur/Deploy.md, docs/betrieb/Compliance.md, docs/betrieb/Risikoregister.md, HANDOFF, CHANGELOG, Feature-Liste, Test-Uebersicht, Timesheet |
| MED-D-221 | 2026-07-24 | Betrieb/CI · DocuSign-Credentials via GitHub-Secrets | Die 5 DocuSign-Credentials werden als GitHub-Repo-Secrets hinterlegt und beim Deploy in den Worker gesynct (keine Versionsaenderung, CI/Config + Doku) - dasselbe Muster wie die NextCloud-Secrets. app-deploy.yml-Sync-Schritt um DOCUSIGN_INTEGRATION_KEY/USER_ID/ACCOUNT_ID/PRIVATE_KEY/WEBHOOK_HMAC erweitert (idempotent wrangler secret put, leere uebersprungen, continue-on-error; PKCS#8-PEM behaelt Zeilenumbrueche ueber die Env-Variable). Der Go-Live-Schalter SIGNATUR_PROVIDER=docusign (+ DOCUSIGN_WEBHOOK_URL) bleibt bewusst als nicht-geheimer Toggle in wrangler.toml [vars] (auskommentiert) statt als GitHub-Secret - Everything-as-Code (G-2), damit Go-Live ein sichtbarer, reviewbarer Commit ist. Die Credentials allein schalten NICHTS scharf (Compliance-Gate: AVV/US-Transfer RISK-4 zuerst, DEMO_MODE->false). | Nutzerfrage "koennen wir die Credentials per GitHub Secrets setzen?". Ja - Praezedenz existiert (NextCloud). Trennung geheim/nicht-geheim: Credentials -> GitHub-Secrets (nie im Repo, RISK-8/G-5), Provider-Toggle -> wrangler.toml (sichtbar, EaC/G-2). GitHub-Secrets sind nur zur CI-Laufzeit da -> der Sync-Schritt ist die Bruecke in den Worker-Env. | .github/workflows/app-deploy.yml, server/wrangler.toml, docs/architektur/Deploy.md |
| MED-D-222 | 2026-07-24 | Betrieb/CI · Secret-Sync-Haertung (CodeRabbit-Nachlese #256) | Der Secret-Sync-Schritt (app-deploy.yml, MED-D-221) wird robuster + ehrlicher (keine Versionsaenderung, CI/Config + Doku). Zwei valide CodeRabbit-Befunde umgesetzt: (1 Stabilitaet) ein fehlgeschlagenes wrangler secret put brach unter set -eo pipefail die Schleife ab -> spaetere Secrets blieben stumm ungesetzt, unter continue-on-error unsichtbar. Jetzt: jeder Sync faengt seinen Fehler ab (Schleife laeuft weiter), sammelt betroffene Namen und beendet den Schritt am Ende sichtbar rot (::error:: + Exit 1) statt eine partielle Credential-Menge zu verstecken (per Mock-Lauf verifiziert: 1 Fehler -> restliche Secrets laufen, Exit 1). (2 Widerruf) dokumentiert (bewusst KEIN Auto-Delete): ein leeres/entferntes GitHub-Secret laesst das Worker-Secret bestehen (Entfernen widerruft nicht) - Absicht, damit ein versehentlich leeres Secret keine Produktiv-Credential destruktiv loescht; echter Widerruf = bewusster wrangler secret delete <NAME> (Deploy.md §7d). Nicht uebernommen (1 Befund): CHANGELOG-PR-Link - die Zeile nutzt bewusst den Branch-Namen (etablierte Konvention MED-D-144: Same-Commit-as-PR-Erstellung-Eintraege kennen die PR-Nr. noch nicht, Link wird nicht retroaktiv ergaenzt). | CodeRabbit-Review PR #256 (2 Major "Quick win" + 1 Minor). Auto-Delete verworfen, weil destruktiv (temporaer leeres Secret = Zugriffsverlust); Dokumentation reicht (CodeRabbit bot beide Wege an). Gilt gleichermassen fuer die NextCloud-Secrets (selber Schritt). | .github/workflows/app-deploy.yml, docs/architektur/Deploy.md |
| MED-D-223 | 2026-07-25 | Frontend+Backend/Akte · Akten-Cockpit Slice A (AD-008) | DocumentRow-Zustandsmaschine gebaut (0.100.0->0.101.0, MINOR; erster Delta-Slice des erneut gelieferten Akten-Cockpit-Designs — Spec akte-patterns.md §2.3 identisch zum bereits gebauten Import MED-D-218, nur die AD-Kommentare jetzt inline). Die Ablage-DocumentRow (mandant-detail.component.ts) war ein statischer @switch(dok.status) mit spec-widriger "Signieren"-Sendaktion auf geprueft; jetzt zustandsgetrieben je AD-008: fehlt -> "Zur Unterschrift ->" (oeffnet Assistent); offener SignaturVorgang (gesendet) -> amber Pill "wartet auf Signatur" + "Erinnern" + "Signiert hochladen" (Sign on Paper); erhalten/geprueft -> keine Sendaktion; abgelaufen -> roter Chip + "war geprueft . gueltig bis ..."-Meta. versendet ist ABGELEITET (G-2, Nutzerentscheidung 2) aus einem offenen Vorgang, kein neues Enum/DB-Feld. Zwei duenne Server-Seams: POST /api/signaturen/:id/erinnern (Provider-optionales erinnern?, Fake noop, DocuSign resend_envelope; best-effort + Audit) und POST /api/signaturen/:id/signiert-hochladen (Sign on Paper: Scan in die Ablage, Dokument -> erhalten [Pruefung offen, Nutzerentscheidung 1 "auf Spec"], Vorgang -> signiert, Audit). +8 Vitest (563->571). Labels zentral in labels.ts (DOKUMENT_VERSAND_LABEL). tsc+vitest+ng build gruen (unabhaengig nachverifiziert). | Nutzer lieferte das Akten-Cockpit-Design erneut (mit inline-AD-Kommentaren); Gap-Audit zeigte AD-008 als bewusst deferiert (MED-D-192, "an DocuSign gekoppelt") -> jetzt durch MED-D-220 entsperrt. Nutzerentscheidungen: (1) Vor-Ort/Sign-on-Paper -> Dokument erhalten (Spec, nicht unterschrieben); (2) versendet abgeleitet, kein Enum-Change; (3) Reihenfolge A+B, C, D. | client/src/app/mandant-detail.component.ts, client/src/app/api.service.ts, client/src/app/labels.ts, server/src/api/signatur-service.ts, server/src/api/app.ts, server/src/signatur/provider.ts, server/src/signatur/fake.ts, server/src/signatur/docusign.ts, server/src/api/signatur.test.ts, server/src/version.ts, HANDOFF, CHANGELOG, Feature-Liste, Test-Uebersicht, Timesheet, Stand-Stempel |
| MED-D-224 | 2026-07-25 | Frontend/UX-Fix · 403-Toast-Fehlalarm beim Akte-Oeffnen | Der globale Fehler-Interceptor toastet 403 nur noch bei SCHREIBENDEN Methoden (keine Versionsaenderung, 1-Zeilen-Client-Fix). Symptom (Nutzer): beim Oeffnen der Akte blitzte kurz "Keine Berechtigung fuer diese Aktion." auf. Ursache: mandant-detail laedt eager GET /api/benutzer/zuweisbar (Zuweisen-Dropdown), das admin-only (mandant_zuweisen) ist und fuer eine Berater-Rolle 403 liefert; die Komponente schluckt den Fehler (error: () => {}), aber der globale fehler.interceptor.ts feuert den Toast davor. Fix: else if (status === 403 && req.method !== "GET") — ein 403 auf einem Hintergrund-GET ist eine Rollen-Lesegrenze, keine vom Nutzer ausgeloeste "Aktion" (so sagt es auch der Toast-Text); die Komponente behandelt den leeren Zustand, der Fehler wird weiter propagiert (nur ohne Toast). Schreibende 403s (echte abgelehnte Aktionen) toasten weiter. Behebt die ganze Klasse eager-admin-GET-Fehlalarme. tsc gruen. | Nutzer-Bugreport (Screenshot). Interceptor-Fix statt Server-403->200-Umbau gewaehlt: generell (alle eager-admin-GETs), minimal, aendert keine API-Semantik. | client/src/app/fehler.interceptor.ts |
| MED-D-225 | 2026-07-25 | Betrieb/CI · Pipeline-Speedup fuer GH-hosted Runner | npm-Cache + Angular-Build-Cache konditional aktiviert (keine Versionsaenderung, CI/Workflow + Doku). Nutzerfrage "Can we speed up the pipelines? These run on GH hosted runners." — die CI war fuer die alten self-hosted Dauer-Runner optimiert (warmes ~/.npm + .angular/cache via clean:false), auf GH-hosted ephemeren VMs greifen diese Annahmen NICHT -> jeder npm ci/ng build kalt. Fix (Dual-Mode-erhaltend): konditionaler cache: npm (aktiv nur wenn fork ODER CI_RUNNER == 'ubuntu-latest', sonst leerer String) an alle setup-node-Steps (ci.yml docs-build/server-test/client-build/sbom + app-deploy + docs-deploy), cache-dependency-path je Lockfile; .angular/cache per actions/cache@v4 nur GH-hosted (Key aus client-Lockfile+sha, restore-keys-Fallback). Self-hosted: cache: "" (leer) -> unregressiert. Zusaetzlich auto-rerun.yml (flaky-runner-Selbstheilung, RISK-29) auf GH-hosted abgeschaltet — der Job-Guard vars.CI_RUNNER != 'ubuntu-latest' laesst ihn nur auf self-hosted laufen, auf GH-hosted (== 'ubuntu-latest') ist er deaktiviert (Datei bleibt als Fallback). Erwartung: CI ~2m -> ~60-75s (kaltes npm ci ist der Hauptposten). Alle 4 Workflow-YAML validiert. agents.md §6.6 auf die neue konditionale Regel aktualisiert. | Nutzer bestaetigte "ja". Konditional statt unbedingt gewaehlt, damit self-hosted (MED-D-185-Fallback) nicht regressiert; auto-rerun nur stillgelegt statt geloescht (Dual-Mode). | .github/workflows/ci.yml, .github/workflows/app-deploy.yml, .github/workflows/docs-deploy.yml, .github/workflows/auto-rerun.yml, docs/konventionen/agents.md |
| MED-D-228 | 2026-07-25 | Betrieb/Konvention · Zeit-Statistik | KW-Aggregat im Timesheet je Session aktualisieren + Management-Summary „investierte Zeit" (keine Versionsaenderung, Doku/Konvention). Bisher war das „Aggregat (KW)" als „periodisch nach Wochenschluss geglaettet" (OP-PM-1) formuliert und stand veraltet (KW28 „— vorläufig"). Neu: die Aggregat-Tabelle + eine Gesamtsumme werden je Session mitgezogen (laufende KW aufaddieren, neue KW-Zeile bei Wochenwechsel); verankert in Timesheet.md-Methodik + agents.md §4. Zusaetzlich Management-Summary um eine „Investierte Zeit"-Zeile (~174 h, Link Timesheet) erweitert — beantwortet gebuendelt „wo stehen wir · was steht an · wieviel Zeit". | Nutzer: „Das Aggregat pro KW muss immer auch aktualisiert werden" + „wir brauchen eine Management-Summary …". Aggregat ist eine abgeleitete Sicht (G-2) — die Session-Zeilen bleiben Quelle, das Aggregat wird daraus fortgeschrieben statt nachgelagert geglaettet. | docs/betrieb/Timesheet.md, docs/konventionen/agents.md, docs/produkt/Management-Summary.md, CHANGELOG |
| MED-D-229 | 2026-07-25 | Frontend/Akte · Akten-Cockpit Delta C (Prüfen-Schritt) | Unterschriften-Assistent Schritt 1 (Prüfen) ausgebaut (0.102.0->0.103.0, MINOR; §2.5). Nutzer wählte Delta C = „Prüfen-Schritt ausbauen". Drei neue Blöcke bei ausgewähltem Dokument: (1) Pflichtdaten-Checkliste (Name/E-Mail/Anschrift/Geburtsdatum, ✓ aus Stammdaten / ● fehlt, abgeleitet, read-only); (2) SEPA-Konto-Auswahlkarten (nur SEPA-Kontext) + Inline „Neues Konto erfassen" via bestehende Bankkonto-Route; effektivKontoId (Auswahl vor Kontext) steuert den SEPA-Write-back; (3) Formular-Vorschau (read-only). Assistent lädt Bankkonten selbst, mandant-Input neu. Rein Client, kein Server-Change. | Scope-Entscheidung (bewusst): die Spec sagt „Übernahme fehlender Angaben in Stammdaten bei Weiter" — Mandant-Stammdaten sind aber nur über den auditierbaren Formular-Rücklauf editierbar (MED-D-147), nicht berater-inline. Daher hier kein Stammdaten-Write: fehlende Felder werden markiert + auf Self-Service/Formular verwiesen (G-4-Audit-Design nicht umgehen). SEPA-Konto nutzt die berater-editierbare S3a-Route (kein Grenzkonflikt). Fremdformular/Feld-Editor = eigener Delta (an OP-SIGN-1 gekoppelt). | client/src/app/akte-unterschriften-assistent.component.ts, client/src/app/mandant-detail.component.ts, server/src/version.ts, HANDOFF, CHANGELOG, Feature-Liste, Timesheet, Akten-Cockpit-Redesign |
| MED-D-234 | 2026-07-25 | Betrieb/Doku · DocuSign-Live-Verifikation-Runbook (OP-SIGN-1) | Smoke-Test-Checkliste fürs Scharfschalten in Deploy.md §7d ergänzt (keine Versionsänderung, reine Doku). Nutzerfrage „Kannst du DocuSign testen?" → Unit-Tests laufen (10/10 gegen gemocktes fetch), ein Live-Test war aus der Session heraus unmöglich (keine Secrets, dormant ohne Secret — G-5; kein Sandbox-Konto/Consent). Der bestehende §7d-Runbook beschrieb das Scharfschalten (JWT-App, PKCS#8, Consent, Secrets, Provider-Toggle, Connect-Webhook), aber nicht die Verifikation danach — genau der offene OP-SIGN-1-Rest. Neu: „7d-Live-Verifikation (Smoke-Test)" — 7 konkrete Schritte gegen den Demo-Account (Konfiguration greift · JWT/Consent · Envelope/Zustellung · Webhook-Write-back als Kern · Pull-Fallback RISK-6 · Dormant-Negativtest · QES-AES-Hinweis) + Abnahmekriterium (erst dann DEMO_MODE=false/Prod-Hosts + Ergebnis in OP-SIGN-1 vermerken). Bewusst kein Provider-Health-Endpoint (kein Diagnose-Pfad, der Secrets/PII leaken könnte, G-6) → der erste echte anfordern ist der Test. Cross-Link aus Unterschriften.md. | True North #3 (rechtssichere Doku ist Liefergegenstand) + G-4: „gebaut" ≠ „live verifiziert" muss prüfbar sein, nicht nur behauptet. Verifikation als Doku statt Code, weil der Live-Test Credentials + Sandbox braucht, die bewusst außerhalb des Repos liegen (der Nutzer wählte „nur Unit-Tests reichen"); das Runbook macht die Verifikation reproduzierbar, sobald das Konto steht. | docs/architektur/Deploy.md, docs/architektur/Unterschriften.md, CHANGELOG, Timesheet |
| MED-D-233 | 2026-07-25 | Frontend/UX · S6-Feinschliff · Wording-Zentralisierung (Feldmarkierung) | Kunden-Feldmarkierung „weiß ich nicht"/„wird nachgeliefert" auf eine Quelle (0.104.2->0.104.3, PATCH). Zweiter (letzter) S6-Feinschliff-Rest. Das Enum→Deutsch-Mapping von FeldMarkierung (weiss_nicht/nachgeliefert) stand 3× dupliziert: als lokale Map MARKIERUNG_TEXT (formular-public), als hartkodierter Chip-Button-Text in pub-bausteine (dem eigentlichen Kundeneingabe-Bauteil) und als Inline-Ternär in der Berater-Sicht (akte-formulare). Jetzt ein MARKIERUNG_LABEL in labels.ts (G-3, analog B33), von allen drei Stellen genutzt. Wertident; tsc+ng build grün, Server/Tests unberührt (574). Damit ist der S6-Feinschliff vollständig (Motion-Kurve MED-D-232 + Wording MED-D-233) → das Akten-Cockpit-Redesign hat keine offenen Politur-Reste mehr. | S6-Feinschliff-Rest (weitere Wording-Zentralisierung). Ein sichtbarer Kundentext an einer Stelle definieren, nicht dreifach (G-3 = sprechende Begriffe konsistent; „eine Handschrift" für die Kundenstrecken). Bewusst nur die eindeutige Dreifach-Dopplung gehoben; einmalig genutzte lokale Label-Maps (z. B. KLASSE_LABEL in fragebogen-public) bleiben lokal (YAGNI, keine Zentralisierung ohne zweiten Nutzer). PATCH (wertidenter Refactor, kein neues Feature). | client/src/app/labels.ts, client/src/app/pub-bausteine.ts, client/src/app/formular-public.component.ts, client/src/app/akte-formulare.component.ts, server/src/version.ts, HANDOFF, CHANGELOG, Feature-Liste, Akten-Cockpit-Redesign, Timesheet |
| MED-D-232 | 2026-07-25 | Frontend/UX · S6-Feinschliff · Motion-Kurve zentralisiert + Reduced-Motion gehärtet | Design-Motion-Kurve auf ein Token + prefers-reduced-motion vervollständigt (0.104.1->0.104.2, PATCH). Die „overshoot & settle"-Ease-out-Kurve cubic-bezier(0.22,1,0.36,1) (Fidelity-Pass MED-D-219) stand als 6× wiederholtes Literal in styles.css (5×) + cockpit.component.ts (1× inline, Aktenreife-Ring) — jetzt ein Token --mw-ease im Basis-:root (theme-unabhängig, immer aktiv), überall var(--mw-ease) (G-2 = eine Quelle). Zusätzlich deckte @media (prefers-reduced-motion: reduce) bisher nur .mw-scrim/.mw-overlay-panel (+ Timer-Puls) ab — jetzt auch die dekorativen Entrance-Pops/Fades (.mw-card, .mw-cmd, .mw-cmd-overlay, .mw-empty); die BankRow-Peek-Geste ist bereits über no-preference gegatet. Wertident (kein visueller Unterschied, nur Zentralisierung + A11y). ng build grün. | S6-Feinschliff-Rest aus dem Akten-Cockpit-Redesign (globale Motion-Kurve app-weit); True North indirekt (A11y/WCAG 2.3.3 — Nutzer mit Reduced-Motion-Präferenz respektieren). Token statt Literal = G-2 (eine Definition, überall). Der Funktionsklassen-Ansatz (nur dekorative Animation aus, Farbe/Sichtbarkeit bleibt) statt globalem *{animation:none}. Wording-Zentralisierung (zweiter S6-Rest) bewusst als eigener, späterer bounded Slice belassen (kein Grab-bag). PATCH (wertidenter Refactor + A11y, kein neues Feature). | client/src/styles.css, client/src/app/cockpit.component.ts, server/src/version.ts, HANDOFF, CHANGELOG, Feature-Liste, Akten-Cockpit-Redesign, Timesheet |
| MED-D-231 | 2026-07-25 | Frontend+Backend/UX · App-UX-Welle 9 Rest abgeschlossen (B10/MED-OP-UX-8) | Auftrag-Playbook-Fehler dem Nutzer sichtbar gemacht + MED-OP-UX-8 als vollständig bestätigt (0.104.0->0.104.1, PATCH). Bestandsaufnahme der B8–B12-Restliste (im HANDOFF seit v0.83.0 stehend) ergab: B8 (Cockpit-Chip-Overflow), K1 (AKTION_LABEL['beratungsdoku.geprüft']), K2 (aria-describedby+role=alert am Lifecycle-Fehler) und K3 (Fragebogen-Legende, bewusst produkt-eigen Essenziell/Wichtig/Optional) waren bereits bei früheren Wellen mitgezogen. Einziger echter Rest: die auftrag.playbook_fehler (Produkt-/Status-Playbook scheitert bei Auftrag-Anlage/Statuswechsel) wurden nur PII-arm auditiert, aber nie dem Nutzer gemeldet (Gegensatz zum Mandant-Lifecycle-Pfad, der seit B15/MED-D-204 warnt). Jetzt liefert BeratungsauftragService.anlegen/statusSetzen ein transientes playbookFehler-Flag (nicht Teil der Entität, wie mandant.playbookFehler), die Route flacht es auf die Antwort, der Client (akte-auftraege) warnt „⚠ Standard-Aufgaben konnten nicht angelegt werden". +2 Vitest (572→574). | True North #2 (ehrlich zeigen, was offen/fehlgeschlagen ist) — ein still geschluckter Playbook-Fehler hinterlässt fehlende Folgeaufgaben, ohne dass jemand es merkt. Muster 1:1 vom Mandant-Pfad (B15) übernommen statt neu erfunden (G-2). Backlog-Text im HANDOFF §5 war veraltet → als Doku-Hygiene mitkorrigiert. PATCH, da Korrektheits-/Ehrlichkeitsfix ohne neues Feature. | server/src/api/beratungsauftrag-service.ts, server/src/api/app.ts, server/src/api/beratungsauftrag.test.ts, client/src/app/api.service.ts, client/src/app/akte-auftraege.component.ts, server/src/version.ts, HANDOFF, CHANGELOG, Test-Uebersicht, Timesheet |
| MED-D-230 | 2026-07-25 | Frontend/Akte · Akten-Cockpit Delta D (Fremdformular) | Fremdformular-Markierung + Feld-Editor-Hinweisbox im Prüfen-Schritt (0.103.0->0.104.0, MINOR; §2.5). Der an OP-SIGN-1 gekoppelte, aber jetzt schon baubare Teil von Delta D. (1) Fremdformular-Klassifikation rein abgeleitet: ein Dokument ist Eigenformular, wenn seine Bezeichnung eine bekannte Vorlage trägt (DOKUMENTTYP_LABEL als einzige Quelle, G-2), sonst Fremdformular — keine neue Persistenz/Enum-Flags. (2) amber „Fremdformular"-Pill an der Schritt-1-Dokumentzeile (Markierung am Dokument). (3) Bei gewählten Fremdformularen ersetzt eine neutrale Hinweisbox „Fremdformular — Felder im Feld-Editor setzen" + Button „Im Feld-Editor öffnen →" die (bei unbekannter Feldstruktur sinnlose) Formular-Vorschau; die Vorschau bleibt nur für Eigenformulare. Rein Client, kein Server-/Enum-Change (Tests unverändert 572); tsc+ng build grün. | Scope-/G-1-Entscheidung: kein Eigenbau-Feld-Editor — die echte Feld-/Template-Bindung gehört an DocuSign (OP-SIGN-1). Der Button meldet ehrlich „folgt mit der DocuSign-Anbindung" statt einen Attrappen-Editor vorzutäuschen (MED-KB-5, kein stiller Echt-Eindruck). Fremdformular rein abgeleitet statt neuem Enum-Flag: die versendet/nicht_erforderlich-Flags bleiben bewusst deferiert (S2-Entscheidung), keine Persistenz ohne Not (G-2/G-6). Reihenfolge „erst C mergen, dann D" (Nutzer). | client/src/app/akte-unterschriften-assistent.component.ts, server/src/version.ts, HANDOFF, CHANGELOG, Feature-Liste, Timesheet, Akten-Cockpit-Redesign |
| MED-D-227 | 2026-07-25 | Frontend+Backend/Akte · Akten-Cockpit Slice B (In-Person-Signatur) | Vor-Ort -> Erhalten + geführte In-Person-Strecke + Write-back-Automatik gebaut (0.101.0->0.102.0, MINOR; MED-D-192-Rest, akte-patterns §2.5). (1) Server-Korrektheit: vorOrtAbschluss (Demo/Attrappe) lief bisher durch denselben abgleich-Write-back wie der echte E-Sig-Pfad und setzte Dokument unterschrieben + Item geprueft — ein Falsch-Nachweis (G-4/MED-KB-5), da die Attrappe keine rechtsgueltige Signatur erzeugt. Jetzt gemeinsamer erhaltenAblegen-Helfer mit Sign-on-Paper: Dokument -> erhalten (Pruefung offen), Vorgang -> signiert, Demo-Fassung in die Ablage, Audit signatur.vor_ort_abgeschlossen, Onboarding-Item unangetastet; idempotent. Echter abgleich (DocuSign-Webhook) bleibt auf unterschrieben/geprueft. (2) Geführte In-Person-Strecke (Client): einklickiges "Vor Ort abschließen" wird zur Strecke Übergabe -> Kunden-Signaturansicht (Marke + Formulardaten + eIDAS-Hinweis, "Jetzt signieren") -> Danke/Rückgabe -> Schritt 3 (Vollflächen-Takeover, Host = Berater). (3) Write-back-Automatik (Client): bei Abschluss automatisch SEPA-Konto -> gültig (ersetzt manuellen Button) + auslösende Aufgabe -> erledigt (neuer aufgabeId-Input); best-effort + idempotent; Ergebniskarte. Server-Vitest 571->572. tsc+vitest+ng build grün. | Nutzer beauftragte Slice B nach Merge von #262/#263/#264 (Vor-Ort->erhalten + In-Person-Signing + Write-back-Automatik). Vor-Ort->erhalten schließt die MED-D-223-Entscheidung 1 konsistent zu Sign-on-Paper (Attrappe darf keinen unterschrieben-Zustand vortäuschen). SEPA/Aufgabe client-orchestriert (saubere Session-Linkage via sepaKontoId/aufgabeId, kein Schema-Change). | server/src/api/signatur-service.ts, server/src/api/signatur.test.ts, client/src/app/akte-unterschriften-assistent.component.ts, client/src/app/mandant-detail.component.ts, client/src/app/labels.ts, server/src/version.ts, HANDOFF, CHANGELOG, Feature-Liste, Test-Uebersicht, Timesheet, Akten-Cockpit-Redesign, Design-Entscheidungen-Akte |
| MED-D-226 | 2026-07-25 | Doku/Nachlese · CodeRabbit-Korrekturen zu MED-D-225 (#264) | Fuenf valide Minor-Doku-Befunde aus dem CodeRabbit-Review von PR #264 korrigiert (keine Versionsaenderung, reine Doku). Gegen den Workflow-Code verifiziert: (1+2 Korrektheit) die auto-rerun-Bedingung war in CHANGELOG + dieser Zeile (MED-D-225) invertiert beschrieben — der Job-Guard vars.CI_RUNNER != 'ubuntu-latest' in auto-rerun.yml:40 aktiviert den Job auf self-hosted und deaktiviert ihn auf GH-hosted (== 'ubuntu-latest'); der Wortlaut suggerierte das Gegenteil (irrefuehrend fuer Operatoren). (3+4 Markdown) das rohe || in der Cache-Expression brach in der MED-D-225-Tabellenzeile + im Timesheet die Spaltenanzahl (markdownlint MD056: 8 statt 6 Zellen) — durch Prosa ersetzt (fork oder \CI_RUNNER == 'ubuntu-latest'`). **(5 Aktualitaet)** der spaetere agents.md-§6.6-Absatz ("Persistenter Angular-Build-Cache (nur hot)") war seit MED-D-225 veraltet — .angular/cachewird jetzt auch auf GH-hosted viaactions/cache@v4 restauriert; Absatz unterscheidet jetzt beide Runner-Modi (actions/cacheGH-hosted vs.clean:falseself-hosted).check-doc-consistency.shgruen. | CodeRabbit-Review PR #264 (5 Minor "Quick win", alle vor dem Fix gegenauto-rerun.yml/ci.ymlgegengeprueft und als valide bestaetigt). PR #264 war zum Zeitpunkt des Reviews bereits per Auto-Merge gemergt → Korrektur als **Follow-up-Doku-PR** (Nachlese-Muster) statt Reopen; keine Code-Aenderung noetig (nur Beschreibungen der bereits gemergten Workflow-Aenderung). |CHANGELOG.md, docs/betrieb/Decision-Log.md, docs/betrieb/Timesheet.md, docs/konventionen/agents.md | | **MED-D-235** | 2026-07-25 | Frontend+Backend/Akte · Fremdformular-Feldmapping (AD-010, Weg A) | **Fremdformular-Feld-Editor gebaut: AcroForm-Felder auslesen -> je Feld ein Weltmodell-Attribut -> Prefill aus Stammdaten** (0.104.3->0.105.0, MINOR; MED-OP-FORM-5 Slice 1). Löst den Platzhalter-Toast aus MED-D-230 ab. **Weg A (Hybrid, Nutzerwahl „A" + echtes apoBank-EDÜ-PDF):** die Eigenleistung ist **nur das Mapping** — Füllen via **pdf-lib**, Signieren via **DocuSign** (G-1). Neu: pdf/pdf-formular.ts(AcroForm lesen/füllen, kein Flatten),domain/fremdformular.ts(KatalogWELTMODELL_ATTRIBUTE, G-8, + Prefill-Bildung, rein), api/fremdformular-service.ts(ansicht/mappingSetzen/vorbefuellen über den R2-Ablage-Seam),client/akte-feld-editor.component.ts(Overlay im Unterschriften-Assistenten). Persistenz: **eine JSON-Spaltedokument.fremdformular_mapping** (Migration **v46**) — 1:1 mit dem Dokument, keine neue Entität; die extrahierten Felder bleiben **abgeleitet** (G-2). Routen /api/dokumente/:docId/fremdformular(GET/PUT/POST) mit eigenem Sichtbarkeits-/RBAC-Guard je Handler (PII). +17 Vitest (574->591, +3 Dateien); Adapter zusätzlich gegen das **echte apoBank-PDF** (15 realefill_-Felder gelesen + gefüllt + zurückgelesen) verifiziert; tsc+vitest+ng build+check-doc-consistency.shgrün. | Nutzer wählte Weg A (Hybrid) und lieferte das konkrete Fremdformular (apoBank-EDÜ). Mapping = differenzierender Eigenbau (G-1: PDF/Signatur bleiben Standard); Attribut-Katalog = G-8 (eine Definition, überall gleich). Mapping als JSON-Spalte statt eigener Entität (schlank, 1:1); extrahierte Felder nicht persistiert (G-2). PII-arm (nur Attribut-Schlüssel + Feldzahlen im Audit, G-5/G-6); verlustfreie Rückablage (R2-Vorversion, G-4). Wert-**Rücklauf** in die Stammdaten (über Feld-Sichtung MED-D-89) bewusst als Slice 2 (MED-OP-FORM-5) getrennt. MINOR (neues rückwärtskompatibles Feature). |server/src/pdf/pdf-formular.ts, server/src/domain/fremdformular.ts, server/src/api/fremdformular-service.ts, server/src/api/app.ts, server/src/domain/model.ts, server/src/repo/{repo,memory-repo,d1-repo}.ts, server/src/db/{schema,migrate}.ts, client/src/app/akte-feld-editor.component.ts, client/src/app/akte-unterschriften-assistent.component.ts, client/src/app/api.service.ts, server/src/version.ts, docs/architektur/Fremdformulare.md, HANDOFF, CHANGELOG, Feature-Liste, Test-Uebersicht, Design-Entscheidungen-Akte, Timesheet | | **MED-D-236** | 2026-07-25 | Backend+Frontend/Signatur · Echte Vor-Ort-/In-Person-Signatur (DocuSign embedded) | **In-Person-Signing gebaut + irreführenden 409 entfernt** (0.105.0->0.106.0, MINOR; OP-SIGN-1). Nutzerfund: bei echtem DocuSign warf „Vor Ort abschließen" einen **409** (Vor-Ort lief nur über die Attrappe abschliessenDemo, die echte Provider bewusst nicht bieten). Jetzt echte In-Person-Signatur: SignaturProvider um **vorOrtVorbereiten** (captive/embedded recipient → kein E-Mail-Versand) + **vorOrtSignaturUrl** (recipient view) erweitert; DocuSign-Adapter implementiert beide (In-Person-Envelope mit clientUserId, Host = Berater via DOCUSIGN_HOST_NAME/_EMAIL). Service vorOrtVorbereiten() nutzt In-Person wo verfügbar, sonst Fake-Fallback (eingebettet-Flag); neue Routen + same-origin-Sentinel /oeffentlich/signatur/vor-ort-fertig. Client: iFrame lädt die DocuSign-Signatur-URL (sequenziell bei mehreren Dok.), erkennt signing_completesame-origin →abgleich+Write-back → Dokument erhalten (Prüfung offen, G-4). Demo-Banner/-Schnellabschluss nur noch beim Fake (istEcht-Gate). +5 Vitest (592->597); tsc+vitest+ng build+check-doc-consistency.shgrün. **Live gegen DocuSign noch nicht verifiziert** (keine Secrets/Netz in der Session, wie MED-D-220) → OP-SIGN-1 offen bis Live-Nachweis (RunbookDeploy.md§7d). | Der 409 war ehrlich (Attrappe nicht fälschbar, MED-KB-5), aber die echte Vor-Ort-Strecke fehlte. „Echt vor Ort" = **DocuSign In-Person-Signing** (embedded/captive, kein E-Mail) — kein Eigenbau (G-1). Sicherheitsriegel bleibt: echter Adapter ohneabschliessenDemo → Attrappe weiter 409. Landung wie Sign-on-Paper (erhalten, nie auto-geprüft) wahrt G-4. Kunden-E-Mail bei In-Person optional (G-6); Signatur-URL nie persistiert (G-5). Host als eigene Secrets, kein Repo-PII. MINOR (neues rückwärtskompatibles Feature). | server/src/signatur/provider.ts, server/src/signatur/docusign.ts, server/src/api/signatur-service.ts, server/src/api/app.ts, server/src/index.ts, server/src/signatur/docusign.test.ts, client/src/app/akte-unterschriften-assistent.component.ts, client/src/app/api.service.ts, server/src/version.ts, docs/architektur/Unterschriften.md, HANDOFF, CHANGELOG, Feature-Liste, Test-Uebersicht, Timesheet | | **MED-D-237** | 2026-07-25 | Backend/Signatur · In-Person-Host = eingeloggter Berater | **DocuSign-In-Person-Host aus der eingeloggten Identität statt globalem Secret** (0.106.0->0.106.1, PATCH; Verfeinerung von MED-D-236). Nutzerfrage „Müssten die Host-Werte nicht vom eingeloggten Berater kommen?". Server leitet den Host aus akteurVon(c).email+benutzer.anzeigenameab und reicht ihn anvorOrtVorbereiten/vorOrtSignaturUrl durch (SignaturProvider/DocuSign-Adapter um optionalen host-Parameter erweitert, Typ VorOrtHost); DOCUSIGN_HOST_NAME/_EMAILbleiben Fallback. Kein Client-Change (Host serverseitig). +1 Vitest (597->598); tsc+vitest+ng build+check-doc-consistency grün. | Ein rechtssicherer Signatur-Pfad muss im DocuSign-Audit-Trail den **realen Bezeuger** zeigen (G-4), nicht ein generisches Sammel-Konto — der Host ist die hostende Person, also der eingeloggte Berater (G-3: sprechende, echte Zuordnung). Globales Secret bleibt als Fallback (Dev/kein Login, dediziertes Host-Konto), daher rückwärtskompatibel → PATCH. **Harte Voraussetzung dokumentiert:** die Berater-E-Mail muss ein Nutzer desselben DocuSign-Accounts sein (sonst lehnt DocuSign den In-Person-Host ab); Anlage + Signaturansicht nutzen denselben Host (DocuSign matcht) → derselbe Berater führt die Session durch. |server/src/signatur/provider.ts, server/src/signatur/docusign.ts, server/src/api/signatur-service.ts, server/src/api/app.ts, server/src/signatur/docusign.test.ts, server/src/version.ts, docs/architektur/Unterschriften.md, docs/architektur/Deploy.md, HANDOFF, CHANGELOG, Test-Uebersicht, Timesheet | | **MED-D-238** | 2026-07-25 | Integration/E-Signatur · DocuSign end-to-end live gegen Demo verifiziert + Private-Key-Parser gehärtet (OP-SIGN-1) | **DocuSign-Adapter live gegen die Demo-API getestet + Bug behoben** (0.106.1->0.106.2, PATCH). Mit Demo-Credentials aus dem Environment (account 108a57f9…/demo.docusign.net) den echten DocuSignSignatur-Adapter live laufen lassen (temporaeres Skript, danach entfernt): JWT-Grant + Consent ✅, Envelope real (c4fe2244…) ✅, status/erinnern✅, Webhook-HMAC-Verify ✅, void-Cleanup ✅. Dabei fielpkcs8PemToBufferauf: der Demo-Key hatte einen verstuemmelten PEM-Footer (4 statt 5 Trailing-Hyphens,…KEY----), der strikte Regex liess den Marker stehen → atobwarf "Invalid character" → JWT scheiterte still. Parser jetzt delimiter-tolerant (4+ Hyphens, literale\n, fehlende Umbrueche) + Base64-Validierung; PKCS#1-Ablehnung bleibt. +1 Vitest (598→599). | Standardwerkzeug echt verifizieren statt nur mocken (G-1). Parser-Haertung, weil Secret-Stores (GitHub-Secrets/wrangler secret put/Copy-&-Paste) PEM-Delimiter regelmaessig verstuemmeln — ein strikter Parser lehnt einen sachlich gueltigen Schluessel still ab. Nebenbefund: der deployte Key ist wohlgeformt (JWT gelingt mit dem alten Parser); die Haertung bleibt Defense-in-Depth. Test nur mit Testdaten, keine Mandanten-PII (G-5/G-6). | server/src/signatur/docusign.ts (pkcs8PemToBuffer), server/src/signatur/docusign.test.ts(+1),server/src/version.ts, HANDOFF §4, Deploy.md §7d, CHANGELOG, Test-Uebersicht, Feature-Liste, Timesheet | | **MED-D-239** | 2026-07-25 | Integration/E-Signatur · DocuSign-Webhook-Write-back in Produktion verifiziert (OP-SIGN-1) | **Der Connect-Webhook-Write-back am deployten Worker ist erbracht** (keine Versionsaenderung). Belegt an der echten Produktion (Cloudflare-MCP D1-Query + Endpoint-Probe): (1) Endpoint POST /oeffentlich/signatur/docusign-webhookerreichbar + fail-closed (401 ohne gueltige HMAC). (2) Produktive D1 haelt 3docusign-Vorgaenge, 2 vollstaendig durchgelaufen: Vorgang signiert+ Dokumentunterschrieben+ signierte Fassung in R2 + Auditsignatur.signiert. (3) Ausloeser = Webhook bewiesen via Audit-actor=system(setAkteur laeuft nur in/api/; der /oeffentlich-Webhook nutzt den Default-Actor system, audit-log.ts:34; der on-demand /api-abgleich schriebe die Nutzer-Mail, der Cron macht keinen Signatur-abgleich → einziger system-Pfad = der Webhook). (4) Zeit: 54 s zwischen Anfordern und system-Write-back (12:04:34→12:05:28 UTC) → Echtzeit-Push, kein stuendlicher Cron. | Standardwerkzeug echt verifizieren statt gestellt (G-1/G-4): der letzte offene OP-SIGN-1-Verifikationspunkt (Deploy.md §7d Schritt 4–5) ist damit erledigt. Kein Code-/Versionschange. | HANDOFF §4 (OP-SIGN-1), Deploy.md §7d, CHANGELOG, Feature-Liste, CLAUDE.md, Timesheet | | **MED-D-240** | 2026-07-25 | Doku/Nachlese · CodeRabbit-Befunde zu #275 (PII-Wording · Embedded-Flow-Genauigkeit · Quote) | **Drei valide CodeRabbit-Doku-Befunde aus #275 forward behoben** (keine Versionsaenderung, reine Doku). (1) PII (G-5/G-6): Klarname im MED-D-239-CHANGELOG-Eintrag → rollen-neutral „kein eingeloggter Nutzer-Account". (2) Genauigkeit: Deploy §7d + HANDOFF-OP-SIGN-1-„Rest" nennen jetzt explizit, dass die embedded/captive In-Person-Strecke (MED-D-236) noch nicht durchgeklickt und kein produktionsreifer Rechtssignatur-Pfad ist. (3) Lint: unpaariger Literal „Invalid character" → gerade Quotes in CHANGELOG/Decision-Log/Deploy. | Bewusst NICHT: Bullet-Konsolidierung (Repo fuehrt mehrere D-n je PR) + der darin genannte falsche #274-Link (ist #275); paarige deutsche Fliesstext-Quotes bleiben (Repo-Konvention). CodeRabbit-Befunde kamen nach dem Auto-Merge → Forward-Fix als frische Aenderung (gemergter PR ist abgeschlossen). | CHANGELOG, HANDOFF §4 (OP-SIGN-1), Deploy.md §7d, Timesheet | | **MED-D-243** | 2026-07-25 | Backend+Frontend/Signatur · AD-006 editierbarer Empfänger im Unterschriften-Assistenten | **Die in MED-D-241 deferierte AD-006-Empfänger-Deferral aufgelöst** (0.108.0->0.109.0, MINOR). Der Assistent-Kern war ✅; es fehlte das editierbare Empfänger-Feld im Versenden-Schritt. Ein optionaler empfaenger-Override (Name + E-Mail) wird jetzt durch alle Schichten gefädelt: Client-Feld (vorbelegt aus Mandant-Kontakt + Hinweis „Zeichnungsberechtigt für das gewählte Konto …" aus Bankkonto.zeichnungsberechtigt/inhaber) -> api.service -> Routen (/signatur+/vor-ort, mit E-Mail-Validierung: Remote Pflicht/400, vor Ort optional) -> SignaturService.anfordern/vorOrtVorbereiten(Override schlägt den Mandant-Default). +2 Vitest (600->602);tsc+vitest+ng build+Doku-Check grün. | Der Deferral-Grund („ein freies Eingabefeld wäre ungebunden/irreführend") ist adressiert: das Feld ist **vorbelegt mit echten, gebundenen Daten** (Mandant-Kontakt) statt Blind-Freitext, plus Zeichnungsberechtigter-Hinweis aus realen Kontodaten. Der Provider-Vertrag (unterzeichner) trug den Empfänger schon (kein Provider-Change, G-1). **Kein neues PII persistiert** — nur Versand (G-5/G-6). **Ehrliche Grenze:** die zeichnungsberechtigte Person hat keine hinterlegte E-Mail (kein Signatory-Feld im Modell) -> Hinweis nennt den Namen, E-Mail bleibt Berater-Eingabe; ein persistiertes Signatory-Email-Feld wäre eine separate, G-6-begründete Erweiterung. | server/src/api/signatur-service.ts, server/src/api/app.ts(Routen +leseEmpfaenger), client/src/app/akte-unterschriften-assistent.component.ts, client/src/app/api.service.ts, server/src/api/signatur.test.ts(+2),server/src/version.ts, CLAUDE.md, HANDOFF §2, CHANGELOG, Feature-Liste, Test-Uebersicht, Timesheet | | **MED-D-244** | 2026-07-25 | Backend+Frontend/Signatur · AD-006-Nachlese: Dokument-Scope-Guard auf den Signatur-Routen (Sicherheit) | **Sicherheits-Forward-Fix zum gemergten MED-D-243** (0.109.0->0.109.1, PATCH). CodeRabbit-Review zu #279 fand zu Recht: der neue Empfänger-Override (AD-006) erlaubt, das Signatur-Ziel frei zu wählen — doch die Routen POST /api/dokumente/:docId/signaturund/signatur/vor-orttrugen **keinen** Sichtbarkeits-Guard (der/api/mandanten/:id-Chokepoint greift bei :docId-Routen nicht). Ein authentifizierter Berater mit einer fremden docIdhätte damit ein **fremdes Dokument an eine beliebige E-Mail senden** können = Daten-Exfiltration. Fix:ladeDokScope(bisher nur in der Fremdformular-Strecke, gleiche Klasse von:docId-Routen) auf gemeinsamen Scope **hochgezogen** und vor leseEmpfaenger/sig.anfordern/vorOrtVorbereitenin beide Signatur-Routen gesetzt → Fremd-Mandant **404** (kein Existenz-Leak), Schreiben verlangtmandant_bearbeiten. Zusätzlich zwei valide CodeRabbit-Funktionsbefunde: **(a)** vor Ort wird keine Empfänger-E-Mail mehr mitgeschickt (empfEmail = vorOrt ? '' : …— In-Person signiert eingebettet, kein Versand); **(b)** irreführender Hinweis „… geht an diese Person" → „Empfänger bei Bedarf auf diese Person ändern" (der Zeichnungsberechtigte ist ein Vorschlag, kein Auto-Ziel). +1 Vitest (602->603, HTTP-Guard-Test: fremd→404 kein Versand, eigen→201).tsc+vitest+ng build+Doku-Check grün. | Der Befund ist real und sicherheitsrelevant (bestätigt gegen ladeDokScope/die Route) → sofortiger Forward-Fix. #279 war beim Review bereits per Auto-Merge gemergt → frische Änderung (Nachlese-Muster wie MED-D-240), kein Reopen. Guard **geteilt** statt dupliziert (eine Regel, G-2/G-3); kein neuer Endpunkt/keine neue Persistenz (G-1/G-6). Bewusst **nicht** übernommen: CLAUDE.md-Governance-Refactor + CHANGELOG-PR-Link-Vorschläge (Repo-Konventionen MED-D-140/MED-D-144). PATCH (sicherheitsrelevanter Fix an rückwärtskompatibler API). | server/src/api/app.ts (ladeDokScopehochgezogen + Guard auf beide Signatur-Routen),client/src/app/akte-unterschriften-assistent.component.ts(vor-Ort-E-Mail-Clear + Hinweis-Wording),server/src/api/signatur.test.ts(+1 HTTP-Guard-Test),server/src/version.ts, CLAUDE.md, HANDOFF §2, CHANGELOG, Feature-Liste, Test-Uebersicht, Timesheet | | **MED-D-242** | 2026-07-25 | Frontend/Akten-Cockpit · AD-014 "Über den Link hochgeladen"-Statusliste | **Die in MED-D-241 deferierte AD-014-Liste gebaut** (0.107.0->0.108.0, MINOR). Der Handoff-Prototyp meint mit "Über den Link hochgeladen" die **angeforderten Dokumente + Upload-Status**, nicht je-Token getrackte Uploads. Das Self-Service-Panel (akte-einladungen) zeigt jetzt mandantweit die Self-Service-Pipeline: angefordert-> "noch kein Upload" (amber),erhalten -> "hochgeladen, zu prüfen" (grün) + **Prüfen**-Aktion (->geprüft, Item-/Ring-Propagation). Reine Client-Sicht über api.dokumente+api.dokumentStatusSetzen; ng build+ 600 Vitest grün. | Die MED-D-241-Deferral ("benötigt Upload-Daten je Einladung") hatte über-skopiert: die Upload-Links existieren **je Dokument, nicht je Einladung** — die Liste braucht daher gar keine neue Einladung<->Dokument-Verknüpfung, sondern nur die schon vorhandenen Dokument-Stati (G-8: eine Datenquelle). Standard-Endpunkte statt Nachbau (G-1), keine neue Persistenz/Migration (G-2). Ein Public-Upload-Endpunkt auf der Onboarding-Strecke wäre eine außenwirksame Zero-Trust-Ausnahme gewesen — bewusst **nicht** gebaut, da die Daten ohne ihn vollständig sind. Weiterhin deferiert: AD-006-Empfänger-Feld (Server-Wiring). |client/src/app/akte-einladungen.component.ts, server/src/version.ts, CLAUDE.md, HANDOFF §2, CHANGELOG, Feature-Liste, Test-Uebersicht, Timesheet | | **MED-D-241** | 2026-07-25 | Design/Akten-Cockpit · Design-System-Handoff "Akten-Cockpit 1a (Detail)" exakt übernommen | **Präzise Rekonziliation des bereits gebauten Akten-Cockpits (MED-D-188) gegen den finalen Design-Prototyp** (0.106.2->0.107.0, MINOR). claude_design-MCP-Import nicht autorisierbar (kein interaktives /design-login) → Handoff-ZIP genutzt (Prototyp + akte-patterns.md+design-decisions.mdAD-001…015 + 17 Screenshots). Vier Nutzer-Entscheidungen (AskUserQuestion) an echten Widersprüchen zu bisherigen Festlegungen: **(1)** Stammdaten "Prototyp exakt" → direkt editierbar + versioniert/auditiert, **löst die MED-D-147-Sperre (read-only, nur via Formular-Rücklauf) ab**; **(2)** Lifecycle-Rail: Wording fixen, Editier-Funktion behalten; **(3)** Unterschriften-Assistent: ergänzen, echte DocuSign-/Multi-Doc-Technik behalten; **(4)** Onboarding-Doks: angleichen, zwei Datenquellen getrennt lassen. Umgesetzt: LifecycleRing 5 diskrete SVG-Bögen + Tooltip "Lebenszyklus des Kunden … Schritt N von 5"; Umbenennung "Mandats-Status"→"Lebenszyklus des Kunden" (AD-001, Begriff war für die Person verboten); volles Rail-Stammdaten-Grid; "Anstehende Aufgaben"-TaskCards + rotes "N blockierend"-Pill in die Kontext-Spalte (redundante "Jetzt dran"-Mittelkarte entfernt); editierbare Stammdaten (Server-PATCH umtelefon/geburtsdatum/strasse/plz/orterweitert — Persistenz/Version/Audit trugen die Felder schon; Anschrift atomar, G-8); Versions-Pille "Stand: vN · Datum"; VersionedField "vN · bis Datum · Wert · Quelle"; Wording in Bank/Self-Service/Mandat-Overlay/Assistent. +1 Vitest (599→600). | Nutzerauftrag "Design exakt übernehmen, bei Widersprüchen fragen" (G-3-Wording ist verbindlich; AD-001 verbietet "Mandats-Status" an der Person). MED-D-147 auf **expliziten Nutzerwunsch** abgelöst — die direkte Bearbeitung bleibt **versioniert+auditiert** (append-only, G-4), die Sorge hinter MED-D-147 (Auditierbarkeit) ist damit gewahrt. **Compliance proaktiv (DE):** Steuernummer/Steuer-ID des Prototyp-Grids NICHT übernommen — regulierte PII (Steuer-ID §139b AO, DSGVO/G-5/G-6), erst nach Weltmodell-/Compliance-Entscheidung (Risikoregister/KB). Deferiert (ehrlich, kein Fake): "Über den Link hochgeladen"-Liste (AD-014, fehlende Daten) + editierbares Empfänger-Feld (AD-006, Server-Wiring). |client/src/app/mandant-detail.component.ts, client/src/styles.css (.mw-ring), akte-versioned-field/-einladungen/-auftraege/-unterschriften-assistent.component.ts, client/src/app/api.service.ts (stammdatenAendern), server/src/api/app.ts(PATCH + Felder),server/src/api/service.ts(Audit),server/src/api/app.test.ts(+1),server/src/version.ts, CLAUDE.md, HANDOFF §2/§4/§5, CHANGELOG, Feature-Liste, Test-Uebersicht, Risikoregister, Kunden-Besprechungspunkte, Timesheet | | **MED-D-245** | 2026-07-26 | Frontend/UI · Build-Version dauerhaft sichtbar (inkl. Build-Zeitpunkt) | **Die Build-Version wird jetzt in allen internen Sichten angezeigt** (0.109.1->0.110.0, MINOR). Die App-Shell-Kopfzeile trug v… · build … · {Zeitpunkt}bereits; die zwei Vollbild-Hauptsichten (Cockpit/, Akte /mandant/:id) rendern jedoch mit **eigener** Chrome ohne diese Shell → Cockpit zeigte gar keine Version, Akte nur die SemVer. Beide tragen jetzt den vollen Stempel v{SemVer} · Build {Nr.} · {Zeitpunkt}(Cockpit: Header-Chip vor dem Benutzer-Chip; Akte: „Stand:"-Zeile). Reine Client-Anzeige über den bestehendenhealth-Endpunkt; kein Server-/Persistenz-Change. ng buildgrün, Tests unverändert. | Nutzerwunsch „immer die Build-Version inkl. Zeitpunkt anzeigen" — „immer" verlangt die beiden Shell-losen Hauptsichten, die es bisher nicht zeigten.BUILD_NUMBER/BUILD_ZEIT bleiben git-gestempelt (gen-build-number.mjs, OP-PM-1, nicht von Hand). Öffentliche Kundenstrecken bewusst außen vor (keine Shell/kein /api, G-5). Zeit-Format über datumZeit(G-3, ein Format-Paar). Nebenbei: überholte „Stammdaten read-only"-Notiz inAkten-Cockpit-Redesign.md§4 auf MED-D-241-Stand korrigiert (OP-DOCS-1). |client/src/app/cockpit.component.ts, client/src/app/mandant-akte.component.ts, client/src/styles.css (.mw-nowrap), server/src/version.ts, docs/architektur/Akten-Cockpit-Redesign.md, CLAUDE.md, HANDOFF §2, CHANGELOG, Feature-Liste, Test-Uebersicht, Timesheet | | **MED-D-246** | 2026-07-26 | Domäne/Ableitung · Abgelaufene Dokumente als abgeleitete Aufgabe (nicht persistiert), AD-005 | **AD-005 eingelöst — abgeleitet statt persistiert** (0.110.0->0.111.0, MINOR). Ein R3-Dokument mit überschrittenem gueltigBiswar in beiden Ableitungs-Sichten unsichtbar (bliebgeprüft/dokumentVorhanden→ nichtdokumenteOffen; kein Auto-Setter auf Status abgelaufen). Neuer reiner Helfer dokumentAbgelaufen(d, jetzt); AktenreifeInput.dokumenteAbgelaufen → eigener Reifepunkt (dokument/Stufe aktiv/Schwere wichtig) + naechsteSchritte-Schritt dokumente-erneuern+offenePunkte()-Eintrag (überfällig, faelligAm= Gültigkeitsdatum). Getrennt vondokumenteOffen(fehlt = anfordern ≠ abgelaufen = erneuern). Client: „erneuern"-TaskCard (Akte+Cockpit) + roter „abgelaufen"-Chip jetzt auch abgeleitet ausgueltigBis. +7 Vitest (603->610). | Nutzer-Entscheidung „Aufgaben zu abgelaufenen Dokumenten u.ä. nicht persistieren, sondern ableiten — hält das Backlog sauber" — schärft **G-2** (Derived State nie speichern): die Handlung wird bei jeder Sicht frisch berechnet, es landet **keine** Auto-Wiedervorlage im Backlog (per Test bewiesen: keine Wiedervorlage angelegt). Schwere wichtig(nichtblockierend): ein einmal geprüftes, nun abgelaufenes Dokument ist fällig, aber kein Aktenreife-Blocker (D-41). Persistierter Status bleibt geprüft; der Ablauf wird abgeleitet dargestellt — bewusste Verfeinerung ggü. AD-005s ursprünglichem „Status steht auf Fehlt". | server/src/domain/aktenreife.ts (+dokumenteAbgelaufen), server/src/domain/naechste-schritte.ts (dokumente-erneuern), server/src/api/service.ts (dokumentAbgelaufen+offenePunkte/baueAktenreifeInput), client/src/app/mandant-detail.component.ts (dokAbgelaufen+ Chip),aktenreife.test.ts/naechste-schritte.test.ts/dokument.test.ts(+7),design-decisions.md(AD-005),server/src/version.ts, CLAUDE.md, HANDOFF §2, CHANGELOG, Feature-Liste, Test-Uebersicht, Timesheet | | **MED-D-247** | 2026-07-26 | Backend+Frontend/Signatur · Formular-Rücklauf-Prüfung (AD-009, DocuSign form_data → Review-and-apply), live verifiziert | **AD-009 gebaut + live gegen DocuSign Demo verifiziert** (0.111.0->0.112.0, MINOR). Schließt den Fremdformular-Loop (Prefill = Slice 1 MED-D-235; Wert-Rücklauf = jetzt, löst MED-OP-FORM-5-Slice-2). Provider-Vertrag formularRuecklauf(externalId)(optional); DocuSign-Adapter liestGET …/form_data(Feldname→Wert); FakesetzeFormularWerte-Seam. Domäne ATTRIBUT_ZU_STAMMZIEL(nur verlustfrei rückschreibbare Person/Kontakt/Anschrift,satisfies STAMM_ZIELE) + ruecklaufRegelnspeisen die bestehendebaueVorschlaege/bauePatch-Maschine. SignaturService.formularRuecklauf(Diff, on-demand, nichts persistiert) +ruecklaufUebernehmen(nur gewählt+gültig → versionierterupdateMandant, Quelle formular) + Audit formular.ruecklauf_gesichtet/_uebernommen. Routen GET/POST /api/dokumente/:docId/ruecklauf[/uebernehmen](Dokument-Scope-Guard). Client: „Rücklauf prüfen"-Overlay (Diff, Checkbox je gültigem Feld). **Live verifiziert** (Session-DocuSign-Demo-Credentials, temp. Skript, danach entfernt): JWT → Envelope mit Text-Feld →form_data {f_plz:"40210"}→ gevoidet. +7 Vitest (610→617). | Nutzer „AD-009, nutze für die Verifikation die env-Angaben hier in der Session." **Vier-Augen/G-4:** Kundenkorrektur ≠ automatische Stammdatenänderung → Review-and-apply. **G-6:** die zurückgelesenen Werte (PII) werden **nicht persistiert**, on-demand aus DocuSign gelesen, erst „Übernehmen" schreibt. **G-1/G-2:** dieselbe Review-Maschine wie die übrigen Formular-Rückläufe, kein Zweitpfad; Rückschreib-Whitelist gegenSTAMM_ZIELEtypverankert. Neue Stammdaten-Quelleformular(Enum-Erweiterung;quelle-Spalte ist plain TEXT → migrationsfrei). Bank/Praxis-Rückschreibung bewusst außen vor (eigene Entitäten, kein eindeutiges Mandant-Ziel). **Grenze:** Client-Overlay im Browser noch nicht durchgeklickt (Attrappe liefert ohne Seam leere Rückläufe); der reale form_data-Pfad ist gegen DocuSign verifiziert. | server/src/signatur/provider.ts·signatur/docusign.ts (formularRuecklauf) · signatur/fake.ts·domain/fremdformular.ts (ATTRIBUT_ZU_STAMMZIEL/ruecklaufRegeln) · domain/enums.ts(Quelleformular) · api/signatur-service.ts (formularRuecklauf/ruecklaufUebernehmen) · api/app.ts(2 Routen) ·client/src/app/api.service.ts·client/src/app/mandant-detail.component.ts(Overlay) ·signatur.test.ts/fremdformular.test.ts(+7) ·server/src/version.ts · CLAUDE.md · HANDOFF §2 · CHANGELOG · Feature-Liste · Test-Uebersicht · design-decisions.md · Fremdformulare.md · Timesheet | | **MED-D-248** | 2026-07-26 | Architektur/Fremdformulare · Einbindung neuer Fremd-Formulare = DocuSign-Templates/Tabs (Weg B) | **Neue Fremd-Formulare werden über DocuSign-Templates mit Tabs eingebunden** (keine Versionsänderung — Design-/Doku-Entscheidung, Bau folgt). Einmalig je Formular: PDF als DocuSign-Template, Tabs im DocuSign-Editor platzieren (Ankertext bevorzugt, sonst Koordinate), **tabLabel= Weltmodell-Attribut-Schlüssel** (Mapping = Identität → Prefill+Rücklauf ohne separate Feldnamen-Tabelle). Medidentas hält nur eine Vorlagen-Referenz{name, templateId, attribute[], eIDAS-Niveau} (kein PDF-Blob, G-1/G-6). Laufzeit: Envelope aus Template (compositeTemplates), Tab-Werte aus Stammdaten vorbefüllt, signieren (Remote/In-Person), Rücklauf via form_data→ die AD-009-Review-and-apply (MED-D-247) läuft unverändert. | Nutzerwahl „B". **Deckt flache PDFs** (Druck/Scan ohne AcroForm) — der häufige Bankformular-Fall, den Weg A (pdf-lib) nicht füllen kann. **G-1:** ein Werkzeug (DocuSign) für Füllen+Signieren+Rücklesen; ein Eigenbau-Feld-Editor (Weg C) würde DocuSign-Templates nachbauen → bewusst nicht. **Ankertext** übersteht kleine Layout-Änderungen des Partners. Weg A (AcroForm) bleibt Schnellpfad für PDFs mit Feldern. **Zurückgestellt (Nutzer): MED-OP-FORM-6** — Eigen-Formulare (R12) ebenfalls als DocuSign-Templates → Eigen+Fremd an *einer* Stelle; jetzt nicht bauen, als OP gehalten. Kundenklärung MED-KB-11. |docs/architektur/Fremdformulare.md§8 (+Roadmap Slice 3 · Bezug) · HANDOFF §4 (MED-OP-FORM-5 aktualisiert, MED-OP-FORM-6 neu) ·docs/betrieb/Kunden-Besprechungspunkte.md(MED-KB-11) | | **MED-D-249** | 2026-07-26 | Doku/Nachlese · CodeRabbit-Review zu MED-D-248 (#282) | **Forward-Fix zum gemergten #282** (keine Versionsänderung). 2 von 3 CodeRabbit-Befunden übernommen: (a) Katalog-Feldname überall auf{name, templateId, attribute[], eIDAS-Niveau}vereinheitlicht (war teilsNiveau); (b) MED-KB-11 (5) umformuliert — die Kunden-Korrektur-Schleife ist per MED-D-89/MED-OP-FORM-4 **verbindlich**, nicht optional; offen ist nur ihre Anwendung auf **signierte** Formulare. Bewusst NICHT übernommen: CHANGELOG-PR-Link (Repo-Konvention MED-D-144 — Branch-Einträge tragen keinen nachträglichen Link). | Befunde (a)/(b) real und in Sekunden verifizierbar (Doku-Konsistenz/G-3; verbindliches Muster nicht als optional darstellen). #282 war beim Review bereits gemergt → frische Änderung statt Reopen (Nachlese-Muster MED-D-240/244). (1) folgt der etablierten, dokumentierten CHANGELOG-Konvention (kein Sonderfall). | docs/architektur/Fremdformulare.md(§7 Bezug + §8 Korrektur-Schleife-Bullet),docs/betrieb/Decision-Log.md(Katalog-Feldname),HANDOFF.md§4 (Katalog-Feldname),docs/betrieb/Kunden-Besprechungspunkte.md (MED-KB-11 (5)), CHANGELOG, Timesheet | | **MED-D-250** | 2026-07-26 | Backend+Frontend/Fremdformulare · Weg B gebaut (DocuSign-Templates/Tabs), live verifiziert | **Setzt MED-D-248 (Weg B) um** (0.112.0->0.113.0, MINOR). Neue Entität FremdformularVorlage {name, templateId, attribute[], niveau}(Migration v47, kein PDF-Blob/PII, G-1/G-6); ProvideranfordernAusTemplate(DocuSigncompositeTemplates: Server-Template + Inline-Template mit Unterzeichner + vorbefüllten Text-Tabs), Fake mit Round-trip-Seam; Domäne baueTabWerte(tabLabel=Attribut→Wert) +identitaetsMapping(AD-009-Rücklauf unverändert nutzbar);FremdformularVorlageService(Katalog-CRUD +starten= Dokument+Vorgang+Envelope). Routen/api/weltmodell-attribute, /api/fremdformular-vorlagen(Admineinstellungen_verwalten), /api/mandanten/:id/fremdformular-vorlagen/:id/starten(Mandant-Scope-Chokepoint). Client: Verwaltung-Registrierung + Akte-„vorbefüllt starten". Live gegen DocuSign Demo verifiziert (Template → Envelope aus Template →form_data-Prefill anschrift.plz=40210→ gevoidet). +8 Vitest (617->625). | Nutzer „B implementieren". **G-1:** DocuSign-Template statt Eigenbau-Feld-Editor → deckt auch flache PDFs. **Symmetrie:**tabLabel= Weltmodell-Schlüssel → Prefill+Rücklauf ohne separate Feldnamen-Tabelle; das erzeugte Dokument trägt das Identitäts-Mapping, damit die bestehende AD-009-Maschine unverändert greift (kein Zweitpfad, G-2). **G-6:** Katalog hält nur Attribut-Schlüssel, Audit PII-arm (Zählungen/Enums). Template-Rolle-KonventionUnterzeichner(KB-11). Admin-CRUD reuseeinstellungen_verwalten(keine neue Permission → keine RBAC-Matrix-Änderung). **Grenze:** Client-Strecke im Browser noch nicht durchgeklickt; Template-Kern live belegt. |server/src/domain/model.ts (FremdformularVorlage) · db/migrate.ts(v47) ·db/schema.ts·repo/repo.ts+memory-repo.ts+d1-repo.ts·domain/fremdformular.ts (baueTabWerte/identitaetsMapping) · signatur/provider.ts+docusign.ts+fake.ts (anfordernAusTemplate) · api/fremdformular-vorlage-service.ts(neu) ·api/app.ts(Routen) ·client/src/app/api.service.ts·verwaltung.component.ts·mandant-detail.component.ts·fremdformular.test.ts(+3)/fremdformular-vorlage.test.ts(neu,+5) · Fremdformulare.md §6/§8 · HANDOFF · CHANGELOG · Feature-Liste · Test-Uebersicht · version.ts · CLAUDE.md · Timesheet | | **MED-D-251** | 2026-07-26 | Backend+Frontend/Fremdformulare · CodeRabbit-Nachlese zu Weg B (#284) | **Forward-Fix zum gemergten #284** (0.113.0->0.113.1, PATCH, keine Verhaltensänderung). **(1) Unique je Template:** eine Katalog-Zeile je DocuSign-Template — Migration **v48** (Dedup-UPDATEjetemplate_id, dann CREATE UNIQUE INDEX idx_ff_vorlage_template), schema.templateId.unique(), Service-Vorabprüfung in anlegen(klarer Nutzer-Grund statt DB-Constraint-Fehler) + Memory-Repo-Guard (Test-DB verhält sich wie D1). **(2) Kein verwaistes Dokument:**starten ruft den Provider (anfordernAusTemplate) **vor** createDokument— wirft der Envelope-Call, entsteht keine Waise (es gibt keinendeleteDokument-Primitiv). **(3) Fake:** markiereSignierterhält dieformularWerte(Rücklauf nach Signatur nicht mehr leer). **(4) Client:**weltmodellAttribute-/fremdformularVorlagen-Ladefehler surfacen jetzt (kein stiller error: () => {}); Wording „Tab-Name" → „Tab-Label (tabLabel)". +2 Vitest (625->627). | CodeRabbit #284. Alle Befunde real und in Sekunden verifizierbar (Datenintegrität/G-4 · UX-Ehrlichkeit · Doku-Konsistenz/G-3). #284 war beim Review bereits gemergt → frische PATCH-Änderung statt Reopen (Nachlese-Muster MED-D-240/244/249). **Bewusst NICHT übernommen:** MED-Präfix auf die Entität-ID (ungültig — FremdformularVorlagenutztneueId()= nackte ULID) und reine Straight-Quote-Nitpicks (repo-weites Muster, geringer Nutzen). |server/src/api/fremdformular-vorlage-service.ts·signatur/fake.ts·db/migrate.ts(v48) ·db/schema.ts·repo/memory-repo.ts·client/src/app/verwaltung.component.ts·mandant-detail.component.ts·fremdformular-vorlage.test.ts(+2) · HANDOFF · CHANGELOG · Feature-Liste · Test-Uebersicht · Management-Summary · version.ts · CLAUDE.md · Timesheet | | **MED-D-252** | 2026-07-26 | Frontend+Backend/Cockpit · Fokus-Seite entschlackt + Mandant-Filter/-Suche + „Zu fakturieren" | **Cockpit-Fokus umgestaltet** (0.113.1->0.114.0, MINOR). Nutzer: „Wie können wir diese Seite entschlacken? … einfacher Weg, um einen bestimmten Mandaten zu öffnen oder zu filtern, zB wo rechnungen offen sind." → gewählt „a+1+2+3". **(A) Entschlacken:** „Als Nächstes" **nach Mandant gruppiert** (restGruppen, alle Züge eines Kunden zusammen statt verstreut) · „Brennt"-Rail **je Mandant eine Zeile** dedupliziert (schlimmster Rückstand + Punkte-Zähler) · Kontext-Liste „Offen bei diesem Mandanten" auf 6 **gekappt** (+N weitere, Rest in der Akte). **(1+2) Sichtbare Filterleiste:** Mandant-**Suche** (Freitext) + **Kategorie-Chips** (5 Offen-Kategorien an/aus) schränken alle Bahnen ein (Ring bleibt Tagesganzes); löst die vorher nur im Cmd-Palette versteckte Filterung ab. **(3) „Zu fakturieren"-Filter:** neuer abgeleiteter Wert MandantCockpit.offeneFakturierungMinuten(SummedauerMinutenje Mandant mitabrechenbar && !abgerechnet, G-2, nicht persistiert); Chip schaltet einen Modus, der die Mandanten mit offener abrechenbarer Zeit listet (Absprung in die Akte). +1 Vitest (627->628). | Entschlacken + gezielter Mandant-Zugriff (True North #1/#2). **G-2:** Fakturierungs-Minuten **abgeleitet** aus der Leistungszeit, nie doppelt gespeichert. **Abgrenzung (MED-KB-12):** „offen zu fakturieren" = abrechenbar & noch nicht abgerechnet; die **echte Rechnung** entsteht extern (SevDesk, OP-INVOICE-1) — der Filter ist nur der Hinweis „hier wartet Abrechenbares". **Grenze:** Server+Build+Unit verifiziert; die Client-Strecke im Browser noch nicht interaktiv durchgeklickt. | server/src/api/service.ts (MandantCockpit.offeneFakturierungMinuten+cockpit()) · app.test.ts(+1) · client/src/app/api.service.ts·cockpit.component.ts(Filterleiste/Gruppierung/Fakturierung) ·styles.css (.mw-fchip) · Decision-Log · HANDOFF · CHANGELOG · Feature-Liste · Test-Uebersicht · Kunden-Besprechungspunkte MED-KB-12 · version.ts · CLAUDE.md · Timesheet | | **MED-D-253** | 2026-07-26 | Frontend/Cockpit + Doku · CodeRabbit-Nachlese zu MED-D-252 (#286) | **Forward-Fix zum gemergten #286** (keine Versionsänderung, kein Verhaltens-Regressionsrisiko). Übernommene Befunde: **(1)** offenBeiKappe(c.mandantId) wurde je Kontext-Zeile 3× ausgewertet → jetzt einmal via **@let kontextOffen** gecacht (Angular-Template-Memoisierung). **(2)** Die **Kategorie-Chips** blieben im „Zu fakturieren"-Modus sichtbar/klickbar, obwohl fakturierungMandantensie ignoriert → jetzt in dem Modus **ausgeblendet** (nur die Mandant-Suche greift dort). **(3)** Doku-Konsistenz: Sanity-Checkliste True-North-#2-Zeile um den „Zu fakturieren"-Filter ergänzt (nicht nur Header-Version); Timesheet-Gesamt196.4→**196.2** an die KW-Summe (36.5+57.3+29.7+72.73=196.23) angeglichen; Management-Summary „Investierte Zeit" ≈185 h→**≈196 h** an die Timesheet-Wahrheit synchronisiert. | CodeRabbit #286. Befunde real und in Sekunden verifizierbar (Rendering-Effizienz · UX-Ehrlichkeit · Doku-Konsistenz/G-2). #286 war beim Review bereits gemergt → frische Änderung statt Reopen (Nachlese-Muster MED-D-240/244/249/251). **Bewusst NICHT übernommen:** (a) **N+1 in cockpit()** (je Mandant listLeistungszeitByMandant) — die Cockpit-Aggregation ist **bereits** N+1 (Onboarding + Aufträge je Mandant); ein SQL-SUM()-Aggregat bräuchte neue Repo-Methoden über memory+d1 und ist für den Einzeloperator-Betrieb unnötig → als Optimierung aufgeschoben, falls die Portfolio-Größe es erzwingt. (b) **CHANGELOG-Branch- statt PR-Link** — Repo-Konvention (MED-D-144: im selben Commit entstandene Einträge tragen den Branch-Namen, kein retroaktiver Link; wie MED-D-249). (c) **Straight-Quote-Nitpicks** — das Repo nutzt durchgängig deutsche „…"(Opener„+ Straight-Closer"); nur die neuen Zeilen umzustellen bräche die lokale Konsistenz; markdownlint ist nicht Teil des CI-Gates. (d) **MD038** — keine echten führenden/nachgestellten Leerzeichen in Code-Spans reproduzierbar (nur legitime interne Spaces in Ausdrücken wie abrechenbar && !abgerechnet). | client/src/app/cockpit.component.ts (@let, Chip-Ausblendung) · docs/betrieb/Sanity-Checkliste.md·docs/betrieb/Timesheet.md·docs/produkt/Management-Summary.md · Decision-Log · CHANGELOG | | **MED-D-254** | 2026-07-26 | Backend+Frontend/Signatur · DocuSign-Fehler im Live-System sprechend machen (OP-SIGN-1) | **Bugfix** (0.114.0->0.114.1, PATCH). **Symptom (Nutzer, Live):** beim „Versenden" im Unterschriften-Assistenten erscheinen die generischen Toasts „Verbindung zum Server fehlgeschlagen" + „Anfrage fehlgeschlagen" — der echte DocuSign-Grund blieb verborgen. **Ursache:** die Signatur-Anfrage-Routen (/api/dokumente/:docId/signatur[/vor-ort]) reichten jeden Provider-Wurf als **unbehandelten 500** durch (der DocuSign-Adapter wirft bei fehlenden PDF-Bytes, fehlendem Empfänger oder Upstream-Fehler JWT/Consent/Envelope). **Fix:** SignaturService.anfordern/vorOrtVorbereitenprüfen beim **echten** Provider **vorab** (Bytes/Empfänger) und **fangen** den Provider-Wurf ab → typisierte Gründekein_inhalt/kein_empfaenger/provider_fehler(detail); die Routen mappen auf **422** (klarer Handlungshinweis: „Dieses Dokument hat keine abgelegte Datei …" / „Kein Empfänger …") bzw. **502** (sanitisierter DocuSign-Grund, server-seitig PII-arm geloggt) statt 500. Client: der Fehler-Interceptor bevorzugt bei 5xx die **Server-Klartextmeldung**; der Assistent zeigt bei komplettem Fehlschlag den konkreten Grund statt „Anfrage fehlgeschlagen". **Prod-Befund (D1-Query):** DocuSign funktioniert grundsätzlich (2 signiert, 1 gesendet) — alle erfolgreichen Vorgänge hatten eine abgelegte Datei; fileless Dokumente sind der wahrscheinlichste Auslöser des opaken 500. +5 Vitest (628->633). | Live-Fehlerbild ohne Diagnosewert (True North #2/#3) — ein 500 sagt weder Nutzer noch Support, WAS bei DocuSign scheitert. Ein früher, typisierter Grund macht den Fehler handlungsleitend (Datei fehlt → PDF ablegen; Empfänger fehlt → im Assistenten setzen; Upstream → echter DocuSign-Status im Log/Toast). G-6: detailsanitisiert (Status + kurzer Snippet, keine Secrets/Kunden-PII), auf 200 Zeichen begrenzt. **Grenze:** der exakte Live-Grund zeigt sich erst beim nächsten Versand mit der neuen Meldung; beide plausiblen Ursachen (Datei fehlt / DocuSign-Upstream) sind jetzt abgedeckt. |server/src/api/signatur-service.ts(Vorab-Prüfung + try/catch +providerFehlerText) · server/src/api/app.ts (signaturFehlerAntwort422/502 + Log) ·client/src/app/fehler.interceptor.ts(Server-Klartext bei 5xx) ·client/src/app/akte-unterschriften-assistent.component.ts(konkreter Grund) ·signatur.test.ts(+5) · HANDOFF · CHANGELOG · Feature-Liste · Test-Uebersicht · version.ts · CLAUDE.md · Timesheet | | **MED-D-255** | 2026-07-26 | Prozess+Backend/Härtung nach dem DocuSign-Live-Vorfall (#288/#289) | **Zwei Härtungen** (0.114.1->0.114.2, PATCH). **(A) Push-Guardrail gegen den #288-Fehler:** #288 mergte ein Duplikat und der Fix erreichte nie main/Prod, weil ein Commit auf **detached HEAD** entstand und git pushdie **stale Branch-Ref** verschickte. Eingecheckter.githooks/pre-push-Hook bricht einen Push aus detached HEAD (bzw. Spitze≠HEAD) ab; per git config core.hooksPath .githooksinscripts/session-start-hook.shje Session automatisch scharf; verbindliche 4-Schritt-Push-Disziplin inagents.md §7(checkout -B statt detached · Remote==Local nach Push prüfen · PR-Diff vor Merge sichten · Deploy verifizieren). **(B) CodeRabbit-#289-Nachlese am Signatur-Dienst:** (1) **Sicherheit/G-6** —providerFehlerText **redigiert E-Mail-Adressen** ([email]), bevor der DocuSign-Fehler in 502-Antwort **und** Log fließt (DocuSign echot bei "invalid email" die Adresse zurück → keine Empfänger-PII nach außen); (2) **Robustheit** — der Ablage-Read (nextcloud.get) + die Empfänger-Auflösung laufen jetzt **mit im try/catch** (ein R2-Read-Fehler wird zu provider_fehler, nicht zu einem opaken 500) — symmetrisch in anfordern**und**vorOrtVorbereiten. +2 Vitest (633->635). | (A) Verhindert die schlimmste Klasse "Fix gemergt, aber nie live" — als Guardrail (Hook) **und** Konvention (agents.md), weil beides zusammen greift (Hook = mechanisch, Konvention = für Mensch/Agent). (B) Beide Befunde real: die rohe res.text()-Provider-Antwort darf keine Kunden-PII in Antwort/Log tragen (G-5/G-6/RISK-1); der Upstream-Read war exakt der Fehlermodus (opaker 500), den MED-D-254 beseitigen sollte. | .githooks/pre-push(neu) ·scripts/session-start-hook.sh(hooksPath + Reminder 8) ·docs/konventionen/agents.md§7 ·server/src/api/signatur-service.ts(Redaktion + try/catch-Weitung) ·signatur.test.ts(+2) · Decision-Log · CHANGELOG · HANDOFF · Test-Uebersicht · version.ts · CLAUDE.md · Timesheet | | **MED-D-256** | 2026-07-26 | Backend/Signatur+Dokumenterzeugung · Eigenformular beim Versenden erzeugen+vorbefüllen (R12→R4) | **Neues Feature** (0.114.2->0.115.0, MINOR). Nutzer (Live, Makler-Alleinauftrag): "Hier sollte das Formular erstellt und vorausgefüllt werden - die Eingaben vom Kunden sollen dann zurückfließen." **Befund:** die Dokument-Erzeugung (DokumentgenerierungService, R12) existiert und kennt die Makler-Vorlage, aber der Unterschriften-Assistent rief sie nie auf → das Dokument hatte keine Datei → 422 kein_inhalt(MED-D-254). **Fix (Baustein 1):**SignaturService.anfordern/vorOrtVorbereitenerzeugen ein bekanntes **Hausformular** ohne abgelegte Datei jetzt **on-the-fly** — neuevorlageFuerBezeichnung(bezeichnung)(Dokument trägt keinendokumenttyp, nur die sprechende Bezeichnung → Vorlage über Titel-Match, exakt oder generierungBezeichnung-Form), dann befuelleVorlage(aus Stammdaten) +erzeugePdf+ Ablage-PUT +nextcloudPfadam bestehenden Dokument (append-only Auditdokument.eigenformular_erzeugt, PII-arm). Danach läuft die Signatur normal. Bezeichnung ohne Vorlage (echtes Fremdformular wie „Personalausweis") → bleibt kein_inhalt. +2 Vitest (635->637). | Behebt den 422 für Eigenformulare direkt und macht die Assistenten-Zeile „Formular-Vorschau · füllt beim Signieren aus" wahr (True North #2/#3). Reuse der vorhandenen R12-Engine (G-1/G-2, kein Zweitpfad); nur pure Funktionen + der schon injizierte NextCloud-Client, kein neuer Dienst. **Grenze/OFFEN (Baustein 2, MED-OP-FORM-6):** die erzeugte PDF ist eine **flache** „Angaben aus dem Stammsatz"-Tabelle ohne ausfüllbare Felder → **echter Kunden-Rücklauf** (Anschrift/Geburtsdatum vom Kunden ausgefüllt → AD-009 zurück in die Stammdaten) braucht die **ausfüllbare Weg-B-Fassung** (Makler-Alleinauftrag als DocuSign-Template registrieren, dann greifen Prefill + AD-009 unverändert). Empfehlung dokumentiert; Umsetzung nach Kunden-Steuerung. | server/src/domain/dokumentvorlagen.ts (vorlageFuerBezeichnung) · server/src/api/signatur-service.ts (erzeugeEigenformular+ Aufruf in anfordern/vorOrtVorbereiten) ·dokumentgenerierung.test.ts(+1) · signatur.test.ts(+1, 2 Bezeichnungen auf Nicht-Vorlage umgestellt) · HANDOFF · CHANGELOG · Feature-Liste · Test-Uebersicht · version.ts · CLAUDE.md · Timesheet | | **MED-D-257** | 2026-07-26 | Backend+Frontend/Signatur+Fremdformulare · Hausformular auf ausfüllbare DocuSign-Fassung routen (MED-OP-FORM-6, Baustein 2) | **Neues Feature** (0.115.0->0.116.0, MINOR). Nutzer wählte „Rücklauf-Weg 1: Kunde füllt in DocuSign → AD-009". **Kern:** eine **Weg-B-Vorlage** (ausfüllbares DocuSign-Template, MED-D-248) kann jetzt optional mit einem **Hausformular-Dokumenttyp** (R12, z. B. makler_allein_auftrag) verknüpft werden (FremdformularVorlage.dokumenttyp, Migration **v49** ADD COLUMN dokumenttyp). Ist die Verknüpfung gesetzt, routet SignaturService.anfordernbeim **Versenden** eines solchen Hausformulars **ohne abgelegte Datei** automatisch auf **dieses Template** (neuer HelperversuchAusfuellbaresTemplate: Bezeichnung → vorlageFuerBezeichnung→ Dokumenttyp → aktive Vorlage; Prefill viabaueTabWerteaus den Stammdaten;anfordernAusTemplate; Identitäts-Mapping am **bestehenden** Dokument → AD-009-Rücklauf greift; Template-Niveau + PII-arm auditiert dokument.ausfuellbares_template_gestartet) — der **Kunde füllt die offenen Felder selbst in DocuSign**, die Angaben fließen als Rücklauf zurück (AD-009). Kein Match → **flache PDF-Erzeugung bleibt** (MED-D-256 Fallback). Verwaltung-UI: optionaler Dropdown „Ausfüllbare Fassung von (Hausformular)" bei der Vorlagen-Registrierung. +3 Vitest (637->640). | Schließt Weg 1 **an derselben „Versenden"-Taste** des Assistenten (True North #2/#3) — statt einer flachen, nicht ausfüllbaren PDF erhält der Kunde die ausfüllbare Fassung, und der bereits gebaute AD-009-Rücklauf (MED-D-247) greift ohne Zweitpfad (G-1/G-2, Reuse baueTabWerte/identitaetsMapping/anfordernAusTemplate). Auto-Routing nur im E-Mail-Versand (anfordern), nicht Vor-Ort (dort bleibt die flache Fassung). **Nicht-Code-Voraussetzung (an den Kunden):** das echte Makler-Alleinauftrag-**DocuSign-Template muss angelegt** (Tabs mit tabLabel= Weltmodell-Attribut) und über die Verwaltung mit dem Dokumenttyp verknüpft werden — erst dann greift das Routing live (der Kern-Loop ist verifiziert, MED-D-238/247/248). **Grenze:** Server+Client-Build+Unit verifiziert; die Live-Strecke wartet auf das registrierte Template. |server/src/domain/model.ts (FremdformularVorlage.dokumenttyp) · db/schema.ts·db/migrate.ts(v49) ·repo/repo.ts·repo/d1-repo.ts·repo/memory-repo.ts·api/fremdformular-vorlage-service.ts (anlegendokumenttyp) ·api/signatur-service.ts (versuchAusfuellbaresTemplate+ Routing inanfordern) · api/app.ts·client/src/app/api.service.ts·client/src/app/verwaltung.component.ts·signatur.test.ts(+2) · fremdformular-vorlage.test.ts(+1) · HANDOFF · CHANGELOG · Feature-Liste · Test-Uebersicht · version.ts · CLAUDE.md · Timesheet | | **MED-D-258** | 2026-07-26 | Backend+Frontend/Signatur+Fremdformulare · CodeRabbit-Nachlese zu MED-D-257 (#292) | **Forward-Fix zum gemergten #292** (0.116.0->0.116.1, PATCH). #292 auto-mergte vor Review-Abschluss → frische Änderung, Branch neu von main. Drei reale Befunde übernommen: **(A) eIDAS-Untergrenze wahren (Major/RISK-2):** versuchAusfuellbaresTemplatereichteff.niveau des Templates direkt durch → eine als SES registrierte ausfüllbare Fassung hätte einen AES/QES-pflichtigen Dokumenttyp heimlich abschwächen können. Jetzt wird mit dem **stärkeren** aus Template-Niveau und geforderter Rechtswirkung (niveauFuer/Berater-Override, neuer Helper staerkeresNiveauüberSIGNATUR_NIVEAU-Ordnung) signiert — über-signieren ist unschädlich, unter-signieren nicht. **(B) Eindeutiges Auto-Routing (Major/Datenintegrität):** anlegenwies nur doppeltetemplateIdab → mehrere **aktive** Vorlagen auf denselbendokumenttyp hätten dasselbe Hausformular mehrdeutig geroutet (.find= erster Treffer).anlegenlehnt jetzt eine zweite aktive Vorlage je Hausformular-Dokumenttyp ab (Service-Guard wie v48; DB-Partial-Index bewusst nicht — „unique among active" mitaktiv-Toggle ist für den Einzeloperator-Betrieb Overkill). **(C) Kanonischer Dokumenttyp-Katalog (G-8):** der Verwaltung-Dropdown wird jetzt aus DOKUMENTTYP_LABELabgeleitet statt hartkodiert; Client-ContractFremdformularVorlage.dokumenttyp+anlegen-Input auf Dokumenttyp | nullverengt (Compile-Zeit-Schutz statt Laufzeit-Reject). +2 Vitest (640->642). | Alle drei real und in Sekunden verifizierbar (Compliance/eIDAS · Datenintegrität · G-8-Single-Source). #292 war beim Review bereits gemergt → frische PATCH-Änderung statt Reopen (Nachlese-Muster MED-D-240/244/249/251/253). **Bewusst NICHT übernommen:** (a) CLAUDE.md „Aktueller Stand"-Absatz nach HANDOFF verschieben — bewusste Repo-Struktur (MED-D-140), der Absatz hält den 1-2-Satz-Stand kanonisch; (b) CHANGELOG-Branch- statt PR-Link — Repo-Konvention MED-D-144; (c) Straight-Quote-/MD038-Nitpicks über 6 md-Dateien — das Repo nutzt durchgängig deutsche„…"(Opener„+ Straight-Closer"), nur neue Zeilen umzustellen bräche die lokale Konsistenz, markdownlint ist nicht im CI-Gate. | server/src/api/signatur-service.ts (staerkeresNiveau+versuchAusfuellbaresTemplatemindestNiveau) ·server/src/api/fremdformular-vorlage-service.ts (anlegendokumenttyp-Guard) ·client/src/app/api.service.ts(TypDokumenttyp | null) · client/src/app/verwaltung.component.ts(Dropdown ausDOKUMENTTYP_LABEL) · signatur.test.ts(+1) · fremdformular-vorlage.test.ts(+1) · Decision-Log · CHANGELOG · HANDOFF · Feature-Liste · Test-Uebersicht (642) · version.ts · CLAUDE.md · lebende Stempel · Timesheet | | **MED-D-259** | 2026-07-26 | Betrieb/Qualität · App- + Doku-Meisterwerk-Audit-Refresh (MED-OP-REVIEW-1) | **Beide Meisterwerk-Audits aufgefrischt auf v0.116.1** (keine Versionsänderung; Bezugspunkt Commit 5031530, 2026-07-26). Anlass: Stale-Regel (agents.md§6.7) — der bisherige Bezugspunktv0.99.12lag 17 Minor-Versionen zurück (≥10-Schwelle), mechanischer Check meldete beide Audits als veraltet; Nutzer beauftragte die Aktualisierung. Methode: **2 parallele Evidenz-Läufe** (App-Code-Sweep des Angular-Clients + Doku-Sweep über alle Einstiegs-/Architektur-Docs), jeweils mit Datei:Zeile-Belegen; Zitate stichprobenhaft gegengeprüft. **App-Ergebnis:** der Design-System-Kern (geteiltemd-overlay-Shell, Reiter-Roving-tabindex) **hält ohne Regress**, die vier großen neuen Flächen (DocuSign-Assistent inkl. Vor-Ort · Fremdformular-Verwaltung · Cockpit-Fokus-Umbau · Mandate-Overlay) sind überwiegend sauber (ehrlicher Teilfehlschlag, role="alert", aria-pressed, zentrale G-8-Labels); **aber** die zwei jüngsten Komponenten tragen die einzigen neuen Defekte → Feedback 8,5→8, Konsistenz 8→7,5, A11y 8,5→8. Neuer Backlog **B41–B43 → MED-OP-UX-12**: **B41 (hoch)** akte-feld-editornutzt undefinierte Tokens--fg/--fg-faint/--gruen→ hartkodierte Dark-Hex-Fallbacks greifen immer → Feldname-Text im Default-/Light-Theme nahezu unsichtbar (Token-Disziplin-Regress + A11y); **B42 (mittel-hoch)** Rücklauf-Prüfung zeigt bei Load-Fehler eine Falsch-Leere „nichts zu prüfen" (True North #2); **B43 (niedrig)** „Rücklauf prüfen"-Button <24px. **B36–B40 (MED-OP-UX-11) über 17 Minor unverändert offen** (verifiziert). **Doku-Ergebnis:** mechanische Achse **makellos** — alle 9 Einstiegs-Docs auf0.116.1, Testzahl 642/55an allen 5 Pflichtstellen (inkl. „Was läuft wo?"-Tabellenzeile), IDs MED-D-218…258 lückenlos,check-doc-consistency.shgrün außer den 2 erwarteten Audit-Staleness-Warnungen; **aber** Doku↔Code 9→8: die langsamen Architektur-Docs hängen hinter dem Feature-Churn. Neuer Backlog **B49–B52 → MED-OP-DOKU-9** (Doku-Welle 7): **B49 (hoch)**Fremdformulare.mdbeschreibt das gebaute MED-OP-FORM-6 (MED-D-256/257/258) noch als „zurückgestellt/nicht bauen" +FremdformularVorlageohnedokumenttyp/v48/v49; **B50** HANDOFF §4↔§2-Widerspruch zu FORM-6; **B51** Unterschriften.mdnennt den DocuSign-Adapter „nicht live verifiziert" trotz MED-D-238/239; **B52** stale AD-Stempel0.99.12. | Stale-Regel MED-OP-REVIEW-1 (agents.md §6.7) + Nutzer-Auftrag „Meisterwerk-Audits aktualisieren". Audit-Refresh = Zeitdokument OHNE Versions-Bump (agents.md §6.7 Regel 4, analog MED-D-217/211/201/180); Befunde → MED-OP-UX-12/MED-OP-DOKU-9, **nicht im Audit abgearbeitet**. Vorgänger-Bezugspunkte bleiben über die Git-Historie der zwei Audit-Dateien als Zeitzeugen. B41 als dringendster Einzelpunkt (unsichtbar > sub-AA) + billigster Fix ausdrücklich als Vorzieh-Empfehlung markiert. | docs/betrieb/UX-Prozess-Review-2026-07.md, docs/betrieb/Doku-Review-2026-07.md, HANDOFF.md(MED-OP-REVIEW-1 + neue MED-OP-UX-12/MED-OP-DOKU-9 + MED-OP-UX-11-Bestätigung),CHANGELOG.md, docs/betrieb/Timesheet.md | | **MED-D-260** | 2026-07-26 | Backend+Frontend/RBAC · Selbst-Rollenwahl in der UI (interim Admin-Bootstrap) | **Neues Feature** (0.116.1->0.117.0, MINOR). Nutzer: „Die Benutzer-Rolle soll zunächst in der UI auswählbar sein" — Anlass: die Fremd-Formular-Verwaltung (und die gesamte Admin-Sektion) war unerreichbar, weil in Produktion die benutzer-Tabelle **leer** ist (0 Admins, per D1-Query bestätigt) und AUTH_BOOTSTRAP_ADMINnicht/falsch gesetzt → jeder fällt auf die Default-Rolleberater→@if (istAdmin())-Block unsichtbar. **Gebaut:** neuer Endpoint POST /api/ich/rolle(setzt die **eigene** Rolle des eingeloggten Nutzers viaupsertBenutzer, validiert gegen ROLLE, append-only auditiert benutzer.eigene_rolle_gesetzt) **bewusst OHNE benutzer_verwalten-Guard** + Verwaltung-UI-Karte „Meine Rolle" (Dropdown berater/backoffice/admin, für ALLE sichtbar, oberhalb des Admin-Gates; nach Wechsel auf admin lädt die Komponente die admin-gated Listen nach). **Sicherheits-Weichenstellung mit dem Nutzer geklärt** (AskUserQuestion): gewählt **„freie Selbst-Wahl"** statt der bootstrap-gesicherten Variante. +2 Vitest (642->644). | Löst den Admin-Bootstrap-Deadlock direkt in der UI (True North: die App bedienbar machen). **Bewusst als Privilege-Escalation-Loch akzeptiert** — vertretbar, weil **alle** Zugänge hinter Cloudflare Access laufen (Golden Rule Zero Trust vor Public); jede Änderung auditiert (G-4). **Proaktiv als RISK-31 geflaggt** (Sicherheit/RBAC, Score 6, Status akzeptiert-interim) mit **Rückbau-Bedingung**: sobald Rollen sauber vergeben sind, auf benutzer_verwaltengaten / auf „nur solange kein Admin existiert" verriegeln / entfernen +AUTH_BOOTSTRAP_ADMINkorrekt setzen. Alternative bootstrap-gesicherte Variante dem Nutzer angeboten, bewusst abgelehnt. |server/src/api/app.ts (POST /api/ich/rolle) · client/src/app/api.service.ts (eigeneRolleSetzen) · client/src/app/verwaltung.component.ts(„Meine Rolle"-Karte) ·server/src/auth/auth.test.ts(+2) · docs/betrieb/Risikoregister.md (RISK-31) · HANDOFF · CHANGELOG · Feature-Liste · Test-Uebersicht (644) · version.ts · CLAUDE.md · lebende Stempel · Timesheet | | **MED-D-261** | 2026-07-26 | Frontend/A11y · B41 Feld-Editor-Token-Fix (Vorzieh-Fix aus MED-OP-UX-12) | **Bugfix** (0.117.0->0.117.1, PATCH). Nutzer: „Ja" (auf die Empfehlung, B41 vorzuziehen). B41 (App-Audit v0.116.1, MED-D-259, hoch): der akte-feld-editordeklarierte drei Farben über **undefinierte** CSS-Variablen--fg/--fg-faint/--gruen(existieren nirgends → die hartkodierten Dark-Mode-Hex-Fallbacks#e6e9ef/#8a90a0/#76b82agriffen **immer**) → der **Feldname-Text** (den der Mitarbeiter zum Mappen lesen muss) war im Default-/Light-Theme near-white auf hellem Grund = **nahezu unsichtbar**. Fix: auf die echten, theme-fähigen Tokensvar(--text)/var(--mut)/var(--green)(styles.css, hell+dunkel definiert) umgestellt, Hex-Fallbacks entfernt. Reine CSS-Deklarationen im component-lokalenstyles:-Block (kein Logik-/Server-Change) → ng build ist die Verifikation, keine neue Unit (644 unverändert). Mitgezogen: der deferierte UX-Review-Belegpfad-Nit (akte-feld-editor.ts→.component.ts, CodeRabbit #297). | Behebt den dringendsten Einzelpunkt des v0.116.1-App-Audits (unsichtbarer Text > sub-AA) bei minimalem Aufwand + stellt die Token-Disziplin wieder her (kein eingeschleuster Hex, G-3/Konsistenz). Der Audit selbst bleibt Zeitdokument (agents.md §6.7); B41 in MED-OP-UX-12 als erledigt markiert, B42/B43 bleiben offen. | client/src/app/akte-feld-editor.component.ts(3 Farb-Deklarationen) ·docs/betrieb/UX-Prozess-Review-2026-07.md (Belegpfad-Nit) · HANDOFF (MED-OP-UX-12 B41 ✅) · Decision-Log · CHANGELOG · version.ts · CLAUDE.md · lebende Stempel · Timesheet | | **MED-D-262** | 2026-07-26 | Backend+Frontend/Fremdformulare · DocuSign-Templates ziehen + Felder anzeigen | **Neues Feature** (0.117.1->0.118.0, MINOR). Nutzer: „Ziehe die vorhandenen DocuSign-Templates automatisch (mit Refresh-Button Kreisel) und zeige auch die vorhandenen Felder im Formular." + Options-Frage „unsere Felder in DocuSign zeigen?" (AskUserQuestion: A/B/C erklärt, C vertieft) → Nutzer wählte **A (Konvention + App-Anzeige = dieses Feature)**, kein Plugin. **Gebaut:** zwei neue Provider-Lesemethoden listeTemplates() (GET /templates) + templateFelder(id) (GET /templates/{id}/recipients?include_tabs=true→ Tabs mittabLabel, dedupliziert), im DocuSign-Adapter implementiert + Fake-Stub (2 Demo-Templates + Felder, damit ohne Live-DocuSign testbar); Service-Passthroughs + Routen GET /api/fremdformular-vorlagen/docusign-templates[/:id/felder](Admin, 502-Fallback). **Verwaltung-UI:** die GUID-Freitext-Eingabe wird durch ein **Template-Dropdown + Refresh-Button mit Lade-Kreisel** ersetzt (Freitext bleibt als Fallback, wenn DocuSign nicht konfiguriert); bei Auswahl werden die **echten Template-Felder** angezeigt und gegen die Weltmodell-Attribute gematcht (✓ erkannt →attributLabel, ⚠ unbekannt), erkannte Felder werden automatisch als vorbefüllbar vorgemerkt. +2 Vitest (644->646). | Behebt das Kernproblem des Screenshots: GUID-Tippen + blinde statische Attributliste → Auswahl aus echten Templates + Sichtbarkeit der tatsächlichen Felder (True North: die App bedienbar/ehrlich machen; G-3). Reine **Lese**-Aufrufe (kein Envelope), Admin-gated. **Umkehrung eines Plugins** (wir zeigen DocuSigns Felder in unserer App); die drei Plugin-Optionen (A Konvention · B In-App-Authoring · C Extension App/Connected Fields) sind dem Nutzer erklärt, C als eigenes Großprojekt zurückgestellt. **Grenze:** live gegen den echten DocuSign-Account erst beim Testen verifizierbar (Fake liefert Stubs); Server+Build+Unit grün. **Mitgezogen:** CodeRabbit-#298-Befund — Management-Summary-DocuSign-Status von „simuliert/Platzhalter" auf „Kern gebaut + demo-verifiziert, Prod-Rechtswirkung offen" korrigiert (nur E-Mail/KI bleiben Platzhalter). | server/src/signatur/provider.ts (TemplateInfo/TemplateFeld+ 2 Methoden) ·signatur/docusign.ts(Implementierung) ·signatur/fake.ts(Stub) ·api/fremdformular-vorlage-service.ts(Passthrough) ·api/app.ts(2 Routen) ·client/src/app/api.service.ts·client/src/app/verwaltung.component.ts(Dropdown+Refresh-Kreisel+Feld-Anzeige) ·fremdformular-vorlage.test.ts(+2) · docs/produkt/Management-Summary.md (DocuSign-Status) · HANDOFF · CHANGELOG · Feature-Liste · Test-Uebersicht (646) · version.ts · CLAUDE.md · lebende Stempel · Timesheet | | **MED-D-263** | 2026-08-02 | Frontend+Backend/Fremdformulare · CodeRabbit-Nachlese #299 (stale-Attribut-Fix + Template-Paginierung) | **Bugfix** (0.118.0->0.118.1, PATCH). Nachlese der CodeRabbit-Review auf dem gemergten MED-D-262-PR #299. **Major (Funktionskorrektheit):** templateGewaehlt (verwaltung.component.ts) vereinigte die je Template auto-erkannten Weltmodell-Attribute in ffAttribute, ohne die des vorherigen Templates zu entfernen -> Wechsel A->B ließ A's Attribute angehakt -> die registrierte FremdformularVorlage.attributeenthielt Felder, die im gewählten Template gar nicht existieren (danach vonbaueTabWerte/anfordernAusTemplatebefüllt+gesendet). Fix: neuerdsAutoErkannt-Signal verfolgt die auto-angehakten Schlüssel je Template und dsAutoErkanntZuruecksetzen() entfernt sie bei JEDEM Wechsel -- Dropdown (templateGewaehlt) UND manuelle GUID (neuer templateIdManuellGesetzt-Pfad statt direktem ffTemplateId.set); zusätzlich Out-of-order-Guard (ffTemplateId() !== id-> veraltetetemplateFelder-Antwort bei schnellem Wechsel verworfen). **Minor:** listeTemplates()zog nur die erste Seite -> >2000 Templates abgeschnitten; jetzt folgt esnextUriüber alle Seiten und aggregiert (Kappe 100 Seiten). **Nitpick:**listeTemplates/templateFelder nennen bei Nicht-OK den DocuSign-Response-Body (txt.slice(0,300)) im Fehler statt nur den Status. +2 Vitest (646->648). | Behebt einen echten Datenkorrektheits-Defekt der gerade gelieferten MED-D-262-Strecke (falsch registrierte Vorlagen-Attribute -> falsch befüllte/gesendete Tabs; True North #3: rechtssicher/korrekt dokumentiert). Paginierung + Fehler-Body härten den Live-Betrieb gegen echte DocuSign-Accounts. **Nicht übernommen** (bewusst, mit Grund): die Markdown-Quote-Style-Nits (die geänderten Zeilen folgen dem umgebenden Bestandstext, der deutsche „…"-Quotes nutzt; eine dateiweite Vereinheitlichung des Zeichenstils ist ein eigener Doku-Wellen-Schritt, nicht Scope dieser Nachlese) und die fehlende CHANGELOG-PR-Link-Ergänzung an der MED-D-262-Zeile (Branch-statt-PR-Link ist seit MED-D-144 etabliert, kein nachträgliches Ergänzen). | client/src/app/verwaltung.component.ts (dsAutoErkannt/dsAutoErkanntZuruecksetzen/templateIdManuellGesetzt/Out-of-order-Guard) · server/src/signatur/docusign.ts (listeTemplates-Paginierung + Fehler-Body) · server/src/signatur/docusign.test.ts(+2) · HANDOFF §2 · CHANGELOG · Test-Uebersicht (648) · Sanity-Checkliste (Frage 3) · Management-Summary (Status-Konsistenz) · version.ts · lebende Stempel · Timesheet | | **MED-D-264** | 2026-08-02 | Doku/Fremdformulare · Runbook Template-Anlegen + Doku-Welle-7-Teil (B49) | **Reine Doku** (keine Versionsänderung). Nutzer: „ja" (Anleitung zum DocuSign-Template-Anlegen als Repo-Doc ablegen). **Neu:** docs/architektur/Fremdformulare.md**§9 Runbook** — Klick-für-Klick ein Fremdformular als DocuSign-Template anlegen (Teil A DocuSign: PDF hochladen, Rollemandant, Tabs platzieren, tabLabel= Weltmodell-Attribut-Schlüssel; Teil B Verwaltung-Registrierung; Teil C Test) inkl. kanonischertabLabel-Referenztabelle (Quelle WELTMODELL_ATTRIBUTE). **B49 (MED-OP-DOKU-9) teilweise erledigt:** §8 korrigiert — MED-OP-FORM-6 von „nicht bauen" auf „teilweise gebaut" (Hausformular-Auto-Routing via dokumenttyp/MED-D-257 live); §6/§7-Feldspec-Nachzug bleibt offen. **Mitgezogen:** die im #300-Merge verlorene cad8c82-Politur (Auto-Merge feuerte vor dem 2.-Runde-Push) — Test-Uebersicht „bis zu 100 Seiten" + True-North-#3-Satz; Decision-Log-MED-D-263-Quote-Rationale umformuliert. | Liefert die vom Nutzer angefragte, versionierte Schritt-für-Schritt-Anleitung (True North #3: die App korrekt bedienbar dokumentieren) und schließt zugleich den dringendsten Doku↔Code-Drift (B49) an der Stelle, die das neue Feature betrifft. Kein Version-Bump: reine Doku = Zeitdokument-Analogie (agents.md§6.7, wie Audit-Refresh MED-D-259). |docs/architektur/Fremdformulare.md(§8 korrigiert + §9 Runbook) · HANDOFF §2 + MED-OP-DOKU-9 (B49) · CHANGELOG ·docs/betrieb/Test-Uebersicht.md(100-Seiten-Wording + True-North) ·docs/betrieb/Decision-Log.md(MED-D-263-Rationale) · Timesheet | | **MED-D-265** | 2026-08-02 | Doku/Fremdformulare · Runbook-Korrektur Datumsfelder (CodeRabbit-Nachlese #304) | **Reine Doku** (keine Versionsänderung). CodeRabbit-Review auf dem gemergten MED-D-264-PR #304 fand einen realen Doku↔Code-Fehler: der Prefill sendet ausschließlichtextTabs (baueTabWerte→anfordernAusTemplate, docusign.ts:262/280), aber Runbook §9 empfahl für Datumsfelder wahlweise einen DocuSign-Date-Tab → der bliebe leer (unvollständiges Formular). **Korrigiert:** §9 Teil A Schritt 3 — alle vorbefüllten Datenfelder (auch person.geburtsdatum) auf Text-Tabs; Date-Tabs nur für Unterzeichner-eigene Daten. Neuer offener Punkt **MED-OP-FORM-7** (§8): Prefill/Rücklauf optional auf Date/Checkbox-Tabs ausdehnen, zurückgestellt. | Verhindert, dass der Nutzer beim Anlegen des echten Templates ein Datumsfeld auf einen nicht-befüllten Date-Tab legt (True North #3: korrekt/vollständig). Kein Version-Bump: reine Doku (Zeitdokument-Analogie). Quote-Style-Nits bewusst nicht übernommen (Korpus nutzt durchgängig „…", dateiweite Vereinheitlichung = eigener Schritt). | docs/architektur/Fremdformulare.md(§9 Schritt 3 + §8 MED-OP-FORM-7) · HANDOFF §2 · CHANGELOG · Timesheet | | **MED-D-266** | 2026-08-02 | Doku/Fremdformulare · Runbook-Präzisierung (CodeRabbit-Nachlese #305) | **Reine Doku** (keine Versionsänderung). CodeRabbit-Review auf dem gemergten MED-D-265-PR #305 fand zwei gegen den Code bestätigte Ungenauigkeiten: (1) §8 behauptete, gemappte Date-/Checkbox-Tabs kämen auch imform_data-Rücklauf nicht zurück — falsch: formularRuecklaufliestform_datagenerisch jename/value (alle Tab-Typen), nur das Prefill (baueTabWerte→anfordernAusTemplate) ist text-only; Einschränkung jetzt auf das Prefill beschränkt. (2) §9 Schritt 3 „Text-Tabs auf alle Datenfelder" → „auf alle vorbefüllten Datenfelder". | Hält die eigene Genauigkeits-Korrektur (MED-D-265) selbst genau (True North #3): keine falsche Aussage über das eigene Verhalten im Repo (G-2/OP-DOCS-1). Kein Version-Bump: reine Doku. Quote-Style-Nits bewusst nicht übernommen (Korpus „…"). | docs/architektur/Fremdformulare.md (§8 Rücklauf-Aussage + §9 „vorbefüllt") · HANDOFF §2 · CHANGELOG · Timesheet | | **MED-D-267** | 2026-08-16 | Frontend/Cockpit · Mandanten-Liste als aufgeräumter Einstieg | **Neues Feature** (0.118.1->0.119.0, MINOR). Nutzer: „wie können wir den Einstieg in die App aufräumen? Zb eine Mandanten-Liste anzeigen mit Filter-Möglichkeiten?" → per AskUserQuestion geklärt: **Liste wird die Landing** (Fokus/Leitstand rücken auf Reiter 2/3), Filter **Lifecycle-Status · Betreuungsmodell · offene Fakturierung**. **Gebaut:** dritter Cockpit-Modus „Mandanten" (cockpit.component.ts), per Default aktiv (modeDefault'mandanten') — Filterleiste (Namenssuche mSuche+ Lifecycle-ChipsmLifecycle+ Betreuungs-ChipsmBetreuung+ „Zu fakturieren"mNurFakt+ Reset), computedmandantenListe(rein abgeleitet ausmandanten()/GET /api/mandanten, alphabetisch sortiert), Zeilen mit Name/Lifecycle/Betreuung/Fortschritt-% + offene Fakturierung, Klick → oeffneMandant. Label-Maps aus labels.tswiederverwendet.tsc+ng buildgrün. | Beantwortet True North #1 („Wo steht der Kunde?") direkter: bisher war der Einstieg der task-zentrierte Fokus-Strom, Mandanten nur über ⌘K/Fokus-Absprung erreichbar (kein sichtbarer Index). Jetzt ein ruhiger, durchblätterbarer, filterbarer Einstieg. **Kein Eigenbau-Backend** (G-1/G-2): nutzt vorhandene Cockpit-Daten + Navigation; keine neue Route (derpath: ''-Landing zeigt zuerst die Liste). Tastatur-Shortcuts bleiben fokus-gegated (onKeyguardmode() !== 'fokus'), ⌘K//wirken in allen Modi. Client-only → Build-verifiziert statt Vitest (wie MED-D-260/261; Angular-Komponenten haben keine Unit-Test-Infrastruktur). **Alternativen** (eigene Route + Nav-Item; oder dritter Modus ohne Default-Wechsel) dem Nutzer angeboten, „Liste wird Landing" gewählt. |client/src/app/cockpit.component.ts(Mode'mandanten'+ Filter-Signals +mandantenListe+#mandantenTpl + Segment-Button) · HANDOFF §2 · CHANGELOG · Feature-Liste · Test-Uebersicht · Sanity-Checkliste (Frage 1) · version.ts · lebende Stempel · Timesheet | | **MED-D-268** | 2026-08-16 | Frontend/A11y · Mandanten-Zeilen bleiben echte Buttons (CodeRabbit-Nachlese #307) | **Bugfix/A11y** (0.119.0->0.119.1, PATCH). CodeRabbit-Review auf dem gemergten MED-D-267-PR #307 fand einen realen A11y-Defekt (Major): die Mandanten-Listenzeilen trugen role="listitem"auf dem