Skip to content

Execution model

A BOM executes when a Shopify order containing the finished-good variant is created (or cancelled, refunded, edited). The pipeline runs in milliseconds; the audit log captures every step. This page explains the model end-to-end so you can predict — and debug — what happens for any given order.

  • The execution pipeline at a glance
  • The order of operations inside Assemblified
  • Pre-fulfillment vs post-fulfillment timing
  • Multi-location behavior
  • The execution log — where to find it, what to look at
  • Common failure modes
  1. Customer places an order in your Shopify storefront.
  2. Shopify fires a webhook to Assemblified.
  3. Assemblified disambiguates the event — is it a create, a cancel, a refund, or an edit?
  4. The work is enqueued. A background job buffers the order so it can be retried if anything goes wrong.
  5. Assemblified processes the order. It walks the BOM’s recipe and computes inventory deltas, drawing from pre-assembled inventoryPre-Assembled InventoryStock of finished sub-assemblies and BOM items that have already been built and are sitting on the shelf. When a work order needs a sub-assembly, it draws from pre-assembled inventory first and only builds fresh ones if the shelf comes up short. Read more → first.
  6. Shopify gets the inventory adjustments. Component variants are decremented; if you have dynamic adjustmentDynamic adjustmentA per-BOM toggle that recalculates the BOM's Shopify-displayed quantity from current component availability after every order. The displayed quantity is the bottleneck-resource count plus pre-assembled stock — your storefront never sells more than you can build. Read more → on, the BOM’s displayed quantity is recalculated.
  7. An execution log rowBOM execution logThe audit trail for one BOM execution — one row per order webhook → DO → Shopify cycle. Captures webhook receipt timestamps, queue lifecycle, DO execution, BOM processing metadata, calculated material changes, Shopify sync status, dynamic-adjustment results, refund history, and pre-assembled consumption. Surfaced in the BOM detail page. Read more → is written. This is your audit trail.

The whole pipeline typically takes 1–5 seconds for a simple BOM and a few seconds longer for BOMs with deep sub-assembly nesting or many locations.

When Assemblified processes an order, materials are sourced in a specific order. This matters because it affects what gets decremented:

  1. Pre-assembled stock first. If the BOM has pre-assembled inventoryPre-Assembled InventoryStock of finished sub-assemblies and BOM items that have already been built and are sitting on the shelf. When a work order needs a sub-assembly, it draws from pre-assembled inventory first and only builds fresh ones if the shelf comes up short. Read more → , that’s consumed before anything else. Order quantity 8, pre-assembled 5 → 5 come off the shelf, 3 still need to be sourced.

  2. Sub-assemblies next. For each remaining unit, expand the BOM’s sub-assembly references. Each sub-assembly has its own pre-assembled shelf — that’s consumed before falling through to its components.

  3. Raw materials last. Whatever remains after the shelves are exhausted pulls from raw-material inventory. Shopify-linked materialsRaw materialThe atomic component of a BOM or sub-assembly. Two flavors: a Shopify-linked variant (inventory tracked in Shopify) or a virtual material (DO-side inventory only). Both kinds appear in the same component picker and are consumed identically when a BOM fires — except virtual materials never trigger a Shopify call. Read more → are decremented through Shopify. Virtual materialsVirtual MaterialA material tracked entirely inside Assemblified — not a Shopify variant. Useful for shop-floor consumables (glue, packaging, labour units) where you need quantity tracking but don't want a Shopify product on your storefront. Read more → are decremented inside Assemblified’s own inventory (no Shopify call).

  4. Dynamic adjustment cascade. If any BOM in the order (or any other BOM that shares components with it) has dynamic adjustment on, Assemblified recomputes the displayed Shopify quantity for those BOMs from current availability.

  5. Maintain inventory level. If the BOM has Maintain inventory levelMaintain inventory levelA per-BOM toggle that keeps the Shopify-displayed BOM quantity flat after orders. After execution, Assemblified pushes a positive delta back to the BOM variant equal to what was consumed. Components still decrement underneath — only the displayed quantity is replenished. Mutually exclusive with dynamic adjustment. Read more → on, a positive delta equal to what Shopify just decremented is pushed back, keeping the displayed quantity flat.

  6. Auto-generate material list. If on, a Materials Order flow + linked TODO is created for the operator to pick or download.

  7. Log the result. All of the above is recorded in bom_execution_log.

By default, BOMs execute on the ORDERS_UPDATED webhook, which fires on order create/edit/cancel/refund. So the inventory adjustment happens at order time — before you’ve fulfilled anything.

Some sellers want the opposite: only adjust inventory when the order ships. Today this isn’t directly configurable per-BOM in the UI.

Assemblified resolves the location for each component in this priority:

  1. The component reference’s locationId (if set on the BOM/sub-assembly raw-material reference).
  2. The order’s fulfillment location, if your shop has location-sensitive dynamic adjustments enabled in settings.
  3. The shop’s default Shopify location.

So if you have multi-location inventory:

  • Set per-component locations on the BOM detail page when a specific material always comes from one warehouse.
  • Leave them blank to let the order’s fulfillment location drive the choice (with the shop-level setting on).

Every order writes one row to bom_execution_log. The row captures:

  • Webhook details — when it arrived, the topic, the Shopify event ID.
  • Queue lifecycle — when the job was picked up, retry count.
  • Processing — start, end, duration, status of Assemblified’s run.
  • BOMs processed — which BOMs fired, and which were skipped (e.g., because they were inactive).
  • Material calculations — the exact deltas applied. One array for Shopify-side changes, another for Logistified demand tracking (Enhanced).
  • Inventory sync — the result of each Shopify call.
  • Dynamic adjustment — what was recomputed, what was pushed.
  • Refund history — prior refunds for this order, used by the cancel-after-partial-refund netting logic.
  • Pre-assembled consumption — per-entity, per-location records of what came off (and back onto) the shelf.

Where to find it:

  • In-app: the BOM detail page has an Execution Log section listing recent runs for that BOM.
  • From a debugger: the test endpoint pollExecutionLogs action (see internal docs).

If a BOM didn’t seem to fire, check bomsSkipped in the log. The most common causes are an inactive BOM or a webhook that never arrived (which the log won’t have a row for at all).

SymptomLikely cause
Order placed, no log row appearsWebhook not registered. Reinstall the app or check the webhook config.
Log shows bomsSkipped with the BOMBOM is inactive (Status card → Active).
Components didn’t decrement, log says successPre-assembled shelf absorbed it. Look at preAssembledConsumption in the log.
Shopify shows wrong quantity after orderDynamic adjustment may not have run (off, or known issue with the adjustment cascade).
Cancel didn’t restore rawsCheck Keep Assembled on Return — if on, raws stay assembled. See Refunds & cancellations.
Inventory went negativeShopify allows negatives if your location settings permit. Lock it down at the shop level, not the BOM level.