Changelog¶
[Unreleased / Build 746–747] — Scoped Mandate (Branch feat/scoped-mandate)¶
Grundlage fuer den Agentic-Commerce-PoC: Ein Shopping-Agent kauft nach einer SCA im Namen des Nutzers ein; die Bank haelt und prueft das Mandat (Payment-Scope), der Haendler prueft den Fach-Scope und signiert eine Attestation, der Agent hat eigene Identitaet und eigenen Key. Fachliches Brief in docs/SCOPED_MANDATE_EUDIPal.md, Implementierungsstand in docs/scoped-mandate.md.
AP1 — Typen, Fehler, Schnittstellen (Build 746)¶
Neue Schicht Sources/ScopedMandate/: Cents (Cent-Integer), ScopedMandate, PaymentScope, FunctionalScope, MandateRequest, GenericMandateTransactionData (PaSO transaction_data Typ generic_mandate), MerchantAttestation, AgentPaymentRequest, PaymentReceipt, AgentIdentityCredential. Jede Ablehnung ist ein ScopedMandateError mit rejectedBy (Bank oder Haendler) und Code. Drei Protokolle (MandateServiceProtocol, MerchantServiceProtocol, AgentIdentityProtocol), damit Phase 2 die Mocks gegen PaSO-Referenz und echtes UCP tauschen kann. 12 Tests.
AP2/AP3 — Bank- und Haendler-Mock live¶
tools/mock-bank (Flask, Firestore) als Sparkassen-Mandate-Service mit Mandats-Anfrage, Autorisierung, Zahlung, Widerruf, Aktivitaetslog und Bank-Dashboard; tools/mock-merchant mit Katalog (21 Artikel), Fach-Scope-Pruefung und ES256-signierter Attestation (Key nur im Secret Manager). Beide auf Cloud Run Frankfurt, oeffentlich unter https://bank.s-you.me und https://shop.s-you.me (globaler HTTPS-Load-Balancer, weil Domain-Mappings in europe-west3 nicht erlaubt sind; tools/setup-lb.sh). Smoke-Tests: Bank 24, Haendler 20 Checks, alle gruen gegen die Domains.
OpenAPI-Specs und digitallabor.berlin-Design¶
docs/openapi/mandate-service.yaml und merchant-service.yaml (OpenAPI 3.1, validiert): alle Endpunkte, Schemata, Fehler-Envelope, Rejection-Codes, Beispiele. Bank und Händler liefern ihre Spec unter /openapi.yaml und verweisen in der Discovery darauf; die Doku-Site rendert beide mit Redoc (/api/mandate-service, /api/merchant-service) und bietet die Roh-YAML an. Die Doku-Site traegt jetzt die Design-Tokens von digitallabor.berlin (Sparkassen-Rot, Graublau, SparkasseHead/Sparkasse-Schriften, Logo) — Logo und Schriften werden beim Deploy von digitallabor.berlin geladen und liegen nicht im Repo.
Doku-Site docs.s-you.me¶
tools/docs-site: kleiner Flask-Service, der die Markdown-Dokumente des Repos (Interface-Spezifikation, Implementierungsstand, Brief, Deployment, Changelog) beim Build zu einer Website rendert — Startseite mit den vier Parteien, Dokument-Karten, Live-Systemen und Quick-Start; Seitenleiste, Inhaltsverzeichnis, Dark Mode. Quelle bleibt das Repo, deploy.sh kopiert die Dateien in den Build. Dritter Host am bestehenden Load Balancer (poc-cert-v2 mit drei Hostnamen, altes Zertifikat bleibt parallel aktiv).
Haendler-Sicht (Mock, ohne App-Aenderung)¶
shop.s-you.me/dashboard: KPI-Kacheln, jede Warenkorb-Pruefung mit Agent, Positionen (betroffene Artikel rot), Fach-Scope des Mandats und Ergebnis (Attestation-ID bzw. Haendler-Ablehnung mit Code und Klartext), darunter der Katalog nach Warengruppen. GET /events liefert das Log als JSON; es lebt nur in der Instanz — der Haendler persistiert nichts ueber Nutzer oder Bank. Damit hat jede der drei Parteien ihren eigenen Bildschirm: Wallet (iPhone), Bank, Haendler. Smoke-Test +3 Checks.
AP7 — Einkaufs-Agent im Chat (Build 751)¶
Fuenf neue Agenten-Tools: get_scoped_mandates, request_scoped_mandate (oeffnet das Freigabe-Sheet und wartet auf die Face-ID-Entscheidung), shop_with_mandate (Einkaufsliste → Katalogsuche → Haendler-Attestation → Zahlungsauftrag mit agent_proof → Beleg mit SCT-Inst-Referenz und Rest), get_scoped_mandate_activity, revoke_scoped_mandate. Fachlogik in ScopedMandateAgent (Bank, Haendler, Identitaet, Consent injizierbar), Tool-Schicht formatiert nur. Keine Rueckfrage vor dem Kauf — die Freigabe war das Mandat; jede Ablehnung nennt Partei, Grund und betroffene Artikel. Systemprompt um den Abschnitt „Einkaufs-Agent mit Bank-Mandat" ergaenzt. Die aelteren M1/M2-Tools list_mandates/purchase_with_mandate sind fuer das LLM nicht mehr sichtbar (Code bleibt). 9 Tests mit Fake-Bank und Fake-Haendler.
AP5 — Consent-Screen und SCA fuer das Agenten-Mandat (Build 750)¶
ScopedMandateConsentCoordinator fuehrt Flow B: Mandatsanfrage an die Bank, Consent-Sheet nach dem Muster von PaSOPaymentConsentView (Agent + Anbieter, Grenzen, Haendler, Gueltigkeit, Verfahren, Fach-Scope), dann echte Geraete-Authentifizierung (Face ID / Touch ID / Code) mit dem Mandatstext als Begruendung, lokaler Hash ueber genau die angezeigten transaction_data, authorize bei der Bank. Abbruch im Face-ID-Dialog fuehrt zurueck zum Consent ohne Bank-Call. Jeder Fehler nennt die Partei. Aufhaengung ueber Notification.Name.scopedMandateConsentRequested in WalletHomeView (schliesst andere Sheets vorher), Demo-Trigger unter Einstellungen → Labor → „Agent-Mandat erteilen". 8 Tests mit Fake-Bank und Fake-SCA.
HTTP-Services gegen die Live-Server (Build 749)¶
HTTPMandateService und HTTPMerchantService implementieren die Protokolle aus AP1 gegen bank.s-you.me und shop.s-you.me. Fehlerantworten (HTTP 422) werden mit Partei und Code in ScopedMandateError abgebildet — unbekannte Codes behalten die Partei (.rejected(by:code:message:)). Client-seitige Gegenpruefungen: transaction_data_hash wird lokal nachgebildet und mit der Bank verglichen; Haendler-Attestationen werden auf Hash und ES256-Signatur gegen den Discovery-Key geprueft. MandateActivityEntry.Outcome liest jetzt das Wire-Format der Bank. 9 Wire-Tests ohne Netz (URLProtocol-Stub) plus ein zuschaltbarer Live-Test ueber Flow A–D.
Vorgaben Sparkasse eingearbeitet (Build 748)¶
Vier Punkte aus der Abstimmung vom 10.10.2026: (1) Agent und Plattformanbieter weisen sich aus — MandateRequest traegt das vollstaendige Agenten-Credential inkl. Betreiber-Registernummer, die Bank prueft Hash- und Key-Bindung (neuer Code agent_identity_invalid) und zeigt beide im Dashboard; (2) Mandat laeuft unter SPAA Dynamic Recurring Payment (scheme: spaa_drp); (3) Widerruf jederzeit durch den Kunden — bankseitig vorhanden, walletseitig in AP6; (4) Settlement als SCT Inst — Rail sct_inst ist Default, jeder Zahlungsbeleg traegt settlement mit End-to-End-ID. Bank-Smoke-Test um 5 Checks erweitert.
AP4 — Agent-Identitaet (Build 747)¶
ScopedAgentIdentity (Actor) mit eigenem Secure-Enclave-Key eudipal.scoped-agent.signer.v1 — getrennt von Wallet- und Mandats-Keys und ohne Biometrie-Pflicht, weil die eine SCA beim Mandat liegt und der Agent Zahlungsauftraege autonom signiert. agent_id wird deterministisch aus dem Public Key abgeleitet, das Credential (Mock-EBW, nur oeffentliche Daten) liegt in UserDefaults und rotiert automatisch mit dem Key. Neu: ECPublicKeyJWK (die Bank verlangt den JWK bei /mandate-requests; MandateRequest traegt ihn jetzt), agent_proof-Bildung exakt wie die Bank sie nachrechnet, SoftwareAgentKey fuer Simulator und Tests. 13 Tests.
[Unreleased / Build 745]¶
EudiWalletKit-Forks unter digitallabor-berlin¶
Die drei geforkten Wallet-Bibliotheken lagen unter github.com/maxthure und sind dort nicht mehr erreichbar (HTTP 404) — damit war das Projekt nicht mehr baubar, die SPM-Auflösung brach schon vor dem Kompilieren ab. Betroffen war eine ganze Abhängigkeitskette: eudi-lib-ios-wallet-kit → eudi-lib-ios-iso18013-data-transfer → eudi-lib-ios-iso18013-security.
Alle drei liegen jetzt unter digitallabor-berlin, mit vollständiger Historie und unveränderten Commit-Hashes (wallet-kit 1191 Commits, data-transfer 341, security 297). Die Patches #1–#10 bleiben damit einzeln nachvollziehbar, und die in EUDIWALLET_COMPLIANCE.md zitierten Commit-Hashes lösen weiterhin auf. Umgestellt wurden project.yml, die Package.resolved des Projekts sowie die Package.swift/Package.resolved innerhalb der Forks (sonst zeigt die Kette eine Ebene tiefer weiter ins Leere). Die Forks sind Apache-2.0 von eu-digital-identity-wallet; LICENSE und NOTICE sind unverändert mitübernommen.
[2.5.0 / Build 744] - 2026-08-23¶
Neues Hauptfeature: terminierte Überweisungen — von Hand und per KI-Assistent. Dazu aktualisierte KI-Modelle, eine optionale Internet-Recherche und mehrere Korrekturen.
Terminierte Überweisungen¶
Überweisungen lassen sich jetzt auf ein Datum in der Zukunft legen; die Bank führt sie dann selbstständig am gewählten Tag aus. Beim Ausfüllen einer Überweisung gibt es dazu den Schalter „Zum Termin ausführen" mit Datumsauswahl (HKCSE). Bestehende Termine werden in einer eigenen Liste geführt (HKCSB, TAN-los abrufbar, persistiert mit „Stand:"-Zeitstempel), lassen sich ändern (HKCSA) und löschen (HKCSL) — je mit einer TAN. Das Ausführungsdatum ist auf TARGET2-Bankarbeitstage begrenzt: fällt es auf Wochenende oder Feiertag, wird automatisch auf den nächsten Werktag verschoben. Der Empfängernamensabgleich (VOP) läuft in-dialog; bei Abweichung wird um Bestätigung gebeten. Nebenbei behoben: ein Endlos-Spinner, wenn direkt nach dem Anlegen gelöscht wurde (die Abschluss-Kette des ersten Vorgangs kaperte den zweiten).
KI-Assistent bedient terminierte Überweisungen¶
Der KI-Assistent kann terminierte Überweisungen jetzt per natürlicher Sprache anlegen, auflisten, ändern und löschen — vier neue Werkzeuge (propose_scheduled_transfer, list_scheduled_transfers, propose_change_scheduled_transfer, propose_delete_scheduled_transfer). Wie bei jeder Überweisung führt der Agent nichts selbst aus: er legt eine Bestätigungskarte vor, TAN und VOP passieren im Formular. Ein Wunschdatum auf Wochenende/Feiertag wird auf den nächsten Bankarbeitstag verschoben und im Chat angesagt.
Aktuelle KI-Modelle¶
Die Modell-Auswahl war veraltet. Claude: neues Top-Modell Opus 4.8 (statt 4.7). Gemini: auf die 3er-Generation umgestellt — 3.7 Flash, 3.5 Flash-Lite, 3.1 Pro — die 2.5-Modelle werden von Google abgekündigt und sind entfernt. Eine gespeicherte, nicht mehr verfügbare Auswahl wird automatisch auf ein aktuelles Modell zurückgesetzt.
Internet-Recherche (neue Laborfunktion, Default aus)¶
Unter Einstellungen → Labor → KI-Assistent lässt sich „Internet-Recherche" einschalten. Dann darf der Assistent bei Bedarf im Netz nachschlagen — anbieter-nativ (Claude web_search, Gemini Google-Search-Grounding inkl. toolConfig.includeServerSideToolInvocations). Ausgeschaltet antwortet er nur aus Kontodaten und seinem Wissensstand.
Bank-PINs gehen beim Update nicht mehr verloren¶
Ein Update von einer alten Version (≤ 2.3.x) wurde fälschlich als Neuinstallation erkannt und löschte gespeicherte Bank-PINs, während die Bankverbindungen überlebten — Folge: Verbindung da, Konten leer, Aktualisierung brach still ab. Bestandsinstallationen werden jetzt zuverlässig erkannt (kein Wipe), und betroffene Verbindungen zeigen eine Reparatur-UI mit Warnhinweis und direktem Weg zum Nachtragen der PIN.
Feinschliff im KI-Chat¶
Bei einer Überweisung erscheinen keine überflüssigen „Als CSV exportieren"-Karten mehr daneben (höchstens eine pro Turn, und keine bei Aktionskarten) — die Überweisungskarte bleibt sichtbar. Der Assistent legt Terminüberweisungen direkt an, statt an die App zu verweisen, und sucht nicht mehr wiederholt in den Transaktionen, um Empfänger oder Betrag zu finden.
[2.4.2 / Build 700] - 2026-08-08¶
Tester-Zugang auch in den Einstellungen¶
KIAgent! wirkte bisher nur im Onboarding. Wer die KI dort übersprungen und
später über Einstellungen → KI-Assistent → API-Schlüssel nachgeholt hat,
landete in einer zweiten, eigenen Schlüssel-Maske (AIKeySetupSheet), die vom
Codewort nichts wusste — die Eingabe ging als echter Schlüssel an den Anbieter
und kam als „ungültig" zurück. Beide Masken verhalten sich jetzt gleich: grüner
Hinweis, sobald das Codewort erkannt ist, Einsetzen des hinterlegten Schlüssels
erst beim Speichern, danach dieselbe Prüfung gegen den Anbieter.
[2.4.2 / Build 698] - 2026-08-07¶
Fehlerbehebung nach dem Test von 2.4.1, plus eine Tester-Meldung vom Gerät.
Tastatur in der Bankeinrichtung¶
Vier Anläufe, weil dreimal am Symptom gearbeitet wurde. Die Ursache: die beiden
Eingabefelder lebten in verschiedenen Welten — der Anmeldename als
SwiftUI-TextField mit @FocusState, die PIN als UIKit-UITextField
(NoAutoFillSecureField, gebaut um Apples „Passwort speichern?"-Dialog zu
unterdrücken). Beim Verlassen des Screens musste man beide Welten treffen; wer
eine verfehlte, ließ die Tastatur stehen. Verschwindet ein
UIViewRepresentable, während sein Feld First Responder ist, hängt die Tastatur
danach an einem Responder, den es nicht mehr gibt — dann bekommt sie weder
„Fertig" noch die Rückgabetaste noch endEditing(true) über alle Fenster weg.
Beide Felder sind jetzt UIKit-Felder: eine Responder-Kette statt zweier
Mechanismen, und dismantleUIView gibt den Fokus ab, bevor das Feld
verschwindet. saveConnection räumt selbst auf statt nur der Knopf. Der
0,3-Sekunden-Timer für den Auto-Fokus nach der Bankauswahl entfällt.
Nebeneffekt, ausdrücklich gewünscht: kein AutoFill-Vorschlagsband mehr. iOS bot gespeicherte Zugangsdaten allein deshalb an, weil ein Textfeld neben einem Passwortfeld stand.
Absturz beim Wechsel zur Sprachsteuerung¶
Gemeldet zu 2.4.1 (686) auf iPhone 17 Pro / iOS 26.6: mehrfaches Hin- und Herschalten zwischen App-Mikrofon und nativer Sprachsteuerung beendet die App. Drei Ursachen im selben Muster — ein fehlgeschlagener Start hinterlässt Reste, der nächste Versuch fällt darüber:
- Der Tap auf dem Mikrofon-Bus wurde vor dem Installieren nie entfernt. Nach
einem gescheiterten Start wirft der nächste
installTapeine Ausnahme aus dem Audio-Framework, die sich in Swift nicht abfangen lässt. Daher „manchmal muss man es mehrfach machen". - Hält die Sprachsteuerung das Mikrofon, liefert der Eingang ein leeres Format
(0 Hz, 0 Kanäle) —
installTapprüft das nicht und beendet den Prozess. - Scheiterte der Engine-Start, blieb der eben gesetzte Tap liegen.
Neu: Reaktion auf AVAudioSession.interruptionNotification — genau das
passiert, wenn die Sprachsteuerung übernimmt — und auf einen
Media-Server-Reset. Nicht auf Gerät verifiziert, der Konflikt lässt sich im
Simulator nicht herstellen.
App-Sperre nennt das echte Verfahren¶
Der Hinweis zählte fest „Face ID, Touch ID oder Gerätecode" auf. DeviceBiometry
fragt jetzt LAContext — die Verfahren hängen am Modell, nicht an der
Geräteklasse (iPhone SE: Touch ID, iPad Pro: Face ID). Dabei drei Kopien
derselben Abfrage eingesammelt.
Tester-Zugang zur KI¶
KIAgent! im Schlüssel-Feld schaltet einen hinterlegten Zugang für den
gewählten Anbieter frei — gedacht für Tester, die sich keinen eigenen
API-Schlüssel besorgen wollen. Der Schlüssel erscheint nicht im Feld, sondern
tritt erst beim Speichern an die Stelle des Codeworts; geprüft und gespeichert
wird er wie jeder selbst eingetragene.
Die Schlüssel liegen XOR-verschleiert im Binary. Das ist ein Bremsklotz gegen
strings, kein Schutz — verlässlich wäre nur ein Proxy, der den Schlüssel
serverseitig hält. Auf die Anbieter-Konten gehört ein Ausgabenlimit.
tools/xor_pad.py erzeugt die Blöcke beim Tausch, ohne dass ein Schlüssel über
die Kommandozeile läuft.
Tests¶
Tests/InMemoryDefaults ersetzt die Wegwerf-UserDefaults-Suiten der
Testklassen; über 240 Preference-Domains hatten sich im Simulator angesammelt.
Behebt eine bekannte Flakiness nicht vollständig: ein voller Unit-Lauf hängt
weiterhin gelegentlich in ToolRegistryTests mit einem Timeout, nie mit einem
inhaltlichen Fehler. Betrifft die App nicht.
Unit 358/358 grün, Simulator-Build erfolgreich.
[2.4.1 / Build 686] - 2026-08-05¶
Nachtrag zu 2.4.0, vom Maintainer auf dem Gerät getestet.
Suche versteht Umlaut-Umschreibungen¶
„Muenchen" fand „München" nicht und umgekehrt — Banksuche und Umsatzsuche
verglichen roh über lowercased(). Beide laufen jetzt über eine gemeinsame
Vergleichsform (String.germanSearchFolded), in der Umlaute ausgeschrieben
werden. Der naheliegende Weg ü → u hätte nichts gebracht: „München" wird dann
munchen, „Muenchen" aber muenchen. Danach fallen die übrigen Diakritika weg,
damit „Credit" auch „Crédit" trifft. Gilt für Institutsnamen (FinTSInstitutes)
sowie Empfänger, Verwendungszweck und Buchungstext (TransactionFilter).
KI-Setup-Screen¶
Der Screen hatte keine ScrollView: der Inhalt passte nicht aufs iPhone, der Demo-Link fiel aus dem Bild und „Ohne KI-Chat fortfahren" klebte am unteren Rand. Jetzt Scroll-Inhalt mit angesetzter Bedienleiste. „Claude einrichten" war zudem der einzige Knopf in der Akzentfarbe und las sich damit als Empfehlung — beide Anbieter sind jetzt gleichwertig. Die Hinweisbox ist nicht mehr vollflächig rot.
App-Sperre am Ende der Einrichtung¶
Der Dialog erschien 1,4 Sekunden nach der Bankverifikation, also während das contentView-Gate noch Screens wechselte — wird die präsentierende View unter einem Alert ausgetauscht, baut UIKit ihn erneut auf, und der Dialog blitzte nach der Auswahl ein zweites Mal auf. Er kommt jetzt am Ende des Onboardings, wo der Bildschirm stillsteht und der Nutzer nicht nebenbei über eine zweite Sache entscheidet.
Metadaten¶
- Unit-Tests 354 (fünf neue für die Suchform), UI-Suite unverändert grün.
- Build 686 ist inhaltlich identisch mit dem getesteten 685 — geändert haben sich nur die Versionszeichenketten.
[2.4.0 / Build 684] - 2026-08-05¶
53 Commits seit 2.3.1 (Build 614). Schwerpunkt: ein Onboarding, das durchgehend funktioniert, ein belastbarer Überweisungs-Pfad und eine Testsuite, die wieder etwas aussagt.
Onboarding¶
- Konten auswählen und umbenennen direkt im Erfolgsscreen der Bankeinrichtung
(
OnboardingBankSuccessView): Schalter pro Konto, „Umbenennen" in fester Spalte, zweizeilige Kontozeile mit vollständiger IBAN. - Nur noch eine TAN-Freigabe und ein Kontoabruf beim Einrichten. Die Verifikation holte bereits Umsätze, danach entschied die Phase-2-Logik anhand von „gab es vorher Daten" erneut auf denselben Abruf.
- Nachweis nur einmal annehmen: der grüne Stempel klebte auf jedem Zustand
außer
.failed, also schon über dem „Annehmen"-Knopf; dazu kam ein „Fertig"-Knopf, obwohl direkt danach der Abschluss-Screen dieselbe Erfolgs- meldung zeigt. Im Onboarding übergibt der Screen jetzt selbst. DerCredentialOfferCoordinatorverwirft außerdem die doppelte Zustellung desselben Angebots — es erreicht die App über Notification, gepuffertependingWalletURL, QR und NFC gleichzeitig. - Kein Ladescreen und kein KI-Aufblitzen bei der Ersteinrichtung, angesetzte Bedienleisten statt schwebender Kapseln, Konten-Screen auch für später ergänzte Banken.
- Neuinstallation zeigt wieder das Onboarding; die Zahlungs-Option am Abschluss ist entfernt (sie öffnete nur den Kamera-Scanner).
Wallet¶
- Neue Karten und Nachweise liegen unten im Stapel — also vorn beim Nutzer.
Die Reihenfolge entscheidet jetzt die Aktualität (
BankConnection.createdAtneu, Credentials überissuedAt) statt der Kategorie; Platzhalter dahinter. Selbst sortierte Reihenfolge behält Vorrang. - Mandats-Layer M0–M2 (Pfad B): Standing-Mandate und Chat-Kauf im Demo-Modus.
- Kurzer Tap öffnet die Karte zuverlässig.
Banking und Überweisungen¶
- Keine false-positive Erfolgsmeldung mehr bei Überweisungen; Bank-Ablehnung im Polling wird sauber als Fehlschlag behandelt.
- FinTS-Sessions: frischer Connect vor jedem Transfer, Cross-Bank-Schutz ohne
system_id-Reset,_sca_just_completedüberlebt Connect-Cycles, kein Endlos-Loop beineeds_reconnectmit leeremtan_medium, BPD-Heuristik löscht keinen Device-Trust mehr, verständliche Meldung bei BPD-Fehlschlag. - Die Zustandsdatei überlebte das Löschen einer Bankverbindung — behoben.
- Kaltstart zeigt keine leeren Karten und braucht nur eine TAN.
- Umsatzsuche versteht ganze Sätze, offline; keine falschen Treffer bei mehrteiligen Namen, Vormerkungen gefiltert, Cache-Treffer auf den angefragten Zeitraum beschnitten.
- Einmalig ein Jahr Umsatzhistorie nach der Einrichtung.
- Cashback und Erstattungen gelten nicht mehr als Einkommen.
Lokal und KI¶
- Beleg-OCR überarbeitet: VisionKit, EPC-/BezahlCode-QR, Multi-Kandidaten, Review-Dialog.
- Labor-Setting „Strikte Anmeldung" mit deterministischen zwei TANs.
Datenschutz¶
- App löschen löscht jetzt alle Daten. Der Keychain-Spiegel der
Bankverbindungen lag als
kSecAttrSynchronizableim iCloud-Schlüsselbund und überlebte sogar einen Gerätewechsel.
Tests und Doku¶
- Unit-Suite wieder grün (349 Tests), UI-Suite von 13 Fehlschlägen auf 0 bei
gleichzeitig vier Tests weniger im Skip. Die Fehlschläge waren Folgeschäden
der Wallet-Umstellung: die Banking-
MainTabViewist kein Home-Screen mehr, elf Tests warteten trotzdem auf ihre Tab-Bar. AIWalletButtonhat einaccessibilityLabel(„KI-Assistent") — VoiceOver las vorher den SF-Symbol-Namen vor.docs/wallet.mdbehauptete, ein Settings-Toggle wechsle zwischen Wallet und Banking; CLAUDE.md stand auf Build 615.
Offen¶
- Die Auswertung ist auf dem iPhone nicht erreichbar:
AppFeatures.financeAnalysisist aus, und der einzige Knopf sitzt in der iPad-Toolbar. - Die Backend-UI-Tests der Issuance skippen ohne
SUPER_ADMIN_KEY.
[2.1.0 / Build 401] - 2026-05-07¶
End-to-End-Demo-Stack live: Issuer und Test-Merchant unter eudipay.me. Neben dem realen FinTS-Banking lässt sich EUDIPal jetzt komplett als Wallet erleben — Credential ausstellen, vorzeigen, bezahlen.
Demo-Endpunkte¶
- Issuer:
https://sparkasse-demo.digitallabor.dev— stellt Wero SCA Credential (Payment-Authorisation, PaSO-konform), Alter-Credential (Age Verification) und Account-Login-Credential aus. - Test-Merchant:
https://merchant-demo.digitallabor.dev— akzeptiert Wero SCA für Zahlung, Alter-Credential für Age-Verification beim Checkout, Account-Login-Credential für den Login-Flow. - Issuance via OpenID4VCI Credential-Offer (QR oder Deep-Link), Presentation via OpenID4VP/PaSO. Ein durchgängiger Flow: Issuer öffnen → Credential in EUDIPal ziehen → beim Merchant in derselben Wallet einsetzen.
PaSO/SCA-Korrektheit (Build 401)¶
- EudiWalletKit-Fork-Patch #7 (
ff06624):sendResponse-Overloads sind jetzt Protocol-Requirements statt Extension-Defaults. Vorher hat Swift Static-Dispatch überany PresentationServiceadditionalKBJWTClaimsstillschweigend verworfen —jti,amr,request_integrity,wallet_instance_versionlandeten nie im KB-JWT, der Backend-SCA-Check schlug fehl. Mit dem Fix laufen die SCA-Claims via Witness-Table-Dispatch sauber insOpenId4VpServiceund in jedes produzierte KB-JWT. transaction_data_hash: Encoding von W3C-SRI (sha256-<base64>) auf plain base64url umgestellt — entspricht PaSO Core §6.1 und ist konsistent mit demtransaction_data_hashes-Array, das EudiWalletKit selbst erzeugt.request_integritybleibt korrekt SRI.request_uriJAR-Resolution (RFC 9101): EUDIPal lädt den JAR jetzt selbst und reicht inline an EudiWalletKit weiter — verhindert dass nonce-bound JARs ein zweites Mal gefetcht und damit invalidiert werden.response_modewird aus dem JAR extrahiert und propagiert (vorher hartkodiertdirect_post).PaSOPaymentPayload-Decoder akzeptiert beide Wire-Formate: spec-konformes"100.00 EUR"(combined String) und EUDIPLO-Variante mit getrenntenamount/currency-Feldern.
UX¶
- Credential-Auswahl als Carousel: Bei mehreren Credential-Instanzen desselben Typs wird in
VPConsentViewundPaSOPaymentConsentViewjetzt ein swipebarerTabView(.page)mitCardFaceView-Karten und Liquid-Glass-Page-Indicator-Pille angezeigt — vorher.menu-Picker. Bei Single-Cred-Gruppen unverändert. - Genau ein Face-ID-Prompt pro Zahlung: Der explizite
LAContext.evaluatePolicy-Aufruf vor dem Submit ist raus — der eigeneEudiWallet.authorizedAction-Gate insession.sendResponsemacht den biometrischen Check sowieso. AMR wird auscanEvaluatePolicyohne Trigger inferiert. - Optionale Doc-Type-Toggles wirken jetzt wirklich:
OID4VPCoordinator.userAcceptedPaymentreicht die Nutzer-Auswahl (selectedDocElements) durch — vorher fixcontext.requestedDocuments, was die Toggles in der Consent-View neutralisiert hätte. - DCQL-Lookup für SCA-Credential:
scaDocTypeOrVcts(from:credentialIds:)extrahiert die VCT/docType-Strings aus der DCQL-Query statt blind das erste Document zu nehmen.
Doku¶
EUDIWALLET_COMPLIANCE.mdumnummeriert (Patch 7 als Swift-Dispatch-Fix neu eingeschoben, alte 7→8, 8→9). Vollständige Spec-Begründung pro Patch.AI_AGENT_PLAN.mdals Roadmap-Notizzettel für den nächsten Track (Tool-basierter KI-Agent, noch nicht implementiert).project.pbxprojMerge-Artefakt aufgeräumt (zweiCURRENT_PROJECT_VERSION-Zeilen → eine).
Metadaten¶
- Build 401, Marketing 2.1.0. EudiWalletKit zeigt auf Fork-Revision
ff06624. - Tag
v2.1.0-build401gesetzt.
[2.1.0] - 2026-05-06¶
EUDIPal 2.x: vollwertige EUDI-Wallet (PID/mDL/EAA, OID4VCI/OID4VP/PaSO) mit iOS-26-Liquid-Glass-UI. Banking-Funktionen bleiben parallel verfügbar. Merge des Branches ui/ollis-opinion (Build 394, 66 Commits, ~9400 Zeilen, 121 Dateien) nach main via PR #11.
EUDI-Wallet-Funktionsschicht¶
- OpenID4VCI-Issuance:
OID4VCIServiceführt den Authorization-Code-Flow durch und persistiert ausgestellte Credentials. NeuePIDCredentialDetailViewmit Claim-Anzeige (Vorder- und Rückseite). Bundesdruckerei-PID-Anbindung (eID + AusweisApp + NFC) ist infrastrukturell vorbereitet (PIDIssuerRegistry, Custom-URL-Scheme-Trigger), die produktive Issuance steht noch aus — produktiver Issuance-Flow viaeudipay.mesiehe Build 401. - OpenID4VP-Presentation: QR-Scan (
QRScannerView) und Deep-Link (openid4vp://,mdoc-openid4vp://) öffnenVPConsentViewmit per-Attribut-Toggles. Auth-Response signiert mit Device-Key aus Secure Enclave. - mDL (Mobiler Führerschein, ISO 18013-5) und EAA (Electronic Attestation of Attributes) als eigene Card-Typen mit
MDLCredentialDetailView/EAACredentialDetailView. - PaSO-Konformität (Payment Service Over Identity):
PaSOServiceparst Transaction-Data im VP-Request,PaSOConsentViewzeigt Betrag/Empfänger/Zweck vor SCA-Freigabe. KB-JWT-Injection viaadditionalKBJWTClaimsaus dem EudiWalletKit-Fork. - Statium-Status-Prüfung:
StatiumStatusCheckerprüft pro Credential den Widerrufsstatus, Badge auf der Karte. - EudiWalletKit-Fork auf GitHub-URL umgestellt (
https://github.com/maxthure/eudi-lib-ios-wallet-kit.git, branchmain) — kein lokaler Pfad mehr nötig. Patches #1–#10 im Fork gepinnt: x5c, PaSO KB-JWT-Erweiterung, Patch #10optionalDocTypeOrVcts(für Bundesdruckerei-Kompatibilität).
iOS 26 Liquid Glass UI-Redesign¶
- Kartenstapel (
CardStackView): Apple-Wallet-Style mit Drag-Reorder, Karten-Flip mit echter Rückseite (sichtbare Claims), Hero-Animation viamatchedGeometryEffect. - Ambient-Background: passt sich der Farbe der obersten Karte an.
- Glass-Effekt durchgängig:
.glassEffect-APIs aus iOS-26-SDK in Sheets, Toolbars, Buttons, Segmented Controls — sowohl in Wallet- als auch in Banking-Views. - Liquid-Glass-AppIcon: SVG-basiert, pro Theme eigenes Icon.
- MissionView: Onboarding-Screen mit Mission, Roadmap, Banking-Toggle (Build 304 vom Banking-Track integriert).
KI-Assistent ausgebaut¶
- AIWalletButton: Haupteinstieg in den KI-Chat statt versteckter Tab.
- ChatOverlayView: Chat als Overlay über dem Kartenstapel — Wallet bleibt sichtbar.
- Google Cloud TTS (
GoogleCloudTTSService) als Alternative zuAVSpeechSynthesizerfür natürlichere Sprachausgabe. - KI-Einstellungen als eigene Settings-Section: Provider, API-Keys, TTS-Modus.
Infrastruktur¶
BPComponents.swiftals zentrales Design-System (Buttons, Cards, Sheets im Liquid-Glass-Look).LocalPackages/SwiftCopyableMacro: lokaler Stub mit swift-syntax 600.x — ersetztSwiftCopyableMacro 0.0.4(remote), das swift-syntax 509.x erfordert und damit Swift-6-incompatibel ist. Implementiert@Copyableals No-Op.testbed/: isolierte Python-Backend-Tests, unabhängig von Xcode-Build.EUDIWALLET_COMPLIANCE.md: normative Doku aller Fork-Patches im EudiWalletKit-Fork.
Aus dem Banking-Track v1.13.x übernommen (im Merge erhalten)¶
- Multi-Bank-Tab-Strip (Build 314): horizontale Bank-Leiste mit Logos in der klassischen Banking-Sicht.
- ING/DKB-Brand-Cards (Build 310): bank-spezifische Card-Brandings mit BLZ-basierter Detection (
BankBrand.detect). - Gemini-Prompt-Kappung (Build 315): Provider-aware Detail-Month-Threshold (30k Gemini / 100k Claude), Hard-Cap bei 60k Zeichen für Gemini — verhindert HTTP-5xx bei echten Konten mit großem Kontext.
- ING-DiBa-Crash-Fix (Build 287): defensive PythonKit-Subscripts in
iOSPythonBridge. - Vorgemerkte Umsätze (v1.13.0/v1.13.1): MT942-basiert, persistent, mit DKB-Pending-Pipeline.
- Demo-Modus mit drei Banken (v1.10.1) inkl. 2-Step-Chained-Transfer-Demo.
Anforderungen nach Merge¶
- Xcode 26 beta für iOS-26-SDK und
.glassEffect-APIs. - iOS 26 Deployment-Target (
IPHONEOS_DEPLOYMENT_TARGET: "26.0"inproject.yml). - Bundle-IDs unverändert (
de.digitallabor.eudipal.app).
Doku & Repo¶
CLAUDE.mdauf 2.1.0/Build 394 aktualisiert: Wallet-Funktionsschicht (Issuance/Presentation/PaSO), Liquid-Glass-UI, KI-Erweiterungen, EudiWalletKit-Fork-Hinweis.claude-memory/MEMORY.mdsynchronisiert.TestFlight/WhatToTest.de-DE.txtfür Build 394 neu geschrieben.- Tag
v2.1.0-build394gesetzt.
[2.0.0] - 2026-05-02¶
EUDIPal-Pivot: erste TestFlight-fähige Version unter neuem Branding und neuem Bundle-ID-Schema.
Rebranding & Identifier¶
- App heißt jetzt EUDIPal —
CFBundleDisplayName/CFBundleNameumgestellt, alle nutzersichtbaren Stellen ("BankingPal" → "EUDIPal") in DisclaimerView, SetupView, AccountListView, MainTabView, WidgetViews, WalletHomeView. Schreibweise einheitlichEUDIPal(nichtEUDIPAL/EudiPal/eudipal). - Bundle-ID-Migration auf
de.digitallabor.eudipal.*: App, Widget, Tests, App-Groupgroup.de.digitallabor.eudipal.app, Keychain-Access-Groupde.digitallabor.eudipal.shared, iCloud-KVStore-Identifier, URL-Schemesbankingpalpocketundeudi-openid4ci.de.eudipal.appwar global durch ein fremdes Apple-Team belegt — daher derdigitallabor-Subdomain-Fix. - Apple Developer Team auf
2KVB827EJR(DSGV) fest inproject.ymlverankert (App, Tests, Widget) — vorher2T96J9RV7Paus dem ursprünglichen BankingPal-Setup, das auf der DSGV-Entwicklungs-Hardware nicht eingeloggt war und dadurch beim Build verschwand. - Interne Identifier bewusst nicht umgestellt (an User-Daten gebunden, Renames würden gespeicherte PINs/Caches invalidieren): BGTask
de.bankingpal.pocket.refresh, Keychain-Servicede.bankingpal.pocket, Cache-Key-Servicede.bankingpal.pocket.cachekey, DispatchQueue-Labels, Class-NameBankingPalApp.
EUDI-Wallet-Schicht (Phase 0)¶
- Neue Schicht unter
BankingPal-Pocket/Sources/Wallet/: Credentials/ (CredentialRecord, CredentialStore, SecureEnclaveKeys), Issuance/ (OID4VCIService, PIDIssuerRegistry), Models/ (BankCard, WalletCard, PlaceholderCards), Services/ (EudiWalletBootstrap, URLRewritingNetworking, WalletCardProvider), Views/ (CardFaceView, CardStackView, CardDetailView, CardAddSheet, BankAccountsPane, WalletPlaceholderDetailView), plusWalletHomeView,WalletFeatureFlags,WalletMigration. - Feature-Flags (alle default
false):walletUIEnabled(Wallet-UI statt Banking-UI),walletMockPID(Demo-PID für Phase 1),walletEnableBLE(Phase 4 ISO 18013-5),walletTs12InTransfer(Phase 5 TS12 in TransferView). - OpenID4VCI-Metadata-Fetch (
.well-known/openid-credential-issuer) inOID4VCIServiceist drin (Phase 2b). Echter Issuance-Flow folgt in Phase 2c. - Apple-Wallet-Style Kartenstapel (
WalletHomeView/CardStackView/CardFaceView): iPhone-Hero-Animation viamatchedGeometryEffect, iPad als NavigationSplitView. 5 Kartentypen (.bank/.payment/.loginCredential/.pid/.mDL/.eaa) mit eigenen Farbpaletten. - EudiWalletKit-Integration:
EudiWalletBootstrap.sharedinitialisiert die Wallet-Instanz mit eigenem Keychain-Service (de.digitallabor.eudipal.app.wallet), getrennt vom Banking-Keychain.
TestFlight-Vorbereitungen¶
PrivacyInfo.xcprivacyfür App und Widget angelegt:NSPrivacyTracking=false, keine Tracking-Domains, keine Datensammlung. Required-Reason-APIs deklariert:UserDefaults(CA92.1),File Timestamp(C617.1),System Boot Time(35F9.1),Disk Space(E174.1). Widget reduziert auf UserDefaults + File Timestamp.ITSAppUsesNonExemptEncryption=falsein beiden Info.plists. Eure App nutzt nur Standard-iOS-Crypto (HTTPS, Keychain, CryptoKit AES-GCM, FinTS-TLS) — gilt als US-Export-exempt. Spart bei jedem Upload den Compliance-Dialog.
UX¶
- Wallet-Toggle reaktiv:
BankingPalApplasWalletFeatureFlags.walletUIEnableddirekt aus UserDefaults — nicht reaktiv, SwiftUI re-renderte nicht beim Toggle. Jetzt@AppStorage-Property in der App-Struct, der ViewBuilder beobachtet sie. Switch zwischen Banking und Wallet wirkt sofort, ohne Neustart. - App-Icon konsolidiert:
AppLogo.imageset,AppLogoRed.imagesetundAlternateIcons/icon_red_*.png(alle 13 Größen) zeigen jetzt das aktuelle EUDIPal-Icon (rotes Quadrat mit Sparkassen-S + EU-Wallet) — MD5-identisch mitAppIcon.appiconset. Damit ist überall ein einziges Icon-Bild zu sehen, egal welches Theme oder Alternate-Icon aktiv ist. BrandLogozeigt das echte App-Icon: Vorher zeigte das Imageset nochicon_800px.png(altes BankingPal-Logo). Jetzt 1x/2x/3x aus dem AppIcon-Set, scharfe Anzeige in jedem Header.- Header einheitlich: AppIcon + Schriftzug "EUDIPal", ohne zusätzliche Markenelemente — in
AccountListView,MainTabView,WalletHomeView.WalletHomeView-Header umgestellt von programmatischemSparkasseSLogoaufBrandLogo. - Sparkassen-Logo (
SparkasseLogo.imageset, offizielles Asset aus Wikimedia, intern irrelevant da DSGV-Marke) bleibt nur noch auf der Wallet-.bank-Karte (CardFaceView) als Card-Branding sichtbar.
Doku & Repo¶
CLAUDE.mdauf 2.0.0/Build 301 aktualisiert: neuer Header, Identifier-Tabelle, Wallet-Schicht-Sektion, Privacy-Compliance-Hinweise, Wallet-Verzeichnisstruktur ergänzt.claude-memory/MEMORY.mdsynchronisiert mit aktuellem Stand.- Frank-Weigands Xcode-User-Daten (
xcuserdata/frank.xcuserdatad/) aus dem Repo entfernt — gehörte nie ins Versionsmanagement.
[1.13.1] - 2026-05-02¶
Bugfixes¶
- Vorgemerkte Umsätze überleben jetzt App-Neustart:
AccountBalance.pendingTransactionsist jetzt Teil der Codable-Persistenz (CodingKeypending_transactions), wird mit dem Balance-Cache gespeichert und beim App-Start inpendingByAccountzurückgespielt. Vorher waren die Pending-Posten nach jedem Kaltstart bis zum nächsten vollen Refresh unsichtbar. - DKB-Pending-Pipeline:
fetchTransactions(Pull-to-Refresh in der Detail-View, Time-Range-Expansion) speist jetzt ebenfalls den Pending-Bucket. Vorher war Pending nur viaget_balancePhase 2 verdrahtet — bei DKB wird Phase 2 aber typischerweise wegen stabilem Saldo übersprungen, sodass die "Vorgemerkt"-Section dort nie erschien obwohl FinTS die Daten lieferte. Neuebridge.onPendingTransactionsComplete-Callback-Pipeline parallel zuonTransactionsComplete; AppState mirrort die Pending inbankBalancesund triggertsaveBankBalancesCache(). Resultat: Acht "anstehende" Posten bei DKB (Echtzeitüberweisungen + Kartenzahlung Groupon) erscheinen jetzt nach Pull-to-Refresh im Konto-Detail. - Echtzeit-Toggle bei ING-DiBa führt nicht mehr zu "No supported HIIPZS version found"-Crash: Backend ermittelt jetzt per
_bank_supports_instant_payment(client)ob die BankHIIPZSin der BPD hat und schreibtsupports_instant_paymentins account_info. TransferView's Echtzeit-Toggle ist.disabled(!account.supportsInstantPayment), Footer-Text wechselt zu "Echtzeitüberweisungen werden von dieser Bank über FinTS nicht angeboten."onAppear-Sicherheitsnetz setzt das Flag aktiv auf false falls's irgendwie auf true stand. - ING-DiBa-Konten: Transfer-Feature wird komplett ausgeblendet wenn die Bank kein 2-Schritt-TAN-Verfahren liefert: Neuer Modul-Globaler
_writes_disabledwird in_create_clientgesetzt wenn nach Self-Heal (siehe unten) immer nochselected_security_function='999'ist und keine alternative Mechanism in der BPD verfügbar. account_info enthält dannwrites_disabled: True, AccountBalance.canTransfer/supportsUebertrag/supportsInstantPayment retournieren false, und AccountDetailView versteckt sowohl Transfer-Button als auch den "keine Überweisungen möglich"-Hinweis. Konto wirkt dann wie reine Lese-Verbindung.
Verbesserungen¶
- Self-Heal für 1-Schritt-TAN-States:
_create_clientprüft nach Cache-Load obselected_security_function='999'ist (Bootstrap konnte keine TAN-Mechanism wählen, Bank antwortet auf HKCCS dann mit "Erforderliche TAN fehlt"). Falls ja:system_idzurücksetzen undfetch_tan_mechanisms()erzwingen — triggert HKSYN+frische BPD. Bei Banken die HITANS dann liefern (z.B. wenn das Sicherheitsverfahren später aktiviert wurde) wird automatisch eine pushTAN-Mechanism gewählt und persistiert. Bei ING-DiBa konkret bringt das nichts (Bank liefert auch im Refetch nichts), aber der Mechanismus schützt zukünftige Nutzer mit ähnlich kaputtem Cached-State an anderen Banken. - Favoriten-Label auf eigener Zeile: In TransferView (Standard-Empfänger + Chained-Transfer-Empfänger) und SavedRecipientsView (Einstellungen) wird der vom User vergebene Label-Name jetzt immer auf einer eigenen Zeile zwischen Empfängername und IBAN-Endung angezeigt — statt inline mit "·"/"–"-Trenner und teils nur bei Namens-Duplikaten. Konsistente Optik in allen drei Listen.
- Diagnose-Logging für TAN-Mechanism-Probleme:
📋 connect-self-heal: …-Zeilen im BankingLog zeigen pro Connect densec_func-Wert, die verfügbaren Mechanisms und das Ergebnis des Self-Heal-Versuchs (inkl. dump der BPD-Segmente vor und nach Refetch).📋 Transfer-Diag pre: …direkt vor jedemsimple_sepa_transferzeigt sec_func, tan_medium und HIPINS1-Inhalt. Macht zukünftige TAN-Probleme schnell diagnostizierbar.
Wartung¶
- Erweitertes Diff-Logging in CLAUDE.md zu Pending-Pipeline (Phase 2 vs fetchTransactions), camt-Parser-Patches, Transfer-Resilienz, Echtzeit-Gating, Self-Heal/writes_disabled.
[1.13.0] - 2026-05-02¶
Neue Features¶
- Vorgemerkte Umsätze (Sparkassen): Neue Section "Vorgemerkt" in
AccountDetailView, zwischen Zeitraumfilter und gebuchten Umsätzen. Zeigt anstehende Lastschriften, Daueraufträge und Kartenzahlungen die noch nicht endgültig gebucht sind — kursiv und sekundärfarbig dargestellt um sie klar von gebuchten Posten abzugrenzen, mit Header (Anzahl + Summe) und Footer-Hinweis. KSK Köln liefert sauber 12 Pending-Posten via MT942 (HKKAZmitinclude_pending=True); andere Sparkassen typischerweise auch wenn sie welche haben. DKB sendet einen leeren camt-PDNG-Stream — anstehende Eingangsbuchungen sind dort über FinTS technisch nicht abrufbar (bankseitige Entscheidung), unabhängig vom Format. - Backend (
fints_backend_ios.py): Neuer Helper_extract_pending_transactions()macht eine zweiteclient.get_transactions(include_pending=True)-Anfrage im stehenden Dialog (kein extra TAN), diff't sie gegen die booked-only-Liste über eine (date, amount, applicant, purpose)-Signatur, gibt Pending mitis_pending=Truezurück. Resultat landet inaccount_info["pending_transactions"](Phase 2 vonget_balance) bzw.result["pending_transactions"](inget_transactions). Diagnostics-Liste mit📋 Pending-Zeilen kommt parallel im Result-Dict zurück; die Bridge zieht sie raus und schreibt sie zeilenweise ins BankingLog (Python-stderr ist in Pocket nicht abgefangen). Bei NeedTANResponse für die Pending-Probe wird_pending_tan_responseaktiv zurückgesetzt damit der Client clean bleibt. - Models:
TransactionInfo.is_pending: Bool?(Optional viadecodeIfPresentfür Cache-Kompat) plus computedisPending.AccountBalance.pendingTransactions: [TransactionInfo]?als transientes Feld — expliziteCodingKeysschließen es aus Encoding/Decoding aus, persistiert nicht im Disk-Cache. - AppState: Neuer
@Published pendingByAccount: [String: [TransactionInfo]]-Bucket (in-memory only). Phase-2-Handler ersetzt pro Konto die Pending-Liste ausaccount.pendingTransactions. Wird inclearData/loadDemoData/deleteAllDatamit-geleert.
Bugfixes¶
- DKB-Überweisung schlug fehl mit "did not contain a response": Drei Lecks in der Fehlerbehandlung gefixt:
- Python
execute_transfer+continue_vop: Fingen nurFinTSClientErrorab und setzten dort_clear_client_state()+needs_reconnect: True.FinTSDialogErrorist aber eine Geschwister-Klasse, nicht Subklasse — Dialog-State-Fehler ("did not contain a response", "could not fetch BPD", "dialog initialization") fielen also durch zum generischenexcept Exception:, der weder State löschte noch Reconnect signalisierte. Beide Handler erkennen jetzt zusätzlich diese Fehler-Texte und triggern denselben Cleanup-Pfad. - Swift
submitTransferBPD-Retry: Pattern um"did not contain a response"erweitert (vorher nur"could not fetch BPD"und"dialog initialization"). Der eingebaute Auto-Reconnect-Retry sprang sonst bei DKB nicht an. - Pending-Probe-Aufräumen: Wenn die Bank für
get_transactions(include_pending=True)eine TAN verlangt (bei DKB möglich), bleibt der_pending_tan_response-State im python-fints-Client hängen und torpediert nachfolgende Operationen._extract_pending_transactions()setzt ihn jetzt aktiv zurück bei NeedTANResponse/NeedRetryResponse.
Wartung¶
- camt.052/053-Parser-Fixes (
app_packages/fints/camt_parser.py): Der mitgelieferte python-fints-Parser ist gegenlxmlgeschrieben, läuft aber unter iOS' embedded stdlibxml.etree.ElementTree. Drei Patches damit die camt-Pending-Probe durchläuft:Element.getiterator()→Element.iter()(entfernt in Python 3.9),root.xpath('//Rpt/Acct/Ccy')→root.findall('.//Rpt/Acct/Ccy')(xpath ist lxml-only) plus defensiver Empty-Guard für die Currency-Suche, undrecord["BookingDate.Date"]über.get()mit Fallback aufValueDate.Date(Pending-Einträge haben oft kein BookingDate, da nicht gebucht). Produktiv liefert MT942 die Pending-Daten; die camt-Path-Fixes bleiben drin damit zukünftige Banken über den moderneren Pfad bedient werden können.
[1.12.2] - 2026-05-01¶
Verbesserungen¶
- Push-Notifications nur noch im Hintergrund: Saldo-Änderungs-Benachrichtigungen werden ausschließlich beim echten
BGAppRefreshTaskversendet. Manuelle Refreshs (Pull-to-Refresh, Toolbar-Button), App-Start und Vordergrund-Rückkehr erzeugen keine Notifications mehr — der Nutzer hat die App in diesen Fällen ohnehin offen. Neuer FlagisBackgroundTaskRefreshinAppStategateway das Puffern inpendingBalanceChanges(Phase 1) und das Versenden in Phase 2 sowie im FallbackflushPendingBalanceChanges(). Reset infinishRefresh()und im Frühreturn-Pfad vonbackgroundRefresh(). - Demo: 2-Step-Chained-Transfer demonstrierbar:
Beispiel Sparkassebekommt zusätzlich ein Girokonto, und das vorhandene Sparkonto wird zum Tagesgeldkonto mitcan_transfer=false, supports_uebertrag=trueumgebaut (Sparkassen-typisches Setup).fetchTransferRecipients()liefert im Demo-Modus das Sparkasse-Giro als HKCUB-Empfänger zurück, sobald das Tagesgeld als Quellkonto gewählt ist.TransferView.executeTransfer()erkenntisChainedRequiredim Demo-Pfad und simuliert beide Transfers (Tagesgeld → Giro intern, Giro → externer Empfänger) mit zweiDemoData.recordTransfer()-Calls. Damit können der tanlose HKCUM-Übertrag und der 2-Step-Chained-Transfer auf externe Empfänger im Demo durchgespielt werden.
Wartung¶
- Test-Suite robuster gegen Demo-Mode-Leak:
SavedRecipientsTests,BankingLogTestsundtest_refreshAllBanks_demoMode_isBlockedsetzenDemoData.isActive = falseinsetUp/tearDown. Vorher konnte ein vorheriger Test den Demo-Modus angeschaltet hinterlassen, was nachfolgende Tests fehlschlagen ließ (SavedRecipientsStore.loadAll()→ Demo-Liste,BankingLog.log()→ No-Op).test_generateAccounts_returnsFourAccounts→_returnsFiveAccountsumbenannt für die 5er Kontoliste.
[1.12.1] - 2026-04-29¶
Bugfixes¶
- ING-DiBa-Crash beim Hinzufügen behoben: Build 284 stürzte nach PIN-Eingabe hart ab (
EXC_BREAKPOINTinPythonObject.subscript.getter). Zwei Layer-Fix: iOSPythonBridge: alle 30+ unsicherenresult["..."]-Subscripts inconnect/fetchBalance/fetchTransactions/fetchHoldings/startTransfer/continueVOP/getTransferRecipients/submitTAN/pollTANaufresult.checking[...]mit neuensafeString/safeBool-Helpers umgestellt — verhindert PythonKit_assertionFailurewenn das Backend einen optionalen Key auslässt.parseAccounts/parseTransactions/parseHoldingsnutzen indexierte Loops mit explizitemPython.len()-Check statt Python-Iteration.fints_backend_ios.pyget_balance:_pending_tan_responseinglobal-Deklaration ergänzt — Python machte die Variable funktionsweit lokal weil weiter unten zugewiesen, was bei ING-DiBa beim ersten Read einenUnboundLocalErrorwarf.- Python-Fallback-Returns bei Exceptions enthalten jetzt explizit
"needs_reconnect": False.
Performance¶
- Kategorien-View jetzt flüssig: Sluggy Animation und Hänger beim Tab-Wechsel zu/von Auswertung behoben. Zwei Ebenen:
TransactionCategorizerLookup-Cache (NSLock-geschützt): Overrides, FamilySurnames, OwnAccountOwners und InternalTransferPairs werden einmalig aus UserDefaults gelesen und im RAM gehalten. Invalidation in densave()-Methoden + neuerNotification.Name.categoryOverridesChanged. Vorher: 4 UserDefaults-Reads procategorize()-Aufruf.AnalyticsDerivation-Snapshot in AnalyticsView: Alle teuren Ableitungen (Direction-Summaries × 3, Vorperioden-Maps × 3, Trend-Daten, Account-Map, Totals) werden in einem Detached-Task vorberechnet, getriggert via.task(id: DerivationKey)nur bei echter Input-Änderung. Body liest O(1) aus dem Snapshot, Direction-Switch (Tap auf Summary-Card) ohne Recompute.CategoryDrillDownViewOverride-Set:overrideApplicantseinmal beim Erscheinen geladen statt UserDefaults-Read pro sichtbarer Zelle.- Effekt: Body-Render-Kosten bei 3000 Umsätzen von ~165ms auf ~1ms gesenkt.
Verbesserungen¶
VerificationCrashViewehrlicherer Text: "Verbindung fehlgeschlagen" statt "Anmeldedaten falsch" — nennt FinTS-Inkompatibilität als möglichen Grund (Watchdog kann nicht zwischen Auth-Fehler und Backend-Crash unterscheiden).AccountDetailViewHeader: Inhabername jetzt über der IBAN — verhindert dass die lange IBAN unter dem Konto-Namen optisch in die Saldo-Anzeige reinragt.
[1.12.0] - 2026-04-29¶
Neue Features¶
-
Sparen als eigene Auswertungs-Säule: Vierte Summary-Card "Sparen" neben Einnahmen/Ausgaben/Saldo, mit Sparquote im Titel ("Sparen 18%"). Der Direction-Picker wird 3-fach (Ausgaben | Einnahmen | Sparen) mit eigenem Donut/Bar/Trend für Sparen. Sparen wird strikt aus den Ausgaben-Summen rausgerechnet (Vermögensbildung ≠ Konsum), Saldo = Einnahmen − Ausgaben − Sparen.
-
Sparkonto-Toggle pro Konto in der Konto-Verwaltung — Spalte "Sparen" in der Account-Tabelle, Auswirkung sofort sichtbar via NotificationCenter. Auto-Detection per Konto-Name oder FinTS-Typ wurde bewusst entfernt — der Nutzer entscheidet selbst was als Sparen gilt.
-
Cross-Konto-Pair-Matching für interne Überträge:
InternalTransferPairsfindet zwei Buchungen mit gegenläufigem Vorzeichen in unterschiedlichen eigenen Konten (gleicher Betrag, ±14 Tage bei selber Bank / ±3 Tage cross-bank, min 0,01 € intern / 100 € cross-bank). Klassifiziert pro Pair als.savings(Zielkonto Sparkonto-Toggle) oder.transfers. Robust gegen Schreibweisen-Unterschiede des Bank-Empfängernamens. -
Einnahmen-Drill-Down mit eigenem Donut: Tap auf die Einnahmen-Card schaltet alle Charts (Donut/Bar/Trend) und Legende auf Einnahmen um. Strikte Income-Definition: nur Lohn/Gehalt im Verwendungszweck zählt als
.income, alles andere positive landet in "Sonstige Einnahmen" (inkl. Erstattungen, Cashback, Bahn-Entschädigungen). -
Vorperioden-Vergleich pro Kategorie: Delta-Anzeige (▲ +18% / ▼ −12%) farbig (rot/grün) neben jeder Kategorie in der Legende. Vorperiode automatisch passend gewählt: Vormonat / Vorjahr / gleichlanger Block bei Custom Range. YTD/MTD-aware: Bei aktuellem Jahr/Monat wird die Vorperiode auf den gleich-langen Anfangsblock im Vorjahr/Vormonat begrenzt — kein "ganzes 2026 vs. ganzes 2025"-Vergleichsmurks mehr. Header zeigt "vs. Jan–Apr 2025" oder "vs. 1.–29. März".
-
Future-Monat-Hinweis: Wahl eines Monats in der Zukunft → Hinweis-Karte "Noch keine Daten — Der gewählte Monat liegt in der Zukunft" statt leerer Charts.
-
PDF-Report (3 Seiten) via Toolbar-Share-Menü in der Auswertung — Übersicht mit Summary + Donut + Sparquote-Zeile, Kategorien-Tabelle mit Vorperioden-Delta, Trend-Chart. Apple-nativ (PDFKit + ImageRenderer), keine Drittabhängigkeiten.
-
CSV-Export mit Kategorien: zusätzliche Spalte "Kategorie" im CSV — Multi-Account, Excel-tauglich (Semikolon, UTF-8 BOM).
-
IBAN per Long-Press kopieren: In der Konto-Detail-Ansicht ist die IBAN jetzt selektierbar (
textSelection) plus Kontextmenü mit "IBAN kopieren". -
DTAUS-Textschlüssel-Klartext in der Umsatz-Detailansicht: Numerische Buchungs-Codes (z.B. "166") werden mit Klartext-Bedeutung ("Kartenzahlung") ergänzt. ~30 wichtigste Codes der Deutschen Kreditwirtschaft drin (siehe
BookingTextKeys.swift).
Verbesserungen am Categorizer¶
-
Familie dynamisch aus Konto-Inhabern:
FamilySurnamesextrahiert Nachnamen ausowner_name(Sparkasse-Format "NACHNAME, VORNAME" und "Vorname Nachname"). Familien-Überweisungen werden ohne hardcoded Vornamen erkannt. Firmen-Suffixe (GmbH, AG, KG, e.V., e.K., mbH) werden ausgeschlossen. -
Self-Transfer-Detection:
OwnAccountOwnersspeichert kanonische Form aller eigenen Konto-Inhaber. Empfänger-Match identifiziert Buchungen zwischen eigenen Konten zuverlässig — auch wenn der Bank-Empfängername variiert. -
Lemmatisierung + Synonym-Tabellen (
CategorySynonyms): Apple'sNLTaggerreduziert Wörter auf Grundform ("Versicherungen" → "versicherung"), pro Kategorie 10–20 Synonyme als Trigger. Fängt generische Begriffe ab die nicht durch Marken-Trigger erkannt wurden ("Tankstelle XY", "Praxis Dr. Müller"). -
posting_textals Übertrag-Erkennungsquelle: Bank-deterministischer Buchungstext (vs. Verwendungszweck der frei wählbar ist) — "Umbuchung" / "Übertrag" → sofort.transfers. -
Vorzeichen-aware Categorizer: Soll-typische Patterns (
purpose.contains("versicherung")etc.) greifen nur noch bei negativen Beträgen. Eine positive Buchung mit "Wohngebäudeversicherung" im Zweck ist Erstattung oder interner Übertrag, nicht Versicherungs-Einnahme. -
Personalisierte Hardcodes entfernt: DSGV-Income-Trigger, "lebenshaltungskosten berlin", Personennamen wie "thomas brohl", "kappelchen", "royal india" raus. Stattdessen viele deutsche Supermärkte ergänzt (REWE, Aldi, Lidl, Penny, Netto, Kaufland, Norma, Globus, Real, dm, Rossmann, Müller, Budni, Bäcker, Metzger).
-
Tagesgeld/Festgeld als Sparen erkannt (statt Übertrag).
-
Restaurant-Pattern generischer: pizzeria/ristorante/trattoria/cafe/bistro/gastronomie statt nur "restaurant" + spezifische Marken.
UX-Verbesserungen¶
-
Bank-Editor Apple-typisches Pattern: "Fertig" oben rechts (konsistent mit Settings-Sheet). "Ändern"-Button neben Bank-Auswahl nur im Hinzufügen-Modus (im Edit-Modus ist die Bank fix). Confirmation-Dialog bei ungespeicherten Zugangsdaten beim Schließen ("Speichern und prüfen / Verwerfen / Abbrechen") — verhindert stillen Datenverlust. "Geänderte Zugangsdaten speichern"-Button erscheint nur wenn tatsächlich geändert.
-
Konto-Verwaltung: Spalten-Header (Konto / Sparen / App / Wgt) bündig über den Toggles. Stift-Icon (
square.and.pencil) links vom Konto-Namen signalisiert Tap-Affordanz für Alias-Bearbeitung. -
Override-Badge in DrillDown: Kleines Stift-Icon (
pencil.circle.fill) neben Datum/Konto wenn Kategorie manuell gesetzt wurde. -
DrillDown vorzeichen-aware: Zeigt bei Einnahmen-DrillDown nur positive Buchungen, bei Ausgaben nur negative, bei Sparen/Überträgen nur die Abgangsseite — vermeidet Doppelzählung gepairter Buchungen.
-
Demo-Modus geschützt: BankingLog skipt im Demo-Modus, LogView zeigt Platzhalter-Karte ("Protokoll im Demo-Modus ausgeblendet"). Real-Einträge bleiben erhalten und sind nach Verlassen des Demo-Modus wieder sichtbar.
Bugfixes / Konsistenz¶
-
incomeCategoriesfiltert strikt: Soll-typische Kategorien (Versicherung, Wohnen, Familie, Mobilität, etc.) werden bei positiven Beträgen automatisch zu.otherumgemappt — keine "Versicherung 750 € Einnahme" mehr. -
Pair-Matcher für sub-Euro-Beträge: Min-Betrag bei bank-internen Pairs auf 0,01 € gesenkt — auch Saldenausgleich-Buchungen werden erkannt.
-
Diagnose-Log nach Pair-Matching: BankingLog zeigt "🔗 Pair-Matching: X Pairs erkannt aus Y Buchungen (Z eigene Konten)".
[1.11.0] - 2026-04-28¶
Neue Features¶
-
2-Step-Chained-Transfer für Sparkassen-Geldmarktkonten: Externe SEPA-Überweisung von Tagesgeld/Sparkonten ist jetzt möglich, indem BankingPal die Operation in zwei Schritten verkettet — Schritt 1 (HKCUM, tanlos) überträgt den Betrag aufs Girokonto derselben Bank, Schritt 2 (HKCCS mit TAN+VOP) führt die externe Überweisung aus. Aktivierung im TransferView via „Externe Überweisung (in 2 Schritten)"-Button oder direkten Tap auf einen gespeicherten Empfänger. Erklärungs-Sheet beim ersten Aufruf, mit Option „Nicht mehr anzeigen" (
@AppStorage chainedTransferHintDismissed). NeuerChainedTransferStateCodable-Struct, persistiert in UserDefaults für Crash-Recovery zwischen Step 1 und 2. Verwendungszweck Schritt 1: „Übertrag wegen Überweisung von Girokonto". -
Recovery-Workflow bei Step-2-Fehler: Neue
ChainedTransferRecoveryView(zIndex 75 als Overlay) erscheint, wenn Schritt 1 erfolgreich war aber Schritt 2 fehlschlägt (TAN abgelehnt, VOP-Mismatch, Netzwerk weg, App-Beendigung dazwischen). Drei Optionen: Erneut versuchen (Step 2 mit neuer TAN), Auf Tagesgeld zurückübertragen (Revoke via HKCUM Giro→Tagesgeld), Auf Girokonto belassen (Flow beenden). Lokales Cache-Patching (Tagesgeld -X, Giro +X) während Verkettung — UI zeigt sofort korrekte Salden ohne Refresh, Revoke macht den Patch rückgängig. -
Bestätigungsseite des verketteten Transfers zeigt drei Sektionen: Von (Tagesgeld) → Über (Girokonto) → An (Empfänger). Submit-Button mit Text „In 2 Schritten überweisen".
-
Saved Recipients direkt bei Geldmarktkonten verfügbar: Tap auf einen externen Favoriten startet automatisch den 2-Schritte-Flow ohne Zwischen-Tap auf den „Externe Überweisung"-Button.
-
Konto-Anzeigename in CategoryDrillDownView: Pro Buchung wird der Quellkonto-Name eingeblendet (
28.04. · Tagesgeld 1234) — hilfreich bei Multi-Konto-Auswertungen. Map wird in AnalyticsView aufgebaut und durchgereicht.
Verbesserungen¶
-
Empfänger-Reihenfolge im TransferView neu sortiert: Beim Girokonto erscheint jetzt zuerst die Freitext-SEPA-Eingabe, dann gespeicherte Empfänger, dann Recent, schließlich „Übertrag auf eigenes Konto" am Ende. Bei Tagesgeld bleibt HKCUB-Liste oben (kein direkter SEPA-Pfad).
-
Suchleiste in der Umsatzansicht immer sichtbar:
.searchable(... placement: .navigationBarDrawer(displayMode: .always) ...)— die Suchleiste erscheint sofort beim Öffnen, nicht erst nach Pull-Down. -
Saldo-Header in der Umsatzansicht in Theme-Farben: Positive Salden in
BPTheme.positive(grün), negative inBPTheme.negative(rot bzw. schwarz im Sparkasse-Theme) — konsistent mit Übersichtsseite. Auch Beträge in CategoryDrillDownView und TransactionDetailView angeglichen. -
Header-Spacing Übersichtsseite gefixt: Der
topBarToContentSpacerzwischen TopBar und List nutzt jetzt explizitenColor(.systemGroupedBackground)stattColor.clear. Der transparente Spacer hatte fälschlich die weiße Background-Farbe der TopBar geerbt — jetzt graue 32pt-Pause sichtbar zwischen Header und Saldo-Bubble. -
Top-Inset in der Umsatzansicht reduziert:
CompactTopInsetModifiermit.contentMargins(.top, 4, for: .scrollContent)(iOS 17+) — kleinerer Abstand zwischen Suchleiste und Saldo-Section. -
Hinweis-Sheet-Layout verbessert: Title kompakter (.headline statt .title3, vertikal mit Icon obendrauf), ScrollView für den Inhalt,
.largeDetent — Buttons rutschen nicht mehr aus dem Sheet. -
TransferView UI: Standard-Empfänger-UI erscheint jetzt auch bei Konten mit
supportsUebertrag && canTransfer(z.B. Sparkasse-Giro mit beiden Rechten) — vorher wurde es fälschlich verborgen.
Bugfixes¶
-
2-Step-Chained-Transfer Endlos-Loop:
submitTransferwickeltebridge.onTANDismissedals Wrapper über den vorigen Handler. Bei sequenziellem zweiten Aufruf (Step 2) akkumulierten sich Wrapper, sodass Step-2-Erfolge auch Step-1-Completion triggerten — das löste eine Endlos-Schleife mit immer neuen TAN-Anforderungen aus. Fix: Idempotenz-FlaghasFired(Reset bei BPD-Retry) +bridgeManager.restoreAllCallbacks()zwischen den Schritten. -
Externe Überweisung von Sparkasse-Giro war nicht sichtbar: Wenn ein Konto sowohl
supportsUebertragals auchcanTransferhatte (Sparkasse-Giro mit HKCUM + HKCCS), wurde das Standard-Empfänger-UI ausgeblendet und nur die HKCUB-Liste gezeigt. Filter-Bedingung umaccount.canTransfererweitert. -
Title „Externe Überweisung (in 2 Schritten)": Wurde auf zwei Zeilen umgebrochen — jetzt
.lineLimit(1) .minimumScaleFactor(0.7), passt immer in eine Zeile.
Architektur¶
- Neue
ChainedTransferStateCodable-Struct in AppState.swift (Persistenz via UserDefaults JSON-Encoder) - AppState neue Methoden:
submitChainedTransfer,executeChainedTransferStep2,retryChainedTransferStep2,revokeChainedTransfer,dismissChainedTransfer,applyChainedTransferStep1Patch,applyChainedTransferRevokePatch, Persistierungs-Helper - TransferView: Computed Properties
intermediaryAccount,isChainedRequired; ViewBuilder-Sub-ViewshkcubSection,otherAccountsSection,chainedTransferExtraSectionsfür flexible Reihenfolge - BankingPalApp:
ChainedTransferRecoveryViewals ZStack-Overlay (zIndex 75) - Neue View:
ChainedTransferRecoveryView.swift
Wartung¶
- 152/152 Tests bestanden
- Build: 247 → 257 (zehn Build-Iterationen seit v1.10.5)
- CLAUDE.md, MEMORY.md, CHANGELOG.md aktualisiert
- Versionsnummer-Konvention etabliert: Build-Number bei jedem Code-Change +1, MARKETING_VERSION nur bei expliziten Releases (siehe
feedback_versioning.mdin Memory)
[1.10.5] - 2026-04-28¶
Verbesserungen¶
- Gespeicherte Empfänger direkt bei Geldmarktkonten: Auf HKCUM-Quellkonten (Tagesgeld/Sparkonto) erscheinen externe Saved Recipients jetzt direkt unter der HKCUB-Liste — ein Tap aktiviert automatisch den 2-Schritte-Modus und springt zur Betragseingabe. Spart den Zwischen-Tap auf den „Externe Überweisung (in 2 Schritten)"-Button. HKCUB-IBANs werden in der Saved-Liste ausgeblendet (Doppelung vermeiden).
Wartung¶
- 152/152 Tests bestanden
- Build: 246 → 247
[1.10.4] - 2026-04-28¶
Bugfixes¶
- 2-Step-Chained-Transfer Endlos-Loop bei Step 2: Bei verketteten Transfers (Tagesgeld → Giro → extern) wickelte
submitTransferden Bridge-CallbackonTANDismissedals Wrapper über den vorigen Handler. Beim sequenziellen zweiten Aufruf für Step 2 akkumulierten sich die Wrapper, sodass nach erfolgreicher TAN-Bestätigung von Step 2 sowohl Step-2- als auch Step-1-Completion-Closures gefeuert wurden — letztere triggerte erneutexecuteChainedTransferStep2, was zu einer Endlos-Schleife mit immer neuen TAN-Anforderungen ("Gerät als vertrauenswürdig speichern") führte. - Fix: (1) Idempotenz-Schutz
hasFiredinsubmitTransfer— wrappedCompletion feuert garantiert nur einmal, wird beim BPD-Retry zurückgesetzt; (2)bridgeManager.restoreAllCallbacks()wird zwischen Step 1 und Step 2, vor Retry und vor Revoke aufgerufen — setzt die default Dispatcher-Closures zurück, verhindert Wrapper-Akkumulation.
Wartung¶
- 152/152 Tests bestanden
- Build: 245 → 246
[1.10.3] - 2026-04-28¶
Neue Features¶
- Externe Überweisung von Geldmarktkonten in 2 Schritten: Sparkassen-Tagesgeld/Sparkonten haben kein direktes HKCCS-Recht für externe Überweisungen. BankingPal verkettet jetzt automatisch: Schritt 1 (HKCUM, tanlos) überträgt den Betrag aufs Girokonto derselben Bank, Schritt 2 (HKCCS, mit TAN+VOP) führt die externe Überweisung aus. Aktivierung im TransferView via "Externe Überweisung (in 2 Schritten)" — schaltet das Standard-Empfänger-UI (Saved/Recent/Freitext) zusätzlich zur HKCUB-Liste frei. Bestätigungsseite zeigt explizit beide Schritte mit Quell-, Zwischen- und Zielkonto.
- Recovery-Workflow bei Step-2-Fehler: Neue
ChainedTransferRecoveryViewerscheint als Overlay (zIndex 75), wenn Schritt 1 erfolgreich war aber Schritt 2 fehlschlägt (TAN abgelehnt, VOP-Mismatch, Netzwerk weg, App-Beendigung dazwischen). Drei Optionen: Erneut versuchen (Step 2 mit neuer TAN), Auf Tagesgeld zurückübertragen (Revoke via HKCUM Giro→Tagesgeld), Auf Girokonto belassen (Flow beenden). Status der Verkettung wird zwischen Step 1 und 2 in UserDefaults persistiert (pending_chained_transfer) — ein Crash zwischen den Schritten zeigt beim nächsten App-Start direkt die Recovery-View. - Cache-Patching während Verkettung: Nach erfolgreichem Step 1 wird der lokale Saldo-Cache sofort angepasst (Tagesgeld -X, Giro +X) — der Nutzer sieht in der UI die richtigen Werte ohne auf einen Refresh zu warten. Beim Revoke wird der Patch rückgängig gemacht.
Architektur¶
- Neue
ChainedTransferStateCodable-Struct in AppState.swift (Persistenz via UserDefaults JSON-Encoder) - AppState neue Methoden:
submitChainedTransfer,executeChainedTransferStep2,retryChainedTransferStep2,revokeChainedTransfer,dismissChainedTransfer,applyChainedTransferStep1Patch,applyChainedTransferRevokePatch,savePendingChainedTransfer,loadPendingChainedTransfer,clearPendingChainedTransfer - TransferView: neue Computed Properties
intermediaryAccount(wählt erstes Giro mitcanTransfer && in HKCUB-Liste),isChainedRequired. Neuer@State externalTransferRequestedschaltet die UI um - BankingPalApp wires
ChainedTransferRecoveryViewals ZStack-Overlay (zIndex 75, zwischen TwoFASplash z=50 und LoginError z=100)
Wartung¶
- 152/152 Tests bestanden
- Build: 244 → 245
- CLAUDE.md aktualisiert: ChainedTransferRecoveryView in Verzeichnisstruktur
[1.10.2] - 2026-04-28¶
Bugfixes¶
- PythonKit-Crash auf echtem iPhone bei fetchBalance (EXC_BREAKPOINT in
PythonObject.subscript.getter): Wenn das Backend ein nicht-Dict-Objekt zurückgab (z.B. Python-Exception als Bare-Value), triggerteresult["status"]eine Swift-Assertion. Neuer HelperextractStatus(from:)mitresult.checking[...](sicheres Subscript) — alle 8 betroffenen Stellen iniOSPythonBridge.swiftersetzt (connect,fetchBalance,fetchTransactions,fetchHoldings, TAN-Polling,getTransferRecipients). - Depot-Saldo fiel nach Refresh auf 0: Phase 1 + Phase 2 überschrieben den Depot-Wert mit FinTS-Antwort
0(Depots haben keinen klassischen HKSAL-Saldo). Jetzt wird der vorherige Saldo (oder Holdings-Cache-Wert) bewahrt, wenn der frische Wert 0 ist.fetchHoldingsForBankpuffert den alten Cache vor dem Refetch und stellt ihn bei HKWPD-Fehler wieder her. - Analytics-Banner false-positive bei wenig aktiven Konten:
TransactionCacheEntryumrequestedDays: Int?erweitert (Codable mitdecodeIfPresent, rückwärtskompatibel).coveredDaysliefertmax(echterAlter, requestedDays ?? 0).mergeIntoCachereicht dendays-Parameter durch — auch leere Antworten (Konto ohne Buchungen im Zeitraum) markieren den Cache jetzt als abgedeckt. - TwoFASplashView zeigte UUID statt Banknamen während
verifyNewBank: Die neue Bank ist temporär inBankConnectionStore, aber noch nicht inappState.connections.bankName(for:)fällt jetzt aufBankConnectionStore.connection(byId:)zurück. - Englische FinTS-Errors auf Deutsch: Neue
_translate_error_message-Funktion infints_backend_ios.py— Sparkassen-typischer Fehler "Error during dialog initialization, could not fetch BPD…" wird zu "Anmeldung fehlgeschlagen. Bitte prüfe Anmeldename und PIN." - App-Crash bei Erstinstallation nach Disclaimer (XPC_MISUSE im iOS-26-Sim):
WCSession.activate()erst nach Disclaimer-Akzeptanz starten — vermeidet die XPC-Race-Condition mit BackBoardServices beim Setup.
Verbesserungen¶
- TAN-Notification mit 20s Delay: BankingPal-Local-Notification erscheint nicht mehr sofort, sondern verzögert. Reagiert der Nutzer auf den Bank-pushTAN-Push (oder gibt direkt in BankingPal frei), wird die geplante Notification durch
onTANDismissed/cancelTANgecancelt → keine Doppelung mehr.NotificationDelegateunterdrückttanRequired_*im Vordergrund (TwoFASplashView ist sichtbar). Depot-Saldo-Änderungen lösen keine Push-Notification mehr aus. - Bank-Logo-Loading robuster:
BankFaviconLoadermit 5-Min-Cooldown statt for-ever-failure-cache, Content-Type-Validierung, HTML-Parsing-Fallback (<link rel="apple-touch-icon">aus der Bank-Startseite extrahieren), realistische User-Agent/Accept-Header, BankingLog-Diagnose. Sparkasse-Logo wird jetzt zuverlässig ausapple-touch-icon.pnggeladen. - BankIconView: Programmatischer
SparkasseSLogo-Fallback (rotes S als Canvas-Drawing) wenn Favicon nicht verfügbar; Favicon-Inset 8% → 18% (Logo passt sauber in den Kreis statt gequetscht zu wirken). - DisclaimerView/SetupView system-adaptiv: Hardcoded
BPTheme.darkRGB-Hintergrund +.white-Texte ersetzt durchColor(.systemGroupedBackground)+.primary/.secondary. Beide Erst-Screens folgen jetzt der System-Erscheinung (Light/Dark). - Header-Spacing in AccountListView: Expliziter
topBarToContentSpacerzwischen Top-Bar und List — die erste Karte klebt nicht mehr am Header. Padding-Aufteilung 14pt oben + 10pt unten. - HoldingDetailView: Default-Chart-Periode von 1 Jahr auf 1 Tag — Tagesansicht ist beim Öffnen einer WP-Position relevanter.
- CategoryDrillDownView: Pro Transaktion wird der Konto-Anzeigename eingeblendet (
28.04. · Tagesgeld 1234) — hilfreich bei Multi-Konto-/Multi-Bank-Auswertung. Map wird inAnalyticsViewaufgebaut und durchgereicht. - Analytics-Diagnose-Logging:
📊 Analytics-Banner(mitcov/reqDays/oldestpro Konto) und📊 Analytics-HistoryLoad(mit Ergebnis nach Nachladen) ins BankingLog für Cache-Debugging. - Compiler-Warnings beseitigt: Ungenutzte
let rin Theme.swift entfernt;LABiometryType.noneals expliziter Case in LockScreenView (war im@unknown defaultversteckt).
Wartung¶
- 152/152 Tests bestanden
- Build-Nummer: 217 → 244 (stepweise Builds 218–243 in dieser Session)
- CLAUDE.md + MEMORY.md aktualisiert: BankFaviconLoader, BankIconView, requestedDays-Mechanik, Depot-Saldo-Schutz, TAN-Notification-Strategie
[1.10.0] - 2026-04-22¶
Neue Features¶
- SEPA-Übertrag via HKCUB/HKCUM (Sparkassen-Flow, TAN-los): Konten mit aktiviertem
HKCUM-Recht (meist Tagesgeld/Sparkonten) können jetzt Überträge auf die bankseitig hinterlegten Referenzkonten ausführen — innerhalb derselben Bank, ohne TAN. Neue Custom-SegmenteHKCUB1(Empfängerliste),HICUB1(Response mitEmpfaengerkontoInfo-DEG) undHKCUM1(Übertrag) im Python-Backend. Backend-Commandget_transfer_recipients()lädt die freigegebene Ziel-IBAN-Liste;_send_hkcum_transfer()baut pain.001 mitexecution_date=1999-01-01(Spec-Pflicht) und versendet überHKCUM1. Swift-seitig:AccountBalance.supports_uebertrag: Bool?, StructTransferRecipient,AppState.fetchTransferRecipients(...),submitTransfer(..., useUebertrag:). InAccountDetailViewerscheint der Transfer-Button nun auch beisupportsUebertrag(nicht nurcanTransfer). - TransferView: Spezial-UI für Übertragskonten: Bei Quellkonten mit
supports_uebertrag=truezeigt Step 1 ausschließlich die HKCUB-Liste als tappbare Zeilen (mit Kontoname + Saldo ausbankAccountsvia IBAN-Match). Gespeicherte Empfänger, Zuletzt-verwendet und das Freitext-IBAN-Feld werden ausgeblendet — die Bank erlaubt hier nur Überträge auf die im Giro hinterlegten Referenzkonten. - Push-Notifications mit neuen Umsätzen: Kontoupdate-Benachrichtigungen zeigen jetzt zusätzlich zum Saldo-Delta bis zu drei neu erkannte Umsätze (
• Empfänger: ±Betrag, Name auf 24 Zeichen gekürzt) plus optional "… +N weitere". Phase 1 puffert die Saldo-Änderungen inpendingBalanceChanges, Phase 2 reichert sie nach dem Umsatz-Merge mit den frisch erkannten IDs an.finishRefresh()flusht als Fallback ohne Umsätze, wenn Phase 2 abgebrochen wurde.
Bugfixes (bereits in 1.9.1–1.9.8 ausgerollt, im 1.10.0-Release gebündelt enthalten)¶
- Sparkasse-Refresh-Crash bei Depot-Konten ohne
supported_ops-Feld (v1.9.7):supported_ops: []Default im Depot-Init, Swift nutztpyAccount.checking[…]. - BPD-Retry-Fix bei Transfer-Session-Ablauf: Nach
disconnectdie Bridge frisch holen (v1.9.4). - TransferSheet-Guard gegen BGTask während offenem Transfer-Flow (v1.9.3).
- BalanceChange-Push-Layout: Title "Kontoupdate" + Bankname (Subtitle) + Delta/Saldo mit 📉/📈 (v1.9.2).
banksRequiringTANwird bei allen stillen Refreshes geprüft (v1.9.1).
Wartung¶
- 152/152 Tests bestanden
- Build-Nummer: 203 → 217
- CLAUDE.md aktualisiert: HKCUB/HKCUM-Doku in TransferView + FinTS-Backend; Push-Notification mit Umsätzen; AccountBalance um
supports_uebertragerweitert - Python-Backend importiert jetzt
FinTS3Segment,DataElementField,DataElementGroupField,KTI1,BankIdentifier,FinTSParserWarningfür die Custom-Segmente
[1.9.0] - 2026-04-11¶
Neue Features¶
- Kategorien-Auswertung: Neue
AnalyticsViewals dritter iPhone-Tab und iPad-Sidebar-Eintrag. Drei Chart-Typen — Donut (Canvas-basiert, iOS 16 kompatibel), Bar (Top-Kategorien via Swift Charts), Trend (Tages-/Monatsverlauf). Tap auf ein Segment öffnetCategoryDrillDownViewmit allen Buchungen der Kategorie im gewählten Zeitraum. - 17 Kategorien (
TransactionCategorizer): Regex-basierte Kategorisierung, 1:1 aus der Mac-App portiert. Interne Transfers und "Sonstiges" werden aus Summenberechnungen herausgerechnet. - Cache-Verschlüsselung (
DataEncryption):cached_bank_balances,cached_transactions_v2undcached_holdingswerden mit CryptoKit AES-GCM verschlüsselt in UserDefaults abgelegt. Schlüssel liegt in der Keychain (Servicede.bankingpal.pocket.cachekey, AccessAfterFirstUnlock). Legacy-Migration beim ersten Load liest alte Klartext-JSON-Caches und schreibt sie verschlüsselt neu — keine Datenverluste beim Update. - Per-Bank-Refresh: Im Multi-Bank-Pager aktualisieren Toolbar-Button und Pull-to-Refresh jetzt nur die aktuell sichtbare Bank (
refreshBank(bankId:)/refreshBankAsync(bankId:)). Verhindert unnötige Session-Wechsel zu anderen Banken und damit potentielle TAN-Abfragen. Single-Bank-Modus und iPad-Sidebar bleiben beim Gesamt-Refresh. - Auswertung: Default-Bank: Die Auswertung startet mit der ersten Bankverbindung (nach
sortOrder) statt "Alle Banken" — Nutzer kann weiterhin manuell umschalten.
Bugfixes¶
- Sparkasse 2FA-Ursache beseitigt:
AnalyticsViewlud beim Öffnen automatisch fehlende Umsatz-Historie nach. Bei Default "aktuelles Jahr" ergab das >90 Tage HKKAZ-Abruf, was bei Sparkassen (z.B. Kreissparkasse Köln) bankseitig SCA auslöst — selbst wenn die Geräteerkennung für den Dialog-Login noch gültig war. Jetzt lädt die View nur Daten aus dem Cache. Bei nicht ausreichender Abdeckung erscheint ein Banner mit Button "Mehr Historie laden"; ein Bestätigungs-Alert warnt ab >90 Tagen explizit vor möglicher TAN-Abfrage. Erst nach User-Bestätigung wirdfetchTransactions()sequentiell pro Konto aufgerufen. - Transfer-TAN-Freigabe zurücksetzen (
refreshAfterTransfer):tanApprovedBanks.remove(bankId)wird vor dem Refresh-Start aufgerufen, damit die neue TAN-Anforderung (DKB-Saldo-Bug) nicht fälschlich übersprungen wird.
Wartung¶
- 152/152 Tests bestanden
- Build-Nummer: 188 → 203 (stepweise Builds 189–202 in dieser Session)
- CLAUDE.md aktualisiert: AnalyticsView, CategoryDrillDownView, TransactionCategorizer, DataEncryption, Per-Bank-Refresh, Verzeichnisstruktur
[1.8.5] - 2026-04-07¶
Neue Features¶
- Erweiterte Umsatzsuche mit Fuzzy-Match: Alle Textsuchen nutzen Levenshtein-basierte Fuzzy-Logik — Tippfehler und Spracherkennungsfehler werden toleriert (z.B. "Sara Weigand" findet "Sarah Weigand"). Erlaubte Distanz: 1 bei kurzen Wörtern (≤5 Zeichen), 2 bei längeren
- Betrags-Vergleichsoperatoren: "kleiner 1000", "größer 500", "< 100", "> 50", "unter", "über", "mehr als", "weniger als" — vergleicht Absolutbetrag aller Umsätze
- Soll/Haben-Filter: "soll", "haben", "ausgaben", "eingänge", "gutschriften", "einnahmen", "belastungen", "plus", "minus" — optional mit Prefix "alle" und Suffix "Umsätze"/"Buchungen"
- Natürlichsprachliche Umsatzsuche: Erkennt Sätze wie "Zeig mir alle Umsätze an PayPal", "Umsätze vom DSGV", "alle Buchungen mit Verwendungszweck Miete". Präfixe werden automatisch entfernt, Schlüsselwörter steuern die Feldsuche (von/vom/an/für/bei → Empfänger, mit Verwendungszweck → Zweck)
- Erweiterter Betragsbereich-Trenner: Neben "bis" und "–" wird jetzt auch Bindestrich-Minus "-" als Trenner erkannt (z.B. "10 - 1000") — behebt Kompatibilitätsproblem mit Spracherkennung, die "bis" als "-" transkribiert
Wartung¶
- 152 Tests bestanden
- CLAUDE.md aktualisiert (erweiterte Umsatzsuche dokumentiert)
[1.8.4] - 2026-04-04¶
Bugfixes¶
- Timeout-Endlosschleife behoben: Nach einem Netzwerk-Timeout blieb der stale FinTS-State auf der Festplatte erhalten — jeder folgende connect() lud den kaputten State und hing erneut (bis zu 36 Stunden). Jetzt wird der State nach Timeout gelöscht (Swift-seitig
deleteFinTSState+ Python-seitig Timeout-Keyword-Erkennung) - HTTP-Timeout (20s):
FinTSHTTPSConnection.send()infints/connection.pyhat jetzttimeout=20— vorher konnte ein HTTP-Request bei schlechtem Empfang unbegrenzt hängen
Neue Features¶
- TAN-pflichtige Banken bei Vordergrund-Rückkehr überspringen: Banken die immer 2FA verlangen (z.B. DKB) werden bei automatischer Aktualisierung komplett übersprungen — spart ~8-10s pro Bank. Dynamisch erkannt via
banksRequiringTAN-Liste, kein manuelles Konfigurieren nötig. Manueller Refresh weiterhin für alle Banken - Bankname im Konto-Header: AccountDetailView und DepotDetailView zeigen jetzt den Banknamen über dem Kontonamen an. Inhabername wird als "Vorname Nachname" angezeigt (statt "NACHNAME, VORNAME")
- Swipe-Sperre auf Detailseiten: Im Multi-Bank-Modus wird das TabView-Seitenblättern auf Umsatz-/Depot-Seiten deaktiviert — nur der iOS-Back-Swipe (vom linken Rand) funktioniert. UIKit-Bridge
DisablePageSwipeUIViewsteuert dieUIScrollViewdesUIPageViewController
Wartung¶
- Refresh-Lifecycle Testsuite erweitert (152 Tests)
- CLAUDE.md aktualisiert (Timeout-Resilienz, TAN-Skip, Header-Redesign, Swipe-Navigation)
[1.8.3] - 2026-03-25¶
Bugfixes¶
- Sparkasse 2FA-Geräteerkennung:
disconnect()ruft kein HKEND mehr auf — FinTS-Dialog läuft serverseitig ab, Geräteerkennung bleibt erhalten - DKB Endlos-Spinner: Manueller Refresh erzwingt Reset eines laufenden Refresh-Zyklus statt sich zu blockieren
- Depot Aktualisierungsdatum: Bewertungsdatum und Aktualisierungszeitpunkt werden jetzt beide angezeigt
- Leerer Bildschirm nach App-Neustart: Sicherheitsnetz —
isInitialLoadwird nach max. 10s automatisch zurückgesetzt - Protokoll-Export: Share-Sheet funktioniert innerhalb von Sheet-Präsentationen (UIViewController-Kette korrekt durchlaufen)
Neue Features¶
- Per-Bank Aktualisierungszeitpunkt: Jede Bank zeigt Datum/Uhrzeit der letzten Aktualisierung (persistiert über App-Neustarts)
- Kontenverwaltung im Bank-Editor: App/Widget-Sichtbarkeit und Alias-Bearbeitung direkt im BankConnectionEditorView
- Protokoll-Export: Protokoll als Textdatei teilbar (Share-Button in Toolbar)
Code-Qualität¶
AccountToggleRowals wiederverwendbare Komponente extrahiertbankName(for:)Helper ersetzt 11 duplizierte LookupsisStaleCallback(bankId:label:)dedupliziert Stale-Callback-GuardsBankingLogoptimiert: O(1) statt O(n) pro Eintrag- Diagnose-Logging für DKB Refresh-Zyklus (Phase 1/2 Saldenvergleich, TAN-Skip)
[1.8.0] - 2026-03-14¶
Neue Features¶
- Edition RED (Farbthema): Dynamisches Farbschema — Toggle in Einstellungen wechselt die gesamte App zwischen BankingPal-Teal und Sparkassen-Rot.
BPThemenutzt computed properties mitUserDefaults("colorTheme"), Root-View wird per.id(colorTheme)komplett neu aufgebaut - Dynamischer App-Icon-Wechsel: Beim Aktivieren/Deaktivieren von Edition RED wechselt das Home-Screen-Icon automatisch via
setAlternateIconName(). Alternate Icons inCFBundleAlternateIcons(Info.plist) für iPhone und iPad - BrandLogo-Komponente: Theme-aware Logo-Komponente ersetzt
Image("AppLogo")in allen Views — zeigt automatisch das passende Logo je nach aktivem Farbthema - Netzwerk-Prüfung bei Ersteinrichtung:
BankConnectionEditorView.saveConnection()prüftappState.isNetworkAvailablevor der Bankverifikation — verhindert Hänger im Flugmodus - Setup-Optionen bei Neuanlage: Auto-Update und Überweisungen-Toggles sind jetzt auch beim Neuanlegen einer Bankverbindung sichtbar (nicht nur im Edit-Modus)
- Apple-Style Erscheinungsbild: Hell/Dunkel-Buttons im Capsule-Design + Automatisch-Toggle ersetzen den einfachen Picker in den Einstellungen
Bugfixes¶
- 2FA-Doppeltext behoben: TwoFASplashView hat jetzt einen vollständig deckenden Hintergrund (
Color(.systemBackground)unter dem Gradient) — Text scheint nicht mehr durch das darunterliegende Form durch - Auto-Update respektiert Einstellung: App-Start-Refresh verwendet
silent: true→ Banken mit deaktiviertem Auto-Update werden übersprungen - needsInitialTransactionLoad-Reset: Flag wird in
handleDidBecomeActive()zurückgesetzt — verhindert unnötige TAN-Abfragen (DKB) nach Vordergrund-Rückkehr - Swipe-to-Delete funktioniert: SettingsView und SavedRecipientsView nutzen
.onDeleteauf ForEach statt.swipeActions, Navigation-Swipe deaktiviert perDisableSwipeBackHelper(UIViewRepresentable mit Responder-Chain) - Settings-Swipe-Konflikt gelöst: Einstellungen werden als Sheet statt Push-Navigation geöffnet — kein Konflikt mehr mit TabView(.page) Pager-Geste
- iPad SettingsView State-Isolation:
.id(selectedItem)verhindert @State-Bleeding beim Wechsel zwischen Sidebar-Einträgen - selectedBankPage Bounds-Check: Verhindert Index-out-of-bounds bei Änderung der Bankverbindungen
Verbesserungen¶
- Alle Views verwenden
BPTheme.accentstattBPTheme.tealRGB— Farben reagieren dynamisch auf Theme-Wechsel - Bankverbindungen in SettingsView: Sheet-basierte Bearbeitung statt NavigationLink
- Gespeicherte Empfänger: Tap-Geste + Sheet statt NavigationLink für zuverlässiges Swipe-to-Delete
Wartung¶
- 98/98 Tests bestanden (17 neue Tests: ColorTheme, AutoUpdate, SavedRecipients, AccountAliases)
- CLAUDE.md auf Version 1.8.0 aktualisiert
- Build 162
[1.7.1] - 2026-03-12¶
Neue Features¶
- Echtzeit\u{00FC}berweisung (SCT Inst): Toggle auf der Best\u{00E4}tigungsseite erm\u{00F6}glicht SEPA Instant Payments (HKIPZ1 statt HKCCS1). Nur bei externen \u{00DC}berweisungen verf\u{00FC}gbar, nicht bei internen \u{00DC}bertr\u{00E4}gen. Parameter
instantPaymentwird durch alle 4 Schichten durchgereicht (TransferView \u{2192} AppState \u{2192} iOSPythonBridge \u{2192} fints_backend_ios.py) - \u{00DC}berweisungen pro Bank steuerbar: Neues Property
BankConnection.transfersEnabled(Default: deaktiviert). Transfer-Button in AccountDetailView erscheint nur wenn die jeweilige Bank \u{00DC}berweisungen erlaubt - Bank-Optionen im Editor: Section "Optionen" im BankConnectionEditorView (Edit-Modus) mit Toggles f\u{00FC}r Auto-Update und \u{00DC}berweisungen — beide individuell pro Bankverbindung konfigurierbar
- App-Sperre bei Ersteinrichtung: Nach Anlegen der ersten Bankverbindung wird automatisch angeboten, die App-Sperre (Face ID / Touch ID) zu aktivieren
- LockScreenView: Neuer Sperrbildschirm f\u{00FC}r App-Sperre
- HoldingDetailView: Detailansicht f\u{00FC}r einzelne Wertpapierpositionen
- StockDataService: Kursdaten-Service f\u{00FC}r Wertpapiere (Yahoo Finance)
Verbesserungen¶
- SettingsView aufger\u{00E4}umt: Auto-Update und \u{00DC}berweisungen aus den Einstellungen entfernt (jetzt pro Bank im Editor)
- Sicherheits-Section in SettingsView enth\u{00E4}lt nur noch App-Sperre
Wartung¶
- 81/81 Tests bestanden
- CLAUDE.md auf Version 1.7.1 aktualisiert
[1.6.1] - 2026-03-06¶
Neue Features¶
- Multi-Bank-Unterstützung: Mehrere Bankverbindungen werden korrekt verwaltet — jede Bank hat eigene Session, eigenen State, eigene Salden-Anzeige
- Per-Bank-Saldo: Kontenübersicht zeigt pro Bank den Saldo als Section-Header (Bankname + Saldo in Teal + Aktualisierungszeitpunkt) statt eines Gesamtsaldos
- Multi-Bank-Pager: Bei mehreren Banken wird auf iPhone ein PageView pro Bank angezeigt
- AccountManagementView: Neue View für Multi-Bank Konten-Verwaltung (bei 1 Bank inline-Toggles in SettingsView)
- Benutzerdefinierte Kontonamen (AccountAliases): Eigene Namen für Konten vergeben, gespeichert in UserDefaults
- Auto-Update pro Bank:
BankConnection.autoUpdateEnabledstatt globalem Toggle — jede Bank einzeln steuerbar
Bugfixes¶
- 2FA-Geräteerkennung bleibt erhalten:
disconnect()undconnect()speichern den FinTS-State nur noch wenn keine TAN ausstehend war (_pending_operation is None). Verhindert, dass eine unvollständige Session (ohne Geräteerkennung) den guten State überschreibt - Multi-Bank-Session nicht mehr überschrieben:
connect()speichert die vorherige Bank-Session sauber vor dem Wechsel,BridgeManager.activeBankIdtrackt die aktive Bank und erzwingt Reconnect bei Mismatch - TAN-Skip bei stillem Refresh: Vordergrund-Rückkehr und Hintergrund-Refresh überspringen TAN-Anforderungen (
isSilentRefresh+tanApprovedBanks) - Holdings im Per-Bank-Zyklus: Holdings werden innerhalb des Refresh-Zyklus pro Bank abgerufen statt danach separat — verhindert zusätzliche Reconnects und TAN-Anforderungen
- State nach jeder Operation gespeichert:
get_balance(),get_transactions(),get_holdings()speichern den FinTS-State nach Erfolg — Geräteerkennung geht nicht mehr verloren
Verbesserungen¶
- iPad-Sidebar zeigt per-Bank-Saldo im Section-Header
disconnect()ruft kein__exit__(HKEND) mehr auf — Dialog läuft serverseitig aus, Geräteerkennung bleibt erhalten
Wartung¶
- 81/81 Tests bestanden
- CLAUDE.md auf Version 1.6.1 aktualisiert
[1.5.1] - 2026-03-06¶
Neue Features¶
- Inkrementeller Transaktions-Cache: Umsätze werden persistent in UserDefaults gespeichert (
cached_transactions_v2) und wachsen inkrementell. Neue Refreshs mergen Umsätze per Deduplizierung in den bestehenden Cache statt ihn zu ersetzen - Codable TransactionCacheEntry: Neues
TransactionCacheEntryStruct mitoldestDate,transactionsund computedcoveredDaysersetzt das alte Tuple(days: Int, transactions: [TransactionInfo]) - Auto-Update Toggle: Neuer Schalter in den Einstellungen (
autoUpdateEnabled) erlaubt dem Nutzer, automatische Aktualisierung bei Vordergrund-Rückkehr zu deaktivieren - Markdown-Tabellen im KI-Chat: ChatMessageBubble rendert Markdown-Tabellen nativ mit eigenem
MarkdownTableViewstatt als Plaintext - Persistentes Logging: BankingLog speichert Einträge in UserDefaults (max. 500, 7 Tage Retention) statt nur In-Memory
- Spracheingabe Auto-Stop: SpeechRecognitionService erkennt 2 Sekunden Stille und stoppt Aufnahme automatisch
Verbesserungen¶
- Vordergrund-Rückkehr ohne TAN: Transaktions-Cache bleibt bei Rückkehr aus Hintergrund erhalten. Phase 2 (Umsätze nachladen) wird nur ausgelöst wenn sich ein Saldo tatsächlich geändert hat — vermeidet unnötige TAN-Abfragen bei DKB
mergeIntoCache(): Dedupliziert per Transaction-ID (neue überschreiben alte), sortiert nach Datum absteigenddeleteAllData()löscht jetzt auch persistierten Transaktions-Cache
Wartung¶
- 81/81 Tests bestanden
- CLAUDE.md auf Version 1.5.1 aktualisiert (Transaktions-Cache, Zweiphasen-Refresh, Vordergrund-Rückkehr)
[1.5.0] - 2026-03-05¶
Neue Features¶
- Holdings-Cache Persistierung: Wertpapierbestände werden in UserDefaults gespeichert und überleben App-Neustarts — Depots zeigen beim Start sofort den letzten bekannten Bestand statt 0 €
- Automatischer Holdings-Abruf: Nach jedem Refresh werden Holdings aller Depot-Konten automatisch im Hintergrund abgerufen (still, sequentiell, kein Spinner)
- Depot-Saldo beim App-Start: Gecachte Holdings werden beim Kaltstart in
bankBalancesvorbelegt → korrekter Depotwert in Kontenübersicht und Widget - Holdings-Cache-Datum: DepotDetailView zeigt "Letzter Abruf: dd.MM.yyyy, HH:mm" an wenn keine Live-Holdings geladen
- Wertpapierdepot-Ansicht (DepotDetailView): Neues kompaktes Layout — Name fett über volle Breite, Gesamtwert rechts, ISIN darunter, Stückzahl + Kurs + Performance in dritter Zeile
Verbesserungen¶
- HoldingRow: Wertpapiernamen werden nicht mehr abgeschnitten —
layoutPriority,fixedSizeundtruncationMode(.tail)stellen sicher, dass bei Bedarf von rechts gekürzt wird deleteAllData()löscht jetzt auch persistierten Holdings-Cache und -Datum
Wartung¶
- 81/81 Tests bestanden
- CLAUDE.md auf Version 1.5.0 aktualisiert
[1.4.4] - 2026-03-04¶
Neue Features¶
- iPhone: Automatischer Pop-to-root bei Rückkehr aus dem Hintergrund (>30s) — Kontenübersicht mit aktualisierten Salden wird sofort angezeigt
- Netzwerk-Monitoring via
NWPathMonitor— erkennt Flugmodus und fehlende Verbindung
Bugfixes¶
- Crash im Flugmodus behoben: App prüft jetzt Netzwerkverfügbarkeit vor jedem Bank-Refresh und zeigt gecachte Daten im Offline-Modus
- iPhone: NavigationStack auf value-basierte Navigation (
AccountListDestination) umgestellt für programmatische Steuerung - Test-Target: Modulname von
BankingPal_iOSaufBankingPal_Pocketkorrigiert (81/81 Tests bestehen)
Wartung¶
- Symlink
app_packagesvon SD_Reborn-Volume auf iCloud-Hauptlaufwerk umgebogen - CLAUDE.md auf Version 1.4.4 aktualisiert
[1.4.3] - 2026-03-04¶
Wartung¶
- Interne Build-Vorbereitung (Build 78-79)
[1.4.2] - 2026-03-03¶
Neue Features¶
- Gecachte Salden beim App-Start — kein Ladescreen bei vorhandenen Daten
- Zweiphasen-Refresh: Salden sofort, Umsätze nur bei Änderungen nachladen
- Stiller Refresh nach Hintergrund-Rückkehr (>30s) ohne UI-Spinner
- Datum bei Umsatz-Stand in der Kontenübersicht
Bugfixes¶
- iPad: Race Condition bei Umsatzabruf während Refresh behoben (transactionCache-Vorbelegung)