159 lines
15 KiB
Markdown
159 lines
15 KiB
Markdown
<!-- status: build -->
|
||
<!-- started: 2026-04-20 -->
|
||
<!-- component: gateway | frontend-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/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.<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**:
|
||
- `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=<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] `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=<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] `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 `<Route path="data-tables" .../>` ergaenzt.
|
||
- [x] `frontend_nyla/src/types/mandate.ts`: `FEATURE_REGISTRY.trustee.views` um `'data-tables'` ergaenzt.
|
||
|
||
### Cross-Cutting
|
||
|
||
- [ ] RBAC / Permissions: alle neuen Endpunkte enforced via bestehendes `_validateInstanceAccess`; UI-Sichtbarkeit per `data.feature.trustee.<Model>`-Check (Hook liefert das via `permissions.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 konsolidierten `TrusteeDataTablesView` + 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/`.
|