## Audit outcome ### P0 — Preview upload is currently contract-broken - `frontend/src/api/postfinance.ts:3-8` and `PostFinancePage.vue:68` send only filenames and Base64. - The current backend schema also requires: - `zip_mime_type` - `overview_mime_type` - `zip_size_bytes` - `overview_size_bytes` - Result: every real preview request will return HTTP 422. - Existing page test misses this because it assigns a synthetic payload directly and mocks the API. **Minimal fix:** extend `PostFinanceImportPayload` and populate MIME/size metadata from both `File` objects. Add a test that selects actual synthetic `File`s and inspects the preview request. ### P1 — Required route and visible navigation are absent - Router exposes only `/portfolio/postfinance` (`router/index.ts:49`), not exact route `/postfinance/imports/preview`. - PostFinance is absent from the visible Vermögen menu (`navigation/userNav.ts:60-65`). - Upload UI is hidden behind a toggle rather than directly available at the required route. - Navigation smoke coverage omits the required route. **Minimal fix:** - Add `/postfinance/imports/preview` mapped to `PostFinancePage`, opening import mode by default. - Keep `/portfolio/postfinance` as a compatibility route or redirect. - Add visible `PostFinance Import` under Vermögen. - Extend `UserNavigationSmoke.test.ts` and `SidebarNav.mobile.test.ts`. ### P1 — Confirm blocking is fail-open in the frontend - Confirm is disabled only for `conflict` or exact status `mismatch` (`PostFinancePage.vue:26`). - Unknown, missing, or future reconciliation statuses enable Confirm. - `doConfirm()` does not repeat the safety predicate (`PostFinancePage.vue:72`). - Changing a file clears the preview, but an in-flight older preview can resolve afterward and restore a stale, confirmable preview. **Minimal fix:** one shared `canConfirm` allowlist predicate, enforced in both button and handler; invalidate/discard stale preview responses when files change. Render a German blocking reason. Add conflict, unknown-status, mismatch, and stale-response tests. ### P1 — Backend’s useful German errors are hidden - `apiPost()` replaces all non-2xx details with `Lokale API meldet Fehler ` (`api/client.ts:42-44`). - File conversion errors in `selectFile()` are not caught. - This fails the plain, actionable German-error UX requirement. **Minimal fix:** safely extract FastAPI’s string `detail`, with a German fallback; catch file-reading errors locally. Test a 422 German detail and file-read failure. ### P2 — Preview is non-JSON, but not sufficiently rich Current preview shows only four count cards. It omits available review information: - selected filenames and sizes - snapshot date and total - securities/cash and stocks/ETF decomposition - mapped versus total positions - event and quality breakdowns - open orders - warnings - explicit German `bereit/gesperrt` state It also displays raw statuses such as `matched` instead of German labels. **Minimal fix:** expand the existing card layout and render translated labels/warnings; no new component is necessary. ### Existing behavior that already aligns - ZIP and overview are required together for one Preview action via `payloadReady`. - Preview and Confirm use separate API actions. - Desktop/iPad responsive classes are present (`md:grid-cols-2`, wrapping action rows), though no test verifies actual iPad geometry. - Initial render calls only local health/runtime/summary endpoints; it does not call preview, confirm, or an external provider. Add a regression assertion for this. ## Minimal files/tests **Production:** - `frontend/src/pages/PostFinancePage.vue` - `frontend/src/api/postfinance.ts` - `frontend/src/api/client.ts` - `frontend/src/router/index.ts` - `frontend/src/navigation/userNav.ts` **Tests:** - `frontend/src/pages/PostFinancePage.test.ts` - `frontend/src/api/client.test.ts` - `frontend/src/navigation/UserNavigationSmoke.test.ts` - `frontend/src/components/SidebarNav.mobile.test.ts` ## Verification / workspace - No files were edited or created. - Focused frontend tests could not start because `frontend/node_modules` is absent; Vite and `@vitejs/plugin-vue` could not be resolved. - Backend schema/service files became modified concurrently during the audit; the P0 contract finding reflects that current working-tree contract.