Skip to main content

SOP: Backorder Resolution

Document ID: WMS-INV-006 Version: 1.0 Effective date: 04/30/2026 Owner: Warehouse Operations Manager Next review: [six months from effective date] Applies to: Managers and staff resolving backordered orders — the pull side of the inventory inflow that WMS-REC-003 and WMS-INV-002 push into


1. Purpose

This procedure governs what happens when an order can't be fully allocated to inventory at order-creation time. The order's status flips to BACKORDERED (or PARTIALLY_ALLOCATED if some lines could be allocated and partial fulfillment is allowed), and the system queues an automatic retry whenever new stock arrives for any of the affected SKUs. Three SOPs upstream cross-reference this one as the destination for their post-approval enqueue:

  • WMS-REC-003 §4.2 — receiving session approval enqueues enqueueCheckBackorders per received variant
  • WMS-INV-002 §4.8 — cycle-count session approval enqueues the same per variant where variance went up
  • WMS-INV-001 §4.2 — lightweight inventory adjustments don't enqueue today (gap noted there)

This SOP is also the manager-facing dashboard documentation — the /backorders page that surfaces the "what's waiting on what" view across the whole open order book, with manual retry and batch-fulfill actions.

2. Scope

In scope:

  • The BACKORDERED and PARTIALLY_ALLOCATED order statuses and the transitions between them
  • The automatic retry pipeline: enqueueCheckBackorders → worker processCheckBackorderscheckBackorderedOrders → batch enqueueAllocateOrder
  • Stale-backorder escalation to ON_HOLD after the 30-day cutoff
  • Manual retry from the /backorders UI: per-order Fulfill and Fulfill All
  • Splitting a backordered order into a shippable child + a backordered child via splitBackorder
  • Reading backorder events in fulfillment_events (order:backordered, order:backorder_resolved)

Out of scope:

  • Order creation and the initial allocation pass that decides whether an order goes to ALLOCATED vs. BACKORDERED vs. PARTIALLY_ALLOCATED — out of scope here; the allocation logic is upstream
  • Picking, packing, shipping the resolved (now ALLOCATED) order — see WMS-PICK-001, WMS-PACK-001, WMS-SHIP-001
  • Order on-hold management beyond the auto-escalation from this SOPON_HOLD orders need manual review per WMS-AUD-002 (when written)
  • Customer notifications about backorder status — outside the WMS

3. Roles & permissions

API enforcement: The endpoints in this SOP (GET /orders/backorders, POST /orders/:id/allocate, POST /orders/allocate-batch, POST /orders/:id/split-backorder) are auth-only; no inline role gate.

RoleView backorders dashboardManual retry single orderBatch retry allSplit a backorder
READONLY
STAFF
MANAGER
ADMIN
SUPER_ADMIN

Operational expectations:

  • Manual retry is generally not necessary — the automatic retry triggered by inventory inflow handles 90%+ of cases. Reach for the dashboard's Fulfill / Fulfill All when (a) the worker queue is unhealthy, (b) you've moved stock manually via WMS-INV-001 §4.2 (which doesn't enqueue today), or (c) you've just imported stock via a path that bypasses the standard receiving flow.
  • Splitting a backordered order is a commercial decision, not a routine operation. Splitting commits the warehouse to shipping the partial today and the rest later — it's only correct if the customer has agreed to the partial shipment. Manager-level discretion.
  • An order escalating to ON_HOLD after 30 days needs human review, not another retry. Either source the missing stock (special order, vendor PO), substitute a SKU, or cancel and refund. The auto-retry pipeline stops touching ON_HOLD orders by design.

4. Procedures

4.1 How an order ends up backordered

The first allocation pass runs when an order is created (or when it's manually retried per §4.4). Per OrderAllocationService.allocateOrder(), the resulting status is determined by:

ConditionsNew status
One or more order items have no matching variant in the system (unmatchedItems > 0) and totalAllocated == 0ON_HOLD (with holdReason recorded)
unmatchedItems > 0 but partial allocation succeededPARTIALLY_ALLOCATED (with holdReason recorded)
All items matched but zero could be allocated (no available inventory at any pickable location)BACKORDERED
Some items allocated but not all required quantities, and allowPartial: falseBACKORDERED
Some items allocated but not all required quantities, and allowPartial: truePARTIALLY_ALLOCATED
All required quantities allocatedALLOCATED

What gets written:

  • The Order.status field updates to one of the above.
  • If the transition crosses into BACKORDERED from any non-backordered status, a fulfillment_events row of type order:backordered is created with the order, item counts, and the timestamp.
  • A real-time ORDER_BACKORDERED event is published outside the transaction (best-effort SSE).
  • If the transition is out of BACKORDERED into ALLOCATED, a fulfillment_events row of type order:backorder_resolved is created.

What an order item looks like during backorder:

  • quantityAllocated reflects what was successfully allocated (could be zero or partial).
  • The item's matched flag (set during initial item-to-variant matching) determines whether retry will ever consider it.
  • The shortfall is quantity - quantityAllocated per item; the order's overall shortfall is the sum across items.

4.2 Automatic retry on inventory inflow

Use when: This is the system's primary backorder-resolution path. You don't initiate it manually — it runs whenever inventory increases for a SKU.

Triggers (callers of enqueueCheckBackorders):

  • Receiving approval — per WMS-REC-003 §4.2, after the approve transaction commits, the route enqueues one checkBackorders job per unique received variant with triggerSource: "receiving:{sessionId}".
  • Cycle-count approval — per WMS-INV-002 §4.8, after the approve transaction commits, the route enqueues one checkBackorders job per variant where variance > 0 (more found than expected) with triggerSource: "cycle-count:{sessionId}".

Triggers that exist but aren't wired (gaps):

  • Customer return restock (per WMS-RET-002) — restocks credit inventory but do not enqueue a backorder check today. This is a real gap: a return adds sellable stock that won't trigger waiting orders to retry. Workaround: manually run §4.4 after a high-volume return restock.
  • Lightweight /inventory/:id/adjust (per WMS-INV-001 §4.2) — adjustments that increase quantity don't enqueue. Same workaround.

What the worker does (processCheckBackorders in apps/worker/src/processors/order.processor.ts:127):

  1. Receives { productVariantId, triggerSource? } job data.
  2. Calls OrderAllocationService.checkBackorderedOrders(productVariantId) which runs two stages atomically:
    • Stage 1 — Stale escalation: all orders with status: BACKORDERED, updatedAt < (now - 30 days), and at least one matched: true item for this variant are bulk-updated to status: ON_HOLD with holdReason: "Backordered for more than 30 days — manual review required". They will not be considered for retry.
    • Stage 2 — Eligible-orders fetch: finds up to 20 orders with status IN ('BACKORDERED', 'PARTIALLY_ALLOCATED') that have a matched: true item for this variant, ordered by priority ASC, createdAt ASC (EXPRESS before RUSH before STANDARD; FIFO within priority).
  3. For each eligible order, enqueues an allocateOrder job with allowPartial: true and an idempotency key of backorder-retry-{orderId}-{timestamp}.
  4. Logs the final count and returns.

What this means in practice:

  • A receiving session that brings in 100 of variant X triggers a single checkBackorders job. That job kicks off up to 20 follow-on allocateOrder jobs.
  • Each allocateOrder job runs the standard allocation logic. Some will fully allocate (transition to ALLOCATED); others will partially allocate (still PARTIALLY_ALLOCATED); the remainder stay BACKORDERED.
  • Orders with the same priority are retried in receipt order — earliest-created first.

⚠ The MAX_RETRY_BATCH = 20 cap is per check. If 50 orders are waiting on the same SKU and approval brings in stock for that SKU, only the top 20 (by priority + age) get retried in this pass. The next 30 wait for the next inflow event for that variant. If no further inflow comes, those 30 stay backordered until either a manual retry (§4.4) or the 30-day stale escalation fires.

⚠ Stale escalation runs every time the worker checks, not just on a schedule. The Stage 1 bulk update runs on every checkBackorders job for the variant. If the worker queue is healthy, stale orders escalate within minutes of the 30-day threshold. If the queue is backed up or the variant hasn't seen inventory inflow in a long time, escalation is delayed.

4.3 Reading the backorders dashboard

Use when: Manager review of all current backorders — what's stuck, what's been waiting longest, what shortfall by SKU.

Steps:

  1. Open /backorders. The page calls GET /orders/backorders.
  2. The page shows three things:
    • Stats at the top: totalBackorderedOrders, totalSkus, oldestDaysPending, totalShortfall
    • By SKU tab: each SKU with ordersWaiting, quantityNeeded, quantityAvailable, shortfall, fill-percent bar
    • Orders tab: each order with orderNumber, customer, status badge, daysPending, item-level shortfall

What the dashboard counts:

  • Orders included: status IN ('BACKORDERED', 'PARTIALLY_ALLOCATED') — both states are surfaced together.
  • Available inventory per variant: aggregate across all locations with status: AVAILABLE. The dashboard does not filter by isPickable: true — so available stock at a non-pickable location (receiving zone, packing station) shows up as "available" here even though allocation won't actually pull it. See callout below.
  • Days pending: now - order.createdAt, integer days. Doesn't reset on retries.

⚠ The "Available" column overstates what allocation can use. The dashboard sums InventoryUnit rows by variant where status: AVAILABLE, but allocation requires both status: AVAILABLE and location.isPickable: true. So a SKU showing 50 available with 30 ordered may actually have only 10 in pickable locations and 40 in receiving — the dashboard says "fillable" but a manual retry will still backorder. Either rely on the actual retry result (run Fulfill and watch what happens) or move the receiving-zone stock via WMS-REC-004 (whose UI is unbuilt — see callout) or WMS-INV-001 §4.1 first.

4.4 Manually retrying a single order

Use when: The auto-retry pipeline didn't fire (e.g., inflow was via a path that doesn't enqueue), or you want to confirm an order can now be filled.

Steps:

  1. From /backorders → Orders tab, find the order.
  2. Tap Fulfill next to it.
  3. The page calls POST /orders/:id/allocate with { allowPartial: true }.
  4. The route runs OrderAllocationService.allocateOrder(id, true) — the same allocation logic as the auto-retry, but synchronously in-process.
  5. On success, if the order transitions to ALLOCATED, the route also runs OrderPackageService.recommendAndSave(id) to generate box recommendations. Failures here are logged but don't fail the allocation.
  6. The toast shows "Allocation attempted — refreshing..." and the dashboard refetches.

Outcomes:

  • Order goes to ALLOCATED → it will now flow into picking (WMS-PICK-001) per the standard outbound path.
  • Order goes to PARTIALLY_ALLOCATED → some items got stock, others still don't. The order remains on the dashboard.
  • Order stays BACKORDERED → no available pickable stock for any item. The order stays on the dashboard.
  • Order goes to ON_HOLD → there's an unmatched item (no variant match in the system, not just a stock issue). Manual review per §8.

Common errors:

HTTPAPI messageWhat it means
400<varies> from allocateOrderCould be a state-machine error (e.g., trying to allocate a CANCELLED order). Read the response body.
404(depending on order load)Order ID is wrong. Refresh.

4.5 Batch-retrying all visible backorders

Use when: You've just brought in a major inventory wave and want to refresh the entire backorder dashboard at once, rather than relying on the per-variant auto-retry to find each order.

Steps:

  1. From /backorders → Orders tab, with the list loaded.
  2. Tap Fulfill All.
  3. The page collects every order ID currently visible (the current data.orders state) and calls POST /orders/allocate-batch with { orderIds, allowPartial: true }.
  4. The route iterates each order and runs allocation. The toast shows "Batch complete: {n} fulfilled, {m} still backordered" once done.

Important behavior:

  • The batch endpoint runs allocations sequentially in the API process — there's no queue dispatch, no parallelism. Large batches can take noticeable time (seconds-to-minutes for 100+ orders).
  • The batch shares the same MAX_RETRY_BATCH cap of 20 on the dashboard view itself: the GET /orders/backorders endpoint returns up to all current backorders (no take cap), but the take: MAX_RETRY_BATCH constraint inside checkBackorderedOrders only applies to the auto-retry path. Manual batch fulfill processes everything you see. If the dashboard shows 200 orders, all 200 are attempted.

⚠ Batch fulfill is non-atomic per order. If allocation for order #87 throws, orders #1–#86 keep their results, order #87 fails for the user, and orders #88+ may or may not be processed depending on whether the route swallows or re-throws. Read the toast message — the count tells you the truth, but if errors bubble, they show up in app.log.error rather than the UI.

4.6 Splitting a backordered order

Use when: A PARTIALLY_ALLOCATED or BACKORDERED order has some items ready to ship, the customer has agreed to a split shipment, and you want to release the shippable portion now while keeping the unfilled items waiting on a child order.

Prerequisites:

  • Order status is PARTIALLY_ALLOCATED or BACKORDERED.
  • At least one item is fully allocated (otherwise there's nothing shippable).
  • Customer has agreed to a partial shipment. This is a commercial decision that the system doesn't validate.

Steps:

  1. (No UI button mounted on the backorders page today — see §8.) Call POST /orders/:id/split-backorder directly via API.
  2. The route runs OrderAllocationService.splitBackorder(orderId) in a transaction:
    • Finds items where quantityAllocated >= quantity (fully shippable) — these stay on the original order.
    • Finds items where quantityAllocated < quantity (partially or unallocated) — these move to a new child order.
    • Creates the new Order row with status: BACKORDERED, the original customer info, and the unfilled items.
    • Updates the original order's status based on what's left (ALLOCATED if everything remaining is fully allocated, READY_TO_PICK, etc.).
  3. Returns: { originalOrderId, originalOrderNumber, originalStatus, backorderOrderId, backorderOrderNumber, shippableItems, backorderedItems }.

Result:

  • The original order is now ready to flow into picking (WMS-PICK-001) for the shippable items.
  • The new backorder child order stays on the dashboard with the unfilled items. Its createdAt is the split time, not the original creation date — which means daysPending on the child resets. Be aware: a customer who waited 14 days, then got a split, then waited another 14 on the child shows up as a 14-day order on the dashboard, not a 28-day one.

Common errors:

HTTPAPI messageWhat it means
400Order ... cannot be split (status: ...). Only PARTIALLY_ALLOCATED or BACKORDERED orders can be split.The order is in a different state. If it's already ALLOCATED, no split is needed; if it's ON_HOLD, resolve the hold first.
404Order not found: ...Order ID is wrong.

⚠ Split is irreversible. Once split, you cannot merge the child back into the parent through the UI or API. If you split prematurely, the only recovery is to ship the parent normally and let the child sit on the dashboard until its items can be sourced — same as if the customer had placed two separate orders. Confirm the customer agreement before splitting.

5. Reference

5.1 Relevant order statuses

Out of the 13-value OrderStatus enum, this SOP touches:

StatusMeansThis SOP relates to it via
ALLOCATEDInventory reserved for the order; ready for pickingSuccessful retry destination
PARTIALLY_ALLOCATEDSome items reserved, some still need stockDashboard included this; eligible for auto-retry
BACKORDEREDNo items have any allocation yet, OR partial isn't allowedDashboard included this; eligible for auto-retry
ON_HOLDEither unmatched item or stale-backorder escalationAuto-retry skips these — manual review per §8

Everything past ALLOCATED (PICKING, PICKED, PACKING, etc.) is downstream — see WMS-PICK-001 onwards.

5.2 Backorder events

The fulfillment_events table records two event types for backorder transitions:

Event typeWhen written
order:backorderedWhen allocateOrder transitions from any non-backordered status into BACKORDERED
order:backorder_resolvedWhen allocateOrder transitions from BACKORDERED into ALLOCATED

Each row's payload contains orderId, orderNumber, previousStatus, newStatus, totalItems, allocatedItems, backorderedItems, and timestamp.

The events are insufficient for full audit reconstruction. They don't fire on every retry — only on status transitions. A backorder retried 5 times that stays BACKORDERED produces zero events from the second retry on. To trace retry attempts, look at the worker logs for [Orders] Checking backorders for product variant: ... and [Orders] Found N backordered orders to retry, plus the bullmq job-history table if your queue is configured for retention.

5.3 The 30-day stale-escalation cutoff

The cutoff is a hardcoded MAX_BACKORDER_DAYS = 30 in OrderAllocationService.checkBackorderedOrders() (line 388). Orders that have been BACKORDERED (not just any status) for more than 30 days at the time a retry is attempted are bulk-updated to ON_HOLD with holdReason: "Backordered for more than 30 days — manual review required" and excluded from that retry.

This is a soft escalation:

  • It only runs when something triggers checkBackorderedOrders. If no one is enqueuing checks, the escalation doesn't run.
  • The 30-day window starts from Order.updatedAt, not createdAt — meaning any update to the order (even a status flip due to an earlier retry) resets the clock. An order that's been backordered for 90 days but had a retry that touched it within the last 30 days will not yet escalate.
  • An ON_HOLD order can be returned to BACKORDERED via direct DB update, but no application code does this.
  • WMS-REC-003 §4.2 — Receiving approval (the primary upstream trigger for auto-retry)
  • WMS-INV-002 §4.8 — Cycle-count approval (the secondary upstream trigger)
  • WMS-INV-001 §4.2 — Lightweight inventory adjustments (gap: no enqueue today)
  • WMS-RET-002 — Customer return restock (gap: no enqueue today)
  • WMS-PICK-001 — Picking (the destination for resolved orders)
  • WMS-AUD-002 — Shrinkage and on-hold investigation (where ON_HOLD orders go for manual review)

6. Audit & compliance

The backorder lifecycle has partial audit data:

  • Backorder transitionsfulfillment_events of type order:backordered and order:backorder_resolved capture entry/exit, but not the in-between retries.
  • Allocation events — every successful allocation writes its own fulfillment_events row (per the upstream allocation logic). Joining backorder events to allocation events reconstructs the success path.
  • Worker job history — if BullMQ is configured for retention, the job history shows every checkBackorders and allocateOrder invocation, payload, and outcome. Default retention is short (jobs are usually pruned after completion); extend it for forensics if needed.
  • Order.updatedAt advances on every status change; combined with the events, this gives a rough timeline.

What's missing:

  • No retry-attempt log per order. A backorder retried 50 times before it resolves shows only the entry and exit events.
  • No record of which inflow triggered which retry. The triggerSource field in CheckBackordersJobData (e.g., receiving:{sessionId}) reaches the worker logs but is not persisted to the database. To trace "which receiving session unblocked which order," you need worker logs + timestamp correlation.
  • No notification log. Customers waiting on backorders get no automated communication from the WMS today.

Manager monthly review:

  • Pull fulfillment_events WHERE type = 'order:backorder_resolved' AND createdAt > (now - 30 days) — what got resolved this month.
  • Pull Order WHERE status = 'ON_HOLD' AND holdAt > (now - 30 days) — newly escalated orders. Each one is a manual-review queue item.
  • Diff count(BACKORDERED) against last month. Trending up means inflow isn't keeping pace with order volume; trending down is healthy.

Quarterly governance:

  • Median time BACKORDERED → ALLOCATED for orders that resolved this quarter. Tightening means upstream improvements are working.
  • Count of orders that hit ON_HOLD via the 30-day rule. High count means either (a) stocking is genuinely chronic for some SKUs, or (b) the retry pipeline is unhealthy.
  • Top 10 SKUs by total ordersWaiting * shortfall — the buyer's reorder priority list.

7. Troubleshooting

SymptomCauseResolution
Receiving session was approved an hour ago, but my dashboard still shows the same backordered orders waiting on that SKUEither the worker queue is backed up, or the MAX_RETRY_BATCH = 20 cap was hit and your orders are in the next batchCheck #wms-support for queue health. If healthy, wait — the next inflow for that variant will pick up the rest. If urgent, run Fulfill All (§4.5) manually.
Fulfill All reports 0 fulfilled, 50 still backordered even though the dashboard shows available stockPer §4.3 callout, the dashboard "Available" includes non-pickable locations. The available stock is in receiving/staging, not in pickable bins.Either move the stock to a pickable location (WMS-INV-001 §4.1) or wait for putaway (WMS-REC-004). Then retry.
An order has been BACKORDERED for 45 days but isn't ON_HOLDThe 30-day cutoff is on updatedAt, not createdAt. Some retry within the last 30 days touched the order.Check Order.updatedAt. If it's recent, the order is still considered fresh by the retry pipeline. To force escalation, manually update status: ON_HOLD via DB. To prevent the next retry from un-escalating, also set holdAt and holdReason.
Fulfill returns 200 but the order didn't move from BACKORDEREDAllocation tried but found no pickable inventory for any itemExpected. The order stays on the dashboard. Either source the stock or accept the backorder.
Customer-return restock added 50 of a SKU but the backorder for that SKU didn't auto-retryPer §4.2 gap, return restocks don't enqueue checkBackorders todayManual Fulfill All for that order, or run a one-off enqueue script per SKU after a return wave. File the return-restock-enqueue gap as engineering work — it's a 3-line addition to the return restock service.
Lightweight /inventory/:id/adjust increased available stock but waiting backorders didn't triggerSame as above for the adjust pathSame workaround. File the adjust-enqueue gap.
Split was performed accidentallySplit is irreversible per §4.6Ship the parent normally; the child stays on the dashboard until its items can be filled. There's no merge. If this happens repeatedly, lock the split CTA behind a confirm modal as engineering work.
Auto-retry escalated an order to ON_HOLD but the customer just got patient with usThe 30-day rule firedManually re-set status: BACKORDERED and holdAt: null via DB. The next retry will treat it normally. Document the override.
Orders waiting on an SKU but the SKU isn't in the By SKU tabThe order's items may have matched: false (no variant match in the system at all)These orders end up ON_HOLD rather than BACKORDERED. They don't show on the SKU tab because there's no SKU to match. Look in the Orders tab for ON_HOLD filtered.
Worker keeps logging [Orders] Found 0 backordered orders to retry for the same variantEither no waiting orders for that variant, or the orders' items aren't matched: trueConfirm with Order WHERE status IN ('BACKORDERED', 'PARTIALLY_ALLOCATED') AND items.some({ productVariantId: X, matched: true }). If zero, the worker is correct — there's nothing to retry.

8. Escalation

  • Wire enqueueCheckBackorders into the return restock and /inventory/:id/adjust paths. Both are inflow events that should trigger backorder retry. Returns produce real, sellable stock that today's pipeline misses entirely. The integration is roughly 5 lines per call site (per-unique-variant enqueue with triggerSource). High operational value, small effort.
  • Build the split-backorder UI button. The splitBackorder API works; no UI surfaces it. A button on the dashboard's Orders tab that opens a confirm modal explaining the split, then calls the endpoint. Maybe an hour. Without this, splits today require either Postman/Bruno or a developer.
  • Persist triggerSource to the events table. Currently triggerSource: "receiving:{sessionId}" reaches the worker logs but not the DB. Adding a triggerSource column on fulfillment_events would give "which receiving session unblocked which order" as a clean SQL query, instead of timestamp-correlation guesswork.
  • Customer notification on order:backorder_resolved. Today the WMS doesn't notify the customer when their long-backordered item finally allocates. A simple email trigger on the order:backorder_resolved event would close the loop.
  • Sustained ON_HOLD escalation count >5/week. Cross-functional: warehouse manager + buyer review the hold list. Either source missing stock, substitute SKUs (with customer agreement), or cancel and refund.
  • Worker queue persistently backed up affecting auto-retry. IT — BullMQ depth and concurrency. Queue health affects every async path, not just backorders.

9. Revision history

VersionDateAuthorChanges
1.0[DATE][NAME]Initial release. Documents the full backorder resolution lifecycle: status decisions in OrderAllocationService.allocateOrder(), the auto-retry pipeline (enqueueCheckBackordersprocessCheckBackorderscheckBackorderedOrders → batched enqueueAllocateOrder), the 30-day stale-escalation rule (MAX_BACKORDER_DAYS = 30, hardcoded), the 20-order cap per check (MAX_RETRY_BATCH = 20), and the priority+FIFO order of retry. Documents the /backorders UI dashboard, including the available-stock overcount callout (the dashboard sums all AVAILABLE units regardless of pickable, so receiving-zone stock inflates the "fillable" view). Documents the manual retry, batch fulfill, and split-backorder operations. Documents two real upstream gaps: customer-return restock (per WMS-RET-002) and lightweight /inventory/:id/adjust (per WMS-INV-001 §4.2) both add inventory but do not enqueue checkBackorders — backorders waiting on those inflows do not auto-retry. Documents one downstream gap: no UI button for splitBackorder. Documents the partial audit story — events on entry/exit only, no retry-attempt log, no triggerSource persistence. Cross-references WMS-REC-003 (primary trigger), WMS-INV-002 (secondary trigger), WMS-INV-001, WMS-RET-002, WMS-PICK-001, WMS-AUD-002. Code references: packages/queue/src/types.ts:541-544, apps/worker/src/processors/order.processor.ts:127-158, packages/domain/src/services/order-allocation.service.ts:270-360, 387-433, 439+, apps/api/src/routes/order.route.ts:283-380, 653-692, 939+, 1017+, apps/web/src/pages/backorders/index.tsx:255-310.