20 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 | 03 | auth |
|
|
|
|
|
|
|
|
|
|
|
12min | 2026-08-06 | complete |
Phase 16 Plan 3: Gruppen-Rekonziliation gegen das Verzeichnis Summary
syncBoundGroupsForTenant() unterscheidet AD-Umbenennung von AD-Verschwinden ueber den rename-stabilen ldapObjectGuid, laeuft nachweislich vor dem Mitgliedschafts-Abgleich, uebergibt die Standardmarkierung vor jeder Loeschung und traegt Alt-Bindungen aus Plan 15-06 nach — die A1/A2-Live-Pruefung gegen ein echtes Active Directory bleibt offen (kein AD in dieser Sandbox erreichbar).
Performance
- Duration: 12 min (Commit-Spanne 16:15:09 Uhr bis 16:21:10 Uhr; Lesen von PLAN.md, 16-01-/16-02-SUMMARY.md, PATTERNS.md, RESEARCH.md und der Zieldateien davor nicht mitgerechnet)
- Started: 2026-08-06T14:15:09Z (erster Task-Commit)
- Completed: 2026-08-06T14:21:10Z (zweiter Task-Commit)
- Tasks: 2
- Files modified: 3
Accomplishments
- Neue private Methode
LdapService.syncBoundGroupsForTenant(): fragt alle Gruppen mit gesetztemldapObjectGuidODERldapDnab (der D-07-Anschluss fuer Alt-Bindungen), tut fuer eine rein lokale Gruppe (beide Feldernull) nichts und loest dafuer keine einzige LDAP-Suche aus - Rename-Erkennung (SC-3): ein AD-Treffer mit geaendertem
cn/dnziehtGroup.name/Group.ldapDnnach,internalNamebleibt in jedem Codepfad der Methode unberuehrt (D-04); einP2002aus einer Namenskollision wird abgefangen und als Fehlerzeile gemeldet, der Lauf geht weiter - Verschwinden-Loeschung (SC-4/D-05): kein Treffer im binaeren Existenz-Sweep loescht die Gruppe — aber immer erst NACH dem Standardmarkierungs-Handoff (
reassignDefaultBeforeDelete, Plan 16-02), nachweislich in dieser Zeilenreihenfolge; nach jeder Loeschung laeuftensureDefaultGroup()einmal, damit kein Mandant ohne Standardgruppe dasteht (D-06) - Alt-Bindungs-Nachtrag (D-07): eine Gruppe mit
ldapDn, aber ohneldapObjectGuid, bekommt den Identitaetsschluessel per Base-Scoped-Lookup einmalig nachgetragen (groupsAdopted) und wird im selben Lauf reguelaer weiterverarbeitet; loest der DN nicht mehr auf, wird nicht geloescht, nur eine Fehlerzeile erzeugt — ohne stabilen Schluessel waere eine Loeschung eine Vermutung - Der gespeicherte Hex-Wert wird vor jeder Filter-Interpolation auf exakt 32
[0-9a-f]-Zeichen validiert (T-16-01); ein ungueltiger Wert erzeugt eine Fehlerzeile statt einer Filter-Interpolation - Schritt 5a (
syncBoundGroupsForTenant) laeuft insyncUsersForTenant()nachweislich VOR Schritt 5b (syncGroupMembershipsForTenant, D-21) — abgesichert durch einen beobachtenden Call-Order-Test (nicht nur durch Kommentartext), plus einen Regressionstest, der zeigt, dass ein im selben Lauf erkannter Rename zu keinemmemberOf-Filter mit der alten DN mehr fuehrt LdapService-Konstruktor nimmt neuGroupsServiceentgegen;LdapModuleimportiertGroupsModule(kein Zyklus, daGroupsModulewederLdapModulenochUserModuleimportiert)- 17 neue Testfaelle (14 fuer die neue Methode isoliert, 3 fuer die Verdrahtungsreihenfolge); vollstaendige API-Testsuite gruen: 40 Testdateien, 560 Tests
Task Commits
Each task was committed atomically:
- Task 1: Gruppen-Rekonziliation gegen das Verzeichnis (SC-3, SC-4, SC-5, D-05, D-06) —
5222934(feat, tdd) - Task 2: Einhaengen als Schritt 5a vor dem Mitgliedschafts-Abgleich (RESEARCH.md Pitfall 1) —
68aca81(feat, tdd)
Plan metadata: wird mit diesem Summary committet
Files Created/Modified
apps/api/src/ldap/ldap.service.ts—LdapSyncResultumgroupsAdopted/groupsRenamed/groupsDeleted/defaultMarkerMovederweitert; Konstruktor nimmtGroupsService; neue private MethodesyncBoundGroupsForTenant(); Aufruf als Schritt 5a insyncUsersForTenant()vor Schritt 5bapps/api/src/ldap/ldap.module.ts—GroupsModule-Import ergaenztapps/api/src/ldap/ldap.service.spec.ts— zwei neuedescribe-Bloecke (syncBoundGroupsForTenantmit 14 Faellen,Schrittreihenfolge Gruppen vor Mitgliedschaftenmit 3 Faellen); alle achtnew LdapService(...)-Konstruktionen um einen dritten Mock-Parameter ergaenzt; D-21-Block-Fixtures um eine 5a-No-Op-Aufloesung im gemeinsamenmockSearcherweitert, ohne jede der ueber zehn Einzel-Fixtures anzufassen
Decisions Made
syncBoundGroupsForTenant()wurde in Task 1 bewusst noch NICHT insyncUsersForTenant()eingehaengt (Plan-Vorgabe) — Task 1 testet die Methode per direktem Cast auf die private Methode, Task 2 liefert ausschliesslich die Verdrahtung samt Reihenfolge-Test. Diese Trennung macht die zentrale Korrektheitsbedingung der Phase (Reihenfolge) als eigenen, isoliert nachvollziehbaren Schritt sichtbar.- Statt jede der ueber zehn D-21-Test-Fixtures (aus Plan 15, vor Plan 16 gebaut, nie mit
ldapObjectGuidversehen) einzeln um ein Feld zu erweitern, wurde der gemeinsamemockSearchim D-21-Block um eine deterministische No-Op-Aufloesung fuer beide 5a-Filterformen erweitert (DN-abgeleitete GUID, Identitaets-Treffer bei unveraendertemcn/dn). Kleinerer, zentralerer Diff; die D-21-Tests bleiben inhaltlich unveraendert auf die Mitgliedschafts-Reconciliation fokussiert. - PERM-02 bleibt in
REQUIREMENTS.mdbewusst auf[ ](Pending) — dieser Plan liefert Rekonziliation und Verdrahtung, das Requirement schliesst laut Plan-Vorgabe erst mit Plan 16-05.
Deviations from Plan
Auto-fixed Issues
1. [Rule 1 - Bug] Bestehender D-21-Test brach nach der additiven LdapSyncResult-Erweiterung (exaktes toEqual)
- Found during: Task 1
- Issue: Der Test „creates nobody and deactivates nobody when the base DN is empty" verglich
resultpertoEqualgegen ein Literal ohne die vier neuen Felder — nach der additiven Interface-Erweiterung schlug der Vergleich fehl, obwohl das Verhalten unveraendert korrekt war. - Fix: Die vier neuen Felder (
groupsAdopted: 0, groupsRenamed: 0, groupsDeleted: 0, defaultMarkerMoved: 0) im erwarteten Literal ergaenzt. - Files modified: apps/api/src/ldap/ldap.service.spec.ts
- Verification:
npx vitest run src/ldap/ldap.service.spec.tsgruen - Committed in:
5222934
2. [Rule 1 - Bug] Wiederverwendete GUID-Test-Fixture aus Plan 16-01 war tatsaechlich nur 31 Hex-Zeichen lang
- Found during: Task 1
- Issue: Der bestehende
guidBuffer-Fixture-String im "AD group import"-Block ('0123456789abcdef0123456789abcde') ist bei genauer Zaehlung 31, nicht 32 Zeichen lang —Buffer.from(..., 'hex')schneidet das letzte ungerade Zeichen stumm ab und liefert 15 statt 16 Bytes zurueck. Das fiel dort nie auf, weilimportGroupsByDn()die Laenge nie validiert; die neue 32-Hex-Validierung insyncBoundGroupsForTenant()(T-16-01) schlug mit demselben Wert sofort fehl. - Fix: Eigene, lokal im neuen
describe-Block definierte, garantiert 32 Zeichen lange Fixture ('0123456789abcdef'.repeat(2)) statt den bestehenden (fehlerhaften) Fixture-String zu teilen. Der bestehende Fixture-String im 16-01-Block wurde NICHT angefasst (aussarhalb des Scopes dieses Plans, dortige Tests bleiben unveraendert gruen). - Files modified: apps/api/src/ldap/ldap.service.spec.ts
- Verification:
npx vitest run src/ldap/ldap.service.spec.tsgruen, neuer Kommentar dokumentiert den Unterschied explizit - Committed in:
5222934
3. [Rule 1 - Bug] Verdrahtung in Task 2 brach vier bestehende D-21-Tests (Schritt 5a lief nun ungewollt gegen deren Fixtures)
- Found during: Task 2
- Issue: Nach dem Einhaengen von Schritt 5a liefen die vorher isoliert getesteten D-21-Membership-Tests real durch
syncUsersForTenant()— deren Gruppen-Fixtures (nurldapDn, keinldapObjectGuid, vor Plan 16 gebaut) loesten in jedem Lauf den Alt-Bindungs-Nachtragspfad aus und produzierten unerwuenschte Fehlerzeilen bzw. veraendertenresult.errors. - Fix: Der gemeinsame
mockSearchim D-21-beforeEach(und die eine Test-lokale Ueberschreibung im „records a search failure"-Test) um eine deterministische Aufloesung beider 5a-Filterformen erweitert (resolve5aNoOp-Helfer auf Describe-Ebene), die pro Fixture-Gruppe einen DN-abgeleiteten, immer gueltigen GUID annimmt und einen Identitaets-Treffer liefert — 5a wird dadurch fuer jede D-21-Fixture ein reiner No-Op, ohne die ueber zehn einzelnengroups = [...]-Literale anzufassen. - Files modified: apps/api/src/ldap/ldap.service.spec.ts
- Verification:
npx vitest run src/ldap/ldap.service.spec.ts— alle 55 Faelle gruen;npx vitest run— vollstaendige API-Suite (560 Tests) gruen - Committed in:
68aca81
Total deviations: 3 auto-fixed (alle Rule 1, direkte Folgen der additiven Interface-Erweiterung bzw. der Verdrahtung — kein Scope Creep, kein Architekturwechsel) Impact on plan: Keine Auswirkung auf Funktionalitaet oder Scope der neuen Methode selbst — alle drei Korrekturen betrafen ausschliesslich bestehende Testinfrastruktur, die durch additive/verdrahtende Aenderungen aus diesem Plan beruehrt wurde.
Outstanding Live Verification (A1/A2)
RESEARCH.md fuehrt zwei Annahmen, die dieser Plan gegen ein echtes Active Directory pruefen sollte (Task 2 <human-check>), aber in dieser Sandbox nicht pruefen konnte — es ist kein Active-Directory-Server erreichbar (Umgebungsvorgabe fuer diesen Ausfuehrungslauf, siehe <environment> im Auftrag):
- A1 —
objectGUIDuebersteht eine reine CN-Umbenennung unveraendert. Unverifiziert. Die gesamte Rename-Erkennung (SC-3) haengt an dieser Annahme — ist sie falsch, wuerde jede echte AD-Umbenennung weiterhin wie ein Verschwinden+Neuanlage behandelt. - A2 — die byteweise
\XX-Hex-Escaping-Syntax fuer den binaeren(objectGUID=...)-Filter wird vom Ziel-AD korrekt interpretiert. Unverifiziert. Ist sie falsch, liefert der Existenz-Sweep fuer JEDE gebundene Gruppe null Treffer — SC-4 (Loeschung) wuerde dann faelschlich auf jede weiterhin existierende Gruppe angewendet.
Beide Antworten stehen noch aus. Sie sind als offener Eintrag im projektweiten Broken-Windows-Ledger festgehalten: .planning/WINDOWS.md Eintrag #4 (kind: unrun-verify, phase: 16). Ein negatives Ergebnis bei A1 ODER A2 ist ein Stopp-Grund fuer die Loeschsemantik aus D-05 — die Implementierung darf in diesem Fall NICHT einfach "umgebogen" werden (so RESEARCH.md/PLAN.md ausdruecklich), sondern erfordert eine erneute Planungsentscheidung. Vor produktivem Einsatz der Loeschsemantik muss die read-only Pruefung gegen ViCoTest (balios.ctl.local) aus 16-VALIDATION.md nachgeholt werden: (1) eine AD-Gruppe suchen, objectGUID notieren, im AD umbenennen, erneut suchen, GUID vergleichen; (2) eine Suche mit dem byteweise escaped objectGUID-Filter absetzen und pruefen, ob sie exakt diese Gruppe zurueckliefert.
Gemaess workflow.human_verify_mode: end-of-phase wurde dieser Plan trotz der offenen Pruefung bis zum Ende ausgefuehrt, statt mittendrin anzuhalten — die offene Verifikation ist hier klar dokumentiert und im Ledger sichtbar, nicht stillschweigend uebersprungen.
Issues Encountered
Siehe Deviations oben — alle drei Punkte betrafen ausschliesslich bestehende Testinfrastruktur, die durch die additiven bzw. verdrahtenden Aenderungen dieses Plans beruehrt wurde, nicht die fachliche Logik der neuen Methode selbst.
User Setup Required
None — keine externe Service-Konfiguration erforderlich. Der laufende Docker-Stack (lokal) wurde von diesem Plan nicht angefasst; die Aenderungen liegen im Quellcode und werden erst mit einem --build/--force-recreate durch den Nutzer wirksam. Kein Deploy auf den Testserver durch diesen Lauf (Projektregel).
Next Phase Readiness
syncBoundGroupsForTenant()ist vollstaendig implementiert, verdrahtet und getestet — die Kernkorrektheitsbedingung der Phase (Reihenfolge vor dem Mitgliedschafts-Abgleich) ist durch einen beobachtenden Test abgesichert, nicht nur behauptet- Plan 16-04 (Dialog-Umbau) und 16-05 (Anzeige-Fallback Frontend, Requirement-Abschluss PERM-02) koennen auf dieser Grundlage aufsetzen
- Offener Punkt bleibt bestehen (WINDOWS.md #4): A1/A2-Live-Pruefung gegen ein echtes Active Directory (ViCoTest) muss nachgeholt werden, bevor die Loeschsemantik aus D-05 als produktionsreif gilt — siehe Abschnitt „Outstanding Live Verification" oben
Phase: 16-ad-gruppen-synchronisation Completed: 2026-08-06
Self-Check: PASSED
Alle 3 in diesem Plan genannten Quelldateien sowie dieses Summary existieren auf der Festplatte; beide Task-Commit-Hashes (5222934, 68aca81) sind im lokalen Git-Log auffindbar.