feat(quick-260910-das): Steuerungsschicht binden, Selbstloesch-Riegel schliessen
- user.controller.ts: alle sieben Zugriffe binden. ADMIN-Zweig der Benutzerliste laeuft ueber forTenant() mit weiterhin bestehender Mandantenbedingung im where; SUPER_ADMIN-Zweig ueber die neue UserService.findAllForPlatformAdmin(). Die drei Wege ueber die Kennung loesen den Zielbenutzer rollenabhaengig ueber resolveTargetUser() auf (ADMIN gebunden an eigenen Mandanten, SUPER_ADMIN uebergreifend); der Schreibzugriff bei update/delete bindet an den Mandanten des Zielbenutzers, nicht des Aufrufers, damit die uebergreifende Verwaltung durch die oberste Rolle erhalten bleibt - Selbstloesch-Riegel (Befund H) repariert: verglich bisher gegen currentUser.sub, ein Feld, das der Sitzungsnachweis nicht traegt -- der Riegel griff nie. Jetzt gegen currentUser.id. Verhaltensaenderung: ein Administrator kann sein eigenes Konto nun nicht mehr loeschen - Alle fuenf Selbstbedienungszugriffe (Bild hochladen/loeschen/ ausliefern, Akzentfarbe) binden an die Mandantenkennung aus dem Sitzungsnachweis - user.controller.spec.ts (neu): Zwei-Klienten-Nachweis fuer die vorher testlose Steuerungsschicht, 8 Testfaelle, Falsifizierungsnachweis fuer eine gebundene Stelle sowie Rot-vor-Reparatur-Nachweis fuer den Selbstloesch-Riegel (siehe SUMMARY) - docs/mandantentrennung-zugriffsklassifikation.md: alle vier handgepflegten Stellen nachgezogen (Uebersichtszeile 8/14, Summenzeile 118/124, Klassen-Verteilung 63 Paare, Hintergrunddienst-Abschnitt auf fuenf Faelle inkl. admin-seed.service.ts als erster beidseitig korrekter Fall) sowie zwei Klassenkorrekturen (user.service.ts/user und admin-seed.service.ts/user je auf "beides") - docs/mandantentrennung-etappe2-fehlerrichtung.md: Nachtrag zum user-Abschnitt mit den tatsaechlich umgesetzten Pfaden, der geschlossenen Luecke und den Falsifizierungsnachweisen - 810 Tests gruen (8 neue in user.controller.spec.ts), Typpruefung sauber, Wegwerf-Werkzeug meldet weiterhin alle 53 Pruefungen bestanden Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AMASaSxv5QMY7RncqZriRR
This commit is contained in:
@@ -1182,6 +1182,72 @@ entscheidet sie nicht. Er bindet dienst-intern, wie `ldap`, `groups`,
|
||||
Jeweils mit der Feststellung, dass sie geprüft und bewusst gelassen sind —
|
||||
nicht übersehen.
|
||||
|
||||
**Nachtrag (260910-das, 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 angekündigten gehalten:* alle in (u2)
|
||||
genannten Pfade sind wie beschrieben umgestellt. `UserService.findById`,
|
||||
`create`, `update`, `deactivate`, `delete` laufen über `forTenant()`;
|
||||
`create`/`update` übersetzen die plattformweite Eindeutigkeitsverletzung in
|
||||
eine deutsche Konfliktmeldung, die weder Halter noch Mandant nennt.
|
||||
`AdminSeedService.seedAdmin()` bindet die Erstanlage des Administrators an
|
||||
den unmittelbar zuvor angelegten Mandanten und entschärft die Startsperre
|
||||
(P2002 wird wie „Administrator existiert bereits" behandelt, jeder andere
|
||||
Fehler bricht weiterhin ab). `UserController` bindet alle sieben eigenen
|
||||
Zugriffe (ADMIN-Zweig der Benutzerliste, alle fünf Selbstbedienungswege) und
|
||||
löst die drei Wege über die Kennung rollenabhängig auf. `findByUsername`
|
||||
bleibt wie angekündigt ungebunden, mit richtiggestelltem Kopfkommentar.
|
||||
|
||||
*Die geschlossene Lücke im Selbstlösch-Riegel (Befund H):* der Vergleich
|
||||
`user.id === currentUser.sub` griff nie, weil der Sitzungsnachweis kein Feld
|
||||
`sub` trägt (`JwtStrategy.validate()` liefert exakt `{ id, username, role,
|
||||
tenantId }`). Der Nachweis kommt aus der Reihenfolge selbst, nicht aus einer
|
||||
Behauptung: `user.controller.spec.ts`, Test 6, wurde zuerst gegen die alte
|
||||
Fassung ausgeführt — die Zeile `if (user.id === currentUser.sub)` wurde
|
||||
probeweise wiederhergestellt, der Testlauf zeigte den erwarteten roten Test
|
||||
(„promise resolved … instead of rejecting"), danach wurde auf
|
||||
`currentUser.id` repariert und derselbe Testlauf grün. Die Wirkung ist eine
|
||||
Verhaltensänderung: ein Administrator kann sein eigenes Konto seither nicht
|
||||
mehr löschen — das ist die ursprüngliche, im Code bereits formulierte
|
||||
Absicht, nicht neu erfunden.
|
||||
|
||||
*Die gewählte Form der Plattform-Administratorsicht, samt Beleg aus der
|
||||
Messung:* wie in (u3)/Befund F angekündigt, laufen
|
||||
`UserService.findAllForPlatformAdmin()` und `findByIdForPlatformAdmin()` als
|
||||
Schleife über alle Mandanten (`this.prisma.tenant.findMany`, ungebunden, weil
|
||||
`Tenant` keinen Zeilenschutz trägt) mit je EINEM gebundenen Lesezugriff im
|
||||
Rumpf — dieselbe Form wie `AdminSeedService.ensureDefaultGroupsForAllTenants()`.
|
||||
Der Beleg, dass diese Form die heutige Sicht erhält statt sie zu mindern,
|
||||
kommt aus Aufgabe 1: `user-fan-out-je-mandant-gebunden-liefert-alle-zeilen`
|
||||
maß die Vereinigung der je-Mandant gebundenen `SELECT`s gegen eine über die
|
||||
Wartungsrolle (mit `BYPASSRLS`) gemessene Gesamtmenge — beide Mengen waren
|
||||
identisch (`["alice","bob","carol","dave"]`). In `user.service.spec.ts`
|
||||
bestätigen Test 6 und Test 7 dasselbe am Code: je Mandant genau EIN
|
||||
Protokolleintrag, die Sortierung nach Benutzername bleibt über die
|
||||
zusammengeführten Teilmengen hinweg korrekt, und eine Kennungsauflösung für
|
||||
einen Benutzer eines fremden Mandanten gelingt nachweislich über einen
|
||||
gebundenen Lesezugriff.
|
||||
|
||||
*Falsifizierungsnachweise (Aufgabe 2 und 3), je einmal durchgeführt und
|
||||
zurückgenommen:* in Aufgabe 2 wurde `UserService.findById` probeweise auf
|
||||
den ungebundenen Klienten zurückgebaut — genau `user.service.spec.ts`, Test
|
||||
4, wurde rot, mit der Meldung „erwarteter gebundener Aufruf
|
||||
user.findUnique(tenant=t1) fehlt im Protokoll: []"; der Rückbau wurde
|
||||
zurückgenommen, derselbe Testlauf danach wieder grün. In derselben Aufgabe
|
||||
wurde zusätzlich `AdminSeedService.seedAdmin()`s gebundener
|
||||
`tenantPrisma.user.create`-Aufruf probeweise auf den ungebundenen Basisclient
|
||||
zurückgebaut — sechs Tests wurden rot (u. a. Test 9–12), alle mit der
|
||||
Meldung „tenantPrisma.user.create is not a function", weil der ungebundene
|
||||
Basisclient in der Testattrappe keine `create`-Methode auf `user` trägt; der
|
||||
Rückbau wurde zurückgenommen, alle zehn Tests danach wieder grün. In Aufgabe
|
||||
3 wurde `UserController.uploadAvatar`s gebundener Schreibzugriff probeweise
|
||||
auf den ungebundenen Basisclient zurückgebaut — genau
|
||||
`user.controller.spec.ts`, Test 7, wurde rot, mit der Meldung „Cannot read
|
||||
properties of undefined (reading 'update')"; der Rückbau wurde
|
||||
zurückgenommen, derselbe Testlauf danach wieder grün.
|
||||
|
||||
## Verweis
|
||||
|
||||
Die Bestandsaufnahme, welche Fundstelle den hier beschriebenen Übergang
|
||||
|
||||
Reference in New Issue
Block a user