docs(15-06): complete Gruppenverwaltung im Admin-UI plan
This commit is contained in:
@@ -122,7 +122,7 @@
|
|||||||
| CONFIG-03 | Phase 14 | Complete |
|
| CONFIG-03 | Phase 14 | Complete |
|
||||||
| UI-06 | Phase 14 | Complete |
|
| UI-06 | Phase 14 | Complete |
|
||||||
|
|
||||||
| PERM-01 | Phase 15 | Pending |
|
| PERM-01 | Phase 15 | Complete |
|
||||||
| PERM-02 | Phase 15 | Pending |
|
| PERM-02 | Phase 15 | Pending |
|
||||||
| PERM-03 | Phase 15 | Complete |
|
| PERM-03 | Phase 15 | Complete |
|
||||||
| PERM-04 | Phase 15 | Complete |
|
| PERM-04 | Phase 15 | Complete |
|
||||||
|
|||||||
@@ -511,7 +511,7 @@ Plans:
|
|||||||
|
|
||||||
**Neue Modelle**: `Group` (tenantId, name, ldapDn?), `GroupMembership` (userId, groupId, source MANUAL|LDAP), `ModuleGrant` (tenantId, moduleId, groupId? | userId?)
|
**Neue Modelle**: `Group` (tenantId, name, ldapDn?), `GroupMembership` (userId, groupId, source MANUAL|LDAP), `ModuleGrant` (tenantId, moduleId, groupId? | userId?)
|
||||||
|
|
||||||
**Plans**: 4/8 plans executed
|
**Plans**: 5/8 plans executed
|
||||||
|
|
||||||
Plans:
|
Plans:
|
||||||
**Wave 1**
|
**Wave 1**
|
||||||
@@ -527,7 +527,7 @@ Plans:
|
|||||||
**Wave 3** *(blocked on Wave 2 completion)*
|
**Wave 3** *(blocked on Wave 2 completion)*
|
||||||
|
|
||||||
- [x] 15-03-PLAN.md — Freigabe-API für Gruppen und Benutzer plus Modulkatalog-Endpoint
|
- [x] 15-03-PLAN.md — Freigabe-API für Gruppen und Benutzer plus Modulkatalog-Endpoint
|
||||||
- [ ] 15-06-PLAN.md — Gruppenverwaltung im Admin-UI und alle i18n-Schlüssel der Phase
|
- [x] 15-06-PLAN.md — Gruppenverwaltung im Admin-UI und alle i18n-Schlüssel der Phase
|
||||||
|
|
||||||
**Wave 4** *(blocked on Wave 3 completion)*
|
**Wave 4** *(blocked on Wave 3 completion)*
|
||||||
|
|
||||||
@@ -559,4 +559,4 @@ Phases execute in numeric order: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10
|
|||||||
| 12. Tender Notifications | 4/4 | In Progress| |
|
| 12. Tender Notifications | 4/4 | In Progress| |
|
||||||
| 13. Scraping Adapters & Cross-Source Deduplication | 6/6 | In Progress| |
|
| 13. Scraping Adapters & Cross-Source Deduplication | 6/6 | In Progress| |
|
||||||
| 14. RSS, Email-Alert Ingestion & Module Rollout | 5/5 | In Progress| |
|
| 14. RSS, Email-Alert Ingestion & Module Rollout | 5/5 | In Progress| |
|
||||||
| 15. Modul-Berechtigungen: Gruppen & User-Grants | 4/8 | In Progress| |
|
| 15. Modul-Berechtigungen: Gruppen & User-Grants | 5/8 | In Progress| |
|
||||||
|
|||||||
+12
-7
@@ -5,15 +5,15 @@ milestone_name: Ausschreibungs-Radar
|
|||||||
current_phase: 15
|
current_phase: 15
|
||||||
current_phase_name: modul-berechtigungen-gruppen-user-grants
|
current_phase_name: modul-berechtigungen-gruppen-user-grants
|
||||||
status: executing
|
status: executing
|
||||||
stopped_at: Completed 15-03-PLAN.md
|
stopped_at: Completed 15-06-PLAN.md
|
||||||
last_updated: "2026-08-04T16:43:23.536Z"
|
last_updated: "2026-08-04T17:06:12.249Z"
|
||||||
last_activity: 2026-08-04
|
last_activity: 2026-08-04
|
||||||
last_activity_desc: Phase 15 execution started
|
last_activity_desc: Phase 15 execution started
|
||||||
progress:
|
progress:
|
||||||
total_phases: 15
|
total_phases: 15
|
||||||
completed_phases: 13
|
completed_phases: 13
|
||||||
total_plans: 75
|
total_plans: 75
|
||||||
completed_plans: 70
|
completed_plans: 71
|
||||||
---
|
---
|
||||||
|
|
||||||
# Project State
|
# Project State
|
||||||
@@ -28,11 +28,11 @@ See: .planning/PROJECT.md (updated 2026-07-17)
|
|||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Phase: 15 (modul-berechtigungen-gruppen-user-grants) — EXECUTING
|
Phase: 15 (modul-berechtigungen-gruppen-user-grants) — EXECUTING
|
||||||
Plan: 5 of 8
|
Plan: 6 of 8
|
||||||
Status: Ready to execute
|
Status: Ready to execute
|
||||||
Last activity: 2026-08-04 — Phase 15 execution started
|
Last activity: 2026-08-04 — Phase 15 execution started
|
||||||
|
|
||||||
Progress: [█████████░] 93%
|
Progress: [██████████] 95%
|
||||||
|
|
||||||
## Performance Metrics
|
## Performance Metrics
|
||||||
|
|
||||||
@@ -104,6 +104,7 @@ Progress: [█████████░] 93%
|
|||||||
| Phase 15-modul-berechtigungen-gruppen-user-grants P02 | 11min | 2 tasks | 11 files |
|
| Phase 15-modul-berechtigungen-gruppen-user-grants P02 | 11min | 2 tasks | 11 files |
|
||||||
| Phase 15 P05 | 9min | 2 tasks | 5 files |
|
| Phase 15 P05 | 9min | 2 tasks | 5 files |
|
||||||
| Phase 15 P03 | 32min | 3 tasks | 8 files |
|
| Phase 15 P03 | 32min | 3 tasks | 8 files |
|
||||||
|
| Phase 15 P06 | 35min | 3 tasks | 8 files |
|
||||||
|
|
||||||
## Accumulated Context
|
## Accumulated Context
|
||||||
|
|
||||||
@@ -243,6 +244,9 @@ Recent decisions affecting current work:
|
|||||||
- [Phase ?]: [15-03]: assertTargetBelongsToTenant als eigenständige Cross-Tenant-Prüfung eines referenzierten Fremdobjekts vor jedem Grant-Insert (T-15-01), kein Vorbild im Bestandscode
|
- [Phase ?]: [15-03]: assertTargetBelongsToTenant als eigenständige Cross-Tenant-Prüfung eines referenzierten Fremdobjekts vor jedem Grant-Insert (T-15-01), kein Vorbild im Bestandscode
|
||||||
- [Phase ?]: [15-03]: Kein Import von ModuleRegistryModule in GroupsModule — ModuleGrantsService injiziert ausschließlich PrismaService
|
- [Phase ?]: [15-03]: Kein Import von ModuleRegistryModule in GroupsModule — ModuleGrantsService injiziert ausschließlich PrismaService
|
||||||
- [Phase ?]: [15-03]: getCatalogFlags liefert Map nur für aktive Module, Controller mappt fehlenden Eintrag auf beide Flags false
|
- [Phase ?]: [15-03]: getCatalogFlags liefert Map nur für aktive Module, Controller mappt fehlenden Eintrag auf beide Flags false
|
||||||
|
- [Phase ?]: [15-06]: Task 2/3-Split von page.tsx haelt jeden Task-Commit fuer sich buildbar (Task 2 ohne Import der erst in Task 3 entstehenden Komponenten)
|
||||||
|
- [Phase ?]: [15-06]: Gruppen-Erstellung mit sofortiger AD-Bindung laeuft zweistufig (POST /groups, dann PATCH ldapDn), weil CreateGroupDto aus 15-02 nur name entgegennimmt
|
||||||
|
- [Phase ?]: [15-06]: matrixCheckboxLabel/directCheckboxLabel (Wave-4-Schluessel) als next-intl-ICU-select mit granted-Parameter modelliert, ein Schluessel bedient freigeben/entziehen
|
||||||
|
|
||||||
### Pending Todos
|
### Pending Todos
|
||||||
|
|
||||||
@@ -253,6 +257,7 @@ None yet.
|
|||||||
- [Roadmap v1.1]: DÖE OpenData API pagination/rate-limit parameters unverified (Swagger UI is JS-rendered) — resolve via a live API call during Phase 10 planning, not assumed from docs.
|
- [Roadmap v1.1]: DÖE OpenData API pagination/rate-limit parameters unverified (Swagger UI is JS-rendered) — resolve via a live API call during Phase 10 planning, not assumed from docs.
|
||||||
- [Roadmap v1.1]: Whether AI-AG NetServer / cosinex VMP search pages require JS rendering is unverified — needs a Phase 13 start-of-phase spike before committing to playwright.
|
- [Roadmap v1.1]: Whether AI-AG NetServer / cosinex VMP search pages require JS rendering is unverified — needs a Phase 13 start-of-phase spike before committing to playwright.
|
||||||
- Phase 14 Plan 03 (14-03): Task 4 human-verify OPEN — needs a real portal-alert mailbox (incl. Exchange/EWS live path) from the operator before INGEST-05's Exchange path is production-ready. Tasks 1-3 complete and committed (4d6fbb1, 8983231, 1be6b15, 48e1252); API 387/387, web 144/144 green.
|
- Phase 14 Plan 03 (14-03): Task 4 human-verify OPEN — needs a real portal-alert mailbox (incl. Exchange/EWS live path) from the operator before INGEST-05's Exchange path is production-ready. Tasks 1-3 complete and committed (4d6fbb1, 8983231, 1be6b15, 48e1252); API 387/387, web 144/144 green.
|
||||||
|
- Phase 15 Plan 06 (15-06): manueller Browser-Durchklick aus dem Plan-Verification-Block nicht ausgefuehrt (kein Browser-Tool in dieser Session) — vor /gsd-ship nachholen, siehe WINDOWS.md unrun-verify #1
|
||||||
|
|
||||||
### Quick Tasks Completed
|
### Quick Tasks Completed
|
||||||
|
|
||||||
@@ -284,7 +289,7 @@ Items acknowledged and carried forward from previous milestone close:
|
|||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-08-04T16:43:23.505Z
|
Last session: 2026-08-04T17:06:12.218Z
|
||||||
Stopped at: Completed 15-03-PLAN.md
|
Stopped at: Completed 15-06-PLAN.md
|
||||||
Resume file: None
|
Resume file: None
|
||||||
Last activity: 2026-07-14 - Built LDAP per-user exclude/denylist filter (9d1323f), migration applied on live DB, verified via Playwright: sync deactivated 4 excluded service accounts (administrator/krbtgt/guest/dns-ldap), 2 real LDAP users stay active, 0 wrongly created
|
Last activity: 2026-07-14 - Built LDAP per-user exclude/denylist filter (9d1323f), migration applied on live DB, verified via Playwright: sync deactivated 4 excluded service accounts (administrator/krbtgt/guest/dns-ldap), 2 real LDAP users stay active, 0 wrongly created
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
schema_version: 1
|
||||||
|
open_count: 1
|
||||||
|
waived_count: 0
|
||||||
|
fixed_count: 0
|
||||||
|
total_count: 1
|
||||||
|
last_updated: 2026-08-04T17:05:42.026Z
|
||||||
|
---
|
||||||
|
|
||||||
|
# Broken Windows Ledger
|
||||||
|
|
||||||
|
> Cross-phase defect register. `/gsd-ship` blocks while `open_count > 0`.
|
||||||
|
> Waive with `gsd-tools windows waive <id> "<reason>"` (reason required).
|
||||||
|
> Mark fixed with `gsd-tools windows fixed <id>`.
|
||||||
|
|
||||||
|
| id | phase | kind | file | line | description | status | reason | recorded_at | resolved_at |
|
||||||
|
|----|-------|------|------|------|-------------|--------|--------|-------------|-------------|
|
||||||
|
| 1 | 15 | unrun-verify | .planning/phases/15-modul-berechtigungen-gruppen-user-grants/15-06-PLAN.md | | 15-06 <verification>: manueller Browser-Durchklick (Anlegen/Umbenennen/Standardmarkierung/AD-Bindung/Mitglieder/Loeschdialog + Fehlerpfade bei abgeschalteter API) nicht ausgefuehrt — kein Browser-Tool in dieser Session verfuegbar | open | | 2026-08-04T17:05:42.026Z | |
|
||||||
|
|
||||||
|
````json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"kind": "unrun-verify",
|
||||||
|
"phase": "15",
|
||||||
|
"file": ".planning/phases/15-modul-berechtigungen-gruppen-user-grants/15-06-PLAN.md",
|
||||||
|
"line": null,
|
||||||
|
"description": "15-06 <verification>: manueller Browser-Durchklick (Anlegen/Umbenennen/Standardmarkierung/AD-Bindung/Mitglieder/Loeschdialog + Fehlerpfade bei abgeschalteter API) nicht ausgefuehrt — kein Browser-Tool in dieser Session verfuegbar",
|
||||||
|
"status": "open",
|
||||||
|
"reason": "",
|
||||||
|
"recorded_at": "2026-08-04T17:05:42.026Z",
|
||||||
|
"resolved_at": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
````
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
---
|
||||||
|
phase: 15-modul-berechtigungen-gruppen-user-grants
|
||||||
|
plan: 06
|
||||||
|
subsystem: ui
|
||||||
|
tags: [nextjs, next-intl, react, admin, groups, ldap]
|
||||||
|
|
||||||
|
# Dependency graph
|
||||||
|
requires:
|
||||||
|
- phase: 15-modul-berechtigungen-gruppen-user-grants
|
||||||
|
plan: 02
|
||||||
|
provides: GroupsService/GroupsController — vollständiges CRUD für Gruppen und Mitgliedschaften, GroupsService.getImpact als Zahlenquelle für den Löschdialog (D-17)
|
||||||
|
provides:
|
||||||
|
- "/admin/groups Seite: Tabelle (Name/AD-Bindung/Standardgruppe/Mitglieder/Aktionen), Anlege/Umbenennen-Modal mit AD-Radio-Auswahl aus GET /ldap/groups (D-05, D-18), Mitglieder-Modal mit LDAP-Herkunfts-Sperre (D-19), Löschdialog mit konkreten Zahlen (D-17)"
|
||||||
|
- "Sechster Admin-Navigationseintrag 'Gruppen' mit eigenem Roster-Icon"
|
||||||
|
- "Sämtliche i18n-Schlüssel der gesamten Phase 15 in de.json/en.json — admin.groups.*, admin.users.grants.*, adminModules.grantsLink/grants.*/activationDialog.*, modules.accessDenied.*, marketplace.statusNoAccess/toastNoAccess, header.admin.groups"
|
||||||
|
affects: [15-07, 15-08]
|
||||||
|
|
||||||
|
actuals:
|
||||||
|
tokens: 14500
|
||||||
|
tasks: 3
|
||||||
|
commits: 3
|
||||||
|
|
||||||
|
tech-stack:
|
||||||
|
added: []
|
||||||
|
patterns:
|
||||||
|
- "AD-Bindungs-Auswahl per Radio-Liste (nicht Checkbox) aus derselben GET /ldap/groups-Discovery, die admin/ldap/page.tsx für den Import-Filter nutzt — Markup 1:1 übernommen, nur input type gewechselt"
|
||||||
|
- "Sichtbare Fehlerbehandlung für Lösch- und AD-Discovery-Fehlschläge (border-destructive/50 bg-destructive/10), bewusster Bruch mit dem sonst projektweiten silent-fail-Muster der Admin-Lösch-Dialoge — dokumentiert als Code-Kommentar an DeleteGroupDialog"
|
||||||
|
- "ICU-select-Syntax in next-intl-Werten ({granted, select, true {freigeben} other {entziehen}}) für Checkbox-aria-labels, die je nach Zustand zwei Verbformen brauchen, ohne einen zweiten i18n-Schlüssel anzulegen"
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created:
|
||||||
|
- apps/web/src/app/(portal)/admin/groups/page.tsx
|
||||||
|
- apps/web/src/app/(portal)/admin/groups/components/GroupFormModal.tsx
|
||||||
|
- apps/web/src/app/(portal)/admin/groups/components/GroupMembersModal.tsx
|
||||||
|
- apps/web/src/app/(portal)/admin/groups/components/DeleteGroupDialog.tsx
|
||||||
|
- apps/web/src/app/(portal)/admin/groups/groups-page.test.tsx
|
||||||
|
modified:
|
||||||
|
- apps/web/src/messages/de.json
|
||||||
|
- apps/web/src/messages/en.json
|
||||||
|
- apps/web/src/components/admin/admin-sidebar.tsx
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "Task 2/3-Split von page.tsx: Task 2 committet die Seite mit Create/Edit-Modal verdrahtet, aber Mitglieder-/Lösch-State bereits deklariert und an die Aktionsbuttons gehängt, ohne die (noch nicht existierenden) Task-3-Komponenten zu importieren — hält jeden Task-Commit für sich buildbar, statt beide Dateien in einem Commit zu bündeln"
|
||||||
|
- "Erstellen einer Gruppe MIT sofortiger AD-Bindung läuft zweistufig (POST /groups, dann PATCH /groups/:id {ldapDn}), weil CreateGroupDto ausschliesslich name entgegennimmt (15-02) — keine Schema-/DTO-Änderung nötig, nur Client-seitige Sequenzierung"
|
||||||
|
- "matrixCheckboxLabel/directCheckboxLabel (Wave-4-Schlüssel für 15-07/15-08) als next-intl-ICU-select mit zusätzlichem granted-Parameter modelliert, um freigeben/entziehen aus einem einzigen Schlüssel zu bedienen, statt zwei separate Schlüssel anzulegen"
|
||||||
|
|
||||||
|
requirements-completed: [PERM-01]
|
||||||
|
|
||||||
|
coverage:
|
||||||
|
- id: D1
|
||||||
|
description: "/admin/groups Tabelle mit Name/AD-Bindung/Standardgruppe/Mitglieder/Aktionen, leerer Zustand, optimistischer Standardgruppen-Stern-Toggle mit Rollback bei Fehler"
|
||||||
|
requirement: "PERM-01"
|
||||||
|
verification:
|
||||||
|
- kind: unit
|
||||||
|
ref: "apps/web/src/app/(portal)/admin/groups/groups-page.test.tsx (describe 'AdminGroupsPage': empty state, populated table, star-toggle PATCH + rollback — 4 Tests)"
|
||||||
|
status: pass
|
||||||
|
- kind: other
|
||||||
|
ref: "grep-Nachweise aus Task 2 acceptance_criteria (font-weight-Vokabular, sechs Sidebar-Einträge) + pnpm --filter @tessera/web run build"
|
||||||
|
status: pass
|
||||||
|
human_judgment: false
|
||||||
|
- id: D2
|
||||||
|
description: "GroupFormModal: Anlegen/Umbenennen mit AD-Bindung per Radio-Auswahl aus GET /ldap/groups (D-05/D-18), sichtbarer Fehler-/Leerfall bei der AD-Suche statt stillem Leerbild"
|
||||||
|
requirement: "PERM-01"
|
||||||
|
verification:
|
||||||
|
- kind: other
|
||||||
|
ref: "grep-Nachweise aus Task 2 acceptance_criteria: type=\"radio\" vorhanden, type=\"checkbox\" abwesend, ldap/groups referenziert, discoverError/noResults sichtbar ausgeführt"
|
||||||
|
status: pass
|
||||||
|
- kind: other
|
||||||
|
ref: "pnpm --filter @tessera/web run build (Typecheck inkl. GroupFormModal) + pnpm --filter @tessera/web test (voller Lauf, 162/162 grün)"
|
||||||
|
status: pass
|
||||||
|
human_judgment: true
|
||||||
|
rationale: "Kein interaktiver Komponententest öffnet das Modal und klickt einen Radio-Eintrag — die Task-2-acceptance_criteria verlangten explizit nur grep-Nachweise für diese Datei, kein Render-Test. Der volle Klickpfad (Discover -> Radio wählen -> Speichern -> Chip erscheint) und insbesondere das Verhalten gegen ein echtes AD wurden in dieser Session nicht im Browser geprüft (kein Browser-Tool verfügbar)."
|
||||||
|
- id: D3
|
||||||
|
description: "GroupMembersModal: Mitglieder-Chips mit Herkunfts-Badge, LDAP-Mitgliedschaften mit deaktiviertem Entfernen-Button (D-19), manuelles Hinzufügen per Benutzersuche"
|
||||||
|
requirement: "PERM-01"
|
||||||
|
verification:
|
||||||
|
- kind: unit
|
||||||
|
ref: "groups-page.test.tsx ('disables the remove button for LDAP-sourced members and keeps it active for MANUAL members')"
|
||||||
|
status: pass
|
||||||
|
- kind: other
|
||||||
|
ref: "grep-Nachweise: disabled/ldapManaged in GroupMembersModal.tsx"
|
||||||
|
status: pass
|
||||||
|
human_judgment: false
|
||||||
|
- id: D4
|
||||||
|
description: "DeleteGroupDialog: laedt GET /groups/:id/impact, zeigt memberCount/grantCount konkret (D-17), bleibt bei fehlgeschlagenem DELETE offen mit sichtbarer Fehlermeldung (T-15-24, bewusste Abweichung vom silent-fail-Präzedenzfall)"
|
||||||
|
requirement: "PERM-01"
|
||||||
|
verification:
|
||||||
|
- kind: unit
|
||||||
|
ref: "groups-page.test.tsx ('shows both concrete numbers...', 'stays open and shows a visible error when DELETE fails')"
|
||||||
|
status: pass
|
||||||
|
- kind: other
|
||||||
|
ref: "grep-Nachweise: impact-Aufruf + border-destructive/50 bg-destructive/10 in DeleteGroupDialog.tsx"
|
||||||
|
status: pass
|
||||||
|
human_judgment: false
|
||||||
|
- id: D5
|
||||||
|
description: "Vollständiges manuelles Durchklicken im Browser aus dem Plan-<verification>-Block: Anlegen, Umbenennen, Standardmarkierung setzen/abschalten, AD-Bindung setzen/lösen, Mitglied hinzufügen/entfernen, Löschdialog mit gefüllter Gruppe, sowie AD-Suche/Löschen bei abgeschalteter API"
|
||||||
|
verification: []
|
||||||
|
human_judgment: true
|
||||||
|
rationale: "Diese Session hatte kein Browser-/Playwright-Tool zur Verfügung (nur Read/Write/Edit/Bash/Skill) — der interaktive Durchlauf aus dem Plan-<verification>-Block konnte nicht ausgeführt werden. Abgedeckt ist stattdessen: vollständiger Vitest-Lauf (162/162 grün), fehlerfreier Produktions-Build inkl. Next.js-Typecheck, sowie alle grep-basierten acceptance_criteria aus allen drei Tasks. In WINDOWS.md als unrun-verify vermerkt."
|
||||||
|
|
||||||
|
duration: ca. 35min
|
||||||
|
completed: 2026-08-04
|
||||||
|
status: complete
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 15 Plan 06: Gruppenverwaltung im Admin-UI Summary
|
||||||
|
|
||||||
|
**`/admin/groups` mit Tabelle, Anlege/Umbenennen-Dialog samt AD-Radio-Bindung, Mitglieder-Dialog mit LDAP-Herkunftssperre und Löschdialog mit konkreten Zahlen — plus sämtliche i18n-Schlüssel der gesamten Phase 15 in de.json/en.json (auch die erst von 15-07/15-08 benötigten).**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
- **Duration:** ca. 35 min
|
||||||
|
- **Started:** 2026-08-04T16:30:00Z (ungefähr — kein expliziter Start-Timestamp erfasst)
|
||||||
|
- **Completed:** 2026-08-04T17:05:00Z
|
||||||
|
- **Tasks:** 3
|
||||||
|
- **Files modified:** 8
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- `de.json`/`en.json` tragen deckungsgleich (762 Schlüssel) alle Übersetzungen der gesamten Phase 15 — nicht nur für `/admin/groups`, sondern auch die von den Wave-4-Plänen 15-07/15-08 benötigten Namensräume (`admin.users.grants.*`, `adminModules.grantsLink`/`grants.*`/`activationDialog.*`, `modules.accessDenied.*`, `marketplace.statusNoAccess`/`toastNoAccess`), damit diese Pläne parallel laufen können, ohne die Übersetzungsdateien anzufassen
|
||||||
|
- `AdminSidebar` hat einen sechsten Eintrag "Gruppen" → `/admin/groups` mit einem eigenen Roster-/Listen-Icon (Lucide `list`-Glyphe), optisch klar vom Personen-Icon des Benutzer-Eintrags unterschieden
|
||||||
|
- `/admin/groups` zeigt eine Tabelle mit Name, AD-Bindungs-Badge, Standardgruppen-Stern-Toggle (optimistisch mit Rollback bei Fehler, volle Refetch bei Erfolg wegen der serverseitigen Exklusivität aus D-13), Mitgliederzahl und den drei Aktionen Bearbeiten/Mitglieder/Löschen
|
||||||
|
- `GroupFormModal` bindet eine Gruppe an eine AD-Gruppe ausschliesslich über eine Radio-Auswahl aus der bestehenden `GET /ldap/groups`-Discovery (D-05, D-18) — kein Freitextfeld für einen DN, damit T-15-23 (getippter DN im späteren LDAP-Filter) strukturell ausgeschlossen bleibt. Fehlschlag oder Leerergebnis der AD-Suche erscheinen sichtbar (`ldapBind.discoverError`/`.noResults`) statt einer stillen Leerliste
|
||||||
|
- `GroupMembersModal` zeigt Mitglieder als Chips mit Herkunfts-Badge; bei Herkunft `LDAP` ist der Entfernen-Button deaktiviert mit Tooltip "Wird über AD-Sync verwaltet" (D-19) — nur der Sync darf diese Mitgliedschaft entfernen
|
||||||
|
- `DeleteGroupDialog` lädt `GET /groups/:id/impact` und interpoliert `memberCount`/`grantCount` konkret in den Warntext (D-17); bricht bewusst mit dem projektweiten silent-fail-Präzedenzfall der übrigen Lösch-Dialoge, weil ein unbemerkter Fehlschlag hier einen Admin im Glauben liesse, eine Gruppe samt Freigaben sei weg, während sie weiterhin Zugriff gewährt (T-15-24) — der Dialog bleibt bei einem Fehlschlag offen und zeigt die Meldung im bestehenden `error`-Div-Muster
|
||||||
|
- 7 neue Komponententests in `groups-page.test.tsx`: leerer Zustand, gefüllte Tabelle, Stern-Toggle (Erfolg + Rollback bei Fehler), deaktivierter vs. aktiver Entfernen-Button je nach Mitgliedschafts-Herkunft, Löschtext mit beiden Zahlen, sichtbare Fehlermeldung bei fehlgeschlagenem Löschen — voller Web-Testlauf 162/162 grün, `pnpm --filter @tessera/web run build` fehlerfrei
|
||||||
|
|
||||||
|
## Task Commits
|
||||||
|
|
||||||
|
Jeder Task wurde atomar committet:
|
||||||
|
|
||||||
|
1. **Task 1: Alle i18n-Schlüssel der Phase und der sechste Admin-Navigationseintrag** - `90dc398` (feat)
|
||||||
|
2. **Task 2: Gruppenübersicht mit Anlege-, Umbenennen- und AD-Bindungs-Dialog** - `c3ba1f7` (feat)
|
||||||
|
3. **Task 3: Mitglieder-Dialog und Löschdialog mit konkreten Zahlen** - `4985e43` (feat)
|
||||||
|
|
||||||
|
**Plan metadata:** siehe Commit dieser SUMMARY.md (docs: complete plan)
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
- `apps/web/src/app/(portal)/admin/groups/page.tsx` - Gruppenübersicht, State/Fetch-Logik, Standardgruppen-Stern-Toggle, hängt alle drei Dialoge ein
|
||||||
|
- `apps/web/src/app/(portal)/admin/groups/components/GroupFormModal.tsx` - Anlegen/Umbenennen inkl. AD-Radio-Bindung
|
||||||
|
- `apps/web/src/app/(portal)/admin/groups/components/GroupMembersModal.tsx` - Mitglieder-Chips + manuelles Hinzufügen per Benutzersuche
|
||||||
|
- `apps/web/src/app/(portal)/admin/groups/components/DeleteGroupDialog.tsx` - Löschdialog mit `impact`-Zahlen und sichtbarem Fehlerfall
|
||||||
|
- `apps/web/src/app/(portal)/admin/groups/groups-page.test.tsx` - 7 Komponententests
|
||||||
|
- `apps/web/src/messages/de.json`, `en.json` - alle i18n-Schlüssel der gesamten Phase 15
|
||||||
|
- `apps/web/src/components/admin/admin-sidebar.tsx` - sechster Navigationseintrag
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
- Task 2/3-Split von `page.tsx`: Task 2 committet die Seite mit Create/Edit-Modal verdrahtet und Mitglieder-/Lösch-State bereits deklariert, aber ohne Import der (in Task 2 noch nicht existierenden) Task-3-Komponenten — jeder Task-Commit bleibt für sich buildbar
|
||||||
|
- Gruppen-Erstellung mit sofortiger AD-Bindung läuft zweistufig (`POST /groups`, dann `PATCH /groups/:id {ldapDn}`), weil `CreateGroupDto` aus 15-02 ausschliesslich `name` entgegennimmt — keine Schema-/DTO-Änderung, reine Client-Sequenzierung
|
||||||
|
- `matrixCheckboxLabel`/`directCheckboxLabel` (Wave-4-Schlüssel für 15-07/15-08) als next-intl-ICU-`select` mit einem zusätzlichen `granted`-Parameter modelliert (`{module} für Gruppe {group} {granted, select, true {freigeben} other {entziehen}}`), damit ein einziger Schlüssel beide Aria-Label-Varianten (freigeben/entziehen) bedient, statt zwei separate Schlüssel für denselben Text-Baustein anzulegen
|
||||||
|
- `DeleteGroupDialog` behandelt einen fehlgeschlagenen `impact`-Abruf (nicht nur den Lösch-Aufruf selbst) sichtbar und deaktiviert den Löschen-Button, statt mit `memberCount: 0`/`grantCount: 0` eine falsche Zahl zu zeigen — D-17 verlangt konkrete, korrekte Zahlen, ein Fallback auf 0 wäre irreführend
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
### Auto-fixed Issues
|
||||||
|
|
||||||
|
**1. [Rule 2 - fehlende Funktionalität] DeleteGroupDialog behandelt einen fehlgeschlagenen impact-Abruf sichtbar**
|
||||||
|
- **Found during:** Task 3, beim Implementieren von `DeleteGroupDialog`
|
||||||
|
- **Issue:** Der Plan beschreibt nur den Fehlerfall des eigentlichen `DELETE`-Aufrufs explizit; ein fehlschlagender `GET /groups/:id/impact`-Aufruf hätte sonst entweder eine `undefined`-Anzeige oder (schlimmer) eine falsche `0`/`0`-Zahl gezeigt — beides würde D-17 verletzen, das konkrete, korrekte Zahlen verlangt
|
||||||
|
- **Fix:** `impactError`-State zeigt bei fehlgeschlagenem Impact-Abruf den Fehler-Div statt des Warntexts und deaktiviert den Löschen-Button, bis die Zahlen tatsächlich geladen sind
|
||||||
|
- **Files modified:** `apps/web/src/app/(portal)/admin/groups/components/DeleteGroupDialog.tsx`
|
||||||
|
- **Commit:** `4985e43`
|
||||||
|
|
||||||
|
**2. [Rule 2 - fehlende Funktionalität] ICU-select für matrixCheckboxLabel/directCheckboxLabel statt reiner Freigeben-Formulierung**
|
||||||
|
- **Found during:** Task 1, beim Anlegen der Wave-4-Schlüssel `admin.groups.grants.matrixCheckboxLabel` und `admin.users.grants.directCheckboxLabel`
|
||||||
|
- **Issue:** Der Copywriting Contract des UI-SPEC beschreibt für dieselbe Checkbox zwei Textvarianten ("… freigeben" bzw. "… entziehen" je nach Zustand), der Plan listet aber nur je einen Schlüssel mit den Parametern Modul/Gruppe bzw. Modul/Benutzer — ohne einen dritten Parameter hätte der Schlüssel nur eine der beiden Zustandsvarianten abdecken können
|
||||||
|
- **Fix:** Beide Schlüssel nutzen next-intl-kompatible ICU-`select`-Syntax mit einem zusätzlichen `granted`-Boolean-Parameter, der zwischen den beiden Verbformen wählt — bleibt bei genau einem Schlüssel pro aria-label, wie im Plan vorgegeben
|
||||||
|
- **Files modified:** `apps/web/src/messages/de.json`, `apps/web/src/messages/en.json`
|
||||||
|
- **Commit:** `90dc398`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Total deviations:** 2 auto-fixed (beide Rule 2 — fehlende Funktionalität)
|
||||||
|
**Impact on plan:** Beide Ergänzungen waren für Korrektheit (D-17) bzw. Vollständigkeit der Wave-4-Schlüssel notwendig. Kein Scope Creep — beide bleiben innerhalb der im Plan beschriebenen Dateien und Verantwortlichkeiten.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
- Diese Session lief ohne Browser-/Playwright-Tool (nur Read/Write/Edit/Bash/Skill verfügbar). Der im Plan unter `<verification>` geforderte manuelle Durchklick-Test im Browser (Anlegen, Umbenennen, Standardmarkierung, AD-Bindung setzen/lösen, Mitglied hinzufügen/entfernen, Löschdialog mit gefüllter Gruppe, sowie AD-Suche/Löschen bei abgeschalteter API) konnte nicht ausgeführt werden. Abgedeckt ist stattdessen: voller Vitest-Lauf (162/162 grün, davon 7 neue Tests für diesen Plan), fehlerfreier Produktions-Build inkl. Next.js-Typecheck, und alle grep-basierten `acceptance_criteria` aus allen drei Tasks. Als `coverage`-Eintrag D5 (`human_judgment: true`) und in `.planning/WINDOWS.md` als `unrun-verify` vermerkt — ein menschlicher Durchklick-Test vor dem Ship dieser Phase wird empfohlen.
|
||||||
|
- Die lokale Dev-DB hat nur einen Mandanten mit einer Gruppe ("Alle Benutzer", laut lokaler Notiz aktuell `isDefault = false`). Dieser Plan hat die DB in dieser Session nicht angefasst — kein Stern-Toggle wurde live gegen die lokale API ausgeführt (siehe Issue oben), der DB-Zustand ist unverändert gegenüber dem Sessionstart.
|
||||||
|
|
||||||
|
## User Setup Required
|
||||||
|
|
||||||
|
None - keine externe Service-Konfiguration nötig.
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
|
||||||
|
- `de.json`/`en.json` sind vollständig für die gesamte Phase 15 vorbereitet — 15-07 und 15-08 können parallel laufen, ohne die Übersetzungsdateien anzufassen
|
||||||
|
- `/admin/groups` ist vollständig nutzbar (PERM-01): Gruppen anlegen/umbenennen/löschen, Mitglieder manuell zuweisen/entfernen, AD-Bindung setzen/lösen, Standardgruppe markieren
|
||||||
|
- Empfehlung vor `/gsd-ship` dieser Phase: einmaliger manueller Durchklick-Test im Browser (siehe Issues Encountered/D5), da diese Session ohne Browser-Tool lief
|
||||||
|
- Kein neuer Blocker aus diesem Plan; 15-04 (AD-Gruppen-Mitgliedschafts-Sync) blieb wie in den Files-to-read vermerkt an einem offenen Human-Verify-Checkpoint stehen (nicht Teil dieses Plans) — dessen `15-04-SUMMARY.md` existiert entsprechend noch nicht
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 15-modul-berechtigungen-gruppen-user-grants*
|
||||||
|
*Completed: 2026-08-04*
|
||||||
|
|
||||||
|
## Self-Check: PASSED
|
||||||
|
|
||||||
|
Alle neun in dieser SUMMARY genannten Dateien existieren auf der Platte, alle drei Task-Commit-Hashes (`90dc398`, `c3ba1f7`, `4985e43`) sind im Git-Log auffindbar.
|
||||||
Reference in New Issue
Block a user