# Session restore 每日登录埋点案例(2026-05-08) ## 现象 用户反馈:已经登录且 cookie 没过期时,打开网页没有触发每日登录埋点。 ## 根因 当本地 access token 仍有效时,前端 `AuthGate` 恢复登录态只会复用现有 token 并请求 `/api/auth/me`。`/api/auth/me` 只读取当前用户,不会进入 `POST /api/auth/session/refresh`,因此后端 refresh handler 中的每日登录埋点不会执行。 关键误判点:后端已经在 refresh cookie 续期写埋点,不等于“打开网页”一定会触发。前端必须实际调用 refresh/session 接口。 ## 修复模式 1. 在 `src/services/apiClient.ts` 暴露强制 refresh 方法,例如: ```ts export async function refreshStoredAccessToken() { return refreshAccessToken(); } ``` 2. 在 `src/components/auth/AuthGate.tsx` 的 hydrate/restore 中,使用: ```ts await refreshStoredAccessToken(); const nextSession = await getCurrentAuthUser(); ``` 而不是只调用: ```ts await ensureStoredAccessToken(); const nextSession = await getCurrentAuthUser(); ``` 3. 保留 `ensureStoredAccessToken()` 给普通受保护请求兜底;不要把所有请求都改成强制 refresh。 4. 确认 `server-rs/crates/api-server/src/refresh_session.rs` 在 rotate refresh session 成功且新 access token 签发成功后调用每日登录埋点 helper。 5. 确认 `server-rs/crates/spacetime-module/src/runtime/profile.rs` 中 `get_profile_task_center` 不再顺手写 `daily_login`,避免任务中心读取污染登录埋点。 ## 测试 前端测试重点: - `AuthGate` 会等待 `refreshStoredAccessToken()` 完成后才暴露已恢复用户内容。 - `AUTH_STATE_EVENT` 触发 hydrate 时仍保持已挂载平台内容和本地 tab 状态。 命令: ```bash npm run test -- AuthGate.test.tsx npm run typecheck ``` 后端/SpacetimeDB 编译: ```bash cd server-rs && cargo check -p spacetime-module cd server-rs && cargo check -p api-server ``` 全局检查: ```bash npm run check:encoding git diff --check ``` ## 注意 - Vitest 0.34 不支持 Jest 的 `--runInBand` 参数;命令里不要加。 - 埋点失败只能 warning,不能阻断登录态恢复。 - 如果后续发现打开页面产生过多 refresh 请求,需要在产品口径和埋点口径之间重新设计节流;但不能退回“只读 `/api/auth/me` 却期待写登录埋点”的状态。