Commit Graph
115 Commits
Author SHA1 Message Date
ScarriffleandClaude Opus 5 dd2c33725f feat: Ein Markenlogo je Vertrag
Am Logo findet man den Vertrag schneller als am Namen: Netflix erkennt man am
roten N, nicht am Wort – und erst recht nicht an einem Zahnrad aus der
Symbolauswahl. Die bleibt als Rueckfall fuer alles, wozu es kein Logo gibt.

Hochgeladen wird, was das Telefon hergibt; gespeichert ein PNG von hoechstens
128 Pixeln Kantenlaenge. Aus drei Megabyte werden ein paar Kilobyte, und das
Seitenverhaeltnis bleibt – ein verzerrtes Logo sieht falscher aus als ein
kleines.

Immer PNG, egal was hereinkam. Das erspart der Anzeige jede
Fallunterscheidung und schliesst SVG aus: Eine SVG-Datei kann Skript
enthalten, und ein Bild, das der Nutzer hochlaedt und der Browser ausfuehrt,
ist genau die Art Falle, die man sich nicht in ein Finanzprogramm legt.

Eigene Tabelle, nicht eine Spalte an den Vertraegen: Sonst zoege jede
Listenabfrage saemtliche Bilder mit heraus, obwohl die Liste sie einzeln
nachlaedt.

ZWEI FEHLER IM SICHERN, die dabei aufgefallen sind:

Binaeres liess sich gar nicht sichern – die Ausgabe scheiterte an den Bytes,
und zwar erst beim Schreiben, also nachdem der Nutzer glaubt, ein Backup zu
haben. Jetzt Base64.

Und "Ergaenzen" legte Zeilen von Tabellen mit natuerlichem Schluessel ein
zweites Mal an, statt sie wiederzuerkennen. Beim Logo kippte damit die ganze
Wiederherstellung. Betraf bisher keine Tabelle, weil noch keine solche einen
Vergleichsschluessel hatte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 19:35:37 +02:00
ScarriffleandClaude Opus 5 0a790fd45a feat: Nur die Waehrungen zeigen, die man braucht – und auf dem Telefon lesbar
Drei Sachen, die beim Benutzen aufgefallen sind.

ANGEBOTENE WAEHRUNGEN. In den Einstellungen steht jetzt, welche Waehrungen in
den Auswahlfeldern erscheinen (Vorgabe EUR, CHF, USD). Dass dreissig
unterstuetzt werden, ist gut; dreissig Zeilen in einem Feld zu sehen, wenn man
drei davon braucht, ist es nicht.

Die Einstellung beschraenkt nur die ANZEIGE. Gueltig bleibt alles mit
EZB-Kurs, und die gerade gesetzte Waehrung steht IMMER im Feld – sonst stuende
ein Konto in Dollar vor einem Feld ohne Dollar und wechselte beim naechsten
Speichern stillschweigend die Waehrung. Der Saldo waere danach still falsch.
Die Hauptwaehrung laesst sich nicht abwaehlen.

ZEICHEN STATT KUERZEL, wo es hilft: "€ EUR", "$ USD", "£ GBP". CHF steht
bewusst ohne: "Fr." ist weniger gelaeufig als CHF selbst. Mehrfach belegte
Zeichen bleiben ebenfalls draussen – "US$" von "CA$" zu unterscheiden ist
Raetselraten.

AUF DEM TELEFON. Die Vertragszeile quetschte vier Spalten in 375 Pixel; vom
Namen blieb "Sal..." uebrig und von der Kategorie ein Punkt. Sie ist jetzt ein
Gitter: Unter 620 Pixel rutscht der Betrag unter den Namen, die Knoepfe
bleiben rechts. Der Name bekommt die volle Breite – auf dem Telefon ist er das
Einzige, woran man die Zeile erkennt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 16:16:45 +02:00
ScarriffleandClaude Opus 5 f99be47587 feat: Abos & Vertraege – was regelmaessig abgeht, an einer Stelle
Netflix, Handyvertrag, Krankenkasse, Halbtax. Bisher sah man sie nur als
einzelne Buchungen im Auszug; die Frage "welche Abos habe ich eigentlich, und
was kosten die zusammen im Monat" liess sich nicht beantworten. Genau die
steht jetzt oben auf der Seite.

Der Bereich heisst "Abos & Vertraege", nicht "Abos": Ein Handyvertrag ist kein
Abo und die Versicherung erst recht nicht – niemand soll ueberlegen muessen,
wo sie hingehoert.

Der Monatswert wird gerechnet, nicht gespeichert (Betrag durch Intervall).
Gespeichert veraltete er beim naechsten Preisaufschlag stillschweigend.

Bei laengerem Intervall klappt "Ich lege monatlich zurueck auf" auf, mit dem
gerechneten Monatsbetrag daneben. Bei monatlicher Abrechnung gibt es nichts
anzusparen, also steht es da auch nicht.

DAZU: Waehrungen sind offen.

Die Rechen-Maschinerie konnte immer schon beliebige Waehrungen – sie rechnet
ueber den Euro als Drehpunkt. Beschraenkt haben es zwei Konstanten: eine
Erlaubnisliste mit EUR und CHF, und ein Filter, der aus dem EZB-Feed alles
ausser CHF wegwarf, obwohl er dreissig Waehrungen liefert.

Massgeblich ist jetzt die Liste der EZB. Frei erfundene Waehrungen bleiben
draussen, und das ist kein Geiz: Ohne Kurs liesse sich der Betrag nie
umrechnen – er stuende in keiner Summe und in keinem Budget, und das faellt
erst spaet auf. Ein Vertrag in einer Waehrung ohne Kurs wird deshalb genannt,
statt die Summe stillschweigend zu klein anzuzeigen.

Erkannt und gebucht wird noch nichts; der Erkennungstext wird nur erfasst.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 15:45:59 +02:00
ScarriffleandClaude Opus 5 ff621984dc feat: Eine Ausgabe, die kein Verlust ist
Sparen zaehlt im Budget wie eine Ausgabe – zu Recht, das Geld ist diesen Monat
gebunden. Es stand danach aber in Rot da, und wer tausend zuruecklegte statt
achthundert, bekam eine Warnung fuer etwas Gutes.

Ein Haken an der Kategorie stellt das ab. Zwei Folgen:

Der Betrag steht neutral. NICHT gruen: Gruen heisst in Certain ueberall "Geld
kommt rein", und CHF 1'010 in Gruen liest sich als Einnahme. Grau sagt genau
das Richtige – kein Verlust, kein Gewinn.

Und mehr als geplant ist keine Ueberschreitung mehr. Das gilt auch eine Ebene
hoeher: Eine Gruppe misst sich an dem, was WIRKLICH zu viel war. Sonst faerbt
sich "Finanzen" rot, weil jemand gespart hat, und die echte Ueberschreitung
daneben faellt nicht mehr auf. Angezeigt werden weiter die vollen Summen; nur
das Urteil laesst das Sparen aus.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 15:28:36 +02:00
ScarriffleandClaude Opus 5 b69c383a72 fix: "Nicht in Auswertungen einrechnen" galt fuer Sparen nicht
Wer den Haken an einer Kategorie setzt, sagt damit ausdruecklich: nicht ins
Budget, nicht ins Dashboard, nicht in die Statistik. Die Sparen-Auswertung
las ihn nicht – das Geld stand danach im Ringdiagramm, obwohl der Nutzer
genau das abbestellt hatte.

Beide Uebertrags-Wege halten sich jetzt daran, der am Stueck wie der aus zwei
verknuepften Buchungen. Der Haken an der Kategorie gewinnt; ein Sparziel am
Konto darf ihn nicht stillschweigend aushebeln.

Und weil beides zusammen keinen Sinn ergibt, sagt es das Konto-Formular jetzt
auch: Waehlt man dort eine Kategorie mit Haken, steht darunter, dass so nichts
im Budget erscheinen wird.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 14:13:22 +02:00
ScarriffleandClaude Opus 5 25392b9d08 feat: Ein Konto kann sagen, dass Ueberweisungen darauf Sparen sind
Wer auf ein Pocket spart, budgetiert dafuer eine Ausgabe – im Budget stand
davon aber nichts. Zwei Gruende:

Erstens gibt es zwei Formen von Uebertrag. Die eine ist EINE Buchung mit
Zielkonto, wie sie das Formular anlegt; nur fuer die gab es die Sparen-Logik.
Die andere sind ZWEI verknuepfte Buchungen, und genau so kommt ein Uebertrag
ueber die Bankanbindung herein. Beide Seiten uebersprang die Auswertung
ausnahmslos.

Zweitens hing das Sparen am Kontotyp. Ein Revolut-Pocket ist bei der Bank ein
ganz normales Konto und kommt als "girokonto" herein – am Typ ist nicht
abzulesen, dass man darauf spart.

Jetzt sagt man es dem Konto einmal ("Sparen gegen Kategorie X"), und es gilt
fuer beide Formen. Wer eine einzelne Bewegung anders sieht, nimmt sie an der
Buchung heraus oder gibt ihr eine eigene Kategorie – dieselben zwei Felder wie
bisher.

Der Normalfall aendert sich nicht: Ein Uebertrag auf ein Konto ohne Sparziel
ist weiterhin bloss verschobenes Geld.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 13:53:26 +02:00
ScarriffleandClaude Opus 5 991a8e4fc2 fix: Die Kennung der Bank steht jetzt an der Buchung selbst
Bisher lag sie nur am Eingangs-Eintrag. Das reicht nicht: Der Eintrag ist eine
Zwischenstation und faellt weg, wenn ein Konto geloescht wird oder ein aelteres
Backup ihn nicht kannte. Dann war die Zahlung fuer den naechsten Abruf neu,
obwohl sie laengst gebucht war.

Am schlimmsten bei einem als Uebertrag gebuchten Umsatz: Der ist von der
Aehnlichkeitspruefung ausgenommen, dort griff also gar nichts mehr.

Die Kennung gehoert deshalb an die Buchung (transactions.source_uid, mit der
Quelle davor). Dort ueberlebt sie alles, was mit dem Eingang passiert, und die
Eindeutigkeit haelt die Datenbank selbst durch – nicht erst der pruefende Code
davor. Gestempelt wird an allen drei Buchungswegen: Eingang, Kurzbefehl und
Uebertrag.

Vorhandene Buchungen bekommen die Kennung nachgetragen, solange ihr
Eingangs-Eintrag noch da ist.

Ohne Kennung – von Hand erfasst, aus einer CSV-Datei – bleibt es beim
bisherigen Schutz ueber die Aehnlichkeit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 11:59:43 +02:00
GuidoandClaude Opus 5 ee36dae34a feat: Zeigen, welche Buchungen in einem Ausgaben-Anteil stecken
Eine Zahl, die man nicht aufschluesseln kann, muss man glauben. Genau das
war der Streitpunkt: Die Karte nannte fuer Lebensmittel einen Betrag, und
es gab keine Moeglichkeit nachzusehen, welche Zahlungen darin einbezogen
sind und welche nicht.

Jetzt oeffnet ein Klick auf einen Anteil - in der Liste wie in der
Legende des Kreises - die Buchungen dahinter: Datum, Empfaenger, Konto,
Betrag. Die Liste kommt aus derselben Stelle, die auch die Summe bildet
(`budget.expense_rows`), sie kann also gar nicht etwas anderes zeigen als
das, was gezaehlt wurde. Ein Test haelt das fest.

Steht eine Buchung darin, obwohl ihr Datum ausserhalb des Zeitraums
liegt, traegt sie die Kalendermarke: Dann wurde ihr Budget-Monat von Hand
gesetzt, und das ist der Grund.

Nebenbei: Dialoge haengen jetzt am Seitenkoerper. Kacheln der Uebersicht
werden per `transform` positioniert - damit war die Kachel der
Bezugsrahmen fuer `position: fixed`, und der Dialog sass eingeklemmt
darin statt ueber der Seite.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 15:10:19 +02:00
GuidoandClaude Opus 5 0b19e07ce0 feat: Zu welchem Budget-Monat eine Buchung gehoert
Bisher entschied allein das Datum. Bei einem Budget-Monat, der nicht am
Ersten beginnt, faellt das auf: Die Zahlung geht am 24. ab und gehoert
doch zum naechsten Monat, die Rechnung wird verspaetet beglichen und
gehoert zum letzten.

Neu traegt jede Buchung einen Budget-Monat. Leer heisst weiterhin "aus dem
Datum" - der Normalfall, und er bleibt es. Wird einer von Hand gesetzt,
zaehlt die Buchung nur noch dort und in ihrem eigenen Monat NICHT mehr,
sonst stuende sie zweimal da.

Das Aendern liegt bewusst hinter einem Klick und hinter Pfeilen statt
hinter einer Auswahlliste: Es ist der Ausnahmefall, nicht der Normalfall,
und soll sich auch so anfuehlen. Waehlt man genau den Monat, der ohnehin
gilt, bleibt die Buchung automatisch - verschiebt sich das Datum spaeter,
wandert sie mit. In der Liste zeigt eine Marke den Monat, aber nur, wenn
jemand eingegriffen hat.

Der Server nimmt drei Monate in jede Richtung an. Ein Vertipper wie
2019-03 wird abgelehnt: Er liesse die Buchung aus jeder Auswertung
verschwinden, ohne dass irgendwo etwas fehlt.

Geprueft im Browser gegen eine Wegwerf-Datenbank mit Stichtag 25: Die
Karte summiert 25.08.-24.09., eine verschobene Buchung verlaesst diesen
Zeitraum und kehrt beim Zuruecknehmen zurueck.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 14:57:16 +02:00
GuidoandClaude Opus 5 bd79b83339 feat: Zeitraum an der Karte, und eine schaerfere Suche nach Dubletten
Zwei Dinge, die zusammen die Frage beantworten "zaehlt das wirklich ab
meinem Stichtag, und sind das wirklich zwei Zahlungen?".

Die Karte Ausgaben-Anteile nennt jetzt ihren Zeitraum. Gerechnet hat sie
schon immer ueber den eingestellten Budget-Monat (25.08.-24.09. bei
Starttag 25); nachvollziehen liess sich das nur nicht, weil die Karte
nirgends sagte, worueber sie summiert.

Die Dublettensuche vergleicht nicht mehr stur ueber den Text. Ein krummer
Betrag wie 10.43 kommt an einem Tag kaum zweimal vor - auch wenn zwei
Quellen ihn verschieden benennen, und genau daran scheiterte der
Textvergleich. Bei einem runden Betrag (Vielfaches von 50 Rappen) muss der
Text weiter passen, sonst waeren zwei Zwanziger am selben Tag ein Fund.

Und was die Bank selbst als verschieden gemeldet hat, gilt als geklaert:
Stammen alle Zeilen aus demselben Bankkonto und tragen verschiedene
Kennungen, verschweigt die Karte sie. Das sind die Revolut-Aufrundungen,
die echt sind.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 14:39:08 +02:00
GuidoandClaude Opus 5 335a7d55c8 feat: Gleich aussehende Buchungen stehen in der Arbeitsliste
Bisher fand man Dubletten nur zufaellig beim Durchscrollen der Buchungsliste –
oder ich habe ein Skript dafuer geschrieben, und der Nutzer musste sich auf
einen Server einloggen, um seine eigenen Zahlen zu reparieren. Beides ist
falsch.

Die Arbeitsliste zeigt sie jetzt: gleiches Konto, gleicher Tag, gleicher
Betrag, gleicher Text. Je Zeile steht die Kennung der Bank dabei, und die
entscheidet die Frage – dieselbe Kennung heisst sicher dieselbe Zahlung,
verschiedene heissen, die Bank hat sie als verschieden gemeldet.

Entschieden wird bewusst NICHTS von selbst. Drei Aufrundungen ueber 1.00 am
selben Tag sind echt, drei gleiche Einkaeufe koennen es auch sein; das weiss
nur der Nutzer. Certain meldet und laesst loeschen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 14:32:40 +02:00
GuidoandClaude Opus 5 63056ae76a feat: Ringdiagramm faerbt Legende und Mitte nach Budget
Eingefaerbt war bisher nur die Listen-Darstellung der Ausgaben-Anteile. In der
Kreis-Darstellung blieben die Betraege der Legende grau, und die Summe in der
Mitte sagte gar nichts ueber den Stand.

Jetzt tragen beide die Aussage: gruen im geplanten Rahmen, rot darueber. Faehrt
man ein Segment an, zeigt die Mitte dessen Betrag – dann gilt dort das Budget
dieser Kategorie, sonst das des Ganzen.

Fuer die Mitte liefert der Server jetzt auch das Geplante ueber ALLE
Ausgaben-Einheiten, nicht nur ueber die mit Ausgaben: Der Monatsplan umfasst
auch, wofuer noch nichts ausgegeben wurde.

Ohne Plan bleibt alles, wie es war. Der Donut faerbt nur, wenn ein Segment die
Angabe mitbringt – die Budget-Karte, die dieselbe Komponente benutzt, bleibt
also unberuehrt.

Der Test hat dabei gleich einen Fehler gefunden: ``_units`` ist ein Generator,
und ich lief zweimal darueber – beim zweiten Mal war er leer und das Geplante
immer 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 14:13:49 +02:00
GuidoandClaude Opus 5 5e70644f73 feat: Ausgaben-Anteile faerben nach Budget
Die Karte zeigte nur, wie sich die Ausgaben verteilen – nicht, ob sie im
Rahmen liegen. Der Betrag ist jetzt gruen, solange er unter dem Geplanten
bleibt, und rot darueber. Dieselben Farben wie ueberall sonst fuer Einnahme
und Ausgabe.

Ohne Plan bleibt der Betrag gedeckt. "Ueber Budget" waere sonst die Aussage
ueber jede Kategorie, fuer die nie eine Vorgabe gemacht wurde – die Karte
stuende dann fast durchgehend auf Rot und sagte nichts mehr.

Das Geplante kommt aus derselben Quelle wie im Budget-Fortschritt, also
einschliesslich eines Monats-Werts, der die Vorlage uebersteuert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 14:05:28 +02:00
GuidoandClaude Opus 5 1509695760 fix: Ein Umsatz unter neuer Kennung kam ein zweites Mal herein
Der Bankabruf nahm die ERSTE Kennung, die ein Umsatz mitbringt – meist die
Referenz der Bank. Vergibt die Bank sie beim Buchen neu (aus vorgemerkt wird
gebucht), ist es fuer Certain ein anderer Umsatz, und dieselbe Zahlung steht
zweimal da. Genau so sind zwei Mietbuchungen ueber 288 Euro am selben Tag
entstanden.

Zwei Aenderungen:

- Geprueft wird gegen ALLE Kennungen des Umsatzes, nicht nur gegen eine. Damit
  treffen auch Eintraege, die frueher unter einer anderen abgelegt wurden.
- Gespeichert wird die bestaendigste: die eigene Kennung der Schnittstelle
  bleibt gleich, wenn die Bank ihre Referenz austauscht.

Das ist eine von vier Stellen, an denen Certain Dubletten erkennt – neben dem
Import-Schluessel, dem unscharfen Eingangs-Abgleich und dem
Ueberschneidungsschutz. Diese vier gehoeren zusammengefuehrt; das ist ein
eigener Umbau und nicht Teil dieser Korrektur.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 13:51:50 +02:00
GuidoandClaude Opus 5 67a32bdda9 feat: Aufschluesselung zeigt, was der Stichtag ausschliesst
Buchungen bis einschliesslich des Stichtags zaehlen nicht in den Kontostand –
sie stecken schon im Anfangsbestand. In der Liste stehen sie aber, und in den
Auswertungen zaehlen sie mit. Das ist richtig so, war in der Oberflaeche aber
nirgends zu sehen: Der Unterschied zwischen dem, was man sieht, und dem, was
gerechnet wird, liess sich nicht erklaeren.

Ein Konto, dessen Stichtag nach dem Beginn des eingelesenen Auszugs liegt,
zeigt deshalb einen Kontostand, der zu den sichtbaren Buchungen nicht passt –
und niemand kaeme darauf, warum.

Die Rechnung nennt jetzt Stichtag, Anzahl und Summe der ausgeschlossenen
Buchungen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 13:41:22 +02:00
GuidoandClaude Opus 5 7c0d13cc8a feat: Kontostand aufschluesseln – und der Angleich-Knopf bleibt
Zwei Sachen aus derselben Wurzel: Wenn ein Saldo nicht stimmt, sieht man nicht,
warum, und kann auch nichts dagegen tun.

Ein Klick auf den Kontostand zeigt jetzt die Rechnung: Anfangsbestand,
Einnahmen, Ausgaben, Uebertraege raus und rein – jeweils mit der Anzahl der
Buchungen – und was daraus wird. Darunter der Saldo der Bank und, einzeln
aufgefuehrt, alle Uebertraege des Kontos. Genau die sind die haeufigste
Ursache und in einer langen Buchungsliste am schwersten zu ueberblicken.

Rechnung und Kontenliste kommen aus EINER Quelle: ``account_balance_cents``
liest jetzt aus der Aufschluesselung. Sonst koennte die Anzeige etwas anderes
behaupten als der Saldo, und man suchte den Fehler im Falschen.

Ausserdem war der Knopf "Saldo der Bank uebernehmen" verschwunden, sobald die
Bank nur einen verfuegbaren Saldo meldet. Das war zu weit gedacht: Nicht
vergleichbar heisst nicht, dass man nicht angleichen duerfte. Der Knopf ist
zurueck, und die Nachfrage sagt in dem Fall, worauf man sich einlaesst – der
verfuegbare Saldo enthaelt Vorgemerktes, das spaeter noch als Buchung kommt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 13:33:27 +02:00
GuidoandClaude Opus 5 e0d8882851 fix: Automatischer Abruf lief gegen die Abfragegrenze der Banken
"Weniger als 15 Minuten lassen die Banken nicht zu" stand als Hinweis im
Formular. Das war erfunden. PSD2 verpflichtet die Banken zu VIER
unbeaufsichtigten Abfragen je Konto und Tag – haeufiger duerfen sie ablehnen,
und N26 tut es: "Too many requests", und der Abruf scheitert, bis das
Zeitfenster weiterrueckt.

Bei zehn angebundenen Konten und einem Takt von 15 Minuten waren es tausende
Anfragen am Tag. Der Takt betraegt jetzt mindestens sechs Stunden, also genau
die zugesicherten vier je Tag. Bestehende, zu knappe Einstellungen werden beim
Faelligkeitspruefen mitgebremst – sonst liefe eine gespeicherte 15 weiter
dagegen.

Von Hand abrufen bleibt unbegrenzt: Dabei sitzt der Nutzer davor, und fuer
diesen Fall gilt die Grenze nicht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 13:11:35 +02:00
GuidoandClaude Opus 5 6ed91ddd58 fix: Verknuepfte Buchungen brauchen keine Kategorie mehr
Eine verknuepfte Buchung gehoert zu einem Uebertrag und zaehlt in keiner
Auswertung. Trotzdem stand sie unter "Zu erledigen" und wurde in der
Buchungsliste nach einer Kategorie gefragt – Arbeit, die nichts bewirkt, und
ein falsches Signal: Sie sah aus, als fehle noch etwas.

Der Filter fuer offene Buchungen laesst verknuepfte jetzt aus, und in der
Buchungsliste steht bei ihnen ein Strich statt der Auswahl – so wie bei einem
echten Uebertrag.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 13:07:29 +02:00
GuidoandClaude Opus 5 bb748cc092 feat: Certain fragt in der Buchungsliste nach, ob es ein Uebertrag ist
Die Erkennung gab es laengst – aber nur auf der Seite "Zu erledigen", in einer
Karte, die man erst finden muss. Wer in der Buchungsliste steht und die zweite
Haelfte eines Uebertrags sieht, greift stattdessen zum ↔-Knopf und legt einen
zweiten Uebertrag an. Genau so ist heute eine Zahlung doppelt verschoben
worden.

Jetzt steht die Frage in der Zeile: "Uebertrag von/nach Revolut CHF?" mit
Verbinden und Ignorieren. Ignorieren wird gemerkt, sonst fragte Certain bei
jedem Laden erneut.

Dafuer gibt es die Suche jetzt auch als reines Nachschlagen: ``finde`` mit
``nur_vorschlaege`` verknuepft nichts, und dahinter liegt GET
/uebertraege/vorschlaege. Eine Ansicht, die bloss fragt, darf beim Hinsehen
nichts veraendern – sonst entschiede das Anschauen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 13:03:25 +02:00
GuidoandClaude Opus 5 7b3ed3e63c fix: Zweiter Uebertrag fuer dieselbe Bewegung wurde nicht erkannt
Die Sperre sah auf dem Zielkonto nur nach Ausgaben und Einnahmen. Steht dort
schon ein UEBERTRAG, der dasselbe Geld zwischen denselben beiden Konten
bewegt, fand sie nichts – und der zweite ging durch.

Genau das passiert im Alltag: Die eine Seite kommt von der Bank, die andere
aus der CSV-Datei, und beide sehen einzeln nach einem Uebertrag aus. Wer beide
umwidmet, hat das Quellkonto doppelt belastet und das Ziel doppelt
gutgeschrieben – bei 1'575 macht das 3'150 Unterschied auf zwei Konten.

Jetzt wird zuerst geprueft, ob zwischen denselben beiden Konten schon ein
Uebertrag ueber denselben Betrag in derselben Woche steht. Die Richtung ist
dabei egal, ein Uebertrag hat kein Vorzeichen. Dieser Fall laesst sich auch
nicht mit "trotzdem" uebergehen: Dasselbe Geld zweimal zu verschieben ist
keine Ansichtssache.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 12:58:37 +02:00
GuidoandClaude Opus 5 c1561acdce fix: Vier Ursachen, warum Saldo und Umsaetze auseinanderliefen
Die staendige Meldung "weicht ab" hatte mehrere Quellen, und eine davon war
ueberhaupt keine Abweichung.

1. Ein VERFUEGBARER Saldo enthaelt Vorgemerktes. Certain bucht Vorgemerktes
   bewusst nicht – es kaeme spaeter mit anderer Kennung ein zweites Mal. Beides
   zu vergleichen musste also dauerhaft danebengehen. Verglichen wird jetzt nur
   noch ein GEBUCHTER Saldo (CLBD, ITBD, PRCD); sonst steht dort "verfuegbarer
   Saldo, nicht vergleichbar" und keine Abweichung.

2. Die Saldi wurden VOR den Umsaetzen geholt und sofort geschrieben. Brach der
   Umsatz-Abruf danach ab, stand ein aktueller Saldo neben altem Bestand – und
   die Anzeige meldete eine Abweichung, die nur aus der Reihenfolge kam. Sie
   kommen jetzt zuletzt. Ohne Kontozuordnung weiterhin zuerst: Dort gibt es
   keine Umsaetze zu holen, und bei mehreren gleich aussehenden Pockets ist der
   Betrag das Einzige, woran man sie unterscheidet.

3. Jeder weitere Abruf griff nur drei Tage hinter den letzten zurueck. Banken
   buchen mitunter spaeter zurueck; was einmal ausserhalb lag, kam nie wieder.
   Jetzt sieben Tage – doppelt holen kostet nichts, die Kennung des Umsatzes
   faengt es exakt ab.

Damit ist die Anzeige nicht mehr nur ehrlicher, sondern zeigt auch wieder auf
etwas: Steht dort eine Abweichung, ist sie echt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 21:44:01 +02:00
GuidoandClaude Opus 5 4000082df4 fix: Dieselbe Zahlung ueber zwei Bankzugaenge kam doppelt herein
Wer dieselbe Bank zweimal verbindet, bekommt fuer dieselbe Zahlung zwei
verschiedene Kennungen – Enable Banking fuehrt eine Bank je Land getrennt.
Genau das passiert bei Revolut: Ueber den DE-Eintrag kommen drei Konten, ueber
den LT-Eintrag zusaetzlich die Pockets, also verbindet man beide. Zeigen dann
zwei Bankkonten auf dasselbe Konto in Certain, holt jeder Zugang dieselben
Umsaetze, und der Duplikatschutz kann sie nicht als dieselben erkennen.

Drei Aenderungen:

- Ein Konto in Certain wird nur noch von EINEM Bankkonto gefuellt. Ordnet man
  ein zweites zu, wird die alte Zuordnung geloest. Sie ist ohnehin nie richtig,
  und stillschweigend doppelt zu buchen ist schlimmer als eine geloeste
  Zuordnung.
- Die Ausnahme im Ueberschneidungsschutz gilt nur noch fuer DASSELBE Bankkonto.
  Dort entscheidet die Kennung der Bank, und die ist exakt – zwei Aufrundungen
  ueber 1.00 duerfen sich nicht verschlucken. Buchungen aus einem ANDEREN
  Zugang zaehlen jetzt mit.
- Das Aufraeumskript kennt den Fall: Findet es in einer Gruppe (Konto, Art,
  Tag, Betrag) Buchungen aus zwei Zugaengen, bleibt die Fassung EINES Zugangs
  stehen. Aufrundungen aus einem einzigen Zugang bleiben unangetastet, auch
  wenn sie gleich aussehen.

An nachgestellten Daten geprueft: Aus -579.50 wird -290.50; die drei gleichen
Aufrundungen aus einem Zugang bleiben alle stehen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 21:39:57 +02:00
GuidoandClaude Opus 5 a159546218 feat: Rueckkehr von der Bank sagt, was ankam und was liegen blieb
"3 Konten gefunden" beantwortet die entscheidende Frage nicht: Hat die Bank nur
drei geschickt, oder hat Certain die uebrigen verworfen? Der Server rechnet
beides laengst aus, die Seite zeigte es nur, wenn ueberhaupt kein Konto ankam.

Jetzt steht immer dabei, wie viele die Bank geschickt hat. Und Konten, die
Certain nicht uebernehmen konnte, werden nicht mehr bloss gezaehlt, sondern
mitsamt dem gezeigt, was von ihnen ankam – uebersprungen werden sie, weil die
Kennung fehlt, mit der sich Salden und Umsaetze holen lassen.

Anlass: Fuenf Revolut-Pockets sind im Control Panel freigeschaltet und wurden
bei der Autorisierung ausdruecklich mitgewaehlt, kommen in Certain aber nicht
an. Ohne diese Zahlen laesst sich nicht sagen, wo sie verloren gehen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 21:12:45 +02:00
GuidoandClaude Opus 5 385352974c fix: Abruf ueber schon eingelesene Monate buchte alles doppelt
"Aelteres nachholen" greift 90 Tage zurueck – mitten in Monate, die schon per
CSV eingelesen sind. Genau davor schuetzt sonst das Startdatum, und der Knopf
haengt es aus. Der Duplikatschutz faengt das nicht: Sein Schluessel enthaelt
den Empfaengertext, und der lautet bei der Bank anders als im Auszug. Ergebnis:
jede Zahlung des Zeitraums zweimal.

Das war mein Fehler – ich habe den Knopf gebaut UND empfohlen, ohne die
Sicherung zu ersetzen, die er aushebelt.

Der Abruf prueft jetzt selbst: Gibt es auf dem Konto schon eine Buchung
gleicher Richtung und gleichen Betrags im Umkreis von drei Tagen, die NICHT
von der Bank kam, ist der Umsatz dieselbe Bewegung und wird uebersprungen.
Jede vorhandene Buchung erklaert dabei hoechstens einen Umsatz – sonst
verschluckte eine Kaffeezahlung alle weiteren desselben Betrags. Die Zahl der
uebersprungenen steht in der Rueckmeldung.

Fuer den bereits angerichteten Schaden gibt es
scripts/raeume_doppelte_bankumsaetze.py: Es findet Bank-Umsaetze, die eine
vorhandene Buchung wiederholen, und entfernt IMMER die von der Bank – die
eigene traegt die Kategorie des Nutzers. Sie wird verworfen, nicht geloescht,
damit kein spaeterer Abruf sie wiederholt. Ohne --wirklich passiert nichts;
mit --wirklich wird zuerst eine Kopie der Datenbank angelegt.

An nachgestellten Daten geprueft: Aus -95.80 wird -48.40, die eigenen
Buchungen samt Kategorie bleiben, der echte neue Umsatz bleibt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 20:55:51 +02:00
GuidoandClaude Opus 5 12ea391e9f fix: Startdatum lag in der Zukunft – Saldi kamen, Umsaetze nicht
Beim ersten Abruf beginnt Certain am Tag NACH der neuesten vorhandenen Buchung
des Kontos, damit es nicht in schon eingelesene Monate zurueckgreift. Liegt
diese Buchung auf heute, ist der Tag danach morgen – und die Schnittstelle
lehnt das rundweg ab: "date_from can not be in the future".

Der Fehler faellt erst beim Umsatz-Abruf an. Die Saldi sind da schon gelesen
und geschrieben, der Abruf bricht danach ab. Von aussen sieht es genau so aus,
wie der Nutzer es beschrieben hat: Der Kontostand aktualisiert sich, die
Buchungen kommen nie – und die Abweichung bleibt bestehen, obwohl man den
Saldo gerade erst von der Bank uebernommen hat. Genau dieses Uebernehmen legt
naemlich keine Buchung an, aber es gibt fast immer eine von heute.

Das Startdatum wird jetzt auf heute begrenzt. Gegenprobe: Ohne die Begrenzung
verlangt der Abruf den 28.08. an einem 27.08.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 20:48:03 +02:00
GuidoandClaude Opus 5 b4c90f5221 fix: Bankabruf verschluckte Umsaetze mit wiederkehrendem Betrag
Der Eingangs-Abgleich vergleicht Betrag und Datum mit ein paar Tagen
Spielraum – bewusst unscharf, damit eine per Kurzbefehl erfasste Zahlung nicht
ein zweites Mal ankommt. Er merkt sich dabei, welchen Eintrag er schon
verbraucht hat.

Nur ruft der Bankabruf ihn JE ZEILE einzeln auf, und damit begann diese Menge
jedes Mal von vorn: Derselbe Eintrag liess sich beliebig oft verbrauchen. Bei
Revolut-Aufrundungen – dreimal 1.00 in drei Tagen – kam so nur die erste an,
und der Saldo wich ab, ohne dass irgendwo etwas stand.

Zwei Aenderungen:

- Der Aufrufer kann die Menge jetzt ueber mehrere Aufrufe mitfuehren; der
  Bankabruf haelt eine je Konto.
- Gegen andere BANK-Eintraege wird gar nicht mehr unscharf verglichen. Zwei
  Umsaetze derselben Quelle sind nie Dubletten voneinander – dort entscheidet
  die Kennung der Bank, und die ist exakt.

Dazu ein Weg zurueck: Ein verschluckter Umsatz hinterliess keinen Eintrag, der
naechste Abruf haette ihn also wieder geholt – nur liegt er dann vor dem
Fenster des letzten Abrufs. "Aelteres nachholen" gibt es jetzt auch je Konto,
wie beim Postfach.

Nachgestellt und als Test festgehalten: dreimal 1.00 in drei Tagen, alle drei
kommen an, Saldo -3.00.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 16:45:38 +02:00
GuidoandClaude Opus 5 f2c1ab7dec feat: Regeln nachtraeglich auf Buchungen ohne Kategorie anwenden
Regeln greifen beim Import. Alles, was vorher hereinkam – oder hereinkam, bevor
es die Regel gab –, bleibt liegen. Bei einer Bankanbindung passiert genau das
dauernd: Die Umsaetze kommen von selbst, die Regel entsteht spaeter. Die
Revolut-Aufrundungen aufs Sparen-Pocket sind der Fall, an dem es aufgefallen
ist.

Der Knopf steht bei der Transfer-Erkennung und zeigt erst, was passieren
wuerde. Uebertrags-Regeln laufen durch denselben Dienst wie jeder andere
Uebertrag – er lehnt ab, wo die Gegenseite schon gebucht ist, und solche
Buchungen bleiben unangetastet und werden mit Grund gemeldet.

Ohne festes Zielkonto wird es aus dem Buchungstext erraten, aber nur bei GENAU
einem Treffer und nur an Wortgrenzen: "Euro" darf nicht "PayPal Europe"
treffen. Zwei Moeglichkeiten heisst raten, und dann passiert nichts.

Angefasst werden nur Buchungen OHNE Kategorie – sonst ueberschriebe der Knopf
stillschweigend, was von Hand zugeordnet wurde. Ein Uebertrag ist kein Kandidat
mehr, ein zweiter Klick verschiebt das Geld also nicht erneut.

Zwei Dinge fielen beim Testen auf und sind mit behoben:

- Ein fehlgeschlagener Uebertrag verwarf per rollback() auch alles, was im
  selben Durchlauf schon gelungen war. Jetzt haelt ein Rettungspunkt je
  Uebertrag den Schaden bei dem einen.
- test_neutral_category nahm VORHANDENE Kategorien und stellte eine davon auf
  "nicht einrechnen". Benutzten andere Buchungen sie, fielen die mit heraus und
  die Rechnung ging um deren Summe daneben – ohne Bezug zum Gepruefften. Der
  Test legt sich seine Kategorien jetzt selbst an.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 16:02:04 +02:00
GuidoandClaude Opus 5 1b47e5abe1 fix: Ohne Anmeldung liessen sich beliebige Dateien vom Server lesen
Die Auslieferung des Frontends nahm den Pfad roh aus der Adresse: "Path /
'../../x'" verlaesst den Ordner klaglos, und die Route liegt VOR jeder
Anmeldepruefung. Gegen die eigene Instanz nachgestellt – roh und
prozentkodiert kam beides Mal die Datei heraus:

    GET /../../GEHEIM.txt            -> "geheim"
    GET /../../backend/app/config.py -> der Quelltext

Damit war alles lesbar, was der Dienst lesen darf: Quelltext, Konfiguration,
und mit der passenden Zahl von Ebenen die Datenbank samt verschluesseltem
Postfach-Passwort und Bank-Schluessel. Der Pfad wird jetzt aufgeloest und
muss im Auslieferungs-Ordner liegen.

Zweitens prueft der Postfach-Abruf jetzt das Zertifikat. Ohne eigenen
SSL-Kontext tut imaplib das NICHT – die Verschluesselung schuetzt dann vor
niemandem, der sich dazwischenhaengt, und das Postfach-Passwort geht mit.
Gilt fuer beide Wege, SSL und STARTTLS.

Drittens warnt der Start, wenn das Sitzungs-Cookie ohne "Secure" ausgeliefert
wird. Die Vorgabe bleibt bewusst aus: Sie umzustellen sperrt jeden aus, der
Certain im Heimnetz ueber HTTP aufruft – und ein Ausgesperrter saehe die
Ursache nirgends.

Die Befunde stammen aus dem /security-review dieser Sitzung und waren seither
offen. Sie wiegen schwerer, seit die Anwendung fuer die Bankanbindung unter
einer oeffentlichen HTTPS-Adresse erreichbar sein muss.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 15:07:42 +02:00
GuidoandClaude Opus 5 d88967d77d fix: Budget-Monat war bei Starttag 29 bis 31 nicht schluessig
Der Starttag wird auf den letzten Tag des Monats gekappt – einen 31. Februar
gibt es nicht. period_bounds tat das, period_of nicht: Es verglich stur den
Tag des Monats. Damit fiel der 28. Februar bei Starttag 31 in einen Monat, der
vom 31. Januar bis zum 27. Februar reicht – der Tag lag also in keiner
Auswertung.

Betroffen waren elf Tage in vier Jahren, alle am Ende kurzer Monate, und nur
bei Starttag 29, 30 und 31. Bei allen anderen stimmte es.

Zwei Tests halten es fest: Jeder Tag von 2024 bis 2027 muss bei JEDEM Starttag
in dem Monat liegen, den period_of ihm zuweist – und die Monate muessen
lueckenlos aneinanderstossen, keiner doppelt, keiner dazwischen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 14:37:32 +02:00
GuidoandClaude Opus 5 61dc6c7f0b feat: Mail-Abruf sagt, was mit den Treffern passiert ist – und jede Buchung,
woher sie kommt

Die Meldung nach einem Abruf zaehlte geprueft, neu und unklar – aber nicht
"schon bekannt". Wurden alle Treffer beim vorigen Abruf schon uebernommen,
stand da "0 neu", und es sah aus, als waere nichts passiert, obwohl die
Eintraege im Eingang liegen. Die Zahl steht jetzt dabei.

Und die uebergangenen Mails wurden aufgelistet, die unklaren nicht: nur eine
Zahl, ohne zu sagen, welche Mail gemeint ist oder was ihr fehlt. Jetzt stehen
sie mit Grund da – kein Konto zugeordnet, kein Betrag erkannt, Richtung unklar,
Zahlung noch nicht ausgefuehrt.

Ausserdem traegt jede Buchung jetzt ihre Herkunft: Bank, Mail, Kurzbefehl,
Datei-Import oder von Hand. In der Buchungsliste steht sie als kleines
Kennzeichen unter dem Text. Ermittelt wird sie mit einer Sammelabfrage, nicht
je Zeile.

Bei einem Uebertrag zeigen zwei Eingangs-Eintraege auf dieselbe Buchung; die
Gegenseite hat Certain selbst angelegt, gemeint ist die echte Quelle. Genau
dafuer gibt es einen Test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 13:11:18 +02:00
GuidoandClaude Opus 5 60b8178c57 fix: Mails vor der Einrichtung waren fuer immer ausserhalb des Suchfensters
Der Zeitstempel des letzten Abrufs wird auch dann gesetzt, wenn ein Abruf
nichts fand – und danach sucht Certain nur noch ab gestern. Wer das Postfach
einrichtet, nachdem die Mails schon da waren, findet sie nie: Der erste,
ergebnislose Abruf schiebt das Fenster an ihnen vorbei.

Jetzt gibt es "Aelteres nachholen": Es sucht die letzten 90 Tage und uebergeht
den Zeitstempel. Dass dabei nichts doppelt ankommt, sichert wie bisher die
Message-ID.

Ausserdem sagt die Meldung jetzt, AB WANN gesucht wurde. Bisher stand dort
"Stimmt der Ordner?" – die Frage war fast immer die falsche.

Und ein latenter Fehler, der im August nicht auffaellt: Das Suchdatum wurde mit
strftime("%b") gebaut, also mit dem Monatskuerzel in der Sprache des Servers.
IMAP verlangt die englischen; auf einem deutschen System haette die Suche im
Maerz, Mai, Oktober und Dezember nichts gefunden. Die Kuerzel stehen jetzt fest
im Code.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 12:59:08 +02:00
GuidoandClaude Opus 5 6cd1c100c0 fix: Uebertrag pruefen, ob die Gegenseite schon gebucht ist
Ein Franken-in-Euro-Tausch stand zweimal da: die CHF-Seite als Uebertrag nach
Revolut Euro, die EUR-Seite weiterhin als eigene Einnahme. Revolut Euro war
damit doppelt gutgeschrieben. Drei Fehler auf einmal.

Erstens prueft "zum Uebertrag machen" jetzt, ob die Buchung bereits mit ihrer
Gegenseite VERBUNDEN ist. Dann sind beide Seiten gebucht und zaehlen schon in
keiner Auswertung; ein Uebertrag bewegt das Geld auf dem Zielkonto ein zweites
Mal. Das laesst sich auch nicht mit "trotzdem" wegdruecken – es ist nicht
Ansichtssache.

Zweitens wird auf dem Zielkonto nach einer passenden gebuchten Gegenseite
gesehen, auch ohne Verknuepfung: gleiche Tage, passender Betrag, ueber
Waehrungen hinweg mit Spielraum. Findet sich eine, kommt die Warnung samt dem
richtigen Weg – die beiden verbinden statt einen Uebertrag anzulegen. Der
Treffer ist unscharf, deshalb hier mit "trotzdem" uebergehbar.

Drittens der beobachtete Punkt: Der nachtraegliche Weg reichte den
Eingangs-Eintrag nicht durch und rechnete deshalb IMMER mit dem EZB-Kurs, auch
wenn die Bank ihren eigenen genannt hatte. Jetzt wird er nachgeschlagen, und
der Kurs der Bank landet an der Buchung.

Und Loeschen raeumt die Eingangs-Eintraege mit. Der Fremdschluessel setzt sonst
nur ihre Verweisspalte auf NULL, und sie blieben als "gebucht" ohne Buchung
stehen – bei einem Uebertrag sind das zwei.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 11:22:13 +02:00
GuidoandClaude Opus 5 b303c87801 feat: Eine Arbeitsliste, und Kategorien direkt in der Buchungsliste
'Eingang' und 'Offene Buchungen' zeigten fast dasselbe. Seit angebundene Konten
selbst buchen, ist eine Bank-Buchung sofort gebucht und ohne Kategorie – sie
stand damit in BEIDEN Listen. Die Trennung stammte aus der Zeit, als der
Eingang nur Vorschlaege enthielt.

Jetzt eine Seite 'Zu erledigen' mit allem, was noch eine Hand braucht: offene
Vorschlaege zum Buchen oder Uebertragen und Buchungen ohne Kategorie, egal ob
von Bank, Mail, Kurzbefehl oder Datei. Aelteste zuerst, mit der Herkunft in der
Zeile. Erledigtes verschwindet – die Eingangs-Eintraege bleiben in der
Datenbank, weil der spaetere Import gegen sie abgleicht. /offen leitet um.

Das Haekchen 'Schlagwort merken' aus der alten Seite bleibt: Es ist der Grund,
warum der Stapel mit der Zeit kleiner wird, und der Eingang hatte es nie. Der
Uebertrags-Knopf gilt jetzt auch fuer schon gebuchte Buchungen – sonst haette
in einer gemeinsamen Liste die eine Haelfte der Zeilen ihn gehabt und die
andere nicht.

In der Buchungsliste steht die Kategorie jetzt als Auswahl in der Zeile, dort
wo bisher nur ihr Name stand. Vorher musste man jede Buchung einzeln zum
Bearbeiten oeffnen. Die Zeile aendert sich an Ort und Stelle, die
Bildlaufposition bleibt.

Ausserdem tragen API-Antworten jetzt 'Cache-Control: no-store'. Ohne das darf
ein Browser selbst entscheiden, und der Zurueck-Knopf zeigt Salden von vorhin –
bei Geld ist eine veraltete Anzeige schlimmer als eine langsame.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 10:25:20 +02:00
GuidoandClaude Opus 5 8309f58a67 feat: Kurs der Bank statt EZB-Naeherung, und Saldo uebernehmen
Bei einer Fremdwaehrungs-Zahlung nennt die Bank oft ihren echten Kurs und den
Betrag in der Ausgangswaehrung. Certain warf das weg und naeherte mit dem
EZB-Kurs. Das faellt genau dort auf, wo es teuer ist: Die spaeter gelieferte
Gegenseite eines Uebertrags laesst sich mit einem geschaetzten Betrag nicht als
dieselbe Bewegung wiedererkennen.

Der Uebertrag waehlt jetzt in drei Stufen: der von der Bank genannte
Gegenbetrag (exakt), sonst ihr Kurs, sonst die EZB. Nur die erste Stufe gilt
als bekannt – daran haengt, ob bei einem angebundenen Zielkonto nachgefragt
wird.

Der Parser klopft mehrere Formen ab, weil die Feldnamen je Anbindung
verschieden sind, und setzt still nichts, wenn keine passt. Keine dieser Formen
ist gegen echte Daten geprueft; ein falscher Kurs saehe aus wie ein richtiger,
deshalb wird lieber gar keiner gesetzt.

Ausserdem ein Knopf auf der Kontenseite: den Saldo der Bank als richtig
uebernehmen. Die Differenz wandert in den ANFANGSBESTAND – sie steht fuer
Bewegungen, die Certain nie gesehen hat, und genau dafuer ist er da. Eine
Korrekturbuchung stuende dagegen fuer immer in der Liste und liefe durch jede
Auswertung. Die Buchungen bleiben unangetastet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 10:18:33 +02:00
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
GuidoandClaude Opus 5 90bda6b161 fix: Ein Uebertrag im Eingang fragt nicht mehr nach der Kategorie
Die Zeile im Eingang zeigte die Kategorie-Auswahl bedingungslos – auch bei
einem Kontouebertrag, der gar keine bekommt. Die Oberflaeche konnte es auch
nicht wissen: InboxItemOut hatte kein Feld, an dem sich ein Uebertrag
erkennen laesst.

Jetzt liefert der Eintrag transfer_account_id mit – das jeweils ANDERE
Konto, aus seiner Sicht. Steht es, zeigt die Zeile '↔ Kontoname' statt der
Auswahl. Ermittelt wird es mit einer Sammelabfrage, nicht je Zeile: Die Liste
geht bis 200 Eintraege.

Dazu die Luecke dahinter: set_category schrieb die Kategorie auch auf die
Buchung und konnte sie so auf einem TxnType.transfer ablegen – genau das,
was das Buchungsformular beim Anlegen verhindert. Bei einem Uebertrag lehnt
der Endpunkt jetzt ab; bei allem anderen bleibt es, wie es war.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 10:08:09 +02:00
GuidoandClaude Opus 5 8084ba511a feat: Umsaetze je Konto holen, Takt fuer den automatischen Abruf
Drei Sachen an der Bankanbindung.

'Umsaetze holen' lief ueber alle Konten einer Verbindung. Seit angebundene
Konten selbst buchen, ist ein Klick damit folgenreich: Er bucht auf zwei
Konten. Der Knopf sitzt jetzt in der Kontozeile; an der Verbindung bleibt
'Alle Konten holen'.

Dabei musste der Zeitstempel mitwandern. last_sync_at hing an der
Verbindung – ein Einzelabruf haette damit das Startdatum der uebrigen Konten
mit vorgeschoben, und deren Umsaetze aus dem uebersprungenen Zeitraum waeren
nie angekommen. Der Stempel gehoert an das Konto, das abgerufen wurde.

Neu ist ein Takt je Verbindung, nach demselben Muster wie beim Postfach: ein
Hintergrund-Thread, der jede Minute nachsieht, ob etwas faellig ist. Bewusst
ein eigener Thread – ein haengender Bankzugang darf den Mail-Abruf nicht
mitreissen. Die Vorgabe ist 0, also aus: Anders als beim Mail-Abruf entstehen
hier Buchungen, das laeuft nicht ungefragt los. Schlaegt ein Abruf fehl, wird
der Stempel trotzdem gesetzt, sonst liefe die Verbindung jede Minute in
denselben Fehler.

Und die Abschnitte heissen jetzt 'Bankkonten Anbindung' und 'Mail Import'.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 10:04:29 +02:00
GuidoandClaude Opus 5 a471eba617 feat: Kontouebertraege lassen sich im Eingang buchen
Bisher blieb im Eingang nur, eine Umbuchung als Ausgabe oder Einnahme zu
kategorisieren. Sie zaehlte dann als Ausgabe, obwohl kein Geld weg ist – nur
verschoben.

Jetzt gibt es je Vorschlag den Weg 'Als Uebertrag buchen': Zielkonto waehlen,
fertig. Es entsteht EINE Buchung, die beide Salden bewegt und in keiner
Auswertung zaehlt. Die Richtung kommt aus dem Vorzeichen – ein Abgang geht von
hier weg, ein Zugang kommt vom Gegenkonto her; entsprechend fragt der Dialog
'wohin' oder 'woher'. Bei verschiedenen Waehrungen wird die Seite exakt
gesetzt, die wir wirklich kennen, und die andere umgerechnet.

Der teuerste Fehler an dieser Stelle waere ein Zielkonto, das selbst an einer
Bank haengt: Es meldet den Zugang von allein, eine Gegenbuchung hier haette das
Geld zweimal. Der Server lehnt das mit einer Begruendung ab; wer es besser
weiss, bestaetigt und kommt durch. Das Wissen bleibt an einer Stelle – die
Oberflaeche fragt nicht selbst nach, sie zeigt die Antwort des Servers.

Die Betragslogik ist dafuer aus dem Buchungs-Router in einen Dienst gewandert.
Zwei Kopien derselben Umrechnung waeren genau die Stelle, an der Salden
auseinanderlaufen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 06:31:49 +02:00
GuidoandClaude Opus 5 b9abb912e3 feat: Angebundene Konten buchen selbst – der Saldo kann nicht abweichen
Bisher legte der Bankabruf Vorschlaege in den Eingang, die man von Hand buchen
musste. Ein angebundenes Konto ist aber die Quelle der Wahrheit: Was die Bank
gebucht hat, IST gebucht. Jetzt wird es sofort gebucht; uebrig bleibt das
Zuordnen der Kategorie.

Drei Dinge mussten dafuer stimmen, sonst haette es Salden verfaelscht:

- Der erste Abruf greift nicht mehr hinter die neueste vorhandene Buchung des
  Kontos zurueck. Vorher holte er neunzig Tage – mitten in Monate, die schon
  per CSV eingelesen sind. Der Duplikatschutz haette die nicht gefunden: Sein
  Schluessel enthaelt den Empfaengertext, und der lautet bei der Bank anders
  als im Kontoauszug. Das Startdatum steht in der Rueckmeldung.
- Vorgemerkte Umsaetze werden nicht gebucht. Sie kommen spaeter noch einmal,
  dann mit anderer Kennung, weil die Bank beim Buchen eine neue vergibt.
  Beides zu nehmen hiesse doppelt buchen. Ihre Zahl wird gemeldet, nicht
  verschwiegen.
- Nach dem Buchen wird nach Uebertraegen gesucht. Ein Uebertrag zwischen zwei
  angebundenen Konten kommt in EINEM Abruf an – beide Seiten.

Nebenbei schliesst das eine bestehende Luecke: Der Eingangs-Abgleich beim
CSV-Import sieht nur gebuchte Eintraege. Solange Bank-Vorschlaege unbeachtet
liegen blieben, haette ein spaeterer Import derselben Wochen sie verdoppelt.

Das Buchen aus dem Eingang ist dafuer vom Router in einen Dienst gewandert;
zwei Kopien derselben Umrechnung waeren genau die Stelle, an der Salden
auseinanderlaufen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 06:21:10 +02:00
GuidoandClaude Opus 5 2379cf4973 feat: Uebertraege lassen sich endlich bedienen
Der Uebertrags-Dienst und seine fuenf Endpunkte gab es seit Wochen – ohne
einen einzigen Aufrufer in der Oberflaeche. Man konnte also nirgends sagen,
dass zwei Buchungen derselbe Uebertrag sind, und eine gefundene Verknuepfung
auch nicht wieder loesen.

Jetzt: eine Karte "Moegliche Uebertraege" im Eingang mit beiden Seiten
nebeneinander, Verbinden und Ignorieren; in der Buchungsliste eine Marke mit
dem Gegenkonto und ein Knopf zum Loesen. Das Gegenkonto kommt vom Server mit –
die andere Buchung steht oft gar nicht in der gefilterten Liste, und
"Uebertrag" ohne Angabe wohin sagt nichts.

Ausserdem wird nach dem Buchen aus dem Eingang nach Uebertraegen gesucht, so
wie bisher nur nach einem Import. Seit die Bankanbindung ihre Umsaetze in den
Eingang legt, entsteht die Gegenseite naemlich erst dort; ohne diesen Aufruf
wuerde sie nie gefunden. Ein Fehler dabei kippt das Buchen nicht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 23:13:40 +02:00
GuidoandClaude Opus 5 63de8368f0 feat: Kontostand von der Bank – die eigene Rechnung wird geprueft
Certain rechnet den Saldo bisher ausschliesslich selbst aus: Anfangsbestand
plus alle Buchungen. Stimmt eine Buchung nicht, faellt das erst auf, wenn man
von Hand mit dem Auszug vergleicht.

Der von der Bank gemeldete Saldo wird jetzt mitgefuehrt und danebengestellt.
Weicht er ab, fehlt oder doppelt eine Buchung – und man sieht es auf der
Kontenseite und in den Einstellungen sofort, statt es zu suchen.

Banken melden mehrere Saldi nebeneinander; ausgewaehlt wird der gebuchte, denn
nur der ist mit Certains Rechnung vergleichbar. Ein verfuegbarer Saldo enthaelt
Vorgemerktes oder einen Ueberziehungsrahmen.

Die Saldi kommen auch fuer noch nicht zugeordnete Konten: Bei mehreren
Revolut-Pockets ist der Betrag oft das Einzige, woran man sie unterscheidet.
Ein Fehler bei einem Konto beendet den Durchlauf nicht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 23:08:56 +02:00
GuidoandClaude Opus 5 f684c752d8 feat: Pockets sind erkennbar und zuordenbar
Ein Revolut-Pocket bringt weder eigene IBAN noch eigenen Namen mit. Certain
hielt bisher nur uid, IBAN, Name und Waehrung fest – mehrere Konten derselben
Bank sahen damit gleich aus, und in der Zeile stand die rohe Kennung.

Jetzt werden Produktbezeichnung und die Kennung fuer Konten ohne IBAN
mitgefuehrt, der angezeigte Name faellt der Reihe nach auf Name, Details,
Produkt, Kennung, IBAN zurueck statt auf die uid, und der uebermittelte
Datensatz laesst sich aufklappen – nachsehen statt raten, wenn zwei Konten
gleich aussehen. Beim Neuverbinden werden die Merkmale aufgefrischt, ohne die
Zuordnung anzutasten.

Fehlt ein Konto in der Waehrung des Bankkontos, steht das jetzt dabei; vorher
war die Auswahl einfach leer.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 23:02:25 +02:00
GuidoandClaude Opus 5 b4f76c03d2 feat: Erneut verbinden statt loeschen und neu anlegen
Um eine Verbindung aufzufrischen – etwa nachdem man im Control Panel weitere
Konten verknuepft hat – haette man sie bisher erst loeschen muessen. Dabei
gehen die Kontozuordnungen mit verloren, also genau das, was man behalten
will; ein zweiter Verbindungsversuch haette sonst einen doppelten Eintrag
erzeugt.

Jetzt frischt das Verbinden derselben Bank den bestehenden Eintrag auf: neue
Sitzung, neue Konten, bestehende Zuordnungen bleiben. Der Warntext beim
Trennen sagt ausserdem, dass Trennen dafuer gar nicht noetig ist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 22:35:52 +02:00
GuidoandClaude Opus 5 277fe8b0e2 fix: "Keine Konten" nennt jetzt die Ursache
Drei verschiedene Faelle sahen alle gleich aus: Die Bank schickte nichts, sie
schickte Eintraege ohne Kennung (die still verworfen wurden), oder alle Konten
waren schon bekannt – Letzteres meldete faelschlich "0 Konten", obwohl alles
in Ordnung war.

Die Antwort unterscheidet jetzt uebermittelt / neu / bekannt / ohne_kennung.
Die Rueckkehr-Seite zeigt bei null nutzbaren Konten den passenden Hinweis: Im
eingeschraenkten Betrieb gibt eine Bank nur heraus, was zuvor im Control Panel
unter "Activate by linking accounts" verknuepft wurde.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 22:32:23 +02:00
GuidoandClaude Opus 5 beb1bb3419 fix: Bank-Suche verlor die besten Treffer beim Kuerzen
Der Fehler, den der Nutzer gefunden hat: Die Suche nach "n" lieferte
"genau 200" Treffer und darunter nie N26. Ursache war die Reihenfolge –
alphabetisch sortiert und ERST DANN bei 200 gekuerzt. "N26" liegt hinter
"Aachener Bank", fiel also hinter zweihundert Banken heraus, die irgendwo
ein n im Namen tragen. Die Bank war die ganze Zeit da.

Jetzt wird zuerst bewertet (genauer Name > Namensanfang > Wortanfang >
Teiltreffer > nur BIC/Gruppe) und erst danach gekuerzt. Ausserdem wird die
ECHTE Trefferzahl gemeldet statt der gekuerzten – "genau 200" sah aus wie ein
Suchergebnis, war aber die Obergrenze.

Ein Regressionstest stellt den Fall nach: 300 Banken mit "n" im Namen,
alphabetisch vor N26. Ohne den Fix faellt er um.

Nebenbei geprueft und ausgeschlossen: /aspsps blaettert nicht, die Liste ist
also vollstaendig; Sandbox und alphabetische Kuerzung waren es auch nicht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 22:10:41 +02:00
GuidoandClaude Opus 5 f53efc4767 diag: Zeigen, was unter dem gesuchten Buchstaben steht
Die Liste ist nicht abgeschnitten – sie reicht von "Aachener Bank" bis
"Oelands Bank" und enthaelt N und R. Damit sind beide bisherigen Vermutungen
widerlegt (Sandbox, alphabetisch gekuerzt), und Raten ueber Namensvarianten
bringt nichts mehr.

Bleibt die Suche ohne Treffer, stehen jetzt alle Eintraege mit demselben
Anfangsbuchstaben da. Damit ist auf einen Blick zu sehen, ob die Bank unter
einem anderen Namen gefuehrt wird – oder ob sie in diesen 815 von ueber 2500
schlicht fehlt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 21:57:53 +02:00
GuidoandClaude Opus 5 74641aeeac diag: Alphabetischen Bereich der Bankliste zeigen
815 geladene Banken bei ueber 2500 verfuegbaren, und alle Beispiele beginnen
mit A oder B – das deutet auf eine abgeschnittene Liste, nicht auf einen
falschen Suchbegriff. Die Sandbox-Vermutung ist damit widerlegt: "Aachener
Bank" und "BBVA" sind echte Institute.

Die Antwort nennt jetzt den Bereich von/bis und alle vorhandenen
Anfangsbuchstaben. Fehlen N und R, ist die Sache entschieden und die Abfrage
braucht Blaettern – dann suche ich nicht laenger am falschen Ende.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 21:54:58 +02:00
GuidoandClaude Opus 5 d3e4b0e089 fix: Bei keinem Treffer zeigen, was ueberhaupt geladen wurde
N26 und Revolut sind bei Enable Banking abgedeckt – in 31 Laendern, unter
genau diesen Namen. Wer sie trotzdem nicht findet, bekommt die falsche Liste,
und der haeufigste Grund ist eine als Sandbox statt Production angelegte
Anwendung: Dann kommen Test-Institute, man sieht also Banken, nur nicht die
echten.

Bleibt die Suche ohne Treffer, stehen jetzt acht Beispiele aus der geladenen
Liste da. Sind das lauter Mock-Institute, ist die Ursache auf einen Blick zu
sehen statt nach Namensvarianten zu raten.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 21:52:04 +02:00
GuidoandClaude Opus 5 9a0c607e8c fix: "Keine Treffer" sagt jetzt, woran es liegt
Bei der Bank-Suche kam nur "Keine Treffer" – das hiess zweierlei: Die
Schnittstelle lieferte gar keine Liste, oder sie lieferte eine und der
Suchbegriff passte nicht. Beides sieht gleich aus, fuehrt aber an ganz
verschiedene Stellen. Genau diese Verwechslung hat heute schon zweimal Zeit
gekostet.

Die Antwort traegt jetzt die Gesamtzahl mit. Kam nichts, steht der
wahrscheinliche Grund dabei: Die Anwendung bei Enable Banking wird erst
aktiv, wenn man dort die eigenen Konten verknuepft hat.

Ausserdem wird breiter gesucht – auch in BIC und Gruppenname, weil Banken in
so einer Liste nicht immer so heissen wie im Alltag – und die Antwort wird
defensiv gelesen, falls die Liste ohne Schluessel kommt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 21:48:59 +02:00
GuidoandClaude Opus 5 71e8419634 feat: Bank ueber alle Laender suchen
Unter "Deutschland" liessen sich N26 und Revolut nicht finden – und bei
Revolut kann das gar nicht klappen: Die Bank vergibt deutsche IBANs, ist aber
die Revolut Bank UAB in Litauen. Das Sitzland einer Bank steht nicht in der
IBAN, also ist die Laenderauswahl der falsche Einstieg.

Jetzt ein Suchfeld, das ohne Land ueber alle sucht; das Land ist nur noch ein
optionaler Filter. Der Treffer zeigt sein Land mit an, und verbunden wird mit
dem Land der BANK statt dem des Filters – sonst schluege die Autorisierung
fehl, sobald ohne Land gesucht wurde.

Ohne Land UND ohne Begriff wird abgelehnt: Sonst kaemen alle Banken Europas
ins Formular.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 21:42:08 +02:00