Pricing & promotions
Cart Price Rules (Automatic)
Generated from docs/plan/core/cart-price-rules/PLAN.md in the AstroBaaS repository. Nothing described below is implemented — it is the written plan for it.
Core free module that applies automatic discounts at checkout based on cart conditions: ‘spend €50 get free shipping’, ‘20% off orders over €100’, ‘buy product X get €10 off’. Rules are evaluated server-side; discount is applied in checkout, not as a coupon code (no code entry required). Merchants create multiple rules; checkout evaluates all rules and applies highest discount.
The problem
Coupons require customers to know and enter a code, reducing conversion. Merchants want ‘spend €50 free shipping’ to apply automatically. Currently, they can only use coupons or manually adjust orders, losing sales because automatic promotions are unavailable.
What it does
- Rule types: spend threshold (€50 → free shipping), item quantity (buy 3+ → 20% off), specific product (buy iPhone → €50 off), category (buy €100 in shoes → 10% discount)
- Discount types: percentage off, amount off, free shipping, buy-X-get-Y (BOGO)
- Rule conditions: min cart value, min quantity, product/category inclusion, exclude low-margin items
- Rule priority: merchant defines priority; highest-priority matching rule is applied (can’t stack)
- Time-based rules: rule is active only during date range (e.g., ‘Labor Day sale’, Sep 1–3)
- Storefront disclosure: show ‘free shipping on orders over €50’ in cart summary before checkout
- Audit log: log rule creation, edits, and which rule was applied to each order
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.
- Coupon codes (already exist; this is automatic rules, not codes)
- Complex stacking logic (one rule per order; merchants choose priority)
- Customer segment rules (e.g., ‘VIP customers only’); see loyalty-points-vip-tiers-rewards
Data model
Add cart_price_rules table: { id, shop_id, rule_name, rule_type (‘spend_threshold’, ‘item_quantity’, ‘product’, ‘category’), conditions (JSON), discount_type (‘percent’, ‘amount’, ‘free_shipping’, ‘bogo’), discount_value, priority, active, start_date, end_date }. Schema migration: new table.
API
- POST /admin/cart-price-rules — create rule
- GET /admin/cart-price-rules — list all rules with matching conditions
- PUT /admin/cart-price-rules/:id — edit rule
- DELETE /admin/cart-price-rules/:id — delete rule
- POST /checkout/evaluate-cart-rules — { items, cart_total } → returns { applied_rule_id, discount_amount }
Every route added here must also appear in src/pages/openapi.json.ts — a test
fails the build if it does not.
Admin
Add ‘Cart Price Rules’ in Commerce > Promotions. List: rule name, type, conditions, discount, priority, active status. Create rule form: name, rule type selector, conditions builder (spend €50? yes/no, quantity 3+? etc.), discount type and value, priority slider, date range picker, active toggle. Preview: show discount amounts for test cart values.
The seam — why this is core
Core owns cart rule evaluation and checkout integration. Merchants create rules in admin. Paid scheduled-promotions-manager module adds calendar UI for managing multiple time-based rules.
Currently only coupons are available. This is 50% of promotion use-cases. Built on the price-rule engine primitive. Essential for competitive pricing.
Dependencies
- Checkout flow (to evaluate and apply rules)
- Audit log system (to log rule application)
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.
- Rule ‘Free shipping on €50+’ is active; cart totals €75 → free_shipping is applied (shipping cost removed from order total)
- Rule ‘spend €100 get 20% off’ matches; cart = €120 → discount = €24 applied
- Two rules match the cart; priority 1 = ‘20% off’, priority 2 = ‘free shipping’ → only priority 1 is applied
- Rule is time-limited (Sep 1–3); checkout on Sep 4 doesn’t apply rule (date check passed)
- Audit log records which rule was applied: ‘Free shipping on €50+ applied to order #12345 on Sep 2’
Risks
If rules are evaluated on the client (storefront), merchant can edit JS and change discount (always evaluate server-side). If rule priority is numeric and not enforced (duplicate priorities cause ambiguity), wrong rule applies. If discount amount exceeds cart total (e.g., 20% off €50 = €10, but rule specifies €50 off), checkout total becomes negative (validate: discount <= cart_total).
Commercial context
| Suggested price | Free; core promotion engine |
| Rival anchor | Magento Open Source Cart Price Rules; 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.