8.2 KiB
phase, plan, subsystem, tags, status, dependency-graph, tech-stack, key-files, decisions, metrics, actuals
| phase | plan | subsystem | tags | status | dependency-graph | tech-stack | key-files | decisions | metrics | actuals | |||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| quick-260805-d0r | 01 | admin-users |
|
complete |
|
|
|
|
|
|
Phase quick-260805-d0r Plan 01: Benutzer-Detail zeigt Gruppenmitgliedschaften Summary
Das Benutzer-Detail in /admin/users zeigt Gruppenmitgliedschaften jetzt aus den tatsaechlichen GroupMembership-Zeilen, unabhaengig davon, ob die Gruppe gerade ein Modul freigibt.
Was gebaut wurde
Task 1 — Mitgliedschaften end-to-end (D-16):
ModuleGrantsService.getUserAccess liefert jetzt ein Objekt { groups, modules } statt des bisherigen Arrays. groups kommt aus einer neuen this.prisma.groupMembership.findMany-Abfrage mit where: { userId, group: { tenantId } } — dem expliziten Mandantenfilter ueber die Relation, weil GroupMembership keine eigene tenantId-Spalte traegt. assertTargetBelongsToTenant bleibt unveraendert die erste Anweisung der Methode. modules ist feldgleich zum bisherigen Rueckgabewert ({ module, viaGroups, direct } je aktivem Modul).
Die API-Spec (module-grants.service.spec.ts) bekam einen groupMembership-Zweig im Hand-Fake-Prisma, einen dritten optionalen source-Parameter fuer __seedMembership (Default MANUAL) und sieben neue/umgestellte Tests: den Regressionsfall ("Mitglied einer Gruppe ohne Modul-Freigabe bleibt sichtbar"), den Cross-Tenant-Fall, den LDAP-Herkunfts-Fall, den Leer-Modul-Fall und den Sortierungs-Fall.
UserAccessModal.tsx liest die Gruppen-Chips jetzt direkt aus data.groups (React-key ist die Gruppen-ID statt des Namens) statt sie aus der Vereinigung aller row.viaGroups abzuleiten. Das useMemo, das die Namen bisher zusammensetzte, und der ungenutzte useMemo-Import wurden entfernt. Der Kopfkommentar der Datei wurde neu formuliert — der alte Satz ("Chips sind die deduplizierte Menge aller viaGroups-Namen, ein zweiter Endpoint existiert bewusst nicht") widersprach sonst dem neuen Code.
Der Controller-JSDoc ueber GET /module-grants/users/:userId wurde an die Zwei-Schluessel-Antwort angepasst; der Controller-Code selbst blieb unveraendert (reicht die Service-Antwort weiter).
Task 2 — Herkunfts-Badge (D-19/D-20):
Ein zweiter useTranslations('admin.groups.members')-Hook (tMembers) liest die bereits bestehenden Schluessel sourceManual/sourceLdap. Jeder Chip zeigt jetzt zusaetzlich zum Gruppennamen ein Badge — Markup und Klassen 1:1 aus GroupMembersModal.tsx (Zeilen 176-184) uebernommen: blaue Variante bei LDAP, neutral-grau sonst. de.json/en.json blieben unveraendert — kein neuer Schluessel, deckungsgleiche Pruefung bestand mit 762 Schluesseln auf beiden Seiten.
Task 3 — Browser-Gegenprobe: delegiert an den Orchestrator. Der lokale Stack (web:3000, api:3001, db) laeuft; die Browser-Verifikation aus dem Plan (Chip bleibt nach Entzug aller Modul-Freigaben stehen, Leerzustand bei Benutzer ohne Mitgliedschaft, Badges sichtbar) wurde in dieser Ausfuehrung NICHT durchgefuehrt und muss vom Orchestrator nachgeholt werden.
TDD-Ablauf
Beide Tasks liefen als echte RED/GREEN-Zyklen mit getrennten Commits:
b6d4e4atest: Service-Spec-Tests ergaenzt, gegen den unveraenderten Service rot (7 von 25 Tests fehlgeschlagen, bestaetigt).ecadf69feat: Service + Controller implementiert, 25/25 gruen.771f680test: Web-Test-Fixtures auf{ groups, modules }umgestellt, gegen das unveraenderte Modal rot (8 von 8 Tests fehlgeschlagen mitTypeError: (rows ?? []) is not iterable, bestaetigt).f8ff74bfeat: Modal implementiert, 7/7 gruen (die achte, das Badge betreffende Testerwartung, wurde vor diesem Commit wieder entfernt — siehe Deviations).73122b5test: Badge-Test separat ergaenzt, rot bestaetigt (1 von 8 Tests fehlgeschlagen).8ce3748feat: Badge implementiert, 8/8 gruen.
Deviations from Plan
Auto-fixed Issues
1. [Prozess-Korrektur, kein Rule-1/2/3-Fix] Badge-Test versehentlich vorzeitig in Task-1-RED-Commit aufgenommen
- Gefunden bei: Schreiben des Web-Testfiles fuer Task 1.
- Problem: Beim ersten Entwurf der neuen
user-access-modal.test.tsxwurde faelschlich bereits der Badge-Test (Task-2-Umfang) samtadmin.groups.members-Mock-Namensraum mit reingeschrieben und im RED-Commit771f680mitcommittet. - Fix: Vor dem GREEN-Commit von Task 1 wieder entfernt (Namensraum-Eintrag und Testblock), damit Task 1s Commit-Grenze exakt dem Plan entspricht. Der Badge-Test wurde danach in Task 2 als eigener RED/GREEN-Zyklus neu geschrieben.
- Dateien:
apps/web/src/app/(portal)/admin/users/user-access-modal.test.tsx - Commits: Entfernung Teil von
f8ff74b; Neuanlage in73122b5/8ce3748.
Keine weiteren Abweichungen — der Plan wurde ansonsten exakt wie beschrieben umgesetzt, inklusive der bewussten Nicht-Verwendung von forTenant() gemaess der Begruendung im PLAN.md-Objective.
Auth-Gates
Keine.
Known Stubs
Keine.
Threat Flags
Keine — die im Plan dokumentierten Threats (T-d0r-01/02/03) sind durch die umgesetzte Mandanten-Gegenpruefung und das explizite group: { tenantId }-Filter vollstaendig mitigiert bzw. wie geplant akzeptiert; kein zusaetzliches, ungeplantes Angriffsflaechen-Element wurde eingefuehrt.
Verifikation
pnpm --filter @tessera/api test -- module-grants: 25/25 gruen (inkl. Regression, Cross-Tenant, LDAP-Herkunft).pnpm --filter @tessera/api run type-check: sauber.pnpm --filter @tessera/web test -- user-access-modal: 8/8 gruen (inkl. Regression, beider Herkunftsbadges).pnpm --filter @tessera/web run type-check: sauber.pnpm --filter @tessera/api test: 498/498 gruen (keine Kollateralschaeden).pnpm --filter @tessera/web test: 187/187 gruen (keine Kollateralschaeden).de.json/en.json: unveraendert, 762 Schluessel deckungsgleich;admin.groups.members.sourceManual/.sourceLdapin beiden vorhanden.- Diff seit Phase-15-Ende (
be1183a..HEAD) beruehrt exakt die fuenf im Plan gelisteten Dateien, keine Schemaaenderung, keine Migration. - Task 3 (Browser-Gegenprobe): OFFEN. Delegiert an den Orchestrator gemaess Auftrag — bitte vor Abschluss nachholen (siehe orchestrator_decisions im Prompt dieser Ausfuehrung).
Self-Check: PASSED
apps/api/src/groups/module-grants.service.ts: FOUNDapps/api/src/groups/module-grants.service.spec.ts: FOUNDapps/api/src/groups/module-grants.controller.ts: FOUNDapps/web/src/app/(portal)/admin/users/components/UserAccessModal.tsx: FOUNDapps/web/src/app/(portal)/admin/users/user-access-modal.test.tsx: FOUNDb6d4e4a: FOUNDecadf69: FOUND771f680: FOUNDf8ff74b: FOUND73122b5: FOUND8ce3748: FOUND