プレイブック
支払い証明書と支払いステータス: 混同すべきではない理由 (Payment Evidence Vs Payment State)
PSPがそう言っているのが証拠です。状態はあなたが決めるものです。これら 2 つを同じレジストリに保存しておくと、回復中にどちらを信頼すればよいかがわかります。
分散型決済エンジン
一部 8 の 22
取得と完了の間のギャップを埋める一連の分散型支払いアーキテクチャ。
2 つの異なる質問、2 つの異なる記録
「PSPは何て言った?」そして「私たちは何を決めたのですか?」これらは 2 つの似た質問ですが、実際にはまったく異なります。 1 つ目の答えは証拠です。PSP からの生の Webhook、API 応答、タイムスタンプ、つまり不変のレコードです。 2 番目の答えは状態です。この証拠とビジネス ルールを組み合わせて行う決定、つまり支払い Captured またはチェックアウト Completed です。```text
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”
## 最初に説明した概念```text
📦 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.
```この違いを最も明確に示す例は次のとおりです。PSP によって送信された Webhook ペイロードが証拠です。このペイロードを読み取って `Payment.Status = Captured` を書き込むかどうかは、状態の決定によって決まります。証拠は決して変わりません。新しい証拠が到着すると、状態を更新できます。
## なぜこれら 2 つが同じテーブルに存在できないのか
一部のシステムは、PSP からの Webhook で `payments` テーブルを直接上書きします。新しい Webhook が到着すると、対応する行が更新され、古い値は失われます。この設計では、「PSP が正確に何を言ったか」という質問にはもはや答えることができません。「最後のコメントは何でしたか?」という質問にしか答えることができません。```text
Yanlış model:
payments
id | status | raw_payload
1 | Captured | {...son webhook'un içeriği, öncekiler üzerine yazıldı...}
```これは、インシデント発生時に最も役立つ情報 (過去の一連の証拠) を失うことを意味します。
## 正しいモデル: 2 つの独立したストレージ
証拠は独自の追加専用テーブルに保存されます。新しい Webhook または API 応答はそれぞれ新しい行として追加され、行は更新または削除されません。状態は、別の表の証拠に基づいて導き出された現在の決定です。```text
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ı
```この区別のおかげで、州境がいつ、なぜ変更されたかを「忘れる」ことはありません。それを生み出した証拠がまだ残っているからです。
## リカバリではなぜ状態ではなく証拠が読み取られるのでしょうか?
インシデント (ワーカーのクラッシュ、誤った配置、疑わしい不一致など) の後にシステムを「正しい」状態に戻す必要がある場合、現在の状態に依存するのは危険です。その状態がインシデントによって壊れた状態とまったく同じである可能性があるためです。代わりに、証拠ログを再読み込みして状態を再生する方が、より信頼性の高い回復方法です。```text
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
```このプロセスは、このシリーズの後半で取り上げる和解要員の基礎を形成します。つまり、国家に疑問がある場合には、常に証拠が仲裁者となります。
## 証拠を「解釈」して保管しないでください
最後の落とし穴: 一部のシステムは証拠を保存する場合でも、不必要なフィールドを削除し、形式を正規化するなど、証拠を少し「クリーンアップ」します。これにより、証拠の実際の価値 (PSP がバイトごとに正確に言ったこと) が失われます。証拠は、PSP からの回答の未加工の、変更されていないバージョンである必要があります。解釈と正規化の作業は、証拠そのものではなく、状態導出ステップに属します。
## このエピソードで最も混乱を招く対戦```text
❌ 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
証拠と状態を区別するためのチェックリスト
- PSP からの生の Webhook ペイロードは別の追加専用テーブルに保存されていますか? それとも
paymentsテーブルによって上書きされますか? - 同じ支払いに対する 2 番目または 3 番目の Webhook は最初のレコードを上書きしますか、それとも新しい証拠行が追加されますか?
- 状態の不一致の疑いがある場合、証拠ログを再生できるプロセスはありますか?
- 証拠を保管する際に「クリーニング」または正規化の手順はありますか?その場合、生データも別途保存しますか?
- State テーブルの行がどの証拠レコードから派生したかを遡及的に追跡できますか?
これら 5 つの質問のうち 1 つに「いいえ」と答えると、インシデントで「PSP は実際に何と言ったか」という質問に答えることができない可能性があります。
このセクションで覚えておくべきこと
- 証拠とは、PSP が伝える生の、不変の真実です。状態は、これらの事実とビジネス ルールを組み合わせて下す決定です。
- 証拠は追加のみである必要があります。新しい Webhook が到着すると、古い Webhook は上書きされず、新しい行が追加されます。
- 回復および調整プロセスは現在の状態に依存すべきではありません。証拠ログを再読み取りして状態を導き出す必要があります。
- 証拠を「クリーニング」して隠すと、PSP が何を言ったか正確にわからなくなります。生データは常に保護される必要があります。
状態は今日のあなたのコメントです。証拠とは、決して変わることのない証人です。事件の目撃者ではなく、自分自身の解釈に疑問を持ち始めたら、あなたは負けます。
FAQ
よくある質問
証拠とは何ですか?
外部システム (PSP) が報告する生の真実の記録。解釈や変更を加えずに保存されます。
状態とは何ですか?
第 2 章と第 4 章で説明したステート マシン内の証拠とビジネス ルールを組み合わせて行う決定。
「証拠と状態は同一線上に保持され、一方が他方を上書きすることができる」は本当ですか?
証拠は追加のみです。状態は別の表の証拠に基づいて導き出されます
このセクションでは何を修正しますか?
このセクションでは、この 2 つを同じログに保存してはいけない理由と、この区別が救助シナリオで命を救う理由について説明します。証拠とは、PSP が伝える生の、不変の真実です。状態は、これらの事実とビジネス ルールを組み合わせて下す決定です。 「PSPは何て言った?」そして「私たちは何を決めたのですか?」これらは 2 つの似た質問ですが、実際にはまったく異なります。 1 つ目の答えは証拠です。PSP からの生の Webhook、API 応答、タイムスタンプ、つまり不変のレコードです。 2 番目の答えは状態です。この証拠とビジネス ルールを組み合わせて行う決定、つまり支払い `Captured` またはチェックアウト `Completed` です。
学んだエンジニアリング原則
- 証拠は PSP の生の、不変の真実です。状態とは、その事実とビジネス ルールを組み合わせて下す決定です。この 2 つは同じ記録ではありません。
- 証拠は常に追加のみである必要があります。新しい情報は上書きされず、古い情報に追加されます。
- 救出と和解は、疑わしい状態ではなく、常に不変の証拠に依存しなければなりません。
続きを読む
続きを読む
シリーズの次のシリーズ
SDK (ソフトウェア開発キット) を漏らさないプロバイダーの抽象化: ゲートウェイの限界
プロバイダー ゲートウェイは PSP SDK をどのように所有しているのですか。なぜチェックアウト オーケストレーターはセマンティック インターフェイスのみを参照する必要があるのでしょうか?カードとウォレットの流れは異なります...
シリーズの次のシリーズ
決済システムにおける送信箱/受信箱のパターン
データベースへの書き込みとイベントのパブリッシュが同じトランザクション内にない場合、そのうちの 1 つが失われるか、繰り返されます。送信トレイのブロードキャスト、コンシューマでの受信トレイの重複排除。
同じシリーズ
生のプロバイダー データの代わりにセマンティック イベント
プロバイダー ゲートウェイによって受信された Webhook は、PSP のイベント名または PaymentCaptured/PaymentFailed などのセマンティック イベントとともにダウンストリームに到達する必要がありますか?