# 客户端缓存键作用域规范(Cache Key Scoping) ## 目标 防止同一设备多账号切换时出现缓存串读(A 账号数据在 B 账号展示)。 本规范适用于 `apps/lib/data/cache/**` 以及所有通过 `CachedRepository` 读写的业务缓存。 --- ## 作用域模型 ### 1) 作用域级别 - `anonymous`:未登录态(或未绑定用户上下文) - `user:`:已登录用户态 ### 2) 键格式 客户端持久缓存最终键必须按以下格式生成: `cache::` 其中 `` 可以附带会话代际后缀(推荐): - `user::v` - `anonymous:v` 该后缀用于切号并发场景,确保旧会话异步回写落在旧命名空间。 示例: - `cache:user:8ef4...:chat:history:first:default` - `cache:user:8ef4...:v12:chat:history:first:default` - `cache:user:8ef4...:v12:calendar:day:2026-03-29` - `cache:anonymous:v13:inbox:list:all` --- ## 责任边界 ### 基础层(必须) - `CachedRepository` 负责统一附加 `` 前缀。 - Feature Repository 只声明业务键(``),不得手工拼接 userId 前缀。 ### 应用层(必须) - 在认证状态变化时更新当前缓存作用域: - 登录成功 -> `user:` - 登出/失效 -> `anonymous` --- ## 并发与切号安全 - 切号后,旧账号异步请求结果不得回写到新账号 UI 状态。 - 推荐使用会话代际(epoch/token)保护异步回写。 - 缓存分区与 UI 状态隔离必须同时存在: - 仅有分区,无代际保护:仍可能出现瞬时回流显示。 - 仅有代际保护,无分区:仍可能读取到旧持久缓存。 --- ## 兼容与迁移策略 ### 向后兼容 - 旧无作用域键允许保留在本地存储中,不参与新读取路径。 - 新版本只读取带 `cache::` 前缀的键。 ### 迁移方式 - 采用增量迁移(additive),不执行强制删除旧键。 - 如需清理旧键,必须通过统一维护任务处理,不在功能逻辑中零散实现。 --- ## 验收标准 1. 同设备 A/B 账号来回切换,不出现跨账号历史/列表串读。 2. 登录后首次读取命中当前用户作用域键;登出后读取命中匿名作用域键。 3. Feature 仓库不再自行实现 userId 拼 key 逻辑。