# Datatables: client-side playbook

n8n data tables: small operational stores a workflow reads/writes at runtime.
Read with `awesomate_n8n_inspect {what: "datatables"}` (tables, columns, row
counts, rows). Tables are created and edited in n8n itself: the user opens
**Data tables** in their n8n's left menu, or Claude creates one through the
n8n MCP server when that server offers a data-table tool. No Awesomate tool
creates or writes a table.

## Right store or wrong store

| Data | Store |
|---|---|
| Dedupe ledger (seen event ids, sent emails) | Datatable |
| Task queue / retry list a workflow drains | Datatable |
| Lookup map (SKU→label, email→owner) | Datatable |
| Cursor/state between runs (last-synced timestamp) | Datatable |
| Real app data (users, orders, content) | The app's own database, never a datatable |
| Analytics, event history, anything unbounded | External store (app DB, sheet, warehouse) |

Rule of thumb: bounded row count, flat rows, no joins, consumed by the
automation itself. n8n caps an instance at 50 tables.

## Creating: same project as the workflow

- **Datatables resolve PER PROJECT at runtime.** A workflow in project A
  referencing a table in project B fails on every run with
  `Could not find the data table: '<id>'` while the table, its columns, and
  permissions are all perfectly intact. When the id matches and structure
  looks fine, the project link is what's broken.
- So the table is created **inside the project that owns the workflow**
  (on a single-user instance that is the owner's personal project; check
  `awesomate_n8n_workflows` for which project a workflow sits in). Tell the
  user which project to be in when they create it, and read it back with
  `awesomate_n8n_inspect` to confirm before the workflow references it.
- Design the full column set up front: n8n's REST API cannot alter a table,
  so a column added later means the user does it in n8n's Data tables UI or
  the table is recreated. Column `type`: `string` | `number` | `boolean` |
  `date` (default `string`). Column names: letters/digits/underscores,
  starting with a letter, no spaces (n8n's row API references columns bare,
  so a spaced name is unwritable even though PG would accept it).
- Reference tables **by name** in the Data table node, never by id: a
  rebuilt table keeps its name and gets a new id.
- Walk the user through it in their words: "open Data tables, click Add,
  name it `sent_invoices`, add these three columns, done". Then confirm with
  `awesomate_n8n_inspect {what: "datatables"}`.

## Rows

Rows are written by the workflow itself (Data table node: insert, update,
delete with a filter) and read back with `awesomate_n8n_inspect`. To put
seed rows in by hand, the user pastes them in n8n's Data tables UI. There is
no delete-all; to empty a table, delete by filter or recreate it.

Tables that arrived with an Awesomate template belong to that managed
automation: read them freely, never change their schema or rows.

## The dedupe gate pattern (rowNotExists)

Insert-if-absent as a barrier before side effects: the main reason a
datatable exists in a client workflow.

1. Table with one key column (e.g. `event_id` string) plus any audit columns.
2. In the workflow, BEFORE the side effect (email, API call, charge): Data
   table node with the **row-does-not-exist** operation matching the key.
   Only unseen items pass.
3. Insert the key immediately after the gate, BEFORE the side effect.
   Insert-first gives at-most-once (right for emails and charges);
   insert-after gives at-least-once (duplicates on crash/retry).
4. The gate and insert are separate node steps, not a transaction: a webhook
   delivered twice in the same instant can pass both. Acceptable for dedupe;
   not a locking primitive.

Queue-drain workflows (`splitInBatches` over a table) need `executionTimeout`
set, and `saveExecutionProgress` stays FALSE. Both are platform invariants
you keep yourself.

## Failure decode

| Symptom | Meaning | Fix |
|---|---|---|
| `Could not find the data table: '<id>'` at runtime | Project scope, not existence | Recreate the table inside the workflow's project; check `awesomate_n8n_inspect {what: "datatables"}` vs the workflow's project |
| Data table node cannot see a column | Column name has a space or starts with a digit | Rename it in n8n's Data tables UI |
| Table count stuck at 50 | n8n's per-instance cap | Reuse or delete tables |
| Data tables missing from n8n's menu | Instance's n8n version predates data tables | No datatable path; use an external store |
