新功能:个性化推荐算法
This commit is contained in:
151
spec_kit/Client User Identity/spec.md
Normal file
151
spec_kit/Client User Identity/spec.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# Client User Identity|客户端用户标识建立(用于 PUSH Token 绑定)|Spec
|
||||
|
||||
> 阶段:高层规范(spec)
|
||||
>
|
||||
> 目标:在**无账号体系或账号可选**的前提下,为客户端生成一个稳定的“客户端用户标识”(下称 `client_user_id`),用于与 APNs/FCM 的 Push Token 建立绑定关系,便于后端精准下发 PUSH,并支持 Token 变更/多设备/环境隔离等场景。
|
||||
|
||||
---
|
||||
|
||||
## 1. 背景与动机(摘要)
|
||||
|
||||
Push Token(APNs device token / FCM registration token)会发生变化(重装、系统升级、重新授权、token rotate 等),且同一用户可能多设备。为了能稳定地“找到这个客户端实例/用户侧主体”并维护 Token 映射,需要一个**与 Token 解耦**、可持久化、不可推断的标识。
|
||||
|
||||
---
|
||||
|
||||
## 2. 目标(Goals)
|
||||
|
||||
- **建立 `client_user_id`**:客户端可生成并持久化一个稳定标识,作为后端 Push Token 绑定的主键之一。
|
||||
- **Token 绑定可更新**:支持 Token 变更时“同一 `client_user_id` 重新上报即可更新”。
|
||||
- **多设备兼容**:同一个账号(若未来引入)可关联多个 `client_user_id`;一个 `client_user_id` 可存在多个 Token(例如同设备多渠道/多应用包形态)时需可扩展。
|
||||
- **环境隔离**:dev/prod、iOS/Android、bundle id / package name 维度隔离,避免串绑。
|
||||
- **隐私友好**:不使用可追踪的硬件标识(IMEI/IDFA/Android ID 等),不引入额外合规风险。
|
||||
|
||||
---
|
||||
|
||||
## 3. 非目标(Non-goals)
|
||||
|
||||
- 不在本阶段引入完整账号体系、登录态、用户合并策略(如“同一人多设备合并为一个 user_id”)。
|
||||
- 不在本阶段强制接入设备证明(App Attest/Play Integrity);仅在安全章节提出可选增强方向。
|
||||
- 不定义具体数据库表结构与迁移脚本(属于 plan 阶段细化)。
|
||||
|
||||
---
|
||||
|
||||
## 4. 术语与对象(Definitions)
|
||||
|
||||
- **`client_user_id`**:客户端生成并持久化的随机标识,代表“一个客户端安装实例(或一段时间内的用户侧主体)”,用于 Push 绑定。
|
||||
- **`push_token`**:系统/厂商下发的推送 token(iOS/APNs,Android/FCM),可能变化。
|
||||
- **`account_id`(可选)**:若未来存在登录账号,则用于把多个 `client_user_id` 归属到同一账号。
|
||||
|
||||
---
|
||||
|
||||
## 5. 关键决策:使用 UUID 做 `client_user_id` 是否合适?
|
||||
|
||||
结论:**合适**,推荐用**随机 UUID(UUID v4 为默认)**,并把它当作后端与客户端都不解析的**不透明字符串**。
|
||||
|
||||
### 5.1 为什么 UUID 合适
|
||||
|
||||
- **唯一性足够**:v4 基于随机数,碰撞概率极低,满足全局唯一需求。
|
||||
- **不可推断**:相较自增 ID,不易被枚举;相较设备硬件标识,更隐私友好。
|
||||
- **跨端易实现**:iOS/Android/JS 都可稳定生成与序列化(字符串)。
|
||||
|
||||
### 5.2 需要明确的边界与注意事项
|
||||
|
||||
- **UUID 不等于“真实用户”**:它更像“安装实例 ID”。用户重装/清数据后可能变化;这对 Push 绑定通常可接受(新装产生新 token 与新 id)。
|
||||
- **不要用设备硬件/系统可追踪 ID 替代**:避免隐私与合规风险,也避免系统限制导致的不稳定。
|
||||
- **安全边界**:如果后端完全信任客户端上报的 `client_user_id`,存在“伪造绑定”风险;应结合登录态或签名/证明(见第 9 节)降低滥用。
|
||||
|
||||
### 5.3 UUID 版本建议
|
||||
|
||||
- **默认**:UUID v4(实现最简单、兼容最好)。
|
||||
- **可选增强**:UUID v7(有时间有序性,利于日志/索引与写入局部性),但需要确保两端实现一致与依赖可控。
|
||||
|
||||
---
|
||||
|
||||
## 6. 客户端行为规范(Client Contract)
|
||||
|
||||
### 6.1 生成与持久化
|
||||
|
||||
- 首次启动(或首次需要注册 Push 时):
|
||||
- 若本地不存在 `client_user_id`:生成一个新的 UUID(字符串),写入持久化存储。
|
||||
- 若已存在:直接复用。
|
||||
- 存储建议(不做强约束,但必须“尽量稳定”):
|
||||
- iOS:Keychain
|
||||
- Android:Keystore 保护的加密存储/SharedPreferences(或等价方案)
|
||||
- React Native/Expo:使用安全存储能力(例如 SecureStore/Keychain wrapper)
|
||||
|
||||
### 6.2 Push Token 获取与上报时机
|
||||
|
||||
- 在以下任一时机触发“注册/更新”:
|
||||
- 用户同意 Push 权限后获得 token
|
||||
- App 冷启动获取到 token(含 token 变更)
|
||||
- 账号登录/登出(若存在账号)
|
||||
- 环境切换(dev/prod)或应用更新(可选)
|
||||
|
||||
---
|
||||
|
||||
## 7. 后端接口契约(API Contract,摘要)
|
||||
|
||||
> 具体路由/鉴权方式在 plan 阶段落地;此处先定义字段语义与幂等行为。
|
||||
|
||||
### 7.1 注册/更新绑定
|
||||
|
||||
- `POST /v1/push/register`
|
||||
- 请求体(最小集):
|
||||
- `client_user_id`: string(UUID 字符串)
|
||||
- `platform`: `"ios" | "android"`
|
||||
- `push_token`: string
|
||||
- `app_id`: string(bundle id / package name,用于隔离)
|
||||
- `env`: `"dev" | "prod"`
|
||||
- (可选)`account_id`: string
|
||||
- (可选)`device_meta`: `{ model, os_version, app_version, locale, timezone }`
|
||||
- 行为要求(幂等):
|
||||
- 以 `push_token + env + app_id` 维度做唯一性约束,避免重复记录。
|
||||
- 若同一 `client_user_id` 上报了新 token:应更新/新增映射,旧 token 进入失效或保留历史(由实现决定,但必须可控)。
|
||||
|
||||
### 7.2 解绑(可选但建议)
|
||||
|
||||
- `POST /v1/push/unregister`
|
||||
- 请求体:
|
||||
- `client_user_id`
|
||||
- `platform`
|
||||
- `push_token`(或让后端按 `client_user_id` 批量解绑,二选一)
|
||||
- `app_id`
|
||||
- `env`
|
||||
|
||||
---
|
||||
|
||||
## 8. 数据模型(逻辑约束)
|
||||
|
||||
最小需要表达的关系:
|
||||
|
||||
- 一个 `client_user_id` 可对应 0..N 个 `push_token`(考虑多端、多渠道、token rotate)。
|
||||
- 一个 `push_token` 在同一 `env + app_id` 下应只对应一个“当前归属”(避免重复推送)。
|
||||
- 若存在 `account_id`:
|
||||
- 一个 `account_id` 可关联 0..N 个 `client_user_id`(多设备)。
|
||||
|
||||
---
|
||||
|
||||
## 9. 安全与滥用防护(高层约束)
|
||||
|
||||
- **最小要求**:接口需具备基本鉴权与频率限制(例如基于设备指纹/匿名 session/应用侧签名的任一组合),避免被脚本批量绑定垃圾 token。
|
||||
- **若存在登录态**:推荐绑定写入需要登录态(或在登录后把 `client_user_id` 归属到 `account_id`),降低“抢绑”风险。
|
||||
- **可选增强(后续)**:接入 iOS App Attest / Android Play Integrity,或对注册请求做一次性挑战签名。
|
||||
|
||||
---
|
||||
|
||||
## 10. 边界场景与处理原则
|
||||
|
||||
- **用户拒绝 Push 权限**:允许只有 `client_user_id`,不产生 token 绑定;后端不应报错。
|
||||
- **token 变化**:客户端重新调用 `register`,后端必须幂等更新,避免重复推送。
|
||||
- **重装/清数据**:`client_user_id` 变化可接受;若未来有 `account_id`,可在登录后重新建立关联。
|
||||
- **多环境**:dev/prod token 不可混用;必须以 `env + app_id` 隔离。
|
||||
|
||||
---
|
||||
|
||||
## 11. 验收标准(Acceptance Criteria)
|
||||
|
||||
- 客户端能稳定生成并持久化 `client_user_id`(重复启动不变)。
|
||||
- 在 token 获取/变更后,调用注册接口可在后端建立(或更新)绑定关系,且接口幂等。
|
||||
- 同一 `push_token` 在同一 `env + app_id` 下不会产生多条“当前有效”绑定,避免重复推送。
|
||||
- 在用户拒绝 Push 权限、无 token 的情况下,不影响 App 正常使用与后续再次授权后的绑定。
|
||||
|
||||
Reference in New Issue
Block a user