Design Coupon Management System
Design a coupon generation system. System will allow users to create discount coupons, manage these coupons. Also, system should be able to validate the coupons.
FR
1. System will allow users to create discount coupons, manage these coupons.
2. User should be able to search coupons
3. System should be able to validate the coupons.
4. Same coupon should not be redeemed multiple times
5. System should focus on managing the coupon.
6. Once a user gets a coupon he/she has to buy something on the website with in 5 mins.
NFR
1. System should have high availability for searching & viewing coupons,
2. Strong consistency for getting coupons (only one user should get a coupon)
3. Ensure low latency while searching
4. system is read heavy, and thus needs to be able to support high read throughput (100:1)
5. system should be scalable and able to handle high throughput in the form of popular coupon
(for instance 10M users for 10k coupons)
Eventual consistent for appearing of coupons after publish across globe
Estimates
Assume the website has 100M active users.
DAU=10% of 100M=10M
Assume 1% of active users (10,0000 users) create new coupons each day.
each user creates 5 coupons per session.
Total coupons generated per day = 10,0000 * 5 = 50,0000 coupons.
Coupon Redemption
Assume 10% of active users (10 M) try to use coupons daily.
The average number of coupon redemption attempts per user per day is 2.
Total coupon validation requests per day = 10 million * 2 = 20 million validations.
For Search
Assume 10% of active users (10M) search for coupons daily.
The average number of search requests per user is 3.
Total search requests per day = 10M* 3 = 30M seacrhes per day
QPS= 30M/10^5=300 qps
Total storage for coupons=500k*200bytes(for coupon metadat)=100GB
API’s
1.POST /api/v1/coupons/create
Allows admins to create a new coupon.
request{
"code": "SAVE20",
"discount_type": "PERCENTAGE", // or "FIXED"
"discount_value": 20,
"max_discount_amount": 100,
"min_order_amount": 500,
"expiration_time": "2024-12-01T23:59:59Z",
"usage_limit": 100,
"target_user_ids": ["user123", "user456"]
}
response
response
{
"coupon_id": "123456",
"message": "Coupon created successfully"
}
2.PUT /api/coupons/{couponId}
update coupon
request
{
"discount_value": 25,
"expiration_time": "2024-12-31T23:59:59Z",
"usage_limit": 150
}
response
{
"message": "Coupon updated successfully"
}
3.Other crud api's
DELETE /api/v1/coupons/{couponId}
4. POST /api/coupons/validate
Validates if the coupon is valid for a given user and order.
request
{
"user_id": "user123",
"coupon_code": "SAVE20",
"order_amount": 750
}
response
{
"valid": true,
"discount_amount": 20,
"final_price": 730
}
5. POST /api/coupons/redeem
Marks a coupon as redeemed for a specific user and order.
request
{
"user_id": "user123",
"coupon_code": "SAVE20",
"order_id": "order789"
}
response
{
"message": "Coupon redeemed successfully",
"discount_amount": 20
}
GET /api/v1/coupons/search
Allows users to search for available coupons based on criteria.
[ { "coupon_id": "123456", "code": "SAVE20", "discount_type": "PERCENTAGE", "discount_value": 20, "expiration_time": "2024-12-01T23:59:59Z", "usage_limit": 100 } ]
7.GET /api/coupons/{couponId}
{ "coupon_id": "123456", "code": "SAVE20", "discount_type": "PERCENTAGE", "discount_value": 20, "max_discount_amount": 100, "min_order_amount": 500, "expiration_time": "2024-12-01T23:59:59Z", "usage_limit": 100, "usage_count": 45 }
8.GET /api/users/{userId}/coupons
fetches list of coupons to be redeemed by user
[ { "coupon_code": "SAVE20", "redeemed_on": "2024-11-01T10:30:00Z", "order_id": "order789", "discount_amount": 20 } ]
DataBase Schema
User Table
id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id VARCHAR(100) UNIQUE, email VARCHAR(255), name VARCHAR(100), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
Coupons Table
{ id BIGINT AUTO_INCREMENT PRIMARY KEY, code VARCHAR(50) UNIQUE NOT NULL, discount_type ENUM('PERCENTAGE', 'FIXED') NOT NULL, discount_value DECIMAL(10, 2) NOT NULL, max_discount_amount DECIMAL(10, 2), min_order_amount DECIMAL(10, 2), usage_limit INT DEFAULT 1, -- Max times this coupon can be used usage_count INT DEFAULT 0, -- Times this coupon has been used is_active BOOLEAN DEFAULT TRUE, expiration_time TIMESTAMP, created_by VARCHAR(100), -- Admin who created the coupon coupon_url created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX (code), INDEX (expiration_time) }
User Coupon Table
Tracks which users have claimed specific coupons, ensuring that each coupon is only used once per user (if required). User_Coupons { id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id VARCHAR(100) NOT NULL, coupon_id BIGINT NOT NULL, redeemed BOOLEAN DEFAULT FALSE, redeemed_on TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE (user_id, coupon_id), -- Ensures a user can only use a coupon once FOREIGN KEY (user_id) REFERENCES Users(user_id), FOREIGN KEY (coupon_id) REFERENCES Coupons(id) }
Orders Table
Orders { id BIGINT AUTO_INCREMENT PRIMARY KEY, order_id VARCHAR(100) UNIQUE NOT NULL, user_id VARCHAR(100) NOT NULL, coupon_id BIGINT, order_amount DECIMAL(10, 2) NOT NULL, discount_amount DECIMAL(10, 2) DEFAULT 0, final_price DECIMAL(10, 2) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES Users(user_id), FOREIGN KEY (coupon_id) REFERENCES Coupons(id) }
Coupon_Redemption_Log_table
Coupon_Redemption_Log { id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id VARCHAR(100) NOT NULL, coupon_code VARCHAR(50) NOT NULL, order_id VARCHAR(100), status ENUM('SUCCESS', 'FAILED') NOT NULL, failure_reason VARCHAR(255), redeemed_on TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES Users(user_id) }
Indexes
Coupons Table: Index on code for quick lookups, and expiration_time to efficiently remove expired coupons. User_Coupons Table: Unique constraint on (user_id, coupon_id) to ensure users can’t redeem the same coupon multiple times. Orders Table: Index on user_id for retrieving user order history. Coupon_Redemption_Log Table: Index on coupon_code and user_id for analytics.
Relationships Between Tables
1. The Coupons table holds information about each coupon, while the 2.User_Coupons table links coupons to users who have claimed them. 3.The Orders table tracks orders where a coupon was applied. 4.The Coupon_Redemption_Log table records every redemption attempt for auditing purposes.