FR
Users should be able to subscribe to a product for periodic deliveries (e.g., weekly, monthly).
Users should be able to modify subscription frequency.
Users should be able to pause, resume, or cancel subscriptions anytime.
Support multiple active subscriptions per user.
Apply discounts based on subscription frequency and quantity.
Handle price fluctuations (e.g., notify users of price changes before the next delivery).
Notify users when a product goes out of stock.
Provide alternative product recommendations if a subscribed item is unavailable.
Automatically charge users before each scheduled delivery.
Generate subscription orders based on user-defined frequency.
Provide users with insights on savings from subscriptions.
NFR
1.System should be highly scalable to handle millions of subscriptions without performance degradation.
2.System should have low latency for subscription modifications (create, update, cancel) should be processed within < 200m
3.System should be highly available to ensure 99.99% uptime to avoid disruptions in recurring order processing.
4.System should maintain strong consistency for subscription updates (e.g., pausing, resuming, canceling).
Back of Envelope Calculation
Total active users: 100M (Amazon scale)
Percentage of users using "Subscribe & Save": 10% → 10M users
Average subscriptions per user: 3
Total active subscriptions: 10M × 3 = 30M subscriptions
Daily scheduled orders: 5% of active subscriptions trigger daily
30M × 5% = 150/100=1.5M=1.5 *10^6=15 *10^5=1500k
QPS=1500k/10^5=15 QPS
1500k*100=150MB for each day
Peak load multiplier: 3x (during flash sales, holidays)
Peak load: 45 QPS
Storage estimation
30M subscriptions × 100bytes = 3GB
for daily data collections
1500k*100=150MB for each day *30=4500MB=4.5GB
API’s
POST /api/v1/subscriptions
request {
"user_id": "12345",
"product_id": "P98765",
"frequency": "monthly",
"start_date": "2025-04-01",
"payment_method_id": "PM123",
"quantity":
"address_id": "ADDR567",
"discount_code": "SUB10"
}
response {
"subscription_id": "SUB123",
"status": "active",
"next_order_date": "2025-04-01"
}
2.GET /api/v1/users/{user_id}/subscriptions
[
{
"subscription_id": "SUB123",
"product_id": "P98765",
"status": "active",
"frequency": "monthly",
"next_order_date": "2025-04-01"
}
]
3.PATCH /api/v1/subscriptions/{subscription_id}
request {
"status": "paused"
}
response {
"subscription_id": "SUB123",
"status": "paused"
}
4.DELETE /api/v1/subscriptions/{subscription_id}
{
"subscription_id": "SUB123",
"status": "canceled"
}
5.GET /api/v1/users/{user_id}/orders/upcoming
[
{
"order_id": "ORD456",
"subscription_id": "SUB123",
"product_id": "P98765",
"delivery_date": "2025-04-02",
"status": "scheduled"
}
]
6.GET /api/v1/users/{user_id}/orders/history?limit=10
[
{
"order_id": "ORD456",
"product_id": "P98765",
"status": "delivered",
"total_amount": 15.99,
"delivery_date": "2025-03-01"
}
]
7.POST /api/v1/subscriptions/{subscription_id}/skip-next
{
"message": "Next order skipped successfully",
"next_order_date": "2025-05-01"
}
8.POST /api/v1/payments/process
request {
"user_id": "12345",
"subscription_id": "SUB123",
"amount": 15.99,
"payment_method_id": "PM123"
}
response {
"transaction_id": "TXN789",
"status": "success",
"charged_amount": 15.99
}
9.POST /api/v1/payments/retry
request {
"transaction_id": "TXN456"
}
response {
"transaction_id": "TXN789",
"status": "success"
}
10.GET /api/v1/users/{user_id}/payments/history
[
{
"transaction_id": "TXN123",
"amount": 15.99,
"status": "success",
"date": "2025-03-01"
}
]
11.POST /api/v1/admin/products
requwst {
"product_id": "P98765",
"name": "Organic Coffee",
"price": 15.99,
"subscription_discount": 10
}
response {
"message": "Product added successfully"
}
Databases
📌 1. Relational Database (SQL) - MySQL/PostgreSQL
Tables for structured data (OLTP use cases like transactions, payments)
Users Table
CREATE TABLE users (
user_id UUID PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(255) UNIQUE,
phone VARCHAR(20),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Subscriptions Table
CREATE TABLE subscriptions (
subscription_id UUID PRIMARY KEY,
user_id UUID REFERENCES users(user_id),
product_id UUID,
frequency ENUM('daily', 'weekly', 'monthly'),
start_date DATE,
next_order_date DATE,
status ENUM('active', 'paused', 'canceled'),
payment_method_id UUID,
address_id UUID,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Orders Table
CREATE TABLE orders (
order_id UUID PRIMARY KEY,
subscription_id UUID REFERENCES subscriptions(subscription_id),
user_id UUID REFERENCES users(user_id),
product_id UUID,
status ENUM('scheduled', 'processing', 'shipped', 'delivered'),
total_amount DECIMAL(10,2),
payment_status ENUM('pending', 'successful', 'failed'),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Payments Table
CREATE TABLE payments (
transaction_id UUID PRIMARY KEY,
user_id UUID REFERENCES users(user_id),
subscription_id UUID REFERENCES subscriptions(subscription_id),
amount DECIMAL(10,2),
status ENUM('successful', 'failed', 'pending'),
payment_method VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
📌 2. NoSQL Database (MongoDB) - Flexible Subscription Metadata
Use case: Storing user subscription preferences and flexible metadata.
Subscription Document
{
"_id": "SUB123",
"user_id": "12345",
"product_id": "P98765",
"frequency": "monthly",
"start_date": "2025-04-01",
"next_order_date": "2025-05-01",
"status": "active",
"preferences": {
"delivery_time": "morning",
"gift_wrap": true
}
}
Order Document
{
"_id": "ORD567",
"subscription_id": "SUB123",
"user_id": "12345",
"product_id": "P98765",
"status": "shipped",
"total_amount": 15.99,
"tracking_info": {
"carrier": "UPS",
"tracking_number": "1Z999AA10123456784"
}
}
📌 3. Key-Value Store (Redis/DynamoDB)
Use case: Fast retrieval of frequently accessed subscription statuses.
Storing Active Subscriptions (Redis)
Key:
subscription:SUB123
Value:
{ "user_id": "12345", "product_id": "P98765", "next_order_date": "2025-05-01", "status": "active" }
📌 5. Time-Series Database (InfluxDB/TimescaleDB)
Use case: Storing subscription trends & tracking user activity.
Schema for Tracking Subscription Renewals
CREATE TABLE subscription_activity (
user_id UUID,
subscription_id UUID,
event_type TEXT, -- ('renewed', 'skipped', 'canceled')
event_time TIMESTAMPTZ DEFAULT now(),
PRIMARY KEY (subscription_id, event_time)
);
📌 6. Search Engine (Elasticsearch)
Use case: Fast searching/filtering subscriptions & order history.
Indexing Subscription Data
{
"subscription_id": "SUB123",
"user_id": "12345",
"product_id": "P98765",
"frequency": "monthly",
"next_order_date": "2025-05-01",
"status": "active"
}
Query to Search Active Subscriptions
{
"query": {
"match": {
"status": "active"
}
}
}
HLD