Catalogue & product data
Order Tracking Portal (Branded Customer View)
Generated from docs/plan/core/order-tracking-portal/PLAN.md in the AstroBaaS repository. Nothing described below is implemented — it is the written plan for it.
A branded, customer-facing order tracking portal where shoppers enter their email and order ID to see real-time fulfillment status, shipping details, and estimated delivery. Reduces support tickets by letting customers self-serve order status without contacting support. Core handles the state machine and portal interface; paid modules integrate carrier APIs for live tracking.
The problem
Customers email ‘where’s my order?’ 50+ times a week. I spend 10 hours manually answering tracking questions. I need a self-service portal so customers can check status themselves, branded to match my storefront, without me forwarding them to a third-party site.
What it does
- Public portal (no login required) where customer enters email + order ID to view their order
- Display order status (pending, processing, shipped, delivered), order total, items, and fulfillment line items
- Show estimated delivery date based on order state and manual input
- Display shipping carrier, tracking number, and link to carrier (if filled by fulfillment module)
- Email notification when order ships, with tracking info and portal link
- Portal fully branded with shop logo, colors, and custom domain support
- API endpoint for merchants to fetch their own order status (for embedding in headless storefronts)
- Audit log of portal visits and status checks per order (for merchant visibility)
- Filter orders by date range in merchant admin, export tracking report as CSV
- Block portal access if order is cancelled or refunded (configurably)
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 carrier API integration — paid carrier modules own this. Core does not call TrakPak, Stamps, or EasyPost; it only stores what the fulfillment module wrote to order.carrier_tracking_number.
- Signature capture or proof of delivery — carrier modules own this; core portal displays what the carrier API returned.
- Return RMA generation — that is order management, not tracking. Paid returns module owns RMA flows.
- SMS or WhatsApp notifications — communication channel integrations are paid plugins; core owns email only.
- ML-driven delivery time estimation — rule-based static estimates stay free; predictive models go paid.
- International customs, duties, or import tracking — country-specific integrations are paid; core shows what the carrier API sent.
Data model
New fields on ORDER entity: estimated_delivery_date (timestamp), carrier_tracking_number (string), carrier_name (enum), fulfillment_line_items (array of {line_id, qty_shipped, qty_delivered, status}). No migration required; fields are optional.
API
- GET /orders/:orderId/tracking (public, requires email + orderId match)
- GET /orders/:orderId/tracking (merchant, requires auth)
- PATCH /orders/:orderId/tracking (merchant fulfillment update: carrier, tracking number, EDD)
- GET /admin/orders/tracking-report (merchant export with date filter)
Every route added here must also appear in src/pages/openapi.json.ts — a test
fails the build if it does not.
Admin
Merchant views Orders list with ‘Tracking’ column. Click to open portal preview. Set carrier, tracking number, and EDD in order detail panel. Export tracking report to CSV grouped by carrier. Email template editor for tracking notification.
The seam — why this is core
Core owns order state machine, portal UI, email notification, and tracking data storage. Paid carrier modules own API integration (calling TrakPak, EasyPost, Stamps) and writing carrier_tracking_number + estimated_delivery_date back to orders. Core never speaks to carrier APIs; it only consumes the result.
Core owns order tracking state machine and customer-facing portal interface; paid modules own carrier API integrations
Dependencies
- Order management (existing)
- Email system (existing)
- Public API routing (existing)
- Fulfillment module (optional; but assumed to exist for real workflow)
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.
- Customer can visit /tracking, enter email + order ID, and see order status without login
- Estimated delivery date displays; if missing, shows ‘Not yet dispatched’ instead of null
- Tracking link to carrier works when carrier_tracking_number is set; omitted if blank
- Shipping email is sent when order transitions to ‘shipped’ state
- Merchant can set carrier, tracking number, and EDD from order detail; changes save and persist
- Export CSV includes order ID, customer email, status, carrier, tracking number, EDD for all orders in date range
- Cancelled order is not visible in public portal (customer gets 404 or ‘order not found’)
- Audit log records portal visits with IP, timestamp, and order ID
Risks
If carrier_tracking_number is public, account takeover via order enumeration is possible. Mitigate: require email + orderId match, throttle failed lookups, log all attempts. If EDD is always displayed, merchants may face complaints about inaccuracy — mitigate with disclaimer or ‘typically by’ language. If merchant forgets to set carrier info, customers see broken links — mitigate with admin warnings.
Commercial context
| Suggested price | free (core) |
| Rival anchor | 17TRACK, CWILL, Track123 (all freemium; free tier basic tracking page) |
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.