docs(quick-260909-dgj): Mandantentrennung vorbereitet — Plan, Bericht, Befunde
Tessera CI/CD / Lint & Type Check (push) Successful in 45s
Tessera CI/CD / Tests (push) Successful in 52s
Tessera CI/CD / Build & Publish Images (push) Successful in 28s

Die Arbeit liefert Rolle, Verbindungstrennung, Pruefwerkzeug und Policies fuer
alle 16 offenen Tabellen, schaltet die Trennung aber bewusst NICHT scharf.

Grund, gemessen statt vermutet: im Code stehen 182 Datenbankzugriffe ohne
Mandantenkontext gegen 19 mit. Der Anmeldeweg ist zwingend darunter — er liest
die Benutzerzeile, bevor der Mandant bekannt ist, weil der Mandant erst aus
dieser Zeile kommt. Unter einer Rolle ohne Umgehungsrecht liefert diese Abfrage
nichts, und niemand koennte sich mehr anmelden. Das Scharfschalten ist damit
ein eigener Vorgang, kein Nebeneffekt dieser Arbeit.

Neu im Ledger als #19: SearchProvider und TenderRssFeedSource haben ein
nullable tenantId. Die einfache Policy vergleicht NULL nie gleich, wodurch die
plattformweiten Zeilen nach dem Scharfschalten fuer JEDEN Mandanten
verschwinden wuerden — nicht nur fuer fremde. Heute wirkungslos, beim
Scharfschalten zwingend mitzuloesen. Die richtige Semantik ist eine
Produktentscheidung, deshalb bewusst nicht eigenmaechtig anders geloest.

673/673 Tests gruen, Typpruefung sauber. #18 bleibt offen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FYZcd3SSmo14QTqWx2KKzU
This commit is contained in:
2026-09-09 10:08:59 +02:00
parent efaabc97a2
commit ea003d44fe
3 changed files with 231 additions and 9 deletions
+7 -6
View File
@@ -4,10 +4,10 @@ milestone: v1.2
current_phase: 17
current_phase_name: eigene-ausschreibungs-quellen-je-nutzer
status: verified
stopped_at: "Quick Task 260909-cx0 abgeschlossen: user-files-Volume ergaenzt (WINDOWS #17 bleibt offen bis Server-Uebernahme), CLAUDE.md-Technik-Block auf installierten Stand korrigiert"
last_updated: "2026-09-09T10:00:00.000Z"
stopped_at: "Drei Vorhaben am 2026-09-09 abgearbeitet: Dateisicherung fuer user-files (benanntes Volume), Versionsangaben in CLAUDE.md auf den installierten Stand samt Abschnitt ueber sechs nie eingebaute Empfehlungen, und die Vorbereitung der Mandantentrennung. Bei letzterer kam der schwerste Befund der Sitzung heraus: die vorhandene Datenbank-Trennung wirkt gar nicht, weil die Anwendungsrolle sie umgeht (#18) — praktisch gemessen. Gebaut sind Rolle, Verbindungstrennung, Pruefwerkzeug und Policies fuer alle 16 offenen Tabellen; das Scharfschalten bleibt aus, weil 182 Zugriffe ohne Mandantenkontext im Code stehen und der Anmeldeweg darunter zwingend ist. OFFEN: #17 (Volume-Zeile auf dem Server nachtragen), #18 (Scharfschalten, braucht die 182 Stellen), #19 (nullable tenantId bei SearchProvider und TenderRssFeedSource)."
last_updated: "2026-09-09T10:10:00.000Z"
last_activity: 2026-09-09
last_activity_desc: Dateisicherung nachgeruestet, Versionsangaben in CLAUDE.md auf den installierten Stand gebracht
last_activity_desc: Mandantentrennung vorbereitet — Rolle, Policies und Pruefwerkzeug gebaut, Umschalten bewusst offen
state_head: c80704957a5518e316a53edc0b8d7e98052a9750
progress:
total_phases: 17
@@ -368,6 +368,7 @@ None yet.
| 260909-ab3 | Zwei Befunde aus der Live-Pruefung behoben. **#14:** Die Suche in der Freigaben-Matrix filterte beide Achsen mit demselben Begriff und leerte dadurch die jeweils andere — jetzt bleibt die nicht getroffene Achse vollstaendig stehen, die Gruppensuche unter internem UND AD-Namen (#6c) ist per Regressionstest gesichert. **#15:** AD-Konten mit bereits vergebener Mailadresse werden nun angelegt, nur ohne Adresse (Produktentscheidung des Users vom 2026-09-09; der erste Anspruch behaelt die Adresse), auf BEIDEN Wegen — Sync und Einzelimport. Rohe Prisma-Texte gehen nur noch ins Log, der Bericht zeigt drei verstaendliche deutsche Abschnitte. **Sicherheitsfund nebenbei geschlossen (T-Q3-01):** der Update-Zweig schrieb die Mailadresse bedingungslos um, ein Verzeichniseintrag haette so die Adresse einer echten Person uebernehmen und deren Passwort-Reset empfangen koennen. `User.email` ist jetzt optional (Migration geschrieben, laeuft beim naechsten API-Start automatisch mit). Verifiziert 8/8: 651/651 API- und 233/233 Web-Tests, beide Typpruefungen sauber; die Sicherheitspruefung wurde durch Rueckbau falsifiziert (ohne Besitzpruefung schlaegt der Test fehl). **Am 2026-09-09 im Browser abgenommen, beide Ledger-Punkte geschlossen** (Bericht: 260909-ab3-UAT-2026-09-09.md) | 2026-09-09 | 2167046 | [260909-ab3-matrix-suche-und-sync-meldungen-reparier](./quick/260909-ab3-matrix-suche-und-sync-meldungen-reparier/) |
| 260909-cx0 | Hochgeladene Dateien (Avatare, DKV-Exporte) ueberlebten kein `--force-recreate` des api-Containers (WINDOWS #17) — lagen nur in der fluechtigen Container-Schicht, keine Compose-Datei mountete `/app/user-files`. Jetzt benanntes Docker-Volume `user-files` in `docker-compose.yml` und `docker-compose.prod.yml` (Eigentuemerschaft uid 1001 aus dem Image, kein Bind-Mount), Betriebshandbuch Kapitel 6/7 entsprechend nachgezogen. Zweiter, unabhaengiger Punkt: CLAUDE.md nannte fuer die Technik-Tabelle noch die 2026-06/07-Empfehlung (Next.js 16.2.x, Prisma 7.8.x, Keycloak, Redis, TanStack Query, shadcn/ui, Playwright, Husky, lint-staged) statt des installierten Stands — jetzt korrigiert auf Next.js 15.5.19, Prisma 6.19.3 etc., nie uebernommene Empfehlungen in eigenem Abschnitt "Recommended But Not Adopted", `.planning/research/STACK.md` nur mit Hinweiszeile ergaenzt. Keine Abhaengigkeit aktualisiert. **WINDOWS #17 bleibt offen** — die Aenderung erreicht die laufende Installation auf alpha nicht, `/opt/tessera/docker-compose.yml` weicht vom Repository ab und muss vom Nutzer selbst ergaenzt werden | 2026-09-09 | dab72eb,c807049 | [260909-cx0-dateisicherung-nachruesten-und-versionsa](./quick/260909-cx0-dateisicherung-nachruesten-und-versionsa/) |
| 260909-cx0 | Dateisicherung nachgeruestet und Versionsangaben geradegezogen. **user-files** liegt jetzt in einem benannten Volume (docker-compose.yml und .prod.yml) — vorher lag der Ordner nur in der fluechtigen Container-Schicht, hochgeladene Profilbilder und DKV-Exporte waeren bei jedem --force-recreate weg gewesen. Benanntes Volume statt Bind-Mount, weil das Image /app/user-files an uid 1001 uebereignet; ein frisch angelegtes Host-Verzeichnis gehoert root und haette aus dem Datenverlust einen kaputten Upload gemacht. docker-compose.dev.yml blieb bewusst unveraendert (Compose fuehrt Mount-Listen ueber das Ziel zusammen). **CLAUDE.md** nennt jetzt die installierten Fassungen statt der urspruenglich empfohlenen (Next.js 15.5.19 statt 16, Prisma 6.19.3 statt 7); neu ist ein Abschnitt 'Recommended But Not Adopted', der sechs nie eingebaute Empfehlungen benennt — darunter Keycloak, Redis und shadcn/ui. Der Block ist generiert, deshalb traegt er einen Herkunftsvermerk und die Recherchedatei eine datierte Hinweiszeile; ihre Zahlen blieben unangetastet. Keine Abhaengigkeit angefasst (per git diff gegengeprueft). **WINDOWS #17 bleibt offen**, bis der User dieselbe Volume-Zeile in /opt/tessera/docker-compose.yml nachtraegt — die Serverdatei weicht vom Repository ab | 2026-09-09 | c807049 | [260909-cx0-dateisicherung-nachruesten-und-versionsa](./quick/260909-cx0-dateisicherung-nachruesten-und-versionsa/) |
| 260909-dgj | Mandantentrennung auf Datenbankebene vorbereitet (WINDOWS #18). Ausloeser war ein gemessener Befund: die Anwendung verbindet als Rolle mit Superuser- und BYPASSRLS-Recht, daher greifen die sieben vorhandenen Policies gar nicht — ohne gesetzten Mandantenkontext lieferte 'SELECT count(*) FROM Group' zwei statt null Zeilen. Gebaut wurden: Rolle `tessera_app` ohne Umgehungsrecht (wiederholbare Migration, kein Kennwort im SQL), Trennung von Migrations- und Laufzeitverbindung ueber TESSERA_MIGRATE_DATABASE_URL, ein Pruefwerkzeug mit fuenf transaktionssicheren Nachweisen, Policies fuer die 16 fehlenden Tabellen und eine Betriebsanleitung. **Der Schalter bleibt bewusst aus, #18 bleibt offen:** im Code stehen 182 Datenbankzugriffe ohne Mandantenkontext gegen 19 mit — darunter zwingend der Anmeldeweg, der die Benutzerzeile liest, bevor der Mandant bekannt ist (er kommt erst aus dieser Zeile). Ein Umschalten wuerde die Anmeldung fuer alle sperren. Dabei fiel #19 an: SearchProvider und TenderRssFeedSource haben ein nullable tenantId; die einfache Policy wuerde die plattformweiten Zeilen nach dem Scharfschalten fuer jeden Mandanten unsichtbar machen. 673/673 Tests gruen | 2026-09-09 | efaabc9 | [260909-dgj-mandantentrennung-auf-alle-tabellen-mit-](./quick/260909-dgj-mandantentrennung-auf-alle-tabellen-mit-/) |
## Deferred Items
@@ -407,7 +408,7 @@ sind. Kein Anlass, sie vorher erneut vorzulegen.
## Session Continuity
Last session: 2026-09-09T07:38:54.774Z
Stopped at: Quick Task 260909-cx0 abgeschlossen: user-files-Volume ergaenzt (WINDOWS #17 bleibt offen bis Server-Uebernahme), CLAUDE.md-Technik-Block auf installierten Stand korrigiert
Last session: 2026-09-09T10:10:00.000Z
Stopped at: Alles Beauftragte erledigt. Offen im Ledger: #17 (der User traegt die Volume-Zeile in /opt/tessera/docker-compose.yml nach), #18 (Mandantentrennung scharf schalten — braucht die 182 unskalierten Zugriffe, eigener Vorgang) und #19 (nullable tenantId, zusammen mit #18 zu loesen). Zurueckgestellt bleiben #12, Abnahmeplan 02-05, Mandanten-Branding und die Lizenzpruefung.
Resume file: None
Last activity: 2026-09-09 - Ledger geschlossen, Mandanten-Branding zurueckgestellt
Last activity: 2026-09-09 - Dateisicherung, Versionsangaben und Vorbereitung der Mandantentrennung