The order-to-printer pipeline - #12
Merged
Merged
Conversation
Order T3DPS-114567 carries the personalisation the whole business runs on - STEP 4-First Name: RAHUL, STEP 5-Second Name: RANU, a WhatsApp number. Tensor fetched every one of those from Shopify and threw them away. The import already requested customAttributes. But mapShopifyLineItems only recognised a hardcoded list - personalisation_name, custom_name, engraving_text - and a real storefront personaliser names its questions for humans, not for parsers. Nothing matched, so the fields were read and silently dropped: the operator sees a blank where a customer typed their child's name, and nothing anywhere records that it was discarded. Two changes, and the difference between them matters. LineItem.Properties now keeps EVERY attribute verbatim and in order. The typed fields stay the machine-readable path, but they are a mapping, and a mapping only knows the keys it was told about. Keeping the raw list means an unrecognised question still reaches the person doing the work instead of vanishing. It is a slice, not a map: "STEP 3 / 4 / 5" is the order the customer answered in, and duplicate keys are legal. On top of that, matching is done on a NORMALISED key, so a store's punctuation does not have to be reproduced exactly - "STEP 4-First Name-:" and "STEP 4 First Name" are the same question, and a label edited in Shopify no longer silently stops matching. Two names on one plank join into one engraving rather than one of them being dropped. No migration: line_items is jsonb, so the shape simply widened. The test uses the real order's property names verbatim, and it earned its keep immediately - normalisePropKey kept only a-z and DELETED uppercase, turning "STEP 6 - WhatsApp Number:" into "6 hats pp umber", which still looked like a plausible key and would have quietly failed to match. Still missing, and not fixable here: customer name, email, phone and the shipping address. Those need the read_customers scope, and Shopify fails the ENTIRE GraphQL call for an inaccessible field rather than omitting it - see the note above listOrdersQuery. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Everything between a Shopify order and a plate on a machine: job creation,
personalised model rendering, colour batching, dispatch to BambuBuddy, and the
fulfilment path that takes finished work back out again.
Batching
- One colour per bed, at most four products, oldest order first. A bed locks
only when it is full; an under-full bed stays a Draft so the next order in
that colour completes it rather than opening a bed of its own.
- The merged plate carries each plank's colour (3MF materials plus Bambu's
per-part extruder config), and is named after the orders on it.
- A bed can be edited by hand after locking: the plate is withdrawn from
BambuBuddy's queue, the membership changed, and the plate rebuilt from what
is left. Editing is all-or-nothing.
Rendering
- OpenSCAD templates for the Dual Name Plank, rendered per job from the order's
own customisation properties.
- The property matcher accepts the storefront's longer labels ("First Name on
Plank"), and reads a heart count from the first candidate whose VALUE parses -
a combo product carries a field called "Name On Heart Keychain" holding a name.
Dispatch
- A plate reaches only a slicer pipeline targeting the printer class it was
planned for. Pipelines were previously tried in whatever order BambuBuddy
returned, so every plate was sliced for the first class in that list.
- A colour gate holds a bed no machine has the filament for, naming the spool.
- BambuBuddy pushes events (print start/complete/failed, queue changes) to
/integrations/bambubuddy/events, which refreshes the fleet within seconds
instead of on the next 60-second tick.
Orders
- The Shopify pull runs on a worker, not on the request. It used to run inside
the HTTP handler, whose caller gives up after five seconds, so the import was
cancelled part way and reported the handful that made it as a success.
Thirty-five orders were missing from the Orders page because of it.
- An order already fulfilled creates no jobs, and one that becomes fulfilled
leaves its bed AND the merged plate.
- Priority-dispatch orders are no longer excluded from production.
Fleet
- A printer whose LAST PRINT failed is idle and schedulable, with the advice to
clear its plate shown as a note. It used to be reported as a machine error,
which took five of thirteen printers out of scheduling entirely.
Packing
- bedpack takes a bed rather than reading compile-time constants, and charges
the clearance gap BETWEEN parts instead of after each one - a 256mm bed holds
four 200x50 planks, and the old rule said three. A geometry test asserts no
overlap and full separation across beds, shapes and counts.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W4ND3pFVaX7yGzWxZiHPYu
|
Too many files changed for review (131 files, 100 file limit). Bypass the limit by tagging |
|
ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Team Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


A Shopify order now reaches a printer without anyone driving it.
Sync pulls the order, a job is created for each plank, the model is rendered
from the customer's own names, matching colours are batched onto a bed, and a
full bed is sliced and sent to BambuBuddy. Each step enqueues the next, so the
floor sees work appear rather than waiting for somebody to press a button.
Workers start with the backend
internal/workersetregisters the job-creation, render, batch-plan and dispatchworkers in one place, and both
cmd/apiandcmd/productionworkerstart it. Aplain
go run ./cmd/apinow runs the whole pipeline.Every stage is event-driven, not periodic. River's periodic jobs are
leader-gated and this database's leader is a remote instance, so a tick-based
design would simply never fire here. Each worker enqueues its successor instead.
Beds
matching order completes it rather than opening a bed of its own; when it
fills, it locks.
BATCH_MAX_WAIT_HOURSis gone: it committed a wasted plate and denied the fourth order its place.
A person can still approve a partial bed by hand.
used to be possible for orders 114654 and 114680 to sit on a locked bed of two
while newer ones filled a bed of four beside them.
withdraws the plate from BambuBuddy's queue, re-renders the merged plate to
match (remove one plank and you get a plate of three), and re-reserves
filament.
and one warped, so the bed stays open until nothing on it is outstanding.
The packer was under-fitting - it charged the inter-part gap after the last part,
so a 256mm bed held three planks instead of four.
internal/bedpacknow chargesthe gap when it splits a free rectangle, and a geometry test asserts no overlap
or overhang across four beds x five shapes x five part counts.
Orders that are already out the door
A fulfilled order makes no jobs, and one fulfilled mid-flight is pulled off its
bed and out of the merged plate, then routed to Done. The priority-dispatch
exclusion is removed - it was holding nineteen unfulfilled orders out of
production on an instruction that no longer describes the floor.
Rendering
The templates are the 4 September OpenSCAD files. The old no-heart template
dropped a padding slot outright rather than filling it, and a padding slot is
what holds the extra letters of the longer name - so a plank for KAUSTUBH and
LIPIKA printed "AUSTUB", losing one letter from each end. Orders with a heart
were never affected, because the heart filled the slot.
Property lookup also gained whole-word containment, because nine orders label
the field "First Name on Plank" rather than "First Name". The heart count is
read from the first candidate whose value parses, so a combo product's "PAVI"
is no longer read as a quantity.
BambuBuddy
POST /integrations/bambubuddy/events, authenticated witha constant-time token compare and debounced for ten seconds. BambuBuddy's own
/webhook/*endpoints are pulls despite the name; real push comes from anotification provider.
FAILEDmaps to idle, not error. A printer whose last print failed isavailable - it just wants its plate cleared - and treating it as an error was
excluding five of thirteen machines from scheduling.
result.
Sync
The Shopify pull moved into a River worker. It ran inline before, so the
frontend's five-second abort cancelled the request context mid-import and the
remaining orders were logged and skipped - which is why 114774 was followed by
114810. The endpoints return 202 and the import finishes on its own.
Commands
markprinted,relinkbeds,rerender,droppedlettersandreformbedsareone-off tools for repairing history - reopening beds frozen under the old
locking rule, re-rendering models built from the broken template, and naming the
planks that printed with letters missing so somebody can decide what to reprint.
reformbedschecks BambuBuddy's live queue before reopening anything, because aplate pulled from under a running printer cannot be put back.
🤖 Generated with Claude Code
https://claude.ai/code/session_01W4ND3pFVaX7yGzWxZiHPYu