2025-12-19 客户端冲突管理接入(ConflictManager + UI)
背景
此前客户端在收到服务端广播的 sync-update 后,会直接覆盖本地内容;当本地存在尚未同步(或正在编辑)的修改时,容易出现内容被远端更新“顶掉”的情况,且缺少可视化冲突提示与人工合并入口。
变更内容
- 为客户端 note 状态补齐版本化元数据:
noteVersion/noteTimestamp/noteDeviceId。setNote(note, meta?)支持传入远端version/timestamp/deviceId;本地编辑时仅更新时间戳,noteVersion保持为“最后一次同步基线版本”(仅在收到远端meta.version时更新)。restoreFromHistory与resetConnection同步维护上述字段,保证状态一致。
- 在
useSocket的sync-update流程中接入ConflictManager:- 解密并重组(chunk)出完整远端内容后,基于
lastSyncedHashRef判断本地是否存在未同步改动。 - 若本地无未同步改动,则直接应用远端内容并更新
lastSyncedHashRef。 - 若本地存在未同步改动,则调用
ConflictManager.checkAndHandle(localData, remoteData)检测冲突;需要人工处理时入队冲突。 - 从 hook 暴露
conflictCount/pendingConflicts/resolveConflict/clearConflicts供 UI 使用。 - 在成功发送
pushUpdate后更新lastSyncedHashRef,用于后续“本地是否脏”的判定。
- 解密并重组(chunk)出完整远端内容后,基于
- 在
App.jsx中渲染冲突 UI:- 顶部显示
ConflictIndicator(冲突数量提示,点击打开)。 - 使用
ConflictDialog展示单个冲突并允许用户选择本地/远端或自定义合并。 - 用户解决后调用
resolveConflict,随后将解决后的内容setNote + pushUpdate回推服务端。 - 离开同步链时清理冲突队列。
- 顶部显示
影响范围
- 客户端:
brave-sync-notes/client/src/store/useStore.jsbrave-sync-notes/client/src/hooks/useSocket.jsbrave-sync-notes/client/src/App.jsx
兼容性说明
- 不改变现有 Socket 事件协议字段(仍使用
join-chain/push-update/sync-update/request-sync)。 - 行为变化仅发生在客户端收到远端更新且本地存在未同步改动时:不再盲目覆盖,而是提示冲突并提供人工解决入口。