Catalogue & product data
Bundle Products (Kit Builder)
Generated from docs/plan/core/bundle-products/PLAN.md in the AstroBaaS repository. Nothing described below is implemented — it is the written plan for it.
A first-class product type where a merchant defines a bundle as a collection of products (child products or variants) with fixed or variable quantities per item, and a bundle-level price that may be less than the sum of parts (incentivizing bundles). Used for PC builds, gift hampers, lens kits, and composite products. Each bundle item can have inventory requirements and can be optional.
The problem
I sell PC builds (CPU + motherboard + RAM + GPU) and gift hampers (candle + tea + chocolates). Right now I create ‘combo’ products and manually calculate price. I need bundles where I pick component products, set quantities and prices, and let customers see the breakdown — and inventory for the bundle only happens if all components are in stock.
What it does
- Bundle product type: select ‘Bundle’ when creating product
- Bundle composition: add child products/variants with qty per bundle item (e.g., 2x RAM modules, 1x CPU, optional 1x cooler)
- Bundle pricing: fixed price (e.g., €1200 for complete PC) or calculated from components with discount
- Bundle inventory: inventory is checked per component; bundle is in stock only if all required components are in stock in sufficient qty
- Optional bundle items: customer can skip optional items (e.g., cooler) or swap for another item in same category
- Bundle discount display: show ‘save €200 by buying bundle’ or ‘You save 15% vs. buying separately’
- Bundle detail page: list all components with images, prices per component, total bundle price
- Cart behavior: bundle appears as one line item; add-to-cart is one step (no component picker) or two-step (let customer confirm components)
- Bundle SKU: either generate composite SKU (PC-CPU-RAM-GPU) or single SKU with component breakdown in notes
- Bundle analytics: track bundle popularity, component combination frequency, bundle discount redemption
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.
- Dynamic bundle builder (customer picks components, price updates dynamically) — that is advanced bundler, a paid feature. This is merchant-defined bundles.
- Bundle discounts tied to customer segments or rules — that is promotion rules module. Bundles have fixed discount; conditional discounts are promotions.
- Cross-shop bundle referencing — bundles use products from same shop only. Multi-shop bundles require a shared catalog layer.
- Bundle recommendations or smart bundling (ML suggests components) — that is ML recommendation module. Bundles are merchant-curated.
- Component substitution based on inventory (auto-swap CPU if out of stock) — that is fulfillment logic. Bundles check inventory; fulfillment owns substitution.
Data model
New field on PRODUCT: product_type (enum: ‘simple’ | ‘configurable’ | ‘bundle’ | ‘grouped’). New BUNDLE_COMPOSITION table (bundle_id, component_product_id, qty, is_optional, display_order). Migration required: update existing products to product_type=‘simple’.
API
- POST /admin/products (create bundle with components)
- PATCH /admin/products/:id (update bundle composition)
- GET /admin/products/:id/bundle-inventory-check (return: ‘in stock’ or ‘out of stock, component X qty needed’)
- GET /products/:id (response includes product_type=‘bundle’, components array with product data)
- POST /cart (add bundle: {product_id, qty, component_overrides?: [{component_id, swapped_variant_id}]})
Every route added here must also appear in src/pages/openapi.json.ts — a test
fails the build if it does not.
Admin
Product create form includes product_type selector. If bundle: composition section with ‘Add Component’ button. Component picker shows products, qty field, optional toggle, remove button. Bundle price input or ‘auto-calculate from components’ with discount %. Inventory checker: ‘Check Stock’ button shows availability of each component.
The seam — why this is core
Core owns bundle schema, inventory checking, and cart handling. Core does not own dynamic pricing based on customer rules (that is promotion rules), AI-driven bundling (that is ML), or fulfillment substitutions. Core owns the interface; paid modules own the logic that consumes bundles.
Real gap. ORDER_LINE_EXTRAS is a workaround, not a feature. Bundle products are a distinct product type for many verticals (tech, gifts, customizable boxes).
Dependencies
- flexible-product-attributes (optional, for variant components)
- variable-products (optional, components may be variants)
- Product model (core, existing)
- Inventory management (core, existing)
- Cart system (core, existing)
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.
- Bundle ‘PC Build’ is created with components: CPU (qty 1), RAM (qty 2), GPU (qty 1), optional Cooler (qty 1)
- Bundle inventory check: CPU 0 in stock, other components in stock → bundle is ‘out of stock’ until CPU restocks
- Bundle price is set to €1200; component breakdown shows sum €1400, discount €200 displayed on product page
- Cart: add-to-cart adds bundle as one line item with qty, not individual components
- Optional Cooler is skipped by customer; order total is €1200 (bundle price as-is, no deduction)
- Bundle SKU is ‘PC-BLD-001’ or auto-generated from component SKUs; appears on order and invoice
- Analytics report: ‘PC Build bundle sold 50 units this month; most popular component combination is AMD CPU’
- Bundle is unavailable (show ‘Out of Stock’) if any required component is out of stock in required qty
Risks
If inventory is checked only at order time, not at add-to-cart time, customer adds unavailable bundle and sees error at checkout (bad UX). Mitigate: check inventory on add-to-cart and show warning. If bundle inventory is not atomic, over-selling occurs (two customers buy same bundle, both get component that’s now out of stock). Mitigate: reserve inventory when bundle is added to cart, release on checkout or cart abandon. If optional component is bundled with fixed price, customer confusion occurs (why is optional item included in price?). Mitigate: show component breakdown clearly and make optional items visually distinct.
Commercial context
| Suggested price | Free; core for kit-based business models |
| Rival anchor | Magento Open Source bundle products; free |
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.