Files
fb/docs/superpowers/specs/2026-07-17-finanzberatung-design.md
2026-07-17 15:11:42 +02:00

10 KiB

Design: Finanzberatungs-Umgebung & Finanzberatungs-Tool

Datum: 2026-07-17 · Status: vom Nutzer abgenommen

Ziel

Eine finanziell schwierige Phase planbar machen: Kontobewegungen der nächsten Zeit vorhersagen, Kreditbedarf (Zeitpunkt und Höhe) ermitteln und sinnvolle Ausgabenkürzungen identifizieren. Dazu werden PDF-Kontoauszüge ausgewertet, in einer Datenbank abgelegt und über Szenarien in die Zukunft gerechnet.

Das Vorhaben besteht aus zwei Repositories:

  • ~/fb (dieses Repo): die Claude-Code-Beratungsumgebung — CLAUDE.md, Projekt-Skills, Memory, Spezifikation und Plan. Kein Tool-Code.
  • ~/bin: das Finanzberatungs-Tool als rootless-Podman-Pod mit Web-GUI, API und Grafana.

Rahmenbedingungen (geklärt)

  • Kontoauszüge liegen als PDF vor, von mehreren Konten bei mehreren Banken: Volksbank/Raiffeisenbank, HypoVereinsbank, DKB.
  • PDF-Verarbeitung durch feste, deterministische Parser je Bank (pdfplumber), keine KI-Abhängigkeit im Import.
  • Import immer mit Vorschau: extrahierte Buchungen werden vor der Übernahme angezeigt und explizit bestätigt.
  • Zugriff: Das Tool bindet nur an lokale Ports (ab 8096); externe Erreichbarkeit regelt der bestehende Traefik-Reverse-Proxy/VPN des Betreibers. Zusätzlich eigener Login-Schutz im Tool (siehe Sicherheit).
  • Szenarien umfassen: wiederkehrende Posten, geplante Einmalposten, Kredit-Simulation, Sparpotenzial-Analyse (alle vier bestätigt).
  • Architektur-Entscheidung: Ansatz A, schlanker Pod (drei Container), bewusst gegen feingranulare Microservices (B) und gegen Firefly III (C).

Architektur

Podman Pod finance_pod, erstellt durch ~/bin/create_pod_finance.sh exakt nach dem Muster von ~/bin/example_create_pod_langflow.sh:

  • gepinnte, unveränderliche Image-Tags (kein :latest),
  • Bind-Verzeichnisse unter ~/.local/share/finance_pod/ mit :Z-Flag,
  • podman generate systemd --new + systemd-User-Service pod-finance_pod.service in ~/.config/systemd/user/,
  • Host-IP/Ports als Variablen am Skriptanfang.
Container Image Port (Host → Container)
finance-db_ctr postgres:17.x (gepinnt) nur pod-intern (5432)
finance-api_ctr eigenes Image aus ~/bin/finance/Containerfile 127.0.0.1:8096 → 8000
finance-grafana_ctr grafana/grafana-oss (gepinnt) 127.0.0.1:8097 → 3000

Das Skript baut das API-Image vor dem Pod-Start per podman build.

Bind-Verzeichnisse: postgres-data, grafana-data, inbox (Import-Eingang, auch vom Host direkt befüllbar), uploads (archivierte Original-PDFs).

Sicherheit

  • Web-GUI: Login-Seite mit Benutzername/Passwort, Session-Cookie. Passwort wird beim Setup gesetzt und nur als Hash gespeichert.
  • API: statischer API-Schlüssel (langer Zufallswert), von Claude Code als Authorization: Bearer-Header mitgeschickt; Anfragen ohne gültigen Schlüssel werden abgelehnt.
  • Secrets: ~/bin/finance/.env (gitignored), beim ersten Skriptlauf mit Zufallswerten erzeugt: Postgres-Passwort, API-Schlüssel, Grafana-Admin-Passwort, GUI-Zugangsdaten.
  • Grafana hat zusätzlich seinen eigenen Login; TLS/externes Auth macht Traefik.

Datenmodell (Postgres, SQLAlchemy + Alembic)

  • accounts — Konten: Bank, IBAN, Name, Typ (Giro/Tagesgeld/Kredit).
  • transactions — Buchungen: Buchungs-/Wertstellungsdatum, Betrag (positiv = Eingang), Verwendungszweck, Gegenpartei, Konto, Kategorie, Quell-Auszug, Duplikat-Hash über (Konto, Datum, Betrag, Zweck).
  • categories + category_rules — Kategorien und Zuordnungsregeln (Muster im Verwendungszweck/Gegenpartei → Kategorie), automatische Kategorisierung beim Import.
  • statements — importierte PDFs: Datei, Bank, Konto, Zeitraum, Anfangs-/Endsaldo laut PDF, Status (Entwurf/übernommen/fehlerhaft).
  • recurring_items — wiederkehrende Posten: Betrag, Rhythmus (monatlich/quartalsweise/jährlich), Stichtag, optionales Enddatum.
  • planned_items — geplante Einmalposten: Datum, Betrag, Beschreibung.
  • loans — Kredite: Auszahlungsdatum, Betrag, Zinssatz, Laufzeit, Tilgungsart (Annuität/endfällig).
  • scenarios (+ Zuordnungs-/Modifikator-Tabellen) — benannte Was-wäre-wenn-Pakete; Kürzungs-Modifikatoren auf Kategorien oder einzelne wiederkehrende Posten (prozentual oder absolut, Streichung).

Import-Pipeline

  1. PDF landet in der Inbox (Drag-and-Drop in der GUI oder Datei-Kopie auf dem Host).
  2. Bank-Erkennung anhand von Textmerkmalen wählt den Parser; drei Parser-Module (vr.py, hvb.py, dkb.py) mit gemeinsamem Interface parse(pdf) → (Auszugsdaten, Buchungsliste).
  3. Prüfungen:
    • Saldo-Plausibilisierung: Anfangssaldo + Summe der Buchungen muss den Endsaldo ergeben; Abweichung ⇒ Auszug wird als fehlerhaft markiert und nicht übernommen.
    • Duplikat-Prüfung über den Duplikat-Hash; bereits vorhandene Buchungen werden markiert und nicht doppelt übernommen.
  4. Vorschau (immer): Buchungen werden als Entwurf gespeichert und in der GUI (bzw. per API) als Tabelle mit Saldo-Status, automatischen Kategorien und Duplikat-Markierungen angezeigt.
  5. Bestätigung übernimmt die Buchungen endgültig; danach greifen sie in allen Auswertungen. Fehlgeschlagene Parses bleiben mit Fehlergrund auf der Import-Seite sichtbar, die Original-PDF bleibt in der Inbox.

Szenario-Engine

Reines Python-Modul (app/engine/), ohne DB-/Web-Abhängigkeiten testbar.

  • Eingabe: Startsaldo (echter aktueller Gesamtsaldo bzw. je Konto), Szenario-Definition, Horizont (konfigurierbar, Standard 18 Monate).
  • Abrollen aller Posten zu einem tagesgenauen Zahlungsstrom: wiederkehrende Posten nach Rhythmus, Einmalposten am Datum, Kredite als Auszahlung + berechnete Raten (Annuitätenformel bzw. endfällig, inkl. Zins-/Tilgungsaufteilung und Restschuldverlauf), Kürzungs-Modifikatoren auf die betroffenen Posten/Kategorien.
  • Ausgabe je Szenario: Saldo-Verlauf (Tagesreihe), Tiefpunkt (Datum + Betrag), erstes Datum der Unterschreitung von Null bzw. einer konfigurierbaren Warnschwelle.
  • Ergebnisse werden in Projektions-Tabellen persistiert, damit Grafana sie direkt visualisieren kann; Neuberechnung per Knopf/API-Aufruf.
  • Unterstützung beim Anlegen: Muster-Erkennung über importierte Buchungen schlägt wiederkehrende Posten vor (Bestätigen/Verwerfen durch den Nutzer).
  • Echte Buchungen werden von Szenarien nie verändert.

Web-GUI

FastAPI + Jinja2 + HTMX, deutschsprachig, vier Seiten:

  1. Übersicht: Gesamtsaldo und Saldo je Konto, nächste anstehende Zahlungen, Warnhinweis bei drohender Schwellen-Unterschreitung, eingebettete Grafana-Panels.
  2. Import: Drag-and-Drop-Fläche, Importliste mit Status, Vorschau-Tabelle mit Bestätigen-Aktion.
  3. Buchungen: filterbare Tabelle (Konto, Zeitraum, Kategorie, Volltext), manuelle Kategorien-Korrektur mit „Regel daraus erzeugen“, manuelles Erfassen von Zahlungen/Einkünften per Formular.
  4. Planung: wiederkehrende Posten (inkl. automatischer Vorschläge), Einmalposten, Kredite, Szenarien mit „Durchrechnen“-Aktion und Ergebnisanzeige.

Grafana

Vollständig provisioniert (Datenquelle Postgres mit lesendem DB-User, Dashboards als Dateien im Repo ~/bin/finance/grafana/):

  • Kontostand-Verlauf (je Konto und gesamt),
  • Einnahmen/Ausgaben pro Monat, gestapelt nach Kategorie,
  • Top-Ausgabenkategorien,
  • Szenario-Vergleich (Vorschau-Kurven übereinander, Nulllinie, Warnschwelle).

API für Claude Code

REST/JSON unter http://127.0.0.1:8096/api/…, OpenAPI-dokumentiert. Abgedeckte Funktionen: Konten/Buchungen lesen und anlegen, Kategorien und Regeln verwalten, Import-Status abfragen und Entwürfe bestätigen, wiederkehrende/geplante Posten, Kredite und Szenarien anlegen/ändern, Szenarien durchrechnen und Ergebnisse (Verlauf, Tiefpunkt, Unterschreitung) abrufen.

Claude-Code-Umgebung in ~/fb

  • CLAUDE.md: Umgebungsbeschreibung (API-URL, Ablageort des API-Schlüssels, Sprache Deutsch), Grundregeln („echte Buchungen nie ändern, Planung nur über Szenarien“).
  • Skills (.claude/skills/):
    • finanz-api — Endpunkt-Referenz mit curl-Beispielen,
    • finanzberatung — Beratungs-Workflow: Lage abrufen → Basis-Szenario → Varianten (Kredit/Kürzung) anlegen und rechnen → vergleichen → Empfehlung mit Zahlen begründen,
    • auszug-import — Import-Betreuung: wartende/fehlgeschlagene Importe prüfen, Parser-Fehler im ~/bin-Repo beheben.
  • Memory: Kategorien-Konventionen, Entscheidungen (z. B. Warnschwelle), Eigenheiten einzelner Banken/Auszüge.

Projektstruktur ~/bin

~/bin/
├── create_pod_finance.sh        # Pod-Skript nach dem Beispiel-Muster
└── finance/
    ├── Containerfile            # Image für finance-api_ctr
    ├── .env                     # Secrets (gitignored, vom Skript erzeugt)
    ├── app/                     # FastAPI: API-Routen, GUI-Routen, Auth
    │   ├── models/              # SQLAlchemy-Tabellen + Alembic-Migrationen
    │   ├── parsers/             # vr.py, hvb.py, dkb.py + Bank-Erkennung
    │   ├── engine/              # Szenario-/Kredit-Rechnung (reines Python)
    │   └── templates/           # Jinja2 + HTMX
    ├── grafana/                 # provisionierte Datenquelle + Dashboards
    └── tests/                   # pytest
        └── fixtures/            # Beispiel-PDFs je Bank (gitignored)

Tests

Testgetriebene Entwicklung (pytest):

  • Engine: Annuitäten-/Zins-Mathematik und Projektionslogik als Unit-Tests (zuerst geschrieben).
  • Parser: Tests gegen echte Beispiel-PDFs in tests/fixtures/ (gitignored). Der Nutzer stellt pro Bank mindestens einen echten Auszug bereit (Beträge dürfen verfremdet sein, Layout muss echt sein) — zugesagt.
  • API/GUI: FastAPI-TestClient gegen eine Test-Datenbank.
  • Deployment: Smoke-Test am Skriptende (analog Beispiel-Skript: curl-Readiness-Check auf GUI und Grafana).

Bewusst weggelassen (YAGNI)

  • Kein automatischer Bank-Abruf (FinTS/PSD2) — Import nur über PDFs.
  • Keine Mehrbenutzer-/Rollenverwaltung — ein GUI-Login genügt.
  • Kein KI-Aufruf im Server — KI-Nutzung ausschließlich über Claude Code gegen die API.
  • Keine Sofort-Übernahme beim Import — Vorschau ist verpflichtend.