- 6 new PocketBase migrations: customer_pos, customer_po_lines, invoices, invoice_items, email_inbox, workflow_runs - n8N workflow JSON: 01-customer-po-to-parsed.json + 02-parsed-po-to-invoice.json - MCP server config (.cursor/mcp.json + .mcp.json) for AI agent PB access - .env.example template with all required credentials documented - n8n/README.md with deployment, testing, and customization notes |
||
|---|---|---|
| .. | ||
| 01-customer-po-to-parsed.json | ||
| 02-parsed-po-to-invoice.json | ||
| README.md | ||
JEISA Automation: Customer PO → Invoice → Stock
End-to-end pipeline that watches a JEI mailbox for incoming customer purchase orders, uploads them to PocketBase, creates QuickBooks invoices, emails them to customers, and decrements stock.
┌─────────────────┐ ┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Customer email │───▶│ n8N workflow │───▶│ PocketBase │ │ QuickBooks │
│ (PO PDF) │ │ 01: email→PB │ │ • customer_pos │ │ Online │
└─────────────────┘ └─────────────────┘ │ • parsed_lines │ └────────┬────────┘
└──────────────────┘ │
┌─────────────────┐ ┌─────────────────┐ ┌──────────────────┐ │
│ Stock list │◀───│ n8N workflow │◀───│ status:parsed │◀────────────┘
│ decremented │ │ 02: invoice+ │ └──────────────────┘ (status changes
└─────────────────┘ │ stock │ to "parsed")
└─────────────────┘
The AI agent you task can do all of this through the PocketBase MCP server
in .cursor/mcp.json — you ask it to "create a customer PO" or "show me all
pending invoices" and it talks to the same database.
What's in this repo
| Path | What |
|---|---|
pocketbase/pb_migrations/1786200001_created_customer_pos.js |
New collection: incoming POs from customers |
pocketbase/pb_migrations/1786200002_created_customer_po_lines.js |
New collection: parsed line items per PO |
pocketbase/pb_migrations/1786200003_created_invoices.js |
New collection: invoices we issue (with QB id) |
pocketbase/pb_migrations/1786200004_created_invoice_items.js |
New collection: line items per invoice |
pocketbase/pb_migrations/1786200005_created_email_inbox.js |
New collection: every email the workflow sees |
pocketbase/pb_migrations/1786200006_created_workflow_runs.js |
New collection: every n8N execution |
.cursor/mcp.json |
Cursor MCP config — pocketbase-mcp-bridge |
.mcp.json |
Same config, for Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json) |
n8n/01-customer-po-to-parsed.json |
n8N workflow: email → upload PDF → parse lines |
n8n/02-parsed-po-to-invoice.json |
n8N workflow: parsed → QuickBooks invoice → send → decrement stock |
.env.example |
Template — copy to .env, fill in credentials |
All 6 migrations have been validated against the local PocketBase 0.30
binary in this repo (pocketbase/pocketbase).
Deploy: PocketBase
-
Copy the new migration files to your PB server's
pb_migrations/dir. The next time your PB instance starts, it will apply them in order. (Tested locally: collectionscustomer_pos,customer_po_lines,invoices,invoice_items,email_inbox,workflow_runswere created.) -
Verify by hitting
GET /api/collectionswith an admin token — you should see all six new collections listed. -
No data backfill is needed — these are fresh tables.
-
Existing customers collection (
pbc_108570809) is referenced bycustomer_pos.customerandinvoices.customer. Make sure every customer has a validemailfilled in — that's how the workflow matches incoming POs to customers.
Deploy: MCP server for the AI agent
The MCP server (pocketbase-mcp-bridge) gives an AI agent (Claude, Cursor,
etc.) full access to read/write PocketBase. This is what you use to "task
a agent to create purchase orders for me."
-
Open
.cursor/mcp.jsonand fill in theREPLACE_ME_*placeholders with the values from.env(POCKETBASE_URL,POCKETBASE_ADMIN_EMAIL,POCKETBASE_ADMIN_PASSWORD). -
Restart Cursor. The MCP server will auto-install via
npx -y pocketbase-mcp-bridgeand authenticate as the superuser. -
Open a new chat and ask the agent to "list the customer_pos records with status=new." It should call
list_recordsand return the rows. -
To create a PO via the agent, say: "Create a customer PO for Isherwood Mining, PO number ISO-001, 10 × Drill Bit at R150 each." The agent will call
create_recordon thecustomer_poscollection with the right shape.
Available tools (55 total, see github.com/nestebe/pocketbase-mcp for the full list):
list_records,get_record,create_record,update_record,delete_record,get_first_recordlist_collections,get_collection,create_collection,update_collection,delete_collectionauth_with_password,list_auth_methodslist_logs,get_settings,list_backupssend_raw_request— call any endpoint (e.g. PB hooks, custom routes)
Deploy: n8N workflows
-
Install n8N (if you haven't already):
npm install -g n8n # or run via Docker: docker run -it --rm -p 5678:5678 n8nio/n8n -
Import the workflows: in the n8N UI, Workflows → Import from File and select:
n8n/01-customer-po-to-parsed.jsonn8n/02-parsed-po-to-invoice.json
-
Create credentials for each node that has a
REPLACE_ME_*:- IMAP credential → your
orders@jeisa.co.zamailbox - PocketBase API credential → URL + admin email/password from
.env - QuickBooks OAuth2 API credential → connect your QBO account
- IMAP credential → your
-
Activate the workflows in the n8N UI (toggle "Active" in the top right of each).
End-to-end test
-
Send a test email from your personal account to
orders@jeisa.co.za. Subject: "PO test — please ignore." Attach a fake PDF with one or two lines like:AB-123 Test Widget 10 100.00 1000.00 -
Workflow 01 should fire within ~30s:
- A
customer_posrecord is created - A
customer_pos_linerecord is created statusbecomesparsed
- A
-
Workflow 02 should fire within ~2 minutes:
- A QuickBooks invoice is created (sandbox)
- An
invoicesrecord is created withstatus=sent - The
stock_itemsquantity is decremented (only if the SKU matches a stock row — wire up more SKUs in thestock_itemscollection) customer_pos.statusbecomesinvoiced
-
Check
workflow_runsandemail_inboxin PB for the audit trail.
Customizing
| Want to | Edit |
|---|---|
| Add fields to the email parser (e.g. delivery date) | n8n/01-…json → "Function: Parse lines from PDF text" |
| Switch to AI-powered PDF parsing (for scanned POs) | Add an "OpenAI" node between "Extract PDF text" and "Function: Parse lines" |
| Email the invoice from JEI's SMTP (not QB) | Replace "QuickBooks: Send Invoice by email" with the Send Email node |
| Use a different QuickBooks Item ID for SKUs | "Function: Build QB invoice payload" → ItemRef.value |
| Only auto-invoice certain customers | Add an auto_invoice boolean to customers, then add a filter in workflow 02 |
| Sync QuickBooks payments back | Add a third workflow that polls QB Invoice.Status every hour and updates invoices.status |
Important: confirm before making this live
Before going live, you'll want a human approval step between workflow 01
and 02 — the current design auto-invoices everything that looks like a PO.
Add a status: "parsed_pending_review" and require a human to flip it to
"parsed" to make this safer. The simplest way:
- In
01-…json, change the final node to setstatus = "parsed_pending_review". - In
02-…json, change the filter fromstatus = "parsed"tostatus = "parsed_pending_review". - Add a tiny approval UI in the React app (a button on the customer_pos row that PATCHes the status to "parsed").
This stops random emails from triggering invoices.