Promotion Schema
A discount engine evaluates active promotions against a cart and computes the final discounted price. The promotion schema captures what qualifies and what discount applies:
CREATE TABLE promotions (
promo_id UUID PRIMARY KEY,
name VARCHAR(128) NOT NULL,
type ENUM('cart_discount','item_discount','volume','bundle','loyalty') NOT NULL,
conditions JSONB NOT NULL, -- {min_cart_value, eligible_skus[], user_segments[]}
discount JSONB NOT NULL, -- {type: 'pct'|'fixed'|'free_item', value}
priority INTEGER NOT NULL DEFAULT 0,
stackable BOOLEAN NOT NULL DEFAULT FALSE,
ab_variant VARCHAR(32), -- NULL = show to all
start_date TIMESTAMPTZ NOT NULL,
end_date TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
Storing conditions and discount as JSONB allows adding new promotion types without schema migrations. Priority determines evaluation order and stacking resolution.
Rule Evaluation Engine
The evaluation engine operates on a cart context object containing: user_id, user_segments, cart_total, line_items (sku, quantity, price, category).
- Load all active promotions:
WHERE start_date <= now() AND (end_date IS NULL OR end_date > now()). Cache this list with a 60-second TTL — promotions change infrequently. - Filter by A/B variant: if
ab_variantis set, only show this promotion to users assigned to that variant. - Evaluate conditions for each promotion:
- Cart total meets
min_cart_value - At least one item's SKU is in
eligible_skus(or list is empty = all SKUs) - User is in one of the
user_segments(or list is empty = all users)
- Cart total meets
- Collect all matching promotions.
Stacking Policy
Three stacking strategies, selected at the engine configuration level:
- Stack all: Apply every matching promotion. Each stackable promotion's discount adds to the total. Non-stackable promotions are skipped if a stackable one was already applied.
- Highest priority only: Sort by priority descending, apply only the first matching promotion. Simplest to reason about; avoids runaway discounts.
- Best deal: Compute the discount value each promotion would give independently, apply the one with the largest discount. Fair to the customer, predictable for the business.
In practice: non-stackable promotions compete with each other (best deal or priority wins); stackable promotions (e.g., a loyalty discount) always layer on top of whatever wins the non-stackable evaluation.
Volume and Bundle Discounts
Volume discounts are tiered by quantity of a specific SKU or category:
conditions: {eligible_skus: ["SKU123"], tiers: [
{min_qty: 3, discount: {type: "pct", value: 10}},
{min_qty: 5, discount: {type: "pct", value: 20}}
]}
Evaluation: find the highest tier the cart quantity satisfies, apply that discount. Only applies to the qualifying items, not the full cart.
Bundle discounts require multiple distinct products to be present:
conditions: {required_skus: ["SKU_A", "SKU_B"]}
discount: {type: "pct", value: 15, applies_to: "bundle_items"}
Evaluation: check all required SKUs are in the cart. Apply discount to those items only.
Price Calculation Order
Apply discounts in this sequence to reach the final cart total:
- Start with original prices for each line item.
- Apply item-level discounts (volume, bundle, item_discount promotions). Discount applies to qualifying items only.
- Sum discounted line item totals to get the discounted subtotal.
- Apply cart-level discounts (cart_discount promotions) to the discounted subtotal.
- Apply coupon code (if any) to the post-promotion subtotal.
- Add shipping and tax (calculated on post-discount subtotal).
- Apply loyalty or payment-method discounts (e.g., 2% off for paying with store credit).
- Return final total.
Return an itemized breakdown showing original price, each discount applied, and final price — both for displaying to the user and for audit/analytics.
Promotion A/B Testing
Assign users to variants deterministically using a hash of user_id and experiment_id:
variant = hash(user_id + experiment_id) % 100
# variant = 50: treatment
Deterministic assignment ensures the same user always sees the same variant across sessions and devices. Store the variant assignment in the cart context. The engine uses it to filter promotions with ab_variant set.
Measure conversion lift by comparing checkout rate and average order value between control and treatment groups. Run for at least 2 weeks before concluding results.
Real-Time Recalculation and Simulation
Recalculate the cart total on every modification (item added, quantity changed, coupon applied). The engine should complete in under 50ms for a typical cart. Optimizations: cache the active promotion list, short-circuit evaluation on first failing condition, avoid N+1 DB queries by loading all needed data upfront.
Display original and discounted prices side by side for each item showing the savings. Surface the promotion name so users understand why they got a discount.
Promotion simulation tool for marketing: given a proposed promotion definition, run it against a sample of recent carts to estimate: how many orders it would have applied to, total discount cost, average discount per order. This lets the business validate a promotion before activating it without impacting production traffic.
See also: Scale AI Interview Guide 2026: Data Infrastructure, RLHF Pipelines, and ML Engineering
See also: Shopify Interview Guide
See also: Stripe Interview Guide 2026: Process, Bug Bash Round, and Payment Systems