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.
{
“@context”: “https://schema.org”,
“@type”: “FAQPage”,
“mainEntity”: [
{
“@type”: “Question”,
“name”: “How is atomic coupon redemption implemented to prevent double-use?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “Redemption uses an atomic conditional update — UPDATE coupons SET status='redeemed', redeemed_by=?, redeemed_at=NOW() WHERE code=? AND status='active' — and checks that exactly one row was affected; if zero rows are affected the coupon is already redeemed or invalid. For Redis-backed implementations, a Lua script performs the check-and-set atomically within a single server-side execution, preventing race conditions under concurrent redemption attempts.”
}
},
{
“@type”: “Question”,
“name”: “How are per-user usage limits enforced concurrently?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “A Redis counter keyed by coupon_id:user_id is incremented with INCR and compared against the limit in a Lua script before the redemption record is written; the counter is set with an expiry aligned to the coupon's validity window so it auto-cleans. Alternatively, a database-level unique partial index on (coupon_id, user_id) where usage_count < limit enforces the constraint durably without a separate counter."
}
},
{
"@type": "Question",
"name": "How are bulk single-use coupon codes generated?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Codes are generated as cryptographically random byte sequences (e.g., 12 bytes from CSPRNG) encoded to a URL-safe Base32 or alphanumeric string, ensuring global uniqueness without coordination; they are bulk-inserted into the database in batches with a unique index on the code column to catch the astronomically rare collision. A checksum character appended to each code lets point-of-sale systems detect transcription errors before a round trip to the server."
}
},
{
"@type": "Question",
"name": "How is coupon fraud detected?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Anomaly detection rules flag patterns such as a single account redeeming many unique single-use codes in a short window, geographically dispersed redemptions for codes that should have been distributed to a specific region, or velocity spikes in redemption rate for a campaign. Flagged events are queued for review and the associated accounts or codes can be soft-blocked pending investigation without immediately impacting legitimate users."
}
}
]
}
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