Orders & fulfilment
Dropship Operations
Indicative price, not an offer: EUR 300-500/year or EUR 750 one-off
Generated from docs/plan/paid/dropship-operations/PLAN.md in the AstroBaaS repository. Nothing described below is implemented — it is the written plan for it.
Merchants define dropship suppliers, associate products with supplier stock, and configure routing rules. On order placement, system routes order to supplier (or splits multi-supplier orders) and sends PO via API or email. Inventory synced from supplier.
The problem
I want to sell without inventory investment, but managing 5 suppliers’ APIs manually is unsustainable. I need automatic PO generation and inventory sync.
What it does
- Supplier entity: supplier_id, name, api_endpoint, api_key, contact_email, edi_format (api|email|sftp), response_time_hours, is_active
- Supplier inventory sync: fetch inventory from supplier API/SFTP daily; update Product.supplier_stock
- Supplier routing rules: ‘product 123 ships from supplier A if quantity <= 100, else from supplier B’
- Order routing: on order creation, determine which supplier fulfills each line item; split if needed
- PO generation: create Purchase Order with order ID, customer details (hidden from supplier), line items, total, delivery address
- PO transmission: send PO to supplier via API (POST to supplier endpoint), email, or SFTP upload
- PO tracking: track PO status (pending, acknowledged, shipped, delivered, cancelled)
- Inventory hold: when order placed, reserve inventory from supplier until shipment confirmed
- Supplier order sync: poll supplier for shipment status; sync tracking number back to order
- Dropship shipment: supplier ships directly to customer; order shows ‘Dropship via Supplier A’
- Margin tracking: purchase price from supplier vs retail price; profit report
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.
- Real-time inventory sync (WebSocket): out of scope—daily polling only. Reason: most suppliers don’t offer real-time.
- Complex routing rules (ML-based optimization): out of scope—simple if/then rules only. Reason: optimization is deferred.
- Supplier cash flow management (payment terms, invoicing): out of scope. Reason: accounting module out of scope.
- Returns routing (reverse logistics): out of scope—returns go to merchant, not supplier. Reason: complexity deferred.
- Price negotiation with suppliers: out of scope. Reason: handled outside system (contracts).
- Multi-currency supplier accounts: out of scope—supplier account in USD only. Reason: currency handling deferred.
Data model
Supplier table/collection (supplier_id, name, api_endpoint, api_key, contact_email, edi_format, is_active, created_at). SupplierProduct table (id, supplier_id, product_id, supplier_sku, cost_minor, min_order_qty, lead_time_days). PurchaseOrder table (po_id, order_id, supplier_id, po_number, status, line_items JSON, total_minor, sent_at, acknowledged_at). Add supplier_id to Order and Shipment.
API
- POST /suppliers (staff, body: {name, api_endpoint, api_key, edi_format, contact_email}) → {supplier_id}
- GET /suppliers → [{supplier_id, name, is_active, last_sync_at, inventory_count}]
- PUT /suppliers/:id (staff, body: {is_active, api_key?, contact_email?}) → {supplier_id}
- POST /suppliers/:id/test-connection (staff) → {success: true | false, error?: string}
- POST /suppliers/:id/sync-inventory (staff, background job) → {sync_id, status: ‘running’}
- POST /suppliers/:id/products (staff, body: {product_id, supplier_sku, cost_minor, min_order_qty, lead_time_days}) → {id}
- GET /suppliers/:id/products → [{product_id, supplier_sku, cost_minor, stock_level, last_sync}]
- GET /purchase-orders → [{po_id, order_id, supplier_id, status, sent_at}]
- GET /purchase-orders/:id → {po_id, order_id, line_items, total, acknowledgment_status, tracking?}
Every route added here must also appear in src/pages/openapi.json.ts — a test
fails the build if it does not.
Admin
Suppliers section: list suppliers with connection status, last inventory sync time, products count. Test Connection button. Add/edit supplier form. Products list for each supplier (product, supplier SKU, cost, stock, lead time). POs section: list all POs with status, supplier, sent date, acknowledgment status.
The seam — why this is paid
Core owns supplier entity, PO generation, and routing rules. Paid pack owns: complex multi-supplier optimization (ML routing), reverse logistics (returns), multi-currency supplier accounts, cash flow management. Why: core provides honest dropship routing and PO generation; optimization and accounting are paid.
Requires supplier API credentials and integration. Support commitment for order routing and inventory sync with drop shippers.
Dependencies
- orders (order entity and order.created event)
- products (product.supplier_stock field)
- shipments-with-tracking-and-carrier-hooks (PO links to order line items)
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.
- Supplier ‘FastShip’ added: api_endpoint=‘https://fastship.example.com/api’, api_key=‘test_key’; supplier_id returned
- POST /suppliers/sup_123/test-connection returns {success: true} if credentials valid
- Sync inventory: fetch from supplier API; Product 123 stock updated to 50 units; SupplierProduct.cost set to 10.00 USD
- Routing rule: if product 456 qty <= 100, use supplier A; order with qty 80 routes to supplier A
- Order placed with 3 line items: items 1-2 from supplier A, item 3 from supplier B; two POs generated (one per supplier)
- PO sent to supplier: API endpoint receives POST with order_id, customer (hidden), line_items, delivery_address
- PO status tracked: supplier acknowledges; status=‘acknowledged’; order.supplier_acknowledged webhook fired
- Supplier shipment arrives; tracking synced back to order via supplier API poll; order shows ‘Shipped by FastShip’
- Inventory hold: when order placed, SupplierProduct.stock decremented; hold released if order cancelled
- Margin report: product cost 10.00, retail 29.99; profit per unit = 19.99 (before tax, shipping)
Risks
Inventory accuracy: if supplier inventory is stale (sync failed), orders can oversell; must validate sync success. PO transmission: if PO API is down, order is placed but PO never sent; supplier doesn’t fulfill; manual escalation needed. Routing: if routing rule is wrong, orders go to wrong supplier; unsellable items shipped to customer. Supplier account: if api_key is leaked, attacker can create fake POs and drain supplier inventory (or cost). Margin tracking: if cost is wrong (outdated supplier pricing), profit is miscalculated.
Commercial context
| Suggested price | EUR 300-500/year or EUR 750 one-off |
| Rival anchor | Webkul Dropship Extension |
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.