fix(canvas): 画布版本 - 合并 PR #528 防止旧内容覆盖并支持历史恢复
将画布 revision CAS 与历史快照接到 schema v23,保留当前顶栏积分弹窗和已有菜单入口。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -23,7 +23,7 @@ description: 影策后端核心持久化表与状态边界
|
||||
|
||||
容器内命令 `migrate-schema up` 应用缺失迁移,`migrate-schema status` 输出当前和期望版本,`migrate-schema verify` 只检查兼容性。`CANVAS_AUTO_MIGRATE=true` 仅用于开发和旧部署兼容;受管生产部署设置为 `false`,并由 Compose 的一次性 `migrate` 服务先完成迁移。后续迁移必须新增版本,不得修改已经发布迁移的实现或校验和。
|
||||
|
||||
当前结构版本为 22。版本 2 为 `schema_migrations.applied_at` 增加 `idx_schema_migrations_applied_at` 索引;版本 3 `asset_taxonomy_candidate_identity` 为资产候选增加规范化名称和来源,收敛资产分类,并为待确认候选建立项目内部分唯一索引;版本 4 `resource_upload_key` 为资源上传幂等补充 `resources.upload_key` 列和用户维度唯一索引;版本 5 `payment_topup` 创建积分充值、支付通知和对账所需结构;版本 6 `resource_playback_variant` 增加资源播放副本状态;版本 7 `asset_library_folders` 增加用户素材自定义分类及 `assets.folder_id`;版本 8 `logical_model_active_code` 将前台模型 code 的唯一约束限定为未归档记录;版本 9 `channel_presentation` 为渠道添加 `public_alias`(默认空字符串)与 `sort_order`(默认 0),为渠道模型添加 `sort_order`(默认 0),不重写既有凭据、价格或能力配置;版本 10 `creation_runtime` 创建创作运行与提交表,并为任务增加可空且唯一的 `creation_submission_id`,旧任务无需伪造提交标识即可继续使用;版本 11 `cloud_agent_runtime` 创建 `cloud_agent_executions`;版本 12 `agent_token_charge_limit` 为账单增加 Agent Token 收费上限;版本 13 `cloud_agent_canvas_mutation` 持久化 Agent 画布变更;版本 14 `cloud_agent_recovery_control` 增加运行恢复控制字段和旧运行回填;版本 15 `agent_profiles` 创建常驻偏好表;版本 16 `agent_lessons` 创建用户记忆表(含分类、路线 JSON、注入/查阅计数);版本 17 `agent_lessons_owner_index` 为 `(author_user_id, status)` 增加复合索引;版本 18 `agent_memory_settings` 创建按用户隔离的压缩周期与最近一次压缩任务状态;版本 19 `payment_plugin_version` 为已有 `payment_provider_configs` 和 `payment_orders` 补上 `plugin_version`,用于把配置和订单钉在具体插件版本上;版本 20 `banner_announcements` 创建首页常驻滚动通知表;版本 21 `banner_announcement_title_runs` 为通知标题增加样式分段;版本 22 `banner_announcement_notice_type` 增加通知类型底色。已发布版本的实现和校验和不得修改。
|
||||
当前结构版本为 23。版本 2 为 `schema_migrations.applied_at` 增加 `idx_schema_migrations_applied_at` 索引;版本 3 `asset_taxonomy_candidate_identity` 为资产候选增加规范化名称和来源,收敛资产分类,并为待确认候选建立项目内部分唯一索引;版本 4 `resource_upload_key` 为资源上传幂等补充 `resources.upload_key` 列和用户维度唯一索引;版本 5 `payment_topup` 创建积分充值、支付通知和对账所需结构;版本 6 `resource_playback_variant` 增加资源播放副本状态;版本 7 `asset_library_folders` 增加用户素材自定义分类及 `assets.folder_id`;版本 8 `logical_model_active_code` 将前台模型 code 的唯一约束限定为未归档记录;版本 9 `channel_presentation` 为渠道添加 `public_alias`(默认空字符串)与 `sort_order`(默认 0),为渠道模型添加 `sort_order`(默认 0),不重写既有凭据、价格或能力配置;版本 10 `creation_runtime` 创建创作运行与提交表,并为任务增加可空且唯一的 `creation_submission_id`,旧任务无需伪造提交标识即可继续使用;版本 11 `cloud_agent_runtime` 创建 `cloud_agent_executions`;版本 12 `agent_token_charge_limit` 为账单增加 Agent Token 收费上限;版本 13 `cloud_agent_canvas_mutation` 持久化 Agent 画布变更;版本 14 `cloud_agent_recovery_control` 增加运行恢复控制字段和旧运行回填;版本 15 `agent_profiles` 创建常驻偏好表;版本 16 `agent_lessons` 创建用户记忆表(含分类、路线 JSON、注入/查阅计数);版本 17 `agent_lessons_owner_index` 为 `(author_user_id, status)` 增加复合索引;版本 18 `agent_memory_settings` 创建按用户隔离的压缩周期与最近一次压缩任务状态;版本 19 `payment_plugin_version` 为已有 `payment_provider_configs` 和 `payment_orders` 补上 `plugin_version`,用于把配置和订单钉在具体插件版本上;版本 20 `banner_announcements` 创建首页常驻滚动通知表;版本 21 `banner_announcement_title_runs` 为通知标题增加样式分段;版本 22 `banner_announcement_notice_type` 增加通知类型底色;版本 23 `canvas_revision_history` 为既有画布回填 `revision = 1` 并新增历史快照与资源引用表。已发布版本的实现和校验和不得修改。
|
||||
|
||||
历史发布曾使用版本 6 `asset_library_folders`,之后合并引入了上述 6/7 顺序冲突。迁移器仅在该历史记录的名称和校验和均精确匹配时选择历史顺序:保留版本 6 的素材目录记录及时间,在版本 7 应用 `resource_playback_variant`,再继续版本 8。新数据库及已采用“6 播放副本、7 素材目录”的数据库保持原顺序;状态检查与启动校验采用同一套识别规则。未知名称、被改动的校验和或冲突的版本 7 记录仍会拒绝迁移,不通过删除、改名或伪造已应用记录绕过检查。
|
||||
|
||||
@@ -31,6 +31,20 @@ description: 影策后端核心持久化表与状态边界
|
||||
|
||||
版本 3 会将 `wardrobe`、`weapon`、`accessory` 迁移为 `prop`,将 `style` 迁移为 `material`,并把原先归入 `other` 的图片、视频、音频和 3D 模型迁移为 `material`。迁移只合并重复的待确认候选:保留最早记录,其余标记为 `ignored`;已经确认的资产不会被自动删除或归并。
|
||||
|
||||
## 画布版本与快照
|
||||
|
||||
| 表 | 用途 | 关键边界 |
|
||||
| --- | --- | --- |
|
||||
| `canvas_projects` | 当前画布内容及递增 `revision`(非空,默认 1) | 客户端新建传 0;后续写入按用户、ID、原版本原子校验,成功才加 1 |
|
||||
| `canvas_snapshots` | 结构 JSON、版本、标题、节点/连线数、字节数、内容时间和备份时间 | `(canvas_id, revision)` 唯一;列表只读摘要,正文按需加载;不复制媒体文件 |
|
||||
| `canvas_snapshot_resources` | 历史快照引用的资源 | `(snapshot_id, resource_id)` 联合主键;资源外键禁止删除被引用记录 |
|
||||
|
||||
浏览器、云端 Agent 和创作任务共用保存事务。内容变化时备份旧内容,普通备份最短间隔 5 分钟,每画布最多保留 20 份;恢复前强制备份当前内容。版本号每次成功写入递增,快照按间隔采样,两者不是一一对应。画布关联项目或解除关联同样推进版本,使旧页面的全量保存失效。
|
||||
|
||||
恢复历史保留当前画布 ID、归属和项目关联,按当前版本做 CAS 后形成新版本;不会把 revision 改回历史值。快照写入、引用保护、恢复和保留数量清理在同一事务内完成。资源删除检查与异步物理删除任务均检查历史引用(包括同对象的资源别名),仍被历史引用的媒体延后回收;删除画布时清理该画布快照及引用。
|
||||
|
||||
升级不改变已有画布正文,也不会凭空产生升级前历史。前后端应一起升级:旧客户端缺少 revision 的保存返回 428,需刷新客户端。
|
||||
|
||||
## 已部署 PostgreSQL 的素材 bytes 修复
|
||||
|
||||
升级到包含修复工具的镜像后,由部署管理员执行一次,无需终端用户修改数据库、清缓存或重建画布。旧镜像不支持以下子命令;请先将部署配置中的镜像版本更新为实际发布的修复版本。此操作不增加表或改变 schema 版本,也不会在启动时静默修改素材。
|
||||
|
||||
@@ -33,6 +33,8 @@ description: 从产品功能快速定位主要代码入口
|
||||
| 页面装配和跨域动作协调 | `web/src/pages/canvas/project.tsx` |
|
||||
| 画布领域规则和生成协议 | `web/src/lib/canvas/canvas-project-domain.ts`、`canvas-project-generation.ts` |
|
||||
| 项目恢复、持久化和项目级动作 | `web/src/pages/canvas/use-canvas-project-lifecycle.ts` |
|
||||
| 云端版本校验与冲突草稿 | `web/src/services/user-data-sync.ts`、`canvas-sync-drafts.ts`、`web/src/lib/canvas/canvas-content.ts`、`web/src/pages/canvas/canvas-sync-status.tsx` |
|
||||
| 历史树与独立只读预览 | `web/src/pages/canvas/canvas-version-history.tsx`、`canvas-version-preview.tsx`;后端 `internal/canvas/canvas_history.go` 与 `repository/canvas_history.go`,Agent 写入桥接在 `app/canvas_bridge.go` |
|
||||
| Patch 历史、生成任务和重试控制 | `web/src/pages/canvas/use-canvas-history.ts`、`use-canvas-generation.ts`、`use-canvas-generation-executor.ts`、`use-canvas-generation-retry.ts` |
|
||||
| 文本、图片、视频和音频生成执行 | `web/src/pages/canvas/canvas-*-generation-executor*.ts` |
|
||||
| 云端 Agent、助手面板、导演台和全局快捷键控制 | `web/src/components/canvas/canvas-cloud-agent-panel.tsx`、`web/src/pages/canvas/use-canvas-assistant-visibility.ts`、`use-canvas-director.ts`、`use-canvas-keyboard.ts`;画布操作契约在 `web/src/lib/canvas/canvas-operation-contract.ts` |
|
||||
|
||||
@@ -9,6 +9,23 @@ description: 信封、错误码与 OpenAPI
|
||||
|
||||
机器可读规范:运行中的 `GET /api/openapi.yaml`,源文件 `backend/internal/handler/openapi.yaml`。前端 TypeScript 仍走 `web/src/services/api` 的 `http`,不从 OpenAPI 生成客户端。
|
||||
|
||||
## 画布保存、历史与恢复
|
||||
|
||||
画布内容使用数据库递增的 `revision` 做乐观并发校验;`updatedAt` 仅用于展示,不作为版本依据。新建 `PUT /canvas-projects/:id` 的 `project.revision` 为 0,已有画布必须带上读取到的版本。数据库在同一次条件更新中匹配 ID、用户与版本,成功后返回 `data.project` 摘要及递增后的版本;缺失版本返回 428,陈旧版本返回 409,非法版本返回 400。客户端不能获取新版号后直接重发旧内容。
|
||||
|
||||
| 接口 | 行为 |
|
||||
| --- | --- |
|
||||
| `GET /canvas-projects/:id` | 返回当前内容及权威版本号 |
|
||||
| `GET /canvas-projects/:id/history` | 返回 `snapshots` 摘要与 `currentRevision`,不批量读取历史正文 |
|
||||
| `GET /canvas-projects/:id/history/:snapshotId` | 按需返回 `snapshot` 摘要和 `project` 历史正文 |
|
||||
| `POST /canvas-projects/:id/history/:snapshotId/restore` | 请求 `{ revision }` 为当前画布版本,成功返回新版本摘要;恢复前强制备份当前内容 |
|
||||
|
||||
历史接口先验证画布归属;无权访问、已删除画布或不存在的快照返回 404。恢复沿用画布写入限流和素材校验,在同一事务完成版本校验、备份、内容写入及历史资源保护。恢复保留当前画布 ID 和项目归属,生成新版本,不倒退版本号。升级前的内容无法补建历史。
|
||||
|
||||
平移和缩放只持久化浏览器视口,内容 PUT 忽略客户端 `viewport` 和 `remoteContentHash`。前端遇到 409/428 会保留账号隔离的本地草稿、暂停该画布自动提交,并提供加载最新版和下载草稿入口;载入最新版前草稿写入失败时停止替换。其他画布仍可保存。
|
||||
|
||||
云端 Agent 与创作任务的写入共用版本和历史事务;Agent `canvasPatch` 携带 `baseRevision`、`revision`,客户端只接受连续增量,跳过重复事件,缺口或同字段冲突时保留草稿并重新核对。删除、重排或顶层内容变化无法由增量完整表示时,事件携带 `requiresRefresh: true` 且不附 `canvasPatch`,客户端完整核对后才推进基线;撤销事件同样触发核对。保存日志仅记录请求/链路 ID、画布/用户 ID、版本、节点数量变化及 HTTP 状态,不记录正文、提示词或媒体 URL。
|
||||
|
||||
## 欢迎页开放配置
|
||||
|
||||
`GET /public/welcome` 无需登录,信封 `data` 仅包含布尔值 `welcomeEnabled`,响应禁用缓存。读取失败按标准错误信封返回。
|
||||
|
||||
Reference in New Issue
Block a user