Changelog
Alle nennenswerten Änderungen an diesem Projekt werden hier dokumentiert.
Format angelehnt an Keep a Changelog, Versionierung nach Semantic Versioning: MAJOR.MINOR.PATCH - MINOR bei neuen Funktionen, PATCH bei Fehlerkorrekturen (solange 0.x.x: auch mal beides in einer Version, wenn zeitlich zusammen entwickelt).
[0.15.0] - 2026-10-12
Added
- Fortschritt bleibt sichtbar, auch beim Menüwechsel, Abmelden und späteren Wiederkehren.
Die Verarbeitung läuft serverseitig unabhängig von der Browser-Sitzung. Laufende
Verarbeitungen erscheinen jetzt auf jeder Seite im Menüband („Verarbeitung läuft ▮▮▯ 41 %",
Klick führt zur Ergebnisseite bzw. Job-Liste), in Meine Jobs mit Fortschrittsbalken
und Live-Aktualisierung und nach erneutem Login wieder genau dort. Wird ein Vorgang fertig,
während man auf einer anderen Seite ist, erscheint ein Hinweis „Fertig – Berichte ansehen"
(bzw. „Fehlgeschlagen – Details"). Neuer Endpunkt
/api/jobs/active. - Mail bei Fertigstellung (opt-in): im Konto-Menü per Klick an/aus („Mail bei Fertigstellung")
und unter
/account(„Einstellungen"). Standard: aus. Die Mail kommt, wenn ein Upload fertig berechnet ist oder fehlgeschlagen ist, enthält nur Status, Dateinamen und Links (keine Finanzdaten) und den Hinweis, wie man sie wieder ausschaltet. Wenn SMTP nicht eingerichtet ist, steht das auf der Einstellungsseite (Mails werden dann nur im Log ausgegeben). - DB: Spalte
users.notify_job_done(wird beim Start automatisch ergänzt).
Changed
- Job-Liste zeigt bei laufenden Jobs schon die hochgeladenen Dateinamen; ein durch einen Server-Neustart unterbrochener Vorgang wird als „abgebrochen" mit Erklärung angezeigt (der Bestand bleibt unverändert, Upload erneut durchführen).
Fixed
- Beim Seitenwechsel auf die Job-Liste ging der Fertig-Hinweis durch das automatische Neuladen verloren (Hinweise überstehen jetzt ein Neuladen).
[0.14.0] - 2026-10-12
Changed
- Einheitliche Navigation und Bedienung auf allen Seiten: festes Menüband oben (Neuer Upload · Steuerjahre & Bestand · Meine Jobs · Tarif & Abo, rechts Konto-Menü mit Abmelden), die aktuelle Seite ist markiert; für Admins zusätzlich ein Menü „Administration“ und eine Tab-Leiste auf den Admin-Seiten. Auf dem Handy klappt das Menü hinter „Menü“ auf. Die verstreuten Rücklinks und „Eingeloggt als …“-Zeilen auf den Einzelseiten entfallen.
- Nach-oben-Knopf unten rechts (erscheint beim Scrollen), sanftes Scrollen, „Zum Inhalt springen“-Link für Tastaturnutzer.
- Gemeinsames Design (
static/app.css/app.js, Basis-Templatebase.html): einheitliche Buttons (Hauptaktion blau, Nebenaktion hell, Löschen rot), Hinweisboxen, Tabellen (auf dem Handy seitlich scrollbar), Formulare mit deutlichem Fokus; Seiten sind jetzt auch auf dem Handy nutzbar (fehlte bisher das Viewport-Meta). - Upload-Seite: 3-Schritte-Hinweis, Liste der gewählten Dateien mit Größe, Gebühren-/Zeilen-/Kursabfrage-Optionen unter „Erweiterte Optionen“ eingeklappt (Texte und Feldnamen unverändert).
- Login/Registrierung: „Passwort anzeigen“, Browser-Passwortmanager-Hinweise
(
autocomplete), die drei Registrierungsschritte werden erklärt. - Nach dem Upload: Erfolgsbox mit Knopf „Zu den Berichten“; leere Zustände („Noch nichts im Bestand“, „Noch keine Jobs“) mit direktem Knopf zum Upload.
- Absende-Knöpfe zeigen nach dem Klick „Bitte warten …“ (verhindert Doppel-Klicks).
- Fußzeile mit Version, Changelog, Support und (wenn in der
.envgesetzt) AGB, Datenschutz, Impressum.
[0.13.0] - 2026-10-11
Added
- Admin-Reset auf Auslieferungszustand (
/admin/reset, Link unten in der Nutzerverwaltung). Löscht alle Nutzer, Uploads/Bestände/Berichte, Job-Einträge sowie Tarife, Abos, Gratis-Zugänge, Einstellungen und das Stripe-Ereignisprotokoll in der Datenbank und setzt die ID-Zähler zurück; danach existieren nur der Admin-Account aus der.env(Start-PasswortADMIN_INITIAL_PASSWORD) und die vier inaktiven Platzhalter-Tarife. Sicherung: Admin-Passwort erneut eingeben undALLES LÖSCHENtippen; Fehlversuche fließen ins Rate-Limiting. Bei laufenden Berechnungen wird abgelehnt; bei laufenden Stripe-Abos erscheint eine Warnung (die Abos bei Stripe selbst bleiben bestehen). Die Datenbank wird in einer Transaktion geleert (bei Fehler bleibt alles unverändert). - Login-Seite zeigt nach dem Reset einen Hinweis.
[0.12.0] - 2026-10-11
Added
- Jahrespaket wahlweise als Abo mit automatischer Verlängerung ODER als Einmalkauf
für 12 Monate (läuft ohne Kündigung von selbst aus). Der Kunde wählt pro Tarif auf
/billing; der Admin legt unter/admin/billingfest, ob beides, nur das Abo oder nur der Einmalkauf angeboten wird (Standard: beides). - Einmalkauf läuft über Stripe Checkout im Zahlungsmodus (inkl. Rechnung), schaltet
erst bei
payment_status = paidfrei (SEPA & Co.: über das neue Eventcheckout.session.async_payment_succeeded), ist über die Checkout-Session idempotent und hängt bei erneutem Kauf die 365 Tage an die Restlaufzeit an. Kein Karenzzeitraum nach Ablauf (die gilt nur für Abos). - Datenbank auf PostgreSQL 18 (
postgres:18-alpine, vorher 16). Das Datenbank-Volume wird jetzt nach/var/lib/postgresqlgemountet (Postgres 18 legt die Daten versioniert unter18/dockerab). Migration: ein vorhandenesdata/pgdatavon Version 16 ist nicht kompatibel - löschen (keine Produktivdaten) oder perpg_dumpsichern und zurückspielen. - Webhook-Events ergänzen:
checkout.session.async_payment_succeeded. - DB: Spalte
subscriptions.stripe_checkout_session_id(wird beim Start automatisch ergänzt).
[0.11.0] - 2026-10-11
Added
- Bezahlmodelle (Blockpit/CoinTracking-Stil), per Admin-Schalter aktivierbar. Hochladen, Berechnen und die Zusammenfassung ansehen bleiben kostenlos; die Berichts-Downloads (CSV/PDF, auch die Teilberichte je Upload) setzen einen Zugang voraus. Standardmäßig ist das Bezahlmodell aus (alles frei).
- Tarife nach Transaktionen pro Steuerjahr (frei konfigurierbar im Admin-Bereich
/admin/billing: Name, Preis, Limit oder unbegrenzt, aktiv/inaktiv, Reihenfolge). Hat ein Jahr mehr Transaktionen als das Limit, ist nur dieses Jahr gesperrt; die Tarif-Seite schlägt den kleinsten passenden Tarif vor. Gezählt werden alle Nicht-Fiat-Buchungszeilen je Steuerjahr (Berliner Zeit). - Jahres-Abo über Stripe Checkout inkl. Kundenportal (kündigen,
Zahlungsart, Rechnungen) und signaturgeprüftem Webhook
/stripe/webhook(Duplikate werden verworfen). Verlängerung, Kündigung zum Periodenende und Zahlungsausfall laufen über die Webhooks; konfigurierbare Karenzzeit. - Gratis-Zugang für ausgewählte Nutzer (Admin pro Nutzer: optional mit Ablaufdatum und eigenem Transaktionslimit) sowie manuell zugewiesene Tarife (z.B. Rechnung/Überweisung), jeweils mit Notiz. Admin-Konten sind immer frei.
- Schalter „Beträge in der Gratis-Vorschau anzeigen“ (aus = „•••“ bei gesperrten Jahren).
- Neue Umgebungsvariablen:
STRIPE_SECRET_KEY,STRIPE_WEBHOOK_SECRET,STRIPE_AUTOMATIC_TAX,STRIPE_TAX_ID_COLLECTION,STRIPE_REQUIRE_TOS,BILLING_GRACE_DAYS,APP_NAME,LEGAL_AGB_URL,LEGAL_PRIVACY_URL,LEGAL_IMPRINT_URL. - Neue DB-Tabellen (werden beim Start automatisch angelegt):
plans,subscriptions,user_access,app_settings,stripe_events. Beim ersten Start entstehen vier inaktive Platzhalter-Tarife - Preise/Limits im Admin-Bereich festlegen. - Tests:
tests/test_entitlement.py,tests/e2e_billing.py.
Changed
tests/e2e_webapp.pyläuft jetzt gegen eine echte PostgreSQL-Testdatenbank (TEST_DATABASE_URL, Name muss auf_testenden) statt gegen einen Fake;tests/_fake_db.pyentfällt, neutests/_pg.py.- Das Berechnungsergebnis (
result.json) enthält zusätzlichtx_per_year.
[0.10.1] - 2026-10-10
Changed
- Projektstruktur fürs Repository:
docker-compose.ymlliegt jetzt im Projekt-Root, die.envdaneben (Docker Compose liest sie automatisch aus dem Ordner des Compose-Files). Start:cp .env.example .env, Werte setzen,docker compose up -d --build(kein-f webapp/docker-compose.ymlmehr). - Alle Laufzeitdaten des Docker-Betriebs liegen unter
./data/(data/pgdata,data/jobs,data/ledger_data) statt im Quellcode-Baum. Migration: neue Struktur, alte Ordner (webapp/pgdata,webapp/jobs, ...) werden nicht mehr gemountet - bei einer bestehenden Installation Daten verschieben oder neu aufbauen. SESSION_COOKIE_HTTPS_ONLYwird jetzt aus der.envan den Container durchgereicht.- Das Volume für den alten Portfolio-Startbestand (0.8-0.9) entfällt.
Added
.env.example(Vorlage aller Variablen, ohne Geheimnisse) und.dockerignore(verhindert, dass.env, Laufzeitdaten und Tests ins Image kopiert werden)..gitignoreignoriertdata/und die.env.
Fixed
tests/e2e_webapp.pylegt Test-Jobs nicht mehr im Projektordner ab.
[0.10.0] - 2026-10-10
Added
- Steuerjahr in der Job-Übersicht:
/my-jobszeigt je Job das Steuerjahr (Jahre der Transaktionen im Upload) und die Dateinamen. - Mehrere Uploads pro Steuerjahr: Enthält ein Jahr Verkäufe aus mehreren Uploads, gibt es je Upload einen Teilbericht (CSV + PDF) und zusätzlich den Gesamtbericht des Jahres (CSV + PDF mit Anlage SO). Die Summe der Teilberichte entspricht exakt dem Gesamtbericht; der Gesamtbericht enthält eine Tabelle "Aufteilung nach Upload". Teilberichte tragen den Titel "Teilbericht" und enthalten bewusst keine Anlage-SO-Zeilen.
- Seite "Steuerjahre & Bestand" (
/years): alle Jahre mit Downloads, alle Uploads im Bestand, einzelne Uploads löschen, gesamten Bestand löschen. - Neues Modul
ledger_store.py(Bestand pro Nutzer), Tests untertests/.
Changed
- Reihenfolge-unabhängige Berechnung: Die Webapp speichert jetzt die hochgeladenen Original-Dateien pro Nutzer und berechnet bei JEDEM Upload (und beim Löschen eines Uploads) alle Berichte aus allen Uploads chronologisch neu. Egal wie, wo und wann etwas hinzukommt - auch ältere Zeiträume nachträglich - das Ergebnis ist immer identisch mit einem einzigen Lauf über alle Dateien (per Test mit allen Upload-Reihenfolgen geprüft, byte-identische CSVs). Bei gleichem Zeitstempel entscheidet die Reihenfolge in der Datei; die Dateien selbst werden in fester, vom Upload-Zeitpunkt unabhängiger Reihenfolge verarbeitet.
- Identische Dateien (SHA-256) werden abgelehnt; zeitliche Überschneidung mit einem früheren Upload derselben Börse warnt nur (wie bisher gewünscht).
- Gebühren-Handling und "Zeilen zusammenfassen" gelten für den gesamten Bestand (zuletzt gewählte Einstellung).
- Job-Einträge werden weiterhin nach
JOB_RETENTION_DAYSautomatisch entfernt, der Bestand bleibt davon unberührt. "Job löschen" löscht nur den Job-Eintrag. Die temporäre Upload-Kopie im Job-Ordner entfällt nach der Übernahme in den Bestand.
Removed
- Webapp: Feld "Nur ein bestimmtes Steuerjahr" und Checkbox "Gespeicherten
Startbestand verwenden" (nicht mehr nötig, es werden immer alle Jahre
berechnet). Die CLI-Option
--yearund--startbestandbleiben. - Der Portfolio-Snapshot (
webapp/portfolio_states/) wird von der Webapp nicht mehr verwendet, weil er sich bei später nachgereichten älteren Daten nicht korrigieren lässt. Migration: die Original-CSVs der früheren Jahre einmal erneut hochladen; "Gesamten Bestand löschen" entfernt auch den alten Snapshot. Neues Docker-Volume:./ledger_data:/app/webapp/ledger_data.
[0.9.1] - 2026-09-18
Fixed
- Binance hat den Export umbenannt (Binance Tax als eigenständiges
Produkt wurde eingestellt): Spalten heißen jetzt
User ID/TimestattUser_ID/UTC_Time.parsers/binance.pyerkennt und verarbeitet jetzt automatisch BEIDE Varianten - auch gemischt in einem Lauf (z.B. ältere Exporte mit alten Spaltennamen zusammen mit einem neuen Export). Keine Einstellung nötig, keine Auswirkung auf bereits vorhandene Dateien im alten Format.
[0.9.0] - 2026-09-15
Added
- Unterstützung für Bitget (Order-History-Export, semikolon-getrennt,
deutsche Spaltennamen). Nur
Typ=SpotundStatus=Ausgeführtwerden verarbeitet - alles andere (Margin/Futures, stornierte Orders) bricht mit klarer Fehlermeldung ab statt zu raten. - CSV-Format-Erkennung unterstützt jetzt auch semikolon-getrennte Dateien (nötig für Bitgets deutschen Export), automatische Erkennung anhand der Header-Zeile.
Known limitations
- Der Bitget-Parser ist NICHT gegen eine echte, unbearbeitete Bitget- Datei validiert (nur gegen eine vom Nutzer bestätigte "echte Struktur, Werte angepasst"-Beispieldatei) - anders als Binance (byte-genau gegen WISO-Referenz geprüft) und Kraken (gegen echten Export geprüft). Vor dem Einreichen Endsumme/Restbestände stichprobenartig gegenprüfen.
- Wie Krakens "Trades"-Export zeigt der Bitget "Order-History"-Export nur Kauf/Verkauf - Deposits, Withdrawals und Earn-Erträge fehlen komplett. Das Tool warnt bei jedem Bitget-Import automatisch darauf hin.
[0.8.2] - 2026-09-10
Changed
- Börsenname(n)-Auswahl von
<datalist>(in Chrome/Edge ohne sichtbaren Dropdown-Pfeil) auf ein echtes<select>-Element umgestellt - garantiert klickbarer, nativer Dropdown-Pfeil in jedem Browser. Auswahl trägt den Namen automatisch in das bestehende Textfeld ein, das weiterhin für freie Eingabe (z.B. mehrere Börsen) genutzt werden kann.
[0.8.1] - 2026-09-10
Changed
- Börsenname(n)-Feld ist nicht mehr mit "Binance" vorausgefüllt (leer, damit die Auswahlliste/Eingabe bewusst genutzt wird).
- Hinweistext beim Börsenname(n)-Feld vereinfacht: statt der detaillierten Erklärung zur kommagetrennten Reihenfolge jetzt der Hinweis, mehrere Dateien unterschiedlicher Börsen chronologisch geordnet einzulesen.
- Label über dem Datei-Upload angepasst: "CSV-Datei (chronologisch geordnet einlesen und verarbeiten lassen)" statt "CSV-Datei(en) (mehrere Jahre/Börsen gemeinsam auswählen)".
[0.8.0] - 2026-09-09
Added
- Mehrjahres-Kontinuität ohne jedes Mal alle Vorjahre neu hochladen zu
müssen: Jeder Lauf schreibt jetzt eine
portfolio_stand.json(Momentaufnahme aller noch offenen FIFO-Lots), die per--startbestandin einen späteren Lauf geladen werden kann - nur noch die neuen Transaktionen müssen dann hochgeladen werden. Validiert: ein kombinierter Lauf und ein aufgeteilter Lauf mit Startbestand liefern byte-identische Ergebnisse. - Warnung (kein Abbruch), falls neu hochgeladene Zeilen zeitlich vor dem Stichtag eines geladenen Startbestands liegen (mögliche Doppelzählung).
- Webapp: Der Startbestand wird jetzt automatisch pro Nutzerkonto gespeichert und bei jedem neuen Lauf automatisch geladen - kein manuelles Datei-Jonglieren nötig. Startseite zeigt den aktuell gespeicherten Bestand (mit Stichtag) inkl. "Bestand zurücksetzen"- Knopf; per Checkbox abschaltbar für bewusst isolierte Kontrollrechnungen (ändert den gespeicherten Bestand dann nicht).
[0.7.0] - 2026-09-09
Added
- Börsenname(n)-Feld im Webapp-Formular zeigt jetzt eine Auswahlliste der aktuell unterstützten Börsen (Binance, Kraken) zum Anklicken, statt nur ein leeres Textfeld - freie Eingabe (z.B. für die kommagetrennte Mehrbörsen-Syntax) bleibt weiterhin möglich. Hinweis zur nötigen Reihenfolge bei mehreren Dateien deutlicher hervorgehoben.
[0.6.1] - 2026-09-09
Fixed
- Kraken-Parser an das tatsächliche Ledgers-Export-Format angepasst
(anhand eines echten Exports geprüft, nicht nur Beispieldaten): neue
Zeilentypen
spend/receivefür Krypto-zu-Krypto-Konvertierungen ergänzt (z.B. USDC direkt zu XRP); Staking-Erträge heißen dortearn/rewardstattstakingund die Gebühr wird dabei VOR der Gutschrift abgezogen statt danach - beides jetzt korrekt behandelt. - Falsch-positive Warnungen bei ganz normalen Kraken-Tickern wie "XRP" entfernt (eine frühere Heuristik für unbekannte Sonderpräfixe war zu unscharf und hat auch normale, unpräfigierte Ticker angemeckert).
[0.6.0] - 2026-09-09
Added
- Unterstützung für Kraken (Ledgers-Export): Deposits, Withdrawals, Trades und Staking-Erträge werden erkannt; der für eine Steuer- berechnung ungeeignete Kraken-"Trades"-Export wird stattdessen mit einer klaren Fehlermeldung abgewiesen.
- Warnhinweis im PDF-Steuerbericht, wenn verkaufte Positionen aus Staking-Erträgen stammen (dafür kann sich die steuerfreie Haltefrist nach § 23 Abs. 1 Nr. 2 EStG auf 10 statt 1 Jahr verlängern).
Fixed
- Die Erkennung von Fiat-Währungen war fest auf EUR beschränkt - US- Dollar (bei Kraken der Normalfall) wäre sonst fälschlich wie eine Kryptowährung behandelt worden.
[0.5.0] - 2026-09-07
Added
- Schutz gegen Brute-Force-Login-Versuche: Sperre nach mehreren Fehlversuchen, sowohl pro Konto als auch pro IP-Adresse.
- Jede versendete E-Mail (Registrierungsbestätigung, Admin- Benachrichtigung, Freischaltung) enthält jetzt automatisch eine Support-Kontaktadresse in der Fußzeile.
Changed
- Hinweis "Nur im internen Netz/VPN betreiben" von der Startseite entfernt - durch TLS, Login und das neue Rate-Limiting nicht mehr nötig.
[0.4.0] - 2026-09-04
Added
- Freigeschaltete Nutzer bekommen jetzt automatisch eine E-Mail mit Login-Link, statt selbst nachfragen zu müssen, ob ihr Zugang schon aktiv ist.
[0.3.0] - 2026-09-02
Added
- PDF-Steuerbericht pro Jahr: Jahres- und Monatsübersicht (getrennt nach steuerpflichtig und steuerfrei), Aufteilung nach Börse bei mehreren beteiligten Börsen, sowie eine Hilfestellung, in welche Zeile der Anlage SO welcher Betrag einzutragen ist.
- Unterstützung für mehrere Börsen in einem Lauf, jede mit eigenem Namen (Voraussetzung für die Börsen-Aufteilung im PDF).
[0.2.0] - 2026-08-31
Added
- Eigenes Favicon für den Browser-Tab (mehrere Größen inkl. Apple-Touch- Icon).
Fixed
- Veraltete README-Notiz korrigiert, die noch einen fehlenden Login behauptete.
[0.1.0] - 2026-08-31
Added
- Erste Version: deterministische FIFO-Berechnung nach § 23 EStG, Buhl/WISO-kompatibler CSV-Export, Binance-Import, Weboberfläche mit Login (Double-Opt-in + manueller Freischaltung durch den Admin), PostgreSQL-Anbindung, Docker-Setup.