# 画布多人协作保存扩展需求 > 扩展需求:当前暂不实现。 ## 背景 当前画布编辑器采用单人编辑模型。前端在画布数据变化后通过 debounce 触发保存,请求 `PATCH /api/canvas/projects/[id]`,服务端将画布数据作为整份 JSON 写入 `canvas_projects.data`。 这个机制适合单人场景:用户新增节点、移动节点、编辑 prompt、删除连接等操作后,只需要可靠地把最新画布状态持久化即可。当前保存状态可以继续围绕 HTTP 请求结果展示,例如“保存中”“已同步”“保存失败”。 ## 判断结论 单人保存不需要 WebSocket。现有 HTTP PATCH 自动保存已经能覆盖主要需求,后续更应该优先完善保存状态、错误提示和失败重试。 多人实时协作需要实时通道。WebSocket 适合承载协作者加入、在线状态、光标/选区、画布变更广播和冲突提示,但它只解决消息传输,不自动解决权限、身份、冲突合并和最终落库。 由于项目未来部署形态暂不确定,协作能力应通过 transport adapter 隔离。这样本机或内网 Node 部署可以使用自建 WebSocket server,Serverless 部署可以替换为托管实时服务,而上层画布协作协议保持一致。 ## 第一版目标 - 提供轻量实时协作,而不是严格无冲突协同编辑。 - 广播节点和连接的增删改结果,让其他已打开同一画布的客户端自动同步。 - 广播在线状态、光标位置和选中节点,帮助用户知道其他协作者正在查看或编辑的位置。 - 通过版本号检测基础冲突,避免旧客户端静默覆盖新状态。 - 保留现有 HTTP PATCH 作为最终落库和实时通道不可用时的回退路径。 ## 非目标 - 当前不实现严格 CRDT 或操作日志合并。 - 当前不引入用户登录、权限模型或项目成员体系。 - 当前不改造图片生成任务的 SSE 监听机制。 - 当前不修改数据库 schema、前端画布组件或运行时配置。 ## 未来方案草案 后续实现时,可以为画布项目引入版本字段,例如 `version: number`。客户端提交协作变更时携带 `baseVersion`,服务端仅接受基于当前版本的变更。服务端接受变更后递增版本、写入数据库,并向同一画布房间内的其他客户端广播新的画布状态。 建议的协作事件包括: - `join_canvas`:客户端进入画布,携带 `projectId`、`clientId` 和显示名称。 - `presence`:广播在线协作者、光标位置和选中状态。 - `canvas_patch`:客户端提交画布变更,携带 `baseVersion` 和变更后的画布数据。 - `canvas_state`:服务端确认并广播最新 `version` 和画布数据。 - `conflict`:客户端基于旧版本提交时返回,提示客户端重新同步。 第一版冲突策略可以采用版本号加后写覆盖保护:服务端拒绝旧版本提交,客户端收到 `conflict` 后重新拉取或应用服务端状态。暂不尝试自动合并同一节点字段的并发修改。 ## 测试场景 - 单人保存:新增节点、移动节点、编辑 prompt、删除连接后,保存状态从“保存中”回到“已同步”。 - 双窗口同步:两个窗口打开同一画布,窗口 A 新增节点后,窗口 B 无需刷新即可看到更新。 - 冲突处理:两个窗口基于同一旧版本同时修改,后提交方收到冲突提示,不能静默覆盖服务端状态。 - 断线回退:实时通道断开后,客户端显示离线或错误状态,并可通过 HTTP PATCH 回退保存。 - 生成任务回归:图片生成期间的 loading/result 节点仍能正确保存和同步,现有 SSE 任务监听保持不变。