Oyun Kitabı
Ham Sağlayıcı Verisi Yerine Anlamsal Olay (Semantic Event) (Ham Provider Payload Yerine Semantik Event)
Provider gateway'in aldığı webhook, downstream'e PSP'nin event adıyla mı, yoksa PaymentCaptured/PaymentFailed gibi semantik bir olayla mı ulaşmalı?
Dağıtık Ödeme Motoru (Distributed Payment Engine)
Bolum 10 / 22
Capture ile complete arasındaki boşluğu kapatan dağıtık ödeme mimarisi serisi.
Önceki bölümde orchestrator'ın PSP SDK'sını hiç görmemesi gerektiğini gördük. Aynı sınır, senkron çağrının bir adım ötesinde tekrar karşımıza çıkar: provider'dan gelen webhook.
Bir PSP webhook'u genellikle kendi iç veri modelini taşır: provider'a özgü event tipi adı, provider'a özgü statü kodları, provider'a özgü nesne yapısı. Bu payload'ı olduğu gibi mesaj kuyruğuna veya event akışına koymak, provider'ın şemasını tüm downstream tüketicilere sızdırmak demektir.
PSP Webhook
{ type: 'charge.succeeded', data: { object: {...} } }
▼
Provider Gateway (çeviri)
▼
Semantik event
PaymentCaptured { paymentId, amount, currency }
Bu bölüm, çeviri katmanının neden ihmal edilemeyecek bir sorumluluk olduğunu ele alıyor.
Kavramlar ilk geçtiği yerde
📦 Semantik Event
İş diliyle adlandırılmış, provider'a hiç referans vermeyen olay: PaymentCaptured, PaymentFailed.
📦 Ham Provider Payload
PSP'nin webhook body'sinde gönderdiği, kendi iç modelini taşıyan orijinal veri.
📦 Çeviri Katmanı (Translator)
Ham payload'ı okuyup semantik event'e dönüştüren, gateway içinde yaşayan bileşen.
📦 Event Sözleşmesi Sahipliği
Semantik event'in alanlarını ve anlamını kimin belirlediği; burada her zaman gateway.
charge.succeeded bir provider'ın kendi iç terminolojisidir; PaymentCaptured ise sizin domain'inizin gerçeğidir. İkisi aynı anda değişmez: provider event adını değiştirebilir, semantik event adı sabit kalır.
Ham payload'ı olduğu gibi taşımanın maliyeti
En hızlı entegrasyon yolu, webhook body'sini ayrıştırmadan mesaj broker'ına basmaktır. Kısa vadede çalışır: tüketici de aynı payload'ı ayrıştırır. Fakat bu, provider'ın şema değişikliklerini her tüketiciye doğrudan yayar. PSP bir alanın adını değiştirdiğinde, sizin kontrolünüzde olmayan bir olay, sizin sistemlerinizin çoğunda aynı anda kırılma yaratır.
Ham payload yayılırsa
PSP şema değişikliği → N tüketici aynı anda etkilenir
Semantik event yayılırsa
PSP şema değişikliği → sadece gateway'in çeviri katmanı güncellenir
Çeviri katmanı ne yapar, ne yapmaz
Çeviri katmanı, provider'a özgü statü kodlarını semantik bir enum'a eşler, tutarsız veya eksik alanları normalize eder, gerekliyse eksik veriyi (örneğin tutar, para birimi) local kayıttan tamamlar. Yapmaması gereken şey, iş kararı vermektir: 'Bu ödeme neden başarısız oldu, ne yapılmalı' sorusunun cevabı orchestrator'ın işidir, çeviri katmanının değil.
Webhook geldi
→ provider event tipini oku
→ statü eşleme tablosuna bak
→ semantik event oluştur
→ local correlation id ile eşle
→ yayınla (Outbox üzerinden)
Eşleme tablosu somut bir tasarım aracıdır
Provider'ın onlarca event tipi olabilir; sizin semantik event kümeniz çok daha küçük ve stabil olmalıdır.
| Provider event | Semantik event |
|---|---|
| charge.succeeded | PaymentCaptured |
| charge.failed | PaymentFailed |
| charge.dispute.created | PaymentDisputed |
| payment_intent.requires_action | PaymentActionRequired |
Bu tablo kod incelemesinde okunabilir olmalı; yeni bir provider event'i geldiğinde 'bu hangi semantik event'e karşılık gelir' sorusu bir satırlık bir karar olmalı, kod tabanına dağılmış bir if-else zinciri değil.
Sıra ve tekrar teslim garantisi hâlâ geçerli
Çeviri katmanı, webhook'un mükerrer geldiği veya sıra dışı geldiği senaryoları da ele almalıdır. Provider aynı webhook'u ağ hatası nedeniyle iki kez gönderebilir; semantik event üretilirken bu, event üretiminin idempotent olmasını gerektirir — aynı webhook id'si ikinci kez geldiğinde aynı semantik event yeniden yayınlanmamalıdır (veya downstream idempotent olarak tasarlanmalıdır).
Sık karıştırılan ayrımlar
❌ Webhook = Event
✓ Webhook bir bildirim tetikleyicisidir; semantik event iş dilindeki gerçektir
❌ Ham payload'ı saklamak gereksizdir
✓ Ham payload tanılama için saklanır, ama yalnızca gateway'in kendi arşivinde
❌ Eşleme tablosu bir kere yazılır, bitmiştir
✓ Provider yeni event tipleri ekledikçe tablo canlı bir sözleşmedir
Ham geçiş ile semantik çeviri
| Kriter | Ham geçiş | Semantik çeviri |
|---|---|---|
| Downstream'in provider bilgisi | Gerekli | Gereksiz |
| Şema değişikliğine kırılganlık | Yüksek | Düşük |
| Tanılama için ham veri | Kaybolabilir | Gateway'de saklanır |
| Yeni PSP eklemek | Tüketicileri etkiler | Sadece eşleme tablosunu etkiler |
Çeviri katmanını tasarlarken kontrol listesi
- Downstream tüketicilerin herhangi biri provider'a özgü bir alan adı veya statü kodu okuyor mu?
- Eşleme tablosu tek bir yerde mi tanımlı, yoksa kod tabanına dağılmış mı?
- Ham webhook payload'ı, tanılama için gateway'in kendi arşivinde saklanıyor mu?
- Aynı webhook iki kez geldiğinde aynı semantik event iki kez mi yayınlanıyor?
- Yeni bir provider event tipi geldiğinde, henüz eşlenmemişse ne olur — sessizce yutulur mu, yoksa görünür bir uyarı mı üretir?
Beşinci soru özellikle önemlidir: sessizce yutulan bilinmeyen event'ler, üretimde en sinsi veri kaybı biçimlerinden biridir.
Bu yazıdan aklında ne kalmalı
- Downstream hiçbir zaman provider'ın event adını veya statü kodunu görmemelidir.
- Çeviri katmanı bir eşleme tablosu ve normalize etme mantığıdır, iş kararı vermez.
- Ham payload tanılama için saklanır ama yalnızca gateway'in kendi sınırında kalır.
- Bilinmeyen provider event'leri sessizce yutulmamalı, görünür bir sinyal üretmelidir.
Bir event'in semantik olup olmadığını anlamanın en kolay yolu: adını provider'ın belgelerinden değil, kendi domain sözlüğünüzden okuyabiliyor olmanızdır.
Bir sonraki bölümde bu semantik event'lerin taşıdığı başarısızlık bilgisini derinleştiriyoruz: her PaymentFailed aynı anlama gelmez, bir hata taksonomisine ihtiyacımız var.
SSS
Sık sorulan sorular
Semantik Event nedir?
İş diliyle adlandırılmış, provider'a hiç referans vermeyen olay: PaymentCaptured, PaymentFailed.
Ham Provider Payload nedir?
PSP'nin webhook body'sinde gönderdiği, kendi iç modelini taşıyan orijinal veri.
"Webhook = Event" doğru mu?
Webhook bir bildirim tetikleyicisidir; semantik event iş dilindeki gerçektir
Bu bölüm neyi sabitler?
Bu bölüm, çeviri katmanının neden ihmal edilemeyecek bir sorumluluk olduğunu ele alıyor. Downstream hiçbir zaman provider'ın event adını veya statü kodunu görmemelidir. Önceki bölümde orchestrator'ın PSP SDK'sını hiç görmemesi gerektiğini gördük. Aynı sınır, senkron çağrının bir adım ötesinde tekrar karşımıza çıkar: provider'dan gelen webhook.
Ogrenilen Muhendislik Prensipleri
- Downstream provider'ın event adını değil, sizin domain'inizin gerçeğini görmelidir.
- Eşleme tablosu canlı bir sözleşmedir, bir kerelik kod değil.
- Bilinmeyen provider event'i sessizce yutulmamalı, görünür olmalı.
Okumaya devam et
Okumaya devam et
Seride sonraki yazi
Ödeme Hata Taksonomisi
Timeout, 429, 5xx, business decline ve infrastructure hatası aynı şey değildir. Her kategori farklı bir retry politikası ister.
Seride sonraki yazi
SDK (Software Development Kit) Sızdırmadan Provider Abstraction: Gateway'in Sınırı
Provider gateway PSP SDK'sını nasıl sahiplenir, checkout orchestrator neden yalnızca semantik bir arayüz görmelidir? Kart ve wallet akışlarının farklı…
Ayni seriden
Ödeme Kanıtı ve Ödeme Durumu: Neden Karıştırmamalısınız?
Evidence, PSP'nin ne dediğidir. State, sizin ne karar verdiğinizdir. Bu ikisini aynı kayıtta tutarsanız, kurtarma sırasında hangisine güveneceğinizi…