Coupon Management System: System Design Interview

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.
One user should get single coupn per day. Once a user gets a coupon he/she has to buy something on the website with in 5 mins otherwise coupon will be availbale for other user. coupons should not redeemed multiple times. System should focus on managing the coupons.

----------Functional Requirements:----------
1. Admin should be able to create 100k coupons daily.
2. User should be able to search coupons
3. User should be able to get coupon and redeem it.
4. One user should get single coupn per day.
5. Once a user gets a coupon he/she has to buy something on the website with in 5 mins.
6. If user did not use coupon 5 in minute then coupon will be availbale for other user.
7. System should be able to validate the coupons(user can not be redeemed multiple times same coupon)

----------Non-Functional Requirements:----------
1. The system should have high availability for searching & viewing coupons, but should consistence for getting coupons (only one user should get a coupon)
2. The system should have low latency search
3. The system should be scalable and able to handle high throughput in the form of popular coupons(10M users for 100k coupons)
4. The system is read heavy, and thus needs to be able to support high read throughput (100:1)

----------Core Entities----------
1. Coupon: This Entity store essential information about a coupon, including details like the date, description, type. It acts as the central point of information for each unique coupon.
2. Redeem: Represents the essential information about redeem.
3. User: Represents the individual interacting with the system.

----------API----------

1. Create Coupon POST:/coupons -> couponId
header: JWT | SessionToken
{
"couponId": string,
"category": string,
"description": string,
"date": date,
"type": string,
}

2. Search Coupon GET:/coupons/search?search_term={search_term}&type={type}
header: JWT | SessionToken

3. Get(Bocked) Coupon POST:/coupons/locked/couponId -> Coupon
header: JWT | SessionToken

4. Redeem Coupon POST:/coupons/redeem/couponId
header: JWT | SessionToken

High-Level Design
1. Admin can create coupon using POST:/coupons api it will return success or fail. Coupon Generation Service will handle the request and it will create coupon based on the request body and save it into the Database.
2. User can search a coupon based on the some seach term or coupon type. Search Service will handle this request. It will search coupon in Database directly and return results to the user. Note: This search will be slow because we needs to scan entire database.
3. Once coupon is presented to user on broser or mobile app user can select coupon, then user will get the couponid or coupon code. In the database status of coupon will be locaked so than no other user can get that coupon.
4. User has to redeem coupon in 5 mins, if coupon will not redeemed then it has to put it back to available state in database so that other user can use it.

image

Deep Dives

Note: If we observe closely then we noticed that if user is not remmeding coupon then in that case coupon will be permanent in locked state. it stuck in the locked state.
how to deal with this.
Solution 1. We can keep one more column in Coupons table lockedTimestamp. When we run a query for availabe coupon then check if lockedTimestamp is more than 5 mins or not. If it is more than 5 mins the it will be return to the users as a availbale coupon.
image

But it looks not good, the state of coupon is saying, it is locked but in reality it is not. This is also not constent.

Solution 2. We can run a cron job which will run every 5 mins and it will check lockedTimestamp of each coupons. if it is more than 5 mins then it will update status to available .
image

Here we again have one issue. If we look closely then we find coupon might be locked for more than 5 mins. Lets consider a cron job finshed at 12:05 and a coupon got locked at 12:06. When crom job will run at 12:10, the time duration for locked coupn will be 4 mins, so it will be not put back to availabale state. next cron job will run at 12:15. So total locked time for coupon is 9 mins. which is not great.
What next?

Solution 3. We can use redis as a locking system with TTL 5 mins and remove locked state and lockedTimestamp column from Coupon table. Redis is single thread database.
image

When a user search for available coupon Search Service get all available coupons and it will also get all the locked coupons from redis and filter out locked coupons from available coupons and return to the coupons.

Optimised Coupon Search Service
image

Comments (6)