# Track A Backend Contract — Analytics Event Pipeline Companion to [PRODUCT-PLAN-v3.1-DELIVERY-PLAN.md](../PRODUCT-PLAN-v3.1-DELIVERY-PLAN.md) Track A. Covers plan §3.1, §6.3, §13.3. **Status: ready to build. Start alongside Phase 1, not last** — longest lead time in the programme, and it's a P0 in the plan's own §3.1. No tracking infrastructure exists at all today; this is missing infrastructure, not a missing endpoint. --- ## 1. Event logging spine ```ts interface AnalyticsEvent { eventType: string; // see §2-4 for the fixed vocabulary marketplaceId: string; sessionId: string; customerId?: string; timestamp: string; properties: Record; isSynthetic: boolean; // see §6 - mandatory, never inferred } ``` ``` POST /api/v2/storefront/analytics/events { eventType, properties } -- server-side batched ingest ``` Frontend fires events client-side; backend is the source of truth for `sessionId` and `isSynthetic` — never trust a client-asserted synthetic flag without a matching signed staging/test-environment token. ## 2. Traffic events ``` session_started, page_view, product_view (with source/utm/referrer), unique users/sessions rollups ``` ## 3. Catalog events ``` search, category_view, product_view, seller_view ``` ## 4. Commerce events ``` add_to_cart, cart_view, checkout_started, payment_started, payment_success, payment_failed, order_created ``` These map directly onto the Phase 1/2/6 contracts' own state transitions — emit them from the same backend code paths that already produce `PaymentEvent`/`OrderEvent`, not a separately-maintained tracking layer that can drift. ## 5. Operational + quality metrics ```ts interface OperationalMetric { name: 'order_paid_to_notification_latency' | 'fulfillment_time' | 'connector_lag' | 'payment_webhook_lag'; marketplaceId: string; value: number; unit: 'seconds' | 'minutes'; measuredAt: string; } ``` Quality events: frontend/backend errors, checkout validation failures, FX stale-rate blocks (Phase 1 §3.2). ## 6. Synthetic traffic separation (hard requirement, plan §3.1/§6.3/§10.2) Synthetic/load-test traffic is permitted in staging and demo environments **only**, and must be technically inseparable-by-accident from production data — i.e. `isSynthetic: true` set server-side based on environment/token, never a client-settable flag that a real visit could accidentally or deliberately carry. Business reports must filter it out by construction, not by a manual exclusion query someone has to remember to add. ## 7. Endpoints ``` GET /api/admin/v2/analytics/funnel?marketplaceId=&period= GET /api/admin/v2/analytics/operational?marketplaceId=&metric= GET /api/admin/v2/analytics/quality?marketplaceId= GET /api/v2/storefront/search/trending?marketplaceId= -- top N queries over a recent window, closes the existing SearchTrendingService.loadTrending() stub (returns of(null) today) ``` ## 8. Post-launch monitoring set (plan §13.3, reuses the same event stream) ``` checkout_conversion, payment_success_failure_rate, webhook_processing_lag, order_notification_lag, external_connector_lag, fx_quote_age_errors, unmatched_reconciliation_count, fulfillment_stuck_count ``` ## 9. What the frontend will start doing once this ships - Replace the fully mock-composed `AdminAnalyticsFacade` with real funnel data. - Fire the event vocabulary above from the relevant storefront interaction points. - Bridge or replace the currently-always-zero `AdminProduct.visits` column with real tracking (see `GAPS-AND-IMPROVEMENTS.md`'s admin-product-views item — already partially speced in this session's [admin product views design](../superpowers/plans/2026-08-15-admin-product-views-column.md)). - Wire `SearchTrendingService.loadTrending()` to the real endpoint in §7.