Documents the GroupFormModal three-state rebuild (D-03/D-04/D-07), the groups-list internalName fallback, and the ldapBind i18n cleanup for Phase 16 Plan 4.
15 KiB
phase, plan, subsystem, tags, requires, provides, affects, actuals, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, coverage, duration, completed, status
| phase | plan | subsystem | tags | requires | provides | affects | actuals | tech-stack | key-files | key-decisions | patterns-established | requirements-completed | coverage | duration | completed | status | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 16-ad-gruppen-synchronisation | 04 | ui |
|
|
|
|
|
|
|
|
|
|
3min (Commit-Spanne 16:28:07 bis 16:30:49; Kontext-Lesen davor nicht mitgerechnet) | 2026-08-06 | complete |
Phase 16 Plan 4: Gruppen-Dialog auf Anlegen/Umbenennen/Import-Herkunft zurueckgebaut Summary
GroupFormModal.tsx verliert restlos die AD-Radio-Auswahl und den zweistufigen Anlegen-dann-Binden-Ablauf (D-07); an ihre Stelle tritt ein gesperrtes Namensfeld mit sichtbarer AD-Herkunft plus editierbarem internem Namen fuer importierte Gruppen (D-03/D-04), ein sichtbarer statt stummer Speicherfehler mit Namenskollisions-Unterscheidung, und eine Gruppenliste, die den internen Namen mit AD-Name-Tooltip zeigt.
Performance
- Duration: 3 min (Commit-Spanne
30affbb16:28:07 Uhr bise900b4316:30:49 Uhr; Lesen von PLAN.md, 16-02-SUMMARY.md, PATTERNS.md, UI-SPEC.md und der Zieldateien davor nicht mitgerechnet) - Started: 2026-08-06T16:28:07+02:00 (erster Task-Commit)
- Completed: 2026-08-06T16:30:49+02:00 (dritter Task-Commit)
- Tasks: 3
- Files modified: 5
Accomplishments
GroupFormModal.tsxauf drei klar getrennte Zustaende zurueckgebaut (Anlegen / lokal bearbeiten / importiert bearbeiten) — der komplette AD-Bindungsblock (Discovery-State,useEffect, Radio-Liste, Bindung-entfernen-Link, zweiter PATCH im Anlegen-Zweig) ist restlos entfernt; ein manipulierter Client kann eine lokale Gruppe ueber diesen Dialog nicht mehr an AD binden (D-07)- Importierte Gruppen zeigen ein deaktiviertes Namensfeld mit Herkunftshinweis, eine reine
AD-DN:-Anzeigezeile und ein unabhaengiges, editierbares Feld "Interner Name" — gespeichert wird in diesem Zustand ausschliesslich{ internalName }per PATCH, niename(D-03, D-04) - Ein einziger
method: 'PATCH'-Aufrufblock bedient sowohl den lokalen Rename- als auch deninternalName-Pfad — die Payload wird vor dem Aufruf perisImported-Verzweigung gebaut, kein zweiter Schreibpfad - Speicherfehler werden nicht mehr stumm verschluckt: der bisherige
catch {}ist durch einen sichtbarentext-sm text-destructive-Zustand ersetzt, der bei HTTP 409saveErrorNameTakenstatt der generischensaveError-Meldung zeigt; der Dialog bleibt in jedem Fehlerfall offen, Eingaben bleiben erhalten Group.internalNameim Frontend-Typ ergaenzt; die Namenszelle der Gruppenliste rendertinternalName ?? name(Nullish, nicht Truthiness) mit dem AD-Namen alstitle-Tooltip — die Badge-Spalte bleibt unveraendert der alleinige "importiert vs. lokal"-Marker- Sechs verwaiste
admin.groups.ldapBind.*-Schluessel ausde.jsonUNDen.jsonentfernt, inklusive des toten Duplikats im Test-Uebersetzungs-Mock; Schluesselparitaet zwischen beiden Sprachen bestaetigt per Node-Check - Vollstaendige Web-Testsuite gruen: 32 Testdateien, 192 Tests (davon 4 neue Faelle aus diesem Plan)
Task Commits
Each task was committed atomically:
- Task 1: GroupFormModal auf drei Zustaende zurueckbauen (D-03, D-04, D-07) -
30affbb(feat) - Task 2: Namensanzeige mit Fallback in der Gruppenliste (D-04) -
6802b48(feat) - Task 3: Verwaiste Uebersetzungsschluessel entfernen und D-07 im Test festnageln -
e900b43(test)
Plan metadata: wird mit diesem Summary committet
Note: Kein TDD-Task in diesem Plan (tdd nicht auf einem Task gesetzt) — je ein feat/feat/test-Commit.
Files Created/Modified
apps/web/src/app/(portal)/admin/groups/components/GroupFormModal.tsx- AD-Bindungsblock vollstaendig entfernt; drei Zustaende (Anlegen/lokal/importiert), gesperrtes Namensfeld,internalName-Feld, sichtbarer 409-unterscheidender Fehlerzustandapps/web/src/app/(portal)/admin/groups/page.tsx-Group.internalName: string | nullim Interface; Namenszelle nutztinternalName ?? namemittitle={name}-Tooltipapps/web/src/app/(portal)/admin/groups/groups-page.test.tsx-internalNameim lokalenGroup-Interface und inmockGroups; neuemockGroupsWithInternalName-Fixture; vier neue Testfaelle (Namensfallback + Tooltip, D-07 kein AD-Request beim Anlegen, gesperrtes Namensfeld + internes Namensfeld beim Bearbeiten einer importierten Gruppe); toterldapBind-Block im Uebersetzungs-Mock durch die sieben neuen Task-1-Schluessel ersetztapps/web/src/messages/de.json/en.json- sieben neueadmin.groups.*-Schluessel (nameLockedHint,adDnLabel,internalName,internalNameHint,createLdapHint,goToLdap,saveErrorNameTaken); sechs verwaisteldapBind.*-Schluessel entfernt
Decisions Made
Group.internalNamewurde bereits in Task 1 zumGroup-Interface inpage.tsxergaenzt, nicht erst in Task 2 wie im Plan vorgesehen —GroupFormModal.tsxreferenziertgroup.internalNameund kompiliert ohne das Feld nicht (tsc --noEmitist Teil von Task 1s eigenem Verify-Block). Task 2 fand das Feld bereits vor und konzentrierte sich wie geplant auf die Namenszelle und die zugehoerigen Tests.- Der verwaiste
ldapBind-Block im next-intl-Uebersetzungs-Mock der Testdatei wurde zusaetzlich zu den beiden echten Sprachdateien entfernt — das war nicht woertlich im Plan gefordert, aber eine tote Kopie desselben Schluesselbaums, deren Entfernung im Sinne von Task 3 liegt (keine verwaisten Schluesselverweise irgendwo im Web-Verzeichnis). - PERM-02 bleibt in
REQUIREMENTS.mdunveraendert auf[ ](Pending) — dieser Plan liefert den vierten von fuenf geplanten Bausteinen; das Requirement schliesst laut Plan-Vorgabe erst mit Plan 16-05.
Deviations from Plan
Auto-fixed Issues
1. [Rule 3 - Blocking] Group.internalName musste vor Task 2 ergaenzt werden, da GroupFormModal.tsx sonst nicht kompiliert
- Found during: Task 1 (eigener
tsc --noEmit-Verify-Schritt) - Issue:
GroupFormModal.tsxliestgroup?.internalNameundgroup.internalName(fuer den AD-DN-Block), aber dasGroup-Interface inpage.tsx(aus dem der Typ importiert wird) hatte das Feld noch nicht — laut Plan sollte das erst in Task 2 ergaenzt werden. Ohne das Feld schlaegttsc --noEmitbereits fuer Task 1 fehl. - Fix:
internalName: string | null;zumGroup-Interface inpage.tsxals Teil des Task-1-Commits ergaenzt (identische Nullbarkeit wieldapDn, wie vom Plan fuer Task 2 spezifiziert). Task 2 fand das Feld vor und musste es nicht erneut hinzufuegen. - Files modified: apps/web/src/app/(portal)/admin/groups/page.tsx
- Verification:
cd apps/web && npx tsc --noEmitfehlerfrei - Committed in:
30affbb(Task 1)
2. [Rule 1 - Bug] t('adDnLabel', { ldapDn: group.ldapDn }) liess sich nicht typsicher aufrufen
- Found during: Task 1 (
tsc --noEmit) - Issue:
group.ldapDniststring | null; dieuseTranslations-Interpolationsfunktion erwartetstring | number | Datefuer Platzhalterwerte. ObwohlisImportedan dieser Stelle logisch bereitsgroup.ldapDn !== nullgarantiert, engt TypeScript den Typ ueber die separateisImported-Variable nicht ein. - Fix:
group.ldapDn ?? ''an der Aufrufstelle — der Leerstring-Fall tritt zur Laufzeit nie ein, da der Block nur beiisImported === truegerendert wird. - Files modified: apps/web/src/app/(portal)/admin/groups/components/GroupFormModal.tsx
- Verification:
cd apps/web && npx tsc --noEmitfehlerfrei - Committed in:
30affbb(Task 1)
Total deviations: 2 auto-fixed (1× Rule 3 Blocker, 1× Rule 1 Typfehler) — beide innerhalb von Task 1 aufgetreten und behoben, kein Einfluss auf den Funktionsumfang. Impact on plan: Kein Scope Creep. Der Rule-3-Fix zieht lediglich eine im Plan fuer Task 2 vorgesehene Interface-Erweiterung um einen Task vor, weil eine harte Kompilierabhaengigkeit besteht, die der Plan nicht explizit adressiert hatte.
Issues Encountered
None.
User Setup Required
None - keine externe Service-Konfiguration erforderlich. Der laufende Docker-Stack (lokal) wurde von diesem Plan nicht angefasst; die Aenderungen liegen im Web-Quellcode und werden erst mit einem --build/--force-recreate durch den Nutzer wirksam.
Known Stubs
Keine. Beide neuen Testfaelle in groups-page.test.tsx (Namensfallback/Tooltip, D-07-Regression) laufen gegen echte Rendering-Pfade der Komponente, keine hartkodierten Platzhalterwerte.
Next Phase Readiness
GroupFormModal.tsxist jetzt der endgueltige, dreizustandsfaehige Dialog fuer Plan 16-05 — kein weiterer Rueckbau an dieser Datei erwartetinternalName ?? nameist jetzt an allen vier geplanten Anzeigestellen implementiert:listForTenant()und beidegetUserAccess()-Projektionen (16-02), sowie die Gruppenliste (dieser Plan). Verbleibend fuer Plan 16-05 laut 16-02-Summary:admin/modules/grants/page.tsx-Spaltenkopf (Surface Contract 5)- Der manuelle Browser-Durchklick aus dem Plan-Verification-Block (drei Dialog-Zustaende inkl. 409-Fehleranzeige, Namensanzeige mit Tooltip nach dem Speichern) ist als WINDOWS.md #5 offen — vor
/gsd-shipnachzuholen, kein Browser-Tool in dieser Session verfuegbar - PERM-02 bleibt bewusst auf Pending — schliesst mit Plan 16-05
Phase: 16-ad-gruppen-synchronisation Completed: 2026-08-06