# 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/frontend-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.`-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=]`) 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.` 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**: - `gateway/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`. - `gateway/modules/features/trustee/mainTrustee.py`: `UI_OBJECTS` um `ui.feature.trustee.data-tables` ergänzen; `TEMPLATE_ROLES.accessRules` der relevanten Rollen erweitern. - **Frontend**: - **Neu**: `frontend_nyla/src/pages/views/trustee/TrusteeDataTablesView.tsx` (Container mit Tab-Bar + URL-Sync). - **Neu**: `frontend_nyla/src/pages/views/trustee/dataTables/TrusteeDataTab.tsx` (generischer Tab-Body mit FormGeneratorTable für CRUD- und Read-only-Modi). - **Erweitern**: `frontend_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**: `frontend_nyla/src/api/trusteeApi.ts` um `fetchTrusteeData*`-Funktionen. - **Anpassen**: `frontend_nyla/src/pages/FeatureView.tsx` (`VIEW_COMPONENTS.trustee` um `'data-tables': TrusteeDataTablesView` ergänzen). - **Anpassen**: `frontend_nyla/src/pages/views/trustee/index.ts` (Export). - **Anpassen**: `frontend_nyla/src/App.tsx` (Route `data-tables` registrieren). - **Optional**: `frontend_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=` | 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.`) 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] `frontend_nyla/src/api/trusteeApi.ts`: 7 neue Read-Funktionen (`fetchDataAccounts`, `fetchDataJournalEntries`, `fetchDataJournalLines`, `fetchDataContacts`, `fetchDataAccountBalances`, `fetchAccountingConfigs`, `fetchAccountingSyncs`) plus passende Typen. - [x] `frontend_nyla/src/hooks/useTrustee.ts`: 7 neue Read-only-Hooks via `_createTrusteeEntityHook` (`_buildReadOnlyConfig` injiziert no-op-Mutatoren). - [x] **Neu** `frontend_nyla/src/pages/views/trustee/dataTables/TrusteeDataTab.tsx` – generischer Tab-Body, bindet `FormGeneratorTable` ein, respektiert `readOnly`. - [x] **Neu** `frontend_nyla/src/pages/views/trustee/TrusteeDataTablesView.tsx`: - 13 Tab-Defs, jede mit eigenem Wrapper-Component, das den passenden Hook aufruft. - URL-Sync via `?tab=`, 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] `frontend_nyla/src/pages/views/trustee/index.ts`: Export ergaenzt. - [x] `frontend_nyla/src/pages/FeatureView.tsx`: Mapping `'data-tables': TrusteeDataTablesView` + Import. - [x] `frontend_nyla/src/App.tsx`: Route `` ergaenzt. - [x] `frontend_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.`); 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=]` 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=` 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 | gateway/tests/test_routeFeatureTrustee_data_tables.py | pending | | T3 | 3,4 | api | ja | gateway/tests/test_routeFeatureTrustee_data_tables.py | pending | | T4 | 6 | api | ja | gateway/tests/test_routeFeatureTrustee_data_tables.py (Unified Filter API: mode=filterValues / mode=ids) | pending | | T5 | 7 | api | ja | gateway/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 | gateway/tests/test_routeFeatureTrustee_data_tables.py (Pagination/Sort) | pending | ## Links - PR: – - Issue: – - Vorlage: `wiki/b-reference/frontend-nyla/formgenerator.md` - Vorbild-Seite: `frontend_nyla/src/pages/basedata/PromptsPage.tsx` - Vorbild-Tabs: `frontend_nyla/src/pages/views/trustee/TrusteeAbschlussView.tsx`, `TrusteeAccountingSettingsView.tsx` ## Abschluss - [x] `b-reference/gateway/architecture.md` aktualisiert: neue Sektion "Feature: Trustee -- Daten-Tabellen-Endpunkte" mit Endpunkt-Tabelle + Helper `_paginatedReadEndpoint` + RBAC-Pattern. - [x] `b-reference/frontend-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/frontend-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/`.