9.7 KiB
phase, plan, subsystem, tags, requires, provides, affects, actuals, tech-stack, key-files, key-decisions, requirements-completed, coverage, duration, completed, status
| phase | plan | subsystem | tags | requires | provides | affects | actuals | tech-stack | key-files | key-decisions | requirements-completed | coverage | duration | completed | status | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 15-modul-berechtigungen-gruppen-user-grants | 05 | dashboard |
|
|
|
|
|
|
|
|
|
9min | 2026-08-04 | complete |
Phase 15 Plan 05: Dashboard-Widget-Modulfilterung Summary
Statische WIDGET_MODULE_MAP (bewusst leer) plus DashboardService.getWidgets(userId, tenantId, role), das Widgets eines für den Benutzer gesperrten Moduls über ModuleAccessService.getAccessibleModuleIds (D-01, aus Plan 15-01) herausfiltert, mit Fail-Closed bei unauflösbarem Modul-Slug — die erste Testsuite für DashboardService überhaupt, mit End-to-End-Nachweis gegen die laufende lokale API.
Performance
- Duration: 9 min
- Started: 2026-08-04T13:28:00Z
- Completed: 2026-08-04T13:37:28Z
- Tasks: 2
- Files modified: 5
Accomplishments
apps/api/src/dashboard/widget-module-map.ts(neu): exportiertWIDGET_MODULE_MAP(Readonly<Record<string, string>>) undgetModuleSlugForWidgetType, mit einem Blockkommentar, der Zweck, Schlüssel/Werte-Bedeutung und die bewusste Entscheidung gegen eine Schemaspalte festhält. Die Tabelle ist zum Abschluss dieser Phase leer — alle acht heute registrierten Widget-Typen (clock/search/calendar/note/calculator/favorites/link/stopwatch) sind Plattform-Widgets ohne ModulbezugDashboardService.getWidgetserweitert von(userId)auf(userId, tenantId, role: Role): die bestehendefindMany-Query mitorderBy: { createdAt: 'asc' }läuft unverändert zuerst; nur wenn mindestens ein geladenes Widget inWIDGET_MODULE_MAPsteht, wirdModuleAccessService.getAccessibleModuleIdsgenau einmal aufgerufen (kein Lookup je Widget) und die betroffenen Modul-Slugs über eine einzelnemodule.findMany-Query auf IDs abgebildet; Widgets ohne Tabelleneintrag bleiben immer erhalten, Widgets mit unauflösbarem Modul-Slug werden entfernt (Fail-Closed)DashboardController.getWidgetsreichttenantIdundrole(ausreq.user, JWT-Herkunft) zusätzlich zuuserIddurchDashboardModuleimportiertModuleRegistryModule, damitModuleAccessServiceinjizierbar wirddashboard.service.spec.ts(neu, 8 Tests): deckt jeden<behavior>-Fall aus dem Plan ab — leere Tabelle liefert exakt die Prisma-Menge ohne Zugriffs-Lookup, sichtbar bei Zugriff, entfernt ohne Zugriff, D-03-ADMIN-Kurzschluss, Nicht-Tabellen-Typen bleiben immer erhalten (adjacency), Sortierung bleibt nach dem Filtern erhalten (ordering), zwei Aufrufe löschen keine Zeile (idempotency), Fail-Closed bei fehlendemModule-Datensatz zu einem eingetragenen Slug.WIDGET_MODULE_MAPwird je Testfall über eine mitvi.hoisted()deklarierte, gemockte Objektreferenz gesteuert (plainconstwäre zur Ausführungszeit der gehobenenvi.mock-Factory noch nicht initialisiert)- End-to-End-Nachweis gegen die laufende lokale API (
pnpm start:devgegen den DB-Container, wie in 15-01/15-02): ein eigens perpsqlangelegter Testbenutzer mit zwei Plattform-Widgets (clock,search) erhält bei leererWIDGET_MODULE_MAPüberGET /dashboard/widgetsexakt dieselben 2 Widgets zurück — Testbenutzer und -Widgets nach dem Nachweis wieder aus der DB entfernt
Task Commits
Jeder Task wurde atomar committet:
- Task 1: Statische Widget-Modul-Zuordnung anlegen -
954cd6e(feat) - Task 2: getWidgets filtert über dieselbe Zugriffsauflösung wie Guard und Sidebar -
d0ff6f0(test, RED) +0ff46ac(feat, GREEN)
Plan metadata: siehe Commit dieser SUMMARY.md (docs: complete plan)
Files Created/Modified
apps/api/src/dashboard/widget-module-map.ts-WIDGET_MODULE_MAP(leer) +getModuleSlugForWidgetType(neu)apps/api/src/dashboard/dashboard.service.ts-getWidgetsum Modulfilter erweitert,ModuleAccessServiceinjiziertapps/api/src/dashboard/dashboard.controller.ts-getWidgets-Handler reichttenantId/roledurchapps/api/src/dashboard/dashboard.module.ts- Import vonModuleRegistryModuleapps/api/src/dashboard/dashboard.service.spec.ts- 8 Tests (neu — erste Testsuite fürDashboardService)
Decisions Made
WIDGET_MODULE_MAPbleibt bewusst leer (kein neuer Widget-Typ, keine Schemaänderung) — wie im Plan-Objective vorgegeben, kein Abweichenvi.hoisted()für die je-Testfall mutierbareWIDGET_MODULE_MAP-Mock-Referenz — nicht explizit im Plan-Action-Text benannt, aber notwendig, weil Vitestvi.mock-Aufrufe an den Dateianfang hebt und ein normalerconst mockMap = {}zur Ausführungszeit der Factory noch nicht initialisiert wäre (verifiziert: erster Testlauf ohnevi.hoisted()schlug mitReferenceError: Cannot access 'mockMap' before initializationfehl)
Deviations from Plan
None - plan wie geschrieben ausgeführt.
Issues Encountered
- Beim End-to-End-Nachweis lief zunächst ein API-Prozess aus einer vorherigen Verifikationsrunde ohne
JWT_SECRETweiter im Hintergrund (Port 3001 belegt,EADDRINUSE); nachpkill -f "nest start --watch"und Prüfung, dass Port 3001 wieder frei ist, startete der Nachweis sauber durch — kein Einfluss auf den eigentlichen Code oder die Testsuite - Es existierte kein Bestandsbenutzer mit bekanntem Passwort in der lokalen DB (nur der SUPER_ADMIN aus einer vorherigen Sitzung,
AdminSeedServiceübersprang das Seeding mangelsTESSERA_ADMIN_*-Env-Vars). Für den E2E-Nachweis wurde perpsqlein isolierter Testbenutzer (argon2-Hash übernode -e) samt zwei Widgets angelegt, gegen die laufende lokale API eingeloggt und nach dem Nachweis vollständig wieder gelöscht — analog zum in 15-02 etablierten Verfahren für den Fremdmandanten-Nachweis
User Setup Required
None - keine externe Service-Konfiguration nötig.
Next Phase Readiness
- Die Mechanik aus D-22 ist vollständig, getestet und end-to-end bewiesen (PERM-07)
- Bei leerer Zuordnungstabelle verändert sich für keinen Bestandsbenutzer etwas — durch Unit-Test (
empty-Fall) und E2E-Nachweis doppelt belegt - Sobald ein künftiges modulgebundenes Widget entsteht, genügt ein Eintrag in
WIDGET_MODULE_MAP— die Filterlogik selbst braucht keine Änderung - Kein offener Blocker aus diesem Plan
- Voller API-Testsuite: 457/457 grün (449 aus 15-02 + 8 neue)
Phase: 15-modul-berechtigungen-gruppen-user-grants Completed: 2026-08-04
Self-Check: PASSED
Alle in dieser SUMMARY genannten Dateien existieren auf der Platte, alle genannten Commit-Hashes (954cd6e, d0ff6f0, 0ff46ac) sind im Git-Log auffindbar.