Coupon Schema
A coupon service manages promotional codes that apply discounts to orders. The core schema:
CREATE TABLE coupons (
coupon_id UUID PRIMARY KEY,
code VARCHAR(32) UNIQUE NOT NULL,
type ENUM('percent_off','fixed_amount','free_shipping','bogo') NOT NULL,
value INTEGER, -- pct (0-100) or cents for fixed_amount
currency CHAR(3),
max_uses_total INTEGER, -- NULL = unlimited
max_uses_per_user INTEGER NOT NULL DEFAULT 1,
min_order_value INTEGER, -- cents, NULL = no minimum
applicable_products JSONB, -- NULL = all products
start_date TIMESTAMPTZ,
expires_at TIMESTAMPTZ,
status ENUM('active','paused','exhausted','expired') NOT NULL DEFAULT 'active'
);
CREATE TABLE coupon_redemptions (
redemption_id UUID PRIMARY KEY,
coupon_id UUID NOT NULL REFERENCES coupons(coupon_id),
user_id BIGINT NOT NULL,
order_id VARCHAR(128) NOT NULL,
discount_amount INTEGER NOT NULL, -- actual discount applied in cents
redeemed_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (coupon_id, user_id) -- enforce per-user limit at DB level
);
Code Generation
Coupon codes must be unique, unguessable, and human-friendly. Use base58 encoding (excludes ambiguous characters: 0/O, 1/l/I) to generate random codes:
BASE58_CHARS = "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz"
function generate_code(length=8):
return ''.join(random.choice(BASE58_CHARS) for _ in range(length))
8-character base58 gives 58^8 ≈ 128 trillion combinations. Collision probability is negligible even with millions of codes. Always check for uniqueness via DB unique constraint before returning the code.
For bulk campaign generation (e.g., 100,000 codes for email blast): batch-insert with ON CONFLICT DO NOTHING and retry any collisions. Generating and storing 100K codes takes under a second.
Redemption Validation Steps
Validate in this order before applying any discount:
- Code exists: Look up by code. Return generic “invalid code” error if not found (do not reveal whether code exists).
- Status active: Reject if status is paused, exhausted, or expired.
- Not expired: Check
expires_at > now()andstart_date <= now(). - Global usage limit:
SELECT COUNT(*) FROM coupon_redemptions WHERE coupon_id=?— reject if >=max_uses_total. - Per-user limit: Check
SELECT COUNT(*) FROM coupon_redemptions WHERE coupon_id=? AND user_id=?— reject if >=max_uses_per_user. - Minimum order value: Reject if cart total <
min_order_value. - Applicable products: If
applicable_productsis set, verify at least one cart item is in the eligible list.
Atomic Redemption
Two users applying the same coupon simultaneously can both pass validation and both redeem, exceeding usage limits. Prevent this with atomicity:
Database approach (preferred): Insert into coupon_redemptions with the unique constraint on (coupon_id, user_id). The unique constraint enforces per-user limits at the database level. For global limits, use a database-level counter with an optimistic lock:
BEGIN;
SELECT usage_count FROM coupons WHERE coupon_id=? FOR UPDATE;
-- check usage_count < max_uses_total
INSERT INTO coupon_redemptions (...);
UPDATE coupons SET usage_count = usage_count + 1 WHERE coupon_id=?;
COMMIT;
Redis approach: For high-throughput scenarios, use SETNX coupon:{code}:lock:{user_id} 1 EX 30 to acquire a short-lived lock before the DB transaction. Prevents redundant DB work from concurrent requests.
Discount Application
- percent_off:
discount = order_total * (value / 100.0). Cap at order total. - fixed_amount:
discount = MIN(order_total, value). Cannot exceed order total. - free_shipping: Discount equals the shipping cost line item. Zero if shipping is already free.
- BOGO (Buy One Get One): Identify the cheapest qualifying item in the cart, set its effective price to zero. Requires sorting eligible items by price ascending and zeroing the first one.
Always record the actual discount_amount applied (in cents) in the redemption record, not just the coupon value. The applied discount may differ from the nominal value (e.g., a $20 coupon applied to a $15 order).
Single-Use Codes
Some campaigns require a unique code per recipient (e.g., referral codes, personalized offers). These differ from campaign bulk codes:
- Generated on demand at the time the offer is issued to a specific user.
max_uses_total=1andmax_uses_per_user=1— effectively single-use by any user.- Often pre-linked to a user for attribution, but can be transferred (friend gives code to friend).
Stacking Rules and Analytics
Stacking policy: by default, only one coupon per order. Enforce this by checking for existing coupon on the cart before applying a new one. Some programs allow stacking (e.g., loyalty discount + promotional code) — implement with a stackable flag on the coupon and a stack priority to determine application order.
Coupon performance analytics: track redemption rate (redemptions / codes_distributed), average discount per order, total revenue impact, and fraud signals (same user, multiple accounts). Surface these metrics in an internal dashboard for marketing teams to evaluate campaign effectiveness.
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
See also: Uber Interview Guide 2026: Dispatch Systems, Geospatial Algorithms, and Marketplace Engineering