-
Notifications
You must be signed in to change notification settings - Fork 9
Add analytics page telemetry + QA data correctness runbook #244
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| from pathlib import Path | ||
|
|
||
| from core.analytics import EVENT_TAXONOMY | ||
|
|
||
|
|
||
| def test_analytics_dashboard_controller_tracks_v1_analytics_events(): | ||
| controller_path = Path(__file__).resolve().parents[2] / "frontend" / "src" / "controllers" / "analytics_dashboard_controller.js" | ||
| source = controller_path.read_text(encoding="utf-8") | ||
|
|
||
| assert "window.posthog.capture" in source | ||
| assert '"analytics_page_viewed"' in source | ||
| assert '"analytics_date_range_changed"' in source | ||
| assert '"analytics_refresh_clicked"' in source | ||
| assert '"analytics_source_error_shown"' in source | ||
| assert "project_id" in source | ||
| assert "date_range_start" in source | ||
| assert "date_range_end" in source | ||
| assert "range_days" in source | ||
|
Comment on lines
+1
to
+18
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The test verifies that event-name strings and a few property names appear somewhere in the controller source file. This means it would pass even if those strings existed in comments, and it would not catch:
Because these are the behaviours that matter for PostHog data quality (the whole point of this PR), consider adding at least one JS unit test (e.g. with Vitest/Jest) that mounts the controller with a stub |
||
|
|
||
| assert source.index("this.captureDateRangeChangedIfNeeded({") < source.index( | ||
| 'this.captureEvent("analytics_refresh_clicked", {' | ||
| ) | ||
| assert "if (end.getTime() < start.getTime())" in source | ||
|
|
||
|
|
||
| def test_analytics_source_error_event_requires_source_status_property(): | ||
| required_properties = EVENT_TAXONOMY["events"]["analytics_source_error_shown"]["required_properties"] | ||
| assert "source_status" in required_properties | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| # Analytics page v1: QA data-correctness checklist + production troubleshooting | ||
|
|
||
| ## Scope | ||
|
|
||
| This checklist validates the v1 Analytics page (`/project/<id>/analytics/`) end-to-end: | ||
|
|
||
| - API payload correctness (`/api/projects/<id>/analytics/aggregation`) | ||
| - UI rendering correctness (KPIs, source health, trend, breakdowns) | ||
| - telemetry reliability for interaction/error signals: | ||
| - `analytics_page_viewed` | ||
| - `analytics_date_range_changed` | ||
| - `analytics_refresh_clicked` | ||
| - `analytics_source_error_shown` | ||
|
|
||
| ## QA checklist (pre-ship + regression) | ||
|
|
||
| ### 1) Access and baseline shell | ||
|
|
||
| - [ ] Logged-out user is redirected to login. | ||
| - [ ] Logged-in user cannot open another user's project analytics page (404). | ||
| - [ ] Owner sees all expected sections: Overview KPIs, Sessions trend, Source state, Source breakdown, Top pages. | ||
|
|
||
| ### 2) Date range controls + query behavior | ||
|
|
||
| - [ ] Default load uses Last 30d and a valid inclusive date window. | ||
| - [ ] Last 7d and Last 90d presets update both date inputs correctly. | ||
| - [ ] Custom start/end + Refresh returns data for the exact selected range. | ||
| - [ ] Validation error appears when either start/end is missing. | ||
|
|
||
| ### 3) Data correctness cross-checks | ||
|
|
||
| Run API and compare to rendered UI values for the same date range: | ||
|
|
||
| ```bash | ||
| curl -sS "http://localhost:8000/api/projects/<PROJECT_ID>/analytics/aggregation?start_date=YYYY-MM-DD&end_date=YYYY-MM-DD" \ | ||
| -H "Cookie: sessionid=<SESSION>" | ||
| ``` | ||
|
|
||
| - [ ] KPI totals match API `overview` (`clicks`, `impressions`, `sessions`, `users`, `conversions`). | ||
| - [ ] CTR and conversion rate match API percent fields (2 decimal places). | ||
| - [ ] Source breakdown table rows map 1:1 to API `source_breakdown` rows. | ||
| - [ ] Trend bars presence/empty-state follows API `daily_trend` content. | ||
| - [ ] Top pages table matches API `page_breakdown` ordering and values. | ||
|
|
||
| ### 4) Partial/missing integration behavior | ||
|
|
||
| - [ ] Missing integration shows `Missing` badge and explanatory copy. | ||
| - [ ] Connected but stale integration shows `Stale` badge. | ||
| - [ ] Connected with healthy sync metadata shows `Connected` badge. | ||
| - [ ] Page does not crash when only one provider has data. | ||
|
|
||
| ### 5) Telemetry correctness (PostHog) | ||
|
|
||
| Open PostHog Live Events (project 105300) and verify properties are attached. | ||
|
|
||
| - [ ] Page load emits `analytics_page_viewed` once with: `project_id`, `date_range_start`, `date_range_end`, `range_days`. | ||
| - [ ] Preset switch emits `analytics_date_range_changed` with `change_source=preset_click`. | ||
| - [ ] Custom date change + Refresh emits `analytics_date_range_changed` with `change_source=custom_date_refresh`. | ||
| - [ ] Refresh click emits `analytics_refresh_clicked`. | ||
| - [ ] API/source error surfaced in UI emits `analytics_source_error_shown` with `source`, `error_message`, `result_status=shown`. | ||
|
|
||
| ## Production troubleshooting notes | ||
|
|
||
| ### Symptom: Analytics page appears empty | ||
|
|
||
| 1. Check source health card: | ||
| - `Missing` => integration not connected. | ||
| - `Stale` + error detail => provider sync issue. | ||
| 2. Inspect latest sync cursor rows for the project in admin (`AnalyticsSyncCursor`). | ||
| 3. Confirm ingestion snapshots exist (`AnalyticsSourceSnapshot`) and are recent. | ||
| 4. Verify date range isn't excluding known data window. | ||
|
|
||
| ### Symptom: KPI mismatch vs expected provider dashboard | ||
|
|
||
| 1. Call aggregation API directly for same date range and compare to UI. | ||
| 2. Confirm canonical metric ownership assumptions: | ||
| - clicks/impressions from search scope | ||
| - sessions/users/conversions from traffic scope | ||
| 3. Check for stale provider cursor and last sync errors. | ||
| 4. Validate timezone/date-boundary assumptions (inclusive day counts). | ||
|
|
||
| ### Symptom: Repeated error toasts/messages | ||
|
|
||
| 1. Inspect browser network call to aggregation endpoint and response status. | ||
| 2. Use PostHog event `analytics_source_error_shown` to identify: | ||
| - `source` (`dashboard_api` or provider from source health) | ||
| - `source_status` | ||
| - `error_message` | ||
| 3. If provider errors repeat, run/inspect provider sync task logs and retry after fixing upstream credentials/rate limits. | ||
|
|
||
| ## Operational note | ||
|
|
||
| When changing Analytics page event names or required properties, update in the same PR: | ||
|
|
||
| 1. `core/analytics/event_taxonomy.json` | ||
| 2. `frontend/src/controllers/analytics_dashboard_controller.js` | ||
| 3. event docs (`docs/posthog-event-coverage-matrix.md`, this checklist) | ||
| 4. test coverage for taxonomy and controller references |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
source_statussent by controller but absent from taxonomyrequired_propertiesThe controller sends
source_statusin both code paths that fireanalytics_source_error_shown:renderError(...)— passessource_status(e.g., HTTP status code or"fetch_failed")renderSourceHealth(...)— passessource_status(mapped fromrow.status)The production runbook in
docs/analytics-page-data-correctness-checklist.mdalso explicitly listssource_statusas a field to inspect when troubleshooting repeated error toasts. It is therefore a de-facto required diagnostic property, but it is not listed inrequired_propertieshere. This creates a gap between what the event actually carries and what the taxonomy documents.Consider adding it: