AstroBaaS

Orders & fulfilment

Fulfillment Status

Free — GPL coresize Mplanned, not built

Generated from docs/plan/core/fulfillment-status/PLAN.md in the AstroBaaS repository. Nothing described below is implemented — it is the written plan for it.

Merchants can’t mark orders as fulfilled, so they don’t know which orders are ready to ship or already shipped. This feature adds a fulfillment workflow state to orders.

The problem

I don’t have a way to say ‘this order is ready to ship’ or ‘this order is fulfilled’. I manually track readiness in my head or notes. I need a status that shows fulfillment progress.

What it does

  • Add fulfillment_status enum to orders: unfulfilled, partially_fulfilled, fulfilled, cancelled
  • Auto-update fulfillment_status based on shipments: if all items shipped, status → fulfilled
  • Allow manual status override: staff can mark order as fulfilled even if no shipment created
  • Display fulfillment status as badge in order list and detail (different colors: gray unfulfilled, yellow partial, green fulfilled)
  • Filter order list by fulfillment status (e.g., show only unfulfilled orders)
  • Show fulfillment % in order detail: (items_shipped / total_items) * 100
  • Support bulk status change: select multiple orders and mark as fulfilled at once

What it deliberately does NOT do

Each boundary carries its reason. A boundary without a reason gets crossed by the next person who reads this.

  • Fulfillment workflow automation (e.g., ‘when payment captured, auto-set status to ready’) — that is automation, separate feature
  • Backorder or pre-order fulfillment states — that is inventory system, separate feature
  • Fulfillment notifications to warehouse (e.g., print pick list) — that is warehouse system, separate feature

Data model

orders.fulfillment_status (enum: unfulfilled, partially_fulfilled, fulfilled, cancelled). orders.fulfillment_updated_at (timestamp). No migration if orders schema is extensible; otherwise migration to add fields.

API

  • PATCH /api/admin/orders/:orderId/fulfillment-status — update fulfillment status
  • GET /api/admin/orders?fulfillment_status=unfulfilled — filter orders by fulfillment status
  • POST /api/admin/orders/bulk-action — bulk update fulfillment status

Every route added here must also appear in src/pages/openapi.json.ts — a test fails the build if it does not.

Admin

Order list includes ‘Fulfillment’ column showing status badge. Order detail shows fulfillment status badge and % progress bar. Button ‘Mark as Fulfilled’ changes status. Bulk actions sidebar: select multiple orders, dropdown ‘Bulk Action’ → ‘Mark Fulfilled’. Filter sidebar: checkbox ‘Unfulfilled’, ‘Partially Fulfilled’, ‘Fulfilled’.

The seam — why this is core

Core owns fulfillment status field, workflow, and UI. No paid seam — fulfillment tracking is infrastructure.

Core owns the interface + honest fulfillment tracker; order workflow is infrastructure, not a support commitment or credential.

Dependencies

  • Existing orders collection (needs fulfillment_status field)
  • shipment-management-tracking (for auto-updating status based on shipments)

Acceptance checks

Each of these must be able to fail. Before claiming this is done, break the code deliberately and watch each one go red.

  • Create order with 5 items and 1 shipment with 2 items; confirm fulfillment_status=‘partially_fulfilled’ and progress=40%
  • Add second shipment with remaining 3 items; confirm fulfillment_status auto-updates to ‘fulfilled’
  • Manually mark order as fulfilled; confirm fulfillment_status=‘fulfilled’ regardless of shipments
  • Filter order list by fulfillment_status=‘unfulfilled’ and confirm only unfulfilled orders are shown
  • Bulk-select 5 orders and mark as fulfilled; confirm all 5 orders update status

Risks

Auto-updating fulfillment_status based on shipments can create race conditions if shipment and fulfillment updates happen concurrently. Use database transactions to ensure consistency. Bulk status updates on large order sets (1000+) can timeout; implement async batch processing.

Commercial context

Suggested pricefree (core)
Rival anchorShopify: included; Magento: included

The anchor is what the nearest equivalent charges on Shopify or Magento today. It is context for a pricing decision, not the decision.


Generated from the commerce plan. See docs/COMMERCE-PLAN.md for the full catalogue and ../../AI-GUIDE.md for how to work on this repository.