mirror of
https://github.com/moeru-ai/airi.git
synced 2026-07-09 15:58:27 +00:00
Some checks failed
CI / Lint (push) Has been cancelled
CI / Build Test (stage-tamagotchi) (push) Has been cancelled
CI / Build Test (stage-tamagotchi-godot) (push) Has been cancelled
CI / Build Test (stage-web) (push) Has been cancelled
CI / Build Test (ui-loading-screens) (push) Has been cancelled
CI / Build Test (ui-transitions) (push) Has been cancelled
CI / Unit Test (push) Has been cancelled
CI / Type Check (push) Has been cancelled
CI / Check Provenance (push) Has been cancelled
Cloudflare Pages (Auth UI) / Deploy - ui-server-auth (push) Has been cancelled
Cloudflare Workers / Deploy - stage-web (push) Has been cancelled
Update Nix pnpmDeps Hash / update (push) Has been cancelled
## What Closes the three structural gaps in AIRI's product analytics: the signup surface had zero instrumentation, the payment funnel had no terminator in PostHog, and SPA route changes emitted no pageviews. Also adds semantic events for character cards, desktop-only features, and data-maintenance actions. ## User paths - User signs up / logs in / verifies email / resets password / links OAuth / deletes account → each step now emits a PostHog event from `apps/ui-server-auth` (previously fully uninstrumented), with `identify()` wired on session load so anonymous funnel events merge into the user person. - User pays via Stripe → webhook writes `product_events` as before, and the product-events service now forwards `payment_completed` (plus signup and subscription lifecycle facts) to PostHog via posthog-node `captureImmediate`, keyed by the Better Auth user id → the `checkout_started → payment_completed` funnel closes end-to-end. Per-request LLM/TTS volume is explicitly not forwarded. - User navigates between routes in any surface (web / desktop / pocket / docs) → `$pageview` + `$pageleave` fire per route change via the posthog-js `defaults: '2025-05-24'` preset in the shared `posthog.config.ts`. - User creates / imports / duplicates / edits a ccv3 card, switches stage background, runs destructive data actions (export / import / clear chats, reset providers, wipe app data), or uses desktop differentiators (Spotlight send, widget windows, in-app updater, MCP server management, pairing QR) → dedicated low-cardinality events. ## Notable decisions - Server forwarding defaults on: `POSTHOG_PROJECT_KEY` defaults to the shared browser-safe phc_* project key; set it to an empty string to disable. Postgres `product_events` remains the source of truth. - Cross-surface events (`oauth_callback_failed`, account lifecycle) share one stage vocabulary exported from stage-ui so the two emitters cannot drift silently. - Events captured right before full-page navigation use `sendBeacon` so they survive the redirect (checkout, OAuth consent handoff, login redirect). - Removed dead wrappers (`trackSignup`, `trackFirstModelSelected`, `trackModelChanged`) that duplicated live event streams under second names. ## How tested - `pnpm -F @proj-airi/server exec vitest run src/services/domain/product-events.test.ts` — 6 passed, covering the forwarding allowlist, the `user_signed_up → signup_completed` mapping, non-forwarded per-request actions, and a throwing sink not failing the webhook path nor losing the DB row. - stage-ui suites (`use-analytics`, `use-linked-accounts`, exports contract) — 22 passed, including new account/card/data/desktop event assertions. - Real transport smoke: posthog-node `captureImmediate` against `us.i.posthog.com` with the production key resolved in 1380ms (one `server_forwarding_smoke_test` event left in the project; filter by event name). - Browser-tested pageviews: `VITE_ENABLE_POSTHOG=true` dev build, two `history.pushState` route changes each produced a `$pageview` with `$pathname`, `navigation_type: pushState`, previous-page dwell time, and the `surface` super property; batched POST to `us.i.posthog.com/e/` returned 200. Note: posthog-js drops events from automated browsers (`navigator.webdriver`) by default — the verification session bypassed the bot filter locally; production config is untouched. - Typecheck and lint pass for server, stage-ui, stage-pages, stage-web, stage-tamagotchi, ui-server-auth. Full verification record: `apps/server/docs/ai-context/verifications/posthog-forwarding-and-pageview.md` ## Follow-ups (not in this PR) - Bot channel usage stats (Discord / Telegram) once they route through server-runtime counters. - Main-process desktop events (tray menu, global shortcut fire) need renderer relay plumbing. - Confirm `payment_completed` arrives in PostHog after the first real Stripe payment post-deploy. https://claude.ai/code/session_01Q1yGavkQ1P41YhTWE4XKex
2.5 KiB
2.5 KiB
Verification: 服务端 PostHog 转发 + SPA 路由 pageview
Status: transport 与 pageview 已真实验证;线上 Stripe webhook 端到端待部署后确认
Owner: Product Analytics
Last updated: 2026-07-08
Environment: commit 689f02ac4 + 本次工作区改动;posthog-node 5.39.4;posthog-js 1.306.1;Node 26.3.0
用户路径
- 场景 1:用户完成 Stripe 支付 → webhook 写
product_events→ 服务端把payment_completed转发到 PostHog(distinctId = Better Auth user id)→ PostHog 付费漏斗在checkout_started后闭环。 - 场景 2:用户在 stage-web 内切换路由(如进入
/settings/flux)→ PostHog 收到$pageview,带$pathname、上一页路径与停留时长。
已验证证据
| 验证项 | 命令 / 方式 | 实际输出 |
|---|---|---|
| 转发白名单与映射 | pnpm exec vitest run src/services/domain/product-events.test.ts(apps/server) |
6 passed:payment_completed 原名转发、user_signed_up→signup_completed 映射、per-request 动作不转发、sink 抛错时 DB 行仍落库且 track 不抛 |
| posthog-node 真实传输 | node posthog-smoke.mjs(captureImmediate → us.i.posthog.com,生产 project key,事件名 server_forwarding_smoke_test) |
captureImmediate resolved in 1380ms + shutdown clean |
| SPA 路由 pageview | VITE_ENABLE_POSTHOG=true pnpm -F @proj-airi/stage-web dev + agent-browser 两次 history.pushState |
两条 $pageview,$pathname 分别为 /settings/flux、/settings/airi-card,navigation_type: pushState,携带 $prev_pageview_duration 与 surface: web super property;批量 POST us.i.posthog.com/e/ 返回 200 |
| 服务端 typecheck / lint | pnpm -F @proj-airi/server typecheck、eslint 改动文件 |
均通过 |
注意事项
- 自动化浏览器(
navigator.webdriver = true)会被 posthog-js 默认 bot 过滤静默丢弃事件;本次浏览器验证通过会话内set_config({ opt_out_useragent_filter: true })绕过,仅影响该验证会话,生产配置未改。人工复测时用普通浏览器即可,无需任何绕过。 - 服务端转发默认开启:
POSTHOG_PROJECT_KEY的默认值就是前端共用的 phc_* project key,置空字符串可关闭。部署后在 PostHog 里确认payment_completed事件出现在真实支付后,即完成端到端收尾。 - PostHog 项目里会留有一条
server_forwarding_smoke_test(distinctIdverification-smoke)测试事件,分析时按事件名过滤。