# Budget Review Bulk Assign & Confirm Workflow

Use this reference for FinanceManager Budget/Cashflow productivity sprints where **Buchungen prüfen** must support selecting multiple import candidates, assigning categories in bulk, and confirming them only after an explicit preview/confirm boundary.

## Scope boundaries

- This is a productivity fix for the existing import-review workflow, not a new import/source/rule/subscription feature.
- Do not start new VISA/Migros/OCR/provider/import engines while implementing this class of fix.
- Do not bulk-confirm real runtime candidates during implementation/browser sanity unless the user gives explicit current-turn approval for the exact selection.
- Keep `Dry Run/Review → Preview → Confirm → Audit` as the write boundary.
- Never commit runtime DBs, real CSV/XLSX/PDF/DOCX, credentials, build artifacts, caches, or real financial data.

## Backend pattern

Implement bulk operations as a batch wrapper around the existing single-candidate audited operations, but add a central blocker function so preview and confirm use the same rules.

Recommended service contract:

- `preview_batch_confirm_candidates(candidate_ids, account_id, budget_year)` returns:
  - `preview_id`
  - `count` of confirmable candidates
  - `categories: {label: count}`
  - `sources: {source_type: count}`
  - `possible_duplicates`
  - `conflicts: [{candidate_id, reason}]`
  - `blockers` counts for duplicate/covered/transfer/missing-category/missing-required-fields/not-confirmable
  - `can_confirm`
  - `requires_explicit_confirm: true`
- `batch_mark_candidates(... action='category')` should update only editable candidates and return `updated_count`, `skipped_count`, and per-candidate `errors`.
- `batch_mark_candidates(... action='confirm')` must require a `preview_id`, re-run blocker checks, call the existing single-candidate confirm operation, and return `confirmed_count`, `skipped_count`, per-candidate `errors`, and a batch audit ID.
- `action='ignore'` and `action='reopen'` should keep per-candidate audit events plus a batch audit event.

Normal user-mode bulk edit/confirm must block:

- `confirmed`
- `covered_by_source` / `covered_by_migros`
- `auto_ignored_duplicate`
- `superseded`
- reference/archive statuses such as `reference_2025` / `archived_reference`
- `duplicate` / `duplicate_candidate` unless an explicit duplicate force-confirm path is being tested separately
- `transfer_candidate` or transfer classifications unless a dedicated transfer-confirm workflow exists
- candidates outside the active budget year
- missing category for expense/income rows
- missing transaction date, amount, or currency

## Frontend pattern

On **Buchungen prüfen**, add a PrimeVue-compatible toolbar above the candidate table:

- visible selection counter, e.g. `Ausgewählt: N`
- bulk category dropdown
- buttons:
  - `Kategorie auf Auswahl anwenden`
  - `Auswahl bestätigen`
  - `Ignorieren`
  - `Wieder öffnen`
- disabled buttons when no selection or missing required input
- per-candidate error feedback after partial success
- no raw technical IDs in User Mode

Bulk confirm should open a modal/dialog with:

- count of confirmable candidates
- categories summary
- sources summary
- possible duplicate count
- candidates without category
- covered/duplicate/transfer blockers
- warning/conflict list
- final confirm disabled unless `can_confirm === true`

Keep selected rows selected after category assignment unless a reload necessarily clears them; if clearing selection, show a clear toast/message with the updated/skipped counts.

## Test matrix

Backend tests should cover:

- bulk category assignment updates only editable open candidates
- partial success with blocked candidates and visible per-candidate errors
- preview blocks duplicates, covered-source candidates, transfer candidates, missing categories and missing fields
- bulk confirm creates real `budget_transactions`
- candidate status becomes `confirmed`
- `confirmed_transaction_id` is set
- confirmed candidates disappear from open review
- effective expenses/income read models can see the resulting transactions
- bulk ignore/reopen updates multiple candidates and writes audit

Frontend tests should cover:

- selection counter visible
- toolbar/dropdown/buttons visible
- buttons disabled without selection
- category apply calls the batch endpoint with selected IDs and category
- preview dialog shows categories/sources/blockers
- final confirm disabled when blockers exist
- partial success/error message remains visible

## Verification and operations

- Run Python compile and full `pytest` with `JARVIS_FINANCE_DB_PATH` unset unless intentionally testing a fixed runtime DB.
- Run full `npm test -- --run` and `npm run build` from `frontend/`.
- Remove `.pytest_cache`, `__pycache__`, and generated frontend caches/build artifacts before Git-safety scans when appropriate.
- Run source secret scan, frontend build secret scan, Git-safety artifact check, and `git diff --check`.
- Restart backend and Vite from the current checkout with browser-visible Tailscale API base, then browser-sanity check:
  - `Buchungen prüfen` toolbar/dialog/no JS errors
  - `Effektive Ausgaben`/`Effektive Einnahmen` after test-confirmed transactions where applicable
  - `Budgetstatus`
- Commit, push, and verify remote hash.
