{
  "type": "excalidraw",
  "version": 2,
  "source": "infra-field-guide local editable architecture",
  "elements": [
    {
      "id": "migration-process",
      "type": "rectangle",
      "x": 40,
      "y": 160,
      "width": 1520,
      "height": 390,
      "angle": 0,
      "strokeColor": "#a9d4e6",
      "backgroundColor": "#ffffff",
      "fillStyle": "solid",
      "strokeWidth": 2,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": {
        "type": 3
      },
      "seed": 3,
      "version": 1,
      "versionNonce": 3,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "customData": {
        "kind": "region",
        "name": "迁移主线 · 每一步有观察结果才进入下一步",
        "responsibility": "正式 writer 包含 API、后台 job、队列、cron/timer、其他机器和手工操作。",
        "evidenceStatus": "reference-model"
      }
    },
    {
      "id": "entry-choices",
      "type": "rectangle",
      "x": 40,
      "y": 855,
      "width": 1520,
      "height": 250,
      "angle": 0,
      "strokeColor": "#a9d4e6",
      "backgroundColor": "#ffffff",
      "fillStyle": "solid",
      "strokeWidth": 2,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": {
        "type": 3
      },
      "seed": 30,
      "version": 1,
      "versionNonce": 30,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "customData": {
        "kind": "region",
        "name": "入口是另一层状态 · 以下是可选分支，不是顺序步骤",
        "responsibility": "确认所有真实客户端与缓存；入口切换成功不等于正式数据已一致。",
        "evidenceStatus": "reference-model"
      }
    },
    {
      "id": "advance-0",
      "type": "arrow",
      "x": 310,
      "y": 380,
      "width": 60,
      "height": 0,
      "angle": 0,
      "strokeColor": "#6ab9db",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 2.5,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 16,
      "version": 1,
      "versionNonce": 16,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "points": [
        [
          0,
          0
        ],
        [
          60,
          0
        ]
      ],
      "startBinding": {
        "elementId": "source-state",
        "focus": 0,
        "gap": 1
      },
      "endBinding": {
        "elementId": "freeze-state",
        "focus": 0,
        "gap": 1
      },
      "startArrowhead": null,
      "endArrowhead": "arrow",
      "elbowed": false,
      "customData": {
        "kind": "edge",
        "source": "source-state",
        "destination": "freeze-state",
        "payload": "完成该阶段验证后进入下一状态",
        "evidenceStatus": "reference-model"
      }
    },
    {
      "id": "advance-1",
      "type": "arrow",
      "x": 615,
      "y": 380,
      "width": 60,
      "height": 0,
      "angle": 0,
      "strokeColor": "#6ab9db",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 2.5,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 17,
      "version": 1,
      "versionNonce": 17,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "points": [
        [
          0,
          0
        ],
        [
          60,
          0
        ]
      ],
      "startBinding": {
        "elementId": "freeze-state",
        "focus": 0,
        "gap": 1
      },
      "endBinding": {
        "elementId": "restore-state",
        "focus": 0,
        "gap": 1
      },
      "startArrowhead": null,
      "endArrowhead": "arrow",
      "elbowed": false,
      "customData": {
        "kind": "edge",
        "source": "freeze-state",
        "destination": "restore-state",
        "payload": "完成该阶段验证后进入下一状态",
        "evidenceStatus": "reference-model"
      }
    },
    {
      "id": "advance-2",
      "type": "arrow",
      "x": 920,
      "y": 380,
      "width": 60,
      "height": 0,
      "angle": 0,
      "strokeColor": "#6ab9db",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 2.5,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 18,
      "version": 1,
      "versionNonce": 18,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "points": [
        [
          0,
          0
        ],
        [
          60,
          0
        ]
      ],
      "startBinding": {
        "elementId": "restore-state",
        "focus": 0,
        "gap": 1
      },
      "endBinding": {
        "elementId": "entry-state",
        "focus": 0,
        "gap": 1
      },
      "startArrowhead": null,
      "endArrowhead": "arrow",
      "elbowed": false,
      "customData": {
        "kind": "edge",
        "source": "restore-state",
        "destination": "entry-state",
        "payload": "完成该阶段验证后进入下一状态",
        "evidenceStatus": "reference-model"
      }
    },
    {
      "id": "advance-3",
      "type": "arrow",
      "x": 1225,
      "y": 380,
      "width": 60,
      "height": 0,
      "angle": 0,
      "strokeColor": "#6ab9db",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 2.5,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 19,
      "version": 1,
      "versionNonce": 19,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "points": [
        [
          0,
          0
        ],
        [
          60,
          0
        ]
      ],
      "startBinding": {
        "elementId": "entry-state",
        "focus": 0,
        "gap": 1
      },
      "endBinding": {
        "elementId": "target-state",
        "focus": 0,
        "gap": 1
      },
      "startArrowhead": null,
      "endArrowhead": "arrow",
      "elbowed": false,
      "customData": {
        "kind": "edge",
        "source": "entry-state",
        "destination": "target-state",
        "payload": "完成该阶段验证后进入下一状态",
        "evidenceStatus": "reference-model"
      }
    },
    {
      "id": "no-new-writes-return",
      "type": "arrow",
      "x": 1102,
      "y": 470,
      "width": 915,
      "height": 130,
      "angle": 0,
      "strokeColor": "#6ab9db",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 2.5,
      "strokeStyle": "dashed",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 20,
      "version": 1,
      "versionNonce": 20,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "points": [
        [
          0,
          0
        ],
        [
          0,
          130
        ],
        [
          -915,
          130
        ],
        [
          -915,
          0
        ]
      ],
      "startBinding": {
        "elementId": "entry-state",
        "focus": 0,
        "gap": 1
      },
      "endBinding": {
        "elementId": "source-state",
        "focus": 0,
        "gap": 1
      },
      "startArrowhead": null,
      "endArrowhead": "arrow",
      "elbowed": false,
      "customData": {
        "kind": "edge",
        "source": "entry-state",
        "destination": "source-state",
        "payload": "目标没有新写入时，关闭目标并恢复旧入口，再重新开放源 writer",
        "evidenceStatus": "reference-model"
      }
    },
    {
      "id": "keep-new-data",
      "type": "arrow",
      "x": 1407,
      "y": 470,
      "width": 0,
      "height": 190,
      "angle": 0,
      "strokeColor": "#6ab9db",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 2.5,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 25,
      "version": 1,
      "versionNonce": 25,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "points": [
        [
          0,
          0
        ],
        [
          0,
          190
        ]
      ],
      "startBinding": {
        "elementId": "target-state",
        "focus": 0,
        "gap": 1
      },
      "endBinding": {
        "elementId": "new-data-recovery",
        "focus": 0,
        "gap": 1
      },
      "startArrowhead": null,
      "endArrowhead": "arrow",
      "elbowed": false,
      "customData": {
        "kind": "edge",
        "source": "target-state",
        "destination": "new-data-recovery",
        "payload": "目标写入后出故障须保留新增数据",
        "evidenceStatus": "reference-model"
      }
    },
    {
      "id": "title",
      "type": "text",
      "x": 40,
      "y": 28,
      "width": 1520,
      "height": 45.900000000000006,
      "angle": 0,
      "strokeColor": "#163a5f",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 1,
      "version": 1,
      "versionNonce": 1,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "fontSize": 34,
      "fontFamily": 2,
      "text": "迁移状态 · 先决定谁能写，再决定请求到哪里",
      "originalText": "迁移状态 · 先决定谁能写，再决定请求到哪里",
      "textAlign": "left",
      "verticalAlign": "top",
      "containerId": null,
      "autoResize": false,
      "lineHeight": 1.35,
      "customData": {
        "weight": 700,
        "boldFirstLine": false,
        "guide": {
          "title": "迁移状态 · 先决定谁能写，再决定请求到哪里",
          "description": "参考：本机 → VPS 或旧 VPS → 新 VPS；DNS、Tunnel、Tailnet 入口切换都不能代替数据一致性。",
          "width": 1600,
          "height": 1210,
          "evidence": [
            "../04-local-to-vps.md",
            "../05-vps-to-vps.md",
            "../../examples/migration-plan.example.json"
          ],
          "state": {
            "canonical": "当前唯一正式 writer 所写的数据库、附件与队列状态",
            "writers": "S0源写；S1-S3两侧禁写；S4目标写源禁写",
            "receipts": "冻结完成记录、最终快照边界、恢复验证、入口读验收、目标首次新写入"
          },
          "question": "迁移什么时候还能恢复旧机，什么时候必须处理新数据？",
          "status": "reference-model"
        }
      }
    },
    {
      "id": "subtitle",
      "type": "text",
      "x": 40,
      "y": 82,
      "width": 1520,
      "height": 25.650000000000002,
      "angle": 0,
      "strokeColor": "#365775",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 2,
      "version": 1,
      "versionNonce": 2,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "fontSize": 19,
      "fontFamily": 2,
      "text": "参考：本机 → VPS 或旧 VPS → 新 VPS；DNS、Tunnel、Tailnet 入口切换都不能代替数据一致性。",
      "originalText": "参考：本机 → VPS 或旧 VPS → 新 VPS；DNS、Tunnel、Tailnet 入口切换都不能代替数据一致性。",
      "textAlign": "left",
      "verticalAlign": "top",
      "containerId": null,
      "autoResize": false,
      "lineHeight": 1.35,
      "customData": {
        "weight": 400,
        "boldFirstLine": false
      }
    },
    {
      "id": "migration-process-heading",
      "type": "text",
      "x": 60,
      "y": 175,
      "width": 1480,
      "height": 29.700000000000003,
      "angle": 0,
      "strokeColor": "#365775",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 4,
      "version": 1,
      "versionNonce": 4,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "fontSize": 22,
      "fontFamily": 2,
      "text": "迁移主线 · 每一步有观察结果才进入下一步",
      "originalText": "迁移主线 · 每一步有观察结果才进入下一步",
      "textAlign": "left",
      "verticalAlign": "top",
      "containerId": null,
      "autoResize": false,
      "lineHeight": 1.35,
      "customData": {
        "weight": 700,
        "boldFirstLine": false
      }
    },
    {
      "id": "migration-process-sub",
      "type": "text",
      "x": 60,
      "y": 209,
      "width": 1480,
      "height": 21.6,
      "angle": 0,
      "strokeColor": "#365775",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 5,
      "version": 1,
      "versionNonce": 5,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "fontSize": 16,
      "fontFamily": 2,
      "text": "正式 writer 包含 API、后台 job、队列、cron/timer、其他机器和手工操作。",
      "originalText": "正式 writer 包含 API、后台 job、队列、cron/timer、其他机器和手工操作。",
      "textAlign": "left",
      "verticalAlign": "top",
      "containerId": null,
      "autoResize": false,
      "lineHeight": 1.35,
      "customData": {
        "weight": 400,
        "boldFirstLine": false
      }
    },
    {
      "id": "source-state",
      "type": "rectangle",
      "x": 65,
      "y": 290,
      "width": 245,
      "height": 180,
      "angle": 0,
      "strokeColor": "#6ab9db",
      "backgroundColor": "#e9f7fc",
      "fillStyle": "solid",
      "strokeWidth": 2,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": {
        "type": 3
      },
      "seed": 6,
      "version": 1,
      "versionNonce": 6,
      "isDeleted": false,
      "boundElements": [
        {
          "id": "source-state-text",
          "type": "text"
        },
        {
          "id": "advance-0",
          "type": "arrow"
        },
        {
          "id": "no-new-writes-return",
          "type": "arrow"
        }
      ],
      "updated": 0,
      "link": null,
      "locked": false,
      "customData": {
        "kind": "node",
        "name": "S0 · 源唯一写入",
        "responsibility": "候选机独立演练 / 代码 / 配置 / 恢复先验证",
        "evidence": [
          "../04-local-to-vps.md",
          "../05-vps-to-vps.md",
          "../../examples/migration-plan.example.json"
        ],
        "evidenceStatus": "reference-model"
      }
    },
    {
      "id": "source-state-text",
      "type": "text",
      "x": 83,
      "y": 337.5,
      "width": 209,
      "height": 81.0,
      "angle": 0,
      "strokeColor": "#163a5f",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 7,
      "version": 1,
      "versionNonce": 7,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 2,
      "text": "S0 · 源唯一写入\n候选机独立演练\n代码 / 配置 / 恢复先验证",
      "originalText": "S0 · 源唯一写入\n候选机独立演练\n代码 / 配置 / 恢复先验证",
      "textAlign": "left",
      "verticalAlign": "top",
      "containerId": "source-state",
      "autoResize": false,
      "lineHeight": 1.35,
      "customData": {
        "weight": 400,
        "boldFirstLine": true
      }
    },
    {
      "id": "freeze-state",
      "type": "rectangle",
      "x": 370,
      "y": 290,
      "width": 245,
      "height": 180,
      "angle": 0,
      "strokeColor": "#6ab9db",
      "backgroundColor": "#e9f7fc",
      "fillStyle": "solid",
      "strokeWidth": 2,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": {
        "type": 3
      },
      "seed": 8,
      "version": 1,
      "versionNonce": 8,
      "isDeleted": false,
      "boundElements": [
        {
          "id": "freeze-state-text",
          "type": "text"
        },
        {
          "id": "advance-0",
          "type": "arrow"
        },
        {
          "id": "advance-1",
          "type": "arrow"
        }
      ],
      "updated": 0,
      "link": null,
      "locked": false,
      "customData": {
        "kind": "node",
        "name": "S1 · 冻结所有写入",
        "responsibility": "两侧均禁写 / 最终快照 + 边界记录",
        "evidence": [
          "../04-local-to-vps.md",
          "../05-vps-to-vps.md",
          "../../examples/migration-plan.example.json"
        ],
        "evidenceStatus": "reference-model"
      }
    },
    {
      "id": "freeze-state-text",
      "type": "text",
      "x": 388,
      "y": 337.5,
      "width": 209,
      "height": 81.0,
      "angle": 0,
      "strokeColor": "#163a5f",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 9,
      "version": 1,
      "versionNonce": 9,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 2,
      "text": "S1 · 冻结所有写入\n两侧均禁写\n最终快照 + 边界记录",
      "originalText": "S1 · 冻结所有写入\n两侧均禁写\n最终快照 + 边界记录",
      "textAlign": "left",
      "verticalAlign": "top",
      "containerId": "freeze-state",
      "autoResize": false,
      "lineHeight": 1.35,
      "customData": {
        "weight": 400,
        "boldFirstLine": true
      }
    },
    {
      "id": "restore-state",
      "type": "rectangle",
      "x": 675,
      "y": 290,
      "width": 245,
      "height": 180,
      "angle": 0,
      "strokeColor": "#6ab9db",
      "backgroundColor": "#e9f7fc",
      "fillStyle": "solid",
      "strokeWidth": 2,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": {
        "type": 3
      },
      "seed": 10,
      "version": 1,
      "versionNonce": 10,
      "isDeleted": false,
      "boundElements": [
        {
          "id": "restore-state-text",
          "type": "text"
        },
        {
          "id": "advance-1",
          "type": "arrow"
        },
        {
          "id": "advance-2",
          "type": "arrow"
        }
      ],
      "updated": 0,
      "link": null,
      "locked": false,
      "customData": {
        "kind": "node",
        "name": "S2 · 目标恢复验收",
        "responsibility": "恢复数据库与附件 / 目标只读；源仍禁写",
        "evidence": [
          "../04-local-to-vps.md",
          "../05-vps-to-vps.md",
          "../../examples/migration-plan.example.json"
        ],
        "evidenceStatus": "reference-model"
      }
    },
    {
      "id": "restore-state-text",
      "type": "text",
      "x": 693,
      "y": 337.5,
      "width": 209,
      "height": 81.0,
      "angle": 0,
      "strokeColor": "#163a5f",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 11,
      "version": 1,
      "versionNonce": 11,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 2,
      "text": "S2 · 目标恢复验收\n恢复数据库与附件\n目标只读；源仍禁写",
      "originalText": "S2 · 目标恢复验收\n恢复数据库与附件\n目标只读；源仍禁写",
      "textAlign": "left",
      "verticalAlign": "top",
      "containerId": "restore-state",
      "autoResize": false,
      "lineHeight": 1.35,
      "customData": {
        "weight": 400,
        "boldFirstLine": true
      }
    },
    {
      "id": "entry-state",
      "type": "rectangle",
      "x": 980,
      "y": 290,
      "width": 245,
      "height": 180,
      "angle": 0,
      "strokeColor": "#6ab9db",
      "backgroundColor": "#e9f7fc",
      "fillStyle": "solid",
      "strokeWidth": 2,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": {
        "type": 3
      },
      "seed": 12,
      "version": 1,
      "versionNonce": 12,
      "isDeleted": false,
      "boundElements": [
        {
          "id": "entry-state-text",
          "type": "text"
        },
        {
          "id": "advance-2",
          "type": "arrow"
        },
        {
          "id": "advance-3",
          "type": "arrow"
        },
        {
          "id": "no-new-writes-return",
          "type": "arrow"
        }
      ],
      "updated": 0,
      "link": null,
      "locked": false,
      "customData": {
        "kind": "node",
        "name": "S3 · 切入口后读验收",
        "responsibility": "请求到目标，但尚不写 / 源不会重启后自行复活",
        "evidence": [
          "../04-local-to-vps.md",
          "../05-vps-to-vps.md",
          "../../examples/migration-plan.example.json"
        ],
        "evidenceStatus": "reference-model"
      }
    },
    {
      "id": "entry-state-text",
      "type": "text",
      "x": 998,
      "y": 337.5,
      "width": 209,
      "height": 81.0,
      "angle": 0,
      "strokeColor": "#163a5f",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 13,
      "version": 1,
      "versionNonce": 13,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 2,
      "text": "S3 · 切入口后读验收\n请求到目标，但尚不写\n源不会重启后自行复活",
      "originalText": "S3 · 切入口后读验收\n请求到目标，但尚不写\n源不会重启后自行复活",
      "textAlign": "left",
      "verticalAlign": "top",
      "containerId": "entry-state",
      "autoResize": false,
      "lineHeight": 1.35,
      "customData": {
        "weight": 400,
        "boldFirstLine": true
      }
    },
    {
      "id": "target-state",
      "type": "rectangle",
      "x": 1285,
      "y": 290,
      "width": 245,
      "height": 180,
      "angle": 0,
      "strokeColor": "#e7c979",
      "backgroundColor": "#fff5d9",
      "fillStyle": "solid",
      "strokeWidth": 2,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": {
        "type": 3
      },
      "seed": 14,
      "version": 1,
      "versionNonce": 14,
      "isDeleted": false,
      "boundElements": [
        {
          "id": "target-state-text",
          "type": "text"
        },
        {
          "id": "advance-3",
          "type": "arrow"
        },
        {
          "id": "keep-new-data",
          "type": "arrow"
        }
      ],
      "updated": 0,
      "link": null,
      "locked": false,
      "customData": {
        "kind": "node",
        "name": "S4 · 目标唯一写入",
        "responsibility": "记下首次正式新写入 / 源禁写；不再自动回退",
        "evidence": [
          "../04-local-to-vps.md",
          "../05-vps-to-vps.md",
          "../../examples/migration-plan.example.json"
        ],
        "evidenceStatus": "reference-model"
      }
    },
    {
      "id": "target-state-text",
      "type": "text",
      "x": 1303,
      "y": 337.5,
      "width": 209,
      "height": 81.0,
      "angle": 0,
      "strokeColor": "#163a5f",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 15,
      "version": 1,
      "versionNonce": 15,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 2,
      "text": "S4 · 目标唯一写入\n记下首次正式新写入\n源禁写；不再自动回退",
      "originalText": "S4 · 目标唯一写入\n记下首次正式新写入\n源禁写；不再自动回退",
      "textAlign": "left",
      "verticalAlign": "top",
      "containerId": "target-state",
      "autoResize": false,
      "lineHeight": 1.35,
      "customData": {
        "weight": 400,
        "boldFirstLine": true
      }
    },
    {
      "id": "no-new-writes-return-label-bg",
      "type": "rectangle",
      "x": 265,
      "y": 568,
      "width": 730,
      "height": 26.950000000000003,
      "angle": 0,
      "strokeColor": "#ffffff",
      "backgroundColor": "#ffffff",
      "fillStyle": "solid",
      "strokeWidth": 2,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": {
        "type": 3
      },
      "seed": 21,
      "version": 1,
      "versionNonce": 21,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "customData": {}
    },
    {
      "id": "no-new-writes-return-label",
      "type": "text",
      "x": 270,
      "y": 570,
      "width": 720,
      "height": 22.950000000000003,
      "angle": 0,
      "strokeColor": "#365775",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 22,
      "version": 1,
      "versionNonce": 22,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "fontSize": 17,
      "fontFamily": 2,
      "text": "仅当目标尚无新写入：关闭目标 → 恢复旧入口 → 开放源",
      "originalText": "仅当目标尚无新写入：关闭目标 → 恢复旧入口 → 开放源",
      "textAlign": "center",
      "verticalAlign": "top",
      "containerId": null,
      "autoResize": false,
      "lineHeight": 1.35,
      "customData": {
        "weight": 400,
        "boldFirstLine": false
      }
    },
    {
      "id": "new-data-recovery",
      "type": "rectangle",
      "x": 980,
      "y": 660,
      "width": 550,
      "height": 155,
      "angle": 0,
      "strokeColor": "#e7c979",
      "backgroundColor": "#fff5d9",
      "fillStyle": "solid",
      "strokeWidth": 2,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": {
        "type": 3
      },
      "seed": 23,
      "version": 1,
      "versionNonce": 23,
      "isDeleted": false,
      "boundElements": [
        {
          "id": "new-data-recovery-text",
          "type": "text"
        },
        {
          "id": "keep-new-data",
          "type": "arrow"
        }
      ],
      "updated": 0,
      "link": null,
      "locked": false,
      "customData": {
        "kind": "node",
        "name": "首次新写入之后 · 恢复必须覆盖差异",
        "responsibility": "优先修复目标；或冻结、备份新状态并对账， / 再进行受控反向迁移。只改回 DNS 会漏掉新数据。",
        "evidence": [
          "../04-local-to-vps.md",
          "../05-vps-to-vps.md",
          "../../examples/migration-plan.example.json"
        ],
        "evidenceStatus": "reference-model"
      }
    },
    {
      "id": "new-data-recovery-text",
      "type": "text",
      "x": 998,
      "y": 695.0,
      "width": 514,
      "height": 81.0,
      "angle": 0,
      "strokeColor": "#163a5f",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 24,
      "version": 1,
      "versionNonce": 24,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 2,
      "text": "首次新写入之后 · 恢复必须覆盖差异\n优先修复目标；或冻结、备份新状态并对账，\n再进行受控反向迁移。只改回 DNS 会漏掉新数据。",
      "originalText": "首次新写入之后 · 恢复必须覆盖差异\n优先修复目标；或冻结、备份新状态并对账，\n再进行受控反向迁移。只改回 DNS 会漏掉新数据。",
      "textAlign": "left",
      "verticalAlign": "top",
      "containerId": "new-data-recovery",
      "autoResize": false,
      "lineHeight": 1.35,
      "customData": {
        "weight": 400,
        "boldFirstLine": true
      }
    },
    {
      "id": "keep-new-data-label-bg",
      "type": "rectangle",
      "x": 1205,
      "y": 568,
      "width": 327,
      "height": 26.950000000000003,
      "angle": 0,
      "strokeColor": "#ffffff",
      "backgroundColor": "#ffffff",
      "fillStyle": "solid",
      "strokeWidth": 2,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": {
        "type": 3
      },
      "seed": 26,
      "version": 1,
      "versionNonce": 26,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "customData": {}
    },
    {
      "id": "keep-new-data-label",
      "type": "text",
      "x": 1210,
      "y": 570,
      "width": 317,
      "height": 22.950000000000003,
      "angle": 0,
      "strokeColor": "#365775",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 27,
      "version": 1,
      "versionNonce": 27,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "fontSize": 17,
      "fontFamily": 2,
      "text": "先保留目标新增数据",
      "originalText": "先保留目标新增数据",
      "textAlign": "center",
      "verticalAlign": "top",
      "containerId": null,
      "autoResize": false,
      "lineHeight": 1.35,
      "customData": {
        "weight": 400,
        "boldFirstLine": false
      }
    },
    {
      "id": "dual-write",
      "type": "rectangle",
      "x": 65,
      "y": 660,
      "width": 825,
      "height": 155,
      "angle": 0,
      "strokeColor": "#6ab9db",
      "backgroundColor": "#ffffff",
      "fillStyle": "solid",
      "strokeWidth": 2,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": {
        "type": 3
      },
      "seed": 28,
      "version": 1,
      "versionNonce": 28,
      "isDeleted": false,
      "boundElements": [
        {
          "id": "dual-write-text",
          "type": "text"
        }
      ],
      "updated": 0,
      "link": null,
      "locked": false,
      "customData": {
        "kind": "node",
        "name": "若意外出现双写：冻结受影响 writer，保留两侧事实",
        "responsibility": "按业务主键、事件顺序或账目做对账；不能盲目以旧库覆盖新库。 / 长任务需要 owner、日志、state、status 与 resume，避免重发成重复 writer。",
        "evidence": [
          "../04-local-to-vps.md",
          "../05-vps-to-vps.md",
          "../../examples/migration-plan.example.json"
        ],
        "evidenceStatus": "reference-model"
      }
    },
    {
      "id": "dual-write-text",
      "type": "text",
      "x": 83,
      "y": 695.0,
      "width": 789,
      "height": 81.0,
      "angle": 0,
      "strokeColor": "#163a5f",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 29,
      "version": 1,
      "versionNonce": 29,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 2,
      "text": "若意外出现双写：冻结受影响 writer，保留两侧事实\n按业务主键、事件顺序或账目做对账；不能盲目以旧库覆盖新库。\n长任务需要 owner、日志、state、status 与 resume，避免重发成重复 writer。",
      "originalText": "若意外出现双写：冻结受影响 writer，保留两侧事实\n按业务主键、事件顺序或账目做对账；不能盲目以旧库覆盖新库。\n长任务需要 owner、日志、state、status 与 resume，避免重发成重复 writer。",
      "textAlign": "left",
      "verticalAlign": "top",
      "containerId": "dual-write",
      "autoResize": false,
      "lineHeight": 1.35,
      "customData": {
        "weight": 400,
        "boldFirstLine": true
      }
    },
    {
      "id": "entry-choices-heading",
      "type": "text",
      "x": 60,
      "y": 870,
      "width": 1480,
      "height": 29.700000000000003,
      "angle": 0,
      "strokeColor": "#365775",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 31,
      "version": 1,
      "versionNonce": 31,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "fontSize": 22,
      "fontFamily": 2,
      "text": "入口是另一层状态 · 以下是可选分支，不是顺序步骤",
      "originalText": "入口是另一层状态 · 以下是可选分支，不是顺序步骤",
      "textAlign": "left",
      "verticalAlign": "top",
      "containerId": null,
      "autoResize": false,
      "lineHeight": 1.35,
      "customData": {
        "weight": 700,
        "boldFirstLine": false
      }
    },
    {
      "id": "entry-choices-sub",
      "type": "text",
      "x": 60,
      "y": 904,
      "width": 1480,
      "height": 21.6,
      "angle": 0,
      "strokeColor": "#365775",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 32,
      "version": 1,
      "versionNonce": 32,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "fontSize": 16,
      "fontFamily": 2,
      "text": "确认所有真实客户端与缓存；入口切换成功不等于正式数据已一致。",
      "originalText": "确认所有真实客户端与缓存；入口切换成功不等于正式数据已一致。",
      "textAlign": "left",
      "verticalAlign": "top",
      "containerId": null,
      "autoResize": false,
      "lineHeight": 1.35,
      "customData": {
        "weight": 400,
        "boldFirstLine": false
      }
    },
    {
      "id": "dns-cutover",
      "type": "rectangle",
      "x": 65,
      "y": 945,
      "width": 465,
      "height": 130,
      "angle": 0,
      "strokeColor": "#6ab9db",
      "backgroundColor": "#ffffff",
      "fillStyle": "solid",
      "strokeWidth": 2,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": {
        "type": 3
      },
      "seed": 33,
      "version": 1,
      "versionNonce": 33,
      "isDeleted": false,
      "boundElements": [
        {
          "id": "dns-cutover-text",
          "type": "text"
        }
      ],
      "updated": 0,
      "link": null,
      "locked": false,
      "customData": {
        "kind": "node",
        "name": "直接 DNS / IP",
        "responsibility": "A / AAAA / CNAME 与 TTL / 缓存 / 旧入口在缓存期仍可能收到请求",
        "evidence": [
          "../04-local-to-vps.md",
          "../05-vps-to-vps.md",
          "../../examples/migration-plan.example.json"
        ],
        "evidenceStatus": "reference-model"
      }
    },
    {
      "id": "dns-cutover-text",
      "type": "text",
      "x": 83,
      "y": 967.5,
      "width": 429,
      "height": 81.0,
      "angle": 0,
      "strokeColor": "#163a5f",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 34,
      "version": 1,
      "versionNonce": 34,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 2,
      "text": "直接 DNS / IP\nA / AAAA / CNAME 与 TTL / 缓存\n旧入口在缓存期仍可能收到请求",
      "originalText": "直接 DNS / IP\nA / AAAA / CNAME 与 TTL / 缓存\n旧入口在缓存期仍可能收到请求",
      "textAlign": "left",
      "verticalAlign": "top",
      "containerId": "dns-cutover",
      "autoResize": false,
      "lineHeight": 1.35,
      "customData": {
        "weight": 400,
        "boldFirstLine": true
      }
    },
    {
      "id": "tunnel-cutover",
      "type": "rectangle",
      "x": 565,
      "y": 945,
      "width": 470,
      "height": 130,
      "angle": 0,
      "strokeColor": "#6ab9db",
      "backgroundColor": "#ffffff",
      "fillStyle": "solid",
      "strokeWidth": 2,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": {
        "type": 3
      },
      "seed": 35,
      "version": 1,
      "versionNonce": 35,
      "isDeleted": false,
      "boundElements": [
        {
          "id": "tunnel-cutover-text",
          "type": "text"
        }
      ],
      "updated": 0,
      "link": null,
      "locked": false,
      "customData": {
        "kind": "node",
        "name": "Cloudflare Tunnel",
        "responsibility": "同 tunnel 多 connector 可同时接流量 / 不是天然主备；Access 配置也要验证",
        "evidence": [
          "../04-local-to-vps.md",
          "../05-vps-to-vps.md",
          "../../examples/migration-plan.example.json"
        ],
        "evidenceStatus": "reference-model"
      }
    },
    {
      "id": "tunnel-cutover-text",
      "type": "text",
      "x": 583,
      "y": 967.5,
      "width": 434,
      "height": 81.0,
      "angle": 0,
      "strokeColor": "#163a5f",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 36,
      "version": 1,
      "versionNonce": 36,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 2,
      "text": "Cloudflare Tunnel\n同 tunnel 多 connector 可同时接流量\n不是天然主备；Access 配置也要验证",
      "originalText": "Cloudflare Tunnel\n同 tunnel 多 connector 可同时接流量\n不是天然主备；Access 配置也要验证",
      "textAlign": "left",
      "verticalAlign": "top",
      "containerId": "tunnel-cutover",
      "autoResize": false,
      "lineHeight": 1.35,
      "customData": {
        "weight": 400,
        "boldFirstLine": true
      }
    },
    {
      "id": "tailnet-cutover",
      "type": "rectangle",
      "x": 1070,
      "y": 945,
      "width": 465,
      "height": 130,
      "angle": 0,
      "strokeColor": "#6ab9db",
      "backgroundColor": "#ffffff",
      "fillStyle": "solid",
      "strokeWidth": 2,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": {
        "type": 3
      },
      "seed": 37,
      "version": 1,
      "versionNonce": 37,
      "isDeleted": false,
      "boundElements": [
        {
          "id": "tailnet-cutover-text",
          "type": "text"
        }
      ],
      "updated": 0,
      "link": null,
      "locked": false,
      "customData": {
        "kind": "node",
        "name": "Tailnet 私有入口",
        "responsibility": "新节点身份、grant、端点与客户端 / 不要复制旧节点身份来假装同一台机器",
        "evidence": [
          "../04-local-to-vps.md",
          "../05-vps-to-vps.md",
          "../../examples/migration-plan.example.json"
        ],
        "evidenceStatus": "reference-model"
      }
    },
    {
      "id": "tailnet-cutover-text",
      "type": "text",
      "x": 1088,
      "y": 967.5,
      "width": 429,
      "height": 81.0,
      "angle": 0,
      "strokeColor": "#163a5f",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 38,
      "version": 1,
      "versionNonce": 38,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "fontSize": 20,
      "fontFamily": 2,
      "text": "Tailnet 私有入口\n新节点身份、grant、端点与客户端\n不要复制旧节点身份来假装同一台机器",
      "originalText": "Tailnet 私有入口\n新节点身份、grant、端点与客户端\n不要复制旧节点身份来假装同一台机器",
      "textAlign": "left",
      "verticalAlign": "top",
      "containerId": "tailnet-cutover",
      "autoResize": false,
      "lineHeight": 1.35,
      "customData": {
        "weight": 400,
        "boldFirstLine": true
      }
    },
    {
      "id": "footer",
      "type": "text",
      "x": 40,
      "y": 1168,
      "width": 1520,
      "height": 21.6,
      "angle": 0,
      "strokeColor": "#365775",
      "backgroundColor": "transparent",
      "fillStyle": "solid",
      "strokeWidth": 1,
      "strokeStyle": "solid",
      "roughness": 0,
      "opacity": 100,
      "groupIds": [],
      "frameId": null,
      "index": null,
      "roundness": null,
      "seed": 39,
      "version": 1,
      "versionNonce": 39,
      "isDeleted": false,
      "boundElements": null,
      "updated": 0,
      "link": null,
      "locked": false,
      "fontSize": 16,
      "fontFamily": 2,
      "text": "验收后再观察关键业务周期、独立备份恢复与重启行为。退役旧资源与确认停费是另一个明确动作；旧机存在本身不构成可用恢复。",
      "originalText": "验收后再观察关键业务周期、独立备份恢复与重启行为。退役旧资源与确认停费是另一个明确动作；旧机存在本身不构成可用恢复。",
      "textAlign": "left",
      "verticalAlign": "top",
      "containerId": null,
      "autoResize": false,
      "lineHeight": 1.35,
      "customData": {
        "weight": 400,
        "boldFirstLine": false
      }
    }
  ],
  "appState": {
    "viewBackgroundColor": "#ffffff",
    "gridSize": null
  },
  "files": {}
}
