Meldet die Bank nach der TAN 3045 (noch keine Rückmeldung zum Status),
fragt ein Hintergrundprozess nach der Mindestwartezeit aus HIIPSS per
HKIPS nach (höchstens fünfmal). Ausgeführt wird vermerkt, abgelehnt
entfernt die Buchung; ein verbundener Kontoumsatz klärt den Status
ebenfalls. php-fints-Fork v4.1.7 bringt HKIPS/HIIPS/HIIPSS mit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Der Pull nennt Remote und Branch ausdrücklich (origin main, HTTP/1.1), damit kein
Tracking-Branch nötig ist. Quelle ist der Fork, solange es nur die Entwicklungsumgebung
gibt; für eine spätere Produktion gibt es UPDATE_REMOTE=upstream. Das Skript bricht bei
unverändertem Code nicht mehr ab, sodass Migrationen eines von Hand gezogenen Stands
nachgeholt werden. Doku (CLAUDE.md, PLAN.md, README.md, Changes.md) angepasst.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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, und kein Bildschirmfoto eines fehlgeschlagenen Tests war mehr
zu gebrauchen.
scripts/e2e-aufraeumen.php räumt weg, 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. Der Nutzer selbst bleibt stehen, und er muss 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.
Aufgerufen wird es vor dem Lauf, nicht danach – ein abgebrochener Lauf
hinterlässt sonst einen Bestand, an den niemand mehr denkt, und so bleiben die
Daten des letzten Laufs bis zum nächsten für die Fehlersuche stehen.
Das 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. scripts/e2e-grundbestand.php stellt deshalb 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.
Test 41 prüft jede dieser Grenzen einzeln und nennt den Test, der daran hängt.
87 E2E-Tests grün, in 1,3 statt 2,7 Minuten – die Listen rendern keine
Tausenden Altzeilen mehr.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AQ57wQWZ4xKHcKmp26bzgr
Aus der Kachel QIF-Import wird Import/Export mit je einem Knopf für beide
Richtungen; davor steht die Wahl des Dateiformats (QIF oder CSV), die als
Dialog und ohne Skript als eigene Seite funktioniert.
- CsvBuchungsImport/CsvTabelle: Buchungen samt Splitzeilen, Spalten über die
Kopfzeile, dieselbe Dublettenerkennung und der Trockenlauf wie beim QIF.
- BuchungsExport/ExportController: Filter nach Zeitraum, Konto, Kategorie und
Klasse; die Datei entsteht im Speicher, ein Exportverzeichnis gibt es nicht.
- Housekeeping: Hochgeladene Importdateien und data/tmp werden nach der
eingestellten Frist gelöscht (Vorgabe 14 Tage, 0 schaltet ab).
Migration 013, Test 29 sowie E2E-Spec importexport.spec.js.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Import kannte bisher nur den Zeitraum als Filter – ein Export ließ sich
nur ganz einlesen. Neu ist die Option "konten": im Dialog eine Ankreuzliste,
die erst nach dem Trockenlauf erscheint (vorher ist die Datei ungelesen), auf
der Kommandozeile --konto=NAME und --konten.
Maßgeblich ist nicht allein der !Account-Abschnitt, sondern jedes Konto, das
der Eintrag berührt: das eigene, die Umbuchungsziele aus L und den Splitzeilen
und beim Wertpapiergeschäft das Verrechnungskonto. Eine Umbuchung steht nur
einmal in der Datei – sonst fehlte dem gewählten Konto die Gegenseite.
Die Anfangssalden werden weiter über die ganze Datei gerechnet, aber nur für
die gewählten Konten geschrieben; ein Teilimport überschreibt sonst fremde
Salden. Die Fingerabdrücke entstehen jetzt vorab in einem eigenen Durchgang:
Der laufende Zähler für gleiche Fingerabdrücke hing sonst an der Auswahl, und
dieselbe Buchung wäre beim zweiten Lauf mit anderer Auswahl doppelt angelegt
worden.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Damit ist der geplante Funktionsumfang beisammen.
Phase 4 abgeschlossen
- Konfigurierbare Cockpit-Kacheln; abgewählte werden nicht berechnet
- Einnahmen/Ausgaben je Monat als Balkenpaare mit Saldolinie, aufgesetzt auf
den Summenbericht statt auf eine eigene Abfrage
- Meine Ausgaben als Ring auf der obersten Kategorieebene
- Offene Vorgänge aus allen Modulen
Phase 5 – Online-Banking
- nemiah/php-fints als Fork auf Codeberg, psr/log direkt eingebaut: die
Anwendung hängt an keinem fremden Update-Zyklus
- PIN AES-256-GCM-verschlüsselt; Schlüssel aus APP_KEY oder aus
data/schluessel/app_key, den der Entrypoint einmalig erzeugt
- TAN-Dialog über mehrere Requests (FinTs::persist plus serialisierte Aktion
in der Sitzung) – ein wartender Prozess wäre mit php-fpm der falsche Weg
- Abgleich statt Direktbuchung: verbinden, übernehmen oder verwerfen
- Regeln mit vier Vergleichsarten, Betragsgrenzen und Split-Schema
Phase 6 – Wertpapiere
- Depotbuchung und Geldbuchung als zwei Seiten eines Geschäfts; betrag ist
der Bruttowert, Nebenkosten stehen daneben
- Einstand nach gleitendem Durchschnitt, realisierte Gewinne, Erträge
- Kursabruf über Leeway oder FMP, täglicher Lauf per Cron
- QIF-Import für !Type:Invst
Dabei behoben: Der Import buchte den Geldfluss jedes Wertpapiergeschäfts als
Abgang – auch bei Verkäufen und Dividenden; und er erkannte das
Verrechnungskonto nicht, wenn dem Konto im L-Feld eine Kategorie vorangeht
(bei Verkäufen also immer).
Phase 7 – Nebenmodule und Zahlungsverkehr
- Buchungsvorlagen inklusive QIF-Import, Splits werden mitskaliert
- Regelmäßige Buchungen mit Fälligkeitslauf, Finanzkalender, Erinnerungen
- Adressen mit IBAN-Prüfung, Verträge mit Kündigungsfrist, Sparziele
- Kredite mit gerechnetem Tilgungsplan
- Überweisungen über FinTS; die Buchung entsteht erst nach Annahme durch die
Bank. Die pain.001-Nachricht erzeugt SepaXml selbst
Nebenbei: .dockerignore ergänzt (ohne sie brach der Build an data/mariadb ab),
PlatzhalterController entfernt, zwei Inline-Handler beseitigt, die die
Content-Security-Policy ohnehin blockierte.
888 PHP-Prüfungen und 45 E2E-Tests grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Plan ging davon aus, Umbuchungen stünden zweimal im Export und müssten
zusammengeführt werden. Der Vollexport zeigt das Gegenteil: Eine Umbuchung
steht einmal, in dem Konto, in dem sie erfasst wurde; die Gegenseite ist nur
durch L[Zielkonto] benannt und muss beim Import erzeugt werden. Von 965
Umbuchungen hat keine ein zweites Vorkommen. Mit erzeugter Gegenseite stimmen
acht gegen den FinanzManager geprüfte Kontosalden auf den Cent.
Datenmodell: Migration 003 mit buchungen, buchung_splits und buchungsadressen.
Eine Umbuchung ist ein Datensatz mit gegenkonto_id, kein gespiegeltes Paar -
zwei Zeilen laufen früher oder später auseinander. Das Kontoblatt des
Gegenkontos zeigt sie mit umgekehrtem Vorzeichen. Auch einzelne Splitzeilen
dürfen ein Gegenkonto tragen. Konten führen zusätzlich in_summe, die
Sigma-Spalte der Kontenübersicht, und saldo_online für Phase 5.
Oberfläche: Kontoblatt mit laufendem Saldo, Filter auf Zeitraum, Kategorie,
Klasse und Abgleich, Volltextsuche und Seitenblättern. Buchungsmaske für
Einnahme, Ausgabe und Umbuchung in beide Richtungen, mit Splitzeilen und
Restbetragsanzeige.
Import: QifBuchungsImport arbeitet mit Stichtag. Alles davor wird je Konto zum
Anfangssaldo aufsummiert, Gegenbuchungen eingerechnet; alles danach bis zum
Importtag kommt einzeln in die Datenbank. Spätere Buchungen sind
Vorausberechnungen des FinanzManagers und bleiben draußen. Wertpapiergeschäfte
schlagen vorerst nur mit ihrem Geldfluss auf dem Verrechnungskonto zu Buche.
Am Vollexport geprüft: 833 Buchungen ab 01.01.2026, 7946 in die Anfangssalden
von 35 Konten verrechnet.
Behoben: Die confirm()-Rückfragen vor dem Löschen waren wirkungslos.
public/static/app.js brachte den Mechanismus mit, war aber nie im Layout
eingebunden; die ersatzweise gesetzten onsubmit-Attribute verstoßen gegen die
eigene Content-Security-Policy und wurden vom Browser verworfen - gelöscht
wurde ohne Rückfrage. Ein E2E-Test besteht jetzt auf dem Dialog.
Tests: 307 PHP-Prüfungen und 21 Playwright-Tests, alle grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Konten, Kontengruppen, Kategorien und Klassen samt Übernahme aus dem
QIF-Export des Lexware FinanzManagers.
Kontenübersicht nach Kontengruppen gebündelt, mit Gruppensummen und
Gesamtsumme; die drei Saldospalten (Online-Saldo, aktueller und erwarteter
Saldo) sind angelegt und werden bis Phase 2 aus dem Anfangssaldo gespeist.
Kategorien sind hierarchisch mit ":" als Trenner. Der vollständige Pfad
steht redundant in der Tabelle, weil jede Anzeige und der gesamte Import
darüber laufen; Umbenennen und Verschieben schreiben den Teilbaum neu. Die
Art (Einnahme/Ausgabe) gilt für den ganzen Ast. Register wie im Original:
Alle, Einnahmen, Ausgaben, Umbuchungskonten.
QifParser liest zustandsbehaftet und sequenziell, wandelt ISO-8859-1 nach
UTF-8 und versteht US-Beträge sowie das Datumsformat aus der Kopfzeile.
QifStammdatenImport ist idempotent und bietet Trockenlauf und Protokoll -
im Dialog unter Verwaltung sowie über scripts/qif-import.php. Am echten
Export geprüft: 17 Klassen, 105 Kategorien, 37 Konten.
Enthält außerdem die Korrektur der englischen Monatsnamen im
Einstellungsdialog: date('F') ist sprachlich nicht umschaltbar, deshalb
liegen die Namen jetzt zentral als View::MONATE vor. Die Änderung ließ
sich nicht als eigener Commit trennen, weil sie dieselben Dateien berührt
wie Phase 1.
Tests: 227 PHP-Prüfungen und 14 Playwright-Tests, alle grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Docker Compose mit drei Services (nginx auf Port 8000), Migrationsmechanik,
Update- und Backup-Skript. Anwendung: Router mit CSRF-Prüfung, Anmeldung und
Ersteinrichtung, zentraler Einstellungsdialog mit Reitern, ein- und
ausschaltbares Debug-Log mit Maskierung von Zugangsdaten.
Layout nach Vorbild des FinanzManagers: feste Navigation links,
Werkzeugleiste oben, Tab-Leiste; Farbschema hell/dunkel/System.
Tests: 51 PHP-Prüfungen und 7 Playwright-Tests, alle grün.