Skip to content

feat(ui): track solve_run analytics event - #20

Open
aeronauty-flexcompute wants to merge 1 commit into
mainfrom
harry/solve-run-analytics
Open

feat(ui): track solve_run analytics event#20
aeronauty-flexcompute wants to merge 1 commit into
mainfrom
harry/solve-run-analytics

Conversation

@aeronauty-flexcompute

@aeronauty-flexcompute aeronauty-flexcompute commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator

Why

Vera asked whether FlexFoil is actually being used. GA4 could answer "people open it" (2,791 users YTD, 163 in the last 28 days, 5m29s average engagement) but not "people run solves" — the property carried only GA's six default events (page_view, scroll, session_start, user_engagement, first_visit, click). Engagement time and ~12.7 page views per user were the closest available proxies.

What

  • lib/analytics.ts: add a trackEvent(name, params) helper — a thin window.gtag?.('event', …) wrapper. Optional call because gtag is absent when the tag is blocked.
  • SolvePanel.tsx: fire solve_run from the three user-initiated solve paths:
solve_mode Trigger
single_alpha / single_cl runAnalysis — single point, α or CL targeting
polar runPolar — alpha polar sweep
sweep_1d / sweep_2d runMultiSweep — parameter sweeps

Each event also carries solver_mode (viscous/inviscid) and n_panels.

Events fire at dispatch, not completion, so the count reflects solves requested — independent of convergence, and it can't be lost to a throw or a hang.

Privacy

No change to the consent posture. Google Consent Mode still gates delivery, so this collects nothing extra from users who decline cookies. No airfoil geometry, coordinates, or filenames are sent — only the mode, solver type, and panel count.

Test plan

  • npx vitest run — 67 tests pass across 6 files, including 2 new cases in analytics.test.ts (forwards name + params; does not throw when the tag is blocked). The new test stands up a minimal window on globalThis so it runs in the existing node environment, avoiding a new jsdom dependency.
  • npx tsc -b — clean.
  • npx eslint — the changed analytics files are clean. SolvePanel.tsx reports 8 pre-existing problems (6 errors, 2 warnings, all react-hooks/preserve-manual-memoization in unrelated callbacks); verified identical count on main before these edits, so this change adds none.
  • npm run build — succeeds. Confirmed solve_run and all five solve_mode values survive into dist/assets/index-*.js (not tree-shaken).

After merge

Merging to main triggers deploy-foil.yml and ships to foil.flexcompute.com automatically. solve_run event counts appear in GA4 (property FlexFoil) within ~24h under Engagement → Events. The solve_mode / solver_mode params need registering as custom dimensions in GA4 admin to be reportable as breakdowns — the total event count and user count work without that.

🤖 Generated with Claude Code


Note

Low Risk
Analytics-only UI changes with no solver, auth, or data-model impact; events use coarse metadata and existing consent gating.

Overview
Adds GA4 instrumentation so product usage can distinguish solve attempts from page views, without changing consent behavior or sending geometry.

A new trackEvent helper in lib/analytics.ts wraps optional window.gtag calls; Consent Mode still gates delivery, and blocked tags are a no-op.

SolvePanel emits solve_run at the start of each user-initiated solve path (before the job runs): single-point α/CL (single_alpha / single_cl), alpha polar (polar), and 1D/2D parameter sweeps (sweep_1d / sweep_2d). Each event includes solver_mode (viscous/inviscid) and n_panels only.

analytics.test.ts covers forwarding to gtag and safe behavior when gtag is missing.

Reviewed by Cursor Bugbot for commit a295f0e. Bugbot is set up for automated code reviews on this repo. Configure here.

GA4 carried only the six default events, so we could measure that people
opened FlexFoil but not that they ran anything. Engagement time was the
closest available proxy.

Add a trackEvent helper to lib/analytics and fire solve_run from the three
user-initiated solve paths in SolvePanel: single-point (alpha and CL
targeting), alpha polar, and parameter sweeps. Params record which mode was
used, viscous vs inviscid, and panel count.

Fired at dispatch rather than completion so the count reflects solves
requested, independent of convergence. Consent Mode still gates delivery,
so this collects nothing extra from users who decline cookies.

Co-Authored-By: claude-flow <ruv@ruv.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants