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.

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:

  1. Der Tap auf dem Mikrofon-Bus wurde vor dem Installieren nie entfernt. Nach einem gescheiterten Start wirft der nächste installTap eine Ausnahme aus dem Audio-Framework, die sich in Swift nicht abfangen lässt. Daher „manchmal muss man es mehrfach machen".
  2. Hält die Sprachsteuerung das Mikrofon, liefert der Eingang ein leeres Format (0 Hz, 0 Kanäle) — installTap prüft das nicht und beendet den Prozess.
  3. 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


[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

Wallet

Banking und Überweisungen

Lokal und KI

Datenschutz

Tests und Doku

Offen


[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

PaSO/SCA-Korrektheit (Build 401)

UX

Doku

Metadaten


[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

iOS 26 Liquid Glass UI-Redesign

KI-Assistent ausgebaut

Infrastruktur

Aus dem Banking-Track v1.13.x übernommen (im Merge erhalten)

Anforderungen nach Merge

Doku & Repo


[2.0.0] - 2026-05-02

EUDIPal-Pivot: erste TestFlight-fähige Version unter neuem Branding und neuem Bundle-ID-Schema.

Rebranding & Identifier

EUDI-Wallet-Schicht (Phase 0)

TestFlight-Vorbereitungen

UX

Doku & Repo


[1.13.1] - 2026-05-02

Bugfixes

Verbesserungen

Wartung


[1.13.0] - 2026-05-02

Neue Features

Bugfixes

Wartung


[1.12.2] - 2026-05-01

Verbesserungen

Wartung

[1.12.1] - 2026-04-29

Bugfixes

Performance

Verbesserungen


[1.12.0] - 2026-04-29

Neue Features

Verbesserungen am Categorizer

UX-Verbesserungen

Bugfixes / Konsistenz

[1.11.0] - 2026-04-28

Neue Features

Verbesserungen

Bugfixes

Architektur

Wartung

[1.10.5] - 2026-04-28

Verbesserungen

Wartung

[1.10.4] - 2026-04-28

Bugfixes

Wartung

[1.10.3] - 2026-04-28

Neue Features

Architektur

Wartung

[1.10.2] - 2026-04-28

Bugfixes

Verbesserungen

Wartung

[1.10.0] - 2026-04-22

Neue Features

Bugfixes (bereits in 1.9.1–1.9.8 ausgerollt, im 1.10.0-Release gebündelt enthalten)

Wartung

[1.9.0] - 2026-04-11

Neue Features

Bugfixes

Wartung

[1.8.5] - 2026-04-07

Neue Features

Wartung

[1.8.4] - 2026-04-04

Bugfixes

Neue Features

Wartung

[1.8.3] - 2026-03-25

Bugfixes

Neue Features

Code-Qualität

[1.8.0] - 2026-03-14

Neue Features

Bugfixes

Verbesserungen

Wartung

[1.7.1] - 2026-03-12

Neue Features

Verbesserungen

Wartung

[1.6.1] - 2026-03-06

Neue Features

Bugfixes

Verbesserungen

Wartung

[1.5.1] - 2026-03-06

Neue Features

Verbesserungen

Wartung

[1.5.0] - 2026-03-05

Neue Features

Verbesserungen

Wartung

[1.4.4] - 2026-03-04

Neue Features

Bugfixes

Wartung

[1.4.3] - 2026-03-04

Wartung

[1.4.2] - 2026-03-03

Neue Features

Bugfixes