{
  "docVersion": 1,
  "id": "template-ticket-booking-seat-holds",
  "name": "Ticket booking — seat holds",
  "purpose": "Waiting room levels the on-sale spike; seats are held with lease+fencing-token locks; hold→charge→confirm runs as a saga with automatic release on failure.",
  "nodes": {
    "fan": {
      "type": "users",
      "label": "20k Fans",
      "x": 20,
      "y": 240,
      "runtime": "on-sale at 10:00"
    },
    "waiting": {
      "type": "queue",
      "label": "Waiting Room",
      "x": 280,
      "y": 240,
      "runtime": "admits 200/s · fair order",
      "color": "amber",
      "notes": "The site never sees the stampede — fans see a live queue position instead of an error page."
    },
    "web": {
      "type": "server",
      "label": "Booking API",
      "x": 540,
      "y": 240,
      "runtime": "hold → pay → confirm",
      "color": "blue",
      "patterns": [
        "stateless",
        "autoscale"
      ]
    },
    "cron": {
      "type": "cron",
      "label": "Hold Reaper",
      "x": 540,
      "y": 10,
      "runtime": "expired leases → back on sale"
    },
    "lock": {
      "type": "keyvalue",
      "label": "Seat Holds",
      "x": 800,
      "y": 60,
      "runtime": "lease 120s + fencing token",
      "notes": "Hold = exclusive lock with an expiry and a monotonically increasing token. Expiry frees abandoned seats; the token fences zombies."
    },
    "inv": {
      "type": "database",
      "label": "Seat Inventory",
      "x": 800,
      "y": 400,
      "runtime": "source of truth",
      "patterns": [
        "replicated",
        "backup"
      ]
    },
    "pay": {
      "type": "payment",
      "label": "PSP",
      "x": 1060,
      "y": 240,
      "runtime": "charge within the lease"
    },
    "email": {
      "type": "email",
      "label": "Ticket Delivery",
      "x": 1320,
      "y": 400,
      "runtime": "PDF + wallet pass"
    }
  },
  "edges": {
    "e1": {
      "from": "fan",
      "to": "waiting",
      "fromSide": "right",
      "toSide": "left",
      "label": "stampede in",
      "animated": true
    },
    "e2": {
      "from": "waiting",
      "to": "web",
      "fromSide": "right",
      "toSide": "left",
      "label": "admit 200/s",
      "animated": true,
      "patterns": [
        "load-shed"
      ]
    },
    "e3": {
      "from": "web",
      "to": "lock",
      "fromSide": "right",
      "toSide": "left",
      "label": "hold 14B · lease+token",
      "animated": true
    },
    "e4": {
      "from": "web",
      "to": "pay",
      "fromSide": "right",
      "toSide": "left",
      "label": "charge",
      "patterns": [
        "retry",
        "timeout",
        "idempotent"
      ]
    },
    "e5": {
      "from": "web",
      "to": "inv",
      "fromSide": "bottom",
      "toSide": "left",
      "label": "commit with token — stale holds rejected"
    },
    "e6": {
      "from": "pay",
      "to": "lock",
      "fromSide": "top",
      "toSide": "bottom",
      "label": "payment failed → release hold",
      "style": "dashed",
      "color": "amber"
    },
    "e7": {
      "from": "cron",
      "to": "lock",
      "fromSide": "right",
      "toSide": "top",
      "label": "reap expired",
      "style": "dashed"
    },
    "e8": {
      "from": "web",
      "to": "email",
      "fromSide": "bottom",
      "toSide": "top",
      "label": "confirmed → ticket",
      "style": "dashed"
    }
  },
  "boxes": {
    "b1": {
      "x": 760,
      "y": -20,
      "w": 450,
      "h": 630,
      "label": "consistency core — one writer per seat",
      "color": "blue",
      "opacity": 0.04
    }
  },
  "texts": {
    "t1": {
      "x": 20,
      "y": 430,
      "text": "why fencing tokens:\na browser that froze during payment\nwakes with an EXPIRED hold — its commit\ncarries an old token and is refused.\nthe seat already belongs to someone else",
      "color": "green",
      "size": 12
    }
  },
  "meta": {
    "createdAt": "2026-07-13T09:00:00.000Z",
    "modifiedAt": "2026-07-13T09:00:00.000Z"
  }
}