mirror of
https://github.com/moeru-ai/airi.git
synced 2026-07-10 00:08:33 +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 |
||
|---|---|---|
| .. | ||
| verifications | ||
| account-ban.md | ||
| account-deletion.md | ||
| admin-flux-grants.md | ||
| architecture-overview.md | ||
| auth-and-oidc.md | ||
| billing-architecture.md | ||
| config-and-naming-conventions.md | ||
| data-model-and-state.md | ||
| email-auth-resend.md | ||
| flux-meter.md | ||
| langfuse-tracing.md | ||
| llm-router-codex-followups.md | ||
| metrics-ownership.md | ||
| observability-conventions.md | ||
| observability-metrics.md | ||
| product-analytics-dashboard-setup.md | ||
| product-analytics-instrumentation.md | ||
| README.md | ||
| redis-boundaries-and-pubsub.md | ||
| stripe-pricing.md | ||
| transport-and-routes.md | ||
| workers-and-runtime.md | ||
AIRI Server AI Context
这组文档面向后续 AI / 开发者协作,目标是让人快速回答四个问题:
- 服务端是怎么启动和组装的
- 每条 API / WS 请求最终落到哪个服务
- 哪些状态以 Postgres 为真相源,哪些只是缓存或派生数据
- 计费、充值、事件分发这些高风险链路有哪些约束
文档索引
architecture-overview.md- 入口、依赖注入、应用装配、核心边界
transport-and-routes.md- HTTP / WebSocket 接口面、路由到服务映射、鉴权与中间件
data-model-and-state.md- 主要表、状态归属、缓存边界(事件队列层已拆掉)
workers-and-runtime.md- 单
apirole、无后台 loop、运行时约束(admin grant / Stripe webhook 等都同步在请求线程)
- 单
redis-boundaries-and-pubsub.md- Redis key / channel 收口、Pub/Sub 边界、运行时校验约束
config-and-naming-conventions.mdconfigKV默认值来源、Redis key 命名、HTTP route 命名、后续收敛 TODO
billing-architecture.md- 计费链路专项说明,重点看 Flux ledger / Stripe 幂等
stripe-pricing.md- Flux 充值定价以 Stripe Product/Price 为单一真相源,多币种 / 缓存 / 运营操作
flux-meter.md- Sub-Flux 计量服务(TTS/STT 等)的债务账本机制与复用指南
observability-conventions.md- traces / metrics 命名规则,标准 OTel 字段与
airi.*自定义字段边界,SemconvStability 迁移、Counter priming、Dashboard 变量陷阱
- traces / metrics 命名规则,标准 OTel 字段与
observability-metrics.md- 全量 metric 目录(按域分组:HTTP / Auth / Engagement / Revenue / GenAI / Email / Rate limit / Runtime),含名字、类型、Labels、落点
metrics-ownership.md- 指标分层规则:什么走 Grafana / 什么走 PostHog / 什么是 Postgres truth;含 7 题判定 Checklist、PostHog 事件命名约定、当前指标归属总表、PostHog 接入路线图
product-analytics-instrumentation.md- 面向社区 / 产品问题的埋点补充方案:上手激活、Provider 配置、TTS 音色、语音输入、反馈、看板和异常播报
product-analytics-dashboard-setup.md- 产品分析看板落地说明:PostHog insights、Grafana 产品事件面板、告警表达式;不含 Discord / QQ 同步和日报 / 周报脚本
auth-and-oidc.md- 认证与 OIDC Provider 架构、登录流程、trusted clients、踩坑记录
email-auth-resend.md- Resend 接入、Better Auth 四个邮件 callback、范围 / 决策 / 不做项
account-deletion.md- 账号注销架构:auth 表 hard delete + 业务表软删,handler 协议、各业务行为、failure 模型
admin-flux-grants.md- Admin 批量发 FLUX(活动赠送):单一同步 POST,无 batch 表无后台 loop,
adminGuard邮箱白名单 + 可选idempotencyKey
- Admin 批量发 FLUX(活动赠送):单一同步 POST,无 batch 表无后台 loop,
account-ban.md- Admin 授权改 role-based(better-auth
admin插件,删ADMIN_EMAILS);ban/unban 收敛到 better-auth 原生端点(user.banned),resolveRequestAuth+ userinfo guard 做 OIDC JWT 热路径立即生效;改余额(setFlux)保留自建;含 disabledPaths 端点收口与「dashboard 为何不上」的决策
- Admin 授权改 role-based(better-auth
verifications/email-auth.md- 邮箱注册 / 忘记密码 / OIDC 桥接登录 三条用户路径的真实实测证据
verifications/account-deletion.md- 账号注销端到端验证:what's verified(schema/typecheck/units)和 what's pending(live DB + Resend + Stripe trace)
verifications/admin-flux-grants.md- Admin 同步发 FLUX 路径:同步 grant / dry-run / adminGuard 拒绝(架构刚从 batch 切换到同步,待重新实测)
verifications/flux-unbilled-exploit-fix.md- Unpaid-usage exploit 修补(commit
7267b0d6b)的代码层验证 + 残余 gap(TTS flux-meter 未适配 partial-debit)+ follow-up 清单
- Unpaid-usage exploit 修补(commit
verifications/flux-unbilled-reconciliation.md- 70.2K 历史漏账的取证 SQL + Loki query 模板、处理决策框架、修补后的监控建议
verifications/admin-user-balance-ban.md- Admin role 鉴权 / 封禁热路径闸 / 改余额:role adminGuard、resolveRequestAuth+userinfo 封禁、setFlux 的真实 PGlite/Hono 执行证据(含 flux-grants 集成测试走 role),及 better-auth admin 端点本身待端到端实测
verifications/product-analytics-smoke.md- 产品分析埋点上线冒烟清单:PostHog journey events、Postgres TTS metadata、Grafana Product Analytics row、Prometheus label 安全边界
快速结论
apps/server/src/app.ts是唯一的 API 应用装配入口。- 服务端采用
Hono + injeca + Drizzle + Redis + better-auth。 - 路由层整体较薄,业务逻辑主要在
src/services/。 - Postgres 是所有余额与计费状态的唯一真相源,Redis 只做缓存、KV、Pub/Sub。计费链路不再使用 Redis Streams。
- WebSocket 只用于聊天同步,跨实例广播依赖 Redis Pub/Sub。
- 对外 LLM 能力不是本地推理,而是转发到配置里的 gateway,再按 usage / fallback rate 扣 Flux。
修改代码前建议先看
- 改 API 入口或新增依赖:先看
architecture-overview.md - 改某个接口行为:先看
transport-and-routes.md - 改表结构、缓存或幂等:先看
data-model-and-state.md - 想加任何"异步副作用 / 后台 loop":先看
workers-and-runtime.md的"运行时修改建议" - 改 Redis key、Pub/Sub 边界:先看
redis-boundaries-and-pubsub.md - 改配置默认值、Redis key 命名、HTTP route 命名:先看
config-and-naming-conventions.md - 改扣费、充值、Stripe:先看
billing-architecture.md - 改 Flux 充值价格 / 多币种 / Stripe Product/Price:先看
stripe-pricing.md - 改 trace / metric attributes、OTel 命名:先看
observability-conventions.md - 加新 metric / 找当前 metric 全量列表:先看
observability-metrics.md - 决定新指标该走 Grafana 还是 PostHog:先看
metrics-ownership.md - 改认证、OIDC、登录流程:先看
auth-and-oidc.md - 改邮件 service / Better Auth 邮件 callback:先看
email-auth-resend.md - 改账号注销 / 业务 service 的
deleteAllForUser:先看account-deletion.md - 改 admin 发 FLUX 路径:先看
admin-flux-grants.md - 改 TTS / STT / embedding 等 sub-Flux 计量:先看
flux-meter.md