修复手机号重复账号合并

把手机号、昵称和头像回填并固定到 user_account。

停止新写入依赖 auth_identity 的账号资料旧列。

新增重复手机号账号库内合并 procedure,避免线上全量导出扫描。

更新 SpacetimeDB 绑定和账号资料职责文档。
This commit is contained in:
2026-07-01 15:39:24 +08:00
parent d50ecbc492
commit c8efdbcfc9
11 changed files with 1996 additions and 16 deletions
@@ -91,6 +91,7 @@
- 现象:后台把私有兑换码配给某个陶泥号或手机号后,用户用同一手机号登录兑换仍提示 `该兑换码不适用于当前账号`
- 原因:认证表里可能存在同一手机号的多条 `user_account`。如果认证工作集重建 `phone_to_user_id` 时让 `user_account.phone_number_e164` 后写覆盖前写,当前登录态会漂到没有 `auth_identity` 的重复账号,而兑换码白名单仍指向另一个内部 `user_id`
- 处理:重建认证工作集时以 `auth_identity(provider="phone")` 指向的账号作为手机号索引权威,`user_account.phone_number_e164` 只补没有 identity 的手机号;旧 `auth_store_snapshot` 只允许在正式认证表为空时一次性转移到正式表,随后清空,不再作为运行期回灌来源;Bearer / refresh session 本进程未命中时不要再从 SpacetimeDB 导出整包快照刷新内存。线上止血先核对失败请求附近的 current session `user_id` 与兑换码 `allowed_user_ids`,不要只看手机号展示值。
- 约束:`auth_identity` 只保存登录入口身份键;手机号、昵称和头像的正式资料真相在 `user_account.phone_number_e164` / `display_name` / `avatar_url`。旧 `auth_identity.phone_e164` / `display_name` / `avatar_url` 只能作为历史回填来源,不能继续让新写入依赖这些列。
- 验证:`cargo test -p spacetime-module auth_export -- --nocapture` 应覆盖同手机号重复账号时手机号索引优先指向有 phone identity 的账号;`api-server` 中不应再存在运行期 `refresh_auth_store_from_spacetime` 调用。
- 关联:`server-rs/crates/spacetime-module/src/auth/procedures.rs``server-rs/crates/spacetime-module/src/auth/tables.rs``server-rs/crates/module-auth/src/lib.rs`
@@ -283,6 +283,7 @@ npm run check:server-rs-ddd
- Rust 结构体:`AuthIdentity`
- 源码:`server-rs/crates/spacetime-module/src/auth/tables.rs`
- 职责:只表达登录入口身份键到 `user_account.user_id` 的绑定;`provider_uid` 保存手机号 E.164 或微信 openid`provider_union_id` 保存微信 unionid。账户资料以 `user_account.phone_number_e164``user_account.display_name``user_account.avatar_url` 为准,`auth_identity.phone_e164` / `display_name` / `avatar_url` 仅保留旧行兼容,不再作为写入或恢复真相。
### `auth_store_projection_meta`