This commit includes the temporary Next.js build cache files, public brand logos, and project configuration added in this change.
8.9 KiB
Deliveries — n8n Signed-Copy Workflow
Spec for the future n8n flow that closes out
/deliveriesitems by uploading the scanned signed invoice/DN to PocketBase and flipping the order item tocompleted. Read this when you're ready to wire the workflow — every endpoint, payload shape, and field is defined below.
Status: NOT YET BUILT
This is a spec document, not a working integration. The page
/deliveries ships with three tabs (To Load / Back from Driver /
Checked In); the checked_in items sit there until n8n lands.
The n8n workflow itself is owned by you, not by the app — this
doc just defines the contract so the workflow can be built
independently.
What it does
Once the office has typed the reference number on the signed
paper (the checked_in tab in the app), the signed copy still
needs to be:
- Scanned — by whatever scanner / phone-camera / IMAP inbox the office uses today.
- Uploaded to PocketBase on the right
order_itemsrow. - Status flipped to
completedso the office can stop looking at it.
The app exposes the PB schema fields for steps 2 + 3; n8n owns step 1.
API contract (everything the workflow needs)
Inputs the workflow must know
The workflow runs per signed copy, not per order. A single scan
might cover 1 line or 20. To find the right order_items rows
the workflow uses the reference number the operator typed at
check-in time. The contract is:
workflow_in:
reference: string // e.g. "INV-12345" or "DN26071401"
file: Buffer // the scanned signed copy
filename: string // e.g. "INV-12345-signed.pdf"
1. Find the order_items
Hit the PocketBase list endpoint with the reference filter:
GET /api/collections/order_items/records?filter=delivery_reference%20%3D%20%22INV-12345%22&perPage=200
URL-decoded: filter=delivery_reference = "INV-12345"
PB's
~is substring (case-insensitive);=is exact. Use exact — the reference is meant to be exact, and a fuzzy match risks pulling in the wrong customer's rows. If the workflow has only a partial reference (e.g. the scanner OCR'd "INV-1234" with the last digit missing), it should fail loudly rather than guess.
Response shape (each item):
{
"id": "abc123def456ghi",
"delivery_reference": "INV-12345",
"checked_in_at": "2026-07-20T11:30:00Z",
"checked_in_by": "user_id_here",
"item_status": "checked_in"
}
⚠️ Only items with
item_status = "checked_in"should be auto-completed. An item that's been typo'd and lives atwith_driveror earlier in the lifecycle should be left alone — the office might re-route it.
Optional pre-flight guard:
GET /api/collections/order_items/records?filter=delivery_reference%20%3D%20%22INV-12345%22%20%26%26%20item_status%20%3D%20%22checked_in%22
This way the workflow only operates on rows that are genuinely ready to complete.
2. Upload the signed copy
The signed copy goes onto order_items.order_item_attachements
(multi-file field, maxSelect: 10, accepts any MIME). This is
the existing field for "all attachments on this line" — same
field that delivery-note PDFs, supplier POs, etc. live on.
No new collection, no new field.
Per item, do a single PATCH with the file. PocketBase's REST endpoint for file uploads on an existing record is:
PATCH /api/collections/order_items/records/{id}
Content-Type: multipart/form-data
--boundary
Content-Disposition: form-data; name="order_item_attachements"; filename="INV-12345-signed.pdf"
Content-Type: application/pdf
<bytes>
--boundary--
Naming convention: use the reference number as the filename stem (
{reference}-signed.pdfor{.ext}as the scanner produces). The retrieval side — see "How the office sees it back" below — relies on the filename pattern to find the signed copy on a given item. Don't append timestamps or random suffixes.
3. Flip the status to completed
Same record, same endpoint, JSON body this time:
PATCH /api/collections/order_items/records/{id}
Content-Type: application/json
{ "item_status": "completed" }
No body auth header is needed if the workflow uses the admin PB token (recommended — see "Auth" below).
4. Repeat for each item in the batch
Loop over the items from step 1 and do steps 2 + 3 per item. A single scan = one batch = N items = N×(PATCH file + PATCH status) calls. PB doesn't have a batch endpoint; the per-item round trip is fine for typical batch sizes (1–20).
If the workflow needs to be idempotent (resume after a crash):
check item_status on the response from step 3. If it's already
completed, skip. If it's still checked_in, the PATCH probably
failed — log + retry once.
Auth
The workflow should use the PocketBase superuser token, not a
per-user token. The PB schema's rule is
@request.auth.id != '' on the order_items update, so any
authenticated principal works, but the superuser path is the
simplest because:
- It doesn't expire while the workflow is running.
- It doesn't need refresh handling.
- The signed copy is an automated upload, not a user action — per-user audit doesn't add anything.
To grab the token, use the same flow as the rest of the
back-office n8n workflows: a single "Bootstrap" HTTP node at the
top of the workflow that hits
POST /api/collections/_superusers/auth-with-password with the
admin email + password from the n8n credential store, then stores
token in a workflow variable. Every subsequent HTTP node reads
Authorization: Bearer {{$token}}.
If your PB instance is on the v0.23+ rename (admin collection is
_superusersnot_admins), seedocs/migration-audit.mdfor the endpoint confirmation.
How the office sees it back
Once the file is uploaded, the office has two ways to find it:
- Inside the existing order detail view (the one at
/orders/[id]) — the page already readsorder_item_attachements. The new file just shows up alongside the others. - Inside the
/deliveries"Checked In" tab — when v2 of the page ships (out of scope for v1), it'll show a "View signed copy" link per row that points at PB's file URL. The app'sapi/v1/files/[collection]/[recordId]/[filename]route is the canonical way to stream a PB file back through Next.js with auth.
Filename contract
The workflow must use a deterministic filename per item so the retrieval side can find it without scanning the whole attachment list:
{reference}-signed{ext}
Examples:
INV-12345-signed.pdfINV-12345-signed.pngDN26071401-signed.pdf
If the scanner produces something else, the workflow should rename it to this pattern before the upload — not rely on whatever the device names it. The reference is the only stable key; everything else is mutable.
Failures to handle
The workflow should treat these as "log + retry" rather than "throw and stop the whole run":
- 0 items found for the reference — typo'd reference or a
paper that was never typed into the office. Don't create a new
item; surface the unmatched reference to a "needs review" sink
(a separate
logscollection or a Slack message — your call). - HTTP 5xx on the PATCH — PB blip. Retry once with a 2s backoff.
item_statuscame back ascancelled— the office cancelled the item in the meantime. Skip the upload + status flip; surface to "needs review".
The workflow should treat these as hard failures that abort the run:
- More than 50 items for one reference — almost certainly a data bug. Don't auto-upload 200 files based on a single scan.
- Auth token expired mid-run — re-bootstrap from the start.
Suggested n8n shape
If you want a starting point:
- Trigger: depends on the scanner. Common patterns:
- Watch a dedicated IMAP folder (signed copies get emailed from the scanner).
- Watch a folder (e.g.
/shared/scanner/on a Synology). - A webhook the office hits from a phone app.
- OCR / extract reference: if the scan is an image, OCR
it (Tesseract via a
Execute Commandnode, or one of the hosted OCR services) to read the reference number from the paper. Cross-check against the manually-typed reference from the office — if they disagree, route to "needs review". - HTTP Bootstrap: get the PB superuser token.
- HTTP Find items: list by reference (step 1 above).
- Loop per item: upload + flip (steps 2 + 3 above).
- Log + cleanup: move the source file out of the watch folder, log success/failure.
Out of scope for the app
These are deliberately not part of the /deliveries page
v1 and don't need any app change to support:
- The actual scan ingestion (n8n).
- The OCR (n8n).
- The signed-copy viewer in the page (a future "Completed" tab once there's enough data to be worth showing).
- A "Completed" tab on the page. When the workflow lands and
item_status = "completed"rows accumulate, we can add a 4th tab. The schema already supports it — the page just doesn't render it yet.