AstroBaaS

Orders & fulfilment

Bulk Order Actions

Free — GPL coresize Mplanned, not built

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

Merchants can’t update 50 orders at once; they manually change status one-by-one, which is time-consuming. This feature allows batch operations on multiple orders.

The problem

When I need to update 50 orders (mark as fulfilled, add tag, cancel), I click 50 times. One bulk-action interface would save hours per week.

What it does

  • Add ‘Select All’ checkbox to order list to select multiple orders
  • Show selection count badge: ‘X orders selected’
  • Bulk-action dropdown: ‘Change Status’, ‘Add Tag’, ‘Cancel Orders’, ‘Mark Fulfilled’, ‘Add Note’
  • Confirm dialog before bulk action (e.g., ‘Mark 50 orders as fulfilled?’)
  • Log each action to order_events with user_id so individual orders retain history
  • Show progress bar for long-running bulk actions (e.g., cancelling 500 orders)
  • Support filtering + bulk action: filter orders (e.g., fulfillment_status=unfulfilled), then ‘Select All Filtered’ to apply action
  • Undo bulk action (within 1 hour): revert all orders to previous state

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.

  • Scheduled bulk actions (e.g., ‘mark unfulfilled orders as cancelled at 11:59 PM tomorrow’) — that is scheduling/automation, separate feature
  • Conditional bulk actions (e.g., ‘if order total > $100, add VIP tag’) — that is automation/rules engine, separate feature
  • Bulk export/import of orders — that is data migration, separate feature

Data model

No new schema; bulk actions are UI wrapper around individual order updates. Audit trail stored in order_events (user_id shows who triggered bulk action, and each order event is logged individually).

API

  • POST /api/admin/orders/bulk-action — apply action to multiple orders
  • GET /api/admin/orders/bulk-action/:jobId — check status of long-running bulk action
  • POST /api/admin/orders/bulk-action/:jobId/undo — undo a bulk action

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 view. Checkbox column with ‘Select All’ in header. Bulk-action toolbar appears when ≥1 order selected: ‘X orders selected’ counter, dropdown with actions (Change Status, Add Tag, Cancel, Mark Fulfilled, Add Note), and ‘Undo’ button if recent bulk actions exist. Clicking action opens modal: select target value (e.g., new status), confirm button, cancel button. Progress bar shown during execution.

The seam — why this is core

Core owns bulk-action UI and batch processing. No paid seam — batch operations are infrastructure.

Core owns the interface + honest batch editor; order operations are infrastructure, not a per-country obligation or credential.

Dependencies

  • Existing orders collection
  • order-tags (for ‘Add Tag’ action)
  • order-notes (for ‘Add Note’ action)
  • scheduler (for async bulk processing)

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.

  • Select 10 orders and apply ‘Mark Fulfilled’; confirm fulfillment_status updates for all 10 orders
  • Verify order_events logs 10 individual events (one per order) with same bulk-action-id linking them
  • Apply bulk action to 100 orders and verify progress bar updates during processing
  • Undo bulk action and confirm all 100 orders revert to pre-action state within 1 minute
  • Filter orders (e.g., status=processing), select all filtered, and apply bulk action; confirm only filtered orders are updated

Risks

Bulk actions on 10,000+ orders can timeout or consume too much memory. Implement chunked processing (1000 orders at a time) and run async in background job. Undo feature requires storing previous state; implement snapshot-on-bulk-action or transaction log.

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.