Cart optimisation¶
What this answers: when the user has a complete Build with components available at multiple retailers, what does the optimiser do to recommend the cheapest combination?
This page is a stub — full design lives in the upcoming RFC for #15.
Sequence¶
sequenceDiagram
participant B as Browser
participant S as Next.js server
participant DB as Postgres
participant Opt as Optimiser
B->>S: GET /api/cart/aggregate?build=...
S->>DB: SELECT Listings for each component, JOIN Retailer
DB-->>S: rows (price, retailer, in-stock)
S->>Opt: optimise(buildSlots, listings, shippingRules)
Opt->>Opt: compute single-retailer subtotal per Retailer
Opt->>Opt: compute multi-retailer optimum (combination search)
Opt->>Opt: annotate with shipping, in-stock count, quote-only count
Opt-->>S: trade-off matrix
S-->>B: JSON response
B->>B: render side-by-side options (per-retailer vs split)
What the optimiser must consider¶
- Shipping cost — fixed or threshold-based per retailer (varies; needs a Reference doc when known)
- In-stock availability — a cheaper component the retailer doesn't have isn't useful
- Quote-only listings —
priceUsdis null; can't be summed. Either exclude from total or surface as "+ ? components on quote" - Combinatorial explosion — 8 slots × N retailers gets large fast. With 6-8 retailers (M2 target) and 3-5 listings per slot, brute-force enumeration is fine. With more, prune aggressively.
What it does not do¶
- No checkout integration. The optimiser surfaces the recommended split as URLs to follow. The user clicks through (UC-2 via deep-links) per retailer.
- No coupon / discount codes. Out of scope.
- No price-match guarantee logic. That's a retailer-side feature.
Open questions for the RFC¶
- What's the right UX when "single retailer is $20 more but saves N deep-link clicks"? Show both options? Default to one?
- How are quote-only listings surfaced — exclude entirely, or show "X items need a quote"?
- Caching: optimisation results are derivable but expensive. TTL? Or recompute on each request and trust Listings change rarely?
See #15 for the implementation issue and the upcoming RFC.