{
  "schemaVersion": "flowdrome.workflow.v1",
  "id": "",
  "name": "Lead ledger — Flowdrome Tables",
  "version": "0",
  "status": "draft",
  "nodes": [
    {
      "id": "seed",
      "type": "input.inject",
      "label": "Incoming lead",
      "category": "trigger",
      "config": {
        "contentType": "application/json",
        "payload": {
          "email": "ada@acme.test",
          "company": "Acme",
          "score": 74
        }
      },
      "position": {
        "x": 0,
        "y": 0
      }
    },
    {
      "id": "prep",
      "type": "utility.javascript",
      "label": "Ensure table",
      "category": "script",
      "config": {
        "code": "await flowdrome.tables.ensure('Node Demo Leads', [{ name: 'email', type: 'text' }, { name: 'company', type: 'text' }, { name: 'score', type: 'number' }]); return input;",
        "outputs": [
          "output"
        ]
      },
      "position": {
        "x": 530,
        "y": 0
      }
    },
    {
      "id": "save",
      "type": "storage.table",
      "label": "Upsert lead",
      "category": "io",
      "config": {
        "table": "Node Demo Leads",
        "operation": "upsert",
        "matchColumn": "email",
        "values": {},
        "valuesPath": "",
        "rowId": "",
        "rowIdPath": "id",
        "filters": [],
        "limit": 50,
        "offset": 0,
        "orderBy": "",
        "order": "asc",
        "baseUrl": "",
        "token": "",
        "timeoutMs": 15000
      },
      "position": {
        "x": 1060,
        "y": 0
      }
    },
    {
      "id": "recent",
      "type": "storage.table",
      "label": "Freshest 5",
      "category": "io",
      "config": {
        "table": "Node Demo Leads",
        "operation": "list",
        "filters": [],
        "limit": 5,
        "offset": 0,
        "orderBy": "updatedAt",
        "order": "desc",
        "rowId": "",
        "rowIdPath": "id",
        "values": {},
        "valuesPath": "",
        "matchColumn": "",
        "baseUrl": "",
        "token": "",
        "timeoutMs": 15000
      },
      "position": {
        "x": 1590,
        "y": 0
      }
    },
    {
      "id": "out",
      "type": "utility.console",
      "label": "Lead ledger",
      "category": "utility",
      "config": {
        "message": "ledger holds {{ $json.total }} lead(s); freshest: {{ $json.rows }}"
      },
      "position": {
        "x": 2120,
        "y": 0
      }
    }
  ],
  "edges": [
    {
      "id": "e0",
      "sourceNodeId": "seed",
      "sourcePort": "output",
      "targetNodeId": "prep",
      "targetPort": "input"
    },
    {
      "id": "e1",
      "sourceNodeId": "prep",
      "sourcePort": "output",
      "targetNodeId": "save",
      "targetPort": "input"
    },
    {
      "id": "e2",
      "sourceNodeId": "save",
      "sourcePort": "output",
      "targetNodeId": "recent",
      "targetPort": "input"
    },
    {
      "id": "e3",
      "sourceNodeId": "recent",
      "sourcePort": "output",
      "targetNodeId": "out",
      "targetPort": "input"
    }
  ],
  "triggers": [
    {
      "id": "t0",
      "nodeId": "seed"
    }
  ],
  "meta": {
    "snippets": [],
    "source": "template-gallery",
    "description": "State BETWEEN runs without a database to run: a script node ensures the “Node Demo Leads” table exists (flowdrome.tables — the same API the Tables screen uses), the Table node UPSERTS the incoming lead (matched on email, so re-runs update instead of duplicating), then lists the freshest rows. Open the Nucleus → Tables screen to watch the grid fill; pair with the “New lead lands — Table trigger” demo to react to the writes."
  }
}