Files
tessera-ctl/.planning/quick/260911-cwh-mandantentrennung-etappe-2-bereich-calen/260911-cwh-SUMMARY.md
T

12 KiB

phase, plan, subsystem, tags, requires, provides, affects, actuals, tech-stack, key-files, key-decisions, requirements-completed, coverage, duration, completed, status
phase plan subsystem tags requires provides affects actuals tech-stack key-files key-decisions requirements-completed coverage duration completed status
quick-260911-cwh 01 database
prisma
postgresql
row-level-security
multi-tenancy
nestjs
vitest
calendar
phase provides
quick-260910-krx Bereich dashboard vollstaendig gebunden, Muster fuer generierten-Client-Messung (Pruefung 5b)
Bereich calendar (calendar.service.ts, Modell calendarSource) vollstaendig an forTenant() gebunden, alle zwoelf Datenbankzugriffe
Elfter Abschnitt runCalendarAreaChecks in rls-scratch-check.mjs mit 13 neuen Pruefungen (davon vier ueber den generierten Client)
calendar.service.spec.ts NEU angelegt — erste Testlage dieses Bereichs, 23 Testfaelle mit Zwei-Klienten-Nachweis
Kritikschrift Abschnitt '## Bereich calendar' mit gemessenem Cache-Schluessel-Urteil und Zugangsdaten-Erhaltungsbefund
WINDOWS #26: offener Ledger-Eintrag zur lautlosen Fehlerrichtung im Bereich calendar
etappe-2-mandantentrennung
calendar-modul
rls-scratch-check-tooling
tokens tasks commits plan_head_before
25378 3 3 508d9e4301
added patterns
forTenant(this.prisma, tenantId) als lokale tenantPrisma-Konstante je Methode mit Datenbankzugriff (dienst-interner Weg, wie alle acht Bereiche vor calendar)
Zwei-Klienten-Testnachweis via __makeBoundClient(tenantId) — ungebundener Fake protokolliert nicht, gebundener schon
Generierter-Client-Messung an einer schemagleichen Wegwerf-Tabelle (Spaltenmenge zur Laufzeit gegen schema.prisma geprueft) statt Roh-SQL, fuer Fehlerklassen die die Anwendung tatsaechlich sieht
created modified
apps/api/src/calendar/calendar.service.spec.ts
apps/api/scripts/rls-scratch-check.mjs
docs/mandantentrennung-etappe2-fehlerrichtung.md
apps/api/src/calendar/calendar.service.ts
apps/api/src/calendar/calendar.controller.ts
docs/mandantentrennung-zugriffsklassifikation.md
.planning/WINDOWS.md
Cache-Schluessel (userId:from:to) bleibt OHNE Mandantenanteil — die vierteilige Kette (schema.prisma User.id @default(uuid()) -> JwtStrategy.validate -> auth.service.ts sub:user.id -> extractContext) zeigt eine plattformweit eindeutige UUID, die Etappe-3-Entscheidung (1) betrifft User.username/User.email, nicht User.id
Keine neue Fehleruebersetzung fuer die drei Besitzpruefungen noetig: der gemessene Wettlauf-Fall wirft PrismaClientKnownRequestError/P2025 (nicht PrismaClientUnknownRequestError wie im Bereich dashboard), und dieser Pfad ist durch die vorgeschaltete findUnique-Besitzpruefung strukturell unerreichbar
refreshCacheInBackground wird NICHT als sechster Hintergrunddienst-Fall gefuehrt — sie iteriert nicht ueber Mandanten, sondern traegt den Mandanten der Anfrage, die sie angestossen hat (Befund B)
Antwortsemantik 403 (Forbidden bei fremdem Besitz) vs. 404 (NotFound bei unbekannter Kennung) bleibt unveraendert — waere eine API-Aenderung ausserhalb des Auftrags
WINDOWS-18
ETAPPE-2-CALENDAR
id description requirement verification human_judgment
D1 Alle zwoelf Datenbankzugriffe von calendar.service.ts laufen gebunden ueber forTenant(), ein tenantPrisma-Klient je Methode mit Datenbankzugriff ETAPPE-2-CALENDAR
kind ref status
unit apps/api/src/calendar/calendar.service.spec.ts — 23 Testfaelle pass
kind ref status
unit apps/api/src/prisma/rls-access-inventory.spec.ts — Bestandsaufnahme stimmt mit Quelltext ueberein pass
kind ref status
other node apps/api/scripts/rls-scratch-check.mjs — runCalendarAreaChecks, 13 neue Pruefungen pass
false
id description requirement verification human_judgment
D2 Kritikschrift misst die umgekehrte Fehlerrichtung an der ausgelieferten Regel (Migration 20260909140000, bestaetigt unveraendert durch 20260910120000) inklusive vier Pruefungen ueber den generierten Prisma-Client an einer schemagleichen Wegwerf-Tabelle WINDOWS-18
kind ref status
other node apps/api/scripts/rls-scratch-check.mjs — Pruefungen calendarsource-wegwerftabelle-deckt-alle-spalten-des-generierten-clients, calendarsource-generierter-client-* pass
false
id description verification human_judgment
D3 Fuenf handgepflegte Dokumentstellen der Klassifikation nachgezogen und maschinell gegen den Quelltext gegatet; WINDOWS-Ledger-Eintrag #26 in Tabelle, JSON-Block und Kopfzaehlern konsistent
kind ref status
unit apps/api/src/prisma/rls-access-inventory.spec.ts pass
kind ref status
other Plan-Verify-Gates Aufgabe 3 (Uebersichtszeile, Summenzeile, Klassen-Verteilung, Hintergrunddienst-Abschnitt, WINDOWS.md-Konsistenz) — manuell in der Ausfuehrung nachvollzogen pass
false
21min 2026-09-11 complete

Quick Task 260911-cwh: Etappe 2 Mandantentrennung, Bereich calendar — Summary

Alle zwoelf calendarSource-Datenbankzugriffe in calendar.service.ts auf forTenant() umgestellt (ein tenantPrisma-Klient je Methode), mit einer aus dem Nichts angelegten Testlage (23 Faelle), 13 neuen Wegwerf-Pruefungen — vier davon ueber den generierten Prisma-Client — und einem gemessenen, schriftlich festgehaltenen Urteil zum Cache-Schluessel sowie zur Zugangsdaten-Erhaltung.

Performance

  • Duration: 21 min
  • Started: 2026-09-11T07:39:07Z
  • Completed: 2026-09-11T08:00:00Z (ca.)
  • Tasks: 3
  • Files modified: 7 (6 modified, 1 neu angelegt)

Accomplishments

  • Neunter Bereich der Etappe 2 (Mandantentrennung) abgeschlossen: calendar — der einzige bisher umgestellte Bereich, der verschluesselte Zugangsdaten zu FREMDEN Servern (Exchange/CalDAV/ICS) haelt
  • apps/api/scripts/rls-scratch-check.mjs: elfter Abschnitt runCalendarAreaChecks mit 13 namentlich benannten Pruefungen, davon vier ueber den generierten Client an einer Wegwerf-Tabelle, deren 17-Spalten-Deckung zur Laufzeit gegen schema.prisma geprueft wird — alle 101 Pruefungen des Werkzeugs bestehen
  • calendar.service.spec.ts: NEU angelegt (dieser Bereich hatte zuvor KEINE Testdatei), 23 Testfaelle mit Zwei-Klienten-Nachweis, decken jeden Datenbankpfad, alle drei Besitzpruefungen je Ausnahmeart, die drei Zugangsdaten-Erhaltungsfaelle, beide Rueckschreibungen der Aggregationsschleife und den Wachhund fuer "genau ein Klient je Aufruf" ab
  • Kritikschrift (docs/mandantentrennung-etappe2-fehlerrichtung.md, Abschnitt ## Bereich calendar) mit (k1)-(k5): die tatsaechlich gemessene Fehlerklasse des Wettlauf-Falls (PrismaClientKnownRequestError/P2025, ANDERS als im Bereich dashboard), das vierteilige Cache-Schluessel-Urteil, die Backend- UND Frontend-Leere-als-Abwesenheit-Kette samt Fehlerverschluckung
  • Fuenf handgepflegte Stellen der Klassifikation nachgezogen (Bestandsaufnahme-Zeile, Uebersichtszeile 0/12, Summenzeile 83/159, Klassen-Verteilung mit Stand-Vermerk, Hintergrunddienst-Abschnitt mit dem Sonderfall refreshCacheInBackground), WINDOWS-Ledger-Eintrag #26 angelegt

Task Commits

Each task was committed atomically:

  1. Aufgabe 1: Fehlerrichtung messen - bf5fc4d (feat)
  2. Aufgabe 2: Testlage anlegen, alle zwoelf Zugriffe binden - 77cb124 (feat)
  3. Aufgabe 3: Restliche Dokumentstellen, WINDOWS-Ledger, Falsifizierungsnachweise - e0e163e (docs)

Kein TDD-Modus fuer diesen Plan — die Testlage wurde in Aufgabe 2 als Voraussetzung neu angelegt, nicht als RED/GREEN-Zyklus einzeln entwickelt.

Files Created/Modified

  • apps/api/scripts/rls-scratch-check.mjs - elfter Abschnitt runCalendarAreaChecks (13 neue Pruefungen), Helfer readSchemaModelFieldNames()
  • docs/mandantentrennung-etappe2-fehlerrichtung.md - Abschnitt ## Bereich calendar mit (k1)-(k5)
  • apps/api/src/calendar/calendar.service.spec.ts - NEU, 23 Testfaelle, Zwei-Klienten-Nachweis
  • apps/api/src/calendar/calendar.service.ts - alle zwoelf Zugriffe gebunden, Klassenkommentar praezisiert, Cache-Schluessel-Urteil und Hintergrunddienst-Begruendung als Kommentare
  • apps/api/src/calendar/calendar.controller.ts - sechs kontextnutzende Handler reichen Benutzer- UND Mandantenkennung durch
  • docs/mandantentrennung-zugriffsklassifikation.md - fuenf handgepflegte Stellen nachgezogen
  • .planning/WINDOWS.md - neuer offener Eintrag #26

Decisions Made

  • Cache-Schluessel bleibt ohne Mandantenanteil — vierteilige Kette gemessen, Urteil in Code UND Kritikschrift verankert (siehe key-decisions oben)
  • Keine neue Fehleruebersetzung fuer die Besitzpruefungen: gemessener Wettlauf-Fall (P2025) ist ueber die vorgeschaltete Pruefung strukturell unerreichbar
  • refreshCacheInBackground bleibt ausserhalb des Hintergrunddienst-Abschnitts (kein sechster Fall) — sie traegt den Mandanten der Anfrage, iteriert nicht ueber mehrere Mandanten
  • Antwortsemantik 403/404 bewusst unveraendert gelassen

Deviations from Plan

None - plan executed exactly as written. Alle Planungsbefunde (A-L) wurden zur Ausfuehrungszeit nachgeprueft und bestaetigt; keine Abweichung von den Planungsbefunden trat auf.

Falsifizierungsnachweise (drei, alle durchgefuehrt und zurueckgenommen)

  1. Aufgabe 2 — halb gebundene Aggregationsschleife: Die Bindung der Synchronstatus-Rueckschreibung im Erfolgspfad von fetchAndCacheEvents wurde probeweise zurueckgenommen (tenantPrisma.calendarSource.update → this.prisma.calendarSource.update). Ergebnis: der benannte Test aggregateEvents, Erfolgspfad: das Laden der Quellen UND die Synchronstatus-Rueckschreibung bei Erfolg stehen gebunden unter derselben Mandantenkennung im Protokoll ging rot mit der Meldung erwarteter gebundener Aufruf calendarSource.update(tenant=t1) fehlt im Protokoll: [{"tenantId":"t1","model":"calendarSource","method":"findMany"}]: expected false to be true. Bindung wiederhergestellt, Testlage danach wieder gruen (23/23).
  2. Aufgabe 3a — falscher Stand in der Bestandsaufnahme: Die Zeile calendar.service.ts/calendarSource wurde probeweise auf Stand: ungebunden zurueckgesetzt. Ergebnis: rls-access-inventory.spec.ts ging rot mit Abweichender Stand (Dokument vs. Quelltext): apps/api/src/calendar/calendar.service.ts::calendarSource — dokumentiert=ungebunden, gemessen=gebunden. Zurueckgesetzt, Test danach wieder gruen (10/10).
  3. Aufgabe 3b — falsche Uebersichtszahl: Die Uebersichtszeile calendar wurde probeweise auf 5 | 12 (statt der gemessenen 0 | 12) gesetzt. Ergebnis: das herleitende Gate (grep -qE "^\| calendar \| ${DU} \| ${DB} \| \*\*war 12/0\*\*") meldete UEBERSICHTSZEILE calendar nennt nicht die neu gemessenen Zahlen 0/12 im etablierten Stil. Zurueckgesetzt, Gate danach wieder erfuellt.

Issues Encountered

None.

User Setup Required

None - keine externe Diensteinrichtung erforderlich.

Next Phase Readiness

  • Neunter von zwoelf Bereichen der Etappe 2 abgeschlossen — Klassen-Verteilung (63 Paare) unveraendert, nur die Stand-Spalte des calendar-Paares gewechselt
  • Der Schalter (DATABASE_URL → Rolle tessera, BYPASSRLS) bleibt AUS — keine Compose-/Umgebungsdatei angefasst, keine Schema-/Migrationsaenderung, nichts in Active Directory
  • Baseline am Ende gehalten: 883 Tests gruen (57 Dateien, davon 23 neu), Typpruefung sauber, rls-scratch-check.mjs meldet 101/101 Pruefungen bestanden
  • WINDOWS #26 bleibt bis nach dem Scharfschalten (Etappe 4) offen — an dieselbe Bedingung gebunden wie #18, Familie mit #23/#25
  • Naechster Bereich der Etappe 2 (zehnter von zwoelf) ist aus der Klassen-Verteilung in docs/mandantentrennung-zugriffsklassifikation.md zu waehlen

Self-Check: PASSED

All created/modified files verified present on disk; all three task commit hashes (bf5fc4d, 77cb124, e0e163e) verified present in git history.


Phase: quick-260911-cwh Completed: 2026-09-11