107 lines
4.3 KiB
Markdown
107 lines
4.3 KiB
Markdown
# 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.
|
||
|
||
1. **Schedule Trigger** — fires every 1 minute.
|
||
2. **HTTP Request** — `POST https://mega.dash.apphub.co.za/api/dn-batches/tick`
|
||
with header `x-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 a `dn_batches` row with `status =
|
||
"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 to `delivery_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) and `src/lib/dn-pipeline/types.ts` for 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).
|