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>
7.6 KiB
7.6 KiB
Änderungen
Phase 2 – Buchungen, Kontoblatt und Buchungsimport (10.08.2026)
Erkenntnis aus dem Vollexport
Der Plan ging davon aus, Umbuchungen stünden zweimal in der Datei und müssten
zusammengeführt werden. Das Gegenteil ist der Fall: 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 im Export hat keine ein zweites
Vorkommen. Mit erzeugter Gegenseite stimmen acht gegen den FinanzManager geprüfte
Kontosalden auf den Cent.
Datenmodell
- Migration
003_buchungen.sql:buchungen,buchung_splits,buchungsadressen - Eine Umbuchung ist ein Datensatz mit
gegenkonto_id, kein gespiegeltes Paar – das Kontoblatt des Gegenkontos zeigt sie mit umgekehrtem Vorzeichen - Auch einzelne Splitzeilen dürfen ein Gegenkonto tragen
- Konten führen
in_summe(die Σ-Spalte des FinanzManagers) sowiesaldo_online
Kontoblatt und Buchungsmaske
- 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; Splitzeilen mit Restbetragsanzeige, geprüft auch serverseitig
- Aktueller und erwarteter Saldo; in die Summen zählen nur Konten mit Σ-Kennzeichen
QIF-Buchungsimport
QifBuchungsImportmit Stichtag: alles davor wird je Konto zum Anfangssaldo aufsummiert – einschließlich der erzeugten Gegenbuchungen –, alles danach importiert- Buchungen mit Datum nach dem Importtag gelten als Vorausberechnung und bleiben draußen
- Eröffnungsbuchungen (
L[eigenes Konto]) werden nicht zu Umbuchungen - Wertpapiergeschäfte schlagen vorerst nur mit ihrem Geldfluss auf dem Verrechnungskonto zu Buche; Bestände folgen in Phase 6
- Idempotent über einen Fingerabdruck je Buchung, der auch echte Doppelbuchungen am selben Tag auseinanderhält
- Am Vollexport geprüft: 833 Buchungen ab 01.01.2026, 7946 in die Anfangssalden von 35 Konten verrechnet, eine vorausberechnete verworfen
Behoben
- Die
confirm()-Rückfragen vor dem Löschen waren wirkungslos.public/static/app.jsbrachte den Mechanismus (data-bestaetigen) von Anfang an mit, war aber nie im Layout eingebunden; ersatzweise standen Inline-Handler (onsubmit) im HTML, und die verstoßen gegen die eigene Content-Security-Policy (script-src 'self') – der Browser verwarf sie stillschweigend, gelöscht wurde ohne Rückfrage. Jetzt ist das Skript eingebunden, die Inline-Handler sind raus, und ein E2E-Test besteht auf dem Dialog.
Tests
09_BuchungenTest– Umbuchungen mit zwei Sichten, Splitzeilen samt Summenprüfung, Splitzeile mit Gegenkonto, aktueller und erwarteter Saldo, Σ-Kennzeichen, Filter10_QifBuchungsImportTest– Stichtag, Anfangssalden aus der Vorgeschichte, erzeugte Gegenbuchung, Eröffnungsbuchung, Zukunftsfilter, zweiter Lauf ohne Wirkung- E2E
buchungen.spec.js– Ausgabe, Umbuchung auf beiden Kontoblättern, Splitbuchung, abgewiesene Splitsumme, Suche, Löschbestätigung
Phase 1 – Stammdaten und QIF-Stammdatenimport (09.08.2026)
Datenmodell
- Migration
002_stammdaten.sql:kontengruppen,konten,kategorien,klassen - Alle Tabellen führen
benutzer_id;Mandant::id()liefert die Kennung aus der Session oder – im CLI – vom ersten aktiven Benutzer
Konten
- Kontenübersicht nach Kontengruppen gebündelt, mit Gruppensummen und Gesamtsumme
- Die drei Saldospalten des FinanzManagers (Online-Saldo, aktueller und erwarteter Saldo) sind angelegt und werden bis Phase 2 aus dem Anfangssaldo gespeist
- Kontoarten des FinanzManagers samt Zuordnung zu den QIF-Typen
- Kontenpflege mit Anfangssaldo, Kreditlimit, IBAN/BIC, Kontengruppe, aktiv/inaktiv
- Kontengruppen anlegen, umbenennen, sortieren, löschen – die Konten bleiben erhalten
Kategorien und Klassen
- Hierarchische Kategorien mit
:als Trenner; der vollständige Pfad wird mitgeführt und beim Umbenennen oder Verschieben für den ganzen Teilbaum neu geschrieben - Art (Einnahme/Ausgabe) gilt für den ganzen Ast und vererbt sich an Unterkategorien
- Verschieben, Zusammenführen und Löschen; Verschieben in den eigenen Teilbaum wird abgewiesen
- Register Alle / Einnahmen / Ausgaben / Umbuchungskonten wie im Original
- Klassen als flache zweite Auswertungsdimension, in der Liste direkt bearbeitbar
QIF-Import
QifParser: zustandsbehaftetes, sequenzielles Lesen; ISO-8859-1 nach UTF-8, US-Beträge, Datumsformat aus der Kopfzeile, Mehrfachfelder für spätere SplitzeilenQifStammdatenImportfür Klassen, Kategorien und Konten – idempotent, mit Trockenlauf und Protokoll; fehlende Zwischenstufen im Kategoriepfad entstehen selbsttätig- Dialog unter Verwaltung → QIF-Import mit Upload, Trockenlauf und Übernahme
scripts/qif-import.phpfür dieselbe Aufgabe auf der Kommandozeile- Geprüft am echten Export: 17 Klassen, 105 Kategorien, 37 Konten
Tests
06_KategorienTest– Hierarchie, Pfadpflege, Artvererbung, Verschieben, Zusammenführen07_KontenTest– Kontoarten, Gruppierung und Summen, Betragseingabe08_QifImportTest– Parser, Zeichensatz, Beträge und Datum, Import, Trockenlauf, Prüfung der Dateinamen- E2E
stammdaten.spec.js– Konto, Kategorie mit Unterkategorie, Register, Klasse, QIF-Upload mit Trockenlauf
Korrektur – Monatsnamen auf Deutsch (09.08.2026)
- Der Einstellungsdialog zeigte unter Buchhaltung englische Monatsnamen, weil
date('F')sprachlich nicht umschaltbar ist. - Monatsnamen liegen jetzt zentral als
View::MONATEundView::MONATE_KURZvor, abrufbar überView::monat(). Budgetplaner und Auswertungen greifen später darauf zu. 05_DarstellungTestprüft Monatsnamen, Betrags- und Datumsformat gegen eine feste Sollliste – der Vergleich gegendate('F')allein würde April, August, September und November nicht auffallen lassen.
Phase 0 – Projektgerüst (09.08.2026)
Grundgerüst der Anwendung. Fachliche Module folgen ab Phase 1.
Betrieb
- Docker Compose mit drei Services:
nginx(Port 8000),php(php-fpm 8.3),db(MariaDB 11) docker-entrypoint.shlegt Datenverzeichnisse an und spielt Migrationen einscripts/migrate.php– nummerierte SQL-Migrationen, idempotent, mit Journal-Tabellescripts/update.sh– Update für den Produktionsserver: Backup,git pull, Image-Neubau bei Bedarf, Migrationen, Rechte, Testsscripts/backup.sh– Datenbank- und Dateisicherung mit Rotation (7 Tage / 4 Wochen / 12 Monate), gegen Parallelläufe perflockabgesichert
Anwendung
Config,Database(PDO-Wrapper, verschachtelbare Transaktionen),Router(Platzhalter-Routen, CSRF-Prüfung für alle verändernden Requests),View,Auth- Anmeldung mit Session-Härtung, Ersteinrichtung des ersten Benutzers
- Zentraler Einstellungsdialog mit Reitern (Allgemein, Darstellung, Buchhaltung,
Online-Banking, Import/Export, Wertpapiere, Diagnose); Werte in Tabelle
einstellungen - Debug-Log, ein- und ausschaltbar, mit Maskierung von PINs, Passwörtern, TANs und API-Keys; Ausnahmen werden immer protokolliert
- Layout nach Vorbild des FinanzManagers: feste Navigation links, Werkzeugleiste oben, Tab-Leiste; Farbschema hell/dunkel/System
Tests
- Test-Harness mit Transaktions-Rollback und Aufräumen temporärer Pfade
01_AuthTest– Anmeldung, Passwort-Hashing, CSRF, Cookie-Attribute02_EinstellungenTest– Lesen/Schreiben, Cache-Invalidierung, Bereichsabdeckung03_RouterTest– Pfad-Muster, Platzhalter, keine Treffer über Pfadgrenzen04_DebugLogTest– Schalter, Maskierung, Fehlerprotokollierung