GuidoandClaude Opus 5 8ceee5c5b1 feat: Ein Uebertrag faengt seine Gegenseite ab
Ein Uebertrag legte auf dem Zielkonto nichts an. Der Duplikatschutz konnte die
Gegenseite deshalb nicht sehen – er vergleicht import_hash, den eine
Uebertrags-Buchung nicht hat, und Eingangs-Eintraege, die es dort nicht gab.
Die schon vorliegende Gegenseite liess sich ein zweites Mal buchen, die
spaeter von der Bank gelieferte kam ungeprueft an: das Geld zweimal auf dem
Zielkonto.

Jetzt entsteht auf dem Zielkonto ein Eingangs-Eintrag, der auf DIESELBE Buchung
zeigt. Liegt dort schon ein passender offener Eintrag, wird dieser verbraucht
statt einen zweiten anzulegen – ueber denselben Abgleich wie beim Import, nicht
ueber eine zweite Vergleichslogik. Damit greift auch der vorhandene Schutz
gegen die spaeter eintreffende Gegenseite, ohne dass etwas Neues dafuer gebaut
werden musste.

Die Uebertrags-Logik liegt dafuer in einem eigenen Dienst. Zwei Wege fuehren
hinein – ein offener Vorschlag und eine schon gebuchte Buchung – und beide
brauchen dieselben vier Regeln. Der PATCH-Weg des Buchungs-Routers taete es
nicht: Er dreht die Richtung bei einer Einnahme nicht um und legt keine
Gegenseite an.

Die Sperre richtet sich nicht mehr nach der Waehrung, sondern danach, ob der
Betrag der Gegenseite BEKANNT oder geschaetzt ist. Bei gleicher Waehrung ist er
exakt, die Gegenseite wird sicher wiedererkannt – dann geht ein Uebertrag auf
ein angebundenes Konto ohne Nachfrage durch. Ueber Waehrungen hinweg bleibt die
Warnung, weil der EZB-Kurs nicht der Kurs der Bank ist.

Und Verwerfen raeumt beide Seiten: Bei einem Uebertrag zeigen zwei Eintraege
auf dieselbe Buchung, und der Fremdschluessel haette die andere als 'gebucht'
ohne Buchung zurueckgelassen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 10:13:52 +02:00

Certain Finance

Selbstgehostete Finanzverwaltung für Privathaushalte. Budgets, mehrere Konten (EUR und CHF), ein konfigurierbares Dashboard und Import von Kontoauszügen – lauffähig in einem Proxmox-LXC, erreichbar über eine Web-UI hinter dem eigenen Nginx Proxy Manager.

Der interne Codename/Anzeigename steht zentral an einer Stelle (web/src/brand.js, backend/app/branding.py); der Rest ist generisch.

Stack

  • Backend: FastAPI · SQLAlchemy · SQLite · Alembic · argon2 · Server-Sitzungen (Cookie)
  • Frontend: React 18 · Vite · reines JSX · react-i18next (DE/EN) · Inline-SVG-Icons
  • Betrieb: ein systemd-Dienst (uvicorn) liefert API und gebautes Frontend auf einem Port aus

Entwicklung (lokal)

Backend (Terminal 1):

cd backend
python3 -m venv .venv && . .venv/bin/activate   # Python 3.11+
pip install -r requirements.txt
APP_DATA_DIR=./data uvicorn app.main:app --reload --port 8000

Frontend (Terminal 2):

cd web
npm install
npm run dev        # http://localhost:5173  (leitet /api an :8000 weiter)

Beim ersten Start wird ein Admin angelegt (Standard admin / changeme, per APP_ADMIN_USERNAME / APP_ADMIN_PASSWORD änderbar).

Installation im LXC (Proxmox, Debian/Ubuntu)

git clone <repo-url> /opt/certain-finance
cd /opt/certain-finance
sudo ./deploy/install.sh

Danach im Nginx Proxy Manager einen Proxy-Host auf http://<LXC-IP>:<APP_PORT> anlegen (HTTPS via Let's Encrypt). Updates: sudo ./deploy/update.sh.

Details: docs/ARCHITECTURE.md · Fahrplan: docs/ROADMAP.md

S
Description
No description provided
Readme
8.7 MiB
Languages
Python 55.3%
JavaScript 22.8%
Swift 16.3%
CSS 5%
Shell 0.6%