chore: sync worktree changes - update protocols, trellis workspace, and config
This commit is contained in:
@@ -64,13 +64,20 @@
|
||||
|
||||
## Error Codes
|
||||
|
||||
推荐错误码(由后端映射为 4xx):
|
||||
当前实现(`backend/src/v1/schedule_items/service.py`)实际返回以下稳定错误码:
|
||||
|
||||
- `INVALID_DATETIME_FORMAT`
|
||||
- `NAIVE_DATETIME_FORBIDDEN`
|
||||
- `INVALID_TIMEZONE`
|
||||
- `TIMEZONE_REQUIRED`
|
||||
- `INVALID_TIME_RANGE`
|
||||
- `SCHEDULE_ITEM_DATETIME_TIMEZONE_REQUIRED`:输入 datetime 缺少时区偏移
|
||||
- `SCHEDULE_ITEM_START_AT_TIMEZONE_REQUIRED`:`end_at` 校验阶段缺少可用的 `start_at` 时区信息
|
||||
- `SCHEDULE_ITEM_INVALID_TIME_RANGE`:`end_at <= start_at`
|
||||
|
||||
说明:`timezone` 非法、`start_at/end_at` 无时区等基础结构错误在 schema 校验阶段由 FastAPI/Pydantic 返回 `422`,业务错误码表(`docs/protocols/common/http-error-codes.md`)目前仅登记服务层稳定码。
|
||||
|
||||
---
|
||||
|
||||
## Compatibility Strategy
|
||||
|
||||
- 策略:`backward-compatible`
|
||||
- 本次为文档对齐更新,不改变线上接口行为;客户端若仅按 HTTP 状态码处理不受影响。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -12,28 +12,29 @@
|
||||
|
||||
### 1) 作用域级别
|
||||
|
||||
- `anonymous`:未登录态(或未绑定用户上下文)
|
||||
当前实现仅启用以下作用域:
|
||||
|
||||
- `user:<user_id>`:已登录用户态
|
||||
|
||||
未登录态实现说明:
|
||||
|
||||
- `apps/lib/app/services/session_scope_manager.dart` 在登出后会调用 `CacheScope.resetProvider()`。
|
||||
- 当 provider 未配置时,`apps/lib/data/cache/cached_repository.dart` 会跳过 scoped cache 读写,而不是写入 `anonymous` 命名空间。
|
||||
|
||||
### 2) 键格式
|
||||
|
||||
客户端持久缓存最终键必须按以下格式生成:
|
||||
|
||||
`cache:<scope>:<feature-key>`
|
||||
|
||||
其中 `<scope>` 可以附带会话代际后缀(推荐):
|
||||
当前实现未使用会话代际后缀(epoch/version token),最终键格式为:
|
||||
|
||||
- `user:<user_id>:v<epoch>`
|
||||
- `anonymous:v<epoch>`
|
||||
|
||||
该后缀用于切号并发场景,确保旧会话异步回写落在旧命名空间。
|
||||
- `cache:user:<user_id>:<feature-key>`
|
||||
|
||||
示例:
|
||||
|
||||
- `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`
|
||||
- `cache:user:8ef4...:calendar:day:2026-03-29`
|
||||
|
||||
---
|
||||
|
||||
@@ -47,18 +48,18 @@
|
||||
### 应用层(必须)
|
||||
|
||||
- 在认证状态变化时更新当前缓存作用域:
|
||||
- 登录成功 -> `user:<user_id>`
|
||||
- 登出/失效 -> `anonymous`
|
||||
- 登录成功 -> `user:<user_id>`
|
||||
- 登出/失效 -> 清空当前用户作用域并重置 provider(不进入 `anonymous` 作用域)
|
||||
|
||||
---
|
||||
|
||||
## 并发与切号安全
|
||||
|
||||
- 切号后,旧账号异步请求结果不得回写到新账号 UI 状态。
|
||||
- 推荐使用会话代际(epoch/token)保护异步回写。
|
||||
- 缓存分区与 UI 状态隔离必须同时存在:
|
||||
- 仅有分区,无代际保护:仍可能出现瞬时回流显示。
|
||||
- 仅有代际保护,无分区:仍可能读取到旧持久缓存。
|
||||
- 当前实现依赖 `user:<user_id>` 级别缓存分区 + 认证切换时清理上一用户前缀:
|
||||
- - 登录切换:清理上一用户 `cache:user:<old_user_id>:` 前缀
|
||||
- - 登出:清理当前用户前缀并关闭 scoped cache 读写
|
||||
- 当前实现未引入 epoch/token 代际保护;若未来出现“切号后旧请求晚到并覆盖新 UI”问题,需要另行升级协议与实现。
|
||||
|
||||
---
|
||||
|
||||
@@ -67,7 +68,7 @@
|
||||
### 向后兼容
|
||||
|
||||
- 旧无作用域键允许保留在本地存储中,不参与新读取路径。
|
||||
- 新版本只读取带 `cache:<scope>:` 前缀的键。
|
||||
- 新版本只读取带 `cache:user:<user_id>:` 前缀的键。
|
||||
|
||||
### 迁移方式
|
||||
|
||||
@@ -79,5 +80,12 @@
|
||||
## 验收标准
|
||||
|
||||
1. 同设备 A/B 账号来回切换,不出现跨账号历史/列表串读。
|
||||
2. 登录后首次读取命中当前用户作用域键;登出后读取命中匿名作用域键。
|
||||
2. 登录后首次读取命中当前用户作用域键;登出后 scoped cache 不再参与读取。
|
||||
3. Feature 仓库不再自行实现 userId 拼 key 逻辑。
|
||||
|
||||
---
|
||||
|
||||
## Compatibility Strategy
|
||||
|
||||
- 策略:`backward-compatible`
|
||||
- 本次为文档对齐更新,收敛未落地的 `anonymous`/epoch 设计,不改变现有应用行为。
|
||||
|
||||
@@ -215,12 +215,18 @@ data: {"event_id":"6f0d...","occurred_at":"2026-03-30T07:00:00Z","user_id":"..."
|
||||
"occurred_at": "datetime",
|
||||
"user_id": "uuid",
|
||||
"message_id": "uuid",
|
||||
"event_type": "INBOX_MESSAGE_CREATED | INBOX_MESSAGE_READ_CHANGED | INBOX_MESSAGE_STATUS_CHANGED | INBOX_SNAPSHOT_REQUIRED",
|
||||
"op": "created | read_changed | status_changed | snapshot_required",
|
||||
"version": 1743313300000,
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- SSE 帧的 `event:` 行与 payload 内 `event_type` 当前实现保持一致。
|
||||
- 客户端可优先使用 SSE `event`,也可在 payload 内读取 `event_type` 做调试或补偿。
|
||||
|
||||
### Delta 约定
|
||||
|
||||
- `created`:
|
||||
@@ -275,3 +281,10 @@ data: {"event_id":"6f0d...","occurred_at":"2026-03-30T07:00:00Z","user_id":"..."
|
||||
- 对 `message_type=calendar`,前端必须按 `content.type` 严格分发:`invite | updated | deleted`。
|
||||
- 若 `content` 缺少协议必填字段(`schema_version/item/actor/summary`,以及 `updated` 的 `changes`),前端必须进入协议异常展示路径。
|
||||
- 禁止将协议异常消息兜底渲染为“默认日历邀请”或其他正常业务消息。
|
||||
|
||||
---
|
||||
|
||||
## Compatibility Strategy
|
||||
|
||||
- 策略:`backward-compatible`
|
||||
- 本次仅补全文档遗漏字段 `event_type`,不改变现有 SSE wire 协议。
|
||||
|
||||
@@ -43,7 +43,7 @@ Base URL: `/api/v1/users`
|
||||
|
||||
字段说明:
|
||||
- `id`: 用户唯一标识符 (UUID)
|
||||
- `username`: 用户名,3-30 字符
|
||||
- `username`: 用户名,当前后端更新接口约束为最大 30 字符(最小长度未在 API 层强制)
|
||||
- `phone`: E.164 格式手机号,可为 null
|
||||
- `avatar_url`: 头像 URL,可为 null
|
||||
- `bio`: 个人简介,最大 200 字符,可为 null
|
||||
@@ -142,3 +142,10 @@ Base URL: `/api/v1/users`
|
||||
### Response
|
||||
|
||||
`UserContext` 对象。
|
||||
|
||||
---
|
||||
|
||||
## Compatibility Strategy
|
||||
|
||||
- 策略:`backward-compatible`
|
||||
- 本次仅修正文档约束描述与实现一致,不改变接口字段与响应结构。
|
||||
|
||||
Reference in New Issue
Block a user