# Sprint 15 – versionsgebundene Haushaltsinventur

## Bindung

- Inventur-HEAD: `7411df5ad88ab4b2bebd2ec5c7008aea18d4d7ca`
- `main`, `origin/main`, Merge-Base und Deployment-HEAD wurden vor Branch-Erstellung auf diesen Commit abgeglichen.
- Branch: `Sprint15/household-import-transfer-reconciliation-v1`
- Ausgangsschema: 46 (`046_investment_performance_scope_v1`)
- Ziel: bestehende Budget-/Haushalts-, Kandidaten-, Ledger- und Transferarchitektur konsolidieren; keine Parallelengine.

## Persistenz und wiederzuverwendende Verträge

| Fachbereich | Bestehende Tabellen / Vertrag | Primäre Implementierung |
|---|---|---|
| Kanonische Cashkonten | `accounts`, `cash_account_snapshots`, `accounts.performance_included` | `services/cash_service.py`; `/portfolio/cash` |
| Haushaltskonten | `budget_accounts.linked_account_id` bindet an `accounts` | `services/budget_accounts.py` |
| Kategorien/Tags | `budget_categories`, `budget_tags`, `budget_transaction_tags` | `services/budget_categories.py` |
| Haushaltsledger | `budget_transactions`, `budget_transaction_splits` | `services/budget_transactions.py` |
| Transfers | `budget_transfers`, `budget_transfer_pairs` | `services/budget_transactions.py`, `services/transfer_pairing.py` |
| Importkandidaten | `budget_transaction_candidates`, `budget_import_line_items`, `budget_candidate_splits` | `services/budget_imports.py` |
| Importbatches | `budget_import_sessions` | `services/budget_import_upload.py`, `services/budget_monthly_import.py` |
| Review | Kandidatenstatus + `budget_review_rules`; aggregiert durch `budget_import_status.py` | `build_review_backlog_dashboard` |
| Budgetpläne/Seeds | `budget_plan_items`, `budget_seed_candidates` | `services/budget_plans.py`, `services/budget_seed_review.py` |
| Händler/Regeln | `budget_merchants`, `budget_merchant_aliases`, `budget_import_rules`, `budget_rule_suggestions` | `services/budget_imports.py`, `services/budget_monthly_import.py` |
| Audit | globales append-orientiertes `audit_log` | `audit/log.py::record_audit_event` |
| Migros-Details | Kandidaten/Line-Items sowie `grocery_product_items` | `budget_imports.py`, `grocery_optimizer.py` |

## Bestehende Importquellen

`services/budget_csv_imports.py` enthält vier Profile, die weiterverwendet werden:

- `akb_bank`: Buchung/Valuta/Buchungstext/Belastung/Gutschrift;
- `raiffeisen_bank`: IBAN/Booked At/Text/Credit-Debit Amount/Valuta Date;
- `visa_credit_card`: TransactionId/CardId/Date/Amount/Currency/MerchantName;
- `migros_receipts`: Datum/Zeit/Filiale/Transaktionsnummer/Artikel/Umsatz.

`services/budget_imports.py` enthält bestehende Seeder für Bank, Kreditkarte und Migros sowie Händlernormalisierung, Kategorienregeln, Kandidatenreview, Splits und Confirm. Manuelle Buchungen bleiben über `services/budget_transactions.py` bestehen.

## Festgestellte Lücken gegenüber `household_import_v1`

1. Upload-Preview archiviert aktuell die Rohdatei und schreibt `budget_import_sessions`; Dry-Run ist daher nicht strikt read-only.
2. Der aktuelle Dry-Run liefert im Wesentlichen Zeilenzahlen statt einer vollständigen normalisierten Vorschau.
3. Confirm ist an eine persistierte Preview-ID, nicht an einen vollständigen stabilen Preview-Fingerprint und einen DB-Baseline-Fingerprint gebunden.
4. Dateihash und `raw_fingerprint` existieren, aber der dreistufige Vertrag Datei/Quellzeile/logische Buchung ist nicht explizit und vollständig durch Unique-Verträge geschützt.
5. Eine isolierte synthetische Baseline-Probe zeigte: dieselbe VISA-Zeile unter anderem Dateinamen erzeugt einen zweiten Kandidaten; derselbe Migros-Bon wird dagegen bereits über `receipt_key` abgefangen.
6. Eine VISA-Probe mit `-10.00 EUR` verlor im bisherigen Seeder Vorzeichen, Originalwährung und Kartenkonto (`amount_original=10.00`, `signed_amount_original=NULL`, `currency_original=CHF`). Diese Semantik muss vor Confirm fail-closed korrigiert werden.
7. Gleiche Quellzeilen aus überlappenden Dateien können in einzelnen Pfaden erneut als Kandidat angelegt werden.
8. `transfer_pairing_v2` verwendet Betrag, Währung, Datum und Konten; `_own_account` kann jedoch auf Namen/Hints zurückfallen. Für Sprint 15 ist eine stabile, maskierte Quellreferenz-Zuordnung erforderlich.
9. Transfer v2 kennt vorgeschlagen/bestätigt/unmatched, aber nicht den geforderten vierklassigen, batchfähigen Importentscheidungsvertrag.
10. Sichere Paarungen werden bisher erst nach separatem Paar-Confirm verbucht; der Sprint verlangt automatische Verbuchung innerhalb eines bestätigten Batches.
11. Kreditkartenzahlung, pending/final sowie Refund/Storno benötigen explizite deterministische Klassifikation und Tests.
12. Migros ist teilweise als Coverage-/Detailquelle vorhanden, aber Gesamtbetrag, Abweichung > CHF 0.01 und kanonischer Geldbewegungslink sind nicht als eigener reproduzierbarer Vertrag persistiert.
13. Bestehende Budget-URLs sind umfangreich; die vier gewünschten `/household`-URLs fehlen.

## API-Inventur und Seiteneffekte

Wiederzuverwenden und kompatibel halten:

- `GET /api/budget/import-status-audit`
- `GET /api/budget/review-backlog`
- `GET /api/budget/monthly-import/dashboard`
- `GET /api/budget/monthly-import/history`
- `GET /api/budget/dashboard/cockpit`
- `GET /api/budget/recurring`
- Kandidaten-, Transfer-, Kategorien-, Händler- und Regelendpunkte im bestehenden `budget`-Router.

Die GET-Auswertungen sind lokale DB-Lesewege. Provider-/Drive-Aktionen liegen auf expliziten POST-Pfaden. Der neue Household-Readpfad bleibt providerfrei und mutationsfrei.

## Kontoerstellung und Abgrenzung

Kontoerstellung existiert in mehreren Domänen (`budget_accounts`, Cash-Canonicalizer, generische Account-Importer, Broker-/Manual-Entry-Pfade). Der Household-Import darf keinen davon automatisch aufrufen. Er akzeptiert ausschließlich ein aktives `budget_account`, das eindeutig über `linked_account_id` mit einem existierenden kanonischen `accounts`-Datensatz verbunden ist. Quellen werden über Quelltyp plus einen installationsgebundenen HMAC-Tag der normalisierten Kontoreferenz oder explizit bestätigte Konfiguration zugeordnet. Der HMAC-Schlüssel liegt nur als Runtime-Secret außerhalb von Datenbank, Git, Audit und Browser. Namen sind nur Anzeige, nie Identität.

## Versionsentscheidungen Sprint 15

- Neuer Importvertrag: `household_import_v1`.
- Transfer-Pairing: bestehende Architektur bleibt; materielle Erweiterung wird als `transfer_pairing_v3` ausgewiesen, während v2-Daten/Evidence unverändert lesbar bleiben.
- Persistente Erweiterungen benötigen Schema 47.
- Preview bleibt transaktions- und dateispeicherfrei; Confirm muss die Eingabe erneut senden, die Preview deterministisch rekonstruieren und sowohl Preview- als auch Baseline-Fingerprint prüfen.
- Confirm schreibt bestehende `budget_transaction_candidates`, `budget_transactions`, `budget_transfers` und `budget_transfer_pairs`; neue Tabellen dienen nur der Quellzuordnung, batchweiten Identität/Audit und Migros-Verknüpfung.
- Produktive reale Dateien werden weder in Git noch Browserantworten, Logs oder Abschlussberichte aufgenommen. Kein produktiver Confirm ohne separates Nutzer-Gate.

## Abnahme- und Betriebsgrenzen

- Öffentliche Preview-Zeilen und Dateien verwenden ausschließlich request-lokale Ordinal-Token; persistente Quell-, Datei- und Logik-Tags werden nicht zurückgegeben.
- Nur der explizite Drive-Scan-POST darf den externen Provider starten. Household-GET und Import-Preview sind lokale, mutationsfreie Datenbankpfade.
- Logische oder Legacy-Überschneidungen bleiben Reviewfälle. Sie dürfen weder durch Reversal-Erkennung noch Transfer-Pairing nachträglich automatisch bestätigt werden.
- Das generische Wort `payment` ist kein sicherer Transferbeleg. Sichere Kartenabrechnungen benötigen die explizite Kreditkartenklassifikation; übrige Transfers benötigen eindeutige Eigenkonto-Evidenz.
- Der produktive Dienst benötigt `JARVIS_FINANCE_FINGERPRINT_KEY` aus einer owner-only Runtime-Umgebungsdatei. Fehlt der Schlüssel, schlagen fingerprintabhängige Wege fail-closed fehl.
- Der erste Confirm einer neuen realen produktiven Importdatei bleibt auch nach Deployment gesperrt, bis der Nutzer ihn erneut ausdrücklich freigibt.
