Oyun Kitabı
Ödeme Kanıtı ve Ödeme Durumu: Neden Karıştırmamalısınız? (Odeme Kaniti Ve Odeme Durumu)
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…
Dağıtık Ödeme Motoru (Distributed Payment Engine)
Bolum 8 / 22
Capture ile complete arasındaki boşluğu kapatan dağıtık ödeme mimarisi serisi.
İki farklı soru, iki farklı kayıt
“PSP ne dedi?” ve “biz ne karar verdik?” birbirine benzeyen ama aslında tamamen farklı iki sorudur. Birincisinin cevabı evidence'tır (kanıt): PSP'den gelen ham webhook, API cevabı, zaman damgası — değiştirilemez bir kayıt. İkincisinin cevabı state'tir (durum): sizin bu kanıtları ve iş kurallarınızı birleştirerek verdiğiniz karar — payment Captured mı, checkout Completed mı.
Evidence (kanıt) State (durum)
PSP'nin ham cevabı → Sizin kararınız
Değişmez, append-only → Değişebilir, karar tablosu
“Ne oldu” → “Biz ne yaptık”
Bu bölüm, bu ikisini neden asla aynı kayıtta tutmamanız gerektiğini ve kurtarma senaryolarında bu ayrımın neden hayat kurtardığını anlatıyor.
Kavramlar ilk geçtiği yerde
📦 Evidence (Kanıt)
Dış sistemin (PSP) size bildirdiği ham gerçeğin, yorumlanmadan ve değiştirilmeden saklanan kaydı.
📦 State (Durum)
Evidence'ları ve iş kurallarını birleştirerek sizin verdiğiniz, ikinci ve dördüncü bölümde tanımladığımız durum makinesindeki karar.
📦 Append-only Log
Sadece ekleme yapılan, mevcut kayıtların asla üzerine yazılmadığı veya silinmediği depolama şekli.
📦 Source of Truth vs. Derived Truth
Birincisi ham, tartışmasız gerçek; ikincisi bu gerçekten türetilen, yorum içeren karar.
📦 Reconciliation
Evidence kayıtlarını tekrar okuyup, mevcut state'in bu kanıtlarla hâlâ tutarlı olup olmadığını doğrulama süreci.
Bu ayrımı en açık gösteren örnek şudur: PSP'nin gönderdiği webhook payload'ı bir evidence'tır; sizin bu payload'ı okuyup Payment.Status = Captured yazmanız bir state kararıdır. Evidence hiç değişmez; state, yeni evidence geldiğinde güncellenebilir.
Neden bu ikisi aynı tabloda yaşayamaz
Bazı sistemler, PSP'den gelen webhook'u doğrudan payments tablosunun üzerine yazar: yeni bir webhook gelince ilgili satır güncellenir, eski değer kaybolur. Bu tasarımda “PSP tam olarak ne söylemişti” sorusuna artık cevap veremezsiniz — sadece “son yorumumuz neydi” sorusuna cevap verebilirsiniz.
Yanlış model:
payments
id | status | raw_payload
1 | Captured | {...son webhook'un içeriği, öncekiler üzerine yazıldı...}
Bu, bir incident sırasında en çok işinize yarayacak bilgiyi (geçmiş kanıt zincirini) kaybetmenizdir.
Doğru model: iki ayrı depolama
Evidence, kendi append-only tablosunda saklanır; her yeni webhook veya API cevabı yeni bir satır olarak eklenir, hiçbir satır güncellenmez veya silinmez. State ise ayrı bir tabloda, evidence'lardan türetilen güncel karardır.
payment_evidence (append-only)
id | payment_id | source | received_at | raw_payload
1 | pay_42 | psp | t1 | {...authorize...}
2 | pay_42 | psp | t2 | {...captured...}
3 | pay_42 | psp | t5 | {...captured (duplicate)...}
payments (state)
id | status
pay_42 | Captured ← evidence #2'den türetildi, #3 aynı sonucu doğruladı
Bu ayrım sayesinde, state satırı ne zaman ve neden değiştiğini asla “unutmaz” — çünkü onu üreten evidence hâlâ oradadır.
Kurtarma (recovery) neden evidence okur, state'e güvenmez
Bir incident sonrası (örneğin bir worker crash'i, bir yanlış deploy, bir şüpheli tutarsızlık) sisteminizi “doğru” duruma geri getirmeniz gerektiğinde, mevcut state'e güvenerek ilerlemek risklidir — çünkü state, tam olarak incident'ın bozduğu şey olabilir. Bunun yerine, evidence log'unu baştan okuyup state'i yeniden türetmek (replay) daha güvenilir bir kurtarma yoludur.
Recovery süreci
1. payment_evidence tablosundan pay_42'ye ait tüm kayıtları zaman sırasına göre oku
2. Her evidence'ı iş kurallarına göre tekrar işle (guard'lardan geçir)
3. Sonuçta türeyen state'i mevcut payments tablosundaki değerle karşılaştır
4. Fark varsa, hangisi doğru olduğunu evidence'a dayanarak belirle — state'e değil
Bu süreç, bu serinin ileri bölümlerinde ele alacağımız reconciliation worker'larının temelini oluşturur: state şüpheliyse, evidence her zaman hakemdir.
Evidence'ı asla “yorumlanmış” saklamayın
Son bir tuzak: bazı sistemler evidence'ı saklarken bile onu biraz “temizler” — gereksiz alanları siler, formatı normalize eder. Bu, evidence'ın asıl değerini (PSP'nin tam olarak ne söylediğini, byte byte) kaybettirir. Evidence, PSP'nin size verdiği cevabın ham, değiştirilmemiş hali olmalıdır; yorumlama ve normalize etme işi state türetme adımına aittir, evidence'ın kendisine değil.
Bu bölümde en çok karışan eşleştirmeler
❌ Evidence ve state aynı satırda tutulabilir, biri diğerinin üzerine yazılabilir
✓ Evidence append-only'dir; state ayrı bir tabloda, evidence'tan türetilir
❌ Webhook payload'ını saklamadan önce “temizlemek” zararsızdır
✓ Temizlenmiş evidence, PSP'nin tam olarak ne söylediği bilgisini kaybettirir
❌ Bir incident'te mevcut state'e güvenip devam etmek en hızlı yoldur
✓ Incident sırasında state şüphelidir; evidence'tan yeniden türetmek (replay) daha güvenilirdir
❌ Evidence sadece debug/log amaçlıdır, iş kararı için gerekli değildir
✓ Evidence, reconciliation ve recovery'nin tek güvenilir kaynağıdır
Evidence/State ayrımınızı denetleme listesi
- PSP'den gelen ham webhook payload'ı, ayrı ve append-only bir tabloda mı saklanıyor, yoksa
paymentstablosunun üzerine mi yazılıyor? - Aynı payment için gelen ikinci, üçüncü webhook, ilk kaydın üzerine mi yazılıyor yoksa yeni bir evidence satırı mı ekleniyor?
- Bir state tutarsızlığı şüphesi olduğunda, evidence log'undan yeniden türetme (replay) yapabilecek bir süreciniz var mı?
- Evidence'ı saklarken herhangi bir “temizleme” veya normalize etme adımı var mı? Varsa, ham veriyi de ayrıca saklıyor musunuz?
- State tablonuzdaki bir satırın hangi evidence kaydından türetildiğini geriye dönük olarak izleyebiliyor musunuz?
Bu beş sorudan birine “hayır” diyorsanız, bir incident'te “PSP gerçekte ne demişti” sorusuna cevap veremeyebilirsiniz.
Bu bölümden aklında kalması gerekenler
- Evidence, PSP'nin size söylediği ham ve değişmez gerçektir; state, bu gerçekleri iş kurallarıyla birleştirerek sizin verdiğiniz karardır.
- Evidence append-only olmalıdır; yeni bir webhook geldiğinde eskisinin üzerine yazılmaz, yeni bir satır eklenir.
- Kurtarma ve reconciliation süreçleri mevcut state'e güvenmemeli; evidence log'unu yeniden okuyup state'i türetmelidir.
- Evidence'ı saklarken “temizlemek”, PSP'nin tam olarak ne söylediği bilgisini kaybettirir; ham veri her zaman korunmalıdır.
State, bugünkü yorumunuzdur; evidence, hiç değişmeyen tanıktır. Bir incident'te tanığı değil, kendi yorumunuzu sorgulamaya başlarsanız, kaybedersiniz.
SSS
Sık sorulan sorular
Evidence (Kanıt) nedir?
Dış sistemin (PSP) size bildirdiği ham gerçeğin, yorumlanmadan ve değiştirilmeden saklanan kaydı.
State (Durum) nedir?
Evidence'ları ve iş kurallarını birleştirerek sizin verdiğiniz, ikinci ve dördüncü bölümde tanımladığımız durum makinesindeki karar.
"Evidence ve state aynı satırda tutulabilir, biri diğerinin üzerine yazılabilir" doğru mu?
Evidence append-only'dir; state ayrı bir tabloda, evidence'tan türetilir
Bu bölüm neyi sabitler?
Bu bölüm, bu ikisini neden asla aynı kayıtta tutmamanız gerektiğini ve kurtarma senaryolarında bu ayrımın neden hayat kurtardığını anlatıyor. Evidence, PSP'nin size söylediği ham ve değişmez gerçektir; state, bu gerçekleri iş kurallarıyla birleştirerek sizin verdiğiniz karardır. “PSP ne dedi?” ve “biz ne karar verdik?” birbirine benzeyen ama aslında tamamen farklı iki sorudur. Birincisinin cevabı evidence'tır (kanıt): PSP'den gelen ham webhook, API cevabı, zaman damgası — değiştirilemez bir kayıt. İkincisinin cevabı state'tir (durum): sizin bu kanıtları ve iş kurallarınızı birleştirerek verdiğiniz karar — payment `Captured` mı, checkout `Completed` mı.
Ogrenilen Muhendislik Prensipleri
- Evidence, PSP'nin ham ve değişmez gerçeğidir; state, bu gerçeği iş kurallarıyla birleştirerek verdiğiniz karardır — ikisi aynı kayıt değildir.
- Evidence her zaman append-only olmalıdır; yeni bilgi eskisinin üzerine yazılmaz, yanına eklenir.
- Kurtarma ve reconciliation, şüpheli olan state'e değil, her zaman değişmeyen evidence'a güvenmelidir.
Okumaya devam et
Okumaya devam et
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ı…
Seride sonraki yazi
Ödeme Sistemlerinde Outbox/Inbox Pattern
Veritabanına yazmak ile event yayınlamak aynı transaction'da değilse, biri kaybolur ya da tekrarlanır. Outbox yayınlar, inbox tüketicide dedup eder.
Ayni seriden
Ham Sağlayıcı Verisi Yerine Anlamsal Olay (Semantic Event)
Provider gateway'in aldığı webhook, downstream'e PSP'nin event adıyla mı, yoksa PaymentCaptured/PaymentFailed gibi semantik bir olayla mı ulaşmalı?