📌 Description
We need to implement a scalable analytics pipeline to track video engagement events, starting with a watched_50_percent event.
The goal is to:
-
Detect when a user watches >50% of a video (single-shot)
-
Send analytics event from frontend to backend
-
Queue event in Redis
-
Process asynchronously via worker
-
Persist raw events in DB
-
Maintain aggregated metrics for admin analytics page
This should follow an event-driven architecture to ensure scalability and minimal API latency impact.
🏗 High-Level Architecture
Frontend
↓
POST /analytics (Fastify)
↓
Redis queue (queue:analytics)
↓
analytics-worker (background consumer)
↓
Persist to DB (video_events)
↓
Update aggregate table (video_metrics)
✅ Scope of Work
🔹 Frontend
1. video-player.tsx
-
Add required videoId prop.
-
Implement single-shot detection when playback crosses >50%.
-
Send POST request to analytics endpoint.
Payload:
{
"videoId": "string",
"event": "watched_50_percent",
"ts": 1234567890,
"userId": "string"
}
- Ensure event fires only once per playback session.
2. page.tsx
- Pass page-level
videoId into VideoPlayer.
3. video-feed-card.tsx
- Pass
video.videoId into VideoPlayer for inline previews.
4. Auth / Session Helper
🔹 Backend (PulseVault - Fastify)
1. routes/analytics.js
Add:
Responsibilities:
-
Validate payload fields:
-
Accept only supported event types (watched_50_percent)
-
Push event into Redis queue:
-
Implement deduplication key in Redis:
🔹 Worker
workers/analytics-worker.js (NEW)
Responsibilities:
-
Consume from queue:analytics (BLPOP or Redis Streams).
-
Persist raw event into video_events table.
-
Increment aggregate counter in video_metrics.
Should run independently (Docker service can be added later if needed).
🔹 Database (Prisma / Migrations)
Add table: video_events
Column | Type -- | -- id | UUID video_id | string event | string user_id | string ts | timestamp created_at | timestamp
📊 Admin Analytics
Future endpoint:
Should return videos sorted by highest watched_50_count.
🔐 Deduplication Strategy
To prevent double-counting:
Redis key format:
dedupe:video:{videoId}:user:{userId}:watched50
Use:
If key already exists → ignore event.
📚 Documentation
Update README.md with:
🧪 Tests (Optional but Recommended)
🎯 Acceptance Criteria
-
50% watch event fires only once per session.
-
Backend validates and queues analytics event.
-
Worker persists raw event.
-
Aggregate count increments correctly.
-
No noticeable latency added to video playback.
-
Deduplication prevents duplicate counting.
📌 Description
We need to implement a scalable analytics pipeline to track video engagement events, starting with a
watched_50_percentevent.The goal is to:
Detect when a user watches >50% of a video (single-shot)
Send analytics event from frontend to backend
Queue event in Redis
Process asynchronously via worker
Persist raw events in DB
Maintain aggregated metrics for admin analytics page
This should follow an event-driven architecture to ensure scalability and minimal API latency impact.
🏗 High-Level Architecture
✅ Scope of Work
🔹 Frontend
1.
video-player.tsxAdd required
videoIdprop.Implement single-shot detection when playback crosses >50%.
Send POST request to analytics endpoint.
Payload:
2.
page.tsxvideoIdintoVideoPlayer.3.
video-feed-card.tsxvideo.videoIdintoVideoPlayerfor inline previews.4. Auth / Session Helper
Ensure stable
clientIdoruserIdexists:Logged-in users → use
userIdAnonymous → generate UUID and persist in
localStorage🔹 Backend (PulseVault - Fastify)
1.
routes/analytics.jsAdd:
Responsibilities:
Validate payload fields:
videoIdeventtsuserIdAccept only supported event types (
watched_50_percent)Push event into Redis queue:
queue:analyticsImplement deduplication key in Redis:
dedupe:video:{videoId}:user:{userId}:watched50Use
SET NX EXpattern🔹 Worker
workers/analytics-worker.js(NEW)Responsibilities:
Consume from
queue:analytics(BLPOP or Redis Streams).Persist raw event into
video_eventstable.Increment aggregate counter in
video_metrics.Should run independently (Docker service can be added later if needed).
🔹 Database (Prisma / Migrations)
Add table:
video_eventsColumn | Type -- | -- id | UUID video_id | string event | string user_id | string ts | timestamp created_at | timestamp
📊 Admin Analytics
Future endpoint:
Should return videos sorted by highest
watched_50_count.🔐 Deduplication Strategy
To prevent double-counting:
Redis key format:
Use:
If key already exists → ignore event.
📚 Documentation
Update
README.mdwith:Analytics endpoint description
Redis key structure
Worker behavior
Event schema
🧪 Tests (Optional but Recommended)
POST
/analytics→ assert Redis queue entry.Assert dedupe behavior.
Worker test → ensure DB insert and aggregate increment.
🎯 Acceptance Criteria
50% watch event fires only once per session.
Backend validates and queues analytics event.
Worker persists raw event.
Aggregate count increments correctly.
No noticeable latency added to video playback.
Deduplication prevents duplicate counting.