Compare commits
4 Commits
08bb334840
...
main
| Author | SHA256 | Date | |
|---|---|---|---|
| 17fca90c9e | |||
| 0c724da30a | |||
| 42ce0ece6d | |||
| 96fc544275 |
74
.claude/skills/auszug-import/SKILL.md
Normal file
74
.claude/skills/auszug-import/SKILL.md
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
---
|
||||||
|
name: auszug-import
|
||||||
|
description: Workflow zur Betreuung von Kontoauszugs-Importen (Inbox scannen, Entwürfe prüfen, Vorschau zusammenfassen, bestätigen) sowie zum Beheben von Parser-Fehlern im Tool-Repo ~/bin/finance. Use when neue PDF-Kontoauszüge importiert werden sollen, ein Import in der Vorschau (draft) auf Bestätigung wartet, oder ein Import mit Fehlerstatus (error) fehlgeschlagen ist und der Parser angepasst werden muss.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Auszug-Import betreuen
|
||||||
|
|
||||||
|
## 1. Status prüfen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
KEY=$(grep '^FB_API_KEY=' $HOME/.local/share/finance_pod/.env | cut -d= -f2 | tr -d "'")
|
||||||
|
curl -s -H "Authorization: Bearer $KEY" http://127.0.0.1:8096/api/imports | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
Falls neue PDFs in der Inbox liegen könnten (`~/.local/share/finance_pod/data/inbox/`),
|
||||||
|
zuerst neu einscannen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -X POST -H "Authorization: Bearer $KEY" http://127.0.0.1:8096/api/imports/scan-inbox | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
Auf Status `draft` (wartet auf Bestätigung) und `error` (Parser
|
||||||
|
fehlgeschlagen) filtern.
|
||||||
|
|
||||||
|
## 2. Drafts: Vorschau prüfen und bestätigen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -H "Authorization: Bearer $KEY" \
|
||||||
|
http://127.0.0.1:8096/api/imports/<id>/preview | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
Dem Nutzer zusammenfassen: Zeitraum, Anzahl Buchungen, Saldo-Check
|
||||||
|
(`balance_ok`), Zahl der erkannten Duplikate. Erst nach ausdrücklicher
|
||||||
|
Bestätigung durch den Nutzer:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -X POST -H "Authorization: Bearer $KEY" \
|
||||||
|
http://127.0.0.1:8096/api/imports/<id>/confirm | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
Nie blind übernehmen — auch bei `balance_ok: true` dem Nutzer die Eckdaten
|
||||||
|
vorlegen.
|
||||||
|
|
||||||
|
## 3. Parser-Fehler beheben
|
||||||
|
|
||||||
|
Bei Status `error` (`error_message` beachten) liegt die Original-PDF weiterhin
|
||||||
|
in der Inbox. Vorgehen im Tool-Repo `/home/wlfb/bin/finance`:
|
||||||
|
|
||||||
|
1. PDF-Text ansehen, um Regexe abzugleichen:
|
||||||
|
```bash
|
||||||
|
cd /home/wlfb/bin/finance && .venv/bin/python scripts/dump_pdf_text.py \
|
||||||
|
~/.local/share/finance_pod/data/inbox/<datei>.pdf
|
||||||
|
```
|
||||||
|
2. Regex-Konstanten im passenden Parser fixen — je nach Bank
|
||||||
|
`app/parsers/vr.py`, `app/parsers/hvb.py` oder `app/parsers/dkb.py`
|
||||||
|
(Bank-Erkennung in `app/parsers/detect.py`, gemeinsames Interface in
|
||||||
|
`app/parsers/base.py`).
|
||||||
|
3. Tests laufen lassen:
|
||||||
|
```bash
|
||||||
|
cd /home/wlfb/bin/finance && .venv/bin/python -m pytest -q
|
||||||
|
```
|
||||||
|
4. Image neu bauen und Pod neu aufsetzen, damit die Parser-Änderung im
|
||||||
|
laufenden Container wirksam wird:
|
||||||
|
```bash
|
||||||
|
cd /home/wlfb/bin && ./create_pod_finance.sh
|
||||||
|
```
|
||||||
|
5. Import erneut anstoßen (`scan-inbox` bzw. erneuter Upload) und Vorschau
|
||||||
|
wie unter Schritt 2 prüfen.
|
||||||
|
|
||||||
|
## Grundregeln (siehe auch CLAUDE.md)
|
||||||
|
|
||||||
|
- Importe immer über die Vorschau bestätigen lassen, nie blind übernehmen.
|
||||||
|
- Echte, bereits bestätigte Buchungen nicht anfassen — nur Entwürfe/Importe
|
||||||
|
in diesem Workflow bearbeiten.
|
||||||
135
.claude/skills/finanz-api/SKILL.md
Normal file
135
.claude/skills/finanz-api/SKILL.md
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
---
|
||||||
|
name: finanz-api
|
||||||
|
description: Referenz aller REST-Endpunkte des Finanzberatungs-Tools (Konten, Buchungen, Kategorien, Regeln, Importe, wiederkehrende/geplante Posten, Kredite, Szenarien) mit curl-Beispielen. Use when Claude Code Daten aus dem Finanzberatungs-Tool lesen oder schreiben soll — Konten/Salden abfragen, Buchungen filtern/anlegen/korrigieren, Importe verwalten, Planungsposten oder Szenarien anlegen und durchrechnen.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Finanz-API
|
||||||
|
|
||||||
|
REST/JSON unter `http://127.0.0.1:8096/api/…`, vollständig dokumentiert unter
|
||||||
|
`http://127.0.0.1:8096/docs` (OpenAPI/Swagger). Alle Endpunkte erfordern den
|
||||||
|
Header `Authorization: Bearer <FB_API_KEY>`.
|
||||||
|
|
||||||
|
## Key extrahieren
|
||||||
|
|
||||||
|
```bash
|
||||||
|
KEY=$(grep '^FB_API_KEY=' $HOME/.local/share/finance_pod/.env | cut -d= -f2 | tr -d "'")
|
||||||
|
```
|
||||||
|
|
||||||
|
Verwende `$KEY` in allen folgenden Beispielen. Den Key niemals ausgeben,
|
||||||
|
loggen oder in Antworten an den Nutzer wiederholen.
|
||||||
|
|
||||||
|
## Konten (`/api/accounts`)
|
||||||
|
|
||||||
|
`GET` (Liste inkl. aktuellem Saldo je Konto), `GET /{id}`, `POST` (Konto
|
||||||
|
anlegen: `bank`, `iban`, `name`, `type`).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -H "Authorization: Bearer $KEY" http://127.0.0.1:8096/api/accounts | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
## Buchungen (`/api/transactions`)
|
||||||
|
|
||||||
|
`GET` mit Filtern `account_id`, `date_from`, `date_to`, `category_id`, `q`
|
||||||
|
(Volltext auf Verwendungszweck/Gegenpartei), `status` (Default `confirmed`),
|
||||||
|
`limit`/`offset`. `POST` legt eine Buchung manuell an (`force: true`
|
||||||
|
überschreibt die Duplikat-Prüfung). `PATCH /{id}` ändert **nur**
|
||||||
|
`category_id` — echte Buchungen sonst nie verändern.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -H "Authorization: Bearer $KEY" \
|
||||||
|
"http://127.0.0.1:8096/api/transactions?date_from=2026-01-01&category_id=3&limit=50" | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
## Kategorien (`/api/categories`)
|
||||||
|
|
||||||
|
`GET`/`POST` (`name`).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -H "Authorization: Bearer $KEY" http://127.0.0.1:8096/api/categories | jq
|
||||||
|
|
||||||
|
curl -s -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
|
||||||
|
-d '{"name": "Energie"}' \
|
||||||
|
http://127.0.0.1:8096/api/categories | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
## Kategorie-Regeln (`/api/category-rules`)
|
||||||
|
|
||||||
|
`GET`/`POST` (`pattern`, `category_id`, `priority`) und
|
||||||
|
`DELETE /api/category-rules/{id}`. Regeln kategorisieren künftige Importe
|
||||||
|
automatisch.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
|
||||||
|
-d '{"pattern": "REWE", "category_id": 3, "priority": 50}' \
|
||||||
|
http://127.0.0.1:8096/api/category-rules | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
## Importe (`/api/imports`)
|
||||||
|
|
||||||
|
`POST /upload` (multipart, PDF), `POST /scan-inbox` (scannt die Inbox neu),
|
||||||
|
`GET` (Liste mit Status `draft`/`confirmed`/`error`), `GET /{id}/preview`
|
||||||
|
(Buchungen + Saldo-Check + Duplikat-Zahl), `POST /{id}/confirm`
|
||||||
|
(übernimmt die Vorschau endgültig), `DELETE /{id}`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -X POST -H "Authorization: Bearer $KEY" \
|
||||||
|
http://127.0.0.1:8096/api/imports/scan-inbox | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
## Wiederkehrende Posten (`/api/recurring`)
|
||||||
|
|
||||||
|
`GET`/`POST` (`name`, `amount`, `rhythm`, `due_day`, `start_date`,
|
||||||
|
`end_date`, `category_id`), `PATCH`/`DELETE /{id}`, sowie
|
||||||
|
`GET /recurring/suggestions` (Muster-Erkennung aus importierten Buchungen).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -H "Authorization: Bearer $KEY" \
|
||||||
|
http://127.0.0.1:8096/api/recurring/suggestions | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
## Geplante Einmalposten (`/api/planned`)
|
||||||
|
|
||||||
|
`GET`/`POST` (`name`, `amount`, `due`, `category_id`), `PATCH`/`DELETE /{id}`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
|
||||||
|
-d '{"name": "Zahnarzt", "amount": -450.00, "due": "2026-09-01"}' \
|
||||||
|
http://127.0.0.1:8096/api/planned | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
## Kredite (`/api/loans`)
|
||||||
|
|
||||||
|
`GET`/`POST` (`name`, `principal`, `annual_rate_pct`, `term_months`,
|
||||||
|
`payout_date`, `repayment_type`: `annuity`|`bullet`), `PATCH`/`DELETE /{id}`,
|
||||||
|
`GET /{id}/schedule` (Tilgungsplan: Rate, Zins, Tilgung, Restschuld je Termin).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -H "Authorization: Bearer $KEY" \
|
||||||
|
http://127.0.0.1:8096/api/loans/1/schedule | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
## Szenarien (`/api/scenarios`)
|
||||||
|
|
||||||
|
`GET`/`POST` (`name`, `description`, `include_recurring`, `include_planned`),
|
||||||
|
`PATCH`/`DELETE /{id}`. Kredit zuordnen: `POST`/`DELETE
|
||||||
|
/{id}/loans/{loan_id}`. Modifikator hinzufügen: `POST /{id}/modifiers` mit
|
||||||
|
`target_type` (`category`|`recurring`), `target_id`, `kind`
|
||||||
|
(`percent`|`absolute`|`remove`), `value`; löschen über `DELETE
|
||||||
|
/{id}/modifiers/{mod_id}`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -X POST -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
|
||||||
|
-d '{"name": "Basis-Szenario"}' \
|
||||||
|
http://127.0.0.1:8096/api/scenarios | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
## Durchrechnen (`/api/scenarios/{id}/project`)
|
||||||
|
|
||||||
|
`POST`, optionale Query-Parameter `horizon_days` und `start_date`. Antwort:
|
||||||
|
`low_point_date`, `low_point_balance`, `below_zero_date`,
|
||||||
|
`below_threshold_date`, `series` (Tagesreihe Datum/Saldo).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -X POST -H "Authorization: Bearer $KEY" \
|
||||||
|
"http://127.0.0.1:8096/api/scenarios/1/project?horizon_days=180" | jq
|
||||||
|
```
|
||||||
61
.claude/skills/finanzberatung/SKILL.md
Normal file
61
.claude/skills/finanzberatung/SKILL.md
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
---
|
||||||
|
name: finanzberatung
|
||||||
|
description: Fünf-Schritte-Workflow für Finanzberatung mit dem Finanzberatungs-Tool — Lage erfassen, Basis-Szenario, Varianten (Kredit/Kürzungen) durchrechnen, vergleichen, Empfehlung mit Zahlen begründen. Use when der Nutzer eine Finanzeinschätzung, Kreditberatung, Sparempfehlung oder Liquiditätsplanung ("reicht das Geld", "brauche ich einen Kredit", "wo kann ich kürzen") anfragt.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Finanzberatung
|
||||||
|
|
||||||
|
Beratung erfolgt datengetrieben über das Finanzberatungs-Tool (Skill
|
||||||
|
`finanz-api` für die API-Details). Kein Rat ohne durchgerechnetes Szenario.
|
||||||
|
|
||||||
|
## 1. Lage erfassen
|
||||||
|
|
||||||
|
- Konten und aktuelle Salden abrufen (`GET /api/accounts`).
|
||||||
|
- Unkategorisierte bzw. auffällige Buchungen prüfen (`GET /api/transactions`
|
||||||
|
ohne `category_id`-Filter bzw. mit `q`), damit Auswertungen nach Kategorie
|
||||||
|
belastbar sind.
|
||||||
|
- Prüfen, ob wiederkehrende Posten gepflegt sind (`GET /api/recurring`); falls
|
||||||
|
lückenhaft, `GET /api/recurring/suggestions` durchgehen und mit dem Nutzer
|
||||||
|
bestätigen/verwerfen, bevor weitergerechnet wird.
|
||||||
|
|
||||||
|
## 2. Basis-Szenario anlegen/durchrechnen
|
||||||
|
|
||||||
|
- Falls noch nicht vorhanden: Basis-Szenario anlegen (`POST /api/scenarios`,
|
||||||
|
ohne Modifikatoren, mit vorhandenen wiederkehrenden/geplanten Posten).
|
||||||
|
- Durchrechnen (`POST /api/scenarios/{id}/project`) und Ergebnis als
|
||||||
|
Referenzlinie festhalten (Tiefpunkt, Unterschreitungsdatum falls vorhanden).
|
||||||
|
|
||||||
|
## 3. Fragestellung in Varianten übersetzen
|
||||||
|
|
||||||
|
- Kreditbedarf: Kredit anlegen (`POST /api/loans` mit Betrag, Zinssatz,
|
||||||
|
Laufzeit, Auszahlungsdatum, Tilgungsart) und dem Szenario zuordnen
|
||||||
|
(`POST /api/scenarios/{id}/loans/{loan_id}`).
|
||||||
|
- Kürzungspotenzial: Modifikatoren je Kategorie oder wiederkehrendem Posten
|
||||||
|
anlegen (`POST /api/scenarios/{id}/modifiers`, `target_type`
|
||||||
|
`category`|`recurring`, `kind` `percent`|`absolute`|`remove`).
|
||||||
|
- Für jede Fragestellung ein eigenes Szenario (Kopie der Idee, nicht das
|
||||||
|
Basis-Szenario verändern), damit Varianten unabhängig vergleichbar bleiben.
|
||||||
|
|
||||||
|
## 4. Varianten durchrechnen
|
||||||
|
|
||||||
|
- Jede Variante mit `POST /api/scenarios/{id}/project` (gleicher Horizont wie
|
||||||
|
das Basis-Szenario, damit die Vergleichswerte konsistent sind) durchrechnen.
|
||||||
|
- Bei Kredit-Varianten zusätzlich den Tilgungsplan ziehen
|
||||||
|
(`GET /api/loans/{id}/schedule`) für Gesamtzinskosten und Ratenhöhe.
|
||||||
|
|
||||||
|
## 5. Vergleichen und Empfehlung formulieren
|
||||||
|
|
||||||
|
- Vergleichstabelle je Variante: Tiefpunkt (Datum + Betrag),
|
||||||
|
Unterschreitungsdatum (Null bzw. Warnschwelle), bei Krediten
|
||||||
|
Gesamtzinskosten und monatliche Rate aus dem Tilgungsplan.
|
||||||
|
- Empfehlung immer mit diesen Zahlen begründen, nicht nur qualitativ.
|
||||||
|
- Hinweis an den Nutzer: Das Grafana-Dashboard „Szenario-Vergleich“
|
||||||
|
(http://127.0.0.1:8097) zeigt die Verlaufskurven der Varianten übereinander
|
||||||
|
mit Nulllinie und Warnschwelle — für die visuelle Gegenprobe verlinken bzw.
|
||||||
|
empfehlen, dort nachzusehen.
|
||||||
|
|
||||||
|
## Grundregeln (siehe auch CLAUDE.md)
|
||||||
|
|
||||||
|
- Echte, bestätigte Buchungen nie ändern — Korrekturen nur als
|
||||||
|
Kategorie-Anpassung.
|
||||||
|
- Zukunftsplanung ausschließlich über Szenarien, nie am Basis-Datenbestand.
|
||||||
18
CLAUDE.md
Normal file
18
CLAUDE.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Finanzberatungs-Umgebung
|
||||||
|
|
||||||
|
Beratung und Auswertung laufen auf Deutsch.
|
||||||
|
|
||||||
|
## Finanzberatungs-Tool
|
||||||
|
- API + Web-GUI: http://127.0.0.1:8096 (OpenAPI: /docs), Grafana: http://127.0.0.1:8097
|
||||||
|
- API-Key: `FB_API_KEY` in `$HOME/.local/share/finance_pod/.env` (Header `Authorization: Bearer <key>`)
|
||||||
|
- Quellcode/Betrieb: Repo `/home/wlfb/bin` (Pod `finance_pod`,
|
||||||
|
`systemctl --user status pod-finance_pod.service`)
|
||||||
|
- Import-Inbox (PDFs hier ablegen): `~/.local/share/finance_pod/data/inbox/`
|
||||||
|
|
||||||
|
## Grundregeln
|
||||||
|
- Echte (bestätigte) Buchungen niemals ändern oder löschen — Korrekturen nur
|
||||||
|
als Kategorie-Anpassung; Zukunftsplanung ausschließlich über Szenarien.
|
||||||
|
- Importe immer über die Vorschau bestätigen lassen, nie blind übernehmen.
|
||||||
|
- Empfehlungen (Kredit, Kürzungen) stets mit durchgerechneten Szenarien und
|
||||||
|
Zahlen (Tiefpunkt, Unterschreitungs-Datum, Ratenhöhe) begründen.
|
||||||
|
- Für API-Nutzung den Skill `finanz-api` verwenden.
|
||||||
218
docs/superpowers/specs/2026-07-17-finanzberatung-design.md
Normal file
218
docs/superpowers/specs/2026-07-17-finanzberatung-design.md
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
# 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.
|
||||||
Reference in New Issue
Block a user