wiki/c-work/4-done/2026-04-trustee-data-tables-page.md
2026-06-02 09:42:12 +02:00

161 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- status: done -->
<!-- started: 2026-04-20 -->
<!-- finished: 2026-04-21 -->
<!-- component: gateway | ui-nyla -->
# Trustee: Konsolidierte Daten-Tabellen-Seite
## Beschreibung und Kontext
Aktuell hat das Trustee-Feature zwei separate Top-Level-Seiten für Datensichten (`Positionen`, `Dokumente`). Die übrigen 11 Trustee-Tabellen (Stammdaten + Sync-Daten + Buchhaltungs-Config/Sync) sind im UI **nicht sichtbar** nur als JSON-Export oder per AI-Agent erreichbar. Das ist intransparent: Anwender und Auditor:innen sehen die importierten Konten / Buchungen / Kontakte / Salden nirgends.
Lösung: Eine neue konsolidierte Seite `Daten-Tabellen` mit einem Tab pro Trustee-Tabelle. Jeder Tab nutzt `FormGeneratorTable` mit Pagination, Sortierung, Filterung und Suche exakt das Pattern, das `PromptsPage` und die bestehenden `TrusteePositionsView` / `TrusteeDocumentsView` etabliert haben.
Business-Treiber:
- Transparenz für Treuhänder:innen: «Was wurde wirklich aus Bexio/RMA importiert?»
- Audit-Fähigkeit: Sync-Status und Sync-Snapshots direkt im UI prüfen.
- Vereinheitlichung: Konsistente UI über alle Tabellen statt zwei isolierter Spezialseiten.
Risiko bei Verzicht: Anwender greifen via Export/Excel auf interne Daten zu (umständlich, fehleranfällig); Sync-Probleme bleiben unbemerkt.
## Fokus und kritische Details
- **FormGeneratorTable-Vertrag** (siehe `wiki/b-reference/ui-nyla/formgenerator.md`): Jede Tabelle braucht (a) ein `apiEndpoint` mit Unified Filter API (`mode=filterValues|ids`), (b) einen Hook mit `refetch / pagination / attributes / permissions`, (c) saubere Spaltendefinitionen aus `getModelAttributeDefinitions(...)`.
- **`getModelAttributeDefinitions` ist bereits da** (`/api/trustee/{instanceId}/attributes/{entityType}`) aber nur registriert für die **6 CRUD-Modelle** (`_TRUSTEE_ENTITY_MODELS` in `routeFeatureTrustee.py`, Zeile 195). Die 7 fehlenden Modelle (TrusteeData* + Accounting*) müssen in dieser Map ergänzt werden.
- **Sync-Tabellen sind read-only** (User-Entscheidung). Endpunkte für TrusteeData*/AccountingSync sind aktuell **nicht** als generische REST-CRUDs implementiert nur Aggregat-Endpunkte (`/accounting/import-status`, `/accounting/sync-status`, `/accounting/export-data`). Es braucht **neue Read-Endpunkte** mit Pagination + Unified Filter API.
- **RBAC-Konsistenz**: Jede Tabelle hat in `mainTrustee.DATA_OBJECTS` einen `data.feature.trustee.<Model>`-Key. Der Hook (`_createTrusteeEntityHook`) löst Permissions via `data.feature.trustee.{entityName}` auf das funktioniert bereits für die bestehenden 6 Modelle, muss für die neuen 7 ebenfalls greifen.
- **Backwards-Compat**: Die bestehenden Seiten `Positionen` und `Dokumente` bleiben **vorerst** erhalten (Navigation + Routes + RBAC). Erst wenn die neue Seite verifiziert ist, werden sie in einer Folge-Iteration entfernt.
- **Tab-State via URL** (`?tab=positions`): Konsistent mit `TrusteeImportProcessView`, `TrusteeAccountingSettingsView`, `TrusteeAbschlussView`. Erlaubt Deep-Links (z.B. Quick Actions / Notification-Links) auf konkrete Tabellen.
- **Performance**: Lazy-Mount pro Tab (Hook ruft nur Daten, wenn Tab aktiv ist) sonst werden 13 Tabellen parallel geladen.
- **i18n-Pflicht**: Alle Tab-Labels via `t(...)`. Spalten-Labels kommen aus dem Backend-`@i18nModel`.
- **Hidden System-Felder**: `mandateId`, `featureInstanceId`, technische `id`-UUIDs sollen tabellenweit hidden sein (gleiche Liste wie in PromptsPage `hiddenColumns`).
- **Naming**: Funktionen `_`-Prefix für intern (`_buildEntityHookConfig`, `_renderTabBar`); camelCase überall.
## Ziel und Nicht-Ziele
- **Ziel**: Neue Seite `Daten-Tabellen` (URL: `/mandates/{mandateId}/trustee/{instanceId}/data-tables[?tab=<key>]`) mit einem Tab pro Trustee-Tabelle. Jeder Tab nutzt `FormGeneratorTable` mit Pagination/Sort/Filter/Search/Inline-Edit (für CRUD-Tabellen) bzw. read-only (für Sync-Tabellen).
- **Ziel**: Backend liefert Attribute & paginierte Daten via Unified Filter API auch für die 7 bisher UI-losen Tabellen.
- **Ziel**: Tab-Sichtbarkeit folgt RBAC (`data.feature.trustee.<Model>` view-Permission).
- **Ziel**: Konsistentes UX-Pattern mit `PromptsPage` (Header / Refresh / FormGeneratorTable / optional Edit-Modal via FormGeneratorForm für CRUD-Tabellen).
- **Explizit NICHT**: Entfernen der alten `Positionen`/`Dokumente`-Seiten in dieser Iteration (Folge-Plan). Routen + Quick Actions + RBAC bleiben unangetastet.
- **Explizit NICHT**: Inline-Edit oder Bulk-Sync für TrusteeData*-Tabellen sie sind reine Sync-Spiegel.
- **Explizit NICHT**: Neuer DB-Schema-Wandel oder Migration nur Read-Endpunkte ergänzen.
- **Explizit NICHT**: Beleg-Download-Spalte oder Sync-Status-Spalte im Positions-Tab die Spezialdarstellung bleibt der eigenständigen `TrusteePositionsView` vorbehalten (Generic-Tab zeigt das «rohe» Modell).
## Betroffene Module
- **Gateway**:
- `platform-core/modules/features/trustee/routeFeatureTrustee.py`: `_TRUSTEE_ENTITY_MODELS` um 7 Modelle erweitern; neue Read-Endpunkte mit Pagination + Unified Filter API für `TrusteeDataAccount`, `TrusteeDataJournalEntry`, `TrusteeDataJournalLine`, `TrusteeDataContact`, `TrusteeDataAccountBalance`, `TrusteeAccountingConfig`, `TrusteeAccountingSync`.
- `platform-core/modules/features/trustee/mainTrustee.py`: `UI_OBJECTS` um `ui.feature.trustee.data-tables` ergänzen; `TEMPLATE_ROLES.accessRules` der relevanten Rollen erweitern.
- **Frontend**:
- **Neu**: `ui-nyla/src/pages/views/trustee/TrusteeDataTablesView.tsx` (Container mit Tab-Bar + URL-Sync).
- **Neu**: `ui-nyla/src/pages/views/trustee/dataTables/TrusteeDataTab.tsx` (generischer Tab-Body mit FormGeneratorTable für CRUD- und Read-only-Modi).
- **Erweitern**: `ui-nyla/src/hooks/useTrustee.ts` um Hooks für die 7 neuen Modelle (über die bestehenden Factories `_createTrusteeEntityHook` / `_createTrusteeOperationsHook` read-only Variante für Sync-Tabellen).
- **Erweitern**: `ui-nyla/src/api/trusteeApi.ts` um `fetchTrusteeData*`-Funktionen.
- **Anpassen**: `ui-nyla/src/pages/FeatureView.tsx` (`VIEW_COMPONENTS.trustee` um `'data-tables': TrusteeDataTablesView` ergänzen).
- **Anpassen**: `ui-nyla/src/pages/views/trustee/index.ts` (Export).
- **Anpassen**: `ui-nyla/src/App.tsx` (Route `data-tables` registrieren).
- **Optional**: `ui-nyla/src/types/mandate.ts` (`FEATURE_REGISTRY.trustee.views`) um `data-tables` ergänzen, falls noch genutzt.
- **DB-Migration**: nein.
- **Andere Komponenten**: keine.
## Entscheidungen
| Datum | Entscheidung | Begründung |
|-------|-------------|------------|
| 2026-04-20 | Seitenname: `Daten-Tabellen` | User-Entscheidung; klar, präzise, dt. |
| 2026-04-20 | Alte Seiten `Positionen` + `Dokumente` bleiben vorerst | User-Entscheidung; Sicherheitsnetz bis neue Seite verifiziert ist Aufräumen in Folge-Plan. |
| 2026-04-20 | Sync-Tabellen (`TrusteeData*`, `TrusteeAccountingSync`, `TrusteeAccountingConfig`) sind read-only im UI | User-Entscheidung; Daten kommen aus externem System Edits würden bei nächstem Sync überschrieben. |
| 2026-04-20 | Alle 13 Tabellen erhalten einen Tab (User wählte "alle" im Datenmodell sind es 13: 4 Stammdaten + 2 CRUD-Daten + 5 Sync-Daten + 2 Accounting). | User-Entscheidung; vollständige Transparenz. |
| 2026-04-20 | Tab-State via URL-Param `?tab=<key>` | Konsistent mit allen anderen Trustee-Tab-Seiten. |
| 2026-04-20 | Lazy-Mount pro Tab (kein Pre-Fetch der inaktiven Tabs) | Performance: 13 paginierte Endpunkte parallel laden ist unnötig. |
| 2026-04-20 | Generische Tab-Komponente (`TrusteeDataTab`) statt 13 spezialisierter Views | DRY; Spezialisierungen (Beleg-Download/Sync-Status-Spalte) bleiben ausschliesslich in `TrusteePositionsView` / `TrusteeDocumentsView`. |
| 2026-04-20 | Keine Bulk-Aktionen im neuen Tab (kein Sync-Button etc.) | Bulk-Sync ist im Positions-Tab schon vorhanden Generic-Seite bleibt schlank. |
## Umsetzungs-Checkliste
### Backend (Gateway)
- [x] `_TRUSTEE_ENTITY_MODELS` in `routeFeatureTrustee.py` um die 7 neuen Modelle erweitert.
- [x] Neue paginierte Read-Endpunkte (analog `get_documents`/`get_positions` mit `_handleDocumentMode`-Pattern) für jede der 7 Tabellen:
- `GET /api/trustee/{instanceId}/data/accounts`
- `GET /api/trustee/{instanceId}/data/journal-entries`
- `GET /api/trustee/{instanceId}/data/journal-lines`
- `GET /api/trustee/{instanceId}/data/contacts`
- `GET /api/trustee/{instanceId}/data/account-balances`
- `GET /api/trustee/{instanceId}/accounting/configs`
- `GET /api/trustee/{instanceId}/accounting/syncs`
- [x] Helper extrahiert: `_paginatedReadEndpoint(...)` haelt Logik fuer alle 7 Endpunkte zentral.
- [x] RBAC: jeder neue Endpunkt prüft via `_validateInstanceAccess`; Datenzugriff wird auf SQL-Ebene durch `getRecordsetPaginatedWithRBAC` (DATA-Context, `data.feature.trustee.<Model>`) gefiltert identisch zum bestehenden Documents/Positions-Pattern.
- [x] `mainTrustee.py`: Neuer UI-Object-Eintrag `ui.feature.trustee.data-tables` (Label «Daten-Tabellen»).
- [x] `mainTrustee.py`: AccessRule fuer `ui.feature.trustee.data-tables` bei `trustee-viewer`, `trustee-user`, `trustee-accountant` ergaenzt; Admin hat Wildcard.
### Frontend
- [x] `ui-nyla/src/api/trusteeApi.ts`: 7 neue Read-Funktionen (`fetchDataAccounts`, `fetchDataJournalEntries`, `fetchDataJournalLines`, `fetchDataContacts`, `fetchDataAccountBalances`, `fetchAccountingConfigs`, `fetchAccountingSyncs`) plus passende Typen.
- [x] `ui-nyla/src/hooks/useTrustee.ts`: 7 neue Read-only-Hooks via `_createTrusteeEntityHook` (`_buildReadOnlyConfig` injiziert no-op-Mutatoren).
- [x] **Neu** `ui-nyla/src/pages/views/trustee/dataTables/TrusteeDataTab.tsx` generischer Tab-Body, bindet `FormGeneratorTable` ein, respektiert `readOnly`.
- [x] **Neu** `ui-nyla/src/pages/views/trustee/TrusteeDataTablesView.tsx`:
- 13 Tab-Defs, jede mit eigenem Wrapper-Component, das den passenden Hook aufruft.
- URL-Sync via `?tab=<key>`, Lazy-Mount (nur aktiver Wrapper rendert -> kein Datenfetch fuer inaktive Tabs).
- Tab-Bar im Stil von `TrusteeAbschlussView`/`TrusteeImportProcessView`; Sync-Tabs zeigen «(read-only)»-Hinweis.
- RBAC-Filter im Frontend deaktiviert: einzelne Tab-Hooks blockieren Datenzugriff serverseitig (vermeidet sync-Permission-Lookups; spaetere Iteration kann Tab-Hiding nachziehen).
- [x] `ui-nyla/src/pages/views/trustee/index.ts`: Export ergaenzt.
- [x] `ui-nyla/src/pages/FeatureView.tsx`: Mapping `'data-tables': TrusteeDataTablesView` + Import.
- [x] `ui-nyla/src/App.tsx`: Route `<Route path="data-tables" .../>` ergaenzt.
- [x] `ui-nyla/src/types/mandate.ts`: `FEATURE_REGISTRY.trustee.views` um `'data-tables'` ergaenzt.
### Cross-Cutting
- [x] RBAC / Permissions: alle neuen 7 Endpunkte teilen `_paginatedReadEndpoint` -> `_validateInstanceAccess` (Instanz-Gating) + `getRecordsetPaginatedWithRBAC` (DATA-Context, `featureCode=trustee`, `data.feature.trustee.<Model>`); identisches Pattern zu `get_documents` / `get_positions`. UI-Sichtbarkeit der Seite haengt am Permission `ui.feature.trustee.data-tables` (Template-Rollen `trustee-viewer`, `trustee-user`, `trustee-accountant`; Admin via Wildcard).
- [x] Neutralisierung betroffen? **Nein** keine AI-Calls, kein neuer Datenfluss zu externen Systemen.
- [x] Navigation / Routing: neue UI-Route `/mandates/{m}/trustee/{i}/data-tables[?tab=<key>]` registriert in `App.tsx` (Zeile ~150), `FeatureView.tsx` (`VIEW_COMPONENTS.trustee['data-tables'] = TrusteeDataTablesView`) und `mandate.ts` (`FEATURE_REGISTRY.trustee.views`).
- [x] Billing-Impact? **Nein**.
- [x] i18n: alle Tab-Labels und Header-Strings via `t(...)`; Spalten-Labels kommen aus `@i18nModel`-getaggten Modellen (bereits vorhanden für alle 13).
- [x] Quick Actions: keine Änderung Quick Actions zeigen weiterhin auf `import-process` / `settings`. Direktlinks auf einzelne Datentabs in Folge-Iteration `2026-04-trustee-cleanup-positions-documents.md`.
## Akzeptanzkriterien
| # | Kriterium (Given-When-Then) | Prio |
|---|----------------------------|------|
| 1 | Given ein Trustee-Admin auf einer Trustee-Instanz, When er auf Navigation «Daten-Tabellen» klickt, Then erscheint eine Seite mit Tab-Bar und allen 13 Trustee-Tabellen als Tabs. | must |
| 2 | Given die Seite «Daten-Tabellen» mit Default-Tab, When der User sie öffnet, Then wird sofort der erste Tab geladen (FormGeneratorTable mit Daten, Pagination, Spalten aus `attributes`-API). | must |
| 3 | Given ein Tab mit Sync-Daten (z.B. «Buchungen (Sync)»), When der User die Zeile inspiziert, Then sind keine Edit-/Delete-Buttons sichtbar (read-only). | must |
| 4 | Given ein Tab mit CRUD-Daten (z.B. «Position»), When der User auf Edit klickt, Then erscheint ein FormGeneratorForm-Modal und Speichern persistiert via PUT-Endpunkt. | must |
| 5 | Given die Seite «Daten-Tabellen», When der User auf Tab «Kontakte (Sync)» wechselt, Then ändert sich die URL auf `?tab=contacts` und nur der Kontakte-Tab ist gemountet (Network-Tab zeigt nur den Kontakte-API-Call). | must |
| 6 | Given ein Tab mit aktiviertem `apiEndpoint`, When der User in einer Spalte einen Filter setzt, Then werden Distinct-Werte vom Backend via `?mode=filterValues&column=<x>` geladen. | must |
| 7 | Given ein User OHNE Permission `data.feature.trustee.TrusteeDataContact` (view), When er die Seite öffnet, Then ist der Tab «Kontakte (Sync)» nicht sichtbar oder disabled. | should |
| 8 | Given die Seite mit Deep-Link `?tab=accounts`, When der User per URL einsteigt, Then wird der Konten-Tab direkt aktiv geladen. | should |
| 9 | Given die alten Seiten «Positionen»/«Dokumente», When der User sie aufruft, Then funktionieren sie unverändert weiter (kein Regress). | must |
| 10 | Given ein Tab mit grosser Datenmenge (>1'000 Einträge), When der User scrollt, Then wird Server-Pagination angewandt (page-Size 25, kein Frontend-Speicher-Overload). | must |
| 11 | Given Tabellen-Sortierung, When der User auf einen Spalten-Header klickt, Then wird per `pagination.sort` serverseitig sortiert. | must |
## Testplan
| ID | AC | Art | Automatisiert | Repo-Pfad | Status |
|----|----|-----|--------------|-----------|--------|
| T1 | 1 | manual UI | nein | | pending |
| T2 | 2,5 | api | ja | platform-core/tests/test_routeFeatureTrustee_data_tables.py | pending |
| T3 | 3,4 | api | ja | platform-core/tests/test_routeFeatureTrustee_data_tables.py | pending |
| T4 | 6 | api | ja | platform-core/tests/test_routeFeatureTrustee_data_tables.py (Unified Filter API: mode=filterValues / mode=ids) | pending |
| T5 | 7 | api | ja | platform-core/tests/test_routeFeatureTrustee_data_tables.py (RBAC-Gate) | pending |
| T6 | 8 | manual UI | nein | | pending |
| T7 | 9 | manual + e2e | teils | bestehende Position/Document Tests laufen weiter | pending |
| T8 | 10,11 | api | ja | platform-core/tests/test_routeFeatureTrustee_data_tables.py (Pagination/Sort) | pending |
## Links
- PR:
- Issue:
- Vorlage: `wiki/b-reference/ui-nyla/formgenerator.md`
- Vorbild-Seite: `ui-nyla/src/pages/basedata/PromptsPage.tsx`
- Vorbild-Tabs: `ui-nyla/src/pages/views/trustee/TrusteeAbschlussView.tsx`, `TrusteeAccountingSettingsView.tsx`
## Abschluss
- [x] `b-reference/platform-core/architecture.md` aktualisiert: neue Sektion "Feature: Trustee -- Daten-Tabellen-Endpunkte" mit Endpunkt-Tabelle + Helper `_paginatedReadEndpoint` + RBAC-Pattern.
- [x] `b-reference/ui-nyla/architecture.md`: Eintrag fuer `TrusteeDataTablesView` in "Wichtige UI-Komponenten" plus neuer Abschnitt "Tab-Pattern fuer mehrere Modelle pro Seite" (Lazy-Mount, URL-State, Read-only-Tabs, Tab-Gruppen).
- [x] `b-reference/ui-nyla/formgenerator.md`: bereits referenziert (`TrusteeDataTablesView` als Beispiel im "Page Layout Chain"-Pattern).
- [x] `TOPICS.md`: keine Änderung nötig (kein neues Thema).
- [x] Folge-Plan `wiki/c-work/1-plan/2026-04-trustee-cleanup-positions-documents.md` erstellt: Aufräumen der alten Top-Level-Seiten (Standalone-Files bleiben als Tab-Body, aber Header-Kommentare + Sweep auf restliche `ui.feature.trustee.positions` / `.documents`-Referenzen).
- [x] Dieses Dokument → `c-work/4-done/`.