Test-Übersicht — Medidentas (lebend)
Welche automatischen Tests sichern die Anwendung ab? Sie dienen True North #3 (vollständige & rechtssichere Dokumentation): jeder Test sichert, dass das dokumentierte Verhalten reproduzierbar stimmt und nicht unbemerkt driftet. Diese Übersicht ist lebend (Stand 0.127.1).
692 Tests / 57 Dateien — MED-D-285 (Onboarding-Kundenstrecke als klarer 3-Schritte-Flow, Slice B): +0 Tests — reine Client-Umstrukturierung (onboarding-public.component.ts von flacher Seite zum 3-Schritte-Stepper mit abgeleitetem „wo fehlt was?"-Report; nutzt bestehende Endpunkte kontext/entwurf/einreichen) → ng build-verifiziert; Angular-Komponenten haben keine Unit-Test-Infrastruktur (wie MED-D-267 ff.). 692 unverändert. Davor MED-D-284 (Onboarding-Grunddaten-Katalog erweitert, datensparsam): +1 Test — domain/stammdaten-uebernahme.test.ts: die neuen Grunddaten (Handynummer/Steuernummer/Steuerberater) bilden über ONBOARDING_STAMM_REGELN 1:1 auf die Person ab; es gibt bewusst KEIN Steuer-ID-/Ausweisnummer-Ziel (G-6). Zusätzlich ausfuellgrad-Erwartungen in api/onboarding-formular.test.ts 75→67 (die 2 neuen öffentlichen optionalen Felder Handynummer+Steuernummer verschieben den gewichteten Nenner; die Steuerberater-Felder sind auf der öffentlichen Strecke bewusst nicht erhoben, Art.-14-Gate). 691→692 (keine neue Datei). Davor MED-D-283 (Kunden-Self-Service-Portal, Slice S2 — passwortlose Auth-Routen; inkl. CodeRabbit-#320-Härtung): +9 Tests — neue api/portal.test.ts: dormant→404 (Golden Rule, alle 4 öffentlichen Portal-Routen), Anmelden ohne Konto-Enumeration (unbekannte E-Mail → identische ok-Antwort ohne Link; ungültige E-Mail → 400; ohne testMode: bekanntes vs. unbekanntes Konto → identischer Status UND Body), voller Magic-Link-Flow (Staff legt Konto an → anmelden liefert testLink → login setzt HttpOnly/Secure/SameSite=Lax/Path-Cookie → /ich liefert eigenen Mandanten → abmelden → /ich 401), Token-Replay → 401 (Einmalgebrauch), gesperrtes Konto → laufende Session 401 (Sperre beendet Session), /ich ohne gültiges Cookie → 401, Portal-Konto für unbekannten Mandanten → 404: 682→691, 56→57 Dateien. Davor MED-D-282 (Kunden-Self-Service-Portal, Slice S1 — Fundament, DORMANT): +16 Tests — neue domain/portal-auth.test.ts: Bearer-Hashing deterministisch/64-Hex/Rohwert nicht enthalten (MED-D-280); Magic-Link-Token-Gültigkeit (TTL + Einmalgebrauch); Session-Gültigkeit mit getrennter Idle- UND Absolut-TTL + Widerruf; Record-Konstruktion hasht den Bearer-Wert; atomarer Einmal-Claim verbraucheAnmeldeToken (zweiter Aufruf → null, kein Replay) + Session-Lebenszyklus + Konto-Scope (via MemoryRepo): 666→682, 55→56 Dateien. Davor MED-D-276 (CodeRabbit-Härtung #313, in-PR vor Merge, 4 Runden): +12 Tests — api/timer.test.ts (Segment-Konsistenz: starten öffnet ein Segment, buchen/verwerfen räumen Segmente; Direkt-Buchung bei Zeit über mehrere Mandanten → verteilen_noetig; Push-Endpoint-Allowlist istErlaubterPushEndpoint (HTTPS + Provider); POST /api/timer/vordergrund weist malformte mandantId mit 400 ab / akzeptiert explizit null; POST /api/push/subscribe weist fremden Endpoint mit 400 ab; Runde 2: deleteAktiverTimer als atomarer Claim (zweiter Aufruf → false), buchenVerteilt claim-first → zweite Buchung auf denselben Timer bucht NICHT erneut / kein_timer; Runde 3: loescheTimerSegmenteMitIds räumt nur die genannten Segmente — nebenläufiger Vordergrund überlebt, OP-TIME-5; Runde 4: korrigieren gleicht die Segment-Historie an den korrigierten Gesamtwert an): 654→666 (keine neue Datei). Davor MED-D-275 (Durchlaufender Timer + Vordergrund-Segmente + Buchungs-Overlay + Web-Push): +6 Tests — api/timer.test.ts (Vordergrund-Wechsel protokolliert Zeit je Akte ohne Konflikt; vordergrund(null) → „nicht zugeordnet"; buchenVerteilt legt je Zeile eine Leistungszeit an, räumt Segmente, setzt den Timer zurück; keine gültigen Zeilen → keine_zeilen; Pause schließt/Fortsetzen öffnet Segment): 648→654 (keine neue Datei; Client — SW/Push/Overlay — ng build-verifiziert, keine Client-Unit-Test-Infra). Davor MED-D-273 (Akte „Mandate"-Reiter-IA: Mandat-Overlay + Formulare→Dokumente + Meeting-Doku→Rail): +0 Tests (reine Client-Umstrukturierung in mandant-auftraege.component.ts/mandant-detail.component.ts — Overlay statt inline-Form, [hidden]-Register-Umstellung, Komponenten-Umzug in die Rail + Dead-Code-Bereinigung → ng build verifiziert; Overlay/Reiter-Platzierung wären grundsätzlich testbar, es fehlt aber die Client-Unit-Test-Infrastruktur): 648 unverändert. Davor MED-D-271 (Neuer Mandant als Overlay) + MED-D-272 (Overflow-Fix Akte/Overlay): +0 Tests (MED-D-271: Anlege-Form aus verwaltung.component.ts in neue neuer-mandant-overlay.component.ts verschoben, gleiche POST /api/mandanten-Logik → ng build verifiziert; MED-D-272: CSS-Umbruch-/min-width:0-Fixes in styles.css + eine Rail-Zelle → rein visuell, nicht unit-testbar): 648 unverändert. Davor MED-D-270 (CodeRabbit-Nachlese #310: Statistik-Retry-Race-Guard + Endpunkt-Doc): +0 Tests (monotoner statistikSeq-Guard in cockpit.component.ts + Doku-Korrektur /api/fragebogen/statistik → ng build verifiziert, nicht unit-testbar; der sicherheitsrelevante Server-Gate ist bereits in api/rbac.test.ts getestet — 403/403/200 — CodeRabbits Client-Component-Tests bewusst als Backlog übersprungen, Client build-only): 648 unverändert. Davor MED-D-269 (Statistiken als eigener Cockpit-Bereich): +0 Tests (Widget-Umzug Verwaltung -> Cockpit-Modus in cockpit.component.ts/verwaltung.component.ts -> ng build verifiziert, nicht unit-testbar): 648 unverändert. Davor MED-D-268 (A11y-Fix Mandanten-Zeilen = native Buttons): +0 Tests (Entfernen zweier ARIA-Rollen in cockpit.component.ts -> ng build verifiziert, nicht unit-testbar): 648 unverändert. Davor MED-D-267 (Mandanten-Liste als Landing, Cockpit-Modus): +0 Tests (reine Client-Ansicht in cockpit.component.ts — Filter/Liste rein abgeleitet aus vorhandenen GET /api/mandanten-Daten, kein neues Backend → ng build verifiziert, nicht unit-testbar; Angular-Komponenten haben keine Unit-Test-Infrastruktur): 648 unverändert. Davor MED-D-263 (CodeRabbit-Nachlese #299: stale-Attribut-Bereinigung + Template-Paginierung): +2 Tests — signatur/docusign.test.ts (listeTemplates folgt nextUri über bis zu 100 Seiten und aggregiert, Eintrag ohne id verworfen; templateFelder dedupliziert je tabLabel und nennt den Fehler-Body bei Nicht-OK): 646→648 (keine neue Datei). Davor MED-D-262 (DocuSign-Template-Auswahl + Feld-Introspektion): +2 Tests — api/fremdformular-vorlage.test.ts (Provider-Templates + -Felder gezogen inkl. tabLabel-Reihenfolge; Provider ohne Introspektion → leere Listen, kein Wurf): 644→646 (keine neue Datei). Davor MED-D-261 (B41 Feld-Editor-Token-Fix): +0 Tests (reine CSS-Token-Korrektur im component-lokalen styles:-Block → ng build verifiziert, nicht unit-testbar): 644 unverändert. Davor MED-D-260 (Selbst-Rollenwahl, interim Admin-Bootstrap): +2 Tests — auth/auth.test.ts (Selbst-Rollenwahl POST /api/ich/rolle ohne Admin-Guard → berater→admin bricht den Bootstrap-Deadlock, danach /api/benutzer 200 + /api/ich spiegelt die neue Rolle, ungültige Rolle → 400; erzwungen ohne Access-Header → 401): 642→644 (keine neue Datei). Davor MED-D-258 (CodeRabbit-Nachlese #292: eIDAS-Niveau-Guard + eindeutige Hausformular-Vorlage): +2 Tests — api/signatur.test.ts +1 (Template-Niveau unter der Matrix-Anforderung → auf das Matrix-Niveau angehoben, nie unter-signieren) + api/fremdformular-vorlage.test.ts +1 (zweite aktive Vorlage auf denselben Hausformular-Dokumenttyp → abgewiesen, eindeutiges Auto-Routing): 640→642 (keine neue Datei). Davor MED-D-257 (Hausformular auf ausfüllbare DocuSign-Fassung routen, MED-OP-FORM-6 Baustein 2): +3 Tests — api/signatur.test.ts +2 (Hausformular mit registriertem ausfüllbarem Template → geroutet auf anfordernAusTemplate inkl. Prefill/Template-Niveau/Identitäts-Mapping, keine flache PDF; ohne passendes Template → flache PDF-Erzeugung bleibt) + api/fremdformular-vorlage.test.ts +1 (anlegen übernimmt gültige Hausformular-Verknüpfung, lehnt unbekannten Dokumenttyp ab, ohne Verknüpfung dokumenttyp=null): 637→640 (keine neue Datei). Davor MED-D-256 (Eigenformular beim Versenden erzeugen+vorbefüllen): +2 Tests — api/dokumentgenerierung.test.ts (vorlageFuerBezeichnung: exakter Titel + generierungBezeichnung-Form → Vorlage, unbekannt → null) + api/signatur.test.ts (Makler-Alleinauftrag ohne Datei → beim Versenden erzeugt+vorbefüllt+signiert, %PDF-Bytes an den Provider; zwei Bezeichnungen auf Nicht-Vorlage umgestellt, damit kein_inhalt/422 weiter greifen): 635→637 (keine neue Datei). Davor MED-D-255 (Härtung nach dem DocuSign-Vorfall): +2 Tests — api/signatur.test.ts (Provider-Fehler mit Empfänger-PII → E-Mail im Detail redigiert [email]; Upstream-Read-Fehler der Ablage → provider_fehler statt opaker 500): 633→635 (keine neue Datei). Davor MED-D-254 (DocuSign-Fehler im Live-System sprechend machen): +5 Tests — api/signatur.test.ts (echter Provider: Dokument ohne Datei → kein_inhalt; Datei ohne Empfänger → kein_empfaenger; Provider-Wurf → provider_fehler mit Detail, kein halb angelegter Vorgang; HTTP 422 „keine abgelegte Datei" + HTTP 502 sanitisierter Grund): 628→633 (keine neue Datei). Davor MED-D-252 (Cockpit-Fokus entschlackt + „Zu fakturieren"-Filter): +1 Test — api/app.test.ts (offeneFakturierungMinuten summiert abrechenbar & nicht abgerechnet, lässt nicht-abrechenbare weg): 627→628 (keine neue Datei). Davor MED-D-251 (CodeRabbit-Nachlese zu Weg B): +2 Tests — api/fremdformular-vorlage.test.ts (anlegen lehnt eine zweite Vorlage mit derselben Template-ID ab; Provider-Wurf beim Template-Envelope → kein verwaistes Dokument): 625→627 (keine neue Datei). Davor MED-D-250 (Weg B: Fremd-Formular-Vorlagen/DocuSign-Templates, live verifiziert): +8 Tests — domain/fremdformular.test.ts +3 (baueTabWerte tabLabel=Attribut→Wert, leere weg; identitaetsMapping → AD-009-Rücklauf greift), neue api/fremdformular-vorlage.test.ts +5 (anlegen validiert Niveau/filtert unbekannte Attribute; starten legt Dokument mit Identitäts-Mapping + Vorgang an und befüllt die Tabs aus den Stammdaten; Prefill→Rücklauf-Kreis über AD-009; kein_empfaenger ohne Kontakt; Provider ohne Template-Seam → nicht_verfuegbar): 617→625, 54→55 Dateien. Davor MED-D-247 (Formular-Rücklauf-Prüfung, AD-009): +7 Tests — domain/fremdformular.test.ts +2 (ruecklaufRegeln bildet nur rückschreibbare Attribute ab; ATTRIBUT_ZU_STAMMZIEL ohne bank./praxis.), api/signatur.test.ts +5 (Diff aktuell↔neu; bank.iban ausgeschlossen; formularRuecklauf persistiert nichts; Übernahme schreibt nur Gewähltes versioniert mit Quelle formular; nichts_gewaehlt; kein Mapping → null): 610→617 (keine neue Datei). Davor MED-D-246 (Abgelaufene Dokumente abgeleitet, AD-005): +7 Tests —
domain/aktenreife.test.ts +2 (abgelaufen = fällig/wichtig/Stufe aktiv, blockiert nicht; getrennt von
fehlt), domain/naechste-schritte.test.ts +2 (dokumente-erneuern-Schritt + Sortierung wichtig zwischen
Blocker und Wiedervorlage-Hinweis), api/dokument.test.ts +3 (Service detail/offenePunkte leiten den
Ablauf ab; keine Wiedervorlage angelegt = Backlog sauber): 603→610 (keine neue Datei).
Davor MED-D-244 (AD-006-Nachlese, Dokument-Scope-Guard auf den Signatur-Routen):
api/signatur.test.ts +1 Test (HTTP-Guard: fremder Mandant → POST /signatur + /signatur/vor-ort
liefern 404 ohne Provider-Aufruf; eigener Mandant → 201 mit Empfänger-Override): 602→603 (keine neue Datei).
Davor MED-D-243 (AD-006 editierbarer Empfänger im Unterschriften-Assistenten):
api/signatur.test.ts +2 Tests (aufzeichnender Stub-Provider: anfordern ohne Override → Mandant-Kontakt,
mit Override → gewählte Person; vor Ort → Override-Name greift, E-Mail bleibt optional): 600→602 (keine neue
Datei). Davor MED-D-241 (Akten-Cockpit-Design-System exakt übernommen): api/app.test.ts
+1 Test (direkte, berater-editierbare Stammdaten telefon/geburtsdatum/strasse/plz/ort via PATCH → persistiert
- erzeugt genau eine neue append-only Stammdaten-Version (G-4), leerer Wert löscht das Feld — weiche
Validierung): 599→600 (keine neue Datei). (MED-D-242 „Über den Link hochgeladen" war reine Client-Sicht →
keine neuen Server-Tests, 600 unverändert.) Davor MED-D-238 (DocuSign end-to-end live verifiziert + Private-Key-Parser gehärtet):
signatur/docusign.test.ts+1 Test (verstümmelter PEM-Delimiter — 4 Trailing-Hyphens, keine Umbrüche, literale\n— wird trotzdem geparst, JWT-Signatur läuft durch): 598→599 (keine neue Datei). Davor MED-D-237 (In-Person-Host = eingeloggter Berater):signatur/docusign.test.ts+1 Test (Adapter bevorzugt den übergebenen Berater-Host vor der Default-Konfig, bei Envelope-Anlage und Recipient-View): 597→598. Davor MED-D-236 (echte Vor-Ort-/In-Person-Signatur, OP-SIGN-1):signatur/docusign.test.tsum 5 Tests erweitert (Adapter:vorOrtVorbereitenerstellt captive In-Person-Envelope ohne E-Mail-Versand + verlangt Host + lässtsignerEmailohne Kunden-Mail weg,vorOrtSignaturUrlliefert die Recipient-View-URL über die Host-Identität,docuSignKonfigAusEnvliest Host;SignaturService:vorOrtVorbereiten→eingebettet:truegegen DocuSign /false+nicht_verfuegbargegen Fake): 592→597 (keine neue Datei). Davor MED-D-235 (Fremdformular-Feldmapping, AD-010/MED-OP-FORM-5, Weg A): drei neue Dateien —pdf/pdf-formular.test.ts(4 Tests: AcroForm-Felder lesen inkl. Art/Seite/Optionen, leeres PDF ohne Formular, Text/Auswahl/Ankreuz füllen ohne Flatten, unbekannte Feldnamen defensiv),domain/fremdformular.test.ts(6 Tests: Weltmodell-Katalog eindeutig + Leser,anschrift.komplett,bank.ibanKonto-vor-Alt-IBAN,bereinigeMapping,bauePrefillFelder/-Werte),api/fremdformular.test.ts(7 Tests: Service ansicht/mapping/vorbefuellen + PII-armes Audit + Fehlerpfade, plus HTTP-Route-Test übercreateApp+ FakeNextCloud): 574→591 Tests, 51→54 Dateien. Davor MED-D-231 (B10/MED-OP-UX-8, Auftrag-Playbook-Fehler sichtbar):api/beratungsauftrag.test.tsum 2 Tests erweitert (Anlage mit scheiterndem Playbook →playbookFehler:true+ Auftrag bleibt persistiert + PII-armesauftrag.playbook_fehler-Audit; Statuswechsel mit scheiterndem Status-Playbook →playbookFehler:true+ Wechsel gelingt): 572→574 (keine neue Datei). Davor MED-D-227 (Akten-Cockpit Slice B, In-Person-Signatur):api/signatur.test.tsnetto +1 — der Vor-Ort-Abschluss-Test prüft jetzt Dokument→erhalten(stattunterschrieben) + Onboarding-Item unangetastet + Auditsignatur.vor_ort_abgeschlossen, plus ein neuer Idempotenz-Test (571→572, keine neue Datei). Davor MED-D-223 (Akten-Cockpit Slice A, AD-008 DocumentRow-Zustandsmaschine):api/signatur.test.tsum 8 Tests erweitert (Service:erinnernbest-effort+Audit / unbekannt→null;signiertHochladenDokument→erhalten+Scan-Ablage+Audit / unbekannt→null; HTTP:POST .../erinnern200/404,POST .../signiert-hochladen200/404): 563→571 Tests (51 Dateien, keine neue Datei). Davor MED-D-220 (DocuSign-HTTP-Adapter): neuesignatur/docusign.test.ts(10 Tests gegen gemocktesglobalThis.fetch+ real generierten PKCS#8-Schlüssel: reine HelfermappeStatus/parseWebhook/verifyDocuSignHmac/docuSignKonfigAusEnv-Dormancy; Adapter —anfordernerstellt Envelope mitdocumentBase64+Signer+eventNotification, wirft ohne Bytes/Unterzeichner,statuslädt die kombinierte signierte Fassung, keinabschliessenDemo;SignaturService-Integration — Ablage-Bytes + Mandanten-E-Mail werden an den echten Provider durchgereicht,vorOrtAbschluss→ 409/nicht_verfuegbar): 553→571 Tests, 50→51 Dateien. Davor MED-D-204 (UX-Welle 10 Slice 2, B15 Playbook-Feedback):api/app.test.tsum 1 Test erweitert (erfolgreicher Lifecycle-Wechsel liefertplaybookFehler:false) + bestehender Playbook-Fehler-Test um dieplaybookFehler:true-Antwort-Assertion ergänzt: 552→553 Tests. Davor MED-D-198 (Akten-Cockpit S5, Unterschriften-Assistent):api/signatur.test.tsum 5 Tests erweitert (Vor-Ort-/Demo-Abschluss inkl. Write-back R4→R3→R2; unbekannter Vorgang → null; Provider ohne Demo-Seam →nicht_verfuegbar(kein Fälschen echter Vorgänge); HTTPPOST .../vor-ort-abschluss200/404): 547→552 Tests. Davor MED-D-195 (Akten-Cockpit S3a, 1:n-Bankkonten): neueapi/bankkonto.test.ts(12 Tests: HTTP-CRUD inkl. IBAN-Normalisierung + Archivieren + 400-Validierung + 404; Backfill-Idempotenz, Crash-Teillauf, Nebenläufigkeit, identische-IBAN-kein-Dedup, leere-Felder-kein-Konto, UNIQUE-quellSchluessel-Ablehnung): 535→547 Tests, 49→50 Dateien. Davor MED-D-179 (Stammdaten-Versionierung, Slice 1): neuedomain/stammdaten-version.test.ts(5 Tests:snapshotVon/snapshotGleich, Hash-Ketten-Bau + Verify, Manipulations-Erkennung,feldHistorie) + neueapi/stammdaten-versionierung.test.ts(7 Tests: v1-Seed beicreateMandant, v2 bei Feldänderung mit intakter Kette + Herkunft, kein Rausch-Bump bei reiner lifecycle-/ verantwortlich-Änderung,self_service-Herkunft, idempotenter Backfill, HTTP-Route + Berater-PATCH-Version): 523→535 Tests, 47→49 Dateien. Davor MED-D-177 (CodeRabbit-Nachlese zu MED-D-176, RBAC-Sicherheitsfund):rbac.test.ts+1 Test (By-ID-Wiedervorlage-Routen für fremden Mandanten → 404, für eigenen → 200- Regression, erledigen + wieder öffnen): 522→523 Tests. Davor MED-D-174 (CodeRabbit-Nachlese zu MED-D-172, RBAC-Sicherheitsfund):timer.test.ts+3 Tests (neue RBAC-Describe-Gruppe —/api/timer/start/buchenfür fremden Mandanten → 404, für eigenen → 201-Regression): 519→522 Tests. Davor MED-D-172 (Aktiver Timer, ein Timer je Benutzer statt je Browser-Tab, OP-TIME-3): neueapi/timer.test.tsmit 25 Tests (Service-Ebene: Start/ Konflikt/Idempotenz/Pause/Fortsetzen/Korrigieren/Buchen mit und ohneweiterlaufen/Verwerfen; HTTP-Ebene: alle/api/timer*-Routen inkl. Validierung + 409-Konfliktfälle): 494→519 Tests, 46→47 Dateien. Davor MED-D-158 (CodeRabbit-Nachlese zu MED-D-157:leistungszeit.test.ts+1 Test für missgebildetenauftragRef-Typ, z. B. Zahl/Objekt statt Text/null): 493→494 Tests. Davor MED-D-157 (Zeiterfassungs-Mandat-Zuordnung:leistungszeit.test.ts+2 Tests fürerfassen()mitauftragRef+ HTTP-Validierung unbekannter/fremder Aufträge): 491→493 Tests. Davor MED-D-152 (CodeRabbit-Nachlese zu MED-D-151:app.test.ts+1 Test für Best-effort-Playbook-Fehlerbehandlung inservice.ts#aktualisieren()): 490→491 Tests. Davor MED-D-151 (PROZESS_PHASEretiriert,domain/phasen.test.ts→ neuedomain/lifecycle.test.ts, Guard-Matrix + Playbook-Katalog;beratungsauftrag.test.ts+2 Tests für das neue Auftrags-Status-Playbook, Idempotenz + Fehler-Isolation): 488→490 Tests). Davor MED-OP-VALID-1 (kanonischer Feld-Typ + KI-Formatvorschlag, immer weich): Slice 1 (MED-D-146) +18 Tests (feld-typ.test.ts,regel-vorschlag.test.ts, erweiterteausfuellformular.test.ts); Slice 2 (MED-D-147, Praxis-PLZ im App-internen Formular) +2 Tests inpraxis.test.ts; Slice 3 (MED-D-149, PLZ↔Ort-Plausibilität via OpenPLZ) +13 Tests (openplz.test.ts,fake.test.ts, erweitertepraxis.test.ts); Slice 4 (MED-D-150, Onboarding-Formular) +5 Tests (erweiterteonboarding-formular.test.ts+stammdaten-uebernahme.test.ts). Pflege (verbindlich): je PR mitführen — neue/entfernte Testdateien und die Gesamtzahl aktualisieren (analogCHANGELOG.md/Feature-Liste.md).
0.47.0(D-49, Live-Zeiterfassung auf der Akte): UI (Timer/Guard/Register inmandant-detail.component.ts+zeiterfassung.guard.ts) ist clientseitig → Absicherung über den Angular-Produktions-Build (ng build). Die admin-konfigurierbaren Parameter (Nachfrage-Schwelle + Buchungs-Rundung) und die Buchungs-Rundungsregel (buchungsminuten) sind server-seitig indomain/einstellungen.tsgetestet: +3 Vitest ineinstellungen.test.ts(Schwelle/Rundung +buchungsminuten).
Was läuft wo?
| Ebene | Werkzeug | Umfang | Ausführen |
|---|---|---|---|
Server (server/) | Vitest + tsc | 692 Unit-/HTTP-Tests (57 Dateien) | npm test · npm run typecheck |
Client (client/) | Angular Produktions-Build | Kompiliert die gesamte UI (Typprüfung inkl.) | npm run build |
| Doku-Konsistenz | scripts/check-doc-consistency.sh | tote Links, Log-Hygiene, version.ts↔Doku | bash scripts/check-doc-consistency.sh |
| Doku-Site | Docusaurus-Build | rendert docs/ (Broken-Link-Check) | cd docs-site && npm run build |
Der Client hat bewusst (noch) keine Unit-Tests — die Absicherung ist der strikte Produktions-Build (schlägt bei Template-/Typfehlern fehl). Kandidat für später: Component-Tests der Kern-Flows.
Server-Tests im Detail
Domäne — reine Funktionen (voll deterministisch)
| Datei | Tests | Deckt ab |
|---|---|---|
domain/progress.test.ts | 7 | Abgeleiteter Onboarding-Fortschritt + offene Pflicht-Items (G-2) |
domain/onboarding-vorlagen.test.ts | 3 | MED-D-70: Onboarding-Pflicht-Nachweise je Objektart (Einwilligung·Personalausweis·Kundenfragebogen·SEPA·Dienstleistungsauftrag + IBAN privat) + getrennte private/Entitäts-IBAN |
domain/iban.test.ts | 4 | MED-D-71: IBAN-Normalisierung + ISO-7064-Mod-97-Validierung (DACH-Längen) — erster Baustein MED-OP-VALID-1 |
adressen/openplz.test.ts | 6 | MED-D-149/MED-OP-VALID-1(b): OpenPLZ-PLZ↔Ort-Plausibilisierung (G-1, echter Adapter) — DACH-Reihenfolge DE→AT→CH, Vorschlag bei abweichendem Ort, immer weich (unbekannte PLZ/Netzwerk-/Timeout-Fehler → „nicht prüfbar", nie ein Blocker). |
adressen/fake.test.ts | 3 | MED-D-149: deterministischer PLZ↔Ort-Fake (Test/Dev, kein Netz) — plausibel/unplausibel+Vorschlag/unbekannt, erfüllt den PlzOrtProvider-Vertrag. |
domain/feld-typ.test.ts | 13 | MED-D-146 (G-8 Data Dictionary, MED-OP-VALID-1 Slice 1): kanonischer ValidierungsArt (text/email/tel/select/zahl/datum/iban/plz/betrag) — pruefeWert immer weich (leer/Freitext nie ein Blocker), normalisiereWert (IBAN/Zahl-Komma→Punkt), formatVorschlag (DE-Datum→ISO, IBAN-Normalform, PLZ/Tel-Ziffernbereinigung, null wenn kein sicherer Vorschlag ableitbar). |
api/lead.test.ts | 10 | MED-D-72/OP-LEAD-1: öffentliches Lead-Formular → Mandant als lead + Entität + Sichtungs-Wiedervorlage; Einwilligungs-/Pflichtfeld-Prüfung; Ingress-Scrubbing (G-6); öffentliche Routen trotz AUTH_ENFORCED. MED-D-106 (Slice C2a, Lead-Auto-Anlage): Kontext liefert nur buchbare Produkte (dexman ausgenommen); je gewähltem Interesse ein Auftrag (anbahnung, praxis-gebunden) + Playbook + Audit-Zählung; unbekannte/nicht-buchbare/doppelte Interesse-Werte verworfen (G-6); ohne Auftrags-Dienst keine Aufträge (Regression); Route reicht interesse durch (HTTP e2e) |
domain/lifecycle.test.ts | 8 | MED-D-151 (löst domain/phasen.test.ts ab): Lifecycle-Guard-Matrix — onboarding→aktiv blockiert bei offenem Onboarding bzw. offenen Unterschriften (einzeln + kombiniert), frei bei beidem erfüllt; lead→aktiv (Guard gilt direkt, kollabierte Zwischenstufen); lead→onboarding immer frei; →ruhend/→archiviert + Reaktivierung ruhend→aktiv immer frei (kein Re-Guard); Same-Status-No-Op; LIFECYCLE_SPINE/spineIndex; reduzierter Playbook-Katalog (nachfassen@onboarding, jahrescheck@aktiv) + Ref-Format. |
domain/audit.test.ts | 4 | SHA-256-Hash-Kette + Tamper-Erkennung (G-4) |
domain/zugriff.test.ts | 3 | D-50/RISK-27: Zugriffs-Whitelist — zugriffAktion() = <entitaet>.eingesehen, einheitliches Suffix (G-3), nur die festgelegten sensiblen Entitäten (keine Listen/Cockpit) |
domain/ablage.test.ts | 10 | NextCloud-Ablagepfad-Logik (R3/R9) + Anfangsbuchstaben-Bucket (D-31) + Upload-Ordner uploadOrdner/dokumentIdAusUploadPfad (Webhook, MED-D-55) + konfigurierbare Sandbox-Wurzel setzeBasisOrdner/basisOrdner (MED-D-56). |
domain/beratung-themen.test.ts | 4 | Vollständigkeitsprüfung der Beratungsdoku (R6) |
domain/signatur-niveau.test.ts | 4 | eIDAS-Niveau-Matrix je Dokumenttyp (R4, RISK-2) |
domain/mandant-name.test.ts | 4 | D-31: Anzeigename-Ableitung "Nachname Titel Vorname" aus R1-F08..F10; Fallback auf Einrichtungs-/Freitextname; Trim/leere Teile. |
domain/aktenreife.test.ts | 10 | D-41: Strukturierte Aktenreife (True North #3) — reif nur ohne blockierende Punkte, Score-Heuristik (100 − 25/10/4, Klemmung 0), Stufe/Schwere je Kategorie, offene Wiedervorlage = hinweis (blockiert nicht), jeStufe-Statusableitung + Blocker-Zählung, alle 3 Lifecycle-Spine-Stufen abgedeckt. MED-D-80: jeStufe.hinweis zählt offene Wiedervorlagen je Stufe (WV-Badge, MED-OP-REG-1). MED-D-151: phase→stufe/jePhase→jeStufe umgestellt (löst PROZESS_PHASE ab); neuer Test "ruhend/archiviert (off-spine) fallen auf die letzte Spine-Position zurück". |
domain/naechste-schritte.test.ts | 6 | D-46/OP-NEXTSTEP-1: abgeleitete "nächste Schritte" (G-2) — leer wenn vollständig, "Onboarding starten" vs. "nachfassen", ein Schritt je Kategorie (Dokument/Beratung/Unterschrift/Wiedervorlage), Sortierung blockierend vor hinweis, Wiedervorlage = reiner Hinweis. |
domain/deploy-status.test.ts | 5 | D-47 (Variante B): defensiver Parser des deploy_status-Werts — null bei fehlend/ungültig/Typfehler, gültiger Erfolgs-Status, runUrl optional, unbekannter Status → failure (fail-safe), failure/cancelled erkannt. |
pdf/pdf-dokument.test.ts | 3 | OP-DOCGEN-1: Blockmodell → PDF (pdf-lib) — Magic Bytes/Metadaten/deterministisches Datum, Mehrseiten-Umbruch, WinAnsi-Sanitizer |
domain/dentmarking-kennzahlen.test.ts | 9 | Dentmarking T3: 18 Kennzahlen, Formel-Varianten alt/korrigiert (B-1..B-3/OP-DM-1), Benchmarks je Praxistyp, Potential/Mehrgewinn (inkl. Beispielrechnung Excel-Logik §11), Nenner-Guards |
API / HTTP — Hono-App gegen In-Memory-Repo (MemoryRepo)
| Datei | Tests | Deckt ab |
|---|---|---|
api/app.test.ts | 46 | Kern-API: Health · Mandant (UC-1, natürliche Person ohne Typ D-45; optionale E-Mail R1-F12 + Format-Validierung) · Cockpit (UC-6, inkl. auftragStatusZusammenfassung fürs Board, MED-D-151) · Betreuungsmodell (R1-F11: Default/Cockpit/PATCH+Audit/Validierung) · aggregiertes Cockpit (/offene-punkte) · Aktenreife (Detail + Leitstand-Aggregat /api/aktenreife, OP-AKTE-1) · Lifecycle-Guard (PATCH /api/mandanten/:id lifecycleStatus, MED-D-151, löst /phase ab: 409 bei offenem Onboarding/Unterschriften, frei bei ruhend/archiviert, Playbook-Wiedervorlage bei Eintritt) · Playbooks (admin-editierbar, auf 2 Lifecycle-Stufen reduziert) |
api/beratungsdoku.test.ts | 15 | R6 Beratungsdoku inkl. Pflichtangaben (F11–F20) + Verzicht |
api/wiedervorlage.test.ts | 23 | R5 Wiedervorlagen + Delegation/Zuweisung (OP-WV-1) + Sammelaktionen (P3b, teilfehler-tolerant) + D-42: nachträglich bearbeiten (Betreff/Fälligkeit, Erinnerung reaktiviert) + append-only Kommentare (Autor/Zeitstempel, neueste zuerst, PII-armes Audit, Anzeige an der WV im Detail); MED-OP-WV-2: createWiedervorlage idempotent bei gleichem quelleRef (Race-Simulation ohne externen Check, spiegelt den D1-Unique-Index) |
api/bankkonto.test.ts | 12 | MED-D-195 (Akten-Cockpit S3a, R1-F33): 1:n-Bankkonto je Mandant (HTTP) — CRUD + mandantScopeGuard, Defaults (pruefstatus=neu/sepaGueltig=false/quelle=manuell), IBAN-Normalisierung, PATCH Prüfstatus+SEPA → archivieren statt löschen (append-only, G-4), Validierung (400) + unbekannter Mandant/Konto (404). |
api/praxis.test.ts | 15 | R1 Praxis/Gesellschaft (D-27/D-45): 0..n je Mandant, Objektart (praxis/mvz/gesellschaft) + Default/PATCH/Validierung, Geschäftsjahr-Beginn, Audit, HTTP-Validierung; MED-D-87: strukturierte Anschrift strasse/plz/ort (Wertobjekt, G-8) — anlegen getrimmt + PATCH (leer → null) |
api/dentmarking.test.ts | 31 | Dentmarking T2–T7: Fragenkatalog v1 (111 Felder, Alt-Spalten-Mapping, Zahl-Parser), Erhebung-Split zahl/text, Import-Idempotenz (B-5), GJ-Upsert, PII-armes Audit, Kennzahlen-Endpoint, Gutachten-Beleg (Fassung + R3-Referenz, keine-Daten-Guard/409), Befunde → idempotente Wiedervorlagen, öffentlicher Fragebogen T5 (Einladungs-Token, Einwilligungs-Pflicht, Einmal-Einreichung, Ablauf), T6/DM-9: Zwischenspeichern/Rehydrieren des Entwurfs + Score + Feld-Metadaten im Kontext (Service + HTTP-PUT), Markierungen an der Erhebung (kein Jahreswert), T7/DM-9: TTL aus Tenant-Einstellung + Cap 30, Ablauf-Hook (markiert/benachrichtigt idempotent, Entwurf bleibt), Statistik/Completion-Trichter, Einstellungen-API (GET/PUT admin, geklemmt) |
domain/einstellungen.test.ts | 6 | Tenant-Einstellungen — Fragebogen-TTL Default 30/Cap 30, Normalisierung/Klemmung, effektive Werte; Zeiterfassung (D-49): Schwelle Default 1/Klemmung 0..240, Rundung Default 0/Klemmung 0..60, buchungsminuten (Aufrunden auf Vielfache · kaufmännisch bei 0 · 0/negativ→0) |
domain/dentmarking-score.test.ts | 8 | Dentmarking T6/DM-9: Katalog-Metadaten (Wichtigkeits-Klassen, Markierbarkeit, Wertebereich Behandler 1–500, Struktur-Typ Öffnungszeiten), Ausfüll-Score (leer=0 / voll=100, Gewichtung essenziell>nice, Markierungen zählen als "offen markiert" nicht als Wert, leere Werte) |
ablage/r2.test.ts | 10 | Geschlossene Ablage V2 "R2 + App-UI" (MED-D-54/MED-D-58): R2Ablage erfüllt den NextCloudClient-Vertrag (ensureOrdner/exists/put/get, FakeR2Bucket ohne Netz), put() sichert Vorfassungen unter _versionen/… (verlustfrei), Upload-Link zeigt auf die App-Route, Token-Auflösung (unbekannt/abgelaufen → null, Pfad-Tricks abgewiesen), Upload pfad-sicher benannt, Invariante "nie löschen" (keine delete-Methode, MED-D-56); HTTP end-to-end: provisionieren → Upload-Link → Formular-GET → multipart-POST → erhalten → Datei-Abruf; hochladen/abgleich unverändert über den R2-Vertrag |
api/ausfuellformular.test.ts | 37 | MED-OP-VALID-1/MED-D-146: pruefeAlleWerte ist immer weich (Freitext/leer nie ein Hinweis, nur echte Format-Ausreißer); kontext() liefert hinweise/vorschlaege je Feld (gültiges-aber-nicht-kanonisches DE-Datum bekommt nur einen Vorschlag, ungültige IBAN nur einen Hinweis ohne Vorschlag, Freitext bleibt unangetastet, der Rohwert wird nie automatisch überschrieben). Ausfüll-Formulare (MED-D-63): Domäne (Festwerte aus Stammsatz, Pflichtfeld-Prüfung, Ingress-Scrubbing G-6, deterministische Beleg-Nr.) + Service (erstellen/kontext/speichern/einreichen, Beleg-PDF-Ablage, Idempotenz zweite Einreichung, ohne Ablage rein datenseitig) + HTTP-Fluss (Vorlagen-Katalog, erstellen → PUT ergänzen → einreichen, Pflichtfeld-400, unbekanntes Token-404); MED-D-67: Wichtigkeit 3-stufig, Markierungen "weiß nicht"/"nachgeliefert" (erfüllen Pflichtfeld), Nachlieferungs-Wiedervorlage idempotent + Audit; MED-D-84: Stammdaten-Rückübernahme (Vorschlag nur für eingereichte, Diff-Bildung, uebernehmen schreibt nur ausgewählte+gültige Felder + Audit PII-arm, idempotent, mandant-scoped, ungültige IBAN nicht übernommen; HTTP Vorschlag→übernehmen→idempotent; MED-D-86: Anschrift strukturiert strasse/plz/ort → verlustfreie 1:1-Übernahme); MED-D-89: Feld-Sichtung + Korrektur-Schleife (feldSichten nur eingereicht + nur gelieferte Felder, Ablehnung ohne/mit Grund + Audit PII-arm (kein Grund), sichtungAbschliessen verlangt Vollständigkeit, alles akzeptiert → bleibt eingereicht + Bestätigungs-Feedback + WV erledigt, Ablehnung → Korrektur-Schleife (nur abgelehntes Feld offen, akzeptiertes gesperrt, Re-Einreichung setzt Entscheidung zurück + reaktiviert WV), mandant-scoped) |
domain/stammdaten-version.test.ts | 5 | MED-D-179 (Stammdaten-Versionierung, G-4): snapshotVon zieht nur die versionierten Felder (kein betreuungsmodell/lifecycleStatus/verantwortlich); snapshotGleich (null≡'' , reine lifecycle-Änderung = gleich); baueNaechsteVersion (v1=GENESIS, Folgeversion kettet + zählt hoch); pruefeVersionsKette (intakt ok, manipulierter Feldwert bricht bei Position); feldHistorie (fasst unveränderte Folgeversionen zusammen, setzt gültig-bis). |
domain/stammdaten-uebernahme.test.ts | 12 | MED-D-84 (Formular → Stammdaten): reine Diff-/Validierungslogik — Ausfüll-Formular-Felder → Stammdaten-Ziele, IBAN-Mod-97/Datum-Format-Gültigkeit (ungültig markiert aber vorgeschlagen), Idempotenz (kein Vorschlag bei Gleichstand), Normalisierung, leere/unbekannte Werte übersprungen, bauePatch überträgt nur Zielfelder. pruefeWert/normalisiereWert/ValidierungsArt sind seit MED-D-146 Re-Exporte aus domain/feld-typ.ts (G-8) — Importpfad hier unverändert. |
domain/feld-sichtung.test.ts | 8 | MED-D-89/MED-OP-FORM-4 (Feld-Sichtung, reine Domäne): zuSichtendeFelder (nicht-leer, unmarkiert, sortiert), offene/vollständig gesichtet (leere Menge ≠ vollständig), setzeEntscheid (Ablehnung verlangt Grund, Akzeptanz verwirft Grund), abgelehnte/akzeptierte Felder, entscheidungenZuruecksetzen (Korrektur-Schleife), feedbackNachricht (Ablehnung listet Grund + Korrektur-Link / alles akzeptiert = Bestätigung ohne Link). |
api/formular-vorgaenge.test.ts | 15 | Fragebogen-/Formular-Vorgänge (MED-D-67): Domäne (Katalog maxParallelOffen=1 je Typ, verallgemeinerter Ausfüllgrad Pflicht 2/optional 1 inkl. Whitespace/fremde Schlüssel/leere Felder, SLA-Zustände ok→erinnerung_faellig→ueberfaellig, quelleRefs) + Parallel-Limit idempotent (Onboarding je Mandant · Ausfüll-Formular je Mandant×Vorlage; nach Abschluss/Ablauf wieder frei) + Öffnungs-Tracking geoeffnetAm genau einmal (alle drei Strecken, Audit) + Sichtungs-Wiedervorlage (idempotent, Verantwortliche:r, Quelle formular) + SLA-Cron (weiche Erinnerung einmalig + PII-arm empfaenger:null, harte Eskalation idempotente Wiedervorlage, abgelaufener Link ohne weiche Erinnerung, abgeschlossene Vorgänge neutral) |
api/dokument.test.ts | 13 | R3 Dokumente (Provisionieren/Abgleich/Status) + Upload-Link (OCS File Drop) + Webhook (MED-D-55): uploadLinkErzeugen idempotent, webhookDateiErstellt (Pfad→Dokument, angefordert→erhalten, idempotent, fremde ignoriert), HTTP Upload-Link + Webhook (401 ohne Secret, 200 + Statuswechsel mit Secret) + Invariante "nie löschen" (Vertrag ohne delete/remove/rm, MED-D-56) |
api/dokumentgenerierung.test.ts | 9 | R12 Dokumenten-Automatisierung |
api/individualdokument.test.ts | 11 | MED-D-81: Freitext-Individualdokument — Block-/Benennungs-Engine, Service (erstellen→freigeben→erzeugen→R3-PDF; Bearbeiten nach Freigabe gesperrt; explizites eIDAS-Niveau schlägt Titel-Ableitung; zurUnterschrift lehnt bei erzeugt steckengebliebene Dokumente ab), HTTP-Vollfluss + 503/400. |
api/beratungsauftrag.test.ts | 20 | MED-D-95/99 (Slice A): Katalog (Enum↔Eintrag, laufend nur Dauer-Produkte), Service (anlegen/Status mandant-scoped + produkt-validiert; person-oder-praxis; nicht buchbar/fremde Praxis abgelehnt; Audit-Events G-4). MED-D-101 (Slice B): Reife-Regeln (Beratungsdoku ab Beratung, Unterschrift, Gutachten-Produkt); Artefakt binden/lösen aktualisiert Reife; fremdes Artefakt abgelehnt; idempotente Retro-Ableitung (je Praxis EIN Auftrag abgeschlossen, Gutachten gebunden, zweiter Lauf 0/0); Bindungs-Besitz-Guard (Lösen/Umhängen fremder Auftrag → artefakt_anders_gebunden, CodeRabbit #135). MED-D-104 (Slice C1): Produkt-Playbook — jedes buchbare Produkt hat Standard-Aufgaben (dexman leer); anlegen erzeugt die Playbook-Wiedervorlagen (quelle=playbook, an den Auftrag gebunden). MED-D-105 (Fehler-Isolation, CodeRabbit #138): ein Repo-Fehler beim Playbook lässt die bereits persistierte Auftrags-Anlage nicht scheitern (kein Retry-Doppel) und wird PII-arm als auftrag.playbook_fehler auditiert. MED-D-151 (+2, Auftrags-Status-Playbook): →beratung/→unterschrift erzeugen je genau eine idempotente Wiedervorlage (an den Auftrag gebunden, wiederholter Aufruf kein Duplikat); ein Repo-Fehler beim Status-Playbook rollt den bereits persistierten Statuswechsel nicht zurück. |
api/meeting.test.ts | 8 | MED-D-82 (R11): Gesprächsnotiz/Meeting-Doku — Domain (Bezeichnung, aufgabeQuelleRef normalisiert-stabil), Service (erstellen→Vorschlag→Übernahme legt Wiedervorlagen quelle='aufgabe' an, delegiert; idempotent; ohne Frist sofort fällig; bearbeiten lehnt leeren Titel ab), HTTP-Vollfluss (400 bei ungültiger Art; Aufgabe im WV-Register sichtbar = eine Wahrheit). |
ki/gespraechs-auswerter.test.ts | 4 | MED-D-82: Regel-Auswerter (Fake-Seam) — parst "Aufgabe:"/Checkbox-Zeilen, extrahiert @verantwortlich + ISO-/DE-Fälligkeit, ignoriert Prosa ohne Marker, liefert Haftungshinweis (RISK-14). |
ki/regel-vorschlag.test.ts | 3 | MED-D-146 (MED-OP-VALID-1 Slice 1): RegelVorschlag (Fake-Seam analog RegelPruefer/RegelAuswerter) — schlägt bei erkennbarem Format-Fehler einen korrigierten Wert vor + trägt den Haftungshinweis (RISK-14), liefert vorschlag: null wenn kein sicherer Vorschlag ableitbar ist (z. B. E-Mail-Tippfehler), name identifiziert den Fake-Adapter. |
api/leistungszeit.test.ts | 11 | R13 Leistungszeit + Übersicht (OP-TIME-1) + Mandat-Zuordnung (MED-D-157/158) |
api/timer.test.ts | 46 | MED-D-172 (Aktiver Timer, OP-TIME-3): Service-Ebene — Start (frisch/idempotent bei gleichem Mandanten/Konflikt bei anderem Mandanten, keine stille Überschreibung), Pause/Fortsetzen (Segment-Übernahme in basisMs, idempotent), Korrigieren (überschreibt + pausiert), Buchen (mit weiterlaufen true → frischer Timer läuft weiter; false → Timer beendet, Verlassen-Flow), Verwerfen, Fehlercodes (kein_timer/anderer_mandant); zwei Benutzer haben unabhängige Timer. HTTP-Ebene: alle /api/timer*-Routen inkl. Validierung (400) + 409-Konfliktfälle. MED-D-174 (CodeRabbit-Nachlese, RBAC-Sicherheitsfund): eigene RBAC-Describe-Gruppe — /api/timer/start/buchen für einen fremden (nicht sichtbaren) Mandanten → 404 kein Existenz-Leak, für den eigenen → 201-Regression. |
api/signatur.test.ts | 23 | R4 Signatur-Vorgänge (inkl. AD-006 Empfänger-Override + MED-D-244 Dokument-Scope-Guard) |
api/audit.test.ts | 10 | R8 Audit-API + Integritätsprüfung (/verify); D-50 Zugriffs-Protokollierung: Akte öffnen → mandant.eingesehen (PII-arm details={}, Kette intakt), Beratungsdoku-Lesen → beratungsdoku.eingesehen (Gesundheitsbogen R6-F18), Datei-Abruf → dokument.eingesehen, Listen/Cockpit erzeugen kein .eingesehen (G-6) |
api/onboarding-formular.test.ts | 16 | R2 Self-Service-Onboarding (öffentlicher Formular-Flow) + MED-D-68: Zwischenspeichern/Rehydrieren des Entwurfs + Fertigstellungsgrad (Service + HTTP-PUT, Ingress-Scrubbing) |
Auth
| Datei | Tests | Deckt ab |
|---|---|---|
auth/auth.test.ts | 9 | Identität (Cloudflare Access), RBAC, Bootstrap-Admin, AUTH_ENFORCED (R7/OP-AUTH-1) |
domain/rechte.test.ts | 8 | Rechte-Matrix darf(rolle, faehigkeit) je Rolle + Mandant-Scope darfMandantSehen (null/eigen/fremd, whitespace-normalisiert), D-48; fragebogen_statistik_sehen admin-exklusiv (OP-DM-9/MED-D-63) |
api/stammdaten-versionierung.test.ts | 7 | MED-D-179 (Stammdaten-Versionierung, Slice 1): createMandant seedet v1; updateMandant mit geändertem Feld erzeugt v2 (Kette intakt, Herkunft berater/actor übernommen); reine lifecycleStatus/verantwortlich-Änderung erzeugt keine neue Version (kein Rausch-Bump); self_service-Herkunft; backfillStammdatenV1 idempotent (seedet nur fehlende); HTTP GET /api/mandanten/:id/stammdaten-versionen liefert die Kette aufsteigend; Berater-PATCH erzeugt eine berater-Version mit korrektem Actor/Snapshot. |
api/rbac.test.ts | 14 | RBAC je Mandant HTTP: Flag aus/an, Scope der Aggregate (/api/mandanten, /offene-punkte, /aktenreife), Detail-Guard (Fremd→404), Zuweisung (200/400/403 + Audit), /api/benutzer/zuweisbar-Guard, Rückwärtskompatibilität, D-48; /api/fragebogen/statistik admin-gated 403/200 (OP-DM-9/MED-D-63); MED-OP-AUTH-2: By-ID-Mandant-Scope-Guard für Meetings/Beratungsdoku/Individualdokumente (fremd→404, eigen→200/201, je 1 Test — vor der Implementierung gegengeprüft: schlägt ohne den Fix fehl) |
Worker-Auslieferung (Routing-Weiche des Workers)
| Datei | Tests | Deckt ab |
|---|---|---|
serving.test.ts | 12 | Regressionsschutz zum Public-Link-Vorfall (OP-ONBOARD-1): zielIstAssets leitet /oeffentlich* (Onboarding-/Fragebogen-Daten) + /api* an die App statt an die SPA-Assets (inkl. Pfad-Grenze gegen Präfix-Kollisionen wie /apiary); öffentliche Seiten (/fragebogen/:token, /onboarding/:token) + statische Dateien an die Assets. istSpaNavigation = SPA-Fallback nur für Dokument-Navigationen (kein Datei-Suffix). spaFallback = Fallback liefert index.html als 200, nie als Redirect (Cloudflares Asset-Layer beantwortet explizites /index.html per html_handling-Default mit 307 → / → Access-Loginwand); Fakes decken beide html_handling-Modi ab. echterFaviconPfad (MED-D-78): mappt /oeffentlich/favicon.svg/.png auf die echten Asset-Pfade — Favicon läuft über den bestehenden Access-Bypass, alle anderen Pfade → null. (Die Cloudflare-Access-Konfiguration selbst ist Infrastruktur und nicht per Test abdeckbar.) |
CI-Pipeline (.github/workflows/ci.yml)
Ein changes-Vorabjob (dorny/paths-filter) erkennt die geänderten Bereiche; die schweren Jobs laufen
nur bei betroffenem Bereich (Pfad-Filter, agents.md §6.6) und werden vom aggregierten CI Gate
zusammengefasst (Merge nur bei grünem Gate; übersprungene Bereiche zählen als bestanden):
- Server (typecheck + test) —
tsc+ Vitest. (nur wennserver/**geändert; aufmain-Push immer) - Client (build) — Angular-Prod-Build. (nur wenn
client/**geändert; aufmain-Push immer) - Doku-Konsistenz — mechanischer Check (warnt, blockt nicht — Job selbst ist grün; läuft immer).
- Doku-Site (build) — Docusaurus inkl. Broken-Link-Check. (nur bei
docs/**/docs-site/**/*.md; aufmain-Push immer)
So überspringt ein Doku-only-PR Server/Client, ein Code-only-PR die Doku-Site — schnellere PR-Läufe.
Installs laufen mit npm ci --prefer-offline --no-audit --fund=false, der Checkout ist auf PRs shallow
(fetch-depth: 1, voll nur auf main-Push). CI Gate prüft, dass keiner der erforderlichen Jobs
fehlgeschlagen ist (skipped ≠ failure). CodeRabbit-Reviews laufen separat
und sind nicht-blockierend. Deploys (app-deploy.yml / docs-deploy.yml) laufen getrennt bei Push auf main.
Runner: alle CI-Jobs pinnen auf das Label hot (persistenter self-hosted Runner — warmes ~/.npm,
.angular/cache, clean: false greifen nur dort; ephemere Runner tragen ephemeral), D-38; Fork-PRs auf
ubuntu-latest (Gate). Umschalten auf
GitHub-Runner ohne Commit über die Repo-Variable CI_RUNNER (Details: Deploy.md §7b, RISK-24).
Auto-Rerun (auto-rerun.yml, D-40): ein separater workflow_run-Workflow stößt bei einem
fehlgeschlagenen CI-Lauf die fehlgeschlagenen Jobs einmalig neu an (run_attempt < 2) — heilt
flakige hot-Runner-Läufe automatisch; abgebrochene Läufe und Fork-PRs sind ausgenommen (RISK-24),
Deploys ebenfalls. Kein eigener Testlauf, sondern Selbstheilung der Pipeline.
Konventionen
- Neue Tests beiden Wegen hinzufügen: lokal (
npm test/npm run build) und damit automatisch in CI. - Domänenlogik als reine Funktionen testen; Dienste/Routen über die Hono-App gegen
MemoryRepo(kein D1 im Test). - Zahlen in dieser Datei je PR aktualisieren (siehe Kopf).