{
  "docVersion": 1,
  "id": "template-offline-first-mobile-sync",
  "name": "Offline-first mobile sync",
  "purpose": "Local-first mobile architecture: writes hit the on-device store instantly, a sync engine exchanges deltas with the server via cursors, conflicts are resolved client-side by domain rules.",
  "nodes": {
    "app": {
      "type": "mobile",
      "label": "Mobile app",
      "x": 20,
      "y": 80,
      "runtime": "optimistic UI",
      "color": "green",
      "notes": "Reads and writes ONLY the local store — the UI never waits on the network. Server confirmations reconcile in the background; a rejected write is repaired visibly, not silently."
    },
    "local": {
      "type": "storage",
      "label": "Local store (SQLite)",
      "x": 20,
      "y": 320,
      "runtime": "primary · outbox of pending ops",
      "color": "green",
      "notes": "Holds the full working set plus an outbox of unsynced mutations, each with a client-generated id so the server can dedupe retries."
    },
    "sync": {
      "type": "gateway",
      "label": "Sync API",
      "x": 360,
      "y": 200,
      "runtime": "delta exchange · cursorized",
      "color": "blue",
      "patterns": [
        "stateless",
        "autoscale"
      ],
      "notes": "push: applies client mutations (idempotent by mutation id). pull: streams rows changed since the device's cursor. Detects write-write conflicts via row versions and returns both versions to the client."
    },
    "db": {
      "type": "database",
      "label": "Server DB",
      "x": 700,
      "y": 80,
      "runtime": "authoritative · version per row",
      "patterns": [
        "replicated",
        "backup"
      ]
    },
    "feed": {
      "type": "stream",
      "label": "Change feed",
      "x": 700,
      "y": 340,
      "runtime": "row versions in commit order"
    },
    "push": {
      "type": "push",
      "label": "Push notifier",
      "x": 360,
      "y": 460,
      "runtime": "silent sync nudge"
    }
  },
  "edges": {
    "e1": {
      "from": "app",
      "to": "local",
      "fromSide": "bottom",
      "toSide": "top",
      "label": "read/write · ~2ms",
      "animated": true
    },
    "e2": {
      "from": "local",
      "to": "sync",
      "fromSide": "right",
      "toSide": "left",
      "label": "push outbox deltas",
      "style": "dashed",
      "patterns": [
        "idempotent",
        "retry",
        "batch"
      ]
    },
    "e3": {
      "from": "sync",
      "to": "db",
      "fromSide": "right",
      "toSide": "left",
      "label": "apply · version check",
      "patterns": [
        "idempotent"
      ]
    },
    "e4": {
      "from": "db",
      "to": "feed",
      "fromSide": "bottom",
      "toSide": "top",
      "label": "CDC",
      "style": "dashed"
    },
    "e5": {
      "from": "feed",
      "to": "sync",
      "fromSide": "left",
      "toSide": "bottom",
      "label": "changes since cursor",
      "style": "dashed"
    },
    "e6": {
      "from": "sync",
      "to": "local",
      "fromSide": "bottom",
      "toSide": "bottom",
      "label": "pull deltas → merge",
      "style": "dashed",
      "animated": true,
      "color": "blue"
    },
    "e7": {
      "from": "push",
      "to": "app",
      "fromSide": "left",
      "toSide": "bottom",
      "label": "wake: new changes",
      "style": "dashed",
      "color": "gray"
    }
  },
  "boxes": {
    "b1": {
      "x": -20,
      "y": 0,
      "w": 350,
      "h": 480,
      "label": "the device — fully functional offline",
      "color": "green",
      "opacity": 0.04
    }
  },
  "texts": {
    "t1": {
      "x": 700,
      "y": 520,
      "text": "conflict path: both sides edited row 42 →\nsync returns theirs+ours with versions →\nthe CLIENT merges (domain rules: latest\nstatus wins, notes concatenate) → push again.",
      "color": "amber",
      "size": 12
    }
  },
  "meta": {
    "createdAt": "2026-07-13T09:00:00.000Z",
    "modifiedAt": "2026-07-13T09:00:00.000Z"
  }
}