# MVP Acceptance Dashboard: FX, Valuation, Runtime Cleanup

Use this reference when the user asks to make the existing Finance dashboard workflows genuinely work from a user perspective, especially after provider/manual-position work. This is a stabilization/acceptance bugfix mode, not a provider or feature sprint.

## Scope discipline

- Do not start new provider integrations, DOCX imports, or broad analytics while acceptance bugs remain.
- Fix the workflows already visible to the user: manual position add, FX handling, Equity/ETF valuation display, Cash entry, Command Center summaries, explicit refresh buttons, and runtime cleanup.
- Dashboard rendering must stay local-read-only: no live API/provider calls on page render. Provider/FX/price calls require an explicit button, CLI command, or scheduled job.

## FX UX rules for manual Equity/ETF positions

- User Mode must not expose internal FX status values (`ok`, `missing`, `manual_override_required`, `not_needed`, `manual_override`) as raw choices.
- CHF positions: automatically store FX rate `1`, `fx_status=not_needed`, and do not show an FX input.
- USD/EUR/foreign positions: default to an Auto-FX user choice that resolves local cache first, then configured providers. If a rate is found, persist it and store `fx_status=ok` with a non-secret source label.
- If Auto-FX cannot find a rate, the user must consciously choose either:
  - manual FX entry with source/note, stored as a manual override; or
  - save without FX, stored as `fx_status=missing`, with valuation clearly incomplete.
- Never store `fx_status=ok` without `fx_rate_to_chf`.
- Manual FX override paths need auditability and a note/source.

## Equity/ETF valuation and display

- Tables should show user-facing columns such as Name, Ticker, ISIN, Depot, Assettyp, Menge, Kurs, Kurswährung, Marktwert CHF, Status, Aktionen.
- Missing prices/FX must display as `Preis noch nicht verfügbar`, `FX fehlt`, `nicht bewertet`, or similar—not `0`, empty green status, or fake CHF values.
- Current market price and market value should come from local `market_prices` plus local FX cache during render. Explicit refresh actions may call providers and then persist results.
- Status calculation should reference actual row fields (`cost_basis_chf`, `market_value_chf`, provider mapping status) rather than stale/renamed keys.

## Runtime cleanup pattern

Before deleting review/test/demo/synthetic runtime data:

1. Create a full runtime DB backup under the external runtime backup directory, outside Git, with restrictive permissions.
2. Identify candidates by audit-safe markers (e.g. notes containing synthetic/test/demo/review), not by values or raw rows in chat.
3. Record audit-log events before deletion with aggregate metadata and the backup path, but do not expose real quantities/values.
4. Delete only clearly marked transactions and orphaned marked instruments; retain marked instruments that still have active real transactions unless explicitly approved.
5. Report aggregate counts only: removed transactions, removed orphan instruments, retained marked instruments, remaining marked rows.

## Verification discipline

- Add/adjust regression tests before and after fixes for User Mode FX hiding, cache-first FX, CHF not-needed FX, missing-FX confirmation, table valuation labels, explicit-click refresh behavior, Cash writes, and no-live-API-on-render.
- Run `python -m compileall -q src tests` and `pytest -q`.
- After tests, remove `.pytest_cache` and `__pycache__`, then run Git-safety and `git diff --check`.
- Commit and push only after safety is clean; verify `HEAD` matches `origin/main`.
- If normal `git push` cannot prompt for HTTPS credentials, use a temporary `GIT_ASKPASS` script with the runtime GitHub token, redact token values, and delete the script immediately after use.

## Acceptance report format

Final reports for this mode should include concrete Ja/Nein points for each user acceptance item, tests run, Git-safety result, commit hash, push verification, runtime backup path, cleanup aggregate counts, and explicit open gaps (for example: CoinGecko detailcache absent from the codebase).