## Ergebnis - Read-only-Inventur am exakten Baseline-Commit `7411df5ad88ab4b2bebd2ec5c7008aea18d4d7ca`. - Arbeitsbaum unverändert und sauber; `git diff --check` ohne Befund. - Keine Dateien erstellt oder geändert. ## Backend-Inventur Zentrale Definition: `src/jarvis_finance/api/routers/budget.py`, Prefix `/api/budget`. ### Relevante GET-Flächen - `GET /import-status-audit` → `budget_import_status_audit` → `build_import_status_audit` - `GET /review-backlog` → `budget_review_backlog` → `build_review_backlog_dashboard` - `GET /monthly-import/dashboard` → `monthly_import_dashboard` - `GET /monthly-import/history` → `monthly_import_history` - `GET /recurring` → `recurring_dashboard` - `GET /dashboard/cockpit` → `dashboard_cockpit` - `GET /overview` → `overview` - `GET /transaction-candidates[/*]` - `GET /transfer-pairs` - `GET /transactions` - `GET /transfers` **GET-Seiteneffekte:** Für diese Flächen keine Writes und keine externen Provider-Aufrufe gefunden. Sie lesen SQLite; Cockpit/Overview berechnen zusätzlich Recurring-KPIs. Das wird teilweise explizit abgesichert durch: - `tests/unit/test_budget_import_status_audit_v1.py` - `tests/unit/test_review_backlog_cleanup_v1.py` - `tests/unit/test_fixed_costs_subscriptions_v1.py::test_dashboard_read_does_not_silently_create_detected_candidates` ### Provider-/Preview-Besonderheiten - Externer Aufruf nur explizit über `POST /monthly-import/drive-scan` → `scan_google_drive_budget_folder()` → `subprocess.run(["gog", ...])`. - `POST /monthly-import/dry-run` ist **nicht vollständig seiteneffektfrei**: `preview_drive_monthly_import()` legt `budget_import_sessions` an und committet. Es erzeugt lediglich keine Transaktionskandidaten. - Auch `POST /import/upload/preview` ist technisch schreibend: - archiviert CSV unter Runtime `import_uploads/.csv`, - schreibt/aktualisiert eine Import-Session, - committet. - Damit sind UI-Texte wie „keine Kandidaten geschrieben“ korrekt, „Dry Run ohne Writes“ wäre dagegen falsch. - Alle Budget-Preview-POSTs fallen unter den globalen Write-Gate in `src/jarvis_finance/api/main.py`; sie sind nicht in `READ_ONLY_POST_PATHS` freigestellt. ## Frontend-/UX-Inventur ### Bestehende Routen und Seiten Definition: `frontend/src/router/index.ts`. - `/planning/budget` → `BudgetOverviewPage.vue` - `/planning/budget/expenses/actual` → `BudgetTransactionsPage.vue` - `/planning/budget/expenses/review` → `BudgetImportReviewPage.vue` - `/planning/budget/review-backlog` → `BudgetReviewBacklogPage.vue` - `/planning/budget/transfers` → `BudgetTransfersPage.vue` - `/planning/budget/import` → `BudgetImportPage.vue` - `/planning/budget/monthly-import` → `BudgetMonthlyImportPage.vue` - `/planning/budget/fixed-costs` → `BudgetRecurringPage.vue` - Mehrere Altpfade redirecten bereits auf den Review-Flow. Navigation: `frontend/src/navigation/userNav.ts`, gerendert durch `frontend/src/components/SidebarNav.vue`. - Obergruppe „Haushalt“ verweist auf `/planning/budget`. - Unterpunkte führen separat zu Review, Review Backlog, Transfers, Ausgaben, Import, Konten und Kategorien. - Monthly Import und Recurring/Fixkosten sind nicht in der aktuellen Household-Unternavigation sichtbar. ### Doppelte bzw. überlappende Flächen - **Import:** `BudgetImportPage` und `BudgetMonthlyImportPage` zeigen beide Dashboard/Session-Historie, Kandidatenanlage und Review-Links. Monthly Import ist bereits als Admin/Fallback bezeichnet. - **Review:** `BudgetReviewBacklogPage` triagiert dieselben Kandidaten, die anschließend in `BudgetImportReviewPage` bearbeitet werden. - **Transfers:** Offene Transferentscheidungen liegen im Review-Tab; bestätigte Transfers haben eine separate Seite. - **Cockpit:** `BudgetOverviewPage` nutzt `/dashboard/cockpit`; das ältere `/overview` bleibt parallel für andere/ältere Flächen bestehen. ### Preview/Confirm-UX - **Sauber sichtbar getrennt:** Upload-Import, manuelle Transaktion, manuelle Recurring-Erfassung, Bulk-Confirm im Review. - **Nur technisch getrennt, nicht UX-seitig:** Recurring-Kandidaten rufen Preview und unmittelbar danach Confirm auf; der Preview-Inhalt wird dem Nutzer nicht gezeigt. - **Direkte Mutation:** Review-Backlog-Kategoriezuweisung, Recurring-Archivierung und mehrere Kandidatenaktionen. - **Review-Backlog „ConfirmPreview“:** reine Zusammenfassung ohne zugehörige Confirm-Aktion. - **Split:** UI-Label „Split Preview/Confirm“, ruft aber direkt den Confirm-Endpunkt auf. - **Transferpaar:** generischer Bestätigungsdialog plus Confirm-Endpunkt, aber kein eigener Preview-Vertrag. ### Technische Detail-Exposition - `import-status-audit` ist bewusst amount-free und count-basiert. - Import-Seiten zeigen Dateinamen, Profilnamen, Status, Zeitpunkte und Session-Metadaten; keine Rohzeilen. - `BudgetReviewBacklogPage` rendert Kandidaten-IDs nicht direkt; entsprechender Test existiert. - Größte Exposition in `BudgetImportReviewPage.vue`: - Detaildialog rendert dynamisch fast alle Kandidatenfelder. - Nur `rule_id`, `raw_fingerprint`, `dedupe_key`, `internal_status`, `source_row_hash` werden ausgeblendet. - Damit können technische Feldnamen, interne IDs, Source-Labels/-Rows und Verknüpfungsfelder sichtbar werden. - Weitere technische Begriffe im User-UI: `confirmed only`, Confidence, `covered_by_source`, Audit-ID und interne Statusnamen. ## Responsive-Teststand Vorhanden sind hauptsächlich Vitest/jsdom-Strukturtests: - `frontend/src/pages/MobileUx.test.ts` - `frontend/src/components/SidebarNav.mobile.test.ts` - `frontend/src/navigation/UserNavigationSmoke.test.ts` - Seitenspezifische Tests für Import, Monthly Import, Backlog, Recurring und Review. Abgedeckt werden mobile/desktop DOM-Varianten, Tailwind-Klassen, Navigation und Touch-Zielklassen. **Nicht vorhanden:** - Playwright/E2E-Konfiguration, - echte Viewport-Matrix, - Overflow-/Scrollbreiten-Messungen, - Tablet/iPad-Browserprüfung, - responsive Tests für den sehr breiten Review-Table/Tab- und Toolbar-Bereich, - echte Fokus-/Dialog-/History-Prüfung der konsolidierten Workflows. ## Kleinste kompatible Konsolidierung Keine Backend-API-Umbenennung im Sprint; bestehende Verträge stabil lassen. Nur eine kanonische UI pro Aufgabe: 1. `/household` → bestehende `BudgetOverviewPage.vue` 2. `/transactions` → bestehende `BudgetTransactionsPage.vue` - bestätigte Transfers als `?view=transfers` aus `BudgetTransfersPage` integrieren 3. `/review` → bestehende `BudgetImportReviewPage.vue` - Backlog als `?view=backlog`/Summary-Subview integrieren - offene Transferpaare bleiben `?tab=transfers` 4. `/imports` → bestehende `BudgetImportPage.vue` - Session-Historie und Monthly-Dashboard dort integrieren - Drive-Fallback nur als sekundärer `?mode=admin`, nicht als zweite Produktseite Bestehende `/planning/budget/**`-Pfade als Redirects mit Query-Erhalt weiterführen. Anpassungspunkte: - `frontend/src/router/index.ts` - `frontend/src/navigation/userNav.ts` - `frontend/src/pages/BudgetImportPage.vue` - `frontend/src/pages/BudgetImportReviewPage.vue` - `frontend/src/pages/BudgetTransactionsPage.vue` Danach `BudgetMonthlyImportPage.vue`, `BudgetReviewBacklogPage.vue` und `BudgetTransfersPage.vue` nicht mehr direkt routen/rendern; Logik entweder in kleine Subkomponenten extrahieren oder in die kanonischen Seiten übernehmen. Tests gezielt erweitern: - `frontend/src/navigation/UserNavigationSmoke.test.ts` - `frontend/src/components/SidebarNav.mobile.test.ts` - bestehende Import-/Review-/Transaction-Seitentests - neuer Router-Test für Legacy-Redirects inklusive Query-Erhalt - echter Browser-Responsive-Smoke für `/household`, `/transactions`, `/review`, `/imports`. ## Auffälligkeiten - Keine technischen Blocker. - Zentrale UX-Risiken sind die zwei schreibenden „Preview/Dry Run“-Implementierungen und mehrere Preview→sofort-Confirm-Flows ohne sichtbaren Zwischenschritt.