4.3 KiB
n8n Workflow — Delivery Note Tick
This is the handoff doc for the n8n workflow that drives the
delivery note inbox pipeline. The pipeline itself (extract → segment
→ split → checks → promote) lives in src/lib/dn-pipeline/ and is
run entirely inside Next.js. n8n's only job is to call the tick
endpoint every minute.
What this workflow does
Two nodes. That's it.
- Schedule Trigger — fires every 1 minute.
- HTTP Request —
POST https://mega.dash.apphub.co.za/api/dn-batches/tickwith headerx-ingest-secret: <credential value>.
The Next.js route (src/app/api/dn-batches/tick/route.ts) picks up
the call, walks every dn_batches row whose status is one of
inbox / analysing / needs_attention, and advances each one
through the pipeline until it reaches processed (or stays in
needs_attention until a human acts). All OCR, segmentation,
checks, and PocketBase writes happen in Next.js — n8n does not see
a slip.
When this workflow runs
Every minute, on the minute. The trigger has no special cadence.
What you configure in n8n
Nodes
| # | Node | Type | Notes |
|---|---|---|---|
| 1 | Tick | Schedule Trigger | interval: 1 minute |
| 2 | POST /api/dn-batches/tick | HTTP Request | method POST, URL https://mega.dash.apphub.co.za/api/dn-batches/tick, header x-ingest-secret from a credential |
Connect Tick → POST.
Credentials to set after import
| Credential name | Type | Value |
|---|---|---|
DN Ingest Secret (or whatever you name it) |
Header Auth | x-ingest-secret = the rotated N8N_INGEST_SECRET value |
The HTTP Request node should reference the credential by name — do not paste the secret as a literal in the node's headers table. Anyone exporting the workflow will leak the secret otherwise, and that's exactly what happened with the previous four-node workflow.
Save and keep active
After both nodes are in place and the credential is wired, save and flip the workflow Active. The pipeline is idempotent: running the tick twice produces identical figures and no duplicate rows, so a double-fire from a transient n8n restart is harmless.
Why it collapsed to two nodes
The previous workflow polled PocketBase for processing_status = "pending" rows, downloaded each slip, ran an LLM extraction, and
POSTed results back. Tasks 1–16 of the unit-fix plan moved every
one of those steps into Next.js:
- Upload route (
src/app/api/delivery-notes/upload/route.ts) hashes the file, creates adn_batchesrow withstatus = "inbox", and persists the bytes to PocketBase. - Tick route (
src/app/api/dn-batches/tick/route.ts) is the one place pipeline progression lives. - Pipeline modules in
src/lib/dn-pipeline/:extract.ts— page-by-page OCR / PDF read.segment.ts— group pages into candidate notes.split.ts— resolve ambiguous segmentations (unassigned,needsSubsplit).checks.ts— per-note and per-batch gating.promote.ts— write promoted notes todelivery_notes/delivery_note_items.run.ts— the orchestrator the tick route calls.
What used to be eight nodes is now one HTTP call. Anyone tempted to "just add the OCR back into n8n" should read the pipeline modules first — the rules (no cross-page inference, idempotent re-runs, check-gated promotion) only hold because the steps run in deterministic order inside one process.
What an operator sees
dn_batches.status = "inbox"— uploaded, not yet ticked.dn_batches.status = "analysing"— a tick is running for this batch.dn_batches.status = "needs_attention"— pipeline stopped; open the row in the inbox board to see why.dn_batches.status = "processed"— done.notes_promoted> 0 means new rows landed on the purchasing page.
If the n8n workflow is OFF, batches will sit in inbox until it
comes back. There is no fallback timer inside Next.js — the tick
is the heartbeat.
Reference
- Pipeline spec: this repository,
docs/n8n/delivery-note-ocr.md(this file) andsrc/lib/dn-pipeline/types.tsfor the data shapes. - Tick route implementation:
src/app/api/dn-batches/tick/route.ts. - Existing workflow id in n8n:
wVbLw4paISkbrIpE(name: "Delivery Note OCR" — the name is historical; the workflow body is now the two-node tick).