feat(quick-260910-exd): ModuleRegistryService binden, Klassifikation abschliessen
- module-registry.service.ts: findActiveForTenant, activateForTenant, isModuleActive binden je einen Aktivierungszugriff, deactivateForTenant bindet beide (Lesen+Schreiben) ueber EINEN Klienten unter tenantPrisma; alle sechs Katalogzugriffe (findAll/findBySlug/beide Existenzpruefungen/isModuleActive-Katalogsuche/seedModule) bleiben bewusst ungebunden, mit Kommentar der Messung von Bedingung trennt - isModuleActive-Kopfkommentar richtiggestellt: der Waechter ruft sie nicht auf (0 Aufrufer, TEIL 3 von Aufgabe 1) — Waechter nimmt findBySlug + ModuleAccessService.getAccessibleModuleIds - module-registry.service.spec.ts: NEU, Zwei-Klienten-Nachweis, deckt die bislang ungetestete Datei mit elf der siebzehn Zugriffe des Bereichs ab, inkl. der lauten (deactivate ohne Aktivierung) und stillen (isModuleActive ohne Aktivierung) Richtung und dem Katalog-Wachhund - tender-scheduler.service.spec.ts: forTenant() auf Identitaet gemockt (dieselbe Konvention wie ldap.service.spec.ts) — cross-area Bruch durch die Umstellung von activateForTenant behoben (Rule 1/3) - docs/mandantentrennung-zugriffsklassifikation.md: alle fuenf handgepflegten Stellen nachgezogen (Bestandsaufnahme, Uebersichtszeile 7/10, Summenzeile 108/134, Klassen-Verteilung unveraendert bei 63 Paaren, Hintergrunddienst-Abschnitt haelt die Abwesenheit eines sechsten Falls fest) — alle gemessen, nicht abgeschrieben, Befund K haelt exakt - docs/mandantentrennung-etappe2-fehlerrichtung.md: Nachtrag mit tatsaechlich umgesetzten Pfaden, beiden Falsifizierungsnachweisen (Testname+Meldung), und der Feststellung zum unveraenderten Controller-Kommentar - .planning/WINDOWS.md: neuer offener Eintrag #23 (deviation) — kein Signal unterscheidet "keine Freigabe" von "Abfrage fand nichts", mit Vorabpruefung fuer Etappe 4 und begruendeter Verwerfung einer Laufzeitwarnung - 833 Tests gruen (56 Dateien), Typpruefung sauber, Wegwerf-Werkzeug 66/66 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AMASaSxv5QMY7RncqZriRR
This commit is contained in:
+16
-3
@@ -1,10 +1,10 @@
|
||||
---
|
||||
schema_version: 1
|
||||
open_count: 5
|
||||
open_count: 6
|
||||
waived_count: 1
|
||||
fixed_count: 16
|
||||
total_count: 22
|
||||
last_updated: 2026-09-10T08:17:20.009Z
|
||||
total_count: 23
|
||||
last_updated: 2026-09-10T09:28:45.310Z
|
||||
---
|
||||
|
||||
# Broken Windows Ledger
|
||||
@@ -37,6 +37,7 @@ last_updated: 2026-09-10T08:17:20.009Z
|
||||
| 20 | 2 | unmet-truth | apps/api/src/prisma/prisma-tenant.extension.ts | | forTenant() setzt den Mandantenkontext auf einer anderen Verbindung als die Abfrage laeuft — die Mandantentrennung hat damit nie funktioniert, auch nicht dort, wo sie scheinbar benutzt wird. Die Erweiterung oeffnet prisma.$transaction, setzt app.current_tenant per set_config(..., true) auf tx, ruft dann aber query(args) auf, das ueber den AEUSSEREN Client dispatcht. set_config mit local=true gilt nur in der Transaktion und nur auf deren Verbindung. Am 2026-09-09 gegen die lokale Datenbank reproduziert: set_config landete auf Backend-PID 254999, die eigentliche Abfrage auf 255000, und dort war current_setting('app.current_tenant') NULL. Heute ohne sichtbare Folge, weil die Anwendungsrolle BYPASSRLS hat (#18) und deshalb ohnehin alles sieht. NACH dem Scharfschalten kehrt sich das um: die betroffenen Abfragen liefern dann NULL ZEILEN statt zu vieler. Besonders gefaehrlich in ldap.service.ts (Loeschzweig um Zeile 1559): der Sync deutet die Leere als 'Gruppe im Verzeichnis verschwunden' und loescht sie samt Mitgliedschaften und Modulfreigaben — aus einem stillen Trennungsfehler wuerde stiller Datenverlust. Zusatzbefund: von den 36 vermeintlichen forTenant-Vorkommen sind die meisten Kommentare, die erklaeren, warum forTenant FEHLT; echte Aufrufstellen sind 6, echte mandantengebundene Abfragen 9, alle in ldap.service.ts. Ausserdem setzen tenant.middleware.ts:44 und tenant.guard.ts:41 ein req.tenantPrisma, das in apps/api/src von NIEMANDEM gelesen wird. Muss vor jedem weiteren Umbau repariert werden, sonst baut alles Weitere auf einem Helfer auf, der nicht traegt. NACHTRAG (260909-eor, Aufgabe 1/4): der beschriebene Verbindungsfehler ist behoben (Array-Form von $transaction, prisma-tenant.extension.ts) und gegen eine Wegwerf-Datenbank mit einer Rolle ohne BYPASSRLS live nachgewiesen (rls-scratch-check.mjs, 8/8 Pruefungen bestanden). Bleibt dennoch bewusst OPEN, nicht fixed: die Wirkung unter der echten Anwendungsrolle tessera_app ist erst nach dem Scharfschalten (#18) beobachtbar — bis dahin bleibt #20 an dieselbe Bedingung gebunden wie #18 und #19. | open | | 2026-09-09T08:44:18.496Z | |
|
||||
| 21 | 2 | deviation | apps/api/src/dkv/dkv-scheduler.service.ts | | DKV-Planer-Startpfad (DkvSchedulerService.onModuleInit -> DkvService.loadAnyActiveConfigForScheduler, vormals loadConfig() ohne Mandant) bleibt bewusst UNGEBUNDEN, als benannte Altlast aus 07-04 (260909-mir, Befund D). Zwei Zustaende, beide gehoeren genannt: HEUTE bereits falsch -- findFirst() ohne jede Bedingung zieht bei mehreren Mandanten EINEN beliebigen und bedient die uebrigen NIE (isActive-Pruefung kann den Planer sogar ganz leer laufen lassen, wenn ausgerechnet die gezogene Zeile inaktiv ist, obwohl ein zweiter Mandant aktiv waere). NACH DEM SCHARFSCHALTEN (#18) verstummt sie zusaetzlich -- dieselbe Abfrage liefert dann null, der Planer protokolliert 'no active config found' und richtet fuer JEDEN Mandanten nichts ein, ohne Alarm. Drei erwogene Formen prufen: (a) an einen konkret aufgeloesten Mandanten binden -- nicht moeglich, onModuleInit() hat beim Boot strukturell keinen Mandantenkontext. (b) Umbau auf einmal-abfragen-viele-bedienen -- abgelehnt, das ist die in 07-04 zurueckgestellte Mehrmandanten-Planung (neue Auftragsverwaltung je Mandant statt des heutigen setInterval() mit GENAU EINEM Auftrag) und damit eine Funktionsaenderung, kein Bindungsumbau. (c) Als benannte Altlast weiterfuehren, mit Markierung -- GEWAEHLT, Praezedenzfall LdapConfigService.getAllActiveConfigs() (260909-ipc, Befund B). Die Unsymmetrie zu diesem Praezedenzfall: getAllActiveConfigs ist HEUTE korrekt und verstummt erst spaeter: der DKV-Planer ist HEUTE bereits falsch UND verstummt zusaetzlich spaeter. Markierung dreifach: eigene benannte Methode loadAnyActiveConfigForScheduler() mit Kopfkommentar (dkv.service.ts), fortgeschriebener Kopfkommentar in dkv-scheduler.service.ts, Abschnitt (d4) in docs/mandantentrennung-etappe2-fehlerrichtung.md. Signal fuer das Verstummen gehoert in die Vorabpruefung von Etappe 4 (rls-preflight.mjs), NICHT in diesen Durchlauf. | open | | 2026-09-09T14:41:07.256Z | |
|
||||
| 22 | quick-260910-das | deviation | apps/api/src/user/user.service.ts | | Plattformweite Eindeutigkeit von username/email (kein tenantId-Anteil im Unique-Index): die gemessene Kette unsichtbare Zeile -> falsches 'frei' -> harter Eindeutigkeitsfehler (SQLSTATE 23505) ist in dieser Etappe im Anwendungscode entschaerft (Konfliktmeldung bei create/update, Startsperre in admin-seed.service.ts abgefangen), nicht an der Ursache geloest. Die ehrliche Reparatur waere eine Schemaaenderung (Eindeutigkeit mit Mandantendimension) und ist als Produktentscheidung fuer Etappe 3 vorgemerkt. Siehe docs/mandantentrennung-etappe2-fehlerrichtung.md, Abschnitt 'Bereich user' (u1/u4). | open | | 2026-09-10T08:17:20.009Z | |
|
||||
| 23 | quick-260910-exd | deviation | apps/api/src/module-registry/module-access.service.ts | | Es gibt heute KEIN Signal, das 'wirklich keine Freigabe' (USER hat tatsaechlich keinen Grant) von 'die Abfrage hat nichts gefunden' (z. B. eine nach dem Scharfschalten ungebunden gebliebene Abfrage) unterscheidet: dieselbe ForbiddenException-Meldung im Waechter, dieselbe leere Modulliste mit Status 200, kein Protokolleintrag. Nach dem Scharfschalten ist ein zu kleines Ergebnis in diesem Bereich TOTAL und lautlos -- JEDER Benutzer JEDES Mandanten verliert gleichzeitig jedes Modul, waehrend die Aktivierungs- und Freigabetabellen weiterhin Zeilen halten -- und sieht fuer den Betroffenen wie ein absichtlicher Rechteentzug aus, nicht wie ein Fehler (der Betroffene hat eine fertige, falsche Erklaerung zur Hand und meldet deshalb keinen Fehler). Konkrete Vorabpruefung fuer Etappe 4 (rls-preflight.mjs): aktive Aktivierungszeilen vorhanden, aber die Aufloesung liefert fuer einen bekannten Administrator eine leere Menge. Eine Laufzeitwarnung an den betroffenen Stellen wurde erwogen und begruendet verworfen (Dauerlaerm auf einer frischen Installation, dieselbe Begruendung wie bei getAllActiveConfigs im Bereich ldap und den fuenf Stellen im Bereich tenders). In module.guard.spec.ts als Testfall festgenagelt, damit die Aufzeichnung rot wird, sobald jemand ein unterscheidendes Signal einbaut. Siehe docs/mandantentrennung-etappe2-fehlerrichtung.md, Abschnitt 'Bereich module-registry' (m3). | open | | 2026-09-10T09:28:45.310Z | |
|
||||
|
||||
````json
|
||||
[
|
||||
@@ -303,6 +304,18 @@ last_updated: 2026-09-10T08:17:20.009Z
|
||||
"reason": "",
|
||||
"recorded_at": "2026-09-10T08:17:20.009Z",
|
||||
"resolved_at": null
|
||||
},
|
||||
{
|
||||
"id": 23,
|
||||
"kind": "deviation",
|
||||
"phase": "quick-260910-exd",
|
||||
"file": "apps/api/src/module-registry/module-access.service.ts",
|
||||
"line": null,
|
||||
"description": "Es gibt heute KEIN Signal, das 'wirklich keine Freigabe' (USER hat tatsaechlich keinen Grant) von 'die Abfrage hat nichts gefunden' (z. B. eine nach dem Scharfschalten ungebunden gebliebene Abfrage) unterscheidet: dieselbe ForbiddenException-Meldung im Waechter, dieselbe leere Modulliste mit Status 200, kein Protokolleintrag. Nach dem Scharfschalten ist ein zu kleines Ergebnis in diesem Bereich TOTAL und lautlos -- JEDER Benutzer JEDES Mandanten verliert gleichzeitig jedes Modul, waehrend die Aktivierungs- und Freigabetabellen weiterhin Zeilen halten -- und sieht fuer den Betroffenen wie ein absichtlicher Rechteentzug aus, nicht wie ein Fehler (der Betroffene hat eine fertige, falsche Erklaerung zur Hand und meldet deshalb keinen Fehler). Konkrete Vorabpruefung fuer Etappe 4 (rls-preflight.mjs): aktive Aktivierungszeilen vorhanden, aber die Aufloesung liefert fuer einen bekannten Administrator eine leere Menge. Eine Laufzeitwarnung an den betroffenen Stellen wurde erwogen und begruendet verworfen (Dauerlaerm auf einer frischen Installation, dieselbe Begruendung wie bei getAllActiveConfigs im Bereich ldap und den fuenf Stellen im Bereich tenders). In module.guard.spec.ts als Testfall festgenagelt, damit die Aufzeichnung rot wird, sobald jemand ein unterscheidendes Signal einbaut. Siehe docs/mandantentrennung-etappe2-fehlerrichtung.md, Abschnitt 'Bereich module-registry' (m3).",
|
||||
"status": "open",
|
||||
"reason": "",
|
||||
"recorded_at": "2026-09-10T09:28:45.310Z",
|
||||
"resolved_at": null
|
||||
}
|
||||
]
|
||||
````
|
||||
|
||||
Reference in New Issue
Block a user