refactor(*): 稳定期治理 - 收敛核心架构、错误语义并修复跨项目数据竞态
This commit is contained in:
@@ -52,6 +52,15 @@ description: 影策后端核心持久化表与状态边界
|
||||
|
||||
规范化技能包保存在后端数据目录的 `skill-packages/<skill-id>/<version-id>.zip`,数据库只保存索引和版本指针。上传 ZIP 时强制校验 `SKILL.md`、路径越界、软链接、重复路径、文件数量和解压大小;GitHub 技能保存公开仓库、分支、子目录和提交 SHA,后台每 6 小时检查一次开启自动更新的技能,并记录最近检查、同步时间及失败状态。
|
||||
|
||||
## 提示词模板
|
||||
|
||||
| 表 | 用途 | 关键边界 |
|
||||
| --- | --- | --- |
|
||||
| `prompt_templates` | 保存每个操作的平台提示词版本 | `(operation, version)` 唯一;同一操作同一时间只能有一个启用版本;启用中的版本不能直接改文案或停用 |
|
||||
| `user_prompt_customizations` | 保存用户对某个操作的跟随、追加或改写 | `(user_id, operation)` 唯一;只覆盖创作层。任务事实和 JSON 输出契约由 `compilePrompt` 注入,不能写进这张表来绕过 |
|
||||
|
||||
启动时 `EnsureDefaultPromptTemplates` 只为尚无任何版本的操作写入内置默认稿。新增操作(当前包括短剧大纲 `short_drama_outline` 和技能草稿 `skill_draft`)会在下次启动补种,不改已有操作的启用版本。
|
||||
|
||||
## 短剧分镜生产
|
||||
|
||||
| 表 | 用途 | 关键边界 |
|
||||
@@ -80,7 +89,7 @@ description: 影策后端核心持久化表与状态边界
|
||||
| `GET /api/projects/:id/units` | 全部章节摘要与字数,不包含正文 |
|
||||
| `GET /api/projects/:id/units/:unitId` | 单章正文 |
|
||||
| `GET /api/projects/:id/units/:unitId/workspace` | 当前章节的镜头、版本、产物、引用、候选、相关任务和已绑定资产 |
|
||||
| `GET /api/projects/:id/canvases` | 项目画布与当前页章节关联,使用 `page`、`page_size` |
|
||||
| `GET /api/projects/:id/canvases` | 项目画布与当前页章节关联,使用 `page`、`pageSize` |
|
||||
| `GET /api/projects/:id/assets` | 项目资产分页、分类/目录计数,支持分类、媒体类型、目录和关键词筛选 |
|
||||
| `GET /api/projects/:id/asset-candidates` | 资产候选分页,支持章节、状态、分类和名称关键词筛选 |
|
||||
|
||||
|
||||
104
docs/content/docs/backend/code-map.mdx
Normal file
104
docs/content/docs/backend/code-map.mdx
Normal file
@@ -0,0 +1,104 @@
|
||||
---
|
||||
title: 代码功能地图
|
||||
description: 从产品功能快速定位主要代码入口
|
||||
---
|
||||
|
||||
# 代码功能地图
|
||||
|
||||
这是一张入口地图,不罗列所有文件。先找到功能所属层,再沿调用关系阅读。
|
||||
|
||||
## 前端页面
|
||||
|
||||
| 功能 | 页面入口 | 主要协作模块 |
|
||||
| --- | --- | --- |
|
||||
| 首页与导航 | `web/src/pages/home/`、`web/src/layouts/user-layout.tsx` | `components/layout/`、`router.tsx` |
|
||||
| 创作工作台 | `web/src/pages/create/index.tsx` | `creation-workspace.tsx`、`creation-conversations.ts`、`creation-types.ts`、`creation-assets.ts`、`creation-references.ts` |
|
||||
| 登录注册 | `web/src/pages/auth/` | `stores/use-user-store.ts`、`services/api/auth.ts`、后端 `service/linuxdo.go` |
|
||||
| 积分与计费 | `web/src/pages/wallet/`、`pages/admin/components/platform-finance-panel.tsx` | `services/api/wallet.ts`、后端 `service/finance.go`、`repository/finance.go` |
|
||||
| 任务中心 | `web/src/pages/tasks/` | `services/api/task-center.ts`、`services/api/task-text-stream.ts` |
|
||||
| 我的素材 | `web/src/pages/assets/` | `stores/use-asset-store.ts`、`services/image-storage.ts` |
|
||||
| 技能库 | `web/src/pages/skills/` | `services/api/skills.ts`、`services/skill-runtime.ts`、`components/skills/skill-runtime-picker.tsx` |
|
||||
| 画布列表 | `web/src/pages/canvas/index.tsx` | `stores/canvas/use-canvas-store.ts` |
|
||||
| 画布编辑器 | `web/src/pages/canvas/project.tsx` | `pages/canvas/canvas-project-*`、`pages/canvas/use-canvas-*`、`components/canvas/`、`lib/canvas/`、`stores/canvas/` |
|
||||
| 公开分享 | `web/src/pages/canvas/shared.tsx` | `components/canvas/infinite-canvas.tsx`、`services/api/canvas-share.ts` |
|
||||
| 管理后台 | `web/src/pages/admin/`、`router.tsx` | `admin-context.tsx`、`users/`、`channels/`、`logs/`、`storyboard-prompts/`、`settings/` |
|
||||
|
||||
## 画布核心
|
||||
|
||||
| 职责 | 代码位置 |
|
||||
| --- | --- |
|
||||
| 页面装配和跨域动作协调 | `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` |
|
||||
| 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/pages/canvas/use-canvas-agent-operations.ts`、`use-canvas-assistant-visibility.ts`、`use-canvas-director.ts`、`use-canvas-keyboard.ts`;面板容器 `components/canvas/canvas-assistant-panel.tsx`,展示层 `canvas-assistant-panel-views.tsx`,在线工具 `canvas-assistant-online-tools.ts`,影视续写 `canvas-cinematic-continuation.ts` |
|
||||
| 选择拖拽与连线控制 | `web/src/pages/canvas/use-canvas-selection-controller.ts`、`use-canvas-connection-controller.ts` |
|
||||
| 上传、素材插入、媒体工具和短剧编排 | `web/src/pages/canvas/use-canvas-upload.ts`、`use-canvas-timeline-asset-insert.ts`、`use-canvas-media-tools.ts`、`use-canvas-storyboard.ts`、`use-canvas-generation-batches.ts`、`use-canvas-short-drama.ts` |
|
||||
| 节点操作、节点编辑和视口导航 | `web/src/pages/canvas/use-canvas-node-operations.ts`、`use-canvas-node-editor.ts`、`use-canvas-viewport-controller.ts` |
|
||||
| 小说、画风和角色工作流 | `web/src/pages/canvas/use-canvas-document-workflow.ts` |
|
||||
| 派生渲染模型和画布分层 | `web/src/pages/canvas/use-canvas-render-model.ts`、`canvas-project-world-layers.tsx`、`canvas-project-context-menu.tsx`、`canvas-project-status-dialogs.tsx` |
|
||||
| 顶栏、反馈和 screen-space 浮层 | `web/src/pages/canvas/canvas-project-top-bar.tsx`、`canvas-project-feedback.tsx`、`canvas-project-selection-toolbar.tsx`、`components/canvas/canvas-workspace-overlays.tsx` |
|
||||
| 媒体弹窗装配 | `web/src/pages/canvas/canvas-project-media-dialogs.tsx` |
|
||||
| 画布视口、拖拽、缩放和框选 | `web/src/components/canvas/infinite-canvas.tsx`、`web/src/lib/canvas/canvas-live-viewport.ts` |
|
||||
| 节点渲染与节点工具 | `web/src/components/canvas/canvas-node.tsx`、`canvas-node-hover-toolbar.tsx` |
|
||||
| 生成 Composer | `web/src/components/canvas/canvas-node-prompt-panel.tsx`、`canvas-config-composer.tsx` |
|
||||
| 风格中心、用户风格编辑与项目快照 | `web/src/components/canvas/canvas-style-picker-modal.tsx`、`style-profile-editor-modal.tsx`、`style-asset-binding-modal.tsx`、`web/src/lib/canvas/style-profile.ts`、`web/src/services/api/style-profiles.ts` |
|
||||
| 分镜脚本节点 | `web/src/components/canvas/canvas-script-node.tsx` |
|
||||
| 3D 导演台 | `web/src/components/canvas/director/` |
|
||||
| 节点生成上下文 | `web/src/components/canvas/canvas-node-generation.ts` |
|
||||
| 布局和连线算法 | `web/src/lib/canvas/canvas-layout.ts`、`canvas-frame.ts` |
|
||||
| 任务结果回填 | `web/src/lib/canvas/canvas-generation-task-sync.ts` |
|
||||
| 本地持久化状态 | `web/src/stores/canvas/use-canvas-store.ts` |
|
||||
| Agent 会话状态 | `web/src/stores/canvas/use-canvas-agent-store.ts` |
|
||||
| 官方提示词目录与客户端起始稿 | `backend/internal/service/prompt_template.go`、`web/src/lib/prompts/`、`web/src/lib/canvas/canvas-agent-protocol.ts` |
|
||||
|
||||
## 前端 HTTP 与产品壳
|
||||
|
||||
| 职责 | 代码位置 |
|
||||
| --- | --- |
|
||||
| 业务 JSON 调用面 | `web/src/services/api/request.ts` 的 `http`;拦截器仍挂 `apiClient` |
|
||||
| 自定义渠道传输 | `web/src/services/api/channel-transport.ts`,image / video / audio 只组协议 |
|
||||
| 自带外壳的弹窗 / 侧栏 | `web/src/components/ui/product/app-modal/`、`app-drawer/` |
|
||||
|
||||
## 后端调用链
|
||||
|
||||
```text
|
||||
HTTP 请求 -> handler -> service -> repository/model -> SQLite/PostgreSQL 或资源存储
|
||||
|
|
||||
-> provider/outbound -> 模型上游
|
||||
```
|
||||
|
||||
| 功能 | Handler | Service / Repository |
|
||||
| --- | --- | --- |
|
||||
| 路由与中间件 | `handler/api.go`、`handler/routes.go` | `RegisterCanvasAPI` 挂到 `/api`。合同见 `docs/content/docs/backend/http-api.mdx`、`handler/openapi.yaml`。 |
|
||||
| 用户和管理员 | `handler/auth.go` | `service/auth.go`、`service/admin.go` |
|
||||
| 管理后台批量操作 | `handler/auth.go` | `service/admin.go`、`repository/admin_audit.go`、`repository/analytics.go` |
|
||||
| 管理后台存储资源 | `handler/admin_storage.go` | `service/admin_storage.go`、`service/admin_storage_delete.go`、`repository/admin_storage.go`、`repository/admin_storage_delete.go` |
|
||||
| 资源与请求策略 | `handler/auth.go`、`handler/security.go` | `service/runtime_policy.go`、`service/upload_quota.go`、`service/storage_quota.go`、`service/coordination.go` |
|
||||
| 模型响应拦截 | `handler/response_interception.go`、`handler/custom_proxy.go` | `service/response_interception.go`、`repository/repository.go` |
|
||||
| 异步任务、文本 SSE 与 Agent | `handler/routes.go` | `service/service.go`、`service/provider.go`(调度)及 `provider_text.go` / `provider_image.go` / `provider_video.go` / `provider_audio.go` / `provider_http_client.go` / `provider_protocol.go`、`service/task_text_stream.go`、`service/text_replay.go` |
|
||||
| 用户画布与素材 | `handler/user_data.go` | `service/user_data.go`、`service/user_asset_document.go` |
|
||||
| 文件和 OSS | `handler/routes.go` | `service/resource.go`、`service/settings.go` |
|
||||
| 画布分享 | `handler/canvas_share.go` | `service/canvas_share.go` |
|
||||
| 技能库 | `handler/skills.go` | `service/skills.go`、`repository/skills.go` |
|
||||
| 提示词模板 | `handler/auth.go`、`handler/user_data.go` | `service/prompt_template.go`、`service/prompt_template_defaults.go` |
|
||||
| 用户风格库 | `handler/style_profile.go` | `service/style_profile.go`、`repository/style_profile.go` |
|
||||
| 用量分析 | `handler/admin_analytics.go` | `service/analytics.go`、`repository/analytics.go` |
|
||||
|
||||
登录恢复仅初始化当前账号缓存与增量同步会话,不再自动读取 `GET /api/user-data/snapshot`。画布库通过分页摘要加载,打开、导出、重命名时按 ID 读取完整画布,引用素材通过批量 ID 接口读取;旧快照接口仍保留供显式调用。实现见 `service/user_data_page.go` 和前端 `services/user-data-sync.ts`。用户库素材写入(`UpsertUserAsset` / `ReplaceUserAssets`)在 `user_asset_document.go` 校验 SPA 合同:`kind`、`coverUrl`、`tags` 字符串数组,以及按类型完整的 `data`。不完整 payload 在入库时拒绝;GET 仍返回已保存的原始 JSON。上游异构 JSON 的可选字符串仍走 `stringField`;任务 ID 等关键字段走 `firstJSONString`,数字 ID 不再被当成“缺字段”。
|
||||
|
||||
后端托管的文本生成通过 `GET /api/tasks/:id/text-events` 返回 `progress`、`delta` 和 `terminal` 事件。`delta` 的递增事件 ID 是断线续传游标,前端使用 `?after=<id>` 恢复;分镜任务复用该通道实时接收阶段和进度,但分镜结构和 Agent 工具参数仍在完整响应结束并校验通过后原子应用,不执行半截 JSON。
|
||||
|
||||
## 其他入口
|
||||
|
||||
- `canvas-agent/src/`:本地 Agent、MCP 工具和当前画布会话桥接。
|
||||
- `plugins/infinite-canvas/`:Codex App 插件清单与技能。
|
||||
- `docs/content/docs/`:产品、操作、开发和进度文档。
|
||||
- `docker-compose.local.yml`:本地前后端编排;`nginx.conf`:生产静态资源和 API 代理。
|
||||
|
||||
## 修改原则
|
||||
|
||||
- HTTP 参数与响应只在 handler 处理,业务规则进入 service。
|
||||
- 页面保留流程协调;可独立理解和测试的算法进入同业务域的 `lib`。
|
||||
- 新增功能时只更新本页的主要入口,不增加逐文件清单。
|
||||
51
docs/content/docs/backend/http-api.mdx
Normal file
51
docs/content/docs/backend/http-api.mdx
Normal file
@@ -0,0 +1,51 @@
|
||||
---
|
||||
title: HTTP API 合同
|
||||
description: 信封、错误码与 OpenAPI
|
||||
---
|
||||
|
||||
# HTTP API 合同
|
||||
|
||||
路径前缀是 `/api`。前后端一起发布,不按 `/api/v1`、`/api/v2` 做路径版本。不兼容变更随版本一起改接口和调用方。
|
||||
|
||||
机器可读规范:运行中的 `GET /api/openapi.yaml`,源文件 `backend/internal/handler/openapi.yaml`。前端 TypeScript 仍走 `web/src/services/api` 的 `http`,不从 OpenAPI 生成客户端。
|
||||
|
||||
## 信封
|
||||
|
||||
成功:
|
||||
|
||||
```json
|
||||
{ "code": 0, "data": {}, "msg": "ok" }
|
||||
```
|
||||
|
||||
失败:HTTP status 与 `code` 都不是成功;`reason` 是稳定机器可读原因。
|
||||
|
||||
```json
|
||||
{ "code": 40301, "data": null, "msg": "账号素材数量已达到 100 个上限", "reason": "quota_exceeded" }
|
||||
```
|
||||
|
||||
`code === 0` 才是业务成功。HTTP 200 但 `code !== 0` 必须当失败。前端判断类型用 `ApiError.reason` / `ApiError.code`,不要解析 `msg`。
|
||||
|
||||
## 错误码
|
||||
|
||||
`code` 默认等于 HTTP 状态。需要区分同一状态的不同原因时,使用 `status * 100 + n`。没有单独的 1001/2001 号段,以免和 HTTP 状态、现有 42901 以及重试判断打架。
|
||||
|
||||
| code | HTTP | reason | 含义 |
|
||||
| --- | --- | --- | --- |
|
||||
| 0 | 200 | — | 成功 |
|
||||
| 400 | 400 | `invalid_argument` | 请求不合法 |
|
||||
| 401 | 401 | `unauthorized` | 未登录 |
|
||||
| 403 | 403 | `forbidden` | 无权限 |
|
||||
| 404 | 404 | `not_found` | 资源不存在 |
|
||||
| 409 | 409 | `conflict` | 冲突 |
|
||||
| 429 | 429 | `rate_limited` | 限流(未细分) |
|
||||
| 500 | 500 | `internal` | 内部错误 |
|
||||
| 502 | 502 | `bad_gateway` | 上游失败 |
|
||||
| 503 | 503 | `unavailable` | 暂时不可用 |
|
||||
| 504 | 504 | `timeout` | 超时 |
|
||||
| 40301 | 403 | `quota_exceeded` | 账号配额用尽(不自动重试) |
|
||||
| 40901 | 409 | `conflict` | 幂等冲突 |
|
||||
| 42901 | 429 | `rate_limited` | 请求限流(可带 Retry-After) |
|
||||
|
||||
模型错误把已有字符串码放进 `reason`(如 `model_capability_not_supported`),`code` 仍为 400。
|
||||
|
||||
常量:后端 `service/error_codes.go`,前端 `web/src/services/api/error-codes.ts`。
|
||||
@@ -50,10 +50,12 @@ go run ./cmd/server
|
||||
|
||||
```bash
|
||||
cd web
|
||||
bun install
|
||||
bun install --frozen-lockfile
|
||||
bun run dev
|
||||
```
|
||||
|
||||
`web/` 与 `canvas-agent/` 只使用 `bun.lock`。不要用 pnpm 或 npm 往同一套 `node_modules` 里再装一遍。
|
||||
|
||||
前端默认监听 `0.0.0.0:3000`,Vite 将 `/api` 和 OAuth 回调代理到 `127.0.0.1:8080`。如需修改代理目标,可设置 `VITE_API_PROXY_TARGET`。
|
||||
|
||||
## 时间线字幕转写(whisper.cpp)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"defaultOpen": true,
|
||||
"pages": [
|
||||
"local-development",
|
||||
"http-api",
|
||||
"code-map",
|
||||
"backend-database",
|
||||
"task-runtime-stability",
|
||||
|
||||
@@ -71,6 +71,20 @@ SEO 标题、描述、可选关键词会投影到浏览器 metadata、Open Graph
|
||||
- `backend/internal/service/password_reset.go`:发送策略、验证码校验和密码重置业务边界。
|
||||
- `backend/internal/repository/repository.go`:密码更新、验证码消费和登录会话撤销事务。
|
||||
|
||||
## 官方提示词模板
|
||||
|
||||
平台级 LLM 任务只走后端提示词目录,不在页面里手写整段系统指令。运营可在管理后台维护版本,用户可在设置里跟随、追加或改写创作层;动态上下文和 JSON 输出契约由服务端编译时注入,不能被模板或个人偏好覆盖。
|
||||
|
||||
当前操作包括:章节资产提取、分镜规划/修复、分镜首帧、分镜视频、角色卡提取、角色三视图、短剧大纲、技能草稿。短剧一句话生成和技能库 AI 草稿只提交 `promptTemplateOperation` 与变量,占位 prompt 不会成为模型看到的正文。
|
||||
|
||||
画布内置预设、反推提示词、工作流起步稿、文本改写包装、视频操作包装、字幕高亮指令和在线 Agent 协议提示词属于客户端目录 `web/src/lib/prompts` 与 `web/src/lib/canvas/canvas-agent-protocol.ts`。Agent 系统提示词是产品契约,不开放运营改写,避免把工具权限改坏。
|
||||
|
||||
### 相关实现
|
||||
|
||||
- `backend/internal/service/prompt_template.go`、`prompt_template_defaults.go`:操作定义、编译、受保护契约和结果校验。
|
||||
- `web/src/lib/prompts/`:前端操作名、客户端起始/包装提示词和短剧大纲解析。
|
||||
- `web/src/pages/settings/prompt-preferences-pane.tsx`、`web/src/pages/admin/storyboard-prompts/storyboard-prompts-page.tsx`:用户偏好与运营版本。
|
||||
|
||||
## AI 提示词优化器
|
||||
|
||||
提示词优化器是一个内置 AI 能力插件,用于把模糊的生图或生视频想法整理成可以直接使用的提示词。它复用宿主已经配置的文本模型和渠道,不在浏览器中保存或拼接第三方密钥。
|
||||
|
||||
@@ -5,6 +5,169 @@ description: 当前项目已实现功能的手工验证清单与未确认边界
|
||||
|
||||
# 待测试
|
||||
|
||||
## HTTP API 错误码与 OpenAPI
|
||||
|
||||
- 路径仍是 `/api`。不做 `/api/v1` 双挂;前后端一起发布。
|
||||
- 失败信封增加 `reason`。配额是 HTTP 403 / `code` 40301 / `reason=quota_exceeded`,不再用 400。限流是 429 / 42901 / `rate_limited`。
|
||||
- `GET /api/openapi.yaml` 提供 OpenAPI 3.0。不要生成 TS 客户端替换 `http`。
|
||||
- [x] `cd backend && go test ./internal/handler/ ./internal/service/ ./cmd/server/ -count=1`
|
||||
- [x] `cd web && bun test test/api-request.test.ts`
|
||||
- [ ] 登录后走素材库、画布、任务中心:Cookie 仍有效,请求仍打 `/api/...`。
|
||||
- [ ] 打开已有图片/视频资源 URL(`/api/resources/.../file`)仍能加载。
|
||||
- [ ] 文本任务 SSE 与系统渠道流式仍逐条到达。
|
||||
- [ ] 账号配额打满时前端能用 `reason === "quota_exceeded"` 区分,而不是当可重试 429。
|
||||
|
||||
## JSON 字符串类型与素材写入合同
|
||||
|
||||
- 上游 JSON 不再把数字/布尔伪装成空字符串。`optionalJSONString` / `requireJSONString` / `firstJSONString` 在字段类型错误时返回 `expected string, got T`。视频 / 音频 / 声明式协议的任务 ID 走这条路径。
|
||||
- `stringField` 仍用于可选查找(status、error.message、SSE 增量)。缺字段或类型错误对该键视为空,避免异构上游把整段解析打爆。
|
||||
- 用户库素材写入强制 `kind`、`coverUrl`、`tags`(字符串数组)和按类型完整的 `data`。前端 `parseAssetRecord` 拒绝不完整记录,素材库页不再读时 `normalizeAssetRecord`。
|
||||
- 已入库、缺 `tags` 或 `data` 的历史 payload:GET 仍原样返回;登录快照或素材库分页会解析失败。没有读时补丁,需要重新保存或清洗。
|
||||
- [x] `cd backend && go test ./internal/service/ -count=1`
|
||||
- [x] `cd web && bun test test/asset-record.test.ts test/asset-storage-revision.test.ts test/user-scoped-generation-persistence.test.ts`
|
||||
- [ ] 上传/生成一条完整素材后刷新:素材库、画布引用、跨端同步仍可用。
|
||||
- [ ] 用数字 `id` 的视频/音频上游(若有)应看到类型错误,而不是“没有返回任务 ID”。
|
||||
- [ ] 本地 IndexedDB 若仍是缺 `tags` 的旧缓存,打开素材库应失败而不是 tags 变成 `[]`。
|
||||
|
||||
## 巨型文件按能力/容器拆分
|
||||
|
||||
- `provider.go` 只保留调度、水合和共享类型。文本 / 图片 / 视频遗留 / 音频 / HTTP / 声明式协议分别在 `provider_text.go`、`provider_image.go`、`provider_video.go`、`provider_audio.go`、`provider_http_client.go`、`provider_protocol.go`。未导出函数仍同包,测试无需改 import。
|
||||
- 画布助手:容器 `canvas-assistant-panel.tsx`;展示层 `canvas-assistant-panel-views.tsx`;`onlineToolToOps` 在 `canvas-assistant-online-tools.ts`;影视续写边界在 `canvas-cinematic-continuation.ts`。测试仍从面板文件 re-export 取值。
|
||||
- 创作页:`create/index.tsx` 只做提交和会话状态;历史抽屉、Composer、消息视图在 `creation-workspace.tsx`。
|
||||
- 画布页时间线入轨从 `project.tsx` 抽到 `use-canvas-timeline-asset-insert.ts`。页面仍装配工作区 JSX。
|
||||
- [x] `cd backend && go test ./internal/service/ -count=1`
|
||||
- [x] `cd web && bun test test/generation-task-local.test.ts test/user-scoped-generation-persistence.test.ts test/generation-task-materializer.test.ts test/create-library-button.test.ts test/create-canvas-handoff.test.ts`
|
||||
- [ ] 画布在线助手:发一条会改画布的指令、确认工具、影视项目续写/刷新恢复,行为与拆分前一致。
|
||||
- [ ] 创作页空态/对话流、历史抽屉重命名删除、素材库插入仍可用。
|
||||
- [ ] 画布时间线弹窗内从素材库/项目资产插入音视频仍直连入轨;图片仍提示先插入画布。
|
||||
|
||||
## 前端 HTTP 与产品浮层壳
|
||||
|
||||
- 业务 JSON 模块统一走 `http.get/post/put/patch/delete`,不再写 `request(apiClient.*)`。CSV / 诊断包 zip 走 `http.raw`。资源 404 缓存认 `ApiError.status`,不再看已经解包后的 axios 错误。
|
||||
- image / video / audio 渠道请求经 `createChannelTransport`;语音合成走 `postBlob`,避免把音频当 JSON 解析。
|
||||
- 自带外壳的产品弹窗改用 `AppModal flush`;技能编辑和管理员用户详情改用 `AppDrawer`。不要再复制 `padding: 0` 的 Modal styles。
|
||||
- [x] `cd web && bun test test/api-request.test.ts test/http-ownership.test.ts`
|
||||
- [ ] 登录后打开素材库、画布上传、风格选择、技能详情、渠道模型编辑:弹窗主题、关闭、内部滚动与改造前一致。
|
||||
- [ ] 上传资源、导出管理日志 CSV、导出诊断包:仍走同一登录 Cookie,失败文案可读。
|
||||
- [ ] 用音频渠道生成一条语音:应得到音频,而不是 JSON 解析错误。
|
||||
|
||||
## 产品 LLM 任务收进官方提示词目录
|
||||
|
||||
- 短剧一句话生成和技能库 AI 草稿不再把整段指令写在页面里。前端只传 `promptTemplateOperation` 与变量;服务端按启用模板 + 用户偏好编译,并校验 JSON 契约 `short-drama-outline/v1` / `skill-draft/v1`。
|
||||
- 画布预设、反推提示词、工作流起步稿、文本改写、视频操作包装、字幕高亮指令集中在 `web/src/lib/prompts`。在线 Agent 系统提示词和读写工具名单集中在 `canvas-agent-protocol` / `canvas-agent-tools`,在线写门控与本地日志分类共用同一份读工具列表。
|
||||
- 批改管线、提示词优化器、肖像比对等插件内指令仍留在各自模块,下一刀再收。
|
||||
- [x] `go test ./internal/service/ -run 'TestPromptOperationCatalog|TestRenderShortDrama|TestValidatePromptTemplateResultShortDrama|TestValidatePromptTemplateResultSkillDraft|TestValidatePromptTemplateResultCharacter' -count=1`
|
||||
- [x] `cd web && bun test test/prompt-catalog-ownership.test.ts test/canvas-agent-workflow.test.ts`
|
||||
- [ ] 重启后端后,设置 → 提示词偏好和管理后台提示词模板应出现「短剧大纲」「技能草稿」。改平台默认或用户追加后,项目页一句话生成和技能草稿应吃到新文案,JSON 结构仍能导入章节 / 填入编辑器。
|
||||
- [ ] 在线画布助手仍先读上下文再写;本地助手只读工具日志分类不变。画布预设、反推提示词、工作流缺省 prompt 文案与改造前一致。
|
||||
|
||||
## 最小 ESLint 只锁已退场的 AntD API
|
||||
|
||||
- `web` 增加 `bun run lint`。不是风格检查:只禁止再 `import { Empty } from "antd"`,以及静态 `Modal.confirm(`。
|
||||
- 解析器用 `@babel/eslint-parser` + TypeScript preset。`typescript-eslint` 8 在仓库的 TypeScript 7 上会直接拒绝启动,所以没有用它。
|
||||
- CI Quality / Web checks 在 typecheck 之后跑 `bun run lint`。
|
||||
- [x] `cd web && bun run lint`:通过。
|
||||
- [ ] CI 确认 Web checks 出现 lint 步骤且现有 PR 能过。
|
||||
|
||||
## web / canvas-agent 只认 bun.lock
|
||||
|
||||
- 删除遗留的 `web/pnpm-lock.yaml` 和 `canvas-agent/pnpm-lock.yaml`。同一套 `node_modules` 被 pnpm 覆盖过,会把 Tiptap 和 `lightningcss` 装成两套版本。
|
||||
- `web/package.json` 去掉仅给 pnpm 用的 `overrides` 副本,并声明 `packageManager: bun@1.3.9`。仓库内 Canvas Agent 安装/构建改写为 `bun install` / `bun run build`;对外仍用 `npx -y @ddcat666/open-ai-canvas-agent`。
|
||||
- CI 在 `bun install --frozen-lockfile` 之前拒绝 `pnpm-lock.yaml` / `package-lock.json` / `yarn.lock`。
|
||||
- [x] `bun test test/package-manager-lockfile.test.ts`。
|
||||
- [ ] 干净目录执行 `cd web && bun install --frozen-lockfile` 与 `cd canvas-agent && bun install --frozen-lockfile`,不要再用 pnpm/npm 装前端依赖。
|
||||
|
||||
## 确认框与空态退场静态 API
|
||||
|
||||
- 命令式确认不再使用静态 `Modal.confirm`(拿不到 App 主题和上下文)。画布取消任务、方舟素材上传、任务中心删除本机记录改为 `App.useApp().modal.confirm`。行内危险操作仍用 `Popconfirm`。
|
||||
- 全库最后一处 AntD `Empty`(渠道排序弹窗)改为 `EmptyState`。插件中心筛选空态和提示词偏好空列表也接到 `EmptyState`。工作区整页空态仍用 `WorkspaceState`(信号图标),画布引导空态保持产品专用实现。
|
||||
- [x] `bun test test/ui-kit-retirement.test.ts test/channel-presentation.test.tsx test/plugin-state-switch.test.ts`。
|
||||
- [ ] 画布取消进行中任务、上传到方舟素材库:确认框明暗主题与页面一致,确认后仍执行原操作。
|
||||
- [ ] 任务中心删除本机记录:确认框主题正确,只删本机记录不删素材。
|
||||
- [ ] 管理后台渠道「设置排序」在无条目时显示 EmptyState;插件中心清空筛选后的空态可点「清除筛选」。
|
||||
|
||||
## 官方视频 InterfaceType 只走声明式插件
|
||||
|
||||
- `runVideoTask` 对已有官方插件的接口类型不再回退到手写协议。生产注入插件注册表;单测未注入时会补官方包。显式放入空注册表则报「…视频插件未安装」。
|
||||
- 覆盖的接口:`minimax-video`、`gemini-veo`、`novita-video`、`newapi-channel-1`、`newapi-channel-2`、`xai-video`、`volcengine-ark-video`、`volcengine-jimeng-video`、`newapi`、`agnes-video`。任务恢复也只查询声明式 adapter,不再回退 `queryNewAPIChannel2VideoTask`。
|
||||
- 仍保留的手写路径只有:空 InterfaceType 的 OpenAI 风格 multipart `/videos`、模型名含 `grok` 的 JSON `/videos`、BaseURL 含 `/api/plan/v3` 的 Ark Plan、模型名含 seedance 的 Seedance `/videos`。
|
||||
- 插件契约与旧手写实现不一致处按插件为准:MiniMax 时长必须 4–15 秒且不再把 `720`/`1440p` 映射成 `768P`/`2K`;Channel 2 不再做 grok 单图/音频校验;xAI 结果 URL 不可达时不再回退 `/videos/{id}/content`;Channel 1 音频 `type` 跟随宿主 role(当前为 `reference_audio`)。
|
||||
- [x] `go test ./internal/service/ ./internal/protocol/ -count=1`:通过。
|
||||
- [ ] 用 MiniMax / Veo / Novita / NewAPI Channel 1+2 / xAI / 方舟 / 即梦视频各跑一条生成,确认创建、轮询、下载仍走对应官方插件路径。
|
||||
- [ ] 卸掉某个官方视频插件后再提交同类型任务,应看到「…视频插件未安装」,而不是静默改走另一套协议。
|
||||
- [ ] Channel 2 创建后短暂 `task_not_exist` 仍应延期查询,不要二次创建。
|
||||
|
||||
## 列表分页查询改为 page + pageSize
|
||||
|
||||
- 业务列表查询不再使用 `page_size`、`project_id`、`folder_id`、`media_type`、`unit_id` 或管理端 `limit`。查询名和分页响应字段统一为 camelCase:`page`、`pageSize`,以及 `projectId` / `folderId` / `mediaType` / `unitId`。
|
||||
- 技能库列表信封同步改为 `totalCount`、`hasMore`、`nextOffset`、`pageSize`。技能条目、安装表单、技能包文件与 GitHub 安装请求也已改为 camelCase;`createdAt` / `updatedAt` / `lastCheckedAt` / `lastSyncedAt` 为 RFC3339。内置技能种子文件仍是仓库内部 snake_case,读取后转换成对外合同。
|
||||
- Eagle 素材连接器、Dreamina 本地任务和肖像比对仍走对方自己的 `limit`/`offset`,不纳入这次契约。
|
||||
- [ ] 登录后翻页素材库、画布库、项目资产、技能库和积分流水,确认请求查询是 `pageSize` 而不是 `page_size`/`limit`。
|
||||
- [ ] 管理后台用户、渠道、日志、公告、兑换码、计费、支付订单、对账和存储资源列表翻页正常,响应里是 `pageSize`。
|
||||
- [ ] 技能库列表、详情、创建/编辑、ZIP/GitHub 安装:确认接口字段是 `skillId`、`skillName`、`createdAt` 等 camelCase,时间是 ISO 字符串而不是 unix 毫秒。
|
||||
- [ ] 画布 @技能 提及和技能运行时仍能解析已加入技能。
|
||||
|
||||
## 前端测试改为全目录自动发现
|
||||
|
||||
- `web/package.json` 的 `test` 脚本从手工枚举约 100 个文件改为 `bun test`,CI 的 `bun run test` 会跑到此前从未进闸门的用例(含素材弹窗、上传边界、同步文案等)。
|
||||
- 打开闸门前修了过时源码快照,以及:无入边时 `@图片1` 可引用节点自身;账号切换中止进行中请求的测试不再因 localforage 缺驱动而误失败。
|
||||
- [x] `bun test`:全目录应通过。
|
||||
- [ ] CI Quality / Web checks 确认 `bun run test` 覆盖新增文件且无顺序依赖失败。
|
||||
|
||||
## 写路径诚实化(存储直传 / 云端同步 / 计费退款 / 转码终态)
|
||||
|
||||
- 资源直传失败按 `ApiError.retryable` 分类:401/403/400/413 等永久失败当场抛出;429/5xx 与断网允许退回 IndexedDB,由云端同步用同一幂等键重传。UI 不得把 `pendingRemoteUpload` 说成已保存到服务器。
|
||||
- 素材页、素材弹窗还原、批量上传、画布保存在云端同步失败时会排队 `scheduleRemoteUserDataSync`,文案改为「本地已保存,云端同步失败:…将自动重试」。LibTV/TapNow 导入仍只在本地写失败时回滚,云端失败不回滚已写入的节点。
|
||||
- 系统渠道代理:退款或待核对写失败会打进程日志;退款失败会转 `uncertain`,避免订单停在 running。空 `billingOrderID` 不再假装退款。
|
||||
- 播放转码终态回写失败会重试 3 次并打日志;`mark none` 写失败会恢复内存状态,避免前端把空状态当成 processing 轮询。
|
||||
- Responses→Chat Completions 回退只认 404/405/501,不再把 502/503/504 当成“接口不存在”。
|
||||
- [x] `bun test test/resource-upload-boundary.test.ts test/user-data-sync-message.test.ts`;`go test ./internal/service/ -run 'TestShouldFallbackTextToChat|TestPersistPlaybackResource'`。
|
||||
- [ ] 登录后上传一张图时断开后端:应看到本地已保存+将自动重试,而不是“已保存”。恢复后端后素材应出现在云端。
|
||||
- [ ] 用错误密码/过期登录上传:应直接报鉴权失败,文件不应静默进“稍后同步”。
|
||||
- [ ] 画布导入 LibTV 后人为让同步失败:节点保留,出现云端失败提示。
|
||||
- [ ] 系统渠道明确 4xx 后核对计费订单已退款;退款写库失败时订单应进入待核对。
|
||||
|
||||
## 引用素材库弹窗新增媒体类型筛选
|
||||
|
||||
- `AssetLibraryPickerModal` 左侧在「分类」之上新增「媒体类型」分组:全部类型 / 图片 / 视频 / 音频(可选文本)。媒体类型在分类之前收窄数据源,左侧分类计数、网格和分页描述同一批素材。
|
||||
- 新增 `mediaKinds` prop 声明可选类型,只有一种或调用方已用 `remoteKind` 锁定类型时不展示该分组;新增 item 字段 `mediaKind`,缺省时按本地素材或插件素材的 kind 推断,角色卡这类非媒体条目在筛选生效时不出现。
|
||||
- 远端素材库按服务端 `kind` 过滤并重置到第一页;`remoteKind` 仍是调用方的硬约束,媒体筛选不会覆盖它。
|
||||
- 各入口传参:创作首页与项目主图沿用默认/图片单类型;画布插入素材、画布项目资产、短剧制造引用个人素材声明含文本的四类;角色三视图与角色声音已由 `remoteKind` 锁定,不展示分组。
|
||||
- [x] `bun run typecheck`、`bun test test/canvas-asset-picker.test.ts test/create-library-button.test.ts test/asset-ingest.test.ts test/assets-page-batch-toolbar.test.ts`:23 passed。
|
||||
- [ ] 创作首页「参考内容」:切换图片/视频/音频,确认分类计数、网格和分页一致,翻页后筛选保持。
|
||||
- [ ] 画布「插入素材」「项目资产」:确认文本类型可筛选,角色卡在筛选非全部时不出现。
|
||||
- [ ] 短剧制造「引用个人素材」以及角色三视图/声音绑定:确认前者有媒体类型分组、后两者没有。
|
||||
- [ ] 窄屏(≤680px)下左栏横向滚动,媒体类型与分类合并成一排后仍可点选。
|
||||
|
||||
## 画布顶栏提示被生成任务面板遮挡
|
||||
|
||||
- 现象:画布右上角有进行中任务时,顶栏按钮的悬浮提示被「生成任务」面板压住,文字读不全。
|
||||
- 原因:顶栏是 `--z-toolbar`(30) 的绝对定位浮层,会为子元素建立层叠上下文;顶栏提示原来是行内绝对定位、`--dock-tooltip-z`(140) 只在该上下文内生效,实际仍低于 `--z-panel-floating`(80) 的任务面板。提示向下展开的位置又正好落在 `--canvas-topbar-offset`(72px) 的面板顶边。
|
||||
- 修复:`CanvasTopBarTooltip` 改用 Ant Design `Tooltip`(portal 到浮层层级),与专注模式工具栏、节点悬浮工具的提示实现一致;底部 dock 的提示向上展开,不受影响,保持原样。
|
||||
- 视觉变化:顶栏提示改用全局浮层配色(`--popover`),不再是 dock 提示的自定义样式。
|
||||
- [x] `bun run typecheck` 通过。未做浏览器验证:复现需要画布上有进行中的生成任务。
|
||||
- [ ] 登录画布并发起一个生成任务,逐个悬停顶栏按钮,确认提示显示在任务面板之上、明暗主题下都可读。
|
||||
- [ ] 确认菜单类按钮(画布菜单、导入第三方画布、媒体性能)的下拉仍能正常打开。
|
||||
|
||||
## 远端素材未归一化导致的 tags undefined
|
||||
|
||||
- 现象:部分素材的 `tags` 是 `undefined`,首页点击「参考内容」时页面报「当前页面没有正常加载,Cannot read properties of undefined (reading 'join')」。
|
||||
- 原因:素材在服务端是不透明 payload,早期记录没有 `tags` 字段。本地缓存、登录快照和素材库页面都会走 `normalizeAssetRecord`,但 `user-data-sync` 的 `acceptRemoteAssets`(素材选择弹窗分页、按 ID 拉取引用素材)把服务端原样对象直接写进 store。
|
||||
- 修复:`acceptRemoteAssets` 与登录快照都在写入前归一化,并让 acknowledged 基线复用同一份对象。顺带修掉登录时 store 存归一化副本、基线存原始副本导致这些素材被永久标记为待上传的差异。
|
||||
- [x] `bun test test/user-scoped-generation-persistence.test.ts test/asset-storage-revision.test.ts test/asset-remote-sync.test.ts test/canvas-asset-picker.test.ts`:58 passed;`bun run typecheck` 通过。
|
||||
- [ ] 登录后在首页点击「参考内容」,翻页浏览历史素材,确认不再白屏。
|
||||
- [ ] 观察一次同步周期,确认历史素材没有被反复回传服务端。
|
||||
|
||||
## 声明式协议插件丢失系统指令
|
||||
|
||||
- 现象:短剧「AI 生成章节」报「AI 没有返回有效的章节内容,请重试」。上游请求只带一条 user 消息,要求输出 JSON 的系统指令被丢弃,模型返回散文,前端解析不到章节。
|
||||
- 原因:`manifestRequestValues` 构造的 `request.messages` 不包含 `request.instructions`,而 OpenAI 系官方插件(chat-completion、deepseek-chat、atlascloud-chat 等 26 个)只映射 `request.messages`。
|
||||
- 修复:宿主在 `request.messages` 前补一条 system 消息(请求本身已有 system 消息时不重复);`openai-responses` 和 `google-gemini-generate-content` 改为过滤 system 角色,改用各自的 `instructions` / `systemInstruction` 字段,与 `anthropic-messages` 一致。
|
||||
- 需要重新打包并重装的官方插件:`openai-responses`、`google-gemini-generate-content`。其余 OpenAI 系插件只需后端升级,无需重装。
|
||||
- [x] `go test ./internal/protocol/ ./internal/service/`:通过。
|
||||
- [ ] 登录后用 DeepSeek 等 chat-completion 渠道跑「开始一部新短剧 → AI 生成章节」,确认章节正常导入。
|
||||
- [ ] Claude、Gemini、OpenAI Responses 渠道各跑一次文本生成,确认系统指令生效且没有重复出现在正文里。
|
||||
|
||||
## v1.2.8.rc1 候选版本发布
|
||||
|
||||
- 发布版本与镜像标签分别为 `v1.2.8.rc1` 和 `1.2.8.rc1`;GitHub Release 应标记为预发布,不能被当作正式版本推荐,也不覆盖已发布的 `latest`。
|
||||
|
||||
@@ -326,7 +326,7 @@ X-Diagnostic-Bundle-ID: DIAG_8F3K2P
|
||||
X-Diagnostic-Schema-Version: 1
|
||||
```
|
||||
|
||||
由于成功响应是二进制,不经过只处理 JSON 信封的 `request<T>` 解包函数;仍复用现有 `apiClient` 的认证和 Base URL,设置 `responseType: "blob"`。错误响应继续使用统一 `{ code, data, msg }` 语义,前端按响应类型解析。
|
||||
由于成功响应是二进制,不经过 JSON 信封解包;前端用 `http.raw`(同一 `apiClient` 的认证和 Base URL),设置 `responseType: "blob"`。错误响应继续使用统一 `{ code, data, msg }` 语义,前端按响应类型解析。
|
||||
|
||||
### 权限规则
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
- [AI 审美批改画布插件](content/docs/plugins/ai-art-critique.mdx)
|
||||
- [功能](content/docs/overview/features.mdx)
|
||||
- [本地开发](content/docs/backend/local-development.mdx)
|
||||
- [HTTP API 合同](content/docs/backend/http-api.mdx)
|
||||
- [后端数据库](content/docs/backend/backend-database.mdx)
|
||||
- [代码地图](content/docs/backend/code-map.mdx)
|
||||
- [待办](content/docs/progress/todo.mdx)
|
||||
|
||||
Reference in New Issue
Block a user