fix(data): 清理旧数据并保护服务端写入
This commit is contained in:
@@ -476,3 +476,17 @@
|
||||
- HTTPS 先交给云负载均衡、CDN、宿主机证书工具或外层 Nginx 终止;Compose 内置 Nginx 保持 HTTP 反代基线。
|
||||
|
||||
**理由**:Docker Compose 足够覆盖当前单机云服务器和本地服务器形态,部署成本低、可读性强,也符合现阶段 2 核 4G 云主机目标。同域反代能减少 CORS 和公网端口暴露面。本地服务器默认 8080,避免占用 80 端口或要求管理员权限;云服务器继续使用 80 作为外层入口。HTTPS 证书自动续期和域名接入在不同云环境差异较大,先作为外层能力处理,避免把生产部署模板绑死在某一种证书方案上。
|
||||
|
||||
## 39. AppData 文档写入采用乐观锁,先阻止静默覆盖
|
||||
|
||||
**问题**:V2.1 阶段业务数据仍按模块存成 `app_data.value` 整份 JSON 文档。多人同时打开同一模块后,如果 A 和 B 都基于旧副本编辑,原来的无条件 `upsert` 会让后保存的人覆盖先保存的人,尤其是任务、Bug、成员等高频写入数据。
|
||||
|
||||
**决策**:
|
||||
- `GET /api/v1/data/:key` 返回 `version`,由 `AppData.updatedAt.toISOString()` 派生;空文档返回 `version: null`。
|
||||
- 前端 `server-data.ts` 在读取和保存成功后缓存每个 key 的最新 `version`。
|
||||
- 前端保存已读取过的 key 时提交 `{ value, version }`;尚未读取过的兼容路径仍可提交 `{ value }` 走旧式 upsert。
|
||||
- 后端收到字符串 `version` 时使用 `updateMany({ where: { key, updatedAt }, data: { value } })` 原子比较并更新;`count !== 1` 返回 `409 APP_DATA_CONFLICT`。
|
||||
- 后端收到 `version: null` 时只允许创建不存在的行;如果其他客户端已经创建,返回同样的 `409 APP_DATA_CONFLICT`。
|
||||
- 冲突响应返回 `currentVersion` 和 `currentValue`,但当前前端不自动合并、不自动重试,避免把旧本地副本用新版本号再次覆盖服务端数据。
|
||||
|
||||
**理由**:这是 AppData 阶段成本最低、收益最高的一致性补强。它不能提供字段级协同编辑,但能阻止最危险的“静默最后写入覆盖”。后续拆成关系表和领域 API 后,再在具体实体上做更细粒度的事务、唯一约束、审计日志和冲突合并 UI。
|
||||
|
||||
Reference in New Issue
Block a user