wiki/c-work/4-done/2026-05-udb-toggle-spec-recovery.md

85 lines
3.8 KiB
Markdown

<!-- status: validate -->
<!-- started: 2026-05-26 -->
<!-- component: platform-core | ui-nyla -->
<!-- lastReviewed: 2026-05-26 -->
# UDB Toggle Spec Recovery
## Kontext
Nach dem Generic Tree Refactor (2026-05-18) waren im Code sechs Aggregations-Routinen
(`_aggregatePersonalRoot`, `_aggregateConnection`, `_aggregateMandateGroup`,
`_resolveAttrsForKey`, `getAttributesForKeys`), ein paralleler Endpoint
`POST /tree/attributes` und ein Bug bei virtuellen Coordinates (kein aggregate
fuer Records ohne DB-Eintrag) entstanden. Das Frontend nutzte `refreshAttributes`
als optionalen Pfad und `refreshAfterAction` als Opt-in-Prop, obwohl die Spec
nur einen Pipeline-Pfad vorsieht.
## Ziel
Wiederherstellung der dokumentierten Spec (2026-05-18 "Generic Tree Refactor"):
**Eine** Pipeline, **ein** Resolver, **ein** Mixed-Symbol, **drei** Flags
generisch durch denselben Code-Pfad. Keine optimistic updates, keine
Fallbacks, keine doppelte Logik.
## Durchgefuehrte Aenderungen
### S1 - Backend: virtuelle Coordinates auf aggregate-Pfad
`_inheritFlags.py`: `resolveEffectiveForPath` und `resolveEffectiveForFds` rufen
im else-Zweig (virtual record, kein DB-Match) nun `getEffectiveFlag(virtualRec, flag, allDs, mode=mode)`
bzw. `getEffectiveFlagFds(...)` statt `_resolveWalkValue` auf. Damit koennen
virtuelle Coordinates (z.B. Connection ohne eigenen Root-Record) korrekt
`'mixed'` zurueckgeben, wenn ihre Descendants divergieren.
### S2 - Backend: sechs Aggregatoren entfernt
`_buildTree.py`: Geloescht: `_aggregatePersonalRoot`, `_aggregateConnection`,
`_aggregateMandateGroup`, `_resolveAttrsForKey`, `getAttributesForKeys`.
Diese waren ausschliesslich fuer den parallelen `tree/attributes`-Endpoint noetig.
Synthetic Container (`personalRoot`, `mgrp`) haben laut Spec keine Flags
(UI blendet sie aus); data-bearing Nodes nutzen bereits
`resolveEffectiveForPath`/`resolveEffectiveForFds` via den tree builder.
### S3 - Backend: Endpoint tree/attributes entfernt
`routeFeatureWorkspace.py`: Route `POST /{instanceId}/tree/attributes` und
Model `_TreeAttributesRequest` ersatzlos geloescht.
### S4 - Frontend: refreshAttributes-Pfad entfernt
- `UdbSourcesProvider.tsx`: `refreshAttributes`-Methode entfernt.
- `FolderFileProvider.tsx`: `refreshAttributes`-Methode entfernt.
- `FormGeneratorTree.tsx`: `_refreshVisibleAttributes` nutzt nur noch den
Refetch-All-Expanded-Pfad. `_runAction` ruft immer `_refreshVisibleAttributes`
ohne Bedingung. `refreshAfterAction`-Prop entfernt.
- `types.ts`: `refreshAttributes` aus `TreeNodeProvider`, `refreshAfterAction`
aus `FormGeneratorTreeProps` entfernt.
- `SourcesTab.tsx`, `FilesTab.tsx`: `refreshAfterAction`-Prop-Nutzung entfernt.
### S5 - Klick-Semantik dokumentiert
`wiki/b-reference/platform/neutralization.md`: Klick auf mixed-Symbol setzt
explizit `false` (alle Flags). Begruendung: Toggle behaelt zwei klare
End-Zustaende; Reset auf `null`/inherit durch Parent-Toggle.
### S6 - Tests
8 neue Tests in `test_inheritFlags.py::TestVirtualCoordAggregate`:
- virtual folder mixed neutralize/scope/rag
- virtual folder uniform returns concrete
- virtual FDS workspace mixed/uniform
- virtual connection root mixed via diverging services
Frontend-Test `refreshAfterAction` angepasst: zweiter Test (does NOT refetch
when false) entfernt, da Verhalten nun immer refetch ist.
Resultat: `test_inheritFlags.py` 79/79 gruen, `test_buildTree.py` 19/19 gruen.
## Validierung (Smoke-Tests vor Merge)
1. Folder mit zwei Subfolders, einer toggeln -> Parent zeigt mixed, Root zeigt mixed, Personal Root zeigt mixed.
2. Parent toggeln (war mixed) -> Parent + alle Descendants zeigen den Parent-Wert.
3. Klick auf mixed-Symbol -> setzt explizit `false`, Spinner bleibt bis Refetch durch ist.
4. Toggle in collapsed Subtree (verstecktem Knoten) -> nach expand zeigt Subtree die neuen Werte.
5. Mandate mit zwei Workspaces, einer toggeln -> mgrp zeigt mixed.