[
  {
    "id": "01-system-context",
    "title": "Payment Checkout & Ledger Service — System Context",
    "layout": "context",
    "canvas": {
      "width": 1700
    },
    "colWidth": 265,
    "system": {
      "label": "Payment Checkout & Ledger Service",
      "sub": "Accept · post · settle · pay out"
    },
    "groups": [
      {
        "side": "left",
        "title": "People and merchant systems",
        "nodes": [
          {
            "id": "buyer",
            "label": "Buyer",
            "kind": "actor",
            "rel": "pays",
            "dir": "in"
          },
          {
            "id": "merchsrv",
            "label": "Merchant server",
            "kind": "external",
            "rel": "creates intent",
            "dir": "in"
          },
          {
            "id": "merchops",
            "label": "Merchant finance",
            "kind": "actor",
            "rel": "reads statements",
            "dir": "in"
          },
          {
            "id": "finops",
            "label": "Platform finance ops",
            "kind": "actor",
            "rel": "clears breaks",
            "dir": "in"
          }
        ]
      },
      {
        "side": "right",
        "title": "Money networks",
        "nodes": [
          {
            "id": "acq",
            "label": "Card acquirer",
            "kind": "external",
            "rel": "authorize"
          },
          {
            "id": "a2a",
            "label": "Account-to-account rail",
            "kind": "external",
            "rel": "collect"
          },
          {
            "id": "bank",
            "label": "Settlement bank",
            "kind": "external",
            "rel": "payout",
            "kind2": "batch",
            "icon": "fa4_bank"
          },
          {
            "id": "files",
            "label": "Settlement files",
            "kind": "external",
            "rel": "daily",
            "dir": "in",
            "kind2": "batch"
          }
        ]
      },
      {
        "side": "top",
        "title": "Oversight",
        "nodes": [
          {
            "id": "reg",
            "label": "Regulator / auditor",
            "kind": "actor",
            "rel": "evidence",
            "dir": "in"
          },
          {
            "id": "sanc",
            "label": "Sanctions screening",
            "kind": "external",
            "rel": "check"
          }
        ]
      },
      {
        "side": "bottom",
        "title": "Out of scope",
        "nodes": [
          {
            "id": "issue",
            "label": "Card issuing",
            "kind": "risk",
            "icon": false
          },
          {
            "id": "lend",
            "label": "Lending / credit",
            "kind": "risk",
            "icon": false
          },
          {
            "id": "pos",
            "label": "In-person terminals",
            "kind": "risk",
            "icon": false
          }
        ]
      }
    ],
    "note": "One country, one settlement currency, card-not-present and account-to-account only. The platform is not the network.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "02-high-level-architecture",
    "title": "High-Level Architecture — From Tap to Trial Balance",
    "layout": "flow",
    "canvas": {
      "width": 1760
    },
    "chain": true,
    "align": "top",
    "nodeWidth": 215,
    "stages": [
      {
        "title": "Accept",
        "nodes": [
          {
            "id": "edge",
            "label": "API edge",
            "kind": "integration",
            "sub": "Envoy · mTLS"
          },
          {
            "id": "idem",
            "label": "Idempotency store",
            "kind": "store",
            "sub": "Redis · 24 h keys"
          }
        ]
      },
      {
        "title": "Authorize",
        "nodes": [
          {
            "id": "intent",
            "label": "Intent service",
            "kind": "app",
            "sub": "state machine"
          },
          {
            "id": "router",
            "label": "Routing policy engine",
            "kind": "app",
            "sub": "versioned rules"
          },
          {
            "id": "adapter",
            "label": "Provider adapters",
            "kind": "integration",
            "sub": "circuit broken"
          }
        ]
      },
      {
        "title": "Record",
        "nodes": [
          {
            "id": "log",
            "label": "Durable event log",
            "kind": "queue",
            "sub": "Kafka · ordered"
          },
          {
            "id": "ledger",
            "label": "Ledger poster",
            "kind": "app",
            "sub": "double entry"
          },
          {
            "id": "book",
            "label": "Ledger",
            "kind": "store",
            "sub": "PostgreSQL · append only",
            "icon": "postgresql"
          }
        ]
      },
      {
        "title": "Resolve",
        "nodes": [
          {
            "id": "cb",
            "label": "Callback ingest",
            "kind": "integration",
            "sub": "signed · deduped"
          },
          {
            "id": "poll",
            "label": "Outcome poller",
            "kind": "app",
            "sub": "processing > 60 s"
          },
          {
            "id": "match",
            "label": "Settlement matcher",
            "kind": "app",
            "sub": "daily files"
          }
        ]
      },
      {
        "title": "Notify",
        "nodes": [
          {
            "id": "hook",
            "label": "Webhook delivery",
            "kind": "app",
            "sub": "72 h retry"
          },
          {
            "id": "proj",
            "label": "Balance projections",
            "kind": "store",
            "sub": "rebuildable"
          }
        ]
      },
      {
        "title": "Pay out",
        "nodes": [
          {
            "id": "payout",
            "label": "Payout engine",
            "kind": "app",
            "sub": "T+1 · 06:00"
          },
          {
            "id": "stmt",
            "label": "Statements",
            "kind": "app",
            "sub": "trial balance"
          }
        ]
      }
    ],
    "edges": [
      {
        "from": "intent",
        "to": "log",
        "label": "events",
        "kind": "async"
      },
      {
        "from": "cb",
        "to": "log",
        "label": "outcomes",
        "kind": "async"
      },
      {
        "from": "log",
        "to": "hook",
        "label": "fan-out",
        "kind": "async"
      },
      {
        "from": "match",
        "to": "book",
        "label": "breaks",
        "kind": "batch"
      }
    ],
    "note": "The buyer's answer comes from Accept + Authorize alone. Everything right of the event log is allowed to be slower than the buyer, and the payout run reads the ledger rather than the payment state.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "03-actors-and-journeys",
    "title": "Who This Is For, and What They Get To Do",
    "layout": "actors",
    "canvas": {
      "width": 1740
    },
    "cardWidth": 268,
    "groups": [
      {
        "title": "People paying and being paid",
        "kind": "boundary",
        "actors": [
          {
            "id": "buyer",
            "label": "Buyer at checkout",
            "sub": "12 M attempts / day peak",
            "goal": "Pay for this once, know within a second that it worked, and never see the charge twice.",
            "journeys": [
              {
                "id": "j-pay",
                "label": "Pay for an order",
                "sub": "p95 ≤ 2.5 s"
              },
              {
                "label": "Approve a step-up",
                "sub": "3-DS or UPI collect"
              },
              {
                "label": "Get money back",
                "sub": "refund"
              }
            ]
          },
          {
            "id": "merchfin",
            "label": "Merchant finance",
            "sub": "50,000 merchants",
            "goal": "Tell me what landed in my bank account today and which orders it was for, without asking anyone.",
            "journeys": [
              {
                "label": "Reconcile a payout",
                "sub": "statement"
              },
              {
                "label": "Refund a customer"
              },
              {
                "label": "Contest a chargeback"
              }
            ]
          }
        ]
      },
      {
        "title": "People building against it",
        "kind": "cloud",
        "actors": [
          {
            "id": "merchdev",
            "label": "Merchant developer",
            "sub": "the integration",
            "goal": "Get a working checkout in an afternoon, and never have to reason about a duplicate webhook.",
            "journeys": [
              {
                "id": "j-integrate",
                "label": "Integrate checkout",
                "sub": "intent + webhook"
              },
              {
                "label": "Replay missed events",
                "sub": "catch-up API"
              },
              {
                "label": "Test a failure path",
                "sub": "sandbox"
              }
            ]
          }
        ]
      },
      {
        "title": "People keeping it honest",
        "kind": "trust",
        "actors": [
          {
            "id": "finops",
            "label": "Platform finance ops",
            "sub": "~40 breaks / day",
            "goal": "Close the day with the books balanced, and know the name of every rupee I cannot explain.",
            "journeys": [
              {
                "id": "j-close",
                "label": "Close the day",
                "sub": "trial balance"
              },
              {
                "label": "Clear a break",
                "sub": "dual control"
              },
              {
                "label": "Release a held payout"
              }
            ]
          },
          {
            "id": "support",
            "label": "Support agent",
            "kind": "actor",
            "sub": "masked by default",
            "goal": "Answer 'where is my money' from the record, without being able to move any of it.",
            "journeys": [
              {
                "label": "Trace one payment"
              },
              {
                "label": "Raise a refund request"
              }
            ]
          },
          {
            "id": "auditor",
            "label": "Auditor / regulator",
            "kind": "external",
            "sub": "10-year window",
            "goal": "Reconstruct what the platform believed about this payment, and when it believed it.",
            "journeys": [
              {
                "label": "Reconstruct a payment"
              },
              {
                "label": "Review privileged access"
              }
            ]
          }
        ]
      },
      {
        "title": "Machines in the cast",
        "kind": "plain",
        "actors": [
          {
            "id": "provider",
            "label": "Acquirer / rail",
            "kind": "external",
            "sub": "4 providers",
            "goal": "Receive an attempt I can process, and be believed only when I have settled it.",
            "journeys": [
              {
                "label": "Answer an authorization"
              },
              {
                "label": "Post a callback"
              },
              {
                "label": "Deliver a settlement file"
              }
            ]
          },
          {
            "id": "closejob",
            "label": "Close-of-books job",
            "kind": "platform",
            "sub": "daily 02:00",
            "goal": "Prove the ledger balances before anybody opens a dashboard.",
            "journeys": [
              {
                "label": "Produce the trial balance"
              },
              {
                "label": "Age the break account"
              }
            ]
          }
        ]
      }
    ],
    "note": "Three journeys are mapped next: the buyer who pays, the developer who integrates, and the finance operator who closes the day.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "04-journey-buyer-pays",
    "title": "Journey — The Buyer Pays",
    "layout": "journey",
    "canvas": {
      "width": 1740
    },
    "actor": {
      "label": "Buyer at checkout",
      "sub": "mobile web, patchy network",
      "goal": "Pay once and be told it worked",
      "trigger": "Pressing Pay now on a basket they already decided to buy",
      "success": "An order confirmation, and exactly one line on their bank statement"
    },
    "phases": [
      {
        "title": "Press Pay",
        "sub": "intent created"
      },
      {
        "title": "Choose how",
        "sub": "card or UPI"
      },
      {
        "title": "Prove it is them",
        "moment": true
      },
      {
        "title": "Wait for the rail",
        "moment": true
      },
      {
        "title": "See the outcome",
        "moment": true
      },
      {
        "title": "Ask for it back",
        "sub": "days later"
      }
    ],
    "lanes": [
      {
        "title": "What they do",
        "kind": "step",
        "cells": [
          [
            {
              "label": "Taps Pay now"
            }
          ],
          [
            {
              "label": "Picks a method"
            },
            {
              "label": "Enters details"
            }
          ],
          [
            {
              "label": "Approves in bank app"
            }
          ],
          [
            {
              "label": "Waits on a spinner"
            }
          ],
          [
            {
              "label": "Reads the result",
              "icon": false
            }
          ],
          [
            {
              "label": "Requests a refund",
              "icon": false
            }
          ]
        ]
      },
      {
        "title": "What the platform does",
        "kind": "system",
        "cells": [
          [
            {
              "label": "Create intent",
              "kind": "app"
            },
            {
              "label": "Idempotency key",
              "kind": "store"
            }
          ],
          [
            {
              "label": "Tokenise card",
              "kind": "security"
            },
            {
              "label": "Route to provider",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Step-up orchestration",
              "kind": "app"
            }
          ],
          [
            {
              "label": "8 s provider deadline",
              "kind": "integration"
            },
            {
              "label": "Poll on unknown",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Post to ledger",
              "kind": "store"
            },
            {
              "label": "Webhook merchant",
              "kind": "queue"
            }
          ],
          [
            {
              "label": "Refund object",
              "kind": "app"
            }
          ]
        ]
      },
      {
        "title": "How it feels",
        "kind": "emotion",
        "levels": [
          "Confident",
          "Fine",
          "Anxious"
        ],
        "points": [
          1,
          1,
          2,
          2,
          0,
          1
        ]
      },
      {
        "title": "Where it hurts",
        "kind": "pain",
        "cells": [
          [],
          [],
          [
            {
              "label": "Redirect loses the basket"
            }
          ],
          [
            {
              "label": "Spinner with no deadline"
            },
            {
              "label": "Double tap on timeout"
            }
          ],
          [
            {
              "label": "\"Pending\" means nothing"
            }
          ],
          [
            {
              "label": "Refund invisible for days"
            }
          ]
        ]
      },
      {
        "title": "What answers it",
        "kind": "gain",
        "cells": [
          [
            {
              "label": "Server-created intent"
            }
          ],
          [
            {
              "label": "No card data on merchant"
            }
          ],
          [
            {
              "label": "Intent survives redirect"
            }
          ],
          [
            {
              "label": "Idempotency key on retap"
            }
          ],
          [
            {
              "label": "Honest processing state"
            }
          ],
          [
            {
              "label": "Refund shown pending"
            }
          ]
        ]
      }
    ],
    "chain": true,
    "note": "The trough is the unknown outcome: the rail has not answered, and the buyer's instinct is to press again. Views 13, 14 and 23 answer it.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "05-journey-merchant-integrates",
    "title": "Journey — The Merchant Developer Integrates",
    "layout": "journey",
    "canvas": {
      "width": 1700
    },
    "actor": {
      "label": "Merchant developer",
      "sub": "one afternoon, no payments background",
      "goal": "A working checkout that does not double-ship goods",
      "trigger": "A ticket saying 'add payments to the new storefront'",
      "success": "Orders marked paid exactly once, from events, with no polling cron"
    },
    "phases": [
      {
        "title": "Read and key",
        "sub": "credentials"
      },
      {
        "title": "First payment",
        "sub": "sandbox"
      },
      {
        "title": "Receive events",
        "moment": true
      },
      {
        "title": "Handle the unhappy path",
        "moment": true
      },
      {
        "title": "Go live",
        "sub": "production keys"
      }
    ],
    "lanes": [
      {
        "title": "What they do",
        "kind": "step",
        "cells": [
          [
            {
              "label": "Gets test keys"
            }
          ],
          [
            {
              "label": "Creates an intent"
            },
            {
              "label": "Confirms it client-side"
            }
          ],
          [
            {
              "label": "Writes a webhook handler"
            }
          ],
          [
            {
              "label": "Simulates a decline"
            },
            {
              "label": "Replays an event"
            }
          ],
          [
            {
              "label": "Swaps the key"
            }
          ]
        ]
      },
      {
        "title": "What the platform gives",
        "kind": "system",
        "cells": [
          [
            {
              "label": "Publishable + secret key",
              "kind": "security"
            }
          ],
          [
            {
              "label": "Intent API",
              "kind": "integration"
            },
            {
              "label": "Client secret",
              "kind": "security"
            }
          ],
          [
            {
              "label": "Signed webhook",
              "kind": "queue"
            },
            {
              "label": "Per-object sequence",
              "kind": "app"
            }
          ],
          [
            {
              "label": "Sandbox failure modes",
              "kind": "platform"
            },
            {
              "label": "Replay API",
              "kind": "integration"
            }
          ],
          [
            {
              "label": "Same contract, real rails",
              "kind": "app",
              "icon": false
            }
          ]
        ]
      },
      {
        "title": "How it feels",
        "kind": "emotion",
        "levels": [
          "In control",
          "Fine",
          "Lost"
        ],
        "points": [
          1,
          0,
          2,
          1,
          1
        ]
      },
      {
        "title": "Where it hurts",
        "kind": "pain",
        "cells": [
          [],
          [],
          [
            {
              "label": "Duplicate webhook ships twice"
            },
            {
              "label": "Events arrive out of order"
            }
          ],
          [
            {
              "label": "No way to test unknown"
            }
          ],
          []
        ]
      },
      {
        "title": "What answers it",
        "kind": "gain",
        "cells": [
          [
            {
              "label": "Scoped, revocable keys"
            }
          ],
          [
            {
              "label": "Intent, not a raw charge"
            }
          ],
          [
            {
              "label": "Sequence number per object"
            },
            {
              "label": "At-least-once, stated"
            }
          ],
          [
            {
              "label": "Injectable unknown outcome"
            }
          ],
          [
            {
              "label": "No code change to go live"
            }
          ]
        ]
      }
    ],
    "chain": true,
    "note": "The platform promises at-least-once delivery and says so. The sequence number is what lets a naive handler be correct anyway.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "06-journey-finance-closes-the-day",
    "title": "Journey — Finance Ops Closes the Day",
    "layout": "journey",
    "canvas": {
      "width": 1700
    },
    "actor": {
      "label": "Platform finance ops",
      "sub": "two people, 12 M payments a day",
      "goal": "Close with the books balanced and every unexplained rupee named",
      "trigger": "The 02:00 close-of-books job finishing",
      "success": "A balanced trial balance, and a break list that is shorter than yesterday's"
    },
    "phases": [
      {
        "title": "Files arrive",
        "sub": "30 provider files"
      },
      {
        "title": "Match",
        "sub": "automatic"
      },
      {
        "title": "Look at the breaks",
        "moment": true
      },
      {
        "title": "Correct",
        "moment": true
      },
      {
        "title": "Release payouts",
        "sub": "06:00"
      }
    ],
    "lanes": [
      {
        "title": "What they do",
        "kind": "step",
        "cells": [
          [
            {
              "label": "Checks file arrival"
            }
          ],
          [
            {
              "label": "Reads the match rate"
            }
          ],
          [
            {
              "label": "Triages the break list"
            },
            {
              "label": "Asks the provider"
            }
          ],
          [
            {
              "label": "Raises a correction"
            },
            {
              "label": "Gets a second approver"
            }
          ],
          [
            {
              "label": "Confirms the payout run"
            }
          ]
        ]
      },
      {
        "title": "What the platform does",
        "kind": "system",
        "cells": [
          [
            {
              "label": "Idempotent ingest",
              "kind": "app",
              "icon": false
            },
            {
              "label": "Late-file alarm",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "Matcher",
              "kind": "app"
            },
            {
              "label": "Break account",
              "kind": "store"
            }
          ],
          [
            {
              "label": "Break ageing > 48 h",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "Dual-control journal",
              "kind": "security"
            },
            {
              "label": "Opposite entry only",
              "kind": "store"
            }
          ],
          [
            {
              "label": "Payout engine",
              "kind": "app"
            },
            {
              "label": "Sanctions hold",
              "kind": "security"
            }
          ]
        ]
      },
      {
        "title": "How it feels",
        "kind": "emotion",
        "levels": [
          "Calm",
          "Fine",
          "Exposed"
        ],
        "points": [
          1,
          0,
          2,
          1,
          0
        ]
      },
      {
        "title": "Where it hurts",
        "kind": "pain",
        "cells": [
          [
            {
              "label": "A file is late or restated"
            }
          ],
          [],
          [
            {
              "label": "Break with no provider contact"
            }
          ],
          [
            {
              "label": "Temptation to edit an entry"
            }
          ],
          []
        ]
      },
      {
        "title": "What answers it",
        "kind": "gain",
        "cells": [
          [
            {
              "label": "Re-runnable ingest"
            }
          ],
          [
            {
              "label": "Nothing discarded, ever"
            }
          ],
          [
            {
              "label": "Aged, owned, alarmed"
            }
          ],
          [
            {
              "label": "Append-only, dual control"
            }
          ],
          [
            {
              "label": "No human in the happy path"
            }
          ]
        ]
      }
    ],
    "chain": true,
    "note": "The trough is a break nobody can explain. The architecture's answer is that it is still on the books, named, aged and owned — never netted away.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "07-layered-architecture",
    "title": "Layered Architecture",
    "layout": "bands",
    "canvas": {
      "width": 1740
    },
    "layerHeaderWidth": 158,
    "bands": [
      {
        "name": "Clients",
        "nodes": [
          {
            "id": "ck",
            "label": "Checkout SDK",
            "kind": "external",
            "sub": "buyer browser"
          },
          {
            "id": "ms",
            "label": "Merchant server",
            "kind": "external"
          },
          {
            "id": "dash",
            "label": "Merchant dashboard",
            "kind": "app"
          },
          {
            "id": "ops",
            "label": "Finance ops console",
            "kind": "app"
          }
        ]
      },
      {
        "name": "Edge",
        "nodes": [
          {
            "id": "gw",
            "label": "API gateway",
            "kind": "integration",
            "sub": "Envoy · mTLS",
            "icon": "envoy"
          },
          {
            "id": "au",
            "label": "Credential auth",
            "kind": "security",
            "sub": "scoped keys"
          },
          {
            "id": "ik",
            "label": "Idempotency keys",
            "kind": "store",
            "sub": "24 h"
          },
          {
            "id": "qo",
            "label": "Per-merchant quota",
            "kind": "platform",
            "sub": "fair queue"
          }
        ]
      },
      {
        "name": "Authorization",
        "nodes": [
          {
            "id": "is",
            "label": "Intent service",
            "kind": "app",
            "sub": "state machine"
          },
          {
            "id": "rt",
            "label": "Routing engine",
            "kind": "app",
            "sub": "policy vN"
          },
          {
            "id": "pa",
            "label": "Provider adapters",
            "kind": "integration"
          },
          {
            "id": "su",
            "label": "Step-up orchestration",
            "kind": "app",
            "sub": "3-DS · collect"
          }
        ]
      },
      {
        "name": "Coupling",
        "nodes": [
          {
            "id": "el",
            "label": "Durable event log",
            "kind": "queue",
            "sub": "Kafka · per-intent order"
          }
        ]
      },
      {
        "name": "Ledger",
        "nodes": [
          {
            "id": "pr",
            "label": "Posting rules",
            "kind": "app",
            "sub": "versioned"
          },
          {
            "id": "lp",
            "label": "Ledger poster",
            "kind": "app",
            "sub": "balance at write"
          },
          {
            "id": "lg",
            "label": "Ledger store",
            "kind": "store",
            "sub": "append only",
            "icon": "postgresql"
          },
          {
            "id": "cb2",
            "label": "Close of books",
            "kind": "platform",
            "sub": "trial balance"
          }
        ]
      },
      {
        "name": "Money ops",
        "nodes": [
          {
            "id": "ci",
            "label": "Callback ingest",
            "kind": "integration"
          },
          {
            "id": "op",
            "label": "Outcome poller",
            "kind": "app"
          },
          {
            "id": "sm",
            "label": "Settlement matcher",
            "kind": "app"
          },
          {
            "id": "pe",
            "label": "Payout engine",
            "kind": "app"
          },
          {
            "id": "wd",
            "label": "Webhook delivery",
            "kind": "app"
          }
        ]
      },
      {
        "name": "Projections",
        "nodes": [
          {
            "id": "bal",
            "label": "Merchant balances",
            "kind": "store",
            "sub": "rebuildable"
          },
          {
            "id": "st",
            "label": "Statements",
            "kind": "store"
          },
          {
            "id": "an",
            "label": "Analytics marts",
            "kind": "store"
          }
        ]
      },
      {
        "name": "Cross-cutting",
        "nodes": [
          {
            "id": "hsm",
            "label": "HSM key custody",
            "kind": "security",
            "icon": "fa5_key"
          },
          {
            "id": "tv",
            "label": "Token vault",
            "kind": "security",
            "sub": "PCI CDE"
          },
          {
            "id": "ad",
            "label": "Immutable audit",
            "kind": "security"
          },
          {
            "id": "ob",
            "label": "Observability",
            "kind": "platform"
          },
          {
            "id": "cf",
            "label": "Config & policy versions",
            "kind": "platform"
          }
        ]
      }
    ],
    "edges": [
      {
        "from": "gw",
        "to": "is",
        "label": "authenticated"
      },
      {
        "from": "is",
        "to": "el",
        "label": "events",
        "kind": "async"
      },
      {
        "from": "el",
        "to": "lp",
        "label": "post",
        "kind": "async"
      },
      {
        "from": "el",
        "to": "wd",
        "label": "fan-out",
        "kind": "async"
      },
      {
        "from": "lg",
        "to": "bal",
        "label": "project",
        "kind": "batch"
      },
      {
        "from": "pa",
        "to": "tv",
        "label": "detokenise"
      }
    ],
    "note": "The only path from Authorization to Ledger is the event log. No layer above Coupling writes the books directly.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "08-platform-components",
    "title": "Platform Components (C4 Level 2)",
    "layout": "nested",
    "canvas": {
      "width": 1760
    },
    "boxes": [
      {
        "title": "Authorization plane — stateless, latency bound",
        "kind": "boundary",
        "dir": "row",
        "children": [
          {
            "title": "Accept",
            "kind": "plain",
            "nodes": [
              {
                "id": "gw",
                "label": "API gateway",
                "kind": "integration",
                "sub": "Envoy",
                "icon": "envoy"
              },
              {
                "id": "ik",
                "label": "Idempotency key store",
                "kind": "store",
                "sub": "Redis"
              },
              {
                "id": "is",
                "label": "Intent service",
                "kind": "app",
                "sub": "Go · state machine"
              }
            ]
          },
          {
            "title": "Route and attempt",
            "kind": "plain",
            "nodes": [
              {
                "id": "rt",
                "label": "Routing engine",
                "kind": "app",
                "sub": "policy vN"
              },
              {
                "id": "pa",
                "label": "Provider adapters",
                "kind": "integration",
                "sub": "one per rail"
              },
              {
                "id": "cbk",
                "label": "Circuit breakers",
                "kind": "platform",
                "sub": "per provider"
              },
              {
                "id": "su",
                "label": "Step-up orchestrator",
                "kind": "app",
                "sub": "3-DS · collect"
              }
            ]
          }
        ]
      },
      {
        "title": "Cardholder data environment — PCI-DSS scope",
        "kind": "trust",
        "dir": "row",
        "children": [
          {
            "title": "Card data",
            "kind": "plain",
            "nodes": [
              {
                "id": "prox",
                "label": "Card data proxy",
                "kind": "security",
                "sub": "no PAN egress"
              },
              {
                "id": "tv",
                "label": "Token vault",
                "kind": "store",
                "sub": "format preserving"
              },
              {
                "id": "hsm",
                "label": "Network HSM",
                "kind": "security",
                "sub": "no key export",
                "icon": "fa5_key"
              }
            ]
          }
        ]
      },
      {
        "title": "Record plane — durable, append only",
        "kind": "boundary",
        "dir": "row",
        "children": [
          {
            "title": "Coupling",
            "kind": "plain",
            "nodes": [
              {
                "id": "el",
                "label": "Durable event log",
                "kind": "queue",
                "sub": "Kafka · 7 y"
              }
            ]
          },
          {
            "title": "Books",
            "kind": "plain",
            "nodes": [
              {
                "id": "pr",
                "label": "Posting rule engine",
                "kind": "app",
                "sub": "versioned"
              },
              {
                "id": "lp",
                "label": "Ledger poster",
                "kind": "app",
                "sub": "natural key"
              },
              {
                "id": "lg",
                "label": "Ledger store",
                "kind": "store",
                "sub": "PostgreSQL · sync repl",
                "icon": "postgresql"
              }
            ]
          },
          {
            "title": "Payment state",
            "kind": "plain",
            "nodes": [
              {
                "id": "ps",
                "label": "Payment state store",
                "kind": "store",
                "sub": "merchant sharded"
              }
            ]
          }
        ]
      },
      {
        "title": "Money operations plane",
        "kind": "boundary",
        "dir": "row",
        "children": [
          {
            "title": "Resolve",
            "kind": "plain",
            "nodes": [
              {
                "id": "ci",
                "label": "Callback ingest",
                "kind": "integration",
                "sub": "signed · deduped"
              },
              {
                "id": "op",
                "label": "Outcome poller",
                "kind": "app",
                "sub": "backoff"
              },
              {
                "id": "sr",
                "label": "State resolver",
                "kind": "app",
                "sub": "legal transitions"
              }
            ]
          },
          {
            "title": "Settle",
            "kind": "plain",
            "nodes": [
              {
                "id": "fi",
                "label": "File ingest",
                "kind": "app",
                "sub": "re-runnable",
                "icon": false
              },
              {
                "id": "sm",
                "label": "Matcher",
                "kind": "app",
                "sub": "ref + amount"
              },
              {
                "id": "bm",
                "label": "Break manager",
                "kind": "app",
                "sub": "aged"
              },
              {
                "id": "pe",
                "label": "Payout engine",
                "kind": "app",
                "sub": "idempotent"
              }
            ]
          },
          {
            "title": "Notify",
            "kind": "plain",
            "nodes": [
              {
                "id": "wd",
                "label": "Webhook dispatcher",
                "kind": "app",
                "sub": "72 h retry"
              },
              {
                "id": "wr",
                "label": "Replay API",
                "kind": "integration"
              }
            ]
          }
        ]
      },
      {
        "title": "Projections and control",
        "kind": "boundary",
        "dir": "row",
        "children": [
          {
            "title": "Derived",
            "kind": "plain",
            "nodes": [
              {
                "id": "bal",
                "label": "Balance projector",
                "kind": "app",
                "sub": "rebuildable"
              },
              {
                "id": "stm",
                "label": "Statement service",
                "kind": "app"
              },
              {
                "id": "cob",
                "label": "Close of books",
                "kind": "platform",
                "sub": "02:00 daily"
              }
            ]
          },
          {
            "title": "Control",
            "kind": "plain",
            "nodes": [
              {
                "id": "dc",
                "label": "Dual-control workflow",
                "kind": "security"
              },
              {
                "id": "ad",
                "label": "Immutable audit",
                "kind": "store"
              },
              {
                "id": "cf",
                "label": "Config & policy registry",
                "kind": "platform"
              }
            ]
          }
        ]
      }
    ],
    "outside": [
      {
        "id": "acq",
        "label": "Card acquirer",
        "kind": "external"
      },
      {
        "id": "a2a",
        "label": "A2A rail",
        "kind": "external"
      },
      {
        "id": "bank",
        "label": "Settlement bank",
        "kind": "external",
        "icon": "fa4_bank"
      },
      {
        "id": "sanc",
        "label": "Sanctions screening",
        "kind": "external"
      }
    ],
    "edges": [
      {
        "from": "is",
        "to": "el",
        "label": "events",
        "kind": "async"
      },
      {
        "from": "el",
        "to": "lp",
        "label": "post",
        "kind": "async"
      },
      {
        "from": "pa",
        "to": "acq",
        "label": "authorize · collect"
      },
      {
        "from": "pe",
        "to": "bank",
        "label": "payout",
        "kind": "batch"
      },
      {
        "from": "prox",
        "to": "tv",
        "label": "tokenise"
      }
    ],
    "note": "Omitted: per-service sidecars, the sandbox estate and the merchant onboarding service. Nothing omitted writes the ledger.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "09-integration-surface",
    "title": "Integration Surface — Every Interface In and Out",
    "layout": "hub",
    "canvas": {
      "width": 1720
    },
    "left": {
      "title": "Inbound",
      "nodes": [
        {
          "id": "sdk",
          "label": "Checkout SDK",
          "kind": "external",
          "rel": "confirm"
        },
        {
          "id": "msrv",
          "label": "Merchant server API",
          "kind": "external",
          "rel": "intents"
        },
        {
          "id": "pcb",
          "label": "Provider callbacks",
          "kind": "external",
          "rel": "callbacks"
        },
        {
          "id": "sfile",
          "label": "Settlement files",
          "kind": "external",
          "rel": "daily file",
          "kind2": "batch"
        }
      ]
    },
    "centre": {
      "title": "Payment Checkout & Ledger Service",
      "nodes": [
        {
          "id": "core",
          "label": "Authorization plane",
          "kind": "app"
        },
        {
          "id": "book",
          "label": "Ledger plane",
          "kind": "store"
        },
        {
          "id": "mops",
          "label": "Money operations",
          "kind": "app"
        }
      ]
    },
    "right": {
      "title": "Outbound",
      "nodes": [
        {
          "id": "acq",
          "label": "Card acquirers",
          "kind": "external",
          "rel": "authorize",
          "dir": "out"
        },
        {
          "id": "a2a",
          "label": "A2A rail",
          "kind": "external",
          "rel": "collect",
          "dir": "out"
        },
        {
          "id": "hook",
          "label": "Merchant webhooks",
          "kind": "external",
          "rel": "webhooks",
          "dir": "out",
          "kind2": "async"
        },
        {
          "id": "bank",
          "label": "Settlement bank",
          "kind": "external",
          "rel": "payout",
          "dir": "out",
          "kind2": "batch",
          "icon": "fa4_bank"
        }
      ]
    },
    "note": "Four inbound interfaces, four outbound. Dispute notices arrive on the provider-callback interface, sanctions screening sits inside the payout interface, and the nightly finance extract reads the projections rather than the ledger. The finance ops console is an internal surface, not an integration point. Only the merchant server API may create money movement.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "10-payment-data-flow",
    "title": "Data Flow — One Payment, End to End",
    "layout": "flow",
    "canvas": {
      "width": 1780
    },
    "chain": true,
    "align": "top",
    "nodeWidth": 208,
    "stages": [
      {
        "title": "Capture",
        "nodes": [
          {
            "id": "req",
            "label": "Intent request",
            "kind": "integration",
            "sub": "+ idempotency key"
          },
          {
            "id": "card",
            "label": "Card details",
            "kind": "security",
            "sub": "CDE only"
          }
        ]
      },
      {
        "title": "Normalise",
        "nodes": [
          {
            "id": "tok",
            "label": "Network token",
            "kind": "security",
            "sub": "no PAN onward"
          },
          {
            "id": "intent",
            "label": "Intent record",
            "kind": "store",
            "sub": "merchant shard"
          },
          {
            "id": "attempt",
            "label": "Attempt record",
            "kind": "store",
            "sub": "one per provider call"
          }
        ]
      },
      {
        "title": "Emit",
        "nodes": [
          {
            "id": "ev",
            "label": "Payment event",
            "kind": "queue",
            "sub": "ordered per intent"
          },
          {
            "id": "raw",
            "label": "Raw provider payload",
            "kind": "store",
            "sub": "stored before parsed"
          }
        ]
      },
      {
        "title": "Post",
        "nodes": [
          {
            "id": "rule",
            "label": "Posting rule vN",
            "kind": "app"
          },
          {
            "id": "txn",
            "label": "Ledger transaction",
            "kind": "store",
            "sub": "sums to zero"
          },
          {
            "id": "entry",
            "label": "8 entries",
            "kind": "store",
            "sub": "minor units"
          }
        ]
      },
      {
        "title": "Reconcile",
        "nodes": [
          {
            "id": "line",
            "label": "Settlement line",
            "kind": "external",
            "sub": "provider truth"
          },
          {
            "id": "mt",
            "label": "Match or break",
            "kind": "decision"
          },
          {
            "id": "brk",
            "label": "Break account",
            "kind": "risk",
            "sub": "aged 48 h"
          }
        ]
      },
      {
        "title": "Serve",
        "nodes": [
          {
            "id": "balp",
            "label": "Balance projection",
            "kind": "store",
            "sub": "rebuildable"
          },
          {
            "id": "stm",
            "label": "Statement",
            "kind": "app"
          },
          {
            "id": "tb",
            "label": "Trial balance",
            "kind": "app",
            "sub": "daily"
          }
        ]
      }
    ],
    "edges": [
      {
        "from": "card",
        "to": "tok",
        "label": "tokenise"
      },
      {
        "from": "ev",
        "to": "rule",
        "label": "natural key",
        "kind": "async"
      },
      {
        "from": "txn",
        "to": "balp",
        "label": "project",
        "kind": "batch"
      }
    ],
    "note": "The primary account number stops at Capture. Everything downstream carries a token, the ledger carries integer minor units only, and an unmatched line becomes a correcting transaction rather than an edit.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "11-data-classes-and-ownership",
    "title": "Data Classes — Truth, Residency and Rebuildability",
    "layout": "nested",
    "canvas": {
      "width": 1740
    },
    "boxes": [
      {
        "title": "In-country data centres — all copies, including backups",
        "kind": "onprem",
        "dir": "col",
        "children": [
          {
            "title": "Class 1 · Ledger — the only truth about money · 10 years · RPO 0",
            "kind": "trust",
            "nodes": [
              {
                "id": "txn",
                "label": "Transactions",
                "kind": "store",
                "sub": "balanced at write"
              },
              {
                "id": "ent",
                "label": "Entries",
                "kind": "store",
                "sub": "signed minor units"
              },
              {
                "id": "acct",
                "label": "Account tree",
                "kind": "store",
                "sub": "named accounts"
              },
              {
                "id": "rulev",
                "label": "Posting rule versions",
                "kind": "store"
              }
            ]
          },
          {
            "title": "Class 2 · Payment state — mutable, merchant sharded · 7 years · RPO 5 s",
            "kind": "boundary",
            "nodes": [
              {
                "id": "int",
                "label": "Intents",
                "kind": "store"
              },
              {
                "id": "att",
                "label": "Attempts",
                "kind": "store"
              },
              {
                "id": "ref",
                "label": "Refunds",
                "kind": "store"
              },
              {
                "id": "dsp",
                "label": "Disputes",
                "kind": "store",
                "icon": false
              }
            ]
          },
          {
            "title": "Class 3 · Event log — replayable evidence · 7 years",
            "kind": "boundary",
            "nodes": [
              {
                "id": "pev",
                "label": "Payment events",
                "kind": "queue"
              },
              {
                "id": "rawp",
                "label": "Raw provider payloads",
                "kind": "store",
                "sub": "before parsing"
              },
              {
                "id": "wat",
                "label": "Webhook attempts",
                "kind": "store"
              },
              {
                "id": "aud",
                "label": "Operator audit",
                "kind": "store",
                "sub": "7 years"
              }
            ]
          },
          {
            "title": "Class 4 · Derived — rebuildable, no independent truth",
            "kind": "plain",
            "nodes": [
              {
                "id": "bal",
                "label": "Merchant balances",
                "kind": "store"
              },
              {
                "id": "stm",
                "label": "Statements",
                "kind": "store"
              },
              {
                "id": "mart",
                "label": "Analytics marts",
                "kind": "store"
              },
              {
                "id": "dash",
                "label": "Dashboard cache",
                "kind": "store"
              }
            ]
          },
          {
            "title": "Cardholder data environment — never leaves, never joined",
            "kind": "trust",
            "nodes": [
              {
                "id": "pan",
                "label": "PAN (transient)",
                "kind": "risk",
                "sub": "not at rest"
              },
              {
                "id": "vault",
                "label": "Token vault",
                "kind": "store",
                "sub": "CDE only"
              },
              {
                "id": "keys",
                "label": "HSM key material",
                "kind": "security",
                "sub": "non-exportable",
                "icon": "fa5_key"
              }
            ]
          }
        ]
      }
    ],
    "outside": [
      {
        "id": "dr",
        "label": "DR data centre",
        "kind": "onprem",
        "sub": "same country"
      }
    ],
    "edges": [
      {
        "from": "txn",
        "to": "bal",
        "label": "rebuild",
        "kind": "batch"
      }
    ],
    "note": "Class 4 is deleted and rebuilt from Class 1 and Class 3 on a schedule. If a rebuild changes a number, Class 4 was wrong — never Class 1. Every class is replicated to the DR site in the same country.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "12-ledger-data-model",
    "title": "Ledger and Payment Data Model",
    "layout": "er",
    "canvas": {
      "width": 1700,
      "cols": 4
    },
    "rowGap": 262,
    "entities": [
      {
        "id": "merchant",
        "name": "merchant",
        "kind": "store",
        "row": 0,
        "col": 0,
        "attrs": [
          "merchant_id  PK",
          "risk_tier",
          "hold_period_days",
          "payout_schedule",
          "settlement_account"
        ]
      },
      {
        "id": "intent",
        "name": "payment_intent",
        "kind": "app",
        "row": 0,
        "col": 1,
        "attrs": [
          "payment_id  PK",
          "merchant_id  FK",
          "idempotency_key  UQ",
          "amount_minor  int",
          "currency",
          "state",
          "expires_at"
        ]
      },
      {
        "id": "attempt",
        "name": "payment_attempt",
        "kind": "app",
        "row": 0,
        "col": 2,
        "attrs": [
          "attempt_id  PK",
          "payment_id  FK",
          "provider_id  FK",
          "policy_version",
          "result  enum",
          "provider_code",
          "provider_ref"
        ]
      },
      {
        "id": "provider",
        "name": "provider",
        "kind": "external",
        "row": 0,
        "col": 3,
        "attrs": [
          "provider_id  PK",
          "rail  enum",
          "supports_void  bool",
          "supports_inquiry  bool",
          "fee_schedule"
        ]
      },
      {
        "id": "payout",
        "name": "payout",
        "kind": "app",
        "row": 1,
        "col": 0,
        "attrs": [
          "payout_id  PK",
          "merchant_id  FK",
          "instruction_key  UQ",
          "amount_minor",
          "state",
          "bank_ref"
        ]
      },
      {
        "id": "event",
        "name": "payment_event",
        "kind": "queue",
        "row": 1,
        "col": 1,
        "attrs": [
          "event_id  PK",
          "payment_id  FK",
          "seq  int  monotonic",
          "type",
          "source  enum",
          "payload_ref"
        ]
      },
      {
        "id": "dispute",
        "name": "dispute",
        "kind": "app",
        "row": 1,
        "col": 2,
        "attrs": [
          "dispute_id  PK",
          "attempt_id  FK",
          "payment_id  FK",
          "reason_code",
          "state",
          "liability  enum"
        ]
      },
      {
        "id": "sline",
        "name": "settlement_line",
        "kind": "external",
        "row": 1,
        "col": 3,
        "attrs": [
          "line_id  PK",
          "provider_id  FK",
          "provider_ref",
          "amount_minor",
          "match_state  enum",
          "txn_id  FK  null"
        ]
      },
      {
        "id": "refund",
        "name": "refund",
        "kind": "app",
        "row": 2,
        "col": 0,
        "attrs": [
          "refund_id  PK",
          "payment_id  FK",
          "amount_minor",
          "state",
          "reverses_txn_id  FK"
        ]
      },
      {
        "id": "txn",
        "name": "ledger_transaction",
        "kind": "store",
        "row": 2,
        "col": 1,
        "attrs": [
          "txn_id  PK",
          "event_id  UQ  natural key",
          "posting_rule_version",
          "booked_at",
          "period"
        ]
      },
      {
        "id": "entry",
        "name": "ledger_entry",
        "kind": "store",
        "row": 2,
        "col": 2,
        "attrs": [
          "entry_id  PK",
          "txn_id  FK",
          "account_id  FK",
          "amount_minor  signed",
          "currency",
          "sum per txn = 0"
        ]
      },
      {
        "id": "account",
        "name": "account",
        "kind": "store",
        "row": 2,
        "col": 3,
        "attrs": [
          "account_id  PK",
          "owner_type  enum",
          "owner_id",
          "class  enum",
          "currency"
        ]
      }
    ],
    "relations": [
      {
        "from": "merchant",
        "to": "intent",
        "label": "1 : N",
        "from_side": "e",
        "to_side": "w"
      },
      {
        "from": "intent",
        "to": "attempt",
        "label": "1 : N",
        "from_side": "e",
        "to_side": "w"
      },
      {
        "from": "provider",
        "to": "attempt",
        "label": "1 : N",
        "from_side": "w",
        "to_side": "e"
      },
      {
        "from": "merchant",
        "to": "payout",
        "label": "1 : N",
        "from_side": "s",
        "to_side": "n"
      },
      {
        "from": "intent",
        "to": "event",
        "label": "1 : N",
        "from_side": "s",
        "to_side": "n"
      },
      {
        "from": "attempt",
        "to": "dispute",
        "label": "1 : 0..N",
        "from_side": "s",
        "to_side": "n"
      },
      {
        "from": "provider",
        "to": "sline",
        "label": "1 : N",
        "from_side": "s",
        "to_side": "n"
      },
      {
        "from": "event",
        "to": "txn",
        "label": "1 : 0..1",
        "from_side": "s",
        "to_side": "n"
      },
      {
        "from": "txn",
        "to": "entry",
        "label": "1 : 2..N",
        "from_side": "e",
        "to_side": "w"
      },
      {
        "from": "account",
        "to": "entry",
        "label": "1 : N",
        "from_side": "w",
        "to_side": "e"
      },
      {
        "from": "refund",
        "to": "txn",
        "label": "reverses",
        "from_side": "e",
        "to_side": "w",
        "kind": "optional"
      }
    ],
    "note": "ledger_transaction.event_id is unique: the event's identity is the natural key, which is what makes posting exactly-once. Foreign keys carry the links the view does not draw — every object holds payment_id.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "13-authorization-sequence",
    "title": "Critical Flow — Authorize, Acknowledge, Post",
    "layout": "sequence",
    "canvas": {
      "width": 1740
    },
    "lifelines": [
      {
        "id": "buyer",
        "label": "Buyer",
        "kind": "actor"
      },
      {
        "id": "gw",
        "label": "API gateway",
        "kind": "integration",
        "icon": "envoy"
      },
      {
        "id": "is",
        "label": "Intent service",
        "kind": "app"
      },
      {
        "id": "cde",
        "label": "Token vault / HSM",
        "kind": "security",
        "icon": "fa5_key"
      },
      {
        "id": "pa",
        "label": "Provider adapter",
        "kind": "integration"
      },
      {
        "id": "acq",
        "label": "Acquirer",
        "kind": "external"
      },
      {
        "id": "el",
        "label": "Event log",
        "kind": "queue"
      },
      {
        "id": "lg",
        "label": "Ledger",
        "kind": "store",
        "icon": "postgresql"
      }
    ],
    "messages": [
      {
        "from": "buyer",
        "to": "gw",
        "label": "POST /intents + key",
        "kind": "call"
      },
      {
        "from": "gw",
        "to": "is",
        "label": "authenticated create",
        "kind": "call"
      },
      {
        "from": "is",
        "to": "is",
        "label": "key seen? return original",
        "kind": "self"
      },
      {
        "from": "is",
        "to": "el",
        "label": "intent.created",
        "kind": "async"
      },
      {
        "from": "is",
        "to": "buyer",
        "label": "client secret",
        "kind": "return"
      },
      {
        "from": "buyer",
        "to": "cde",
        "label": "card details (CDE only)",
        "kind": "call"
      },
      {
        "from": "cde",
        "to": "is",
        "label": "network token",
        "kind": "return"
      },
      {
        "from": "is",
        "to": "is",
        "label": "route: policy v7",
        "kind": "self"
      },
      {
        "from": "is",
        "to": "pa",
        "label": "authorize(token)",
        "kind": "call"
      },
      {
        "from": "pa",
        "to": "acq",
        "label": "auth request · 8 s deadline",
        "kind": "call"
      },
      {
        "from": "acq",
        "to": "pa",
        "label": "approved + ref",
        "kind": "return"
      },
      {
        "from": "pa",
        "to": "is",
        "label": "result=approved",
        "kind": "return"
      },
      {
        "from": "is",
        "to": "el",
        "label": "payment.authorized",
        "kind": "async"
      },
      {
        "from": "is",
        "to": "buyer",
        "label": "succeeded",
        "kind": "return"
      },
      {
        "from": "el",
        "to": "lg",
        "label": "post txn (event_id key)",
        "kind": "async"
      },
      {
        "from": "lg",
        "to": "lg",
        "label": "entries sum to zero",
        "kind": "self"
      },
      {
        "from": "lg",
        "to": "el",
        "label": "ledger.posted",
        "kind": "async"
      }
    ],
    "note": "The buyer is answered at message 14; the books move at 15-17. That gap is the architecture, and it is what the resolver and matcher exist to close.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "14-unknown-outcome-resolution",
    "title": "Critical Flow — The Unknown Outcome",
    "layout": "sequence",
    "canvas": {
      "width": 1740
    },
    "lifelines": [
      {
        "id": "buyer",
        "label": "Buyer",
        "kind": "actor"
      },
      {
        "id": "is",
        "label": "Intent service",
        "kind": "app"
      },
      {
        "id": "pa",
        "label": "Provider adapter",
        "kind": "integration"
      },
      {
        "id": "acq",
        "label": "Acquirer",
        "kind": "external"
      },
      {
        "id": "op",
        "label": "Outcome poller",
        "kind": "app"
      },
      {
        "id": "sm",
        "label": "Settlement matcher",
        "kind": "app"
      },
      {
        "id": "lg",
        "label": "Ledger",
        "kind": "store",
        "icon": "postgresql"
      },
      {
        "id": "ms",
        "label": "Merchant",
        "kind": "external"
      }
    ],
    "messages": [
      {
        "from": "buyer",
        "to": "is",
        "label": "confirm",
        "kind": "call"
      },
      {
        "from": "is",
        "to": "pa",
        "label": "authorize",
        "kind": "call"
      },
      {
        "from": "pa",
        "to": "acq",
        "label": "auth request",
        "kind": "call"
      },
      {
        "from": "acq",
        "to": "pa",
        "label": "no answer in 8 s",
        "kind": "error"
      },
      {
        "from": "pa",
        "to": "is",
        "label": "result=unknown",
        "kind": "error"
      },
      {
        "from": "is",
        "to": "is",
        "label": "state := processing",
        "kind": "self"
      },
      {
        "from": "is",
        "to": "buyer",
        "label": "processing, do not retry",
        "kind": "return"
      },
      {
        "from": "buyer",
        "to": "is",
        "label": "re-taps: same key",
        "kind": "call"
      },
      {
        "from": "is",
        "to": "buyer",
        "label": "same intent, no 2nd attempt",
        "kind": "return"
      },
      {
        "from": "op",
        "to": "acq",
        "label": "inquiry (if supported)",
        "kind": "call"
      },
      {
        "from": "acq",
        "to": "op",
        "label": "still unknown",
        "kind": "error"
      },
      {
        "from": "sm",
        "to": "sm",
        "label": "T+1 file: ref present",
        "kind": "self"
      },
      {
        "from": "sm",
        "to": "is",
        "label": "resolve → authorized",
        "kind": "call"
      },
      {
        "from": "is",
        "to": "lg",
        "label": "post, event_id key",
        "kind": "async"
      },
      {
        "from": "is",
        "to": "ms",
        "label": "webhook: succeeded",
        "kind": "async"
      }
    ],
    "note": "No second provider attempt is ever made after an unknown. The resolution ladder is inquiry, then the settlement file, and the file is the evidence.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "15-refund-and-dispute-flow",
    "title": "Money Going Back — Refunds, Reversals and Disputes",
    "layout": "flow",
    "canvas": {
      "width": 1760
    },
    "chain": true,
    "align": "top",
    "nodeWidth": 214,
    "stages": [
      {
        "title": "Raise",
        "nodes": [
          {
            "id": "mreq",
            "label": "Merchant refund",
            "kind": "integration",
            "sub": "idempotent"
          },
          {
            "id": "dnot",
            "label": "Dispute notice",
            "kind": "external",
            "sub": "from network"
          }
        ]
      },
      {
        "title": "Admit",
        "nodes": [
          {
            "id": "cap",
            "label": "Captured amount check",
            "kind": "decision",
            "sub": "under concurrency"
          },
          {
            "id": "void",
            "label": "Void if uncaptured",
            "kind": "app",
            "sub": "not a refund"
          },
          {
            "id": "liab",
            "label": "Liability assignment",
            "kind": "app"
          }
        ]
      },
      {
        "title": "Reserve",
        "nodes": [
          {
            "id": "deb",
            "label": "Debit merchant balance",
            "kind": "store"
          },
          {
            "id": "neg",
            "label": "Negative balance → receivable",
            "kind": "risk",
            "sub": "never rejected"
          }
        ]
      },
      {
        "title": "Execute",
        "nodes": [
          {
            "id": "prov",
            "label": "Provider refund call",
            "kind": "integration"
          },
          {
            "id": "pend",
            "label": "State: pending",
            "kind": "app",
            "sub": "not success"
          }
        ]
      },
      {
        "title": "Confirm",
        "nodes": [
          {
            "id": "cbk",
            "label": "Provider confirmation",
            "kind": "external"
          },
          {
            "id": "rev",
            "label": "Reversing entry",
            "kind": "store",
            "sub": "new, opposite sign"
          }
        ]
      },
      {
        "title": "Resolve",
        "nodes": [
          {
            "id": "won",
            "label": "Dispute won → reverse debit",
            "kind": "opportunity"
          },
          {
            "id": "lost",
            "label": "Dispute lost → stands",
            "kind": "risk"
          },
          {
            "id": "stm",
            "label": "Statement line",
            "kind": "app"
          }
        ]
      }
    ],
    "edges": [
      {
        "from": "dnot",
        "to": "liab",
        "label": "reason code"
      },
      {
        "from": "cap",
        "to": "void",
        "label": "uncaptured",
        "kind": "error"
      },
      {
        "from": "pend",
        "to": "cbk",
        "label": "await",
        "kind": "async"
      },
      {
        "from": "won",
        "to": "rev",
        "label": "second reversal",
        "kind": "error"
      }
    ],
    "note": "No ledger entry is ever reduced. A refund, a dispute debit and a dispute win are three new transactions referencing the original.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "16-settlement-and-payout-pipeline",
    "title": "Settlement and Payout Pipeline",
    "layout": "flow",
    "canvas": {
      "width": 1780
    },
    "chain": true,
    "align": "top",
    "nodeWidth": 212,
    "stages": [
      {
        "title": "Arrive",
        "nodes": [
          {
            "id": "sftp",
            "label": "Provider file drop",
            "kind": "external",
            "sub": "30 files / day"
          },
          {
            "id": "late",
            "label": "Late-file alarm",
            "kind": "platform",
            "sub": "per provider SLA"
          }
        ]
      },
      {
        "title": "Ingest",
        "nodes": [
          {
            "id": "ing",
            "label": "Idempotent ingest",
            "kind": "app",
            "sub": "re-runnable",
            "icon": false
          },
          {
            "id": "stage",
            "label": "Staged lines",
            "kind": "store",
            "sub": "≤ 10 M / file"
          },
          {
            "id": "rest",
            "label": "Restatement handling",
            "kind": "app",
            "sub": "correct, never edit"
          }
        ]
      },
      {
        "title": "Match",
        "nodes": [
          {
            "id": "mref",
            "label": "Match on ref + amount",
            "kind": "app"
          },
          {
            "id": "cls",
            "label": "Matched · unmatched · disputed",
            "kind": "decision"
          }
        ]
      },
      {
        "title": "Break",
        "nodes": [
          {
            "id": "bacc",
            "label": "Break account posting",
            "kind": "store",
            "sub": "nothing discarded"
          },
          {
            "id": "age",
            "label": "Ageing > 48 h",
            "kind": "risk",
            "sub": "incident"
          },
          {
            "id": "dual",
            "label": "Dual-control correction",
            "kind": "security"
          }
        ]
      },
      {
        "title": "Prove",
        "nodes": [
          {
            "id": "tb",
            "label": "Trial balance",
            "kind": "app",
            "sub": "02:00 daily"
          },
          {
            "id": "cash",
            "label": "Cash position vs bank",
            "kind": "app",
            "sub": "tolerance alarm"
          }
        ]
      },
      {
        "title": "Pay out",
        "nodes": [
          {
            "id": "avail",
            "label": "Available balance",
            "kind": "store",
            "sub": "minus hold period"
          },
          {
            "id": "scr",
            "label": "Sanctions screen",
            "kind": "security",
            "sub": "hold, not reject"
          },
          {
            "id": "inst",
            "label": "Payout instruction",
            "kind": "app",
            "sub": "unique key"
          },
          {
            "id": "ret",
            "label": "Return handling",
            "kind": "app",
            "sub": "restore balance"
          }
        ]
      }
    ],
    "edges": [
      {
        "from": "cls",
        "to": "bacc",
        "label": "unmatched",
        "kind": "error"
      },
      {
        "from": "dual",
        "to": "tb",
        "label": "corrected"
      },
      {
        "from": "cash",
        "to": "avail",
        "label": "proven"
      },
      {
        "from": "ret",
        "to": "avail",
        "label": "credit back",
        "kind": "error"
      }
    ],
    "note": "Payout runs on proven cash, not on believed cash: the trial balance and the bank comparison gate the 06:00 run.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "17-webhook-delivery-lanes",
    "title": "Merchant Notification — Delivery by Event Class",
    "layout": "swimlane",
    "canvas": {
      "width": 1740
    },
    "laneHeaderWidth": 182,
    "stages": [
      "Emit",
      "Sign and queue",
      "Attempt",
      "Retry",
      "Catch up"
    ],
    "lanes": [
      {
        "title": "Payment outcome",
        "cells": [
          [
            {
              "label": "payment.succeeded",
              "kind": "queue"
            }
          ],
          [
            {
              "label": "HMAC + seq n",
              "kind": "security"
            }
          ],
          [
            {
              "label": "POST, 5 s budget",
              "kind": "integration",
              "icon": false
            }
          ],
          [
            {
              "label": "backoff to 72 h",
              "kind": "app"
            }
          ],
          [
            {
              "label": "replay by id",
              "kind": "integration"
            }
          ]
        ]
      },
      {
        "title": "Refund and dispute",
        "cells": [
          [
            {
              "label": "refund.updated",
              "kind": "queue"
            }
          ],
          [
            {
              "label": "same signature",
              "kind": "security"
            }
          ],
          [
            {
              "label": "POST",
              "kind": "integration",
              "icon": false
            }
          ],
          [
            {
              "label": "backoff to 72 h",
              "kind": "app"
            }
          ],
          [
            {
              "label": "list since cursor",
              "kind": "integration"
            }
          ]
        ]
      },
      {
        "title": "Payout and balance",
        "cells": [
          [
            {
              "label": "payout.paid",
              "kind": "queue"
            }
          ],
          [
            {
              "label": "batched per merchant",
              "kind": "app"
            }
          ],
          [
            {
              "label": "POST",
              "kind": "integration",
              "icon": false
            }
          ],
          [
            {
              "label": "daily digest fallback",
              "kind": "app"
            }
          ],
          [
            {
              "label": "statement download",
              "kind": "app"
            }
          ]
        ]
      },
      {
        "title": "Ordering guarantee",
        "cells": [
          [
            {
              "label": "per-object seq",
              "kind": "app"
            }
          ],
          [
            {
              "label": "no global order",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "gap detectable",
              "kind": "opportunity"
            }
          ],
          [
            {
              "label": "no head-of-line block",
              "kind": "opportunity"
            }
          ],
          [
            {
              "label": "cursor is authoritative",
              "kind": "app"
            }
          ]
        ]
      },
      {
        "title": "Failing endpoint",
        "cells": [
          [
            {
              "label": "events still emitted",
              "kind": "queue"
            }
          ],
          [
            {
              "label": "per-merchant queue",
              "kind": "queue"
            }
          ],
          [
            {
              "label": "5xx / timeout",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "isolated, not shared",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "auto-disable + notice",
              "kind": "security"
            }
          ]
        ]
      }
    ],
    "note": "At-least-once, stated in the contract. One stalled merchant endpoint never delays another merchant's events — the queue is per merchant.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "18-deployment-architecture",
    "title": "Deployment — Two In-Country Data Centres",
    "layout": "nested",
    "canvas": {
      "width": 1760
    },
    "boxes": [
      {
        "title": "DC-1 (primary) — in country",
        "kind": "onprem",
        "dir": "row",
        "children": [
          {
            "title": "Edge tier",
            "kind": "boundary",
            "nodes": [
              {
                "id": "lb1",
                "label": "L4 load balancer",
                "kind": "platform",
                "sub": "anycast VIP"
              },
              {
                "id": "gw1",
                "label": "Gateway pods",
                "kind": "integration",
                "sub": "Envoy · HPA"
              }
            ]
          },
          {
            "title": "Authorization pool",
            "kind": "boundary",
            "nodes": [
              {
                "id": "k8s1",
                "label": "Kubernetes cluster",
                "kind": "platform",
                "sub": "3 control nodes"
              },
              {
                "id": "auth1",
                "label": "Intent + router pods",
                "kind": "app",
                "sub": "scaled on in-flight",
                "icon": false
              },
              {
                "id": "ad1",
                "label": "Adapter pods",
                "kind": "integration",
                "sub": "static egress IPs"
              }
            ]
          },
          {
            "title": "CDE segment",
            "kind": "trust",
            "nodes": [
              {
                "id": "cde1",
                "label": "Card proxy + vault",
                "kind": "security",
                "sub": "separate cluster"
              },
              {
                "id": "hsm1",
                "label": "Network HSM pair",
                "kind": "security",
                "sub": "FIPS 140-3",
                "icon": "fa5_key"
              }
            ]
          },
          {
            "title": "Record tier",
            "kind": "boundary",
            "nodes": [
              {
                "id": "kf1",
                "label": "Kafka · 5 brokers",
                "kind": "queue",
                "sub": "RF 3 · min.isr 2"
              },
              {
                "id": "pg1",
                "label": "Ledger primary",
                "kind": "store",
                "sub": "PostgreSQL · sync",
                "icon": "postgresql"
              },
              {
                "id": "ps1",
                "label": "Payment state",
                "kind": "store",
                "sub": "sharded by merchant"
              }
            ]
          }
        ]
      },
      {
        "title": "DC-2 (warm, same country) — 40 km, 1.4 ms RTT",
        "kind": "onprem",
        "dir": "row",
        "children": [
          {
            "title": "Edge and authorization",
            "kind": "boundary",
            "nodes": [
              {
                "id": "gw2",
                "label": "Gateway pods",
                "kind": "integration",
                "sub": "live, 30% share"
              },
              {
                "id": "auth2",
                "label": "Intent + router pods",
                "kind": "app",
                "sub": "active",
                "icon": false
              }
            ]
          },
          {
            "title": "Record tier",
            "kind": "boundary",
            "nodes": [
              {
                "id": "pg2",
                "label": "Ledger sync standby",
                "kind": "store",
                "sub": "RPO 0",
                "icon": "postgresql"
              },
              {
                "id": "kf2",
                "label": "Kafka stretch replica",
                "kind": "queue"
              },
              {
                "id": "cde2",
                "label": "CDE + HSM pair",
                "kind": "security",
                "icon": "fa5_key"
              }
            ]
          },
          {
            "title": "Batch tier",
            "kind": "plain",
            "nodes": [
              {
                "id": "bt2",
                "label": "Settlement + payout jobs",
                "kind": "app",
                "sub": "runs here by default"
              },
              {
                "id": "proj2",
                "label": "Projection rebuild",
                "kind": "app"
              }
            ]
          }
        ]
      },
      {
        "title": "Shared control",
        "kind": "boundary",
        "dir": "row",
        "children": [
          {
            "title": "Platform services",
            "kind": "plain",
            "nodes": [
              {
                "id": "obs",
                "label": "Observability stack",
                "kind": "platform",
                "sub": "both DCs"
              },
              {
                "id": "sec",
                "label": "Secrets + PKI",
                "kind": "security"
              },
              {
                "id": "cicd",
                "label": "CI/CD runners",
                "kind": "platform",
                "sub": "air-gapped promote"
              }
            ]
          }
        ]
      }
    ],
    "outside": [
      {
        "id": "acq",
        "label": "Acquirers",
        "kind": "external",
        "sub": "leased line + IPsec"
      },
      {
        "id": "a2a",
        "label": "A2A rail",
        "kind": "external",
        "sub": "allowlisted egress"
      },
      {
        "id": "bank",
        "label": "Settlement bank",
        "kind": "external",
        "sub": "SFTP",
        "icon": "fa4_bank"
      }
    ],
    "edges": [
      {
        "from": "pg1",
        "to": "pg2",
        "label": "sync replication"
      },
      {
        "from": "ad1",
        "to": "acq",
        "label": "static IP"
      },
      {
        "from": "bt2",
        "to": "bank",
        "label": "payout file",
        "kind": "batch"
      }
    ],
    "note": "Both DCs serve authorization traffic; Kafka is stretched across them. Only the ledger has a single writer, and only its failover is a declared operation.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "19-observability",
    "title": "Observability — Signal by Pipeline Stage",
    "layout": "grid",
    "canvas": {
      "width": 1760
    },
    "laneHeaderWidth": 176,
    "columns": [
      "Accept",
      "Authorize",
      "Post",
      "Resolve",
      "Settle",
      "Pay out"
    ],
    "rows": [
      {
        "title": "Business truth",
        "cells": [
          [
            {
              "label": "attempts / s",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "approval rate",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "unposted events",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "processing age p99",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "match rate",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "payouts on time",
              "kind": "platform"
            }
          ]
        ]
      },
      {
        "title": "Correctness alarms",
        "cells": [
          [
            {
              "label": "idem conflicts",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "double capture",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "unbalanced reject",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "illegal transition",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "break value",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "bank vs ledger delta",
              "kind": "risk"
            }
          ]
        ]
      },
      {
        "title": "Latency",
        "cells": [
          [
            {
              "label": "create p99",
              "kind": "app"
            }
          ],
          [
            {
              "label": "provider p95",
              "kind": "app"
            }
          ],
          [
            {
              "label": "post lag p99",
              "kind": "app"
            }
          ],
          [
            {
              "label": "poll backlog",
              "kind": "app"
            }
          ],
          [
            {
              "label": "file-to-match",
              "kind": "app"
            }
          ],
          [
            {
              "label": "instruct-to-bank",
              "kind": "app"
            }
          ]
        ]
      },
      {
        "title": "Saturation",
        "cells": [
          [
            {
              "label": "queue depth / merchant",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "in-flight provider calls",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "consumer lag",
              "kind": "queue"
            }
          ],
          [
            {
              "label": "retry queue",
              "kind": "queue"
            }
          ],
          [
            {
              "label": "staged lines",
              "kind": "store"
            }
          ],
          [
            {
              "label": "held payouts",
              "kind": "store"
            }
          ]
        ]
      },
      {
        "title": "Evidence trail",
        "cells": [
          [
            {
              "label": "request audit",
              "kind": "security"
            }
          ],
          [
            {
              "label": "policy version used",
              "kind": "security"
            }
          ],
          [
            {
              "label": "posting rule version",
              "kind": "security"
            }
          ],
          [
            {
              "label": "raw payload kept",
              "kind": "security"
            }
          ],
          [
            {
              "label": "file hash + run id",
              "kind": "security"
            }
          ],
          [
            {
              "label": "dual-control record",
              "kind": "security"
            }
          ]
        ]
      }
    ],
    "note": "The correctness row is the one that pages. Latency and saturation inform; an unbalanced-transaction reject or a bank delta wakes someone up.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "20-reconciliation-loop",
    "title": "The Loop That Must Close — Reconciliation",
    "layout": "cycle",
    "canvas": {
      "width": 1620
    },
    "centre": {
      "label": "Books that balance",
      "sub": "every day"
    },
    "nodes": [
      {
        "label": "Believe",
        "kind": "app",
        "sub": "provider said approved",
        "id": "believe"
      },
      {
        "label": "Post",
        "kind": "store",
        "sub": "entries sum to zero",
        "id": "post",
        "icon": false
      },
      {
        "label": "Receive evidence",
        "kind": "external",
        "sub": "settlement file",
        "id": "evidence"
      },
      {
        "label": "Match",
        "kind": "decision",
        "sub": "ref + amount",
        "id": "match"
      },
      {
        "label": "Name the gap",
        "kind": "risk",
        "sub": "break account",
        "id": "gap"
      },
      {
        "label": "Correct",
        "kind": "security",
        "sub": "dual control, opposite entry",
        "id": "correct"
      },
      {
        "label": "Prove",
        "kind": "platform",
        "sub": "trial balance + bank",
        "id": "prove"
      }
    ],
    "ringLabels": [
      "natural key",
      "T+1",
      "automatic",
      "unmatched",
      "aged 48 h",
      "new txn",
      "feeds tomorrow"
    ],
    "rx": 440,
    "ry": 218,
    "note": "The loop is the only thing that makes an asynchronous ledger safe. If it ever stops closing, the platform is guessing.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "21-release-and-rollout",
    "title": "Release and Rollout — Changing a System That Holds Money",
    "layout": "flow",
    "canvas": {
      "width": 1780
    },
    "chain": true,
    "align": "top",
    "nodeWidth": 210,
    "stages": [
      {
        "title": "Source",
        "nodes": [
          {
            "id": "pr",
            "label": "Pull request",
            "kind": "app",
            "sub": "2 reviewers",
            "icon": "di_git_pull_request"
          },
          {
            "id": "rule",
            "label": "Posting rule change",
            "kind": "security",
            "sub": "finance sign-off"
          }
        ]
      },
      {
        "title": "Build",
        "nodes": [
          {
            "id": "sbom",
            "label": "Signed image + SBOM",
            "kind": "platform"
          },
          {
            "id": "mig",
            "label": "Forward-only migration",
            "kind": "store",
            "sub": "no destructive DDL"
          }
        ]
      },
      {
        "title": "Gates",
        "nodes": [
          {
            "id": "bal",
            "label": "Ledger balance property test",
            "kind": "decision",
            "sub": "hard gate"
          },
          {
            "id": "repl",
            "label": "Replay last 24 h of events",
            "kind": "decision",
            "sub": "byte-identical"
          },
          {
            "id": "pci",
            "label": "CDE scope diff",
            "kind": "security",
            "sub": "no new PAN path"
          }
        ]
      },
      {
        "title": "Canary",
        "nodes": [
          {
            "id": "shad",
            "label": "Shadow post",
            "kind": "app",
            "sub": "new rules, not booked"
          },
          {
            "id": "can",
            "label": "1% of merchants",
            "kind": "app",
            "sub": "30 min watch"
          }
        ]
      },
      {
        "title": "Promote",
        "nodes": [
          {
            "id": "auth",
            "label": "Authorization pods",
            "kind": "app",
            "sub": "rolling, drain in-flight"
          },
          {
            "id": "ledp",
            "label": "Ledger poster",
            "kind": "app",
            "sub": "one version at a time"
          }
        ]
      },
      {
        "title": "Reverse",
        "nodes": [
          {
            "id": "rb",
            "label": "Image rollback",
            "kind": "opportunity",
            "sub": "minutes"
          },
          {
            "id": "nrb",
            "label": "Posted entries never rolled back",
            "kind": "risk",
            "sub": "correct forward"
          }
        ]
      }
    ],
    "edges": [
      {
        "from": "rule",
        "to": "shad",
        "label": "shadow first"
      },
      {
        "from": "can",
        "to": "rb",
        "label": "on regression",
        "kind": "error"
      }
    ],
    "note": "A posting-rule change ships shadowed before it books anything. Code rolls back; ledger entries do not — they are corrected forward.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "22-security-trust-zones",
    "title": "Trust Zones and What Crosses Them",
    "layout": "zones",
    "canvas": {
      "width": 1740
    },
    "zones": [
      {
        "title": "Internet — untrusted",
        "kind": "trust",
        "nodes": [
          {
            "id": "br",
            "label": "Buyer browser",
            "kind": "external"
          },
          {
            "id": "msv",
            "label": "Merchant server",
            "kind": "external"
          },
          {
            "id": "pcb",
            "label": "Provider callbacks",
            "kind": "external"
          }
        ]
      },
      {
        "title": "Perimeter — authenticated, rate limited",
        "kind": "trust",
        "nodes": [
          {
            "id": "waf",
            "label": "WAF + L7 edge",
            "kind": "platform"
          },
          {
            "id": "gw",
            "label": "API gateway",
            "kind": "integration",
            "sub": "mTLS to backends",
            "icon": "envoy"
          },
          {
            "id": "cred",
            "label": "Credential verifier",
            "kind": "security",
            "sub": "scoped keys"
          },
          {
            "id": "sig",
            "label": "Callback signature check",
            "kind": "security",
            "sub": "5 min freshness"
          }
        ]
      },
      {
        "title": "Application — no card data, no key material",
        "kind": "trust",
        "nodes": [
          {
            "id": "is",
            "label": "Intent service",
            "kind": "app"
          },
          {
            "id": "rt",
            "label": "Routing engine",
            "kind": "app"
          },
          {
            "id": "mops",
            "label": "Money operations",
            "kind": "app"
          },
          {
            "id": "dash",
            "label": "Dashboards",
            "kind": "app",
            "sub": "masked by default"
          }
        ]
      },
      {
        "title": "Cardholder data environment — PCI-DSS scope",
        "kind": "trust",
        "nodes": [
          {
            "id": "prox",
            "label": "Card data proxy",
            "kind": "security"
          },
          {
            "id": "vault",
            "label": "Token vault",
            "kind": "store"
          },
          {
            "id": "hsm",
            "label": "Network HSM",
            "kind": "security",
            "sub": "no key export",
            "icon": "fa5_key"
          }
        ]
      },
      {
        "title": "Record — books and evidence",
        "kind": "trust",
        "nodes": [
          {
            "id": "lg",
            "label": "Ledger",
            "kind": "store",
            "sub": "append only",
            "icon": "postgresql"
          },
          {
            "id": "el",
            "label": "Event log",
            "kind": "queue"
          },
          {
            "id": "aud",
            "label": "Immutable audit",
            "kind": "store"
          }
        ]
      },
      {
        "title": "Money egress — allowlisted only",
        "kind": "trust",
        "nodes": [
          {
            "id": "eg",
            "label": "Egress proxy",
            "kind": "security",
            "sub": "static IPs"
          },
          {
            "id": "acq",
            "label": "Acquirers",
            "kind": "external"
          },
          {
            "id": "bank",
            "label": "Settlement bank",
            "kind": "external",
            "icon": "fa4_bank"
          }
        ]
      }
    ],
    "edges": [
      {
        "from": "br",
        "to": "waf",
        "label": "TLS 1.3"
      },
      {
        "from": "msv",
        "to": "gw",
        "label": "secret key"
      },
      {
        "from": "pcb",
        "to": "sig",
        "label": "signed + nonce"
      },
      {
        "from": "gw",
        "to": "is",
        "label": "mTLS + scope"
      },
      {
        "from": "br",
        "to": "prox",
        "label": "PAN, CDE only",
        "kind": "error"
      },
      {
        "from": "eg",
        "to": "acq",
        "label": "IPsec"
      },
      {
        "from": "mops",
        "to": "lg",
        "label": "no direct write",
        "kind": "error"
      }
    ],
    "note": "Two crossings are drawn in red: the PAN path that bypasses the application zone entirely, and the write to the ledger that money operations may not make. Application-zone services reach the record zone only through the event log.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "23-credential-and-key-flow",
    "title": "Identity and Access — Who May Move Money",
    "layout": "sequence",
    "canvas": {
      "width": 1740
    },
    "lifelines": [
      {
        "id": "op",
        "label": "Finance operator",
        "kind": "actor"
      },
      {
        "id": "idp",
        "label": "Workforce IdP",
        "kind": "security"
      },
      {
        "id": "con",
        "label": "Ops console",
        "kind": "app"
      },
      {
        "id": "dc",
        "label": "Dual-control service",
        "kind": "security"
      },
      {
        "id": "op2",
        "label": "Second approver",
        "kind": "actor"
      },
      {
        "id": "lg",
        "label": "Ledger",
        "kind": "store",
        "icon": "postgresql"
      },
      {
        "id": "aud",
        "label": "Immutable audit",
        "kind": "store"
      },
      {
        "id": "hsm",
        "label": "HSM",
        "kind": "security",
        "icon": "fa5_key"
      }
    ],
    "messages": [
      {
        "from": "op",
        "to": "idp",
        "label": "phishing-resistant MFA",
        "kind": "call"
      },
      {
        "from": "idp",
        "to": "con",
        "label": "assertion + role",
        "kind": "return"
      },
      {
        "from": "con",
        "to": "aud",
        "label": "session opened",
        "kind": "async"
      },
      {
        "from": "op",
        "to": "con",
        "label": "view payment (masked)",
        "kind": "call"
      },
      {
        "from": "con",
        "to": "aud",
        "label": "read + case ref",
        "kind": "async"
      },
      {
        "from": "op",
        "to": "con",
        "label": "propose correction",
        "kind": "call"
      },
      {
        "from": "con",
        "to": "dc",
        "label": "queue for approval",
        "kind": "call"
      },
      {
        "from": "dc",
        "to": "op2",
        "label": "approval request",
        "kind": "async"
      },
      {
        "from": "op2",
        "to": "dc",
        "label": "approve (different human)",
        "kind": "call"
      },
      {
        "from": "dc",
        "to": "hsm",
        "label": "sign the instruction",
        "kind": "call"
      },
      {
        "from": "hsm",
        "to": "dc",
        "label": "signature",
        "kind": "return"
      },
      {
        "from": "dc",
        "to": "lg",
        "label": "opposite-signed txn",
        "kind": "call"
      },
      {
        "from": "lg",
        "to": "lg",
        "label": "balance check, append",
        "kind": "self"
      },
      {
        "from": "lg",
        "to": "aud",
        "label": "both approvers recorded",
        "kind": "async"
      },
      {
        "from": "con",
        "to": "op",
        "label": "no single-actor path",
        "kind": "return"
      }
    ],
    "note": "There is no sequence in which one authenticated human changes the books. Elevation to unmasked data is itself a logged, case-referenced event.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  },
  {
    "id": "24-failure-classes",
    "title": "Failure Classes — What Is Assumed To Fail",
    "layout": "swimlane",
    "canvas": {
      "width": 1760
    },
    "laneHeaderWidth": 196,
    "stages": [
      "Assumed rate",
      "Detected by",
      "Immediate handling",
      "Where truth is restored",
      "Buyer / merchant sees"
    ],
    "lanes": [
      {
        "title": "Provider unknown outcome",
        "cells": [
          [
            {
              "label": "few per 1,000",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "8 s deadline",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "hold in processing",
              "kind": "app"
            }
          ],
          [
            {
              "label": "inquiry, then file",
              "kind": "app"
            }
          ],
          [
            {
              "label": "honest pending",
              "kind": "journey"
            }
          ]
        ]
      },
      {
        "title": "Provider down",
        "cells": [
          [
            {
              "label": "hours / year each",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "approval + latency",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "circuit break, reroute",
              "kind": "app"
            }
          ],
          [
            {
              "label": "no truth lost",
              "kind": "opportunity"
            }
          ],
          [
            {
              "label": "method degraded",
              "kind": "journey"
            }
          ]
        ]
      },
      {
        "title": "Duplicate / late callback",
        "cells": [
          [
            {
              "label": "routine",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "event id seen",
              "kind": "app"
            }
          ],
          [
            {
              "label": "dedupe, legality check",
              "kind": "app"
            }
          ],
          [
            {
              "label": "no state change",
              "kind": "opportunity"
            }
          ],
          [
            {
              "label": "nothing",
              "kind": "journey"
            }
          ]
        ]
      },
      {
        "title": "Merchant endpoint down",
        "cells": [
          [
            {
              "label": "days at a time",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "5xx / timeout",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "per-merchant queue",
              "kind": "queue"
            }
          ],
          [
            {
              "label": "72 h retry + replay",
              "kind": "app"
            }
          ],
          [
            {
              "label": "catch-up on return",
              "kind": "journey"
            }
          ]
        ]
      },
      {
        "title": "Ledger shard unavailable",
        "cells": [
          [
            {
              "label": "rare",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "post lag alarm",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "buffer in event log",
              "kind": "queue"
            }
          ],
          [
            {
              "label": "drain on recovery",
              "kind": "app"
            }
          ],
          [
            {
              "label": "balance lags, no loss",
              "kind": "journey"
            }
          ]
        ]
      },
      {
        "title": "HSM / vault unavailable",
        "cells": [
          [
            {
              "label": "rare",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "tokenise errors",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "fail closed on card",
              "kind": "security"
            }
          ],
          [
            {
              "label": "A2A unaffected",
              "kind": "opportunity"
            }
          ],
          [
            {
              "label": "card method hidden",
              "kind": "journey"
            }
          ]
        ]
      },
      {
        "title": "File late / restated",
        "cells": [
          [
            {
              "label": "monthly",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "arrival SLA",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "re-runnable ingest",
              "kind": "app"
            }
          ],
          [
            {
              "label": "corrections, not edits",
              "kind": "store"
            }
          ],
          [
            {
              "label": "payout may hold",
              "kind": "journey"
            }
          ]
        ]
      },
      {
        "title": "Reconciliation break",
        "cells": [
          [
            {
              "label": "~40 / day",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "matcher",
              "kind": "app"
            }
          ],
          [
            {
              "label": "break account",
              "kind": "store"
            }
          ],
          [
            {
              "label": "dual-control fix",
              "kind": "security"
            }
          ],
          [
            {
              "label": "nothing, unless aged",
              "kind": "journey"
            }
          ]
        ]
      },
      {
        "title": "Data centre loss",
        "cells": [
          [
            {
              "label": "once in years",
              "kind": "risk"
            }
          ],
          [
            {
              "label": "health + quorum",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "declared failover",
              "kind": "platform"
            }
          ],
          [
            {
              "label": "RPO 0 on ledger",
              "kind": "opportunity"
            }
          ],
          [
            {
              "label": "≤ 120 s of declines",
              "kind": "journey"
            }
          ]
        ]
      }
    ],
    "note": "Nine classes, each with a named detector and a named restoration path. The last column is the contract: what a human is allowed to experience.",
    "meta": {
      "v": "1.0",
      "owner": "Payments Platform Architecture",
      "date": "2026-10"
    }
  }
]
