feat(quick-260910-das): user-Dienst binden, Linie ziehen, Startsperre entschaerfen

- user.service.ts: findById/update/deactivate/delete bekommen einen
  Pflicht-Mandanten und laufen ueber forTenant(); create/update
  uebersetzen die plattformweite Eindeutigkeitsverletzung (P2002) in eine
  deutsche Konfliktmeldung ohne Halter/Mandant zu nennen; zwei neue
  Methoden (findAllForPlatformAdmin, findByIdForPlatformAdmin) bilden die
  Plattform-Administratorsicht als Schleife ueber alle Mandanten mit je
  einem gebundenen Lesezugriff nach; findByUsername bleibt bewusst
  ungebunden, Kopfkommentar richtiggestellt (Anmeldeweg laeuft seit
  Etappe 1 ueber SECURITY-DEFINER-Funktionen, kein Aufrufer mehr)
- admin-seed.service.ts: Erstanlage-Pruefung bleibt ungebunden (mit
  Begruendung), Erstanlage des Administrators bindet an den unmittelbar
  zuvor angelegten Mandanten (Befund J-Korrektur); P2002 bei der Anlage
  wird wie "Administrator existiert bereits" behandelt statt den Start
  abzubrechen -- jeder andere Fehler bricht weiterhin ab
- user.controller.ts: die vier Aufrufstellen der geaenderten Signaturen
  auf currentUser.tenantId umgestellt (Signatur-Minimalanpassung; die
  Rollenlogik inkl. Plattform-Administratorsicht folgt in Aufgabe 3)
- Zwei-Klienten-Nachweis in beiden Testdateien (Muster
  groups.service.spec.ts), Falsifizierungsnachweis fuer beide Bereiche
  durchgefuehrt und zurueckgenommen (siehe SUMMARY)
- docs/mandantentrennung-zugriffsklassifikation.md: Zwischenstand fuer
  (user.service.ts, user) und (admin-seed.service.ts, user) auf gemischt
  korrigiert, neue Zeile (user.service.ts, tenant) ergaenzt -- volle
  Klassenkorrektur mit Begruendung sowie die vier handgepflegten
  Uebersichtstabellen folgen in Aufgabe 3
- .planning/WINDOWS.md: offener Eintrag fuer die plattformweite
  Eindeutigkeit von username/email (Produktentscheidung fuer Etappe 3)
- 802 Tests gruen (13 neue in user.service.spec.ts, 4 neue in
  admin-seed.service.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:
2026-09-10 10:27:14 +02:00
parent b848ba6baa
commit 888f66003c
7 changed files with 714 additions and 118 deletions
+13 -5
View File
@@ -97,7 +97,13 @@ export class UserController {
@Get(':id')
@Roles(Role.ADMIN, Role.SUPER_ADMIN)
async findOne(@Param('id') id: string, @CurrentUser() currentUser: any) {
const user = await this.userService.findById(id);
// 260910-das, Aufgabe 2: UserService.findById() bekommt einen
// Pflicht-Mandanten (siehe user.service.ts). Nur die Signatur wird hier
// nachgezogen, damit die Typpruefung sauber bleibt -- die Rollenlogik
// (insbesondere die uebergreifende SUPER_ADMIN-Sicht ueber
// findByIdForPlatformAdmin()) wird erst in Aufgabe 3 vollstaendig
// verdrahtet.
const user = await this.userService.findById(currentUser.tenantId, id);
if (!user) {
throw new NotFoundException('User not found');
}
@@ -156,7 +162,8 @@ export class UserController {
@Body() dto: UpdateUserDto,
@CurrentUser() currentUser: any,
) {
const user = await this.userService.findById(id);
// 260910-das, Aufgabe 2: siehe Kommentar in findOne() oben.
const user = await this.userService.findById(currentUser.tenantId, id);
if (!user) {
throw new NotFoundException('User not found');
}
@@ -174,7 +181,7 @@ export class UserController {
throw new ForbiddenException('Cannot assign SUPER_ADMIN role');
}
const updated = await this.userService.update(id, {
const updated = await this.userService.update(currentUser.tenantId, id, {
username: dto.username,
email: dto.email,
password: dto.password,
@@ -194,7 +201,8 @@ export class UserController {
@Delete(':id')
@Roles(Role.ADMIN, Role.SUPER_ADMIN)
async remove(@Param('id') id: string, @CurrentUser() currentUser: any) {
const user = await this.userService.findById(id);
// 260910-das, Aufgabe 2: siehe Kommentar in findOne() oben.
const user = await this.userService.findById(currentUser.tenantId, id);
if (!user) {
throw new NotFoundException('User not found');
}
@@ -212,7 +220,7 @@ export class UserController {
throw new ForbiddenException('Cannot delete users from other tenants');
}
await this.userService.delete(id);
await this.userService.delete(currentUser.tenantId, id);
return { message: 'User deleted' };
}