# 登录成功每日登录埋点闭环方案(2026-05-08) ## 背景 后台“埋点数据”需要能看到真实登录触发的 `daily_login` 埋点。此前方案 A 已把“读取任务中心时顺手写每日登录埋点”拆成独立 SpacetimeDB procedure: - `record_daily_login_tracking_event_and_return` - `spacetime-client` 方法:`record_daily_login_tracking_event(user_id)` 但认证成功链路还没有调用该方法,因此当前只完成了“任务中心读取不污染登录埋点”,没有完成“用户真实登录写入每日登录埋点”。 ## 现象 用户已经登录、cookie 未过期时,直接打开网页并不会触发每日登录埋点。原因是前端恢复登录态只读取 `/api/auth/me`,这条链路不会主动走 refresh cookie 续期,因此后端新的埋点写入点不会被触发。 ## 修复思路 在 `AuthGate` 恢复已登录会话时,先主动调用一次 refresh 接口轮换 refresh cookie,再调用 `/api/auth/me` 读取当前会话。这样无论本地 access token 是否仍然有效,打开页面都会进入 refresh 续期链路,从而触发后端的 `daily_login` 埋点写入。 ## 目标 在用户认证成功并创建 refresh session / access token 后,异步尝试写入每日登录埋点。 覆盖入口: - 手机验证码登录:`POST /api/auth/phone/login` - 密码入口登录:`POST /api/auth/entry` - 重置密码后自动登录:`POST /api/auth/password/reset` - 微信 OAuth callback 登录:`GET /api/auth/wechat/callback` - 微信绑定手机号后激活/登录态刷新:`POST /api/auth/wechat/bind-phone` - refresh cookie 续期:`POST /api/auth/session/refresh` ## 设计约束 1. 埋点写入不能阻断登录成功响应。 2. 只有认证成功并已创建会话后,或 refresh session rotate 成功并签发新 access token 后才记录。 3. 失败只记 warning,继续返回 token / cookie。 4. 写入统一收口,避免多个登录 handler 各自拼 procedure 调用。 5. 不修改 SpacetimeDB 表结构,不需要更新 `migration.rs`。 ## 实现方案 新增 `api-server` 内部 helper: ```rust record_daily_login_tracking_event_after_auth_success( state: &AppState, request_context: &RequestContext, user_id: &str, login_method: AuthLoginMethod, ).await; ``` 该 helper: - 调用 `state.spacetime_client().record_daily_login_tracking_event(user_id.to_string()).await` - 成功时记录 info - 失败时记录 warn,并明确“登录流程继续” 在各登录入口 `create_auth_session` 成功后调用该 helper。refresh cookie 续期在 `rotate_session` 和 `sign_access_token_for_user` 成功后调用同一个 helper,`login_method` 使用 refresh session 上保存的 `issued_by_provider`,避免把续期统一误标成 password。 ## 验收 - `cargo test -p api-server auth_session -- --nocapture` - `cargo check -p api-server` - `cargo check -p spacetime-client` - `npm run check:encoding` - `git diff --check` - `npm run test -- AuthGate.test.tsx` ## 注意 `npm run dev` 是长期运行进程;如需本地 smoke,应启动后用 `/healthz` 和后台页面验证,不要等待该命令退出。