Functional Requirements:
Non-Functional Requirements:
1. Ingest a Product View POST /v1/views
JSON
{
"user_id": "uuid-1234",
"product_id": "prod-9876",
"category_id": "cat-elec",
"timestamp": "2026-03-08T15:00:00Z"
}
Returns: 202 Accepted. This is a fire-and-forget endpoint. The client does not wait for the aggregation to complete.
2. Get Trending Products (Filtered) GET /v1/trending?category=cat-elec&window=24h&limit=10 Returns: 200 OKwith an ordered array of product IDs and their view counts.
3. Get Co-Viewed Products GET /v1/products/{product_id}/co-viewed Returns: 200 OK with an array of related product IDs.
ORDER BY bottlenecks on the read path.Here is the mechanics of the Flink to Redis pipeline.
1. Stream Aggregation (Apache Flink) Flink consumes the raw_product_views Kafka topic and splits the stream into two parallel jobs:
product_id. When the window slides, Flink emits an upsert event: (product-9876, 24h_views: 1500, category: cat-elec).user_id using a Session Window (closing after 30 minutes of inactivity). When the session closes, Flink looks at all products viewed, generates pairs (e.g., [prod-A, prod-B]), and increments a co-view counter for that specific pair.2. The Read/Sort Bottleneck Resolution If we wrote Job A's output to an RDBMS (PostgreSQL), the API would have to execute: SELECT product_id FROM views WHERE category = 'cat-elec' ORDER BY views_24h DESC LIMIT 10. At thousands of queries per second, this dynamic sorting is highly CPU-intensive and slow.
O(log(N) + M) operation that takes less than a millisecond