Playbook

Semantische Events statt roher Provider-Payloads (Semantische Events Statt Roher Provider Payloads)

Sollte der Webhook, den das Provider-Gateway empfängt, mit dem eigenen Event-Namen des PSP weitergegeben werden — oder als semantisches Event wie…

Verteilte Payment Engine (Distributed Payment Engine)

Teil 10 von 22

Serie zur verteilten Payment-Architektur — die Lücke zwischen Capture und Complete.

Distributed payment engine architecture diagram

Im vorherigen Teil haben wir festgelegt, dass der Orchestrator niemals ein PSP-SDK sehen sollte. Dieselbe Grenze taucht einen Schritt weiter außen wieder auf: beim Webhook, den ein Provider zurücksendet.

Ein PSP-Webhook trägt meist sein eigenes internes Datenmodell: einen providerspezifischen Event-Typ-Namen, providerspezifische Statuscodes, eine providerspezifische Objektstruktur. Diesen Payload direkt auf eine Queue oder einen Event-Stream zu legen, bedeutet, das Schema des Providers an jeden nachgelagerten Konsumenten weiterzugeben.

PSP Webhook
  { type: 'charge.succeeded', data: { object: {...} } }
      ▼
Provider Gateway (Übersetzung)
      ▼
Semantisches Event
  PaymentCaptured { paymentId, amount, currency }

Dieser Teil zeigt, warum diese Übersetzungsschicht keine Aufgabe ist, die man auslassen kann.

Wo die Begriffe zuerst auftauchen

📦 Semantisches Event
Ein Event, benannt in Geschäftssprache, ohne jeden Verweis auf den Provider: PaymentCaptured, PaymentFailed.

📦 Roher Provider-Payload
Die Originaldaten, die ein PSP im Webhook-Body sendet und die sein internes Modell tragen.

📦 Translator
Die Komponente im Gateway, die den rohen Payload liest und das semantische Event erzeugt.

📦 Event-Vertragshoheit
Wer über Felder und Bedeutung des semantischen Events entscheidet — immer das Gateway, nie der PSP.

charge.succeeded ist das interne Vokabular eines Providers; PaymentCaptured ist eine Tatsache in Ihrer Domäne. Beide ändern sich nie gleichzeitig: Der Provider kann sein Event umbenennen, Ihr semantisches Event bleibt unverändert.

Die Kosten des rohen Durchreichens

Der schnellste Integrationsweg ist es, den Webhook-Body ungeparst auf einen Broker zu legen. Kurzfristig funktioniert das — der Konsument parst denselben Payload. Aber jede Schemaänderung des Providers pflanzt sich damit direkt zu jedem Konsumenten fort. Wenn ein PSP ein Feld umbenennt, brechen mehrere Systeme gleichzeitig — ausgelöst durch ein Ereignis, das außerhalb Ihrer Kontrolle liegt.

Bei rohem Payload
  PSP-Schemaänderung → N Konsumenten gleichzeitig betroffen

Bei semantischem Event
  PSP-Schemaänderung → nur der Translator im Gateway muss angepasst werden

Was der Translator tut — und was nicht

Der Translator bildet providerspezifische Statuscodes auf ein semantisches Enum ab, normalisiert inkonsistente oder fehlende Felder und ergänzt bei Bedarf Daten (Betrag, Währung) aus dem lokalen Datensatz. Was er niemals tun darf: eine Geschäftsentscheidung treffen. 'Warum ist diese Zahlung fehlgeschlagen, was passiert jetzt' ist Aufgabe des Orchestrators, nicht des Translators.

Webhook trifft ein
  → Provider-Event-Typ lesen
  → Status-Mapping-Tabelle nachschlagen
  → semantisches Event erzeugen
  → mit lokaler ID korrelieren
  → veröffentlichen (via Outbox)

Eine Mapping-Tabelle ist ein konkretes Entwurfsartefakt

Ein Provider kann Dutzende Event-Typen anbieten; Ihre semantische Event-Menge sollte deutlich kleiner und stabiler bleiben.

Provider-Event Semantisches Event
charge.succeeded PaymentCaptured
charge.failed PaymentFailed
charge.dispute.created PaymentDisputed
payment_intent.requires_action PaymentActionRequired

Diese Tabelle sollte im Code-Review lesbar sein; bei einem neuen Provider-Event sollte 'welchem semantischen Event entspricht das' eine Einzeiler-Entscheidung sein, keine über die Codebasis verteilte if-else-Kette.

Reihenfolge und Mehrfachzustellung gelten weiterhin

Der Translator muss auch doppelte oder nicht geordnete Webhooks behandeln. Ein Provider kann denselben Webhook nach einem Netzwerkfehler erneut senden; die Erzeugung des semantischen Events muss deshalb idempotent sein — dieselbe Webhook-ID darf bei zweitem Eintreffen nicht dasselbe semantische Event erneut veröffentlichen (oder nachgelagerte Systeme müssen ohnehin idempotent sein).

Häufig verwechselte Unterschiede

❌ Webhook = Event
✓ Ein Webhook ist ein Benachrichtigungsauslöser; ein semantisches Event ist eine Tatsache in Geschäftssprache

❌ Den rohen Payload zu speichern ist unnötig
✓ Der rohe Payload wird für Diagnosen aufbewahrt, aber nur im eigenen Archiv des Gateways

❌ Die Mapping-Tabelle wird einmal geschrieben und ist fertig
✓ Sobald der Provider neue Event-Typen hinzufügt, ist die Tabelle ein lebender Vertrag

Rohes Durchreichen vs. semantische Übersetzung

Kriterium Rohes Durchreichen Semantische Übersetzung
Provider-Wissen nachgelagert nötig ja nein
Anfälligkeit bei Schemaänderung hoch niedrig
Rohdaten für Diagnose können verloren gehen im Gateway aufbewahrt
Neuen PSP hinzufügen betrifft Konsumenten betrifft nur die Mapping-Tabelle

Checkliste beim Entwurf des Translators

  1. Liest irgendein nachgelagerter Konsument einen providerspezifischen Feldnamen oder Statuscode?
  2. Ist die Mapping-Tabelle an einer Stelle definiert oder über die Codebasis verteilt?
  3. Wird der rohe Webhook-Payload im Gateway für Diagnosen archiviert?
  4. Wird bei zweifachem Eintreffen desselben Webhooks dasselbe semantische Event zweimal veröffentlicht?
  5. Was passiert bei einem noch nicht gemappten Provider-Event — wird es stillschweigend verschluckt oder erzeugt es einen sichtbaren Alarm?

Die fünfte Frage ist besonders wichtig: stillschweigend verschluckte unbekannte Events sind eine der leisesten Formen von Datenverlust in Produktion.

Was bleiben soll

  1. Nachgelagerte Systeme sollten niemals den Event-Namen oder Statuscode des Providers sehen.
  2. Der Translator ist eine Mapping-Tabelle plus Normalisierungslogik — er trifft keine Geschäftsentscheidung.
  3. Der rohe Payload wird für Diagnosen aufbewahrt, bleibt aber innerhalb der Grenze des Gateways.
  4. Nicht gemappte Provider-Events dürfen niemals stillschweigend verschluckt werden.

Der einfachste Test, ob ein Event wirklich semantisch ist: Sie können seinen Namen aus Ihrem eigenen Domänen-Glossar lesen, nicht aus der Dokumentation des Providers.

Der nächste Teil vertieft die Fehlerinformation, die diese semantischen Events tragen: Nicht jedes PaymentFailed bedeutet dasselbe — wir brauchen eine Taxonomie.

FAQ

Häufige Fragen

Was ist Semantisches Event?

Ein Event, benannt in Geschäftssprache, ohne jeden Verweis auf den Provider: PaymentCaptured, PaymentFailed.

Was ist Roher Provider-Payload?

Die Originaldaten, die ein PSP im Webhook-Body sendet und die sein internes Modell tragen.

Stimmt es, dass „Webhook = Event“?

Ein Webhook ist ein Benachrichtigungsauslöser; ein semantisches Event ist eine Tatsache in Geschäftssprache

Was legt dieser Teil fest?

Dieser Teil zeigt, warum diese Übersetzungsschicht keine Aufgabe ist, die man auslassen kann. Nachgelagerte Systeme sollten niemals den Event-Namen oder Statuscode des Providers sehen. Im vorherigen Teil haben wir festgelegt, dass der Orchestrator niemals ein PSP-SDK sehen sollte. Dieselbe Grenze taucht einen Schritt weiter außen wieder auf: beim Webhook, den ein Provider zurücksendet.

Gelernte Engineering-Prinzipien

  • Nachgelagerte Systeme sehen die Tatsache Ihrer Domäne, nie den Event-Namen des Providers.
  • Eine Mapping-Tabelle ist ein lebender Vertrag, kein einmaliger Codeschnipsel.
  • Ein nicht gemapptes Provider-Event muss sichtbar sein, niemals stillschweigend verschluckt werden.

Weiterlesen

Weiterlesen

Nachster Teil der Serie

ESSAY

Ein Timeout, ein 429, ein 5xx, eine Business-Ablehnung und ein Infrastrukturfehler sind nicht dasselbe. Jede Kategorie braucht ihre eigene Retry-Strategie.

Nachster Teil der Serie

Aus derselben Serie

ESSAY

Beleg (Evidence) ist, was der PSP sagte. Status (State) ist, was Sie entschieden haben. Vermischen Sie beide, weiß die Wiederherstellung nicht, wem sie…

Paylaş