Leonard Surac

Zur Startseite

Im Betrieb · seit 2026

Kassensturz

Meine Frau und ich haben unsere gemeinsamen Ausgaben jeden Monat auf Papier abgerechnet. Ich habe daraus eine App gemacht, die heute unsere komplette Haushaltsabrechnung und meine Finanzen führt.

ASP.NET Core 10 · EF Core · Angular 22 · PostgreSQL · ML.NET · QuestPDF · Playwright

Problem

Meine Frau und ich haben gemeinsame Ausgaben jeden Monat auf einem Papierbogen abgerechnet. Was übrig blieb, haben wir mit einem Rechentrick in den nächsten Monat geschoben, und wenn später noch ein Beleg auftauchte, wusste keiner mehr, welcher Stand eigentlich galt. Meine eigenen Finanzen lagen verstreut in mehreren Banking-Apps.

Meine Rolle

Ich habe die Lösung konzipiert, entwickelt und betreibe sie in meinem Homelab.

Fallstudie

Meine Lösung

Ich habe die Abrechnung so gebaut, wie Buchhaltung funktioniert: Ein abgeschlossener Monat wird eingefroren, und der offene Betrag zwischen uns ist die Summe unveränderlicher Buchungen. Zahlungen und spätere Korrekturen sind eigene Buchungen mit Begründung, nie Änderungen am Alten.

  • Abrechnungsperioden mit Abschluss, Fixkosten-Vorlagen und PDF- und CSV-Export
  • Kontoabruf über PSD2, strikt nur lesend, Belege aus meinem Paperless
  • Buchungen ordne ich über Regeln zu, eine Vorschlags-Inbox und ein lokal trainiertes Modell, ohne externe KI
  • Bargeld trage ich unterwegs per PWA ein; dazu Jahresvergleich, Prognose, Budgets und Abo-Erkennung

Umsetzung

Die Zuordnung fängt immer mit Regeln an, die ich selbst lesen kann. Eine Regel ist eine reine Funktion ohne Datenbank, und erst wenn keine passt, schlägt das Modell etwas vor:

Kassensturz.Api/Domains/Classification/Application/RuleEngine.cs
public static ClassificationRule? FindMatch(IEnumerable<ClassificationRule> rules, BankBooking booking) =>
    rules
        .Where(rule => rule.IsEnabled)
        .OrderBy(rule => rule.Priority)
        .ThenBy(rule => rule.Id)
        .FirstOrDefault(rule => Matches(rule, booking));

Gebaut ist das mit ASP.NET Core, EF Core und PostgreSQL, die Oberfläche mit Angular. Jeder Push läuft durch Tests, einen Vertrags-Check der API und End-to-End-Tests, bevor GitHub Actions über unser privates Netz ausrollt; danach prüft eine automatische Abnahme die laufende App.

Entscheidungen

Der Saldo ist ein Journal
Ich speichere den offenen Betrag nicht, ich rechne ihn aus unveränderlichen Buchungen aus. Das sind mehr Zeilen und etwas mehr Logik, aber jeder Stand lässt sich erklären, auch Monate später.
Unsere Daten bleiben getrennt, auch wenn ich mich irre
Private Daten tragen einen Besitzer ohne Standardwert in der Datenbank. Vergesse ich ihn im Code, gibt es einen Fehler statt einer Buchung beim falschen Menschen. Dafür muss ich den Besitzer überall mitgeben.
KI ohne laufende Kosten
Ich setze zuerst auf Regeln, dann auf ein lokal trainiertes Modell. Automatisch übernommen wird nur bei nachgewiesener Trefferquote und nie bei Buchungen, die unsere gemeinsame Abrechnung betreffen. Ein Teil bleibt Handarbeit.

Ergebnis

Seit Juli 2026 nutzen meine Frau und ich Kassensturz jeden Tag. Abgerechnete Monate bleiben unverändert, offene Beträge sind jederzeit erklärbar, und meine Konten laufen lesend automatisch ein. Dahinter stehen 12 Fachbereiche, rund 850 Backend-Tests und 23 End-to-End-Tests.