1. Overview
This document defines the Product Requirements for a secure, tamper-resistant impression tracking system for Learnille’s marketplace. The system tracks course and consultation visibility, enables instructor/consultant analytics, and supports relevance ranking.2. Goals
Primary Goals
- Track true impressions: product actually appears in user viewport
- Maintain tamper-resistant impression signals via HMAC signing
- Provide accurate session-level deduping and per-product metrics
- Support obfuscated endpoints to prevent competitor detection
Secondary Goals
- Enable instructor/consultant dashboards (impressions, CTR, referrers)
- Support ML/relevance ranking via impression data
- Allow anti-fraud heuristics (velocity, bot detection)
3. Non-Goals
- No external analytics vendor integration
- No third-party fingerprinting SDK
- No cookie consent requirements (privacy-first approach)
- No real-time streaming infrastructure at initial stage
4. Architecture Overview
Initial Phase
Future Upgrade Path
- TimescaleDB: Convert
impressionstable to a hypertable for efficient time-series partitioning and faster aggregation queries (e.g.,time_bucket).
5. Client-Side Requirements
5.1 Impression Trigger
Use browserIntersectionObserver to record an impression only when:
- Product card enters viewport
- Remains visible ≥ 150ms
- Impression for (entity_id + session_id) has not been fired this session
5.2 Required Client Fields
5.3 Legitimacy Verification (Handshake)
To ensure requests are absolutely legitimate and “authorized” by the server without user login: 1. Handshake Phase- Client calls
GET /api/v1/beacon/h. - Server verifies client (IP reputation, standard headers).
- Server returns a Signed Session Token (JWT-like) containing:
session_idissued_atexpiry(e.g., 2 hours)
- Token is signed with
BEACON_PRIVATE_KEY.
BEACON_SESSION_SECRETis derived from the session token or a shared secret.- Server verifies both the Session Token signature and the Impression HMAC.
- The client was initialized by our server.
- The payload hasn’t been tampered with.
- Replay attacks are impossible (even if signature is stolen, it’s tied to an expired token).
5.4 Payload Obfuscation
All fields use short codes to obscure intent:
Entity types use codes:
c=course, n=consultation, i=instructor, o=consultant
6. Session Requirements
6.1 Browser Session ID
- Stored in
sessionStorage(not cookies) - Value: UUIDv4
- Expires when tab closes
- Key:
bkn_sid
6.2 Deduplication
- Track fired impressions in
sessionStorage - Key format:
bkn:{entity_type}:{entity_id} - Prevents duplicate tracking per session
6.3 Device Fingerprint
Minimal fingerprint using:- User agent
- Screen resolution
- Timezone offset
- Language
SHA256(ua + screen + tz + lang).substring(0, 16)
6.4 Client-Side Batching
To improve performance and reduce server load:- Queue: Store impressions in a memory queue.
- Flush Triggers:
- Time: Every 2 seconds.
- Size: Every 10 queued items.
- Event:
pagehide/beforeunload(usingnavigator.sendBeacon).
- Format: Batch array sent to single endpoint.
7. Server Endpoint Specification
7.1 HTTP (Handshake)
{ "token": "signed.session.token", "key": "temporary-signing-key" }
7.2 HTTP (Batch)
7.3 HTTP (Pixel Fallback)
(Unchanged: Single request viapx.gif)
8. Attribution (“The Golden Thread”)
To track conversion value back to impressions:8.1 Search Session Correlation
- Generate
search_session_idon search execution. - Store
search_session_idinsessionStoragefor persistence across the search results page. - Pass
search_session_idto:- Impression payload (
ssfield). - Product URL (query param
?sid=...).
- Impression payload (
8.2 Checkout Association
- The
useBeaconhook capturessidfrom the URL on product detail pages and saves it tosessionStorage(key:search_session_id). - On
Ordercreation, the frontend sends thissearch_session_idto the backend. - The
Orderentity persistssearchSessionId. - Analytics: Join
orderstable withimpressionsviasearch_session_idto calculate “Revenue per Search” and “Conversion Rate by Rank”.
9. Dedupe Logic
8.1 Client-Side Dedupe
Per session, per entity:8.2 Server-Side Dedupe
Redis-based with 1-hour TTL:SET NX (set-if-not-exists) for atomic deduplication.
9. Database Schema
impressions
Metadata JSONB
Stores owner IDs for filtering:10. Analytics Queries
Impressions by Period
CTR Calculation
Instructor Dashboard
11. Fraud & Abuse Detection
Early Indicators
Future Upgrades
- Browser behavior scoring
- ML-based anomaly detection
- Scroll velocity analysis
12. Operational Requirements
12.1 Performance
- API handles ≥500 req/sec
- ≤15ms average response time
- Redis for hot-path operations
12.2 Security
- Rotate BEACON_SECRET every 90 days
- Enforce TLS
- Limit body size to 4KB
- Rate-limit by IP/session
12.3 Monitoring
- Track rejection rate by reason
- Alert on >5% signature failures
- Log suspicious patterns
13. Client SDK Requirements
useBeacon Hook
beacon Function
- Generate/maintain session ID
- Sign events with HMAC
- Fallback to pixel if fetch blocked
- Batch send (via BeaconQueue)
14. Success Metrics
15. Environment Variables
16. File Structure
17. Implementation Phases
Phase 1: Core (Week 1)
- BeaconController with endpoints
- BeaconGuard with HMAC validation
- Frontend beacon.ts service
- useBeacon hook
- Integration on course/consultation pages
Phase 2: Security (Week 2)
- Timestamp validation
- Nonce tracking in Redis
- Rate limiting
- Behavioral detection
Phase 3: Analytics (Week 3)
- Dashboard API endpoints
- Aggregation queries
- Instructor/consultant views
18. Open Questions
- Should we track scroll depth for engagement scoring?
- Should impressions be versioned for ranking model training?
- Should we implement A/B testing for different CTR thresholds?
19. Next Steps
- ✅ Approve PRD
- Generate API contract
- Generate NestJS implementation
- Generate JS client SDK
- Deploy MVP
- Add monitoring & alerts