# Änderungen ## Buchungsbericht: Spalte und Filter „abgeglichen“ (12.10.2026) - Anlass (#137): Der Buchungsbericht zeigte nicht, ob eine Buchung abgeglichen ist, und ließ sich nicht danach filtern. - Neue Spalte „✓“ (Tooltip „abgeglichen“) vor der Spalte „Bar“ des Bargeld-Tools – wie im Kontoblatt. Splitzeilen erben den Haken ihrer Buchung. - Neuer Filter „Abgeglichen“ (alle / abgeglichen / nicht abgeglichen), Filterfeld `abgeglichen` mit den Werten `ja`/`nein`; wie der Bargeld-Filter wirkt er nur im Buchungsbericht und wird mit gespeicherten Berichten gesichert. - Cockpit, *Offene Vorgänge*: „Buchungen nicht abgeglichen“ führt jetzt in den Buchungsbericht mit dem Filter „nicht abgeglichen“ statt in die Kontenübersicht (`Cockpit::nichtAbgeglichenBericht()`). Zeitraum von der ersten betroffenen Buchung bis heute, Umbuchungen eingeschlossen; liegen nicht abgeglichene Buchungen auf aufgelösten Konten, beschränkt sich der Bericht auf die aktiven Konten – so zeigt er genau die gezählten Buchungen. - Tests: `tests/14_AuswertungTest.php`, `tests/15_CockpitTest.php`, `tests/e2e/specs/auswertungen.spec.js`. ## Buchen ohne Bargeld-Abgleich (12.10.2026) - Anlass (#136): Sammelbuchungen und Differenzausgleiche tragen eine Kategorie, die gegen das Bargeld-Tool geprüft wird, stehen dort aber absichtlich nicht – und wurden deshalb immer wieder als offener Vorgang angemahnt. - Die Buchungsmaske hat den Schalter „Ohne Bargeld-Abgleich“ (`buchungen.ohne_bargeld_abgleich`, Migration `031_ohne_bargeld_abgleich.sql`). Er erscheint nur, wenn ein Bargeld-Tool eingerichtet ist; sonst trägt die Maske einen gesetzten Wert unsichtbar weiter. - `BargeldAbgleich::pruefe()` prüft solche Buchungen nicht und löscht einen früheren Status. Sie erscheinen damit weder unter „Bargeld-Tool-Prüfung fehlgeschlagen“ noch unter „im Bargeld-Tool nicht gefunden“. Die Schnellzuordnung im Kontoblatt und die Regelanwendung lassen den Schalter stehen. - Kontoblatt und Buchungsbericht zeigen in der Spalte „Bar“ einen leeren grauen Kreis mit dem Tooltip „Bewusst ohne Abgleich mit dem Bargeld-Tool“. - Tests: `tests/65_OhneBargeldAbgleichTest.php`, `tests/e2e/specs/bargeld.spec.js`. ## Offene Vorgänge des Bargeld-Tools im Buchungsbericht (12.10.2026) - Anlass (#131): Der Liste „Im Bargeld-Tool nicht gefunden“, aufgerufen aus *Offene Vorgänge* im Cockpit, fehlte die Spalte Kategorie/Gegenkonto. Gewünscht war statt einer eigenen Liste ein Filter im Buchungsbericht. - Den Filter „Bargeld-Tool“ hat der Buchungsbericht schon; die beiden offenen Vorgänge „Bargeld-Tool-Prüfung fehlgeschlagen“ und „im Bargeld-Tool nicht gefunden“ führen jetzt dorthin (`Cockpit::bargeldBericht()`): gesamter Zeitraum, Umbuchungen eingeschlossen, Filter „Abruf gescheitert“ bzw. „nicht gefunden“. Der Bericht zeigt Konto, Kategorie bzw. Gegenkonto in eckigen Klammern und Klasse; die Meldung der Gegenstelle steht im Tooltip der Spalte „Bar“. - Ist einer dieser beiden Filter gesetzt, erklärt der Hinweis unter dem Bericht den Status und dass eine erneute Zuordnung der Kategorie die Prüfung erneut anstößt – der Text der bisherigen Liste. - Entfernt: die Seite `/verwaltung/bargeld/fehler` (`VerwaltungController::bargeldFehler()`, `Views/verwaltung/bargeld_fehler.php`) und `Buchung::mitBargeldFehler()`. - Tests: `tests/34_BargeldAbgleichTest.php`, `tests/15_CockpitTest.php`, `tests/e2e/specs/bargeld.spec.js`. ## Anmeldeseite: Marke wie in der Seitenleiste (12.10.2026) - Anlass (#130): Icon und Schrift des Logos auf der Anmeldeseite wichen von der Marke im angemeldeten Zustand ab. - Der schlichte Rahmen (`src/Views/layout/schlicht.php` – Anmeldung, Ersteinrichtung, Fehlerseite) zeigt jetzt das Coinstack-Symbol und den Schriftzug „Finanz**manager**“ im Schriftschnitt der Seitenleiste. Bisher erbte der Schriftzug die Regeln der kleinen Statusmarke (`.marke`) und stand grau mit Rahmen da. - Weil die Karte hell ist, trägt die erste Worthälfte die Textfarbe und die zweite die lesbare Akzentfarbe (`--akzent-schrift`); im dunklen Thema entspricht das dem Blau der Seitenleiste. - Tests: `tests/64_AnmeldeMarkeTest.php`, `tests/e2e/specs/smoke.spec.js`. ## Depotbuchung erfassen: Stück, Kurs und Betrag rechnen sich (12.10.2026) - Anlass (#129): Bei Kauf und Verkauf sollten sich Betrag, Stück und Kurs gegenseitig ergeben – Betrag = Stück × Kurs. - Die Maske *Depotbuchung erfassen* rechnet bei Kauf und Verkauf das dritte Feld aus, sobald zwei eingetragen sind (`public/static/depotbuchung.js`): den Betrag auf zwei, Kurs und Stück auf sechs Nachkommastellen. Der ausgerechnete Wert ist farblich hinterlegt und zieht nach, wenn sich eines der anderen Felder ändert; selbst umgetippt gilt er als eingetragen, beim Leeren eines der anderen Felder verschwindet er. Bei Dividende, Ein- und Auslieferung wird nicht gerechnet; wechselt der Vorgang auf Kauf oder Verkauf, rechnet die Maske nach. - Serverseitig dieselbe Regel für den Weg ohne JavaScript (`Depotbuchung::dritterWert()`): Neben dem Betrag ergeben sich jetzt auch Kurs bzw. Stück bei Kauf und Verkauf. - Der Dialog des Wertpapiergeschäfts im Kontoblatt bleibt unverändert: Dort ist der Buchungsbetrag die feste Größe. - Tests: `tests/63_DepotbuchungDritterWertTest.php`, `tests/e2e/specs/depotbuchung.spec.js`. ## Wertpapiere: Klasse beim Buchen wählen (12.10.2026) - Anlass (#125): Beim Buchen von Wertpapieren fehlte die Auswahl einer Klasse. - Die Wertpapiermaske (Dialog im Kontoblatt und Seite `/buchungen/{id}/wertpapier`) hat ein Feld „Klasse“, vorbelegt mit der bisherigen Klasse der Buchung. Die Klasse steht danach an der Buchung und an jeder Splitzeile der Nebenkosten – das Kontoblatt zeigt so die eine Klasse statt „Splitbuchung“. Eine leere Auswahl entfernt die Klasse. - Auch „Depotbuchung erfassen“ unter *Wertpapiere* bietet die Klasse an; sie gilt der dort erzeugten Geldbuchung auf dem Verrechnungskonto. - Eine unbekannte Klasse wird abgewiesen, ohne dass ein Geschäft entsteht. - Tests: `tests/62_WertpapierKlasseTest.php`, `tests/e2e/specs/wertpapiergeschaeft.spec.js`. ## Umbuchungskonten in jeder Kategorieauswahl (12.10.2026) - Anlass (#124): In den Splitzeilen der Regeln, beim Anlegen einer Regel, im Filter des Buchungsberichts und weiteren Listen fehlten die Umbuchungskonten unter den Kategorien. - Die gemeinsame Liste *Kategorie / Gegenkonto* der Buchungsmaske (`Views/buchungen/zuordnungsliste.php`) steht jetzt überall, wo eine Kategorie gewählt wird: Regeln (Neue Regel, Regeltabelle, Regeldialog im Kontoblatt) samt Splitzeilen, Umsatzabgleich, Buchungsvorlagen, Regelmäßige Buchungen, Zahlungsverkehr und Verträge. Das getrennte Feld „Gegenkonto“ der Regel entfällt; die Regeltabelle verlor bisher beim Speichern ein Gegenkonto, weil sie es gar nicht mitschickte. - Angeboten werden nur aktive Umbuchungskonten, in eigenen Gruppen je Kontengruppe und in deren Reihenfolge (`Konto::umbuchungsgruppen()`). Ein schon gewähltes inaktives Konto bleibt sichtbar; die übrigen inaktiven stehen verborgen in der Liste, damit bestehende Splitzeilen beim Bearbeiten nicht verloren gehen (`kombobox.js` blendet sie aus). - Regel-Splitzeilen können auf ein Umbuchungskonto zeigen; daraus wird eine Splitzeile mit Gegenkonto. Auch „Regel anlegen“ aus einer Buchung übernimmt solche Zeilen. - Buchungsbericht: Umbuchungskonten stehen unter den Kategorien im Filter und bringen ihre Umbuchungen auch ohne „Umbuchungen mitzählen“ mit. Export: Umbuchungskonten unter den Kategorien (`gegenkonten[]`). - Zahlungsaufträge und Verträge bekommen ein Gegenkonto (Migration `030_gegenkonto_auftrag_vertrag.sql`); eine Überweisung aufs eigene Tagesgeld wird beim Senden als Umbuchung gebucht. - Nicht betroffen: Auswahllisten, die keine Buchung zuordnen (Wertpapierkosten in den Einstellungen, Bargeld-Tool, Ober-/Zielkategorie in der Kategorieverwaltung, Budgetplaner). - Tests: `tests/61_UmbuchungskontenAuswahlTest.php`, `tests/e2e/specs/regelausbuchung.spec.js`. ## Regelmäßige Buchungen: automatisch abgleichen (12.10.2026) - Anlass (#123): Buchungen aus regelmäßigen Buchungen mussten nach dem Buchen einzeln abgeglichen werden. - Neuer Schalter „automatisch abgleichen“ unter „automatisch buchen“ im Dialog „Neue regelmäßige Buchung“, in der Vorgabe eingeschaltet. Gesetzt markiert er die entstandene Buchung als abgeglichen – beim Fälligkeitslauf ebenso wie beim Buchen von Hand. - Die Übersicht der regelmäßigen Buchungen hat eine neue Spalte „Abgleichen“ zwischen „Auto“ und „Aktiv“, per Klick umschaltbar. - Migration `029_regelmaessig_abgleichen.sql`; bestehende Reihen übernehmen die Vorgabe (eingeschaltet). - Tests: `tests/60_RegelmaessigAbgleichenTest.php`, `tests/e2e/specs/module.spec.js`. ## Buchungen: bewusst ohne Kategorie (12.10.2026) - Anlass (#134): Abschreibungen oder rein rechnerische Solarerträge sollen ohne Kategorie gebucht werden können, ohne immer wieder als offen angemahnt zu werden. Mit Kategorie belastete eine Abschreibung die Auswertung zusätzlich zum gesunkenen Kontowert. - Neuer Schalter „Bewusst ohne Kategorie“ in der Buchungsmaske (neben „Abgeglichen“). Gesetzt sperrt er Kategorie / Gegenkonto und die Splitzeilen; mit Zuordnung lässt er sich nicht setzen. - Solche Buchungen erscheinen nicht unter den offenen Vorgängen im Cockpit, nicht im Prüflauf des Monatsabschlusses, setzen das Konto in der Kontenübersicht nicht fett, werden von „Regeln auf Buchungen ohne Kategorie anwenden“ ausgelassen und nicht automatisch zu Umbuchungen zusammengeführt. Das Kontoblatt zeigt „bewusst ohne Kategorie“. - Bekommt die Buchung später doch eine Kategorie, ein Gegenkonto oder Splitzeilen (auch über die Schnellzuordnung), entfällt die Markierung. - Migration `028_bewusst_ohne_kategorie.sql`. - Tests: `tests/59_BewusstOhneKategorieTest.php`, `tests/e2e/specs/buchungen.spec.js`. ## Kontoumsätze: Empfänger bei Kartenverfügungen (06.10.2026) - Anlass (#119): Bei Zahlungen mit der comdirect Visa-Debitkarte (Kartenverfügung, GVC 700) blieb der Empfänger leer – die Bank liefert dafür kein Namensfeld (?32/?33), der Händler steht nur im Verwendungszweck zwischen „KARTENVERFÜGUNG“ und „KARTE NR.“. - Fehlt der Name, liest der FinTS-Abruf ihn dort heraus (`Services/UmsatzEmpfaenger`, neu). Der Fingerabdruck des Umsatzes bleibt unverändert, bereits abgerufene Umsätze kommen nicht doppelt herein. - Ein erneuter Abruf trägt den Empfänger bei bekannten Umsätzen und ihren Buchungen nach, wenn er dort leer ist (`Bankumsatz::ergaenzen()`). - Migration `027_empfaenger_kartenverfuegung.sql` zieht vorhandene Kartenverfügungen und ihre Buchungen nach. - Test: `tests/58_EmpfaengerKartenverfuegungTest.php`. ## Echtzeitüberweisung: Status bei der Bank nachfragen (06.10.2026) - Anlass (#113): Bei offenem Status (Rückmeldung 3045) blieb nur der Blick in den Kontoumsatz. - php-fints-Fork v4.1.7: `SendSEPARealtimeTransfer` liest Auftragsidentifikation und Status aus HIIPZ und wirft bei 3045 nicht mehr; neue Action `GetSEPARealtimeTransferStatus` (HKIPS/HIIPS/HIIPSS) samt Mindestwartezeit. - Nach 3045 startet ein Hintergrundprozess (`scripts/echtzeit-status.php`), der nach der Mindestwartezeit der Bank (comdirect 99 s, DKB 5 s) nachfragt, höchstens fünfmal. Der Browser wartet nicht; die Liste zeigt „Ausgang offen“, bis das Ergebnis am Auftrag steht. Fällige Abfragen stößt die Zahlungsverkehrsliste nach einem Container-Neustart erneut an. - Ausgeführt (Status 4/7) wird am Auftrag vermerkt; abgelehnt (2/6/8/9) entfernt die Buchung, der Auftrag steht auf „fehlgeschlagen“ und lässt sich erneut senden. Ein beim Abruf verbundener Kontoumsatz klärt den offenen Status ebenfalls. Verlangt die Bank für die Abfrage eine TAN, wird sie eingestellt. - Im Echtbetrieb bestätigt (comdirect, 06.10.2026): HKIPS ohne TAN, Antwort HIIPS mit Status 7. - `Services/FinTsEchtzeitUeberweisung` entfällt, Migration `026_echtzeit_status.sql`. - Tests: `tests/54_EchtzeitStatusOffenTest.php` (erweitert), `tests/e2e/specs/echtzeitstatus.spec.js`; E2E-Grundbestand enthält eine Echtzeitüberweisung mit offenem Status. ## Zahlungsverkehr: nicht freigegebene Überweisungen nachvollziehbar (06.10.2026) - Anlass (#117): Die comdirect begründete zwei nicht ausgeführte Überweisungen damit, dass eine TAN angefordert, aber nicht verwendet wurde – im Finanzmanager war das nicht nachprüfbar. - Verlangt die Bank eine Freigabe, steht der Auftrag auf „wartet auf Freigabe“ statt auf „Entwurf“; die Liste nennt, ob die TAN-Eingabe noch offen oder nicht abgeschlossen ist. - Abbruch der Freigabe – auch durch einen neuen Sendeversuch – erzeugt einen Eintrag „Freigabe abgebrochen“ im Übermittlungsprotokoll und vermerkt den Auftrag als fehlgeschlagen. - Aufträge mit Übermittlungsprotokoll lassen sich nicht mehr löschen, nur stornieren (Knopf im Formular). - Migration `025_freigabe_nachvollziehen.sql`; E2E-Grundbestand enthält eine wartende Überweisung, der Aufräumer räumt `bank_protokolle` des Testnutzers mit ab. - Tests: `tests/57_FreigabeNachvollziehenTest.php`, `tests/e2e/specs/zahlungsfreigabe.spec.js`. ## TAN-Anfrage: Startcode hervorheben (04.10.2026) - Nennt die Bank bei der TAN-Abfrage einen Startcode für den TAN-Generator, geht er im Fließtext leicht unter. Erkennt der Finanzmanager einen hinterlegten Beispielsatz (jede Ziffernfolge darin gilt als Platzhalter für den Startcode), zeigt er den gefundenen Code fett, zentriert und in eigener Zeile. - Der Beispielsatz steht pro Bankverbindung im Formular unter „Startcode-Satz“; bleibt er leer, gilt „Überprüfe den Startcode 80045248 und bestätige mit der Taste OK.“ als Vorgabe. - `Services/StartcodeErkennung` (neu), `Services/BankFreitext` (neu, aus `FinTsUeberweisung::vopHinweis()` ausgelagert und jetzt von beiden genutzt), Migration `024_startcode_muster.sql`. - Test: `tests/56_StartcodeErkennungTest.php`. ## Verwaltung: Backup und Restore (01.10.2026) - Neue Kachel „Backup“: „Backup“ lädt den gesamten Datenbestand als `finanzmanager-sicherung-….json.gz` herunter, „Restore“ ersetzt den Bestand durch den Inhalt einer solchen Datei (mit Rückfrage). - `Services/Datenbanksicherung`: alle Tabellen mit Spalten und Zeilen; Restore in einer Transaktion (DELETE/INSERT), bei Fehler bleibt der alte Bestand. Abgelehnt werden fremde Dateien und Sicherungen, deren Spalten nicht zum Schema passen. - Test: `tests/55_DatenbanksicherungTest.php`. ## Echtzeitüberweisung: offener Status ist kein Fehler (01.10.2026) - Quittiert die Bank die TAN mit 3045 („noch keine Rückmeldung zum Status“), meldete php-fints „Bank did not confirm SEPATransfer execution“, obwohl der Auftrag bei der Bank liegt. Jetzt gilt der Auftrag als gesendet (gebucht), die Meldung weist darauf hin, den Kontoumsatz zu prüfen und nicht erneut zu senden. - `Services/FinTsEchtzeitUeberweisung` erweitert `SendSEPARealtimeTransfer` um dieses Merkmal. - Eine Statusabfrage bei der Bank (Nachfragen) ist noch offen: php-fints kennt dafür weder `HKIPS` noch `HKTAN` S für Nicht-Decoupled-Verfahren. - Test: `tests/54_EchtzeitStatusOffenTest.php` (Antwort aus einem echten Lauf). ## Überweisung erfassen: QR-Code einlesen (01.10.2026) - Neben „Empfänger“ steht ein Bereich, auf den sich ein Bild (z. B. Rechnungs-Screenshot) ziehen lässt. Ein Klick öffnet einen Dialog zum Einfügen aus der Zwischenablage (Strg+V) oder zur Dateiauswahl. - Ein enthaltener QR-Code im Format EPC-QR (GiroCode) oder BezahlCode (`singlepaymentsepa`) füllt Name, IBAN, BIC, Betrag, Verwendungszweck und ggf. Ausführungstermin. Das Bild wird nur im Browser gelesen. - Decoder: jsQR 1.4.0 (Apache-2.0) als `public/static/jsQR.js`; Fork: codeberg.org/fds2610-bot/jsQR. - Test: `tests/e2e/specs/qrimport.spec.js` (Beispielbilder in `tests/e2e/fixtures/`). ## Position der „+ Neu“-Knöpfe und Erklärtexte als Tooltip (01.10.2026) - Buchungsvorlagen, Erinnerungen, Sparziele, Verträge und Regeln: Die Erklärzeile entfällt, der Text steht als Tooltip am aktiven Reiter. Kredite erhalten einen Tooltip am Reiter „Kredite“. - Adressen: Das Suchfeld steht rechts neben „+ Neu“. - Regelmäßige Buchungen: „Fälligkeitslauf starten“ steht rechts neben „+ Neu“. - Budgets: Reihenfolge Zurück zur Planung · Budgetplaner öffnen · + Neu. - Berichtsgruppen: „Zur Übersicht“ und „+ Neu“ getauscht. ## Buchungsbericht: Gruppen- und Gesamtzeile (01.10.2026) - Die Formatierung von Kategoriezeile und Gesamtzeile ist getauscht. Die Gesamtzeile zeigt nur noch „Gesamt“; die Anzahl der Buchungen steht im Tooltip („Anzahl n“). ## Buchungsbericht: Bargeld-Tool-Abgleich (01.10.2026) - Ist ein Bargeld-Tool eingerichtet, zeigt der Buchungsbericht die Spalte „Bar“ (dasselbe Symbol wie im Kontoblatt) und bietet den Filter „Bargeld-Tool“: alle · gefunden · nicht gefunden · Abruf gescheitert · nicht abgeglichen. - Der Filter wird mit dem Bericht gespeichert (`Auswertung::BARGELD_FILTER`) und wirkt nur im Buchungsbericht. - Test: `14_AuswertungTest.php`. ## Berichte: Filterbereich (01.10.2026) - Der Filterbereich erhält den hellblauen Bereichsrand samt Schatten. - „Zeilen-Summe“ und „Spalten-Aufteilung“ stehen in der ersten Zeile hinter „Bericht anzeigen als“; das Suchfeld ist dafür breiter. ## Cockpit: Tooltip der Kachel „Offene Vorgänge“ (01.10.2026) - Beim Überfahren der Überschrift nennt der Tooltip die Prüfungen, die gerade nichts melden und deshalb nicht in der Liste stehen (`Cockpit::VORGANGSPRUEFUNGEN`). - Test: `15_CockpitTest.php`. ## Cockpit: Offene Vorgänge für nicht gefundene Bargeld-Buchungen (01.10.2026) - Neuer offener Vorgang „im Bargeld-Tool nicht gefunden“ (Status `fehlt`) neben der fehlgeschlagenen Prüfung; die Liste unter `/verwaltung/bargeld/fehler?status=fehlt`. - Test: `15_CockpitTest.php`. ## Rahmen, Schatten und Tabs im Design (01.10.2026) - Tabellen (`table.liste`), Kacheln und breite Formulare (`.formular.breit`, u. a. Einstellungen) erhalten in beiden Themen einen 1px breiten hellblauen Rand (`--bereichsrand`) und einen leichten Schatten (`--bereichsschatten`) für mehr Kontrast zwischen den Bereichen. - Titelleiste: Linie im Stil des Bereichsrands, dazu ein schmaler Schatten nach unten. Tab-Leiste: ebenso, die Linie ist im dunklen Thema dezenter (`--tablinie`). - Aktiver Tab und rechtsbündiger Tab („Kacheln wählen“, „Regeln“) haben im dunklen Thema einen abgesetzten blauen Rand (`--tabrand`). ## Automatische Buchungsnummer (01.10.2026) - Neue Buchungen ohne Nummer erhalten beim Anlegen die nächste laufende Nummer ihres Kontos (höchste rein numerische Nummer + 1, `Buchung::naechsteNummer()`). Vorgegebene Nummern (QIF, CSV, Formular) bleiben, bestehende Buchungen werden nicht verändert; die interne ID bleibt verborgen. - Test: `53_BuchungsnummerTest.php`. ## Regelmäßige Buchungen: Buchen zum gewählten Datum (01.10.2026) - „Buchen“ in „Jetzt fällig“ schlug mit einer Fehlermeldung fehl, weil das Formular ein leeres Datum schickte. Jetzt ist „Fällig am“ per Klick editierbar; „Buchen“ bucht zu diesem Datum. Die Änderung gilt nur für diese Buchung und verändert die Reihe nicht. Ein leeres Datum fällt auf den Termin zurück, ein ungültiges wird abgewiesen. ## „+ Neu“ öffnet das Formular als Dialog (01.10.2026) - Das Formular zur Neuanlage stand in elf Ansichten unter der Liste. Jetzt öffnet der Knopf „+ Neu“ es als modalen Dialog (`app.js`, `.neudialog`); nach dem Speichern erscheint die Liste wieder, mit dem neuen Eintrag. Betroffen: Klassen, Buchungsvorlagen, Regelmäßige Buchungen, Erinnerungen, Verträge, Adressen, Sparziele, Kredite, Abgleichregeln, Budgets, Berichtsgruppen. - E2E: `neudialog.spec.js`; bestehende Specs öffnen den Dialog zuerst. ## Regelmäßige Buchungen: Klick zum Bearbeiten (01.10.2026) - In „Alle Reihen“ erscheinen alle Felder zunächst als Text und werden erst beim Anklicken zum Eingabefeld (`reihenliste.js`). Ja/Nein-Felder schalten per Klick um, „Speichern“ erscheint erst nach einer Änderung. Konto und Klasse stehen untereinander, die Spalte Name/Buchungstext nimmt den freien Platz. ## Klasse und nächster Termin in „Alle Reihen“ (01.10.2026) - Unter der Kontoauswahl gibt es eine Klassenauswahl, der „Nächste Termin“ ist ein Datumsfeld und lässt sich von Hand verschieben (`RegelmaessigeBuchung::speichern()`, ungültige Angaben werden ignoriert). ## Buchungstext bei regelmäßigen Buchungen (01.10.2026) - Das Feld „Buchungstext“ fehlte im Formular für neue regelmäßige Buchungen und war in der Liste nur ein verstecktes Feld. Jetzt beim Anlegen vorhanden und in der Liste unter dem Namen bearbeitbar (`termine/index.php`). ## Fälligkeit folgt der Buchung (01.10.2026) - Eine per Fälligkeitslauf oder „Buchen“ erzeugte Buchung merkt sich jetzt ihre regelmäßige Buchung und den Soll-Termin (`buchungen.regelmaessige_id`, `faelligkeit`, Migration 023). Wird sie gelöscht, rückt die Fälligkeit auf diesen Termin zurück, eine ausgelaufene Reihe wird wieder aktiv, `zuletzt_am` folgt der jüngsten verbleibenden Buchung (`RegelmaessigeBuchung::terminWiederOeffnen()`). Bereits vorhandene Buchungen sind nicht verknüpft; bei ihnen bleibt es beim bisherigen Verhalten. ## Darkmode-Farben nach Mockup (01.10.2026) - Dunkle Palette bläulicher (Navy) statt grau-blau, Seitenleiste, Flächen, Ränder und Akzent angepasst. Der aktive Menüeintrag ist wie im hellen Modus blau hinterlegt (`--navi-aktiv`), der Balken links bleibt weiß (neue Variable `--navi-balken`). Nur Farben, nur im Darkmode (`app.css`). - Blaue Schrift (Links, Überschriften, Marken) besser lesbar: im Darkmode heller, im Hellmodus dunkler. Eigene Variable `--akzent-schrift`, Knöpfe und Rahmen bleiben unverändert. ## Favicon in hellem und dunklem Modus (01.10.2026) - Das Favicon war ein schwarzes „€“ ohne Hintergrund und im Darkmode kaum zu erkennen. Jetzt weißes „€“ auf blauer Kachel – in beiden Modi gut sichtbar (`kopf.php`, `schlicht.php`). ## Offener Vorgang für fehlgeschlagene Bargeld-Tool-Prüfungen (30.09.2026) - Die Kachel „Offene Vorgänge“ im Cockpit zählt jetzt auch Buchungen, deren letzter Abgleich mit dem Bargeld-Tool an einem Abrufproblem gescheitert ist (`bargeld_status = 'fehler'`) – nicht zu verwechseln mit „im Bargeld-Tool nicht gefunden“. Ein Klick führt auf die neue Liste unter Verwaltung → Bargeld-Tool → fehlgeschlagene Prüfungen (`/verwaltung/bargeld/fehler`), die diese Buchungen kontoübergreifend mit Konto, Betrag und Fehlermeldung auflistet (`Buchung::mitBargeldFehler()`). Fix #102. ## phpFinTS auf v4.1.6 (30.09.2026) - Fork neu auf Upstream vom 22.09.2026 aufgebaut (psr/log und Depotaufstellung v6, #598, bleiben als eigene Commits). Der VOP-Patch entfällt, #584 ist upstream gemergt. Neu von Upstream u. a.: gespeicherte BPD werden beim Laden neu geparst (#595), MT940-Schlusssalden (#593). - Abrufe (Umsätze, Depot) und eine Echtzeitüberweisung bei der DKB laufen unverändert durch. ## Stichtag beim Einbuchen des Depotbestands (30.09.2026) - „Bestand einbuchen“ (Wertpapiere → Bestand laut Bank) fragt in einem modalen Dialog nach dem Stichtag. Er ist das Datum aller Ein- und Auslieferungen des Laufs; vorbelegt ist der Stand des Bankabrufs. Die Notiz nennt weiterhin den Bankstand. ## Zuordnungsliste: Depots nur noch als Wertpapiergeschäft (30.09.2026) - Wo die Gruppe „Wertpapiergeschäft im Depot“ steht (Kontoblatt, Buchungsmaske), fehlen die Depots in der Gruppe „Umbuchung auf ein Konto“. Die fast gleich benannten Einträge führten dazu, dass ein Kauf als schlichte Umbuchung ohne Stückzahl, Kurs und Nebenkosten gespeichert wurde. In den Splitzeilen bleibt die Umbuchung ins Depot erhalten. ## Depotabruf per FinTS und Nachweis zur Überweisung (30.09.2026) - Das Depot (Kontoart 30, ohne IBAN) fehlte in der Kontenabfrage, weil `HKSPA` nur Konten mit IBAN liefert. Es steht in den Kontostammdaten der Bank (`HIUPD`) mit erlaubtem `HKWPD`. - Neuer Modus `depot` in `FinTsAbruf`: Anmeldung, Depots aus der UPD, je Depot `GetDepotAufstellung` (gleiche TAN-Behandlung und Protokollierung wie der Umsatzabruf). Der Knopf sitzt unter Wertpapiere → *Bestand laut Bank*, nicht im Umsatzabruf: andere Daten, eigene TAN. - Das Depot im Finanzmanager wird über die Kontonummer gefunden (Kontenverwaltung). `Depotabgleich::uebernehmen()` speichert den Stand des letzten Abrufs (`depot_bankbestaende`, Migration 021) und trägt die Bewertungskurse bekannter Wertpapiere ein. Gebucht wird nichts; `Depotabgleich::vergleich()` zeigt Abweichungen im Bestand. - Nachweis zur Überweisung: `bank_protokolle.pruefsumme` (SHA-256 des Protokolls, beim Speichern gebildet). Im Protokoll einer Überweisung lädt *Nachweis herunterladen* eine Textdatei mit Auftrag, allen Durchläufen im vollen Wortlaut und den Prüfsummen; ein nachträglich geändertes Protokoll fällt dort als ABWEICHUNG auf. - phpFinTS auf v4.1.5: Die DKB meldet die Depotaufstellung nur in Version 6 (`HKWPD`/`HIWPD`/`HIWPDS`); Upstream-PR nemiah/phpFinTS#598. - Zuordnung des Depots der Bank zu einem Depot im Finanzmanager (Migration 022, `bank_konten.art`): Das Depot steht als eigene Zeile bei den Bankkonten des Zugangs und wird beim Kontenabruf (ohne zusätzliche TAN) oder beim Depotabruf erkannt. Passt die Kontonummer zu einem eigenen Depot, wird gleich zugeordnet; sonst unter Online-Banking → Konten zuordnen (dort auch „neues Konto anlegen“). Der Umsatzabruf sieht nur Konten (`Bankzugang::konten()`), Depots über `Bankzugang::depots()`. - „Bestand einbuchen“ über der Tabelle unter Wertpapiere → Bestand laut Bank (`Depotabgleich::einbuchen()`): Mehrbestand wird als Einlieferung, Minderbestand als Auslieferung gebucht (ohne Geldseite), unbekannte Wertpapiere werden angelegt. Kurs der Einlieferung: Einstandskurs der Bank, sonst Bewertungskurs. - Spalte „Einstandskurs“ (soweit die Bank ihn meldet) in der Tabelle Bestand laut Bank. - Test 51. ## Buchungsmaske: Splitzeilen bleiben bei falscher Summe erhalten (29.09.2026) - Scheiterte das Speichern einer Buchung an der Summenprüfung der Splitzeilen (Fehlermeldung „Die Splitzeilen ergeben …, die Buchung lautet über …“), leitete `BuchungenController` bisher mit einer Flash-Meldung auf eine frische Maske weiter – die gerade erfassten Splitzeilen (und alle anderen Feldwerte) waren damit weg, obwohl in der Datenbank nichts geändert wurde: Die Validierung läuft schon vor der Transaktion, es geht nichts kaputt, nur die Eingabe. - `BuchungenController::anlegen()`/`speichern()` zeichnen die Maske jetzt bei einem Validierungsfehler direkt neu, mit den zuletzt abgeschickten Werten (`$_POST`) statt der gespeicherten – die Fehlermeldung erscheint wie gewohnt über `View::flash()`, die eigenen Eingaben bleiben stehen und lassen sich korrigieren. `View::render()` erlaubt dafür jetzt, dass ein Aufruf zusätzlich zur vorgemerkten Flash-Meldung eine eigene mitgibt, statt sie zu überschreiben. - Neu: `tests/e2e/specs/buchungen.spec.js` prüft, dass eine unstimmige Splitsumme die Eingaben (Datum, Betrag, Empfänger, beide Splitzeilen) unverändert lässt und sich nach einer Korrektur wie gewohnt speichern lässt. ## Splitbuchungen: Summenzeile zeigt den Restbetrag, Speichern nur bei Null (29.09.2026) - Die Summenzeile der Splitbuchungen (Buchungsmaske und Splitdialog im Kontoblatt) zeigte bisher die Summe der erfassten Zeilen, mit „(Rest X)“ als Zusatz. Jetzt steht dort direkt der noch offene Restbetrag zum Buchungswert (`Buchungswert - Summe der Zeilen`) – die gemeinsame Rechenfunktion `FmBetrag.splitsumme()` in `betrag.js` liefert ihn beiden Masken. - „Speichern“ (bzw. „Splitbuchung speichern“) bleibt gesperrt, solange mindestens eine Splitzeile einen Betrag trägt und der Restbetrag nicht Null ist. Ohne Splitzeilen – egal ob unbelegt oder mit direkter Kategorie/Gegenkonto zugeordnet – bleibt der Knopf wie bisher an; das Model prüft die Summe der Splitzeilen ohnehin schon serverseitig. - Der bisherige E2E-Test, der eine unstimmige Splitsumme über eine serverseitige Fehlermeldung prüfte, prüft jetzt die neue Sperre im Browser; die serverseitige Prüfung selbst deckt weiterhin Test 09 (PHP) ab. ## Regel direkt aus einer Buchung anlegen (29.09.2026) - Neuer Toggle „Regel anlegen“ in der Buchungsmaske, standardmäßig aus; das bisherige Verhalten bleibt unverändert, solange er aus ist. - Ist er beim Speichern an, entsteht aus Empfänger (ersatzweise Buchungstext), Kategorie, Klasse, Gegenkonto und Splits der Buchung eine neue Regel (`AbgleichRegel::ausBuchung()`). Ohne Empfänger und Buchungstext gibt es kein sinnvolles Muster – dann bleibt es beim gewöhnlichen Speichern ohne Regel. - Das Kontoblatt zeigt die neue Regel danach in einem modalen Dialog (`regeldialog.js`, natives `` wie beim Splitdialog) zum Prüfen und Anpassen – mit denselben Feldern wie „Neue Regel“ in den Bankregeln (ausgelagert nach `regelfelder.php`). - „Abbruch“ löscht die gerade erst angelegte Regel wieder (über das bestehende Lösch-Formular der Regelliste, nur mit Rücksprung zum Kontoblatt statt zur Regelliste); die Buchung bleibt gespeichert. Die Escape-Taste verhält sich genauso, statt den Dialog nur zu schließen und eine verwaiste Regel zurückzulassen. - „Speichern“ übernimmt Änderungen und lässt die Regel in der Liste stehen. - Neu: Test 51 (PHP) und `tests/e2e/specs/regelausbuchung.spec.js`. ## Umbuchungen: beide Seiten finden zueinander (29.09.2026) - Eine Umbuchung erscheint auf zwei Kontoauszügen, wurde aber nicht als eine Buchung erkannt: Der zweite Abruf legte die Gegenseite als eigene Buchung an, der Betrag stand doppelt im Kontoblatt. Jetzt gilt (`Bankumsatz::gegenbuchung()`): anderes Konto, Betrag mit umgekehrtem Vorzeichen, Buchungstag höchstens `banking_abgleich_tage` entfernt, keine Kategorie, keine Splitbuchung, genau ein Umsatz – und die IBANs dürfen sich nicht widersprechen (Gegen-IBAN muss eine IBAN des anderen Kontos sein). Unter mehreren Kandidaten gewinnt der zeitlich nächste. - Konten ohne IBAN (PayPal): Sind die IBANs nicht zu prüfen, wird nur bei einem eindeutigen Treffer automatisch verbunden; bei mehreren bleibt es ein Vorschlag in der Liste. - Fall 1: Der zweite Umsatz wird mit der Buchung der Gegenseite verbunden; sie bekommt das Gegenkonto und wird zur Umbuchung (`Bankumsatz::verbinden()`). - Fall 2: Haben beide Seiten schon eine eigene Buchung, führt der Abgleich sie zusammen (`Bankumsatz::umbuchungenZusammenfuehren()`, am Ende von `Bankabgleich::laufenLassen()`). Die ältere Buchung wird zur Umbuchung, die jüngere fällt weg. Nur Buchungen ohne Kategorie und Klasse; ein abgeschlossener Monat landet im Bericht. - Auch beim Zuordnen: Wählt man in der Schnellzuordnung oder im Buchungsformular ein Gegenkonto, oder setzt eine Regel beim Übernehmen eines Umsatzes eines, sucht das Programm die Gegenseite (`Bankumsatz::gegenseiteZusammenfuehren()`). Sie darf eine einzeln gebuchte Buchung (ohne Kategorie und Klasse) oder eine Umbuchung in Gegenrichtung sein; beide werden zusammengelegt, der Umsatz wandert an die verbleibende Buchung. Bei mehreren Kandidaten gewinnen bestätigte IBANs, dann der zeitlich nächste. - `passendeBuchung()` lässt je Kontoseite einen Umsatz zu. - Neu: Test 50; Test 16 erweitert. ## Bekannte Umsätze bekommen IBAN und Bank der Gegenseite nachgetragen (29.09.2026) - Der Tooltip im Kontoblatt blieb bei älteren Umsätzen leer: IBAN und Bank der Gegenseite werden erst seit dem 28.09. gespeichert, und ein erneuter Abruf übersprang bekannte Umsätze ganz. Jetzt trägt `Bankumsatz::anlegen()` bei einem bekannten Umsatz nach, was ihm fehlt (`Bankumsatz::ergaenzen()`), und gibt es an die verbundene Buchung weiter. Nur leere Felder werden gefüllt, vorhandene bleiben. - Auch `Bankumsatz::verbinden()` überträgt die Angaben auf eine von Hand erfasste Buchung. - Neu: Test 49. ## E2E-Läufe lassen die Einstellungen unverändert (29.09.2026) - Die Browser-Tests laufen gegen die echte Instanz; der Bargeld-Test hatte dabei die Adresse des Bargeld-Tools geleert. `tests/e2e/run.sh` sichert jetzt die ganze Tabelle `einstellungen` vor dem Lauf und stellt sie danach wieder her (auch bei Abbruch mit Strg+C). Eine nach hartem Abbruch liegengebliebene Sicherung wird vor dem nächsten Lauf eingespielt. - Neu: `Services/E2EEinstellungen`, `scripts/e2e-einstellungen.php sichern|wiederherstellen`, Test 48. Die Sicherung liegt unter `data/e2e/` (nicht im Repository). ## Kippschalter statt Ankreuzfeldern (29.09.2026) - Alle Ankreuzfelder erscheinen als Kippschalter im blauen Design des Projekts: aus = graue Fläche mit ✕, an = Akzentfarbe mit Häkchen (helles und dunkles Thema). Reine CSS- Änderung in `public/static/app.css`; die Elemente bleiben echte Ankreuzfelder. - Ausgenommen ist die Zeilenauswahl in den Listen (Kontoblatt, Depotbuchungen, Umsätze inkl. „alle wählen“). ## Regeln: Summe der Anteile in den Splittabellen (29.09.2026) - Die Spalte „Anteil %“ heißt in den Splittabellen der Regeln nur noch „Anteil“, da die Anteile zueinander gelten und keine Prozentwerte sein müssen. - Unter den Anteilen steht eine Summenzeile, die sich mit jeder Eingabe in derselben Tabelle neu berechnet (`public/static/app.js`). ## Zahlungsverkehr: Echtzeitüberweisung scheiterte am SEPA-Format der Bank (28.09.2026) Eine Echtzeitüberweisung schlug mit „Für Echtzeitüberweisungen nimmt die Bank nur SEPA-Formate an, die der Finanzmanager nicht erzeugt: …pain.001.001.09…“ fehl; ohne das Echtzeit-Häkchen kam stattdessen die rohe Bibliotheksmeldung „Combined VOP match confirmation and TAN request“ (#89). Zwei unabhängige Ursachen: - `SepaXml` erzeugte ausschließlich pain.001.001.03 und das DK-Format pain.001.003.03. Banken, die inzwischen nur noch das neuere ISO-Format **pain.001.001.09** führen, wiesen jede Überweisung schon vor der TAN ab. `SepaXml` erzeugt es jetzt mit: Der Ausführungstermin steht in einem eigenen `Dt`-Element (`ReqdExctnDt/Dt`), die Bankkennung heißt `BICFI` statt `BIC`, und jede Zahlung trägt eine `UETR` (eine UUID, die das SEPA-Instant-Regelwerk seit November 2019 verlangt und die für eine Echtzeitüberweisung ohnehin nötig ist). `SepaXml::schemaWaehlen()` bevorzugt es, wenn die Bank es meldet, vor dem älteren pain.001.001.03. - Bestätigt die Bank den Namensabgleich mit einem Volltreffer und verlangt im selben Antwortsatz schon die TAN, kennt `nemiah/php-fints` (Stand v4.1.4) diese Kombination noch nicht und wirft dafür eine rohe `UnsupportedException` – obwohl der Vorgang beide Angaben zu diesem Zeitpunkt schon erhalten hat. `FinTsUeberweisung` fängt genau diese Ausnahme jetzt ab und lässt den ohnehin schon vorhandenen automatischen Volltreffer-Namensabgleich (siehe unten) den Rest erledigen, statt den Auftrag mit der englischen Bibliotheksmeldung scheitern zu lassen. Erweiterte Tests in `tests/39_SepaSchemaTest.php` und `tests/43_EchtzeitueberweisungTest.php` für das neue Format, neuer Test in `tests/40_NamensabgleichTest.php` für die abgefangene Ausnahme. ## Buchungsmaske: Splitbuchung und direkte Zuordnung sperren sich gegenseitig (28.09.2026) Splitzeilen und die Felder *Kategorie / Gegenkonto* und *Klasse* ließen sich in der Buchungsmaske gleichzeitig ausfüllen (#77). - Sobald in einer Splitzeile etwas eingetragen ist, sind *Kategorie / Gegenkonto* und *Klasse* sofort gesperrt; eine Kategorie oder Klasse sperrt umgekehrt alle Splitzeilen. - Neuer Knopf *Splitbuchungen löschen* rechts über der Splittabelle: leert alle Splitzeilen und gibt Kategorie und Klasse wieder frei. - E2E-Prüfung in `buchungen.spec.js`. ## Kontoblatt: Klassen der Splitzeilen in der Klassenspalte (28.09.2026) Die Klassenspalte des Kontoblatts zeigte bei einer Splitbuchung nur die Klasse der Buchung selbst, nicht die ihrer Splitzeilen (#76). - Neu `Buchung::splitKlasse()`: Tragen alle Splitzeilen dieselbe Klasse, steht sie in der Spalte. Unterscheiden sie sich, steht dort die Marke *Splitbuchung*, der Tooltip nennt je Splitzeile Kategorie und Klasse. Ohne Klasse in den Zeilen bleibt es bei der Klasse der Buchung. - Ein Klick auf die Klassenzelle einer Splitbuchung öffnet den Splitdialog, in dem die Klassen der Zeilen geändert werden. - Neuer Test `tests/47_SplitKlasseTest.php`, E2E-Prüfung in `buchungen.spec.js`. ## Online-Banking: Alle Umsätze abrufen (28.09.2026) Über der Tabelle der Bankverbindungen steht ein Knopf *Alle Umsätze abrufen*, der jede aktive Bankverbindung der Reihe nach einzeln abruft (#75). - Neuer Dienst `Services\Sammelabruf` führt die Warteschlange; sie liegt während einer TAN-Runde in der Sitzung, nach der Freigabe geht es mit der nächsten Bank weiter. - Die TAN-Maske zeigt im Sammelabruf, welche Bankverbindung gerade fragt, und bietet *Diese Bank überspringen* neben *Abruf abbrechen*. - Ein Fehler bei einer Bank hält die übrigen nicht auf; am Ende steht je Bankverbindung eine eigene Meldung. Dafür neu: `View::flash()` für mehrere Meldungen auf einmal. - Neuer Test `tests/46_SammelabrufTest.php`, E2E-Prüfung in `banking.spec.js`. ## Einnahme/Ausgabe entscheidet der Geldfluss, nicht die Kategorie-Art (28.09.2026) Cockpit und Berichte zählten eine Bewegung nach der Art ihrer Kategorie zu Einnahmen oder Ausgaben – nicht nach ihrem Vorzeichen. Eine Kategorie wie eine Rückstellung, die in beide Richtungen bebucht wird (z. B. „010 - Rückst. USt“, angelegt als Einnahme), ließ dadurch auch negative Beträge in den Einnahmen auftauchen (n.n., Buchung 29285). - `Auswertung::artDerBewegung()` entscheidet jetzt allein über das Vorzeichen des Betrags. Die zugewiesene Kategorie-Art spielt für die Auswertung keine Rolle mehr – sie bleibt reine Verwaltungs-Metadaten (Reiter in der Kategorienverwaltung, Vorzeichen im Budgetplaner). - `Auswertung::kategoriezeilen()` baut das Zeilengerüst von Summen- und Vergleichsbericht jetzt aus allen Kategorien statt nur denen der passenden Art – sonst wäre eine Bewegung wie oben zwar in der Abschnittssumme, aber in keiner Zeile aufgetaucht. - `Auswertung::budgetbericht()` summiert den Ist-Wert einer Kategorie jetzt aus beiden Töpfen (Einnahme und Ausgabe), da eine Kategorie nun in beiden auftauchen kann. - Betroffen waren dadurch alle Cockpit-Kacheln, die auf dem Summenbericht aufsetzen (*Einnahmen und Ausgaben*, *Meine Ausgaben*) sowie deren Legenden-Drilldown, Summen-, Vergleichs- und Budgetbericht unter *Auswertungen*. - Neuer Test `summenbericht_geldflussEntscheidet()` in `tests/14_AuswertungTest.php` mit einer Kategorie, die in beide Richtungen bebucht wird. ## Cockpit: Legendeneinträge öffnen die Buchungen dahinter (28.09.2026) In allen Cockpit-Kacheln mit Legende führt ein Klick auf einen Legendeneintrag zu den Buchungen, aus denen sich der angezeigte Wert zusammensetzt (#84). - *Meine Ausgaben*: jede Kategorie, „Nicht kategorisiert“ und „Übrige (n)“ öffnen die Ausgaben des laufenden Jahres dieser Kategorien (samt Unterkategorien). - *Einnahmen und Ausgaben*: „Einnahmen“, „Ausgaben“ und „Saldo“ öffnen die Buchungen der letzten zwölf Monate. - *Vermögensentwicklung*: ein Kontoname öffnet das Kontoblatt. - Ziel ist der bestehende Drilldown der Auswertungen mit dem Filter der Kachel; `Auswertung::zeilenbuchungen()` kennt dafür neu einen Art-Filter (Einnahme/Ausgabe), „alle Bewegungen“ und mehrere Kategorien auf einmal. Aus dem Cockpit geht es zurück ins Cockpit. Die Summe der Liste entspricht dem Legendenwert. - Tests in `tests/15_CockpitTest.php` und `tests/e2e/specs/module.spec.js`. ## IBAN und Bank der Gegenseite im Kontoblatt (27.09.2026) Bei einer Buchung aus dem Bankabruf ließ sich oft nicht mehr erkennen, woher sie stammt – der Empfängername allein reicht nicht immer (z. B. bei Überweisungen zwischen eigenen Konten verschiedener Banken). - `Services\FinTsAbruf` löst IBAN/Kontonummer und Bankleitzahl bzw. BIC der Gegenseite schon beim Abruf gegen das Bankleitzahlen-Verzeichnis auf (neu: `Bankinstitut::findeNachBic()` / `findeNachBicOderBlz()`) und schreibt beides nach `bank_umsaetze.gegen_iban` / `gegen_bankname`. - `Bankumsatz::uebernehmen()` trägt beides auf die neue Buchung ein (`buchungen.iban`, `buchungen.bankname`), Migration `020_buchung_herkunft.sql`. - Im Kontoblatt zeigt der Verwendungszweck beim Mouseover IBAN und Bank, sofern bekannt (`kontoblatt.js`, `data-herkunft`). - Gilt nur für künftige Bankabrufe – bereits vorhandene Buchungen aus früheren Abrufen (auch die den Anstoß gebende Buchung 31178) kennen die Gegenseite nicht nachträglich, weil sie beim damaligen Abruf nicht mitgeschrieben wurde. - Test in `tests/45_BuchungHerkunftTest.php`. ## Umbuchung wird auch von der Gegenkontoseite erkannt (27.09.2026) Eine Umbuchung gehört ihrem Ursprungskonto; der automatische Abgleich suchte eine passende Buchung bisher nur über deren `konto_id`. Kam der Kontoauszug der Empfängerseite mit ein paar Tagen Verzug herein, fand er die schon gebuchte Umbuchung nie und legte sie als eigenständige Buchung an – die Umbuchung stand danach doppelt im Kontoblatt und verfälschte den Saldo. - `Bankumsatz::passendeBuchung()` berücksichtigt jetzt auch die Gegenkonto-Seite einer Umbuchung, mit umgekehrtem Vorzeichen wie im Kontoblatt auch. - Test in `tests/16_BankingTest.php` (`umbuchungWirdAuchVonDerGegenkontoseiteErkannt`). ## Buchungen im Kontoblatt verknüpfen (27.09.2026) Liegen zwei Buchungen, die eigentlich derselbe Vorgang sind, zu weit auseinander (oder gehörte eine ursprünglich einem anderen Ursprungskonto), findet der automatische Abgleich sie nicht – die Umbuchung und ihre einzeln erfasste Dublette stehen dann dauerhaft nebeneinander im Kontoblatt. - Neu: `Buchung::verknuepfen()` führt eine Umbuchung (eigene Seite oder Gegenseite auf diesem Konto) und eine einzeln erfasste Buchung mit passendem Betrag zusammen – die Umbuchung bleibt, die Dublette fällt weg, ihr Bankumsatz hängt sich an die Umbuchung. - Im Kontoblatt lässt sich dafür auch die Gegenseite einer fremden Umbuchung ankreuzen; der Knopf „Verknüpfen“ neben „Auswahl löschen“ nutzt dieselbe Auswahl. - Test in `tests/44_BuchungenVerknuepfenTest.php`. ## Buchungsbericht: Splitbuchung nach Konto/Empfänger zusammengefasst (27.09.2026) Nach Kategorie oder Klasse gruppiert erscheint eine Splitbuchung weiterhin mit jeder ihrer Zeilen einzeln – nur so stimmen die Gruppensummen mit dem Summenbericht überein. Nach Konto oder Empfänger gruppiert landen aber ohnehin alle Zeilen einer Splitbuchung in derselben Gruppe; dort erschien bisher trotzdem jede Zeile für sich, mit ihrem Teilbetrag statt dem Gesamtbetrag – wer nur eine der beiden Zeilen sah, hielt das für den kompletten Betrag der Buchung. - `Auswertung::splitsZusammenfassen()` fasst bei Gruppierung nach Konto oder Empfänger alle Splitzeilen einer Buchung zu einer Zeile mit dem Gesamtbetrag zusammen, analog zum Kontoblatt. Die Zeile führt keine einzelne Kategorie, sondern das Badge „Splitbuchung“; die Aufschlüsselung bleibt dem Kontoblatt vorbehalten. - Bei Kategorie oder Klasse bleibt es beim bisherigen Verhalten. - Test in `tests/14_AuswertungTest.php` (`buchungsbericht`). ## Regeln lassen sich auf Buchungen ohne Kategorie anwenden (27.09.2026) Der Knopf unter Verwaltung → Regeln hieß „Gegen offene Umsätze prüfen“ und zählte nur, wie viele noch nicht abgeglichene Umsätze eine Regel träfe – das beantwortet weder, wo im Kontoblatt schon Lücken liegen, noch schließt es sie. - Neu: `Buchung::ohneKategorie()` liefert Buchungen ganz ohne Kategorie – weder direkt (`kategorie_id`) noch in einer Splitzeile –, ausgenommen Umbuchungen (die haben per Definition ein Gegenkonto statt einer Kategorie). - Neu: `Bankabgleich::regelnAufBuchungenOhneKategorieAnwenden()` trägt bei jeder Buchung ohne Kategorie die erste passende Regel nach (Kategorie, Klasse, Gegenkonto oder Split) – ohne Treffer bleibt die Buchung unverändert, ein abgeschlossener Monat oder sonstiger Fehler betrifft nur die eine Buchung und bricht den Lauf nicht ab. - Der Knopf „Regeln auf Buchungen ohne Kategorie anwenden“ (mit Rückfrage) ersetzt den reinen Testlauf; die Regel-Trefferzähler zählen mit. - Test in `tests/16_BankingTest.php` (`buchungOhneKategorieWirdGefunden`, `regelnKategorisierenBuchungenOhneKategorie`). ## `update.sh` zieht aus dem Fork (25.09.2026) - Das Update-Skript holt den Code ausdrücklich per `git pull --ff-only origin main`. Vorher brach es ohne Tracking-Branch mit „Es gibt keine Tracking-Informationen“ ab. - Quelle ist der Fork, weil es derzeit nur die Entwicklungsumgebung gibt; der Upstream ist Backup und Veröffentlichung. Für eine spätere Produktion: `UPDATE_REMOTE=upstream`. - Das Skript bricht bei unverändertem Code nicht mehr ab: Container starten und Migrationen laufen immer, damit ein von Hand gezogener Stand nicht ohne Migration bleibt. - Der Pull läuft mit HTTP/1.1 (Codeberg liefert bei HTTP/2 sonst 504). ## Echtzeitüberweisung im Zahlungsverkehr (25.09.2026) Der Überweisungsdialog bietet jetzt das Häkchen **Echtzeitüberweisung**: Das Geld ist binnen Sekunden beim Empfänger. SEPA behandelt die Echtzeitüberweisung als eigenes Verfahren (SCT Inst), der Finanzmanager deshalb auch. - Über FinTS geht der Auftrag als Geschäftsvorfall HKIPZ hinaus (`SendSEPARealtimeTransfer` aus php-fints) statt als HKCCS. In der pain.001-Nachricht steht die Zahlungsart `LclInstrm/Cd = INST`; das gibt es nur im ISO-Format `pain.001.001.03`. - Eine Echtzeitüberweisung hat keinen Ausführungstermin: Der Dialog sperrt das Feld, ein Termin in der Zukunft wird beim Speichern abgewiesen. - Bietet die Bank keine Echtzeitüberweisung an, scheitert der Auftrag mit einer klaren Meldung und bleibt stehen. Eine stille Umwandlung in eine gewöhnliche Überweisung durch die Bank ist abgeschaltet. - Die Übersicht kennzeichnet Echtzeitüberweisungen in der Spalte „Ausführung“, das Übermittlungsprotokoll nennt sie ausdrücklich. - Neue Spalte `zahlungsauftraege.echtzeit` (Migration `019`). - Test 43 (`tests/43_EchtzeitueberweisungTest.php`) und ein E2E-Test für das Sperren des Termins. ## Übermittlungsprotokoll für Überweisungen und Bankkommunikation (21.09.2026) Als Nachweis gegenüber der Bank, dass eine Überweisung fristgerecht und korrekt übermittelt wurde, speichert der Finanzmanager jetzt den gesamten Dialog – gesendete und empfangene Meldungen im Wortlaut, im Erfolgs- wie im Fehlerfall. PIN und Benutzerkennung sind maskiert (das erledigt die FinTS-Bibliothek, bevor die Zeilen ankommen). - **Zahlungsverkehr:** Ein Klick auf den Status einer Überweisung öffnet ihr Übermittlungsprotokoll in einem modalen Dialog. Eine Überweisung mit TAN-Freigabe hat mehrere Durchläufe; alle stehen darin, der älteste zuerst. Ohne JavaScript führt der Status auf dieselbe Ansicht als eigene Seite. - **Verwaltung › Online-Banking › Protokoll** (`/banking/protokoll`): das Gesamtprotokoll über jede Kommunikation mit den Banken – Überweisungen, Umsatzabrufe und die Abfrage der TAN-Verfahren. Filterbar nach Bank, Zeitraum und Freitext. - Neue Tabelle `bank_protokolle` (Migration `018`), Modell `Bankprotokoll`, Mitschnitt über `Services\BankProtokollLogger`. Das Protokoll bleibt stehen, auch wenn die Überweisung gelöscht wird; es wird nicht automatisch aufgeräumt. - Test 42 (`tests/42_UebermittlungsprotokollTest.php`). ## Letzter roter E2E-Test aus dem Typeahead-Umbau behoben (04.09.2026) Ein Test blieb nach der Anpassung an den Typeahead (siehe unten) noch rot: „Bargeld-Tool › Eine vorgemerkte Kategorie wird beim Zuordnen geprüft“ – und zwar zuverlässig, nicht nur gelegentlich. Ursache war kein Rest des Umbaus mehr, sondern ein zu knapper Timeout: Die Schnellzuordnung im Kontoblatt prüft dabei gegen eine absichtlich ungültige Adresse (`kasse.beispiel.invalid`), und bis der serverseitige Abruf daran scheitert, vergehen durch `BargeldTool::ZEITGRENZE` (8 s Verbindungsaufbau) plus die Namensauflösung der ungültigen Adresse über 15 Sekunden – mehr, als Playwrights Standard-Timeout von 5 s für `toContainText()` hergibt. Die betroffenen Erwartungen tragen jetzt einen eigenen Timeout von 25 s, der Test insgesamt 90 s statt 60 s. ## E2E-Datenbestand wird vor jedem Lauf aufgeräumt (04.09.2026) Die Browser-Tests legten ihre Konten, Kategorien und Buchungen bei jedem Lauf neu an, weggeräumt hat sie niemand: Zuletzt standen über dreitausend Zeilen Testdaten in der Datenbank – vierzig „E2E Bankprovision …“ hintereinander im Kategoriefilter des Kontoblatts, und kein Bildschirmfoto eines fehlgeschlagenen Tests war mehr zu gebrauchen. `scripts/e2e-aufraeumen.php` räumt den Bestand weg; `tests/e2e/run.sh` ruft es vor jedem Lauf auf. Vor dem Lauf und nicht danach, weil ein abgebrochener Lauf sonst einen Bestand hinterlässt, an den niemand mehr denkt – und weil die Daten des letzten Laufs so bis zum nächsten für die Fehlersuche stehen bleiben. `E2E_KEIN_AUFRAEUMEN=1` lässt sie liegen, `--probe` zählt nur, was wegfiele. Gelöscht wird, was am Testnutzer hängt – nicht, was nach Testdaten aussieht. Ein Namensmuster übersähe die Buchung „Supermarkt“ und träfe irgendwann etwas Echtes; die Fremdschlüssel dagegen sagen genau, was zu diesem Nutzer gehört, und nehmen über ihre Kaskaden auch die Zeilen ohne eigene `benutzer_id` mit (Splitzeilen, Budgetpositionen, Bankkonten, Kurse). Der Nutzer selbst bleibt stehen, sonst käme der nächste Lauf nicht durch die Anmeldung. Als Schranke gegen den Fehlgriff muss er den Anzeigenamen tragen, den `scripts/e2e-benutzer.php` setzt: Wer `E2E_USER` versehentlich auf seinen eigenen Zugang stellt, bekommt einen Abbruch statt eines leeren Datenbestands. Das Aufräumen deckte auf, dass sieben Tests auf den Resten früherer Läufe standen: Die Auswertungen prüfen, dass ein Bericht eine Tabelle statt eines Platzhalters zeigt, das Cockpit, dass „Übrige Konten“ eine Ebene tiefer führt – Daten dafür legte keiner von ihnen an. Auf einer frisch aufgeräumten Instanz fielen sie aus; vorher hing ihr Ergebnis davon ab, wer zuletzt was hatte laufen lassen. `scripts/e2e-grundbestand.php` stellt deshalb nach dem Aufräumen einen festgelegten Bestand her, dessen Zuschnitte an genau diesen Tests hängen: mehr Konten als `Vermoegensentwicklung::SERIEN`, Buchungen in jedem Monat des laufenden Jahres, ein Vorjahr für den Vergleichsbericht, ein Depot mit Wertpapiergeschäft. Die Suite prüft damit dasselbe wie vorher, aber auf einem Bestand, den sie kennt. ## E2E-Tests an den Typeahead im Kontoblatt angepasst (04.09.2026) Zwölf E2E-Tests standen seit dem Typeahead-Umbau (Fix #41) auf Rot – nicht, weil die Anwendung etwas falsch machte, sondern weil die Specs den alten Stand prüften. Vier Ursachen lagen darunter: - **Die Kombobox versteckt ihr `` in ein Eingabefeld mit gefilterter Liste um, ohne dass App- oder Formular-Code etwas davon merken – Wert und Ändern-Ereignis bleiben identisch. Geprüft wurde außerdem, dass „Empfänger ins Adressbuch übernehmen“ beim Erfassen einer Überweisung tatsächlich eine Adresse anlegt (`ZahlungsverkehrController::anlegen()` → `Adresse::anlegen()`). ## Zahlungsverkehr: automatische Bankauswahl (31.08.2026) Beim Erfassen einer Überweisung musste bisher neben dem Auftragskonto auch die Bankverbindung von Hand gewählt werden – obwohl sich diese meist schon aus dem Konto ergibt (Feature #50). Das Formular fragt jetzt nur noch das Auftragskonto ab; die passende Bank ermittelt `Bankzugang::zugangJeKonto()` anhand der Kontenzuordnung (`bank_konten.konto_id`) und trägt sie beim Speichern automatisch in `zahlungsauftraege.zugang_id` ein. Konten ohne konfigurierte Bankverbindung stehen als Auftragskonto gar nicht erst zur Auswahl – ohne Bank ließe sich ohnehin nichts senden. Ein bereits erfasster Auftrag behält sein Auftragskonto auch dann, wenn dessen Bank nachträglich entfernt wurde: Es bleibt in der Auswahl, statt beim nächsten Speichern unbemerkt zu wechseln. ## Einstellungen: Reiter "Profil" zum Ändern des eigenen Passworts (20.08.2026) Bislang ließ sich das eigene Passwort nur direkt über den Datenbestand ändern (Feature #46). Der Einstellungsdialog bekommt dafür einen neuen Reiter `Profil`, der den angemeldeten Benutzernamen anzeigt und ein eigenes Formular für die Passwortänderung enthält – getrennt vom generischen Speichern-Formular der übrigen Reiter, weil hier kein Einstellungswert, sondern der Anmeldedatensatz geschrieben wird. `EinstellungenController::passwortAendern()` (Route `POST /einstellungen/passwort`) verlangt das aktuelle Passwort (geprüft über `Benutzer::pruefeAnmeldung()`), ein neues mit mindestens 10 Zeichen – dieselbe Grenze wie bei der Ersteinrichtung – und dessen Wiederholung. Bei Erfolg schreibt `Benutzer::passwortSetzen()` den neuen Hash; ein Eintrag landet wie bei An- und Abmeldung im Debug-Log. ## CONTRIBUTE.md und Setup-Skript für Mitwirkende (19.08.2026) `CONTRIBUTE.md` beschreibt, wie Beiträge ankommen (Issue, PR, E-Mail), welche Unterstützung gesucht wird und die drei bindenden Leitlinien des Projekts: FOSS, Datensparsamkeit und Security mit direktem Kontakt an fds2610@sonnengetrock.net für Sicherheitslücken. Vorangestellt ist ein Disclaimer, dass VIBE Coding ausdrücklich erlaubt ist – das Projekt selbst ist mit intensivem LLM-Einsatz entstanden (Feature #43). Neu ist außerdem `dev-setup.sh` im Repo-Root: richtet Docker (optional), Checkout mit Fork- und Upstream-Remote, lokale Container und optional die E2E-Testinfrastruktur ein. Zielverzeichnis, E2E-Setup und Docker-Installation lassen sich über Flags oder Umgebungsvariablen abweichend vom Default setzen. ## Kontoblatt: Typeahead für die Kategorie (19.08.2026) Die Kategorie ließ sich im Kontoblatt nur über eine lange Auswahlliste finden – bei vielen Kategorien ein langes Blättern (Feature #41). Ein neues `kombobox.js` baut ein markiertes `` bleibt unsichtbar im Formular stehen, damit Wert, Name und das Ändern-Ereignis für vorhandenen Code unverändert bleiben. Betroffen sind der Kategorie-Filter oben im Kontoblatt und die Schnellzuordnung je Buchung (`kontoblatt.js` öffnet dort die Kombobox statt `showPicker()`, sobald ein `` – ihre Liste ist kurz. Ohne JavaScript bleibt es überall beim normalen `