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:
@@ -1457,6 +1457,89 @@ und verlöre ihr Signal.
|
||||
- Schema und Migrationen — geprüft und bewusst gelassen, keine
|
||||
Schemaänderung in dieser Etappe.
|
||||
|
||||
**Nachtrag (260910-exd, Aufgabe 3).** Wie in den vorherigen Durchläufen wird
|
||||
der Text oben NICHT umgeschrieben — er beschreibt korrekt den Stand zum
|
||||
Zeitpunkt der Messung (Aufgabe 1); dieser Nachtrag hält fest, was Aufgabe 2/3
|
||||
tatsächlich umgesetzt haben.
|
||||
|
||||
*Tatsächlich umgesetzte Pfade gegen die in (m2) angekündigten gehalten:*
|
||||
alle in (m2) genannten Pfade sind wie beschrieben umgestellt.
|
||||
`ModuleAccessService.getAccessibleModuleIds` bindet Kurzschlusszweig,
|
||||
Direktweg, Gruppenweg und Schnittmenge über EINEN Klienten je Aufruf;
|
||||
`getCatalogFlags` bindet ihren eigenen Aktivierungs-Lesezugriff, die
|
||||
geschachtelte `getAccessibleModuleIds`-Auflösung erzeugt ihren eigenen
|
||||
Klienten; `findAccessibleModules` erreicht den Katalog weiterhin über den
|
||||
ungebundenen Klienten. `ModuleRegistryService.findActiveForTenant`,
|
||||
`activateForTenant` und `isModuleActive` binden ihren jeweiligen
|
||||
Aktivierungszugriff; `deactivateForTenant` bindet beide Aktivierungszugriffe
|
||||
(Lesen, Schreiben) über EINEN Klienten. Alle sechs Katalogzugriffe in
|
||||
`module-registry.service.ts` (`findAll`, `findBySlug`, die beiden
|
||||
Katalog-Existenzprüfungen, die Katalogsuche in `isModuleActive`,
|
||||
`seedModule`) und der eine Katalogzugriff in `module-access.service.ts`
|
||||
(`findAccessibleModules`) blieben wie angekündigt ungebunden, mit
|
||||
Kommentaren, die Messung und Bedingung trennen. Beide falschen
|
||||
Kopfkommentare aus Befund G sind behandelt: `isModuleActive`s Kommentar ist
|
||||
richtiggestellt (mit Bezug auf die Aufrufermessung aus TEIL 3); der
|
||||
irreführende Satz im Kopfkommentar von `module-registry.controller.ts`
|
||||
("findActiveForTenant on ModuleRegistryService stays unchanged for Plan
|
||||
15-03's marketplace catalog") wurde NICHT mitgeändert — der Controller ist
|
||||
nicht Teil dieses Plans. Die Feststellung, dass diese Aussage falsch ist
|
||||
(der Marktplatz-Katalog wird nachweislich von `getCatalogFlags` bedient,
|
||||
nicht von `findActiveForTenant`), steht stattdessen hier in (m5).
|
||||
|
||||
*Deviation (Rule 1/3): eine cross-area Testabhängigkeit brach durch die
|
||||
Umstellung.* `tender-scheduler.service.spec.ts` instanziiert
|
||||
`ModuleRegistryService` unmocked gegen einen hand-gerollten Fake ohne
|
||||
`$extends` (derselbe Zweck wie in `ldap.service.spec.ts`: der Aktivierungs-
|
||||
Aufruf soll echt sein, nicht ein Stand-in). Nach der Umstellung von
|
||||
`activateForTenant` auf `forTenant()` scheiterte dieser Test mit
|
||||
`prisma.$extends is not a function`. Behoben mit derselben Konvention wie
|
||||
`ldap.service.spec.ts` — `forTenant` in dieser einen Datei über `vi.mock`
|
||||
auf eine Identitätsfunktion gelegt (`forTenant: vi.fn((p) => p)`), weil die
|
||||
Datei RLS-Bindungsmechanik nicht testet, nur das Poll-once-fan-out-many-
|
||||
Verhalten des Schedulers. Kein anderer Aufrufer von `new
|
||||
ModuleRegistryService(...)` existiert im Quelltext (geprüft).
|
||||
|
||||
*Deviation (Rule 3): die Klassifikationsdokument-Stände für
|
||||
`module-access.service.ts` wurden bereits in Aufgabe 2 nachgezogen*, nicht
|
||||
erst in dieser Aufgabe — `rls-access-inventory.spec.ts` ist Teil der von
|
||||
Aufgabe 2 verlangten vollständigen Testsuite und wäre sonst am Ende von
|
||||
Aufgabe 2 bereits rot gewesen. Diese Abweichung von der Aufgabenaufteilung
|
||||
(die Klassifikationsdatei war für Aufgabe 3 vorgesehen) ist auf das
|
||||
Notwendige beschränkt: nur die `Stand`-Spalte der beiden betroffenen Zeilen,
|
||||
keine Begründung, keine Zahlen. Die vollständige Nachziehung (fünf
|
||||
Bestandsaufnahme-Zeilen inklusive `module-registry.service.ts`,
|
||||
Übersichtszeile, Summenzeile, Klassen-Verteilung, Hintergrunddienst-
|
||||
Abschnitt) erfolgte wie geplant in dieser Aufgabe.
|
||||
|
||||
*Falsifizierungsnachweise (Aufgabe 2 und 3), je einmal durchgeführt und
|
||||
zurückgenommen:* in Aufgabe 2 wurde die Gruppenweg-Bindung der
|
||||
Freigabe-Auflösung probeweise zurückgebaut (`tenantPrisma.moduleGrant` →
|
||||
`this.prisma.moduleGrant` im Gruppenweg von `getAccessibleModuleIds`) —
|
||||
genau `module-access.service.spec.ts`, Test "ModuleAccessService — Bindung
|
||||
an forTenant() (260910-exd) > USER-Zweig bindet BEIDE
|
||||
Freigabe-Lesezugriffe (Direktweg und Gruppenweg) UND den
|
||||
Schnittmengen-Lesezugriff an DIESELBE Mandantenkennung", wurde rot, mit der
|
||||
Meldung `expected 1 to be 2`; der Rückbau wurde zurückgenommen, derselbe
|
||||
Testlauf danach wieder grün (23/23). In Aufgabe 3 wurde der
|
||||
Schreibzugriff des Deaktivierens probeweise zurückgebaut
|
||||
(`tenantPrisma.tenantModuleActivation.update` →
|
||||
`this.prisma.tenantModuleActivation.update` in `deactivateForTenant`) —
|
||||
genau `module-registry.service.spec.ts`, Test
|
||||
"ModuleRegistryService.deactivateForTenant > bindet beide
|
||||
Aktivierungszugriffe (Lesen, Schreiben) an denselben Mandanten, über einen
|
||||
Klienten", wurde rot, mit der Meldung "erwarteter gebundener Aufruf
|
||||
tenantModuleActivation.update(tenant=t1) fehlt im Protokoll:
|
||||
[{"tenantId":"t1","model":"tenantModuleActivation","method":"findUnique"}]:
|
||||
expected false to be true"; der Rückbau wurde zurückgenommen, derselbe
|
||||
Testlauf danach wieder grün (16/16).
|
||||
|
||||
*Die offene WINDOWS-Aufzeichnung.* Eintrag #23 (`deviation`) hält fest, dass
|
||||
es kein Signal gibt, das "wirklich keine Freigabe" von "die Abfrage hat
|
||||
nichts gefunden" unterscheidet, mit der Vorabprüfung für Etappe 4 und der
|
||||
begründeten Verwerfung einer Laufzeitwarnung — siehe (m3) oben und
|
||||
`.planning/WINDOWS.md`.
|
||||
|
||||
## Verweis
|
||||
|
||||
Die Bestandsaufnahme, welche Fundstelle den hier beschriebenen Übergang
|
||||
|
||||
@@ -101,14 +101,14 @@ autoritative Quelle.
|
||||
| ldap | 4 | 26 | **war 21/0** — Aufgabe 2/3 (260909-ipc) haben `ldap-config.service.ts` (5 Methoden) und `ldap.service.ts` (6 Methoden, 11 Abfragen) auf `forTenant()` umgestellt. Die 4 verbleibenden ungebundenen Treffer sind bewusst: `getAllActiveConfigs`/`onApplicationBootstrap` (Befund B) und `resolveEmailForWrite` (Befund A, T-IPC-04) |
|
||||
| dkv | 1 | 22 | **war 21/0** — Aufgabe 2/3 (260909-mir) haben `dkv.service.ts` vollständig auf `forTenant()` umgestellt: Konfigurationspfade (`loadConfig`, `getConfigForApi`, `saveConfig`, `testConnection`), Historie, Fahrzeugstammdaten und der neue Besitzriegel vor dem Ausfuhrdatei-Download. Gebunden sind es 22 statt 21, weil der Riegel einen zusätzlichen Lesezugriff auf `dkvInvoiceHistory` einführt (T-MIR-03). Der eine verbleibende ungebundene Treffer ist der benannte Planer-Startpfad `loadAnyActiveConfigForScheduler()` (Befund D, WINDOWS #21) — bewusst, mit dreifacher Markierung |
|
||||
| user | 8 | 14 | **war 17/0** — Aufgabe 2/3 (260910-das) haben `user.service.ts` (`findById`/`create`/`update`/`deactivate`/`delete` sowie die zwei neuen Plattform-Administratorsicht-Methoden), `admin-seed.service.ts` (Erstanlage des Administrators) und `user.controller.ts` (Benutzerliste des ADMIN-Zweigs, alle drei Kennungswege ueber die Dienstmethoden, alle fuenf Selbstbedienungszugriffe) auf `forTenant()` umgestellt. Die 8 verbleibenden ungebundenen Rohtreffer sind bewusst: `findByUsername` in `user.service.ts` (plattformweit eindeutiger Schluessel, derselbe Fall wie `resolveEmailForWrite` im Bereich `ldap`), die Erstanlage-Pruefung und beide Zugriffe auf `tenant` in `admin-seed.service.ts`, sowie der neue Schleifentreiber `this.prisma.tenant.findMany` der beiden Plattform-Administratorsicht-Methoden in `user.service.ts` (`Tenant` traegt keinen Zeilenschutz) |
|
||||
| module-registry | 17 | 0 | unverändert |
|
||||
| module-registry | 7 | 10 | **war 17/0** — Aufgabe 2/3 (260910-exd) haben `module-access.service.ts` (`getAccessibleModuleIds`: Kurzschlusszweig, Direktweg, Gruppenweg, Schnittmenge; `getCatalogFlags`: eigener Aktivierungs-Lesezugriff) und `module-registry.service.ts` (`findActiveForTenant`, `activateForTenant`, `deactivateForTenant`, `isModuleActive`) auf `forTenant()` umgestellt. Die 7 verbleibenden ungebundenen Rohtreffer sind bewusst: der eine Katalogzugriff in `module-access.service.ts` (`findAccessibleModules`) und die sechs Katalogzugriffe in `module-registry.service.ts` (`findAll`, `findBySlug`, die beiden Katalog-Existenzpruefungen in `activateForTenant`/`deactivateForTenant`, die Katalogsuche in `isModuleActive`, `seedModule`) — der Modulkatalog (`Module`) traegt heute keinen Zeilenschutz, eine Bindung waere heute wirkungslos, nicht katastrophal; katastrophal wuerde sie erst, WENN Etappe 3 dieser Tabelle eine Regel gibt (Befund E) |
|
||||
| dashboard | 13 | 0 | unverändert |
|
||||
| auth | 8 | 5 | unverändert gegenüber dem in Etappe 1 (260909-eor) gemessenen Stand |
|
||||
| calendar | 12 | 0 | unverändert |
|
||||
| tenant | 8 | 0 | unverändert |
|
||||
| favorites | 7 | 0 | unverändert |
|
||||
| settings | 4 | 0 | unverändert |
|
||||
| **Summe** | **118** | **124** | Ungebunden: war 127 nach 260909-mir, Delta = die 9 in Aufgabe 2/3 (260910-das) gesunkenen `user`-Rohtreffer (17→8). Gebunden: war 110, jetzt zusätzlich 14 in `user`. Diese Übersicht ist eine Buchführungshilfe; **autoritativ ist die Fundstellentabelle unten**, die `rls-access-inventory.spec.ts` bei jedem Lauf gegen den Quelltext prüft |
|
||||
| **Summe** | **108** | **134** | Ungebunden: war 118 nach 260910-das, Delta = die 10 in Aufgabe 2/3 (260910-exd) gesunkenen `module-registry`-Rohtreffer (17→7). Gebunden: war 124, jetzt zusätzlich 10 in `module-registry`. Diese Übersicht ist eine Buchführungshilfe; **autoritativ ist die Fundstellentabelle unten**, die `rls-access-inventory.spec.ts` bei jedem Lauf gegen den Quelltext prüft |
|
||||
|
||||
## Klassen-Verteilung (nach (Datei, Modell)-Fundstellen, 63 Paare)
|
||||
|
||||
@@ -251,6 +251,16 @@ Verzweigung hinter einem optionalen Parameter, die jemand später
|
||||
`dkv-scheduler.service.ts`, Ledger-Eintrag WINDOWS #21. Das Signal für das
|
||||
Verstummen gehört in die Vorabprüfung von Etappe 4 (`rls-preflight.mjs`).
|
||||
|
||||
**Stand 260910-exd — kein sechster Fall, gemessen statt angenommen.** Der
|
||||
Bereich `module-registry` fügt diesem Abschnitt KEINEN sechsten Fall hinzu.
|
||||
`ModuleRegistryService.seedModule()` (die Katalogpflege beim Start,
|
||||
aufgerufen aus vier Seed-Dateien) schreibt zwar ohne Mandantenkontext — sie
|
||||
iteriert aber über NICHTS je Mandant, sondern schreibt genau eine Zeile je
|
||||
Aufruf auf den plattformweiten Katalog `Module`. Damit fehlt ihr die Bauform
|
||||
der fünf oben geführten Fälle (übergreifend LESEN über alle Mandanten, dann
|
||||
je Mandant BINDEN) — sie ist deshalb kein Kandidat für diese Liste. Dieser
|
||||
Satz hält die Abwesenheit fest, damit sie nicht wie ein Übersehen aussieht.
|
||||
|
||||
## Bestandsaufnahme
|
||||
|
||||
Maschinell ermittelt, `rls-access-inventory.spec.ts` hält Vollständigkeit
|
||||
@@ -288,11 +298,11 @@ verwendet), Klasse, Stand (`gebunden`/`ungebunden`/`gemischt`, seit
|
||||
| apps/api/src/ldap/ldap.service.ts | groupMembership | muss-mandantengebunden | gebunden | Kein eigenes `tenantId`, RLS ueber Join auf `Group`. `syncGroupMembershipsForTenant` laeuft vollstaendig ueber `forTenant()` (Plan 16-03/16-05) — von der alten, nur `this.prisma.*` erkennenden Suche nie erfasst, weil bereits gebunden; die erweiterte Erkennung aus Aufgabe 2 (260909-ipc) macht diese Fundstelle erstmals sichtbar. |
|
||||
| apps/api/src/ldap/ldap.service.ts | ldapConfig | beides | gebunden | Die `lastSyncAt`-Fortschreibung am Ende von `syncUsersForTenant` ist mit Aufgabe 3 (260909-ipc) auf den in derselben Methode bereits vorhandenen `forTenant()`-Client umgestellt — es entsteht kein zweiter. Damit ist der einzige `ldapConfig`-Zugriff dieser Datei gebunden. |
|
||||
| apps/api/src/ldap/ldap.service.ts | user | beides | gemischt | Mit Aufgabe 3 (260909-ipc) sind `upsertMappedUser` (Identitaetssuche und Aktualisierung), `searchUsers` (die "bereits importiert"-Markierung), `importUsersByDn` (Dedup und ldapDn-Nachtrag) und die Deaktivierungsschleife in `syncUsersForTenant` auf `forTenant()` umgestellt. `resolveEmailForWrite` bleibt ausdruecklich UNGEBUNDEN (Befund A, T-IPC-04): `email`/`username` sind plattformweit eindeutig, eine mandantengebundene Suche saehe einen fremden Halter nicht mehr und meldete faelschlich "frei" — die geloeste Klasse waere `muss-mandantengebunden` gewesen, bleibt wegen dieser einen bewusst uebergreifenden Abfrage `beides`. Der Loeschzweig um `syncBoundGroupsForTenant` (WINDOWS #20) ist bereits seit Etappe 1 gebunden und war nie Teil dieses Befunds. |
|
||||
| apps/api/src/module-registry/module-access.service.ts | module | keine-mandantengebundene-tabelle | ungebunden | Modulkatalog ist plattformweit, kein `tenantId`. |
|
||||
| apps/api/src/module-registry/module-access.service.ts | module | keine-mandantengebundene-tabelle | ungebunden | Modulkatalog ist plattformweit, kein `tenantId`. Bleibt bewusst ungebunden (260910-exd, Aufgabe 1, Befund E): keine Regel auf der Tabelle, eine Bindung waere heute wirkungslos, nicht katastrophal — katastrophal erst, WENN Etappe 3 dieser Tabelle eine Regel gibt. |
|
||||
| apps/api/src/module-registry/module-access.service.ts | moduleGrant | muss-mandantengebunden | gebunden | Modulfreigaben je Mandant. Seit 260910-exd (Aufgabe 2) laufen Direktweg und Gruppenweg von `getAccessibleModuleIds` ueber `forTenant()`, EIN Klient je Methode. |
|
||||
| apps/api/src/module-registry/module-access.service.ts | tenantModuleActivation | muss-mandantengebunden | gebunden | Aktivierung je Mandant, `tenantId`-Spalte vorhanden. Seit 260910-exd (Aufgabe 2) laufen Kurzschlusszweig, Schnittmengenabfrage und der eigene Lesezugriff von `getCatalogFlags` ueber `forTenant()`. |
|
||||
| apps/api/src/module-registry/module-registry.service.ts | module | keine-mandantengebundene-tabelle | ungebunden | Modulkatalog ist plattformweit. |
|
||||
| apps/api/src/module-registry/module-registry.service.ts | tenantModuleActivation | muss-mandantengebunden | ungebunden | Aktivierung je Mandant. |
|
||||
| apps/api/src/module-registry/module-registry.service.ts | module | keine-mandantengebundene-tabelle | ungebunden | Modulkatalog ist plattformweit. Bleibt bewusst ungebunden (260910-exd, Aufgabe 1, Befund E): keine Regel auf der Tabelle, eine Bindung waere heute wirkungslos, nicht katastrophal — katastrophal erst, WENN Etappe 3 dieser Tabelle eine Regel gibt. `findBySlug` ist zusaetzlich die Stelle, die `ModuleGuard` bei JEDER Modulanfrage aufruft. |
|
||||
| apps/api/src/module-registry/module-registry.service.ts | tenantModuleActivation | muss-mandantengebunden | gebunden | Aktivierung je Mandant. Seit 260910-exd (Aufgabe 3) laufen `findActiveForTenant`, `activateForTenant`, beide Zugriffe von `deactivateForTenant` (ueber EINEN Klienten) und `isModuleActive` ueber `forTenant()`, je Methode EIN Klient. |
|
||||
| apps/api/src/settings/settings.service.ts | smtpConfig | muss-mandantengebunden | ungebunden | SMTP-Zugangsdaten je Mandant, `tenantId`-Spalte vorhanden. |
|
||||
| apps/api/src/tenant/tenant.controller.ts | tenant | keine-mandantengebundene-tabelle | ungebunden | `Tenant` ist die Mandantentabelle selbst — hat keine eigene `tenantId`-Spalte, kann sie per Definition nicht haben (Migration 20260909140000, Gruppe b). |
|
||||
| apps/api/src/tenant/tenant.service.ts | tenant | keine-mandantengebundene-tabelle | ungebunden | Dieselbe Begründung. |
|
||||
|
||||
Reference in New Issue
Block a user