## Inventory outcome Repository inspected read-only at: `/home/agent/.hermes/worktrees/FinanceManager-sprint12-truewealth-verified-import` Commit: `c332f4c1018699899f11382dff688fbd16a45944` ### Existing TrueWealth route and navigation - `frontend/src/router/index.ts:9,41` - Lazy-loads `frontend/src/pages/TrueWealthPage.vue`. - Existing route is `/portfolio/truewealth`, name `truewealth`, title `TrueWealth Roboadvisor`. - **No route change is needed** for Sprint 12. - `frontend/src/navigation/userNav.ts:60-73` - TrueWealth is already a ready child of **Vermögen**: - key `truewealth` - label `TrueWealth` - target `/portfolio/truewealth` - It appears as a desktop submenu item, mobile drawer deep link, and under mobile **Mehr**. - **No navigation-model change is needed.** - `frontend/src/components/SidebarNav.vue` - Desktop sidebar activates at Tailwind `lg` (`>=1024px`). - Below `lg`, the UI uses a fixed menu button, full-screen drawer, and bottom navigation. - Consequently, iPad portrait behaves as mobile/tablet; a 1024-CSS-pixel landscape viewport crosses into the desktop shell. ### Current TrueWealth page behavior - `frontend/src/pages/TrueWealthPage.vue` - On mount, concurrently calls: - `getHealth()` - `getRuntimeStatus()` - `getOverview()` - `getReferenceAccounts()` - Finds the account where: - `portfolio_bucket === 'truewealth'` - `valuation_mode === 'manual_total_value'` - Displays only `overview.truewealth_value_chf`. - Supports a manual amount/date/note flow: 1. POST account-value preview. 2. Show amount-only preview. 3. POST confirm with `preview_id` and `confirm: true`. 4. Show audit ID and reload. - Explicitly says no provider call during rendering and forbids individual TrueWealth positions. - The “history” section is **static explanatory copy only**; it loads no history. - There is currently: - no snapshot list, - no snapshot detail, - no positions display, - no statement/file import, - no import preview, - no import-session history, - no empty state for a missing TrueWealth account. - If no matching account exists, preview silently returns without user feedback. - Responsive behavior is limited to: - wrapped summary/actions, - form changing from one column to `md:grid-cols-3`. - It has no dedicated mobile cards/table switch. ### Existing frontend API contracts - `frontend/src/api/positions.ts:4,17-18` - Existing calls: - `GET /api/reference/accounts` - `POST /api/accounts/{account_id}/value/preview` - `POST /api/accounts/{account_id}/value/confirm` - `frontend/src/api/types.ts` - Existing relevant types: - `Overview` with optional `truewealth_value_chf` — line 6 - `ReferenceAccount` — line 42 - `PreviewResponse` — line 43 - `ConfirmResponse` — line 44 - `AccountValueRequest` — line 52 - Missing dedicated types for: - TrueWealth snapshot summary/detail, - imported portfolio positions, - upload metadata, - import preview rows/totals/warnings, - import confirm result/session history. ### Existing backend support and gaps - `src/jarvis_finance/api/schemas/positions.py:250-268,371-384` - Defines `ReferenceAccount`, account-value requests, and generic preview/confirm responses. - `src/jarvis_finance/api/routers/positions.py:53-55,138-145` - Exposes reference-account GET and account-value preview/confirm POST. - **No GET endpoint exposes TrueWealth account-value history.** - **No TrueWealth import/preview/confirm/detail endpoint exists in this tree.** - `src/jarvis_finance/services/manual_entry_service.py:121-166,1081-1102` - Classifies TrueWealth as: - `manual_total_value` - bucket `truewealth` - `allow_position_adds = false` - Preview validates a positive amount without writing. - Confirm writes `account_value_snapshots` and an `account_value_confirm` audit. - Provider search is not involved. - `src/jarvis_finance/storage/migrations.py:1520-1535` - `account_value_snapshots` already stores account, valuation date, total CHF value, source, quality, note, and timestamps. - This can back snapshot history once exposed safely. - `src/jarvis_finance/services/manual_entry_service.py:522-528` - Explicitly blocks ordinary equity/ETF position creation under the TrueWealth managed account. - Any Sprint 12 “positions” must therefore be a separate read-only imported snapshot contract, not ordinary ledger positions, unless the domain model is intentionally changed. ## Reusable UI and responsive patterns ### Best reusable components - `frontend/src/components/DetailDrawer.vue` - Best existing detail surface. - Mobile: bottom sheet, maximum `88dvh`. - `md`: centered modal-like sheet. - `lg`: fixed right-side 500px drawer. - Includes dialog semantics, Escape handling, focus trap, and focus restoration. - `frontend/src/components/ui/ConfirmDialog.vue` - Responsive PrimeVue confirmation dialog. - Suitable for a final destructive/explicit confirmation, but it only accepts plain message text; rich import preview should remain in-page or use `DetailDialog`. - `frontend/src/components/ui/DetailDialog.vue` - Generic responsive PrimeVue dialog with a `min(96vw, 52rem)` width. - `frontend/src/components/ui/SectionCard.vue` - Reusable titled card shell with action slot. - `frontend/src/components/ui/PrimeDataTable.vue` - PrimeVue table wrapper with pagination. - Not inherently a mobile-card fallback. - `frontend/src/components/PositionTable.vue` - Generic compact horizontal-scroll table with row selection. - Desktop-oriented and less suitable than dedicated cards for phone layouts. - `frontend/src/components/LoadActionBar.vue` - `frontend/src/components/LocalDataStatus.vue` - `frontend/src/components/MoneyValue.vue` - Already used by TrueWealth and should remain. ### Import/preview/history examples These are useful patterns, but they are currently page-local rather than reusable components: - `frontend/src/pages/BudgetImportPage.vue` - CSV file selection, 5 MB limit, dry-run preview, warnings/errors, confirm-candidate step, and import-session cards. - Responsive result cards use `sm:grid-cols-2 lg:grid-cols-4`. - Import sessions use `md:grid-cols-2 xl:grid-cols-3`. - `frontend/src/pages/BudgetMonthlyImportPage.vue:43-46` - Strongest history responsiveness pattern: - desktop/tablet table: `hidden md:block` - phone cards: `md:hidden` - `frontend/src/pages/CashPage.vue:33-40` - Closest aggregate-snapshot workflow: - inline preview/confirm form, - history loaded on demand, - audit hint without displaying raw snapshot IDs. - It is not extracted into reusable components. - `frontend/src/pages/EquityPage.vue:43-71,80-106` - Strongest positions/detail pattern: - phone cards below `md`, - table at `md+`, - keyboard-openable cards, - responsive `DetailDrawer`, - inline history inside detail. - `frontend/src/pages/CryptoPage.vue:30-36,57-115` - Same mobile-card/desktop-table and drawer pattern, plus explicit no-provider-on-render behavior. ### Global responsive foundation - `frontend/src/components/AppLayout.vue` - Mobile bottom-navigation clearance via `pb-20`. - Content gutters: `px-4`, `sm:px-6`, `lg:px-8`. - Maximum content width 1600px. - `frontend/src/style.css` - Minimum body width 320px and global horizontal overflow suppression. - Existing custom media rule begins at 768px. - `frontend/tailwind.config.ts` - Uses standard Tailwind breakpoints; no custom iPad breakpoint. ## Existing tests - `frontend/src/pages/CashTrueWealthManagement.test.ts:70-99` - Covers current amount preview → confirm → audit flow and no-individual-position wording. - Does not cover history, import, responsive behavior, missing account, errors, or provider-call absence. - `tests/unit/test_cash_truewealth_management.py:121-140` - Covers snapshot persistence, overview aggregation, audit creation, and position blocking. - `tests/unit/test_vue_dashboard_v12_acceptance.py:80-128` - Covers TrueWealth account classification and API preview/confirm. - Generic provider test proves `GET /api/overview` does not trigger provider search; only explicit provider-search POST does. - `frontend/src/navigation/UserNavigationSmoke.test.ts` - Ensures every enabled navigation item has a router route. - TrueWealth is indirectly covered through all enabled items, but not included in the explicit `criticalRoutes` list. - `frontend/src/pages/MobileUx.test.ts` - `frontend/src/components/SidebarNav.mobile.test.ts` - Assert responsive classes/navigation structure. - They do not perform real layout measurements. - `frontend/src/pages/BudgetImportPage.test.ts` - Good model for upload dry run, aggregate preview, candidate confirmation, and filtered review links. ## Minimal frontend file-change plan Assuming Sprint 12 backend contracts are added separately: 1. **Modify** `frontend/src/pages/TrueWealthPage.vue` - Keep the existing route and shell. - Replace the manual-only page with: - current snapshot KPIs, - snapshot/import history, - read-only imported positions, - upload → preview → explicit confirm, - mobile cards and `md+` table, - selected snapshot/import/position detail via `DetailDrawer`, - honest no-account, no-snapshot, no-position, loading, and error states. - Preserve manual aggregate-value fallback if still part of the product contract. - Never call a provider method in `onMounted` or detail-open handlers. 2. **Create** `frontend/src/api/trueWealth.ts` - Keep TrueWealth endpoint wiring isolated instead of further expanding generic `positions.ts`. - Add snapshot/history/detail/import-preview/import-confirm functions. - Read endpoints should respect normal cache/refresh semantics; POST already clears the API cache. 3. **Modify** `frontend/src/api/types.ts` - Add dedicated TrueWealth snapshot, imported position, preview, detail, and import-session types. - Avoid `Record` for this audited flow. 4. **Create** `frontend/src/pages/TrueWealthPage.test.ts` - Move/expand the current TrueWealth frontend tests here. - The existing TrueWealth block in `CashTrueWealthManagement.test.ts` can then be removed to avoid duplicate fixtures. 5. **Optional only if the page becomes too large:** create narrowly scoped components under: - `frontend/src/components/truewealth/TrueWealthImportPanel.vue` - `frontend/src/components/truewealth/TrueWealthHistory.vue` - `frontend/src/components/truewealth/TrueWealthPositions.vue` - Do not first build a generic cross-domain import framework; the current import/history implementations have materially different contracts. 6. **No changes expected** - `frontend/src/router/index.ts` - `frontend/src/navigation/userNav.ts` - JARVIS command dashboard surfaces. ## Tests needed for Sprint 12 ### Vitest component/API tests Add to `frontend/src/pages/TrueWealthPage.test.ts`: - Initial render: - displays latest confirmed snapshot and summary, - loads local APIs only, - does not invoke provider search, quote, chart, or market-update APIs. - No-provider proof: - mock all TrueWealth/local APIs, - spy on global `fetch`, - assert mounted URLs are an explicit local allowlist and contain no provider-search/market-update route. - Missing provider/account: - no matching TrueWealth account renders an actionable neutral empty state, - preview/confirm controls are disabled or absent, - no silent no-op. - Import flow: - accepted file type and size, - preview call does not call confirm, - preview totals, warnings, rejected rows, and positions render safely, - confirm requires current `preview_id` and explicit confirmation, - changing the file/form invalidates stale preview state, - successful confirm reloads snapshot/history/positions and shows audit-safe receipt, - failed preview/confirm remains recoverable. - History/detail: - raw snapshot/import/audit IDs are not printed in the normal page, - row/card opens `DetailDrawer`, - empty and partial histories render honestly. - Responsive DOM: - phone card container is `md:hidden`, - table is `hidden md:block`, - action bars wrap and inputs remain full width, - detail uses the existing responsive drawer. Extend: - `frontend/src/api/client.test.ts` - Assert exact new TrueWealth GET/POST URL and encoded-ID behavior. - `frontend/src/navigation/UserNavigationSmoke.test.ts` - Add `/portfolio/truewealth` to `criticalRoutes`. ### Backend contract tests Extend or add alongside: - `tests/unit/test_cash_truewealth_management.py` - `tests/unit/test_vue_dashboard_v12_acceptance.py` Required assertions: - history/detail endpoints are account-scoped, ordered deterministically, bounded, and user-safe; - preview causes zero snapshot/position/audit writes; - confirm requires explicit confirmation and a valid preview; - confirm is audited and duplicate/replay-safe; - imported positions remain read-only snapshot detail and do not become ordinary equity ledger positions; - no provider adapter is invoked by snapshot/history/positions GET endpoints; - malformed files, stale previews, duplicates, and partial imports fail closed. ### Real viewport acceptance The repository currently has no Playwright dependency/configuration, so current Vitest tests only inspect classes. A real browser acceptance gate is still needed at: - Laptop: `1440×900` - iPad portrait: `768×1024` - iPad landscape: `1024×768` - Mobile: `390×844` - Minimum-width mobile: `320×568` At each viewport verify: - no body-level horizontal overflow; - all controls remain visible and touch targets are at least ~44px; - history/positions switch correctly between cards and table; - preview/confirm receipt and warnings are not clipped; - drawer stays within viewport and is keyboard closable; - mobile bottom navigation does not cover confirm actions; - iPad landscape’s `lg` transition does not cause sidebar/content overlap; - initial render produces no provider network request. ## Verification and issues - No files were created or modified; `git status --short` and `git diff --check` were clean. - Relevant Python tests executed successfully: **8 passed**. - Frontend tests could not run because this worktree has no installed `frontend/node_modules`; Vitest failed resolving `vite` and `@vitejs/plugin-vue`.