15 KiB
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) einapiEndpointmit Unified Filter API (mode=filterValues|ids), (b) einen Hook mitrefetch / pagination / attributes / permissions, (c) saubere Spaltendefinitionen ausgetModelAttributeDefinitions(...). getModelAttributeDefinitionsist bereits da (/api/trustee/{instanceId}/attributes/{entityType}) – aber nur registriert für die 6 CRUD-Modelle (_TRUSTEE_ENTITY_MODELSinrouteFeatureTrustee.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_OBJECTSeinendata.feature.trustee.<Model>-Key. Der Hook (_createTrusteeEntityHook) löst Permissions viadata.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
PositionenundDokumentebleiben 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 mitTrusteeImportProcessView,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, technischeid-UUIDs sollen tabellenweit hidden sein (gleiche Liste wie in PromptsPagehiddenColumns). - 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 nutztFormGeneratorTablemit 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
TrusteePositionsViewvorbehalten (Generic-Tab zeigt das «rohe» Modell).
Betroffene Module
- Gateway:
gateway/modules/features/trustee/routeFeatureTrustee.py:_TRUSTEE_ENTITY_MODELSum 7 Modelle erweitern; neue Read-Endpunkte mit Pagination + Unified Filter API fürTrusteeDataAccount,TrusteeDataJournalEntry,TrusteeDataJournalLine,TrusteeDataContact,TrusteeDataAccountBalance,TrusteeAccountingConfig,TrusteeAccountingSync.gateway/modules/features/trustee/mainTrustee.py:UI_OBJECTSumui.feature.trustee.data-tablesergänzen;TEMPLATE_ROLES.accessRulesder 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.tsum 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.tsumfetchTrusteeData*-Funktionen. - Anpassen:
frontend_nyla/src/pages/FeatureView.tsx(VIEW_COMPONENTS.trusteeum'data-tables': TrusteeDataTablesViewergänzen). - Anpassen:
frontend_nyla/src/pages/views/trustee/index.ts(Export). - Anpassen:
frontend_nyla/src/App.tsx(Routedata-tablesregistrieren). - Optional:
frontend_nyla/src/types/mandate.ts(FEATURE_REGISTRY.trustee.views) umdata-tablesergänzen, falls noch genutzt.
- Neu:
- 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)
_TRUSTEE_ENTITY_MODELSinrouteFeatureTrustee.pyum die 7 neuen Modelle erweitert.- Neue paginierte Read-Endpunkte (analog
get_documents/get_positionsmit_handleDocumentMode-Pattern) für jede der 7 Tabellen:GET /api/trustee/{instanceId}/data/accountsGET /api/trustee/{instanceId}/data/journal-entriesGET /api/trustee/{instanceId}/data/journal-linesGET /api/trustee/{instanceId}/data/contactsGET /api/trustee/{instanceId}/data/account-balancesGET /api/trustee/{instanceId}/accounting/configsGET /api/trustee/{instanceId}/accounting/syncs
- Helper extrahiert:
_paginatedReadEndpoint(...)haelt Logik fuer alle 7 Endpunkte zentral. - RBAC: jeder neue Endpunkt prüft via
_validateInstanceAccess; Datenzugriff wird auf SQL-Ebene durchgetRecordsetPaginatedWithRBAC(DATA-Context,data.feature.trustee.<Model>) gefiltert – identisch zum bestehenden Documents/Positions-Pattern. mainTrustee.py: Neuer UI-Object-Eintragui.feature.trustee.data-tables(Label «Daten-Tabellen»).mainTrustee.py: AccessRule fuerui.feature.trustee.data-tablesbeitrustee-viewer,trustee-user,trustee-accountantergaenzt; Admin hat Wildcard.
Frontend
frontend_nyla/src/api/trusteeApi.ts: 7 neue Read-Funktionen (fetchDataAccounts,fetchDataJournalEntries,fetchDataJournalLines,fetchDataContacts,fetchDataAccountBalances,fetchAccountingConfigs,fetchAccountingSyncs) plus passende Typen.frontend_nyla/src/hooks/useTrustee.ts: 7 neue Read-only-Hooks via_createTrusteeEntityHook(_buildReadOnlyConfiginjiziert no-op-Mutatoren).- Neu
frontend_nyla/src/pages/views/trustee/dataTables/TrusteeDataTab.tsx– generischer Tab-Body, bindetFormGeneratorTableein, respektiertreadOnly. - 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=<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).
frontend_nyla/src/pages/views/trustee/index.ts: Export ergaenzt.frontend_nyla/src/pages/FeatureView.tsx: Mapping'data-tables': TrusteeDataTablesView+ Import.frontend_nyla/src/App.tsx: Route<Route path="data-tables" .../>ergaenzt.frontend_nyla/src/types/mandate.ts:FEATURE_REGISTRY.trustee.viewsum'data-tables'ergaenzt.
Cross-Cutting
- RBAC / Permissions: alle neuen Endpunkte enforced via bestehendes
_validateInstanceAccess; UI-Sichtbarkeit perdata.feature.trustee.<Model>-Check (Hook liefert das viapermissions.view). - Neutralisierung betroffen? Nein – keine AI-Calls, kein neuer Datenfluss zu externen Systemen.
- Navigation / Routing: neue UI-Route
/mandates/{m}/trustee/{i}/data-tables[?tab=<key>]. - Billing-Impact? Nein.
- i18n: alle Tab-Labels und Header-Strings via
t(...); Spalten-Labels kommen aus@i18nModel-getaggten Modellen (bereits vorhanden für alle 13). - Quick Actions: keine Änderung – Quick Actions zeigen weiterhin auf
import-process/settings. Optional in Folge-Iteration: Direktlinks auf einzelne Datentabs.
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 | 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
b-reference/gateway/features/trustee.md(oder analog) aktualisieren: neue Endpunkte + neue UI-Seite dokumentieren.b-reference/frontend-nyla/architecture.md: kurze Erwähnung der konsolidiertenTrusteeDataTablesView+ Tab-Pattern für mehrere Modelle.TOPICS.md: keine Änderung nötig (kein neues Thema).- Folge-Plan
2026-MM-trustee-cleanup-positions-documents.md: Aufräumen der alten Seiten, sobald Daten-Tabellen produktiv verifiziert. - Dieses Dokument →
c-work/2-build/(bei Umsetzungsbeginn) →c-work/3-validate/→z-archive/.