docs(quick-260914-ebg): WINDOWS #29 abgeschlossen und verifiziert 6/6 — Zusammenfassung, Verifikation, Aktenstand
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018N9CD3ebPKm1b32bPpBknY
This commit is contained in:
+243
@@ -0,0 +1,243 @@
|
||||
---
|
||||
phase: quick-260914-ebg
|
||||
plan: 01
|
||||
subsystem: auth
|
||||
tags: [nestjs, prisma, rbac, vitest, biome]
|
||||
|
||||
requires:
|
||||
- phase: quick-260911-fh9
|
||||
provides: "Zielrollen-Riegel-Vorlage in AuthService.adminResetPassword (T-FH9-04) — dieselbe Bedingung (user.role === SUPER_ADMIN && callerRole !== SUPER_ADMIN) wird hier in UserController.update()/remove() uebernommen"
|
||||
provides:
|
||||
- "Zielrollen-Riegel in UserController.update() und UserController.remove(): ein ADMIN kann den SUPER_ADMIN seines eigenen Mandanten weder aendern noch loeschen"
|
||||
- "acht neue Tests (Test 9-16) in user.controller.spec.ts, Spec-Gesamtzahl 8 -> 16"
|
||||
- "WINDOWS #29 geschlossen (fixed); zwei neue Ledger-Eintraege #35 (Biome-Konfiguration defekt) und #36 (Frontend verschluckt 403 still)"
|
||||
affects: [user-management, auth, windows-ledger]
|
||||
|
||||
actuals:
|
||||
tokens: 6669
|
||||
tasks: 3
|
||||
commits: 3
|
||||
plan_head_before: e76c0f8a3371d6ac210bce5e1d2ce0fe1d372e8c
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "Zielrollen-Riegel-Muster: Mandantengrenze IMMER vor Zielrollen-Pruefung, damit die Fehlermeldung nichts ueber die Rolle eines fremdmandantigen Benutzers verraet (jetzt an zwei Stellen: AuthService.adminResetPassword, UserController.update/remove)"
|
||||
|
||||
key-files:
|
||||
created: []
|
||||
modified:
|
||||
- apps/api/src/user/user.controller.ts
|
||||
- apps/api/src/user/user.controller.spec.ts
|
||||
- apps/api/src/auth/auth.service.ts
|
||||
- .planning/WINDOWS.md
|
||||
|
||||
key-decisions:
|
||||
- "Sechs ueberfluessige `as any`-Umschreibungen in den neuen Tests entfernt (Rule 1) — UpdateUserDto ist vollstaendig optional, die Objektliteral-Zuweisung ist ohne Umschreibung typkorrekt, und die Umschreibungen trieben die Biome-Warnungen der Spec-Datei ueber die Baseline (25)"
|
||||
|
||||
requirements-completed: [WINDOWS-29, T-FH9-05]
|
||||
|
||||
coverage:
|
||||
- id: D1
|
||||
description: "ADMIN kann SUPER_ADMIN des eigenen Mandanten weder per PATCH aendern (Kennwort, isActive, Rolle) noch per DELETE loeschen — ForbiddenException, Dienst nicht aufgerufen"
|
||||
requirement: "WINDOWS-29"
|
||||
verification:
|
||||
- kind: unit
|
||||
ref: "apps/api/src/user/user.controller.spec.ts#Test 9: ein Mandanten-Administrator kann den SUPER_ADMIN des eigenen Mandanten weder übernehmen..."
|
||||
status: pass
|
||||
- kind: unit
|
||||
ref: "apps/api/src/user/user.controller.spec.ts#Test 13: ein Mandanten-Administrator kann den SUPER_ADMIN des eigenen Mandanten nicht löschen..."
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D2
|
||||
description: "Regressionsschutz: SUPER_ADMIN gegen SUPER_ADMIN und ADMIN gegen USER bleiben auf beiden Wegen erlaubt"
|
||||
verification:
|
||||
- kind: unit
|
||||
ref: "apps/api/src/user/user.controller.spec.ts#Test 10, Test 11, Test 14, Test 15"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D3
|
||||
description: "Reihenfolge: Mandantengrenze VOR Zielrollen-Pruefung in beiden Handlern — die Mandanten-Meldung verraet nichts ueber die Rolle eines fremdmandantigen Benutzers"
|
||||
requirement: "T-EBG-04"
|
||||
verification:
|
||||
- kind: unit
|
||||
ref: "apps/api/src/user/user.controller.spec.ts#Test 12, Test 16"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D4
|
||||
description: "Falsifizierung: Rueckbau des Riegels macht genau Test 9 und Test 13 rot, byte-identisch wiederhergestellt"
|
||||
verification:
|
||||
- kind: other
|
||||
ref: "git apply -R Rueckbau-Lauf, siehe Abschnitt Nachweis WINDOWS #29 — Rueckbau unten"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D5
|
||||
description: "Kopfkommentar AuthService.adminResetPassword nennt T-FH9-05 nicht mehr als offen"
|
||||
requirement: "T-FH9-05"
|
||||
verification:
|
||||
- kind: other
|
||||
ref: "grep -c T-FH9-05 apps/api/src/auth/auth.service.ts -> 0"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D6
|
||||
description: "WINDOWS-Ledger: #29 fixed, #35 und #36 als eigene Nebenbefunde eingetragen, nicht mitgeschlossen"
|
||||
verification:
|
||||
- kind: other
|
||||
ref: "node gsd-tools.cjs windows fixed 29; windows append (2x); Frontmatter-Gegenprobe"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
|
||||
duration: 6min
|
||||
completed: 2026-09-14
|
||||
status: complete
|
||||
---
|
||||
|
||||
# Quick 260914-ebg: Zielrollen-Riegel in UserController.update/remove Summary
|
||||
|
||||
**Zielrollen-Riegel (Vorlage aus AuthService.adminResetPassword, T-FH9-04) in UserController.update() und remove() eingezogen — ein ADMIN kann den SUPER_ADMIN seines Mandanten nicht mehr uebernehmen, aussperren, herabstufen oder loeschen; acht neue Tests, Falsifizierung durch Rueckbau bestanden, WINDOWS #29 geschlossen.**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** 6 min
|
||||
- **Started:** 2026-09-14T10:33:00+02:00 (Baseline-Lauf vor Task 1)
|
||||
- **Completed:** 2026-09-14T10:38:29+02:00 (Push)
|
||||
- **Tasks:** 3
|
||||
- **Files modified:** 4
|
||||
|
||||
## Accomplishments
|
||||
- Zielrollen-Riegel in `UserController.update()` (nach der Mandantengrenze, vor der `dto.role`-Pruefung) und `UserController.remove()` (nach der Mandantengrenze, vor `userService.delete`), jeweils mit `ForbiddenException` und Kommentar, der auf WINDOWS #29 und die Vorlage T-FH9-04 verweist
|
||||
- Acht neue Tests (Test 9-16) in `user.controller.spec.ts`: drei Angriffsformen gegen den SUPER_ADMIN (Kennwort, isActive, Rolle), zwei Regressionstests (SUPER_ADMIN gegen SUPER_ADMIN, ADMIN gegen USER) je Handler, zwei Ordnungstests (Mandantengrenze vor Zielrolle)
|
||||
- Falsifizierung: Rueckbau des Task-1-Commits macht genau Test 9 und Test 13 rot, danach byte-identisch wiederhergestellt
|
||||
- Kopfkommentar `AuthService.adminResetPassword` fortgeschrieben — die alte Ledger-Kennung T-FH9-05 kommt in der Datei nicht mehr vor
|
||||
- WINDOWS #29 auf `fixed` gesetzt; zwei neue, eigenstaendige Nebenbefunde #35 (Biome-Konfiguration defekt) und #36 (Frontend verschluckt 403 still) eingetragen, nicht mit #29 mitgeschlossen
|
||||
|
||||
## Task Commits
|
||||
|
||||
Alle drei Aufgaben wurden einzeln committet:
|
||||
|
||||
1. **Task 1: Zielrollen-Riegel in update() und remove() — Tests zuerst (RED), dann Riegel (GREEN)** - `759ea3b` (fix)
|
||||
2. **Task 2: Falsifizierung durch Rueckbau, Kopfkommentar der Vorlage nachziehen, Gesamt-Gates** - `63f9df0` (docs)
|
||||
3. **Task 3: Ledger — #29 schliessen, zwei Nebenbefunde eintragen, pushen** - `70d007b` (docs)
|
||||
|
||||
_Task 1 ist TDD: Tests wurden vor dem Riegel geschrieben (RED), dann der Riegel eingezogen (GREEN) — beides im selben Commit, da RED und GREEN Teil derselben Aufgabe und desselben Nachweises sind._
|
||||
|
||||
## Nachweis WINDOWS #29 — Rueckbau
|
||||
|
||||
**RED-Lauf (Task 1, Schritt A — vor dem Riegel, Tests bereits vorhanden):**
|
||||
|
||||
```
|
||||
Test Files 1 failed (1)
|
||||
Tests 2 failed | 14 passed (16)
|
||||
```
|
||||
|
||||
Rot: `Test 9: ein Mandanten-Administrator kann den SUPER_ADMIN des eigenen Mandanten weder übernehmen (Kennwort setzen), noch aussperren (isActive=false), noch herabstufen (role=USER) — alle drei Angriffsformen werden mit der Zielrollen-Ausnahme abgelehnt, und der Dienst wird in keinem der drei Fälle aufgerufen` (Fehler: `Cannot destructure property 'passwordHash' of 'updated' as it is undefined` statt der erwarteten `Cannot modify a SUPER_ADMIN user`) und `Test 13: ein Mandanten-Administrator kann den SUPER_ADMIN des eigenen Mandanten nicht löschen — die Zielrollen-Ausnahme greift, und der Dienst wird nicht aufgerufen` (Promise loeste mit `{ message: 'User deleted' }` auf statt abzulehnen). Alle anderen 14 Tests gruen.
|
||||
|
||||
Nach dem Riegel (GREEN): `Tests 16 passed (16)`.
|
||||
|
||||
**Falsifizierungs-Rueckbau (Task 2, Schritt A — gegen den committeten Stand):**
|
||||
|
||||
```bash
|
||||
git show HEAD -- apps/api/src/user/user.controller.ts > $SCR/riegel.patch && git apply -R $SCR/riegel.patch
|
||||
pnpm -C apps/api exec vitest run src/user/user.controller.spec.ts
|
||||
```
|
||||
|
||||
Ergebnis, woertlich:
|
||||
|
||||
```
|
||||
Test Files 1 failed (1)
|
||||
Tests 2 failed | 14 passed (16)
|
||||
```
|
||||
|
||||
Rot exakt dieselben zwei: `Test 9` (`AssertionError: expected [Function] to throw error including 'Cannot modify a SUPER_ADMIN user' but got 'Cannot destructure property \'passwor…'`) und `Test 13` (`AssertionError: promise resolved "{ message: 'User deleted' }" instead of rejecting`). Die anderen 14 Tests blieben gruen — der Riegel ist damit als notwendig fuer genau diese zwei Verhaltensnachweise belegt.
|
||||
|
||||
**Wiederherstellung:**
|
||||
|
||||
```bash
|
||||
git checkout -- apps/api/src/user/user.controller.ts
|
||||
git status --porcelain apps/api/src/user/user.controller.ts
|
||||
```
|
||||
|
||||
Ausgabe der zweiten Zeile: leer (byte-identisch wiederhergestellt). Spec danach erneut `Tests 16 passed (16)`.
|
||||
|
||||
## Gates
|
||||
|
||||
1. `pnpm -C apps/api exec vitest run` -> `Test Files 62 passed (62)` / `Tests 1028 passed (1028)` (Baseline 1020/62 plus 8 neue Tests)
|
||||
2. `pnpm -C apps/api exec tsc --noEmit; echo EXIT=$?` -> `EXIT=0`
|
||||
3. `D=$(git diff --stat 37a2f73 -- . ':!.planning'); echo GIT_EXIT=$?; tail -n1 <<< "$D"` -> `GIT_EXIT=0`, `3 files changed, 136 insertions(+), 2 deletions(-)`
|
||||
4. `grep -cE "^\| 29 \|.*\| fixed \|" .planning/WINDOWS.md` -> `1`
|
||||
|
||||
**Biome-Zahlentripel (Ersatzkonfiguration im Scratchpad, relativ zur Baseline — `biome.json` im Repo unangetastet):**
|
||||
|
||||
| Datei | Fehler | Warnungen | Infos | Baseline-Warnungen |
|
||||
|-------|--------|-----------|-------|---------------------|
|
||||
| `apps/api/src/user/user.controller.ts` | 0 | 22 | 2 | 22 |
|
||||
| `apps/api/src/user/user.controller.spec.ts` | 0 | 25 | 0 | 25 |
|
||||
| `apps/api/src/auth/auth.service.ts` | 0 | 20 | 1 | 20 |
|
||||
|
||||
Alle drei Dateien treffen die Baseline exakt (nach dem Rule-1-Nebenfund unten). Kein neues `any`, kein neuer Import.
|
||||
|
||||
**git status --porcelain nach Task 3 (Arbeitsbaum sauber):**
|
||||
|
||||
```
|
||||
(leer)
|
||||
```
|
||||
|
||||
**git log e76c0f8..HEAD:**
|
||||
|
||||
```
|
||||
70d007b docs(quick-260914-ebg): Ledger — WINDOWS #29 fixed, Nebenbefunde Biome-Konfiguration und stilles 403 im Frontend eingetragen
|
||||
63f9df0 docs(quick-260914-ebg): Kopfkommentar adminResetPassword — Schwesterwege PATCH/DELETE /users/:id geschlossen (WINDOWS #29)
|
||||
759ea3b fix(quick-260914-ebg): Zielrollen-Riegel in UserController.update/remove — ADMIN kann SUPER_ADMIN nicht mehr aendern oder loeschen (WINDOWS #29)
|
||||
```
|
||||
|
||||
## Files Created/Modified
|
||||
- `apps/api/src/user/user.controller.ts` - Zielrollen-Riegel in `update()` und `remove()`, je ein Kommentarblock mit Verweis auf WINDOWS #29 und T-FH9-04
|
||||
- `apps/api/src/user/user.controller.spec.ts` - neuer describe-Block mit acht Tests (Test 9-16), Spec-Gesamtzahl 16
|
||||
- `apps/api/src/auth/auth.service.ts` - Kopfkommentar `adminResetPassword` fortgeschrieben (T-FH9-05 nicht mehr offen)
|
||||
- `.planning/WINDOWS.md` - #29 `fixed`, #35 und #36 neu (`quick-260914-ebg`, `deviation`)
|
||||
|
||||
## Decisions Made
|
||||
- Zielrollen-Riegel als eigenstaendige `if`-Pruefung nach der Mandantengrenze eingezogen, nicht als Erweiterung der bestehenden `dto.role`-Pruefung — die bestehende Pruefung sichert die NEUE Rollenzuweisung, der neue Riegel sichert das bereits vorhandene ZIEL; beide bleiben unabhaengig lesbar
|
||||
- Mandantengrenze bewusst VOR der Zielrollen-Pruefung belassen (nicht umgestellt), damit ein Ordnungsfehler durch die Ordnungstests (Test 12, Test 16) sofort rot wird
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 1 - Bug] Sechs ueberfluessige `as any`-Umschreibungen in den neuen Tests entfernt**
|
||||
- **Found during:** Task 2, Schritt C.3 (Biome-Gate)
|
||||
- **Issue:** Die acht neuen Tests in `user.controller.spec.ts` trugen sechs `as any`-Umschreibungen bei den `UpdateUserDto`-Objektliteralen (`{ password: '...' } as any` usw.). Der Plan hatte in `planning_measurements` bereits festgehalten, dass `UpdateUserDto` vollstaendig optional ist und die Objektliterale ohne Umschreibung zuweisbar sind — die Umschreibungen waren unnoetig und trieben die Biome-Warnungen von `user.controller.spec.ts` von der Baseline 25 auf 31 (relative Ersatzkonfiguration, `noExplicitAny`-Familie).
|
||||
- **Fix:** Alle sechs `as any` an den betroffenen Aufrufstellen entfernt (Test 9, Test 10, Test 11, Test 12).
|
||||
- **Files modified:** `apps/api/src/user/user.controller.spec.ts`
|
||||
- **Verification:** `pnpm -C apps/api exec vitest run src/user/user.controller.spec.ts` weiterhin `Tests 16 passed (16)`; Biome-Gate danach `Found 25 warnings.` (Baseline exakt getroffen)
|
||||
- **Committed in:** `63f9df0` (Task 2 Commit, zusammen mit dem Kopfkommentar in `auth.service.ts`, da beide Aenderungen aus demselben Gate-Durchlauf stammen)
|
||||
|
||||
---
|
||||
|
||||
**Total deviations:** 1 auto-fixed (Rule 1)
|
||||
**Impact on plan:** Reine Aufraeumarbeit an eigenem, in Task 1 neu geschriebenem Testcode — kein Scope-Creep, keine Verhaltensaenderung, Biome-Schwelle nicht angehoben, sondern die Baseline exakt wiederhergestellt.
|
||||
|
||||
## Nebenbefunde
|
||||
|
||||
**#35 (Biome-Konfiguration defekt, `biome.json`):** Biome ist im Bestand nicht lauffaehig — `biome.json` traegt den in Biome 2.5.0 unbekannten Schluessel `organizeImports` (gehoert unter `assist`), und es fehlt `javascript.parser.unsafeParameterDecoratorsEnabled`, ohne den jeder NestJS-Parameter-Dekorator ein Parse-Fehler ist. Der CI-Schritt „Lint" ruft `pnpm lint` = `turbo lint`, doch keine App hat ein `lint`-Skript — der Schritt ist ein Leerlauf, der gruen meldet. Als eigener Ledger-Eintrag festgehalten (nicht in #29 mitgeschlossen), `biome.json` liegt ausserhalb der Erlaubnisliste dieses Plans.
|
||||
|
||||
**#36 (Frontend verschluckt 403 still, `apps/web/.../admin/users/page.tsx`):** `handleSubmit` und `handleDelete` pruefen nur `res.ok` ohne `else`-Zweig und fangen mit leerem `catch` — ein 403 fuehrt zu keiner sichtbaren Reaktion. Bestehendes Verhalten fuer alle 403-Wege, aber seit diesem Plan (WINDOWS #29) fuer einen ADMIN im Alltag erstmals erreichbar, weil die SUPER_ADMIN-Zeile in der eigenen Benutzerliste steht und Aendern/Loeschen darauf jetzt 403 liefert. Als eigener Ledger-Eintrag festgehalten, Frontend von diesem Plan nicht geaendert (ausserhalb der Erlaubnisliste).
|
||||
|
||||
## Issues Encountered
|
||||
None - die Umsetzung folgte dem Plan, bis auf den in „Deviations from Plan" dokumentierten Rule-1-Nebenfund.
|
||||
|
||||
## User Setup Required
|
||||
None - keine externe Konfiguration erforderlich.
|
||||
|
||||
## Next Phase Readiness
|
||||
- WINDOWS #29 geschlossen, Rechteausweitung ADMIN gegen SUPER_ADMIN in beiden Schwesterwegen (`adminResetPassword`, `UserController.update/remove`) geschlossen
|
||||
- Zwei Nebenbefunde (#35 Biome, #36 Frontend-403) offen und im Ledger sichtbar — kein Blocker fuer diesen Plan, aber vor dem naechsten Milestone-Abschluss zu pruefen
|
||||
- Kein laufender Milestone begonnen; v1.2 bleibt abgeschlossen (siehe STATE.md)
|
||||
|
||||
---
|
||||
*Phase: quick-260914-ebg*
|
||||
*Completed: 2026-09-14*
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
Alle vier geaenderten Dateien und die SUMMARY-Datei selbst gefunden; alle drei Task-Commits (`759ea3b`, `63f9df0`, `70d007b`) in der Historie gefunden.
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
---
|
||||
phase: quick-260914-ebg
|
||||
verified: 2026-09-14T10:44:00Z
|
||||
status: passed
|
||||
score: 6/6 must-haves verified
|
||||
covered_files:
|
||||
- .planning/WINDOWS.md
|
||||
- .planning/quick/260914-ebg-windows-29-schliessen-rechteausweitung-a/260914-ebg-PLAN.md
|
||||
- .planning/quick/260914-ebg-windows-29-schliessen-rechteausweitung-a/260914-ebg-SUMMARY.md
|
||||
- apps/api/src/auth/auth.service.ts
|
||||
- apps/api/src/user/user.controller.spec.ts
|
||||
- apps/api/src/user/user.controller.ts
|
||||
covered_digest: "v1:sha256:6bdca3a5ea5b9c6eccd3f2c1118f8de02e124d12b1e4e6099abacf2c0286cd51"
|
||||
behavior_unverified: 0
|
||||
overrides_applied: 0
|
||||
---
|
||||
|
||||
# Quick-Task 260914-ebg: WINDOWS #29 schliessen — Verifikationsbericht
|
||||
|
||||
**Ziel:** Rechteausweitung ADMIN -> SUPER_ADMIN in `UserController.update` (PATCH /users/:id) und `UserController.remove` (DELETE /users/:id) verhindern, Zielrollen-Riegel nach der Mandantengrenze, acht Tests, Falsifizierung durch Rueckbau, Ledger-Eintrag #29 auf `fixed`, gepusht.
|
||||
**Verifiziert:** 2026-09-14, unabhaengig vom SUMMARY nachgemessen (nicht dessen Angaben uebernommen).
|
||||
**Status:** passed
|
||||
|
||||
## Beweisfuehrung (jeder Schritt unabhaengig ausgefuehrt)
|
||||
|
||||
### 1. Commit- und Dateiumfang
|
||||
|
||||
Befehl: `git log --oneline 37a2f73..HEAD`
|
||||
|
||||
```
|
||||
70d007b docs(quick-260914-ebg): Ledger — WINDOWS #29 fixed, Nebenbefunde Biome-Konfiguration und stilles 403 im Frontend eingetragen
|
||||
63f9df0 docs(quick-260914-ebg): Kopfkommentar adminResetPassword — Schwesterwege PATCH/DELETE /users/:id geschlossen (WINDOWS #29)
|
||||
759ea3b fix(quick-260914-ebg): Zielrollen-Riegel in UserController.update/remove — ADMIN kann SUPER_ADMIN nicht mehr aendern oder loeschen (WINDOWS #29)
|
||||
e76c0f8 docs(quick-260914-ebg): Plan fuer WINDOWS #29, Zielrollen-Riegel in UserController.update/remove
|
||||
```
|
||||
|
||||
Befehl: `git diff --stat 37a2f73..HEAD -- . ':!.planning'`
|
||||
|
||||
```
|
||||
apps/api/src/auth/auth.service.ts | 5 +-
|
||||
apps/api/src/user/user.controller.spec.ts | 115 ++++++++++++++++++++++++++++++
|
||||
apps/api/src/user/user.controller.ts | 18 +++++
|
||||
3 files changed, 136 insertions(+), 2 deletions(-)
|
||||
```
|
||||
|
||||
Ergebnis: **VERIFIZIERT** — genau die drei vom Plan vorgesehenen Nicht-Planning-Dateien geaendert (`.planning/WINDOWS.md` liegt ausserhalb dieses Filters und wurde separat geprueft, siehe Punkt 6).
|
||||
|
||||
### 2. Reihenfolge der Pruefungen in `user.controller.ts`
|
||||
|
||||
Beide Handler gelesen (`sed -n '160,270p' apps/api/src/user/user.controller.ts`):
|
||||
|
||||
- `update()`: `resolveTargetUser` -> 404 (`NotFoundException`) -> Mandantengrenze -> 403 `Cannot modify users from other tenants` -> Zielrollen-Riegel -> 403 `Cannot modify a SUPER_ADMIN user` -> `dto.role`-Zuweisungspruefung -> 403 `Cannot assign SUPER_ADMIN role` -> `userService.update(...)`.
|
||||
- `remove()`: `resolveTargetUser` -> 404 -> Selbstloeschriegel -> 403 `Cannot delete your own account` -> Mandantengrenze -> 403 `Cannot delete users from other tenants` -> Zielrollen-Riegel -> 403 `Cannot delete a SUPER_ADMIN user` -> `userService.delete(...)`.
|
||||
|
||||
Ergebnis: **VERIFIZIERT** — Reihenfolge entspricht dem must-have (Ziel aufloesen -> 404, Mandantengrenze -> 403, Zielrolle -> 403, [nur update] Rollenzuweisung -> 403, dann Dienstaufruf). Beide neuen Riegel tragen einen Kommentarblock mit Verweis auf WINDOWS #29 und die Vorlage T-FH9-04.
|
||||
|
||||
### 3. Controller-Spec — 16 Tests, Inhalt gelesen
|
||||
|
||||
Befehl: `cd apps/api && npx vitest run src/user/user.controller.spec.ts`
|
||||
|
||||
```
|
||||
✓ src/user/user.controller.spec.ts (16 tests) 24ms
|
||||
Test Files 1 passed (1)
|
||||
Tests 16 passed (16)
|
||||
```
|
||||
|
||||
Alle acht neuen Tests (Test 9-16) vollstaendig gelesen (`sed -n '281,396p'`):
|
||||
|
||||
- Test 9 (update, verboten, 3 Formen: Kennwort/isActive/Rolle) — jeweils `rejects.toThrow('Cannot modify a SUPER_ADMIN user')` UND `expect(userService.update).not.toHaveBeenCalled()`.
|
||||
- Test 10 (update, SUPER_ADMIN gegen SUPER_ADMIN) — `userService.update` mit `toHaveBeenCalledWith('t1', 'boss', ...)`.
|
||||
- Test 11 (update, ADMIN gegen USER) — `toHaveBeenCalledWith('t1', 'u1', ...)`.
|
||||
- Test 12 (update, Ordnungstest) — `rejects.toThrow('Cannot modify users from other tenants')` (woertlich die Mandanten-Meldung, nicht die Zielrollen-Meldung) UND `not.toHaveBeenCalled()`.
|
||||
- Test 13 (remove, verboten) — `rejects.toThrow('Cannot delete a SUPER_ADMIN user')` UND `expect(userService.delete).not.toHaveBeenCalled()`.
|
||||
- Test 14 (remove, SUPER_ADMIN gegen SUPER_ADMIN) — `toHaveBeenCalledWith('t1', 'boss')`.
|
||||
- Test 15 (remove, ADMIN gegen USER) — `toHaveBeenCalledWith('t1', 'u1')`.
|
||||
- Test 16 (remove, Ordnungstest) — `rejects.toThrow('Cannot delete users from other tenants')` UND `not.toHaveBeenCalled()`.
|
||||
|
||||
Ergebnis: **VERIFIZIERT** — die Tests behaupten nicht nur einen geworfenen Fehler, sondern pruefen explizit den Dienstaufruf (nicht/aufgerufen). Kein Test prueft nur den Wurf ohne Mock-Kontrolle.
|
||||
|
||||
### 4. Gesamte API-Suite und Typpruefung
|
||||
|
||||
Befehl: `cd apps/api && npx vitest run`
|
||||
|
||||
```
|
||||
Test Files 62 passed (62)
|
||||
Tests 1028 passed (1028)
|
||||
```
|
||||
|
||||
Befehl: `cd apps/api && npx tsc --noEmit; echo EXIT=$?` -> `EXIT=0`
|
||||
|
||||
Ergebnis: **VERIFIZIERT** — exakt die im Plan geforderten Zahlen.
|
||||
|
||||
### 5. Falsifizierung (unabhaengig wiederholt)
|
||||
|
||||
Reverse-Patch aus dem Task-1-Commit (`759ea3b` = `HEAD~2`) erzeugt und angewendet:
|
||||
|
||||
```bash
|
||||
git show HEAD~2 -- apps/api/src/user/user.controller.ts > $SCR/riegel.patch && git apply -R $SCR/riegel.patch
|
||||
```
|
||||
|
||||
`APPLY_EXIT=0`. Spec danach erneut ausgefuehrt:
|
||||
|
||||
```
|
||||
FAIL src/user/user.controller.spec.ts > ... > Test 13: ... AssertionError: promise resolved "{ message: 'User deleted' }" instead of rejecting
|
||||
Test Files 1 failed (1)
|
||||
Tests 2 failed | 14 passed (16)
|
||||
```
|
||||
|
||||
Rot ausschliesslich Test 9 (Fehlermeldung `Cannot destructure property 'passwordHash' ...` statt `Cannot modify a SUPER_ADMIN user`, weil der Riegel fehlt und der Update-Mock nicht konfiguriert war) und Test 13 (Promise loeste mit `{ message: 'User deleted' }` auf statt abzulehnen) — exakt die zwei im Plan/SUMMARY behaupteten Tests, die anderen 14 blieben gruen.
|
||||
|
||||
Wiederherstellung:
|
||||
|
||||
```bash
|
||||
git checkout -- apps/api/src/user/user.controller.ts
|
||||
git status --porcelain -- apps/api/src/user/user.controller.ts # leer
|
||||
git status --porcelain -- apps/api # leer
|
||||
```
|
||||
|
||||
Spec danach erneut: `Tests 16 passed (16)`.
|
||||
|
||||
Ergebnis: **VERIFIZIERT** — Falsifizierung unabhaengig reproduziert, byte-identische Wiederherstellung bestaetigt, Arbeitsbaum nach Wiederherstellung sauber.
|
||||
|
||||
### 6. Ledger
|
||||
|
||||
Befehl: `node gsd-tools.cjs windows status` und Grep gegen `.planning/WINDOWS.md`:
|
||||
|
||||
- Frontmatter: `open_count: 16`, `waived_count: 1`, `fixed_count: 19`, `total_count: 36` — stimmt exakt mit dem Plan-Gate ueberein.
|
||||
- Zeile `| 29 | quick-260911-fh9 | unmet-truth | ... | fixed | | 2026-09-11T10:00:38.418Z | 2026-09-14T08:37:53.307Z |` — Status `fixed`, `resolved_at` gesetzt.
|
||||
- Zeile `| 35 | quick-260914-ebg | deviation | biome.json | ... | open | ...` und `| 36 | quick-260914-ebg | deviation | apps/web/.../page.tsx | ... | open | ...` — beide als eigenstaendige, offene Nebenbefunde eingetragen, nicht in #29 mitgeschlossen.
|
||||
|
||||
Ergebnis: **VERIFIZIERT**.
|
||||
|
||||
### 7. Kopfkommentar `auth.service.ts`
|
||||
|
||||
Befehl: `grep -n "T-FH9-05" apps/api/src/auth/auth.service.ts` -> kein Treffer (Exit 1, Anzahl 0).
|
||||
Befehl: `grep -c "260914-ebg" apps/api/src/auth/auth.service.ts` -> `1`.
|
||||
|
||||
Kommentar gelesen (Zeilen um 395-410): „Die Schwesterwege `PATCH /users/:id` und `DELETE /users/:id` tragen seit 260914-ebg (WINDOWS #29) denselben Riegel in `UserController.update()`/`remove()`." — ersetzt den alten Satz, der T-FH9-05 als offen benannte. `adminResetPassword`-Verhalten unveraendert (nur Kommentar).
|
||||
|
||||
Ergebnis: **VERIFIZIERT**.
|
||||
|
||||
### 8. Push-Status
|
||||
|
||||
Befehl: `git fetch -q && git status -sb | head -1` -> `## main...origin/main` (kein `[ahead`).
|
||||
|
||||
Ergebnis: **VERIFIZIERT** — alle drei Task-Commits sind im Remote.
|
||||
|
||||
## Beobachtete Arbeitsbaum-Reste
|
||||
|
||||
Nach allen Pruefungen ist der Arbeitsbaum exakt im Ausgangszustand: nur `.planning/STATE.md` (modifiziert) und die neue `260914-ebg-SUMMARY.md` (untracked) sind vorhanden — beides Artefakte, die dem Orchestrator gehoeren und laut Auftrag nicht angefasst werden durften. Kein von dieser Verifikation verursachter Rest.
|
||||
|
||||
## Beobachtete Truths
|
||||
|
||||
| # | Truth | Status | Beweis |
|
||||
|---|-------|--------|--------|
|
||||
| 1 | ADMIN kann SUPER_ADMIN des eigenen Mandanten weder aendern noch loeschen (Dienst nicht aufgerufen) | VERIFIZIERT | Test 9, Test 13 gelesen + unabhaengig ausgefuehrt (16/16 gruen); Falsifizierung macht genau diese zwei rot |
|
||||
| 2 | SUPER_ADMIN gegen SUPER_ADMIN und ADMIN gegen USER/ADMIN bleiben erlaubt | VERIFIZIERT | Test 10, 11, 14, 15 gelesen + gruen |
|
||||
| 3 | Mandantengrenze vor Zielrolle, Meldung verraet keine fremde Rolle | VERIFIZIERT | Test 12, 16 gelesen + gruen, Reihenfolge im Quellcode bestaetigt |
|
||||
| 4 | Falsifizierung: Rueckbau macht genau 2 Tests rot, danach wiederhergestellt | VERIFIZIERT | unabhaengig wiederholt, identisches Ergebnis, `git status --porcelain` leer |
|
||||
| 5 | Kopfkommentar `adminResetPassword` nennt T-FH9-05 nicht mehr als offen | VERIFIZIERT | grep 0 Treffer, Kommentartext gelesen |
|
||||
| 6 | WINDOWS #29 `fixed`, Nebenbefunde als eigene Eintraege, Frontmatter-Zaehler korrekt, gepusht | VERIFIZIERT | Ledger-Grep, `git status -sb` gegen origin/main |
|
||||
|
||||
**Score:** 6/6 truths verifiziert.
|
||||
|
||||
### Required Artifacts
|
||||
|
||||
| Artefakt | Erwartung | Status | Details |
|
||||
|----------|-----------|--------|---------|
|
||||
| `apps/api/src/user/user.controller.ts` | Zielrollen-Riegel in update()/remove() | VERIFIZIERT | Code gelesen, Reihenfolge und Meldungen bestaetigt |
|
||||
| `apps/api/src/user/user.controller.spec.ts` | 8 neue Tests, Spec 16 | VERIFIZIERT | Vollstaendig gelesen, alle 16 Tests gruen |
|
||||
| `apps/api/src/auth/auth.service.ts` | Kopfkommentar aktualisiert, kein Verhaltensaenderung | VERIFIZIERT | Diff nur im Kommentarblock (5 Zeilen), `auth.service.spec.ts` unangetastet und Teil der gruenen Gesamt-Suite |
|
||||
| `.planning/WINDOWS.md` | #29 fixed, #35/#36 neu | VERIFIZIERT | Frontmatter + Zeilen gepruef |
|
||||
|
||||
### Anti-Pattern-Scan
|
||||
|
||||
Keine TBD/FIXME/XXX/TODO/HACK/PLACEHOLDER-Marker in den drei geaenderten Code-Dateien gefunden. Keine leeren Stub-Implementierungen. Keine Blocker.
|
||||
|
||||
### Requirements Coverage
|
||||
|
||||
- `WINDOWS-29`: SATISFIED (Riegel + Tests + Ledger `fixed`).
|
||||
- `T-FH9-05`: SATISFIED (Kopfkommentar aktualisiert, Kennung entfernt).
|
||||
|
||||
### Human Verification Required
|
||||
|
||||
Keine. Alle must-haves sind unit-testbar und wurden unabhaengig ausgefuehrt/reproduziert; keine UI-/Laufzeit-/Browser-Pruefung im Scope dieser Aufgabe.
|
||||
|
||||
### Gaps Summary
|
||||
|
||||
Keine Luecken gefunden. Alle im Plan formulierten must-haves sind im Code, in den Tests, im Ledger und im Git-Verlauf nachweisbar — unabhaengig von den SUMMARY-Behauptungen nachgemessen mit identischem Ergebnis.
|
||||
|
||||
---
|
||||
|
||||
_Verifiziert: 2026-09-14_
|
||||
_Verifier: Claude (gsd-verifier)_
|
||||
Reference in New Issue
Block a user