一页读懂
这份方案做了三件事:把七个竞品逐一复刻并实测,画出它们的 ER 图、表结构、接口清单和 Agent 交互,再吸收各家最有效的做法,得出我们自己的设计(Lumen)。技术看架构、ER、接口与代码;产品看竞品对比与取舍原因。
- 七家后端几乎一样,差别只在入口和外观 → Lumen 只做一个内核,品牌和入口做成配置(D17)。
- 三个最关键的设计:先报价、批准带哈希,不会错扣或重复扣(D2);积分复式账本,先冻结再结算(D3);Agent 产出落成可编辑的项目文档,不留在聊天记录里(D1、D6)。
- 已证明:7 个测试站真实跑通对话与视频生成。未证明:最终技术栈(PostgreSQL + Temporal)还没实现,见“技术方案自审”。
- 怎么读:产品看下面的竞品对比;开工看“我们的最终设计 → 落地指南”;试用看“在线试用与部署”。
七个竞品,各自做对了什么
| 竞品 | 它的做法 | Agent 交互特点 | 我们借鉴 / 不采纳 | 决策 |
|---|---|---|---|---|
| TopView | 商品链接 → 广告片;同一项目有两种编辑模式 | 审批有两种:每次先问(Ask First)/ 始终允许(Always Allow) | Ask First 的审批思路;同项目多视图 | D1 D2 |
| Pollo | 营销批量生成 + 大模板库(63 个技能) | 流式事件,可停止,刷新后恢复 | 事件带序号可续读;模板与技能做成数据 | D8 D9 |
| CreaTok | 缺信息时弹结构化表单;方案是 3 镜头表格 | 只改第 2 镜头,其余不动 | 澄清卡(必填/单选)和镜头局部修改 | D5 D6 |
| Flova | 画布 / 分镜 / 时间轴三视图 | 发送前就提示积分够不够 | 发送前说明准入;三视图共用一份项目 | D1 D7 |
| LibTV | 画布 + 故事板 + Agent;技能社区 | 技能固定版本绑定会话;预算只提醒 | 技能版本固定。不采纳“只提醒不拦截”的预算 | D1 D9 |
| invideo AI | 一句话让 Agent 出片,再进编辑器 | Agent 产物可在编辑器继续改 | Agent 产出落成可编辑对象 | D1 |
| Creatify | URL → 视频,入口最短 | 入口多,内核同一套 | 多个入口汇成同一个“创作意图” | D11 |
“决策”编号对应最终设计里的取舍表(D1–D17),点“我们的最终设计 → 设计取舍与原因”可查每一条。
最终设计:六条原则,每条都有原因
| 原则 | 怎么做 | 为什么好 |
|---|---|---|
| 1. 一个核心,多个入口 | 七家后端结构实测几乎一样(24 张表、55 个接口形状),差别只在入口与外观。 | 内核只做一份,品牌和入口是配置与适配器,新增产品不重写后端。 |
| 2. 对话、画布、时间线共用一份项目文档 | Agent 的产出落成节点(storyboard → scene → shot),不留在聊天记录里。 | 用户改画布,Agent 能看见;只改第 2 镜头不会误伤别的;撤销与版本只做一次。 |
| 3. 先报价,再批准,批准带哈希 | 生成前给带有效期的报价;批准必须带请求哈希与报价哈希;重复批准只返回同一任务。 | 用户看到的价格和提示词,与实际执行的不可能不一致;也不会重复扣费。预算是硬上限,不是提醒。 |
| 4. 积分用复式账本:先冻结,再结算 | 充值、赠送、冻结、结算、释放都是只追加的分录。 | 每一分有来源和去向;失败的任务不会吞积分(明确未受理的失败释放冻结,状态不明的标“待核对”);日额度与积分分开建模。 |
| 5. 缺信息用结构化澄清卡,可恢复 | 运行进入等待状态,下发带 ID 的卡片;提交带卡片哈希,恢复同一个 Run。 | 刷新、断线后卡片还在;答案可校验;重复提交不会恢复两次。 |
| 6. 模型靠“注册表 + 适配器”接入 | 模型、版本、价格、约束放数据里;适配器按 key 注册;每个模型独立 worker。 | 我们实测:加一个模型只需登记一份数据,再起一个带环境变量的独立 worker,核心代码不动;Seedance 2.0 已真实出片。 |
架构
flowchart TB
subgraph Client[客户端]
WEB[Web 工作台<br/>对话 · 画布 · 时间线]
EXT[外部 Agent / MCP / API]
end
subgraph Core[核心服务 Go 模块化单体]
PRJ[项目 · 文档<br/>doc_version]
AGT[Agent 编排接入]
BIL[账务 · 报价 · 冻结]
AST[素材]
INT[创作意图 intent<br/>入口适配器]
end
subgraph Runtime[运行时]
RUN[Agent Runtime Python]
TMP[Temporal 工作流]
GWY[模型网关<br/>注册表 + 适配器]
RND[渲染集群]
end
WEB --> PRJ
WEB --> AGT
EXT --> AGT
AGT --> RUN
INT --> AGT
RUN -->|同一套工具面| PRJ
RUN --> BIL
BIL --> TMP
TMP --> GWY
TMP --> RND
GWY --> M[(视频 / 图片 / 声音模型)]
PRJ --- DB[(PostgreSQL)]
BIL --- DB
AST --- DB一次生成的完整过程
sequenceDiagram autonumber participant U as 用户 participant S as 业务后端 participant A as Agent participant M as 模型适配器 U->>S: 发送前:查额度与准入 U->>S: 发消息(client_action_id) S->>A: 启动 Run A-->>U: 缺信息?经后端下发澄清卡 U->>S: 回答卡片(带卡片哈希) S->>A: 恢复同一个 Run A->>S: 方案落成镜头节点 U->>S: 点“生成”,请求报价 S-->>U: 报价(含有效期与两个哈希) U->>S: 批准(请求哈希 + 报价哈希) S->>S: 冻结积分并建任务 S->>M: 提交生成(幂等键) M-->>S: 结果 / 失败 S->>S: 结算或释放 S-->>U: 事件流(序号可续读)
核心 ER(26 张表,取自最终设计;线上是基数 1:N 一对多、0..1:N 父可选、1:1 一对一,N:M 为多对多;完整的 46 张和逐条关系在“我们的最终设计 → ER 图”)
默认缩放到页面宽度,先看整体结构;点一下图切换到原始大小(看清表名,在框内上下左右滚动),再点一下缩回。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":28,"rankSpacing":60}}}%%
flowchart LR
subgraph sg_tenant["租户与成员"]
direction TB
t_app_user["app_user ◆"]
t_workspace["workspace"]
t_member["⇄ member"]
end
subgraph sg_canvas["画布 · 时间轴(项目文档)"]
direction TB
t_project["project"]
t_project_asset_ref["⇄ project_asset_ref ◆"]
t_node["node"]
t_node_version["node_version"]
t_edge["⇄ edge"]
t_timeline["timeline"]
t_export_job["export_job"]
end
subgraph sg_agent["⭕ Agent 交互"]
direction TB
t_agent_session["agent_session"]
t_agent_run["agent_run"]
t_run_event["run_event"]
t_interaction["interaction"]
t_run_action["run_action ★"]
t_skill["skill ◆"]
t_skill_version["skill_version ◆"]
end
subgraph sg_gen["生成 · 报价批准 · 模型"]
direction TB
t_model_catalog["model_catalog"]
t_model_version["model_version ★"]
t_generation_quote["generation_quote ★"]
t_generation_approval["generation_approval ★"]
t_generation_task["generation_task"]
end
subgraph sg_asset["素材"]
direction TB
t_asset["asset"]
end
subgraph sg_billing["积分账本 · 订阅 · 额度"]
direction TB
t_ledger_entry["ledger_entry"]
t_point_lot["point_lot"]
t_hold["hold"]
end
t_asset -->|"0..1:N"| t_project
t_project -->|"1:N"| t_node
t_node -->|"0..1:N"| t_node
t_node -->|"1:N"| t_node_version
t_asset -->|"0..1:N"| t_node_version
t_generation_task -->|"0..1:N"| t_node_version
t_project -->|"1:N"| t_edge
t_node -->|"1:N"| t_edge
t_node -->|"1:N"| t_edge
t_project -->|"1:N"| t_timeline
t_timeline -->|"1:N"| t_export_job
t_asset -->|"0..1:N"| t_export_job
t_hold -->|"0..1:1"| t_export_job
t_project -->|"1:N"| t_agent_session
t_agent_session -->|"1:N"| t_agent_run
t_agent_run -->|"1:N"| t_run_event
t_agent_run -->|"1:N"| t_interaction
t_project -->|"0..1:N"| t_generation_task
t_node -->|"0..1:N"| t_generation_task
t_agent_run -->|"0..1:N"| t_generation_task
t_model_catalog -->|"0..1:N"| t_generation_task
t_hold -->|"0..1:1"| t_generation_task
t_generation_task -->|"0..1:N"| t_asset
t_point_lot -->|"0..1:N"| t_ledger_entry
t_generation_quote -->|"1:N"| t_generation_approval
t_generation_task -->|"0..1:N"| t_generation_approval
t_model_version -->|"1:N"| t_generation_quote
t_model_catalog -->|"1:N"| t_model_version
t_agent_run -->|"1:N"| t_run_action
t_app_user -->|"1:N"| t_member
t_app_user -->|"1:N"| t_agent_session
t_app_user -->|"1:N"| t_project
t_skill -->|"1:N"| t_skill_version
t_skill -->|"1:N"| t_agent_session
t_agent_run -->|"0..1:N"| t_generation_quote
t_project -->|"1:N"| t_project_asset_ref
t_asset -->|"1:N"| t_project_asset_ref
t_node <-.->|"N:M · 经 edge"| t_node
t_workspace <-.->|"N:M · 经 member"| t_app_user
t_project <-.->|"N:M · 经 project_asset_ref"| t_asset
classDef tenant fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef canvas fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef gen fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef billing fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef platform fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
class t_app_user,t_workspace,t_member tenant
class t_project_asset_ref,t_project,t_node,t_node_version,t_edge,t_timeline,t_export_job canvas
class t_skill,t_skill_version,t_agent_session,t_agent_run,t_run_event,t_interaction,t_run_action agent
class t_model_catalog,t_model_version,t_generation_quote,t_generation_approval,t_generation_task gen
class t_asset asset
class t_point_lot,t_ledger_entry,t_hold billing
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_project_asset_ref,t_member,t_edge junction
style sg_tenant fill:none,stroke:#3b82f6,stroke-width:1px
style sg_canvas fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_agent fill:#fff7ed,stroke:#f97316,stroke-width:4px
style sg_gen fill:none,stroke:#22c55e,stroke-width:1px
style sg_asset fill:none,stroke:#06b6d4,stroke-width:1px
style sg_billing fill:none,stroke:#eab308,stroke-width:1px
linkStyle 13,14,15,16,19,28,30,32,33,34 stroke:#f97316,stroke-width:2.5px核心接口(12 条;完整的 55 条按领域分组,在“我们的最终设计 → 接口清单”)
| 路径 | 作用 | 状态 | |
|---|---|---|---|
| POST | /projects | 新建项目(可带 kind、输入) | 原有 |
| POST | /projects/{id}/sessions | 创建会话(选 skill) | 原有 |
| POST | /sessions/{id}/messages | 请求头 / body 带 client_action_id;返回 202 + run_id;同 ID 不同内容 409 | 调整 |
| GET | /sessions/{id}/events (SSE) | 事件流,支持 Last-Event-ID | 原有 |
| POST | /runs/{id}:stop | 幂等停止;回执 status=terminal_observed | unknown;已输出的文字保存为一条 status=stopped 的助手消息;不承诺供应商侧已取消计费 | 调整 |
| POST | /interactions/{id}:respond | 带 card_sha256;答案按卡片 schema 校验;已恢复过的卡再提交返回原回执 | 调整 |
| POST | /generations:quote | 报价,不扣费;返回 quote_id、request_sha256、quote_sha256、expires_at | 调整 |
| POST | /generations | 批准并创建任务:body 带 quote_id、client_approval_id、两个哈希;重放返回同一任务;报价过期返回 409 quote_expired | 调整 |
| GET | /generations/{id} | 查询任务 | 原有 |
| GET | /billing/balance | 余额、冻结、即将过期 | 原有 |
| GET | /models?capability= | 模型清单:版本、约束、价格表(来自 model_version) | 调整 |
| POST | /projects/{id}/graph:patch | 批量变更节点/边(画布拖拽、Agent 写入) | 原有 |
已实测 / 未实测
- 已实测:七个复刻的登录、新建项目与会话、Agent 对话、停止;七个测试部署(http://119.23.106.60:8101–8107)上:报价→批准→生成成片(Seedance 2.0 Mini,接口级);只在 Pollo 上:扣费入账核对、切换模型、刷新恢复、素材页;多模型(Seedance 2.0 真实出片,新增模型只加数据);聊天图片附件和澄清卡片(Pollo 测试部署上走通)。详见“在线试用与部署”和“技术方案自审”。
- 未做完:附件和澄清卡片尚未在生产启用;澄清卡目前只支持“商品名称”一种。没有一个品牌是完美复刻,见下面的审计结论。
复刻是否完美?审计结论 388 项能力逐项核对,展开查看
复刻是否完美?审计结论(2026-10-19)
没有一个品牌是完美复刻。七个竞品官方资料里列出的 388 项能力,在复刻页上端到端实测跑通的只有 13 项(另有 1 项只在隔离环境跑通),59 项后端有接口但从没在该品牌页面上跑过,308 项复刻里根本没有后端。真正能用的是一条主线:登录 → 新建项目 / 会话 → Agent 对话 → 停止;Pollo 另外跑通了报价 → 批准 → 文生视频、切换模型、刷新恢复、素材页。
为什么不可能做到“完美”:竞品的源码和后端都不公开,能拿到的只有界面、公开文档和自己账号下看到的行为。复刻的前端是按真实页面的可见结构与样式重做的静态页,加一套七个品牌共用的脚本;后端是我们自己的一套实现,七个品牌库的表结构完全相同(各 24 张表)—— 所以各竞品页里的 ER 图和接口清单描述的是“我们的复刻后端”,不是竞品真实的后端。
| 品牌 | 官方能力 | 实测跑通 | 只有通用对话 | 后端有、没跑过 | 没有后端 | 真实页面的控件文字,复刻页找到 | 可点控件 | 点了有效 | 只提示“正在接入” | 没反应 / 只变样式 |
|---|---|---|---|---|---|---|---|---|---|---|
| TopView | 63 | 1 | 0 | 9 | 53 | 15/38(画布编辑器(新建项目后,已登录)) | 51 | 7 | 38 | 3 |
| Pollo | 80 | 5 +1 隔离 | 0 | 5 | 69 | 15/18(首页(已登录)) | 47 | 14 | 28 | 3 |
| invideo AI | 58 | 1 | 1 | 11 | 45 | 17/18(首页(已登录 Agent Two)) | 123 | 20 | 10 | 89 |
| LibTV | 34 | 3 | 2 | 9 | 20 | 29/59(首页(已登录)) | 45 | 15 | 26 | 0 |
| Flova | 63 | 2 | 0 | 18 | 43 | 11/17(首页) | 36 | 7 | 21 | 1 |
| CreaTok | 45 | 1 | 3 | 2 | 39 | 55/65(工作台首页(已登录)) | 78 | 4 | 64 | 2 |
| Creatify | 45 | 0 | 1 | 5 | 39 | 3/20(Agent 首页(已登录)) | 27 | 4 | 15 | 3 |
口径:能力来自各家的功能目录(官方说明、公开代码、实际观察);“实测跑通”只认在该品牌复刻页上真实跑过的记录(真实 Maa、真实生成)。控件对照用的是真实产品已登录时采集的 DOM。“可点控件”是登录后首页上所有可见的按钮、链接和可点元素逐个点击的结果(发送、批准、删除、退出、停止这类不点)。脚本都在下载包的 verification/ 里,可以重跑。
在线试用与部署
- 7 个站各自是一整套独立部署(前端、BFF、Maa 智能体、数据库、生成 worker),地址见下表。
- 注册任意邮箱即可登录对话;生成视频需要先发测试积分(运维脚本 grant_credits.sh)。
- 7 个站都已真实跑通:注册 → Agent 对话 → 停止 → 报价 → 批准 → 出片。
七个复刻站各自是一整套独立部署:自己的前端、BFF、Maa 智能体、MySQL 库(身份库 + 7 个档案库)、Postgres 库(Maa)和 3 个视频生成 worker(Seedance 2.5 / 2.0 Fast / 2.0 Mini)。注册任意邮箱即可试用,测试积分由运维脚本发放。这是测试环境,不对外宣传,页面带 noindex 和“内部复刻研究”标识。
全部代码:all-brands-code.zip · 后端与合同:backend-and-contracts.zip
部署结构
| 层 | 做法 | 原因 |
|---|---|---|
| 入口 | nginx,每个站一个端口:http://119.23.106.60:8101–8107,文档 8108;纯 HTTP,同一页面、同一 BFF | IP 入口使用单独的非 Secure 会话 Cookie(studio_ip_session),仅允许配置里列出的 IP:端口;HTTP 下密码与登录态明文传输,只用于测试 |
| 前端 | 复刻页面原样部署,只改后端地址为同源、加 noindex 与标识;内联图片和字体在部署时外置成按内容寻址的文件 | CreaTok 页面原本 12 MB,服务器出口慢,首屏要 100 秒;外置后 HTML 3.2 MB、2.8 秒 |
| BFF | 同一个 Go 二进制,7 份配置(域名、库名、品牌档案) | 决策 D17:一个共享内核加品牌配置 |
| Maa | 同一个镜像(b75bc95),7 个实例,各连自己的 Postgres 库 | 会话、运行、澄清卡互不串号 |
| 网络 | 每个品牌一个 socat “pod”,BFF 与 Maa 共用它的网络命名空间 | BFF 只接受回环地址的监听、数据库和 Maa 地址 |
| 视频生成 | 每品牌每模型一个 worker,走模型网关;输出只允许火山引擎 TOS 域名 | 与正式环境同一套准入、报价、批准、结算流程 |
| 资源 | 每个容器有内存上限;MySQL 关闭 performance_schema、缓冲池 256 MB | 同机还有原有的 grafana / zabbix,不能被挤掉 |
| 备份 | 每天 04:07 导出 MySQL 与 Postgres,保留 7 天 | 测试数据也要能恢复 |
在部署上实际跑通的流程
| 流程 | 范围 | 结果 |
|---|---|---|
| 注册、登录、建项目、建会话、绑定 Agent 模型、发消息、收到回复 | 7 个站 | 已验证 7/7,回复 14–25 秒 |
| 真实图片生成:报价 → 批准 → 任务 → 出图 | Pollo、TopView、LibTV、CreaTok、Flova,各自的图片入口 | 已验证 5/5 出图 1024×1024,2 积分/张(Qwen-Image 2.1 Turbo) |
| 真实视频生成:报价 → 批准 → 任务 → 成片 | 7 个站,Seedance 2.0 Mini 5 秒 | 已验证 7/7 任务成功,约 2 MB MP4(Pollo 抽检 h264 720×1280 5 秒) |
| 停止正在运行的回复 | Pollo、TopView | 已验证 运行状态变为 cancelled |
| 图片附件参与对话 | Pollo | 已验证 上传红色方图,Agent 回答“红色” |
| 澄清卡:缺信息时提问,回答后同一次运行继续 | Pollo | 已验证 询问 product_name,回答后同一 run 完成 |
| 页面引用的脚本与样式全部存在 | 7 个站 | 已验证 部署前自动校验,缺一个就不发布 |
技术方案自审
用线上部署去检验技术方案:方案里的每条关键决策,在部署上有没有被真实流程证明;部署过程中暴露的问题,哪些已经修掉、哪些留作待办。
- 17 条决策:6 条已验证,5 条部分验证,6 条没有在线验证(多为最终设计独有、复刻站没有的能力)。
- 最大风险:复刻站和最终设计是两套技术栈。复刻证明了交互与业务合同,没证明 PostgreSQL + Temporal 的选型;落地时要在新栈上重跑同一套用例。
- 部署中发现的问题大多已修复;仍待办的是充值对账没验证、最终技术栈没实现。
决策逐条核对
| 编号 | 决策 | 状态 | 依据 |
|---|---|---|---|
| D1 | 一个项目、三种视图共用一份文档 | 未验证 | 部署的是复刻页面,三视图共用一份文档的编辑器没有在线验证。 |
| D2 | 先报价,再批准,批准带哈希 | 已验证 | 每次生成都先报价,批准时带 request_sha256 与 quote_sha256;7 个站都按此流程生成成功。 |
| D3 | 积分用复式账本,先冻结再结算 | 部分验证 | 积分先校验再扣(不足时返回 credits_insufficient);冻结与结算的账本分录没有逐条对账。 |
| D4 | 文字推理成本和媒体成本分开显示 | 未验证 | 界面没有分开展示推理成本和媒体成本。 |
| D5 | 缺信息时用结构化澄清卡 | 已验证 | Pollo 上澄清卡提问、回答后同一次运行继续。 |
| D6 | 方案是结构化实体,不是一大段文字 | 部分验证 | Agent 回复里有分镜方案,但方案没有作为结构化实体落库展示。 |
| D7 | 发送前就说明准入条件 | 部分验证 | 积分不足、模型不可用在提交时就被拒;发送前的提示文案没有逐一检查。 |
| D8 | 事件流带游标,可停止、可恢复 | 部分验证 | 停止已验证;断线后按游标续读事件没有单独测试。 |
| D9 | Skill 与模板有版本,会话固定绑定版本 | 未验证 | Skill / 模板版本绑定没有在部署上验证。 |
| D10 | 模型靠注册表和适配器接入 | 已验证 | 模型来自注册表(studio_media_models):3 个 Seedance 视频模型 + 2 个 Qwen-Image 图片模型,新增图片模型只加数据和 worker;其余 3 个视频模型禁用。 |
| D11 | 不同入口汇成同一个「创作意图」 | 未验证 | 多入口汇成同一“创作意图”没有在线验证。 |
| D12 | 素材归用户,项目只引用 | 部分验证 | 附件以素材 ID 引用已验证;素材归属与项目引用的完整规则没有测试。 |
| D13 | 修订可恢复 | 未验证 | 修订恢复没有在线验证。 |
| D14 | 能力对内外一致:Agent、API、MCP 用同一套工具面 | 未验证 | MCP 对外工具面没有部署。 |
| D15 | 不展示做不到的功能 | 已验证 | 没有后端的入口保持为明确的占位,不假装可用。 |
| D16 | 登录与会话状态要有可见入口 | 已验证 | 未登录、会话过期都有可见入口(Pollo 过期横幅已验证)。 |
| D17 | 一个共享内核加品牌配置,而不是七套代码 | 已验证 | 7 个站是同一个 BFF 二进制和同一个 Maa 镜像,只有配置不同。 |
发现的问题
| 级别 | 问题 | 影响 | 处理 | 状态 |
|---|---|---|---|---|
| 高 | 复刻站和最终设计用的是两套技术栈:复刻站跑在现有的 Go BFF + MySQL + Maa 上,最终设计是 PostgreSQL + Temporal + 模型网关 gRPC。 | 复刻站证明的是交互与业务合同(报价/批准、澄清卡、停止、附件、生成),不能证明最终设计的存储和工作流选型。 | 落地时先在最终栈上实现同一组合同测试(e2e.cjs / gen.cjs 的流程),两边跑同一套用例再切换。 | 待办 |
| 高 | 首次部署只拷贝了部分样式目录,Pollo 有 7 个样式层 404,页面能用但样式不完整。 | 线上效果与本地验收不一致,之前的视觉比对结论对线上不成立。 | 同步时拷贝全部 CSS/JS;新增 check_refs.py,引用缺失就不发布。 | 已修复 |
| 高 | 容器没有内存上限,同机的 grafana / zabbix 可能被挤掉(可用内存一度只剩约 2 GB)。 | 违反“不要动服务器上原来的服务”。 | 所有容器加内存上限;MySQL 关闭 performance_schema、缓冲池 256 MB(1.3 GB 降到 0.4 GB)。 | 已修复 |
| 中 | CreaTok 页面 12 MB(大量内联 base64 图片),服务器出口约 120 KB/s,首屏约 100 秒。 | 试用体验差,容易被误判为站点挂了。 | 开启 gzip;部署时把内联图片和字体外置为按内容寻址的文件并长缓存;页面运行时对素材表做兼容。 | 已修复 |
| 中 | 数据库没有备份。 | 测试数据和会话无法恢复。 | 每日逻辑备份,保留 7 天。 | 已修复 |
| 中 | 测试积分由脚本直接写入授权,没有走支付。 | 计费链路只验证了“报价—冻结—扣减”,没有验证充值与对账。 | 正式环境接支付后补对账测试。 | 待办 |
| 中 | BFF 调 Maa 的服务凭据有效期 365 天(2026-10 签发)。 | 到期后所有站对话会返回 401。 | 每天自动检查凭据和证书到期,剩 30 天写警告,状态公开在 http://119.23.106.60:8108/status.txt;到期前用 issue_service_tokens.sh 重新签发。 | 已修复 |
| 低 | 生成验收脚本读取成片素材 ID 的字段不对,报告为“asset none”;LibTV 有一次成片接口返回 404。 | 成片已生成(任务 succeeded、文件存在),但脚本没有自动核对素材下载。 | 原因是素材 ID 是 32 位十六进制而不是 UUID,加上成片读取比任务完成略晚;脚本已修正并重试,复测 TopView 视频与 5 个站的图片都读到成片。 | 已修复 |
| 中 | 图片生成原先没有接:整条生成链路写死为视频,Image 模式只提示未接入。 | 图片能力无法演示。 | 后端支持图片模型(同一套报价、批准、结算;图片只能是图片任务的产出),接入 Qwen-Image 2.1;5 个有图片入口的站点都能真实出图。 | 已修复 |
| 中 | Agent 运行时界面只显示“Agent is working…”,一轮常常要几分钟(30 多次工具调用),用户看不到进度。 | 容易被当成卡死。 | BFF 新增只读的进度接口(只放出工具名和待办标题,经过隐私过滤),7 个站在输入框上方显示“任务进度 n/m”和当前步骤,与官方 Pollo 一致。 | 已修复 |
| 中 | Pollo 澄清卡没有输入框,答案要在下方输入框里填,但界面没有任何提示。 | 用户以为无法回答。 | 卡片标签旁加说明,输入框加橙色描边和“Enter the product name…”提示;真实界面回答后同一个 Run 继续。 | 已修复 |
| 中 | 交给其他同事的编码 Agent 开发时,接口没有数据结构,仓库里还有一份冲突的旧接口规格。 | 编码 Agent 会被带偏或无从下手。 | 发布 lumen-handoff.zip:OpenAPI 3.1(61 个操作,已校验)、可执行建表脚本、契约、状态机、验收用例、待拍板事项。 | 已修复 |
| 中 | 部署新后端时 28 个容器同时重连,MySQL 超出 1 GB 内存上限被系统杀掉,服务中断约 5 分钟。 | 测试环境短暂不可用。 | MySQL 上限 1.8 GB,最大连接数限到 450(常驻约 280),内存有上界;批量重启分两批。1.6 GB 时又被杀过一次,加连接上限后稳定。 | 已修复 |
| 中 | 二级页面与官方差异大:TopView 画布顶栏积分只显示“积分”、四个工具图标重复、工作区切换器压住按钮;Creatify 项目列表和 Ad Flow 的下拉、按钮、侧栏图标与官方不符。 | 用户一眼看出不是同一个产品。 | BFF 新增只读积分余额接口,画布与 Upgrade 显示真实余额;对照官方截图重做 TopView 画布和 Creatify 项目列表、Ad Flow。 | 已修复 |
| 高 | 服务器出口带宽约 1 Mbps,CreaTok 首页 4.7 MB(单张 PNG 1.8 MB),首屏 39 秒;运行时核对登录的请求排在图片后面超过 15 秒被中止,页面显示“创作服务暂时未准备好”。 | 用户打开 CreaTok 就看到报错,只能刷新。 | 部署时大图转 WebP(宽度最大 1600 px),首屏外的图片懒加载。CreaTok 首屏降到 4.5 秒(0.7 MB),7 个站单独打开都不再出错。 | 已修复 |
| 中 | CreaTok 画布、LibTV 画布、invideo 时间线显示官方采集时的样例项目名;LibTV 画布顶栏还写着“实际AI/生成/支付未接”(生成已接通);新建项目弹窗的按钮被套上首页大按钮样式。 | 看起来不是自己的项目,说明文字与实际不符。 | 三处标题改为当前项目名(未选时显示“未命名项目”/“Untitled project”),去掉过时说明,画布积分显示真实余额;弹窗按钮统一为一行。 | 已修复 |
| 中 | 登录核对请求超过 15 秒就整页报错,只能手动刷新;网络慢或多人同时打开时仍会出现。 | 偶发“创作服务暂时未准备好”。 | 部署时给启动加自动重试(最多 3 次,间隔 2 秒);模拟首个请求挂起 20 秒,页面自动恢复登录,不再报错。 | 已修复 |
| 中 | “我的项目”弹窗只能列项目、不能新建,空账号打开后无路可走(Flova 等);Flova 工作区标题为空、没有积分、项目/会话切换器挤在聊天框底部。 | 新用户走不通。 | 弹窗加“新建项目”按钮(调用运行时自己的新建流程);Flova 工作区显示当前项目名、真实积分,切换器移到项目名旁。 | 已修复 |
| 中 | Flova 工作区“时间线”标签点了没反应;Creatify 视频编辑器左栏图标重复、右上图标是文字符号、积分未显示;Creatify 的项目/会话切换器偶发显示成“ / ”。 | 时间线无法查看;切换器看不出当前项目。 | 时间线标签接到运行时自带的时间线视图,布局与高亮跟随当前视图;编辑器换成独立图标并显示真实积分。切换器空白的原因是运行时把“项目标题”绑定到了 Ad Flow 标题,刷新时清空切换器文字后不再写回;现在文字为空时从同名控件取值补上,连测 3 次都正常。 | 已修复 |
| 高 | Agent 方案里没有消息表,历史只能从事件拼;刷新后恢复不了停止键和写到一半的回复;停止后半截回复丢失。实测 Pollo 与复刻都有这些问题。 | 刷新或停止后,用户看到的和服务端保存的不一致。 | 方案新增 agent_message 表、会话列表 / 快照 / 消息翻页 3 个接口;事件带 session_id 和步骤标题,接流时用 assistant.snapshot 续接;新增 payment_required 卡片;补 9 条验收用例(AGT-11~19)。复刻前后端还没按此改造。 | 进行中 |
| 中 | 复刻的 Agent 回复写法与各竞品不同;聊天区不渲染表格,分镜表显示成一行行竖线。 | 对话内容一眼看出不是同一个产品。 | 每站 maa 拼入按实测整理的回复版式(结构、口吻、结尾),并禁止编造数字和促销;新增 Markdown 渲染(标题、表格、列表、分隔线)。7 站用同一任务对照,结构一致。 | 已修复 |
| 低 | LibTV 首页倒计时每秒改文本,运行时随即重设属性,空闲时每秒约 70 次 DOM 变动。 | 空闲耗电、页面偶有闪动。 | 倒计时数字放进 Shadow DOM,文档级观察器看不到,空闲变动降为 0。 | 已修复 |
| 低 | 6 个统一档案站点的旧会话可能打不开(新会话正常)。 | 只影响部署前创建的会话。 | 保持现状,测试环境不迁移旧数据。 | 接受 |
| 低 | 访问入口改为 IP + 端口的纯 HTTP。 | 密码和登录态明文传输,同一 IP 只能靠端口区分站点。 | BFF 只对配置列出的 IP:端口放行,并给它们单独的非 Secure Cookie;仅作测试环境,不放真实账号。 | 接受 |
没有覆盖的范围
- 并发与压测:每个站只有单用户验收,没有做多用户并发。
- 高可用:单机部署,没有主备;最终设计的单 Region 多可用区方案没有演练。
- 安全:没有做渗透测试;会话 Cookie、CSRF、来源白名单按 BFF 默认配置,未单独审计。
- 各竞品的大部分工具入口(剪辑、模板市场等)仍是占位,复刻程度见各竞品“代码与下载”页的复刻核对。
TopView · 总览
- 它是什么:商品链接 → 广告片;同一项目有两种编辑模式;Agent 交互:审批有两种:每次先问(Ask First)/ 始终允许(Always Allow)。
- 我们借鉴:Ask First 的审批思路;同项目多视图(决策 D1 D2)。
- 复刻现状:4 项已验证,在线试用 http://119.23.106.60:8101/;后端与其余六个品牌共用一套(24 张表、55 个接口),所以 ER / 表结构 / 接口页的通用部分默认折叠。
围绕 Canvas Agent、Drama Studio、Board 和广告工作流,覆盖 3D 镜头预演、团队共编及 API/MCP/Skill/Plugin;另有广告收藏扩展和原生应用。主要证据来自官方公开说明和 API 合同,尚无完整登录媒体实测。
证据:W 官方说明,A 官方接口合同,C 客户端代码,O 实测。“未实测”= 只核对了官方页面,没有上传素材或生成。
63 项,分 12 类
首页(Video Agent / Canvas / Drama Studio)
24 张表 · 34 个外键 · 85 个索引
能力目录
Agent 与场景 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 创作 Agent | 输入想法、脚本、参考视频或商品链接,Agent 规划镜头和生成素材。 | W | 官网产品说明;当前 Agent 登录请求和完整媒体任务未实测。 |
| 场景 Skill | 官方 Skill 覆盖商品短视频、短剧、试穿、痛点广告和电影风格等流程。 | W | 官网列出的内置场景;未逐个调用,场景名称不等于独立模型。 |
| 计划审阅与逐步推进 | Drama Studio 先产出计划,允许修改和批准后再进入分镜与生成。 | W | 官网工作流;批准记录、撤销和失效规则未验证。 |
项目与会话 2 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 结构化剧情工作台 | 大纲、集数、人物、地点、道具、剧本和 beat sheet 可在聊天外编辑。 | W | 官网界面说明;实体键、版本与并发保存协议未知。 |
| Campaign Workspace | 研究、策略和生成资产保留在同一活动工作区,作为后续创作上下文。 | W | 官方说明;持久化对象、Web 项目映射和隔离权限未验证。 |
视频生成 9 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 文生视频与模型比较 | 文字生成视频,可将同一提示词交给多个模型比较结果。 | W | 多模型对比入口已说明;规格、时长与成本依模型变化,未生成。 |
| 图生视频与参考创作 | 图片作为视频起点,并通过参考或提示词控制画面方向。 | W | 官网功能;参考类型和一致性效果未逐模型验证。 |
| 参考动作控制 | 角色图片配参考视频,迁移动作、表情和身体运动。 | W | 未实测 |
| 视频角色全身替换 | 以参考角色替换目标视频中的人物身体,保留动作。 | W | 未实测 |
| 视频放大 | 提升视频分辨率和清晰度。 | W | 未实测 |
| 视频水印移除 | 移除视频中的覆盖标记,可选择处理区域。 | W | 未实测 |
| 视频字幕移除 | 移除已有烧录字幕。 | W | 未实测 |
| 唇形同步 | 官方工具目录提供将人物口型与输入音频匹配的入口。 | W | 官方导航可见入口;具体页面本次访问失败,未验证参数或生成结果。 |
| 视频延长 | 官方 Plugin 提供继续生成已有视频后续内容的工具。 | W | 官网插件说明;Web 独立入口、时长与输出质量未验证。 |
图片生成与编辑 13 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 图片生成与模型比较 | 文字生成图片,可比较不同模型结果并继续编辑。 | W | 未实测 |
| 蒙版局部重绘 | 涂抹需要更改的区域,移除、替换或添加物体。 | W | 官网说明;未测试边缘质量与未选择区域的保持程度。 |
| 图片角度编辑 | 以已有图片为起点调整观察方向或构图。 | W | 未实测 |
| 图片换脸 | 用面部参考替换目标图片中的脸。 | W | 未实测 |
| 图片角色替换 | 以人物参考替换目标照片中的整个人物。 | W | 未实测 |
| 图片放大 | 扩大图片并增强画面清晰度。 | W | 未实测 |
| 图片文字编辑 | 修改图片中已存在的文字内容。 | W | 未实测 |
| 图片重新打光 | 调整人物或物体图片的光照方向与氛围。 | W | 未实测 |
| 商品摄影 | 将商品参考制作成营销展示照片。 | W | 未实测 |
| 图片色板提取 | 从参考图片提取颜色,供后续视觉创作使用。 | W | 未实测 |
| 图片反推提示词 | 根据参考图片生成描述提示词。 | W | 未实测 |
| 图片去背景 | MCP 创作流程提供从图片移除背景的步骤。 | W | 官网示例流程可见;未调用,不确认独立 Web 入口或透明格式。 |
| 图片裁剪 | Plugin 提供裁剪参考图片的工具。 | W | 官网插件说明;尺寸限制和 Web 编辑能力对应未验证。 |
角色与音频 6 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 说话数字人 | 照片或预设角色配文字或音频生成口播视频。 | W | 官网三类入口;角色训练、口型和商品持有关系未亲测,时长上限不跨工具通用。 |
| 多语言配音 | 输入脚本选择语言和音色,生成可用于视频的旁白音频。 | W | 未实测 |
| 声音克隆 | 参考音频用于生成可复用的声音。 | W | 未上传声音;授权、样本要求和支持语言须确认。 |
| 歌曲与背景音乐 | 文字、歌词或音乐参考生成歌曲或纯音乐,并调整风格和情绪。 | W | 官网称可商业使用,但许可范围以条款和素材来源为准;未生成试听。 |
| 商品数字人 | 以商品参考生成数字人展示内容。 | W | 未实测 |
| 自建数字人形象 | 官方提供 Design My Avatar 入口,用于创建自己的角色形象。 | W | 官方入口与页面标题已核实;具体创建输入、角色训练和复用范围未验证。 |
画布与时间轴 7 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 自由画布与场景组织 | 在画布上摆放故事板、参考和生成片段,组织多场景与局部修改。 | W | 官网说明;画布保存、快照、权限和导出协议未知。 |
| 节点连接、分组与导航 | 插件展示节点连接、吸附对齐、分组和 minimap,便于组织创作依赖。 | W | 官网插件说明;当前 Web 与插件的节点 Schema 和功能对应未实测。 |
| 绘制编辑与参考卡片 | Draw to Edit 可标记修改区域,参考卡片可配合裁剪、调色和提示词反推。 | W | 官网工具入口;操作质量与卡片同步一致性未验证。 |
| 剧本到镜头分镜 | 脚本或想法与参考图生成镜头分镜,表达构图、机位和情绪。 | W | 未实测 |
| 分集镜头生产与版本比较 | 按 beat 生成镜头,保留参考与候选版本,再继续生成、后处理和导出。 | W | 官网流程;版本不可变性、输出格式与耗时未实测。 |
| 3D 镜头预演 | 摆放人物和道具,先调整空间位置和相机,再将构图用于生成。 | W | 空间规划是官网能力;不代表生成模型保证人物身份或物理关系。 |
| 可漫游 3D 世界 | 文字、图片或短视频生成可漫游场景,截取机位图返回 Canvas。 | W | 官方说明产物为 Gaussian Splat/SPZ,并非 GLB/STL 网格;未生成或导出。 |
素材与品牌 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 统一 Board 素材库 | 集中管理图片、视频、音频和数字人,供结果检查、比较与复用。 | W | 官网目录说明;Board 页面正文有限,用户级/团队级归属与素材版本未知。 |
| 签名上传与文件检查 | API 先获取上传凭证和 fileId,直传存储后检查上传结果。 | A | 官方合同未调用;链接有效期、上传限制和服务端鉴权未验证。 |
| 团队共享 Brand Kit | 团队套餐支持共享素材库、Board 和 Brand Kit,供成员复用。 | W | 官网 Team 权益;Brand Kit 字段、自动应用范围及权限继承未验证。 |
模板与灵感 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 作品示例和场景模板 | 官网展示营销、短剧、改编、社交和图片设计案例;移动端有一键视频/图片模板。 | W | 公开案例与商店说明;投稿、搜索、互动与模板收费未实测。 |
| 广告灵感与脚本分析 | 官方扩展和移动端提供参考广告收集、灵感查找、脚本分析和改编起点。 | W | 仅官方商店说明;当前广告覆盖、来源条款和自动分析质量未验证。 |
| 浏览器广告收藏与 Board 分享 | 扩展将 TikTok 或 Facebook 广告保存到 Board,官方描述可通过链接分享。 | C | 2026-10-12 静态检查历史 0.0.4 包证实 folder/收藏逻辑;分享来自商店声明。未安装或执行,不输出包内密钥。 |
营销批量创作 5 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 商品链接转广告 | 商品页提取背景后进入 Canvas Agent;可继续改文案、重排镜头、替换画面与字幕。 | W | 官网流程;未访问商品链接或生成,抓取完整性与素材授权未知。 |
| 广告变体与参考改编 | 改变受众、卖点或风格形成 A/B 变体,并有批量电商与参考视频改编流程。 | W | 官方说明;并发、数量上限、失败扣费和批量导出策略未知。 |
| 商品试穿图片 | 将服装商品和人物参考组合,生成穿搭展示。 | W | 未实测 |
| 市场与广告研究 | MCP 提供社交平台与电商信息检索,整理受众痛点、竞品差距和内容方向。 | W | 官网声称覆盖 TikTok、YouTube、Amazon、Shopee;数据授权、时效和覆盖率未验证。 |
| 活动策略和内容 Brief | 研究后形成受众洞察、Message Map、Campaign Plan 和 Content Brief。 | W | 官网工作流;策略准确性与输出 Schema 未调用验证。 |
分享与团队 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| Canvas 与 Storyline 实时共编 | Team 页面明确列出 Canvas、Storyline 实时共编和团队内容访问。 | W | 官方权益声明;未建立团队,编辑冲突协议、版本控制和邀请权限未知。 |
| 团队席位和积分控制 | 团队可管理席位、成员用量和积分控制,并提供发票等管理入口。 | W | 官网套餐说明;管理员角色、审计和结算实现未验证。 |
| 企业身份与共享工作区 | 企业方案列出共享工作区、积分池、管理分析和 SSO/SAML。 | W | 官方销售权益;是否启用、数据条款及身份接入合同须商务确认。 |
订阅与权益 2 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 订阅积分、加购与并发权益 | 个人、团队和企业套餐按积分、并发及附加权益区分。 | W | 不固化动态价格和额度;未购买、升级或验证扣费规则。 |
| Unlimited 与自动化权益边界 | Unlimited 有模型和排队限制,不能等同于 MCP、CLI、API 或自动化不限量。 | W | 官方明确自动化边界;实际账号适用模型和排队条件须确认。 |
开放集成与客户端 7 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 广告任务、脚本候选与导出 API | 提交链接或素材生成广告;可取脚本候选、修改脚本并指定 scriptId 导出。 | A | 官方合同未调用;修改与导出形成独立步骤,不证明当前 Web 使用相同接口。 |
| Board 批量 ZIP 下载 API | 按明确任务或筛选集合发起异步 ZIP 下载,返回 downloadTaskId。 | A | 官方合同未调用;下载任务 TTL、文件权限与完成通知机制未验证。 |
| 远程 MCP 与自然语言工具调用 | 授权后由外部 AI 助手调用研究与创作工具,并管理生成结果。 | W | 未连接;身份、任务失败和工具调用保证未验证。 |
| 官方 Skill 与本地参考文件 | 外部助手通过官方 Skill 调用生成工具,自动上传本地参考并管理结果。 | W | 未安装;支持的客户端、文件上传和状态查询保证未执行验证。 |
| iOS、Android 与移动广告创作 | 官方有双端下载入口;Android 说明商品参考、广告改编、多语言和模板能力。 | W | 未安装;iOS 具体功能、Canvas/3D/企业管理与 Web 同步范围未知。 |
| 官方 Plugin 与 3D 软件工作流 | Plugin 连接外部助手,并提供 Blender、Maya、C4D、3ds Max 等创作流程。 | W | 官方工作流列表;未安装,不推断通用格式兼容或所有软件都有独立原生插件。 |
| 异步视频生成与任务查询 API | 公开合同描述图生视频、文生视频和参考生成任务,结果可关联 Board 记录。 | A | 复用 2026-10-12 已有官方合同研究;本次复查页面访问失败。未调用,不当作现行 Web 实际请求。 |
尚不清楚的部分
- Agent 实际流式协议与会话生命周期:未取得有效登录请求,不能确认 SSE/WebSocket、恢复、Run/Thread Schema 或幂等保证。
- Project、Canvas、Board、Storyline 的实体关系:官网呈现工作台,API 呈现任务与素材;私有持久化、基数、版本和删除规则未验证。
- Canvas 与 Storyline 并发保存协议:官方列出实时共编,但无冲突解决、快照、CAS、离线恢复和回滚实测。
- 数字人训练、音色克隆与内容授权:只有官网能力,未提交人物或音频,授权流程与输出质量未知。
- 完整社区与发布协作:案例、模板、Board 链接存在;投稿、点赞、审批发布、社交平台自动投放未证实。
- iOS 与 Android 的完整 Web 功能对应:官方双端入口与 Android 商店能力可核实,未安装,不能确认 Canvas、3D 和企业功能对应。
竞品技术栈观察
Topview 仅历史 Chrome 扩展 runtime 可确证 React 版本;当前 Web 栈、Nginx、后端与源站未知。官方 plugins/skill 是外部集成资料,不能当生产网站源码。
| 项目 | 观察到的内容 | 状态 | 置信度 |
|---|---|---|---|
| Nginx 产品及准确版本 | 未确认使用 Nginx;准确版本未知。 | unknown | low |
| 浏览器运行语言 | 历史 Chrome 扩展使用 JavaScript;当前 Web 的发布运行时本轮未取得。 | observed | high |
| 前端原始源码语言 | 当前 Web 与历史扩展原始源码语言均未证实;已发布 JS 不能区分 JS/TS/TSX。 | unknown | low |
| 前端框架及版本 | 仅扩展 0.0.4:React 18.2.0;react-dom 18.2.0-next-9e3b772b8-20220608。当前 Web 未知。 | observed | high |
| 构建器、SSR 与渲染模式 | 当前 Web SSR/Bundler 未知;历史扩展可见 ES module 拆包,构建器及版本未披露。 | unknown | low |
| 后端语言 | 未知:当前 Web/API/Agent/生成任务的后端语言均未证实。 | unknown | low |
| 后端框架及版本 | 未知:官方 API/MCP 合同没有证明实际后端框架或其版本。 | unknown | low |
| CDN、边缘与源站界限 | 当前 CDN 与源站未知;本机 198.18.x.x 为保留地址,不能定位服务器。 | unknown | low |
| 前后端仓库与目录关系 | 公开 plugins/skill 仓库是集成资料;生产网站前后端是否同仓、同目录未知。 | unknown | low |
竞品服务调用图
公开 API 主线为签名上传 → 广告预览任务 → 候选脚本修改 → 指定版本导出 → 查询交付。Canvas 和历史扩展另外标注,不把公开合同当作 Web 抓包。
| 节点 | 层 | 职责 | 证据 |
|---|---|---|---|
| API调用方 | client | 按官方合同编排文件、广告任务、脚本与导出请求的调用方。 | A |
| Canvas客户端 | client | 官方 Canvas 产品呈现创作、场景、素材和局部编辑过程。 | W |
| 历史Chrome扩展 | client | 0.0.4 包含广告收藏、目录和 Chrome 消息转发逻辑。 | C |
| 公开API入口 | entry | api.topview.ai 的上传、m2v、脚本、导出与 Board 公开合同边界。 | A |
| Web入口待核实 | entry | 当前 www 域的私有 Web/Agent 接口未取得;旧扩展曾准备调用此域 tRPC 收藏接口。 | U |
| 文件接口职责 | domain | 公开 credential/check 路由提供 fileId、签名 URL 与上传确认。 | A |
| 广告任务职责 | domain | 公开 m2v submit/query 合同组织任务输入和查询身份。 | A |
| 脚本候选职责 | domain | 公开 list/update 路由组织任务内候选与修改内容。 | A |
| 导出处理职责 | runtime | 选择 taskId/scriptId 后产生最终交付,可能有独立于预览的处理阶段。 | I |
| Board接口职责 | domain | 公开 ZIP 打包接口使用 Board 与任务集合,单独返回 downloadTaskId。 | A |
| 异步生成职责 | runtime | 任务提交与后续查询分开,可能有生成调度和异步执行职责。 | I |
| 状态保存职责 | data | 任务和下载作业能按身份查询,可能有持有状态与结果的介质。 | I |
| 签名对象上传 | data | 合同由调用方 PUT 字节至 uploadUrl;S3 是公开文档的具体示例。 | A |
| 模型执行边界 | external | 生成任务合同和 Canvas 说明表明模型生成能力,可能依赖内部或外部模型执行。 | I |
增长与运营机制
复刻状态
| 能力 | 状态 | 依据 |
|---|---|---|
| 工作区条、登录框、新建项目框 | 已验证 | 令牌生效;弹窗背景 #1c1c1c、主按钮 #eee |
| Agent 对话:新建项目与会话、自动选默认模型、发送收回复 | 已验证 | 真实 Maa,收到回复;注意输入框是 contenteditable,脚本直接写 value 无效,需真实输入 |
| 停止回复 | 已验证 | maa_run_stop_actions=terminal_observed,run=cancelled |
| 首页、Canvas、Video Agent 布局 | 已加载 | 沿用早期静态页 |
| 生成视频(报价→批准→成片) | 已验证 | 测试部署 119.23.106.60:8101 上真实生成:Seedance 2.0 Mini 5 秒,报价 3 积分,批准后任务成功、产出 MP4(接口级验证;素材页展示未逐项核对) |
agent-integration/apps-production-brand-v14/topview/candidate-8875-unified-v22.html复刻的架构 七个品牌相同,展开查看
flowchart LR U[浏览器] -->|静态页| FE[品牌前端<br/>令牌 + 通用层 + 运行时脚本] FE -->|/v1/* Cookie + CSRF| BFF[BFF 业务服务 Go] BFF --> MY[(MySQL<br/>共享身份库 + 品牌库)] BFF -->|会话 / 消息 / 事件| MAA[Maa Agent] BFF -->|任务| WK[媒体 worker] WK -->|submit_video| GW[模型网关] GW --> MOD[视频模型] MAA --> GW BFF --> OBJ[(素材 / 导出存储)]
?profile=topview 区分品牌)。品牌差异在前端:令牌(颜色、圆角、字体)、入口与页面结构。TopView · Agent 交互过程
竞品里观察到的
NOT_RUN_COST_GATE 已确认登录工作台与空测试工程;按用户明确“只做明确免费Agent对话、不能花现有积分”的限制,没有发送任何Agent消息。
- 同一项目双编辑模式
- 多会话入口与当前会话积分显示
- @素材及/Skills提示
- Ask First/Always Allow生成策略
- Agent模型成本倍率
- 可编辑文字节点及素材管理器条目
- 独立导出历史
- 项目名称与手工文字持久化
费用与准入
| 项 | 值 |
|---|---|
| selected_model | GPT 5.6 Terra |
| observed_price | 当前模型Cost 2.5x;菜单最低可见GPT-6 Luna Cost 0.1x。仅倍率,无单回合上限。 |
| available_credits | 7.23 |
| exact_per_turn_cost | unknown |
| approval | 用户已明确只做确认零积分费用的Agent对话;本轮不得消耗现有积分,先前10积分预算询问不构成授权。 |
| action_taken | no_send |
| reason | 真实模型菜单显示非零Cost倍率,未有普通文字消息零积分保证;Ask First控制生成许可,不能证明文字推理免费。 |
| free_only_requirement | true |
| zero_credit_cost_confirmed | false |
竞品公开的调用流程
| 步骤 | 调用关系 | 操作 | 证据 |
|---|---|---|---|
| 取得上传身份 | API调用方 → 文件接口 | GET https://api.topview.ai/v1/upload/credential?format=...&needAccelerateUrl=...;请求头 Topview-Uid、Authorization;返回 fileId/uploadUrl。 | A |
| 直传文件字节 | API调用方 → 对象存储 | PUT <返回的 uploadUrl>,Body 为本地文件字节;公开文档示例为 S3 签名 URL。 | A |
| 确认文件可用 | API调用方 → 文件接口 | GET https://api.topview.ai/v1/upload/check?fileId=...;合同示例检查 result=true。 | A |
| 提交预览任务 | API调用方 → 广告接口 | POST https://api.topview.ai/v1/m2v/task/submit;productLink 或 fileIds、preview=true;返回 taskId。 | A |
| 轮询预览结果 | API调用方 → 广告接口 | GET https://api.topview.ai/v1/m2v/task/query?taskId=...&needCloudFrontUrl=...。 | A |
| 审阅修改脚本 | API调用方 → 脚本接口 | GET https://api.topview.ai/v1/m2v/script/list?taskId=...;选择候选后 POST /v1/m2v/script/update,Body:{taskId,scriptId,scriptContents}。 | A |
| 选定版本导出 | API调用方 → 导出接口 | POST https://api.topview.ai/v1/m2v/export;Body:{taskId,scriptId}。 | A |
| 查询最终交付 | API调用方 → 广告接口 | 按 taskId 继续使用 GET https://api.topview.ai/v1/m2v/task/query 查询任务状态与结果;最终资源地址以实际合同响应为准。 | A |
在本品牌复刻上的测试结果
| 能力 | 状态 | 依据 |
|---|---|---|
| Agent 对话:新建项目与会话、自动选默认模型、发送收回复 | 已验证 | 真实 Maa,收到回复;注意输入框是 contenteditable,脚本直接写 value 无效,需真实输入 |
| 停止回复 | 已验证 | maa_run_stop_actions=terminal_observed,run=cancelled |
| 首页、Canvas、Video Agent 布局 | 已加载 | 沿用早期静态页 |
| 生成视频(报价→批准→成片) | 已验证 | 测试部署 119.23.106.60:8101 上真实生成:Seedance 2.0 Mini 5 秒,报价 3 积分,批准后任务成功、产出 MP4(接口级验证;素材页展示未逐项核对) |
复刻里的 Agent 交互设计(时序图、状态机、规则) 七个品牌相同,展开查看
sequenceDiagram
autonumber
participant B as 浏览器
participant S as BFF
participant DB as MySQL
participant M as Maa Agent
participant W as 媒体 worker
participant G as 模型网关
B->>S: POST /projects, /conversations
B->>S: POST maa/binding
S->>DB: maa_bindings dispatching
S->>M: 创建原生会话
M-->>S: native_cid
S->>DB: maa_bindings bound
B->>S: POST maa/messages {client_action_id, content}
S->>DB: maa_message_actions 幂等回执
S-->>B: 202 + run_id
S->>M: 提交消息
S->>DB: maa_runs queued 到 running
loop 事件游标
B->>S: GET runs/{id}/events
S-->>B: assistant.delta / assistant.message
end
M-->>S: run.completed
S->>DB: 记录助手内容 SHA-256
B->>S: POST media/requests/from-maa {source_run_id, sha256}
S-->>B: 报价 + 有效期 + quote_sha256
B->>S: POST approve {client_approval_id, request_sha256, quote_sha256}
S->>DB: 冻结积分 + 建任务
W->>G: submit_video
G-->>W: 视频
W->>DB: 产出入库 + 扣费
B->>S: GET media/jobs/{id}Run 状态机
stateDiagram-v2 [*] --> queued: POST maa/messages 202 queued --> running running --> waiting_interaction: 需要澄清卡 waiting_interaction --> running: respondInteraction running --> completed running --> failed running --> cancelled: stopRun waiting_interaction --> cancelled completed --> [*] failed --> [*] cancelled --> [*]
媒体任务状态机
stateDiagram-v2 [*] --> quoted quoted --> expired: 约 5 分钟 quoted --> approved: approve approved --> held: 冻结积分 held --> queued queued --> running: worker 领取 running --> succeeded: 产出入库 succeeded --> captured: 扣费确认 running --> failed failed --> 待核对: 供应商已受理后失败,冻结保留,界面写「费用待核对」
交互规则
| 环节 | 规则 | 落库 |
|---|---|---|
| 绑定会话 | bindMaa 传 agent_model 或 use_default;先 dispatching,拿到原生会话号后才 bound(约束保证二者一致) | maa_bindings |
| 发消息 | client_action_id 幂等;返回 202 + run_id;同一个动作 ID 内容不同返回 409 | maa_message_actions, maa_runs |
| 事件 | 按 seq 游标读取;服务端先清洗路径、内部地址和令牌再公开 | maa_runs.last_event_seq |
| 完成证据 | 完成时记录助手内容的两份 SHA-256 与字节数 | maa_runs |
| 澄清卡(HITL) | Run 进入 waiting_interaction;respondInteraction 带 card_sha256;不能恢复两次 | maa_interactions, maa_interaction_actions |
| 停止 | stopRun 幂等,回执只说「已观测到终态」;对话里保留「已停止回复」 | maa_run_stop_actions |
| 切换模型 | 必须带 expected_revision;有未决切换时拒绝发新消息 | maa_model_change_actions |
| 生成视频 | from-maa → 报价 → 批准 → 冻结 → worker → 入库 → 扣费;批准带请求哈希与报价哈希 | studio_media_*, 积分账本 |
| 报价过期 | 批准被拒,不建任务不扣费;界面提示重新报价 | studio_media_requests.expires_at |
| 失败后的积分 | 供应商已受理后失败:冻结保留,界面写「费用待核对」,不自动释放;本部署的账本里还没出现过释放分录(12 笔冻结、8 笔扣费、其余 4 笔仍冻结) | studio_credit_ledger_entries |
| 会话过期 | 每 8 秒检查登录状态;失效时横幅提示,登录后恢复 | — |
TopView · ER 图
品牌库 studio_profile_topview:24 张表、34 个真实外键、66 个检查约束、22 个触发器。图由实际表结构生成,箭头从父表指向子表。品牌库与共享身份库之间的 owner_id、asset_id 靠应用层归属检查,不画成外键。
共 61 条关系:一对多 37 条,一对一 10 条,一对多(父可选) 10 条,一对一(父可选) 4 条;多对多 2 组(经关联表)。
用户与登录 素材 积分账本 支付与订阅 模型目录 项目与会话 画布 · 时间轴 · 导出 Agent 交互 生成 · 媒体 · 交付
基数标注(线上的文字,箭头从父表指向子表):1:N 一对多,子表外键必填;0..1:N 一对多,但外键可空,所以父是可选的;1:1 一对一,子表外键上有唯一键;0..1:1 一对一且父可选。红色粗双向线 = N:M 多对多,经带 ⇄ 的关联表(它的主键就是两个外键)。实线 = 数据库真实外键;灰色虚线 = 跨库关系(两个库之间数据库无法建外键,由应用层检查);橙色粗框与粗线 = Agent 交互相关。每张表都带 owner_id(指向用户),为了图清楚没有逐条画线。
全景图:全部实体与关系
默认缩放到页面宽度,先看整体结构;点一下图切换到原始大小(看清表名,在框内上下左右滚动),再点一下缩回。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":26,"rankSpacing":80}}}%%
flowchart LR
subgraph sg_i_user["用户与登录"]
direction TB
t_studio_users["users"]
t_studio_sessions["sessions"]
end
subgraph sg_i_asset["素材"]
direction TB
t_studio_assets["assets"]
end
subgraph sg_i_credit["积分账本"]
direction TB
t_studio_credit_accounts["credit_accounts"]
t_studio_credit_lots["credit_lots"]
t_studio_credit_authorizations["credit_authorizations"]
t_studio_credit_authorization_allocations["⇄ credit_authorization_allocations"]
t_studio_credit_ledger_entries["credit_ledger_entries"]
t_studio_credit_plan_versions["credit_plan_versions"]
t_studio_billing_cycles["billing_cycles"]
end
subgraph sg_i_pay["支付与订阅"]
direction TB
t_studio_payment_orders["payment_orders"]
t_studio_payment_events["payment_events"]
t_studio_subscriptions["subscriptions"]
end
subgraph sg_i_model["模型目录"]
direction TB
t_studio_media_models["media_models"]
t_studio_media_model_versions["media_model_versions"]
end
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_canvas["画布 · 时间轴 · 导出"]
direction TB
t_studio_video_documents["video_documents"]
t_studio_canvases["canvases"]
t_studio_canvas_revisions["canvas_revisions"]
t_studio_timeline_revisions["timeline_revisions"]
t_studio_export_jobs["export_jobs"]
t_studio_project_asset_refs["⇄ project_asset_refs"]
end
subgraph sg_agent["⭕ Agent 交互"]
direction TB
t_maa_bindings["maa_bindings"]
t_maa_runs["maa_runs"]
t_maa_message_actions["maa_message_actions"]
t_maa_interactions["maa_interactions"]
t_maa_interaction_actions["maa_interaction_actions"]
t_maa_model_change_actions["maa_model_change_actions"]
t_maa_run_stop_actions["maa_run_stop_actions"]
end
subgraph sg_media["生成 · 媒体 · 交付"]
direction TB
t_studio_media_requests["media_requests"]
t_studio_media_jobs["media_jobs"]
t_studio_media_submission_attempts["media_submission_attempts"]
t_studio_media_outputs["media_outputs"]
t_generation_jobs["gen_jobs"]
t_generation_reservations["gen_reservations"]
t_generation_deliveries["gen_deliveries"]
t_generation_development_budgets["gen_development_budgets"]
t_studio_credit_recovery_intents["credit_recovery_intents"]
end
t_studio_users -->|"1:N"| t_studio_assets
t_studio_payment_orders -->|"1:1"| t_studio_billing_cycles
t_studio_subscriptions -->|"1:N"| t_studio_billing_cycles
t_studio_users -->|"1:1"| t_studio_credit_accounts
t_studio_credit_authorizations -->|"1:N"| t_studio_credit_authorization_allocations
t_studio_credit_lots -->|"1:N"| t_studio_credit_authorization_allocations
t_studio_credit_accounts -->|"1:N"| t_studio_credit_authorizations
t_studio_credit_authorization_allocations -->|"0..1:N"| t_studio_credit_ledger_entries
t_studio_credit_authorizations -->|"0..1:N"| t_studio_credit_ledger_entries
t_studio_credit_lots -->|"1:N"| t_studio_credit_ledger_entries
t_studio_credit_accounts -->|"1:N"| t_studio_credit_lots
t_studio_billing_cycles -->|"0..1:1"| t_studio_credit_lots
t_studio_payment_orders -->|"0..1:1"| t_studio_credit_lots
t_studio_media_models -->|"1:N"| t_studio_media_model_versions
t_studio_media_model_versions -->|"0..1:1"| t_studio_media_models
t_studio_payment_orders -->|"0..1:N"| t_studio_payment_events
t_studio_subscriptions -->|"0..1:N"| t_studio_payment_events
t_studio_users -->|"1:N"| t_studio_payment_events
t_studio_credit_plan_versions -->|"1:N"| t_studio_payment_orders
t_studio_users -->|"1:N"| t_studio_payment_orders
t_studio_users -->|"1:N"| t_studio_sessions
t_studio_credit_plan_versions -->|"1:N"| t_studio_subscriptions
t_studio_users -->|"1:N"| t_studio_subscriptions
t_generation_jobs -->|"1:1"| t_generation_deliveries
t_studio_projects -->|"1:N"| t_generation_deliveries
t_studio_conversations -->|"1:N"| t_generation_deliveries
t_generation_development_budgets -->|"1:N"| t_generation_jobs
t_studio_projects -->|"1:N"| t_generation_jobs
t_studio_conversations -->|"1:N"| t_generation_jobs
t_generation_jobs -->|"1:1"| t_generation_reservations
t_studio_conversations -->|"1:1"| t_maa_bindings
t_maa_model_change_actions -->|"0..1:1"| t_maa_bindings
t_maa_interactions -->|"1:1"| t_maa_interaction_actions
t_maa_runs -->|"1:N"| t_maa_interactions
t_maa_bindings -->|"1:N"| t_maa_message_actions
t_maa_runs -->|"0..1:N"| t_maa_message_actions
t_maa_bindings -->|"1:N"| t_maa_model_change_actions
t_maa_runs -->|"1:1"| t_maa_run_stop_actions
t_maa_bindings -->|"1:N"| t_maa_runs
t_studio_canvases -->|"1:N"| t_studio_canvas_revisions
t_studio_canvas_revisions -->|"0..1:N"| t_studio_canvas_revisions
t_studio_projects -->|"1:1"| t_studio_canvases
t_studio_projects -->|"1:N"| t_studio_conversations
t_studio_media_jobs -->|"1:N"| t_studio_credit_recovery_intents
t_studio_projects -->|"1:N"| t_studio_export_jobs
t_studio_media_requests -->|"1:1"| t_studio_media_jobs
t_studio_media_jobs -->|"1:N"| t_studio_media_outputs
t_studio_conversations -->|"1:N"| t_studio_media_requests
t_maa_runs -->|"0..1:N"| t_studio_media_requests
t_studio_media_jobs -->|"1:N"| t_studio_media_submission_attempts
t_studio_projects -->|"1:N"| t_studio_project_asset_refs
t_studio_video_documents -->|"1:N"| t_studio_timeline_revisions
t_studio_timeline_revisions -->|"0..1:N"| t_studio_timeline_revisions
t_studio_projects -->|"1:1"| t_studio_video_documents
t_studio_assets -.->|"1:N"| t_studio_project_asset_refs
t_studio_assets -.->|"1:N"| t_studio_media_outputs
t_studio_assets -.->|"1:N"| t_generation_deliveries
t_studio_media_model_versions -.->|"1:N"| t_studio_media_requests
t_studio_media_models -.->|"1:N"| t_studio_media_requests
t_studio_credit_authorizations -.->|"0..1:N"| t_studio_media_jobs
t_studio_credit_authorizations -.->|"0..1:N"| t_studio_credit_recovery_intents
t_studio_credit_authorizations <-.->|"N:M · 经 credit_authorization_allocations"| t_studio_credit_lots
t_studio_projects <-.->|"N:M · 经 project_asset_refs"| t_studio_assets
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_users,t_studio_sessions user
class t_studio_assets asset
class t_studio_credit_accounts,t_studio_credit_lots,t_studio_credit_authorizations,t_studio_credit_authorization_allocations,t_studio_credit_ledger_entries,t_studio_credit_plan_versions,t_studio_billing_cycles credit
class t_studio_payment_orders,t_studio_payment_events,t_studio_subscriptions pay
class t_studio_media_models,t_studio_media_model_versions model
class t_studio_projects,t_studio_conversations project
class t_studio_video_documents,t_studio_canvases,t_studio_canvas_revisions,t_studio_timeline_revisions,t_studio_export_jobs,t_studio_project_asset_refs canvas
class t_maa_bindings,t_maa_runs,t_maa_message_actions,t_maa_interactions,t_maa_interaction_actions,t_maa_model_change_actions,t_maa_run_stop_actions agent
class t_studio_media_requests,t_studio_media_jobs,t_studio_media_submission_attempts,t_studio_media_outputs,t_generation_jobs,t_generation_reservations,t_generation_deliveries,t_generation_development_budgets,t_studio_credit_recovery_intents media
class t_studio_credit_authorization_allocations,t_studio_project_asset_refs junction
style sg_i_user fill:none,stroke:#6b7280,stroke-width:1px,stroke-dasharray:5 4
style sg_i_asset fill:none,stroke:#06b6d4,stroke-width:1px,stroke-dasharray:5 4
style sg_i_credit fill:none,stroke:#eab308,stroke-width:1px,stroke-dasharray:5 4
style sg_i_pay fill:none,stroke:#ec4899,stroke-width:1px,stroke-dasharray:5 4
style sg_i_model fill:none,stroke:#6366f1,stroke-width:1px,stroke-dasharray:5 4
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_canvas fill:none,stroke:#3b82f6,stroke-width:1px
style sg_agent fill:#fff7ed,stroke:#f97316,stroke-width:4px
style sg_media fill:none,stroke:#22c55e,stroke-width:1px
linkStyle 30,31,32,33,34,35,36,37,38,48 stroke:#f97316,stroke-width:2.5px
linkStyle 54,55,56,57,58,59,60 stroke:#64748b,stroke-width:1.5px,stroke-dasharray:4 3
linkStyle 61,62 stroke:#dc2626,stroke-width:3px多对多(N:M)
数据库里没有“多对多”这种列,它总是靠一张关联表表达。下面这几张表的主键由两个外键组成,所以它们两端是多对多:
| 多对多的两端 | 关联表 | 关联表的主键 / 唯一键 |
|---|---|---|
studio_credit_authorizations ⇄ studio_credit_lots | studio_credit_authorization_allocations | owner_id, authorization_id, lot_id |
studio_projects ⇄ studio_assets | studio_project_asset_refs | project_id, asset_id |
Agent 交互相关(圈出来)
绑定 → Run → 消息 / 澄清卡 / 切换模型 / 停止,每个动作一张回执表;线上是“外键列 · 基数”。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":40,"rankSpacing":90}}}%%
flowchart LR
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_agent["⭕ Agent 交互"]
direction TB
t_maa_bindings["maa_bindings"]
t_maa_runs["maa_runs"]
t_maa_message_actions["maa_message_actions"]
t_maa_interactions["maa_interactions"]
t_maa_interaction_actions["maa_interaction_actions"]
t_maa_model_change_actions["maa_model_change_actions"]
t_maa_run_stop_actions["maa_run_stop_actions"]
end
t_studio_conversations -->|"conversation_id · 1:1"| t_maa_bindings
t_maa_model_change_actions -->|"pending_model_change_id · 0..1:1"| t_maa_bindings
t_maa_interactions -->|"interaction_id · 1:1"| t_maa_interaction_actions
t_maa_runs -->|"public_run_id · 1:N"| t_maa_interactions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_message_actions
t_maa_runs -->|"public_run_id · 0..1:N"| t_maa_message_actions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_model_change_actions
t_maa_runs -->|"public_run_id · 1:1"| t_maa_run_stop_actions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_runs
t_studio_projects -->|"project_id · 1:N"| t_studio_conversations
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_projects,t_studio_conversations project
class t_maa_bindings,t_maa_runs,t_maa_message_actions,t_maa_interactions,t_maa_interaction_actions,t_maa_model_change_actions,t_maa_run_stop_actions agent
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_agent fill:#fff7ed,stroke:#f97316,stroke-width:4px
linkStyle 0,1,2,3,4,5,6,7,8 stroke:#f97316,stroke-width:2.5px画布与时间轴
项目下是一份视频文档,画布、画布版本、时间线版本和导出都挂在这份文档上;素材放在共享身份库,项目只记引用,项目与素材是多对多,经 project_asset_refs。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":40,"rankSpacing":90}}}%%
flowchart LR
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_canvas["画布 · 时间轴 · 导出"]
direction TB
t_studio_video_documents["video_documents"]
t_studio_canvases["canvases"]
t_studio_canvas_revisions["canvas_revisions"]
t_studio_timeline_revisions["timeline_revisions"]
t_studio_export_jobs["export_jobs"]
t_studio_project_asset_refs["⇄ project_asset_refs"]
end
subgraph sg_asset["素材(共享身份库)"]
direction TB
t_studio_assets["assets"]
end
t_studio_canvases -->|"project_id · 1:N"| t_studio_canvas_revisions
t_studio_canvas_revisions -->|"restored_from_revision · 0..1:N"| t_studio_canvas_revisions
t_studio_projects -->|"project_id · 1:1"| t_studio_canvases
t_studio_projects -->|"project_id · 1:N"| t_studio_conversations
t_studio_projects -->|"project_id · 1:N"| t_studio_export_jobs
t_studio_projects -->|"project_id · 1:N"| t_studio_project_asset_refs
t_studio_video_documents -->|"project_id · 1:N"| t_studio_timeline_revisions
t_studio_timeline_revisions -->|"restored_from_revision · 0..1:N"| t_studio_timeline_revisions
t_studio_projects -->|"project_id · 1:1"| t_studio_video_documents
t_studio_assets -.->|"asset_id · 1:N"| t_studio_project_asset_refs
t_studio_projects <-.->|"N:M · 经 project_asset_refs"| t_studio_assets
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_projects,t_studio_conversations project
class t_studio_video_documents,t_studio_canvases,t_studio_canvas_revisions,t_studio_timeline_revisions,t_studio_export_jobs,t_studio_project_asset_refs canvas
class t_studio_assets asset
class t_studio_project_asset_refs junction
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_canvas fill:none,stroke:#3b82f6,stroke-width:1px
style sg_asset fill:none,stroke:#06b6d4,stroke-width:1px
linkStyle 9 stroke:#64748b,stroke-width:1.5px,stroke-dasharray:4 3
linkStyle 10 stroke:#dc2626,stroke-width:3px关系清单 逐条 61 条,含基数
| 父表 | 子表 | 外键列(子表里) | 基数 | 约束 | 域 |
|---|---|---|---|---|---|
generation_jobs | generation_deliveries | job_id | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_assets | generation_deliveries | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 生成 · 媒体 · 交付 |
studio_conversations | generation_deliveries | owner_id, project_id, session_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_projects | generation_deliveries | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
generation_development_budgets | generation_jobs | owner_id, budget_id | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_conversations | generation_jobs | owner_id, project_id, session_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_projects | generation_jobs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
generation_jobs | generation_reservations | job_id, budget_id, owner_id | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
maa_model_change_actions | maa_bindings | owner_id, project_id, conversation_id, id, pending_model_change_id | 0..1:1 一对一(父可选) | DB 外键 | Agent 交互 → Agent 交互 |
studio_conversations | maa_bindings | owner_id, project_id, conversation_id | 1:1 一对一 | DB 外键 | 项目与会话 → Agent 交互 |
maa_interactions | maa_interaction_actions | owner_id, project_id, conversation_id, binding_id, public_run_id, interaction_id | 1:1 一对一 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_interactions | owner_id, project_id, conversation_id, binding_id, public_run_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_message_actions | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_message_actions | owner_id, project_id, conversation_id, binding_id, public_run_id | 0..1:N 一对多(父可选) | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_model_change_actions | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_run_stop_actions | owner_id, project_id, conversation_id, binding_id, public_run_id | 1:1 一对一 | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_runs | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
studio_users | studio_assets | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 素材 |
studio_payment_orders | studio_billing_cycles | owner_id, payment_order_id, plan_version_id | 1:1 一对一 | DB 外键 | 支付与订阅 → 积分账本 |
studio_subscriptions | studio_billing_cycles | owner_id, subscription_id, provider_key, provider_account | 1:N 一对多 | DB 外键 | 支付与订阅 → 积分账本 |
studio_canvas_revisions | studio_canvas_revisions | owner_id, project_id, kind, restored_from_revision | 0..1:N 一对多(父可选) | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_canvases | studio_canvas_revisions | owner_id, project_id | 1:N 一对多 | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_projects | studio_canvases | owner_id, project_id | 1:1 一对一 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_projects | studio_conversations | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 项目与会话 |
studio_users | studio_credit_accounts | owner_id | 1:1 一对一 | DB 外键 | 用户与登录 → 积分账本 |
studio_credit_authorizations | studio_credit_authorization_allocations | owner_id, authorization_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_lots | studio_credit_authorization_allocations | owner_id, lot_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_accounts | studio_credit_authorizations | owner_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_authorization_allocations | studio_credit_ledger_entries | owner_id, authorization_id, lot_id | 0..1:N 一对多(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_authorizations | studio_credit_ledger_entries | owner_id, authorization_id | 0..1:N 一对多(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_lots | studio_credit_ledger_entries | owner_id, lot_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_billing_cycles | studio_credit_lots | owner_id, source_cycle_id | 0..1:1 一对一(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_accounts | studio_credit_lots | owner_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_payment_orders | studio_credit_lots | owner_id, source_order_id | 0..1:1 一对一(父可选) | DB 外键 | 支付与订阅 → 积分账本 |
studio_credit_authorizations | studio_credit_recovery_intents | authorization_id | 0..1:N 一对多(父可选) | 跨库(应用层检查) | 积分账本 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_credit_recovery_intents | owner_id, project_id, conversation_id, job_id, request_sha256 | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_projects | studio_export_jobs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_credit_authorizations | studio_media_jobs | credit_authorization_id | 0..1:N 一对多(父可选) | 跨库(应用层检查) | 积分账本 → 生成 · 媒体 · 交付 |
studio_media_requests | studio_media_jobs | owner_id, project_id, conversation_id, request_id, request_sha256, quote_sha256 | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_media_models | studio_media_model_versions | model_id | 1:N 一对多 | DB 外键 | 模型目录 → 模型目录 |
studio_media_model_versions | studio_media_models | id, published_version_id | 0..1:1 一对一(父可选) | DB 外键 | 模型目录 → 模型目录 |
studio_assets | studio_media_outputs | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_media_outputs | owner_id, project_id, conversation_id, job_id | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
maa_runs | studio_media_requests | owner_id, project_id, conversation_id, source_binding_id, source_run_id | 0..1:N 一对多(父可选) | DB 外键 | Agent 交互 → 生成 · 媒体 · 交付 |
studio_conversations | studio_media_requests | owner_id, project_id, conversation_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_media_model_versions | studio_media_requests | model_version_id | 1:N 一对多 | 跨库(应用层检查) | 模型目录 → 生成 · 媒体 · 交付 |
studio_media_models | studio_media_requests | model_id | 1:N 一对多 | 跨库(应用层检查) | 模型目录 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_media_submission_attempts | owner_id, project_id, conversation_id, job_id, request_sha256 | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_payment_orders | studio_payment_events | owner_id, order_id, provider_key, provider_account | 0..1:N 一对多(父可选) | DB 外键 | 支付与订阅 → 支付与订阅 |
studio_subscriptions | studio_payment_events | owner_id, subscription_id, provider_key, provider_account | 0..1:N 一对多(父可选) | DB 外键 | 支付与订阅 → 支付与订阅 |
studio_users | studio_payment_events | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_credit_plan_versions | studio_payment_orders | plan_version_id | 1:N 一对多 | DB 外键 | 积分账本 → 支付与订阅 |
studio_users | studio_payment_orders | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_assets | studio_project_asset_refs | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 画布 · 时间轴 · 导出 |
studio_projects | studio_project_asset_refs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_users | studio_sessions | user_id | 1:N 一对多 | DB 外键 | 用户与登录 → 用户与登录 |
studio_credit_plan_versions | studio_subscriptions | plan_version_id | 1:N 一对多 | DB 外键 | 积分账本 → 支付与订阅 |
studio_users | studio_subscriptions | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_timeline_revisions | studio_timeline_revisions | owner_id, project_id, kind, restored_from_revision | 0..1:N 一对多(父可选) | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_video_documents | studio_timeline_revisions | owner_id, project_id | 1:N 一对多 | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_projects | studio_video_documents | owner_id, project_id | 1:1 一对一 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
完整 ER:39 张表的全部列,带主键 / 外键与基数符号(鸦脚)
erDiagram
studio_assets {
CHAR id PK
CHAR owner_id FK
CHAR sha256
JSON metadata_json
VARCHAR storage_key
DATETIME created_at
VARCHAR publication_state
}
studio_billing_cycles {
CHAR id PK
CHAR owner_id FK
CHAR subscription_id FK
CHAR plan_version_id FK
CHAR payment_order_id FK
VARCHAR provider_key FK
VARCHAR provider_account FK
VARCHAR provider_invoice_id
DATETIME period_start
DATETIME period_end
BIGINT_UNSIGNED grant_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
VARCHAR state
CHAR paid_evidence_sha256
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_accounts {
CHAR owner_id PK
VARCHAR unit
VARCHAR status
BIGINT_UNSIGNED revision
DATETIME updated_at
}
studio_credit_authorization_allocations {
CHAR owner_id FK
CHAR authorization_id PK
CHAR lot_id PK
BIGINT_UNSIGNED allocated_credits
DATETIME created_at
}
studio_credit_authorizations {
CHAR id PK
CHAR owner_id FK
VARCHAR profile
CHAR project_id
CHAR conversation_id
CHAR job_id
CHAR request_id
CHAR request_sha256
CHAR quote_sha256
BIGINT_UNSIGNED credits
DATETIME expires_at
MEDIUMBLOB reservation_bytes
CHAR reservation_sha256
MEDIUMBLOB policy_bytes
CHAR policy_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_ledger_entries {
CHAR id PK
CHAR owner_id FK
CHAR lot_id FK
CHAR authorization_id FK
VARCHAR operation_key
VARCHAR kind
BIGINT grant_delta
BIGINT held_delta
BIGINT captured_delta
MEDIUMBLOB facts_bytes
CHAR facts_sha256
DATETIME created_at
}
studio_credit_lots {
CHAR id PK
CHAR owner_id FK
BIGINT_UNSIGNED grant_credits
BIGINT_UNSIGNED held_credits
BIGINT_UNSIGNED captured_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
CHAR source_order_id FK
CHAR source_cycle_id FK
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_plan_versions {
CHAR id PK
VARCHAR plan_key
VARCHAR version_key
VARCHAR kind
BIGINT_UNSIGNED price_minor
CHAR currency
BIGINT_UNSIGNED grant_credits
INT_UNSIGNED credit_validity_seconds
INT_UNSIGNED billing_interval_months
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
DATETIME published_at
DATETIME retired_at
}
studio_media_model_versions {
CHAR id PK
CHAR model_id FK
VARCHAR version_key
MEDIUMBLOB config_bytes
CHAR config_sha256
DATETIME published_at
}
studio_media_models {
CHAR id PK
VARCHAR model_key
VARCHAR kind
VARCHAR display_name
VARCHAR status
CHAR published_version_id FK
BIGINT_UNSIGNED revision
DATETIME updated_at
}
studio_payment_events {
CHAR id PK
CHAR owner_id FK
VARCHAR provider_key FK
VARCHAR provider_account FK
VARCHAR provider_event_id
CHAR order_id FK
CHAR subscription_id FK
MEDIUMBLOB body_bytes
CHAR body_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_payment_orders {
CHAR id PK
CHAR owner_id FK
CHAR client_action_id
CHAR plan_version_id FK
BIGINT_UNSIGNED price_minor
CHAR currency
BIGINT_UNSIGNED grant_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
VARCHAR provider_key
VARCHAR provider_account
VARCHAR provider_idempotency_key
VARCHAR provider_order_id
VARCHAR state
CHAR paid_evidence_sha256
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_sessions {
CHAR token_hash PK
CHAR user_id FK
DATETIME created_at
DATETIME expires_at
DATETIME revoked_at
}
studio_subscriptions {
CHAR id PK
CHAR owner_id FK
VARCHAR provider_key
VARCHAR provider_account
VARCHAR provider_subscription_id
CHAR plan_version_id FK
VARCHAR state
DATETIME period_start
DATETIME period_end
TINYINT cancel_at_period_end
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_users {
CHAR id PK
VARCHAR email
VARBINARY password_hash
TINYINT enabled
DATETIME created_at
}
generation_deliveries {
CHAR job_id PK
CHAR owner_id FK
CHAR project_id FK
CHAR session_id FK
CHAR asset_id FK
CHAR request_sha256
CHAR maa_source_sha256
CHAR provider_source_sha256
VARCHAR model
VARCHAR tool_name
CHAR input_sha256
JSON metadata_json
DATETIME created_at
}
generation_development_budgets {
CHAR id PK
CHAR owner_id
VARCHAR policy_version
BIGINT_UNSIGNED credits_limit
BIGINT_UNSIGNED credits_reserved
INT_UNSIGNED calls_limit
INT_UNSIGNED calls_reserved
DATETIME expires_at
}
generation_jobs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR session_id FK
CHAR native_conversation_id
CHAR native_run_id
CHAR source_sha256
CHAR budget_id FK
MEDIUMBLOB request_bytes
CHAR request_sha256
BIGINT_UNSIGNED credits
DATETIME expires_at
VARCHAR status
INT_UNSIGNED attempts
MEDIUMBLOB result_bytes
DATETIME updated_at
}
generation_reservations {
CHAR job_id PK
CHAR budget_id FK
CHAR owner_id FK
BIGINT_UNSIGNED credits
INT_UNSIGNED calls
VARCHAR status
}
maa_bindings {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR provider
VARCHAR model_name
VARCHAR status
VARCHAR native_cid
DATETIME created_at
BIGINT_UNSIGNED model_revision
CHAR pending_model_change_id FK
}
maa_interaction_actions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR interaction_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_iid
CHAR client_action_id
CHAR card_sha256
CHAR request_sha256
CHAR content_sha256
VARCHAR response_action
JSON values_payload
VARCHAR status
DATETIME created_at
}
maa_interactions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_iid
CHAR card_sha256
JSON card_payload
DATETIME created_at
}
maa_message_actions {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR client_action_id
CHAR request_sha256
MEDIUMTEXT content
VARCHAR status
CHAR public_run_id FK
CHAR proposed_run_id
DATETIME created_at
}
maa_model_change_actions {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_cid
CHAR client_action_id
CHAR request_sha256
CHAR native_request_sha256
BIGINT_UNSIGNED expected_revision
VARCHAR from_provider
VARCHAR from_model_name
VARCHAR target_provider
VARCHAR target_model_name
VARCHAR status
BIGINT_UNSIGNED dispatch_attempt
JSON receipt_payload
DATETIME created_at
DATETIME updated_at
}
maa_run_stop_actions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_cid
VARCHAR native_rid
CHAR client_action_id
CHAR request_sha256
VARCHAR stop_action
VARCHAR status
BIGINT_UNSIGNED attempt
VARCHAR terminal_run_status
DATETIME created_at
DATETIME updated_at
}
maa_runs {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_rid
VARCHAR status
DATETIME created_at
CHAR native_assistant_sha256
CHAR public_assistant_sha256
BIGINT_UNSIGNED native_assistant_bytes
BIGINT_UNSIGNED assistant_event_seq
BIGINT_UNSIGNED last_event_seq
}
studio_canvas_revisions {
CHAR owner_id PK
CHAR project_id PK
VARCHAR kind PK
BIGINT_UNSIGNED revision PK
MEDIUMBLOB state_bytes
CHAR state_sha256
VARCHAR origin
BIGINT_UNSIGNED restored_from_revision FK
DATETIME recorded_at
}
studio_canvases {
CHAR project_id PK
CHAR owner_id FK
BIGINT_UNSIGNED revision
JSON state_json
DATETIME updated_at
}
studio_conversations {
CHAR id PK
CHAR project_id FK
CHAR owner_id FK
VARCHAR title
DATETIME created_at
}
studio_credit_recovery_intents {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
CHAR request_sha256 FK
CHAR quote_sha256
VARCHAR kind
CHAR authorization_id FK
MEDIUMBLOB intent_bytes
CHAR intent_sha256
VARCHAR state
CHAR lease_token_sha256
DATETIME lease_until
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_export_jobs {
CHAR id PK
CHAR project_id FK
CHAR owner_id FK
BIGINT_UNSIGNED document_revision
CHAR input_hash
VARCHAR status
JSON input_json
JSON output_json
VARCHAR error_code
CHAR lease_token_hash
DATETIME lease_until
INT_UNSIGNED attempts
DATETIME created_at
DATETIME updated_at
}
studio_media_jobs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR request_id FK
CHAR request_sha256 FK
CHAR quote_sha256 FK
CHAR client_approval_id
CHAR approval_sha256
CHAR credit_authorization_id FK
VARCHAR authorization_mode
DATETIME authorization_expires_at
VARCHAR status
BIGINT_UNSIGNED revision
CHAR lease_token_sha256
DATETIME lease_until
VARCHAR provider_task_id
CHAR client_cancel_id
CHAR cancel_request_sha256
DATETIME cancel_requested_at
CHAR staged_asset_id
CHAR staged_asset_sha256
DATETIME created_at
DATETIME updated_at
}
studio_media_outputs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
INT_UNSIGNED ordinal
CHAR asset_id FK
CHAR asset_sha256
CHAR asset_metadata_sha256
CHAR provider_result_sha256
DATETIME created_at
}
studio_media_requests {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR client_request_id
CHAR model_id FK
CHAR model_version_id FK
CHAR model_config_sha256
MEDIUMBLOB request_bytes
CHAR request_sha256
MEDIUMBLOB quote_bytes
CHAR quote_sha256
BIGINT_UNSIGNED quoted_credits
DATETIME expires_at
VARCHAR origin
CHAR source_binding_id FK
CHAR source_run_id FK
CHAR source_assistant_sha256
MEDIUMBLOB source_snapshot_bytes
DATETIME created_at
}
studio_media_submission_attempts {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
INT_UNSIGNED attempt_no
CHAR request_sha256 FK
VARCHAR provider_idempotency_key
VARCHAR stage
DATETIME dispatch_started_at
VARCHAR provider_task_id
CHAR receipt_sha256
CHAR terminal_receipt_sha256
CHAR reconciliation_sha256
DATETIME created_at
DATETIME updated_at
}
studio_project_asset_refs {
CHAR project_id PK
CHAR owner_id FK
CHAR asset_id PK
CHAR asset_sha256
CHAR asset_metadata_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
DATETIME detached_at
}
studio_projects {
CHAR id PK
CHAR owner_id
VARCHAR title
DATETIME created_at
}
studio_timeline_revisions {
CHAR owner_id PK
CHAR project_id PK
VARCHAR kind PK
BIGINT_UNSIGNED revision PK
MEDIUMBLOB state_bytes
CHAR state_sha256
VARCHAR origin
BIGINT_UNSIGNED restored_from_revision FK
DATETIME recorded_at
}
studio_video_documents {
CHAR project_id PK
CHAR owner_id FK
BIGINT_UNSIGNED revision
JSON state_json
DATETIME updated_at
}
studio_users ||--o{ studio_assets : "owner_id"
studio_payment_orders ||--o| studio_billing_cycles : "plan_version_id"
studio_subscriptions ||--o{ studio_billing_cycles : "provider_account"
studio_users ||--o| studio_credit_accounts : "owner_id"
studio_credit_authorizations ||--o{ studio_credit_authorization_allocations : "authorization_id"
studio_credit_lots ||--o{ studio_credit_authorization_allocations : "lot_id"
studio_credit_accounts ||--o{ studio_credit_authorizations : "owner_id"
studio_credit_authorization_allocations |o--o{ studio_credit_ledger_entries : "lot_id"
studio_credit_authorizations |o--o{ studio_credit_ledger_entries : "authorization_id"
studio_credit_lots ||--o{ studio_credit_ledger_entries : "lot_id"
studio_credit_accounts ||--o{ studio_credit_lots : "owner_id"
studio_billing_cycles |o--o| studio_credit_lots : "source_cycle_id"
studio_payment_orders |o--o| studio_credit_lots : "source_order_id"
studio_media_models ||--o{ studio_media_model_versions : "model_id"
studio_media_model_versions |o--o| studio_media_models : "published_version_id"
studio_payment_orders |o--o{ studio_payment_events : "provider_account"
studio_subscriptions |o--o{ studio_payment_events : "provider_account"
studio_users ||--o{ studio_payment_events : "owner_id"
studio_credit_plan_versions ||--o{ studio_payment_orders : "plan_version_id"
studio_users ||--o{ studio_payment_orders : "owner_id"
studio_users ||--o{ studio_sessions : "user_id"
studio_credit_plan_versions ||--o{ studio_subscriptions : "plan_version_id"
studio_users ||--o{ studio_subscriptions : "owner_id"
generation_jobs ||--o| generation_deliveries : "job_id"
studio_projects ||--o{ generation_deliveries : "project_id"
studio_conversations ||--o{ generation_deliveries : "session_id"
generation_development_budgets ||--o{ generation_jobs : "budget_id"
studio_projects ||--o{ generation_jobs : "project_id"
studio_conversations ||--o{ generation_jobs : "session_id"
generation_jobs ||--o| generation_reservations : "budget_id"
studio_conversations ||--o| maa_bindings : "conversation_id"
maa_model_change_actions |o--o| maa_bindings : "pending_model_change_id"
maa_interactions ||--o| maa_interaction_actions : "interaction_id"
maa_runs ||--o{ maa_interactions : "public_run_id"
maa_bindings ||--o{ maa_message_actions : "binding_id"
maa_runs |o--o{ maa_message_actions : "public_run_id"
maa_bindings ||--o{ maa_model_change_actions : "binding_id"
maa_runs ||--o| maa_run_stop_actions : "public_run_id"
maa_bindings ||--o{ maa_runs : "binding_id"
studio_canvases ||--o{ studio_canvas_revisions : "project_id"
studio_canvas_revisions |o--o{ studio_canvas_revisions : "restored_from_revision"
studio_projects ||--o| studio_canvases : "project_id"
studio_projects ||--o{ studio_conversations : "project_id"
studio_media_jobs ||--o{ studio_credit_recovery_intents : "job_id"
studio_projects ||--o{ studio_export_jobs : "project_id"
studio_media_requests ||--o| studio_media_jobs : "request_id"
studio_media_jobs ||--o{ studio_media_outputs : "job_id"
studio_conversations ||--o{ studio_media_requests : "conversation_id"
maa_runs |o--o{ studio_media_requests : "source_run_id"
studio_media_jobs ||--o{ studio_media_submission_attempts : "job_id"
studio_projects ||--o{ studio_project_asset_refs : "project_id"
studio_video_documents ||--o{ studio_timeline_revisions : "project_id"
studio_timeline_revisions |o--o{ studio_timeline_revisions : "restored_from_revision"
studio_projects ||--o| studio_video_documents : "project_id"
studio_assets ||--o{ studio_project_asset_refs : "asset_id"
studio_assets ||--o{ studio_media_outputs : "asset_id"
studio_assets ||--o{ generation_deliveries : "asset_id"
studio_media_model_versions ||--o{ studio_media_requests : "model_version_id"
studio_media_models ||--o{ studio_media_requests : "model_id"
studio_credit_authorizations |o--o{ studio_media_jobs : "credit_authorization_id"
studio_credit_authorizations |o--o{ studio_credit_recovery_intents : "authorization_id"自动生成的整体图(按真实表结构,备查)
共享身份库 ER 图
实测验证与设计原因 七个品牌相同,展开查看
实测验证(本机 MySQL 实库)
对照本机真实运行的数据库 studio_profile_topview 和 studio_platform_identity,逐项核对本页的表、列、关系与说明。18 / 18 项通过。
查看全部核对项
| 核对项 | 结果 |
|---|---|
| 表数 = 发布值 24 | 通过 |
| 列数 = 289 | 通过 |
| 外键数 = 34 | 通过 |
| 检查约束数 = 66 | 通过 |
| 触发器数 = 22 | 通过 |
| 索引数(含主键) = 85 | 通过 |
| 列定义与 pollo 逐列一致 | 通过 |
| 外键与 pollo 完全一致 | 通过 |
| 索引与 pollo 一致 | 通过 |
| 触发器与 pollo 一致 | 通过 |
| 外键 CSV 行数 = 实库外键数 | 通过 |
| mmd 实体 = 实库表 | 通过 |
| svg 标题 24 tables / 34 actual foreign keys = 实库 | 通过 |
| 参考 SQL 表集合与列顺序 = 实库 | 通过 |
| 15 张表 | 通过 |
| 外键 CSV 行数 = 实库外键数 | 通过 |
| svg 标题与实库一致 | 通过 |
| 参考 SQL 表集合与列顺序 = 实库 | 通过 |
实库里的关系是这样的
- 34 个外键里 31 个是复合外键,且都带着 owner_id,其余 3 个是单列外键;22 张子表都带 owner 外键。所以一行数据不可能指向别的用户的项目或会话。
- 删除与更新规则全部是 RESTRICT / NO ACTION,没有任何级联:被引用的行不能被删除。
- 品牌库与共享身份库之间的关系(owner_id、asset_id、model_id + model_version_id)没有数据库外键,靠应用层检查;我们逐表核对了现有数据,没有孤儿。
主动破坏测试(在事务里尝试,全部回滚)
| 尝试 | 数据库的反应 |
|---|---|
| 外键:导出任务.project_id 改成不存在的项目被拒绝 | 拒绝 |
| 复合外键:项目素材引用.project_id 改成别的用户的项目被拒绝(owner 与 project 必须成对) | 拒绝 |
| 触发器:已提交的消息动作不可改写 | 拒绝 |
| 触发器:媒体产出不可改写 | 拒绝 |
| 外键 RESTRICT:被会话引用的项目不能删除 | 拒绝 |
| 复合外键:被引用的会话不能把 owner 改成别人 | 拒绝 |
| 检查约束:Run 状态只能是约定的六个值 | 拒绝 |
| 触发器:账本分录不可修改 | 拒绝 |
| 触发器:账本分录不可删除 | 拒绝 |
TopView · 表结构
MySQL 8,字符集 utf8mb4,ID 为 char(36) ascii_bin。点击展开 DDL。
按职责分组
项目与会话 2 张
studio_projects:用户拥有的创作项目studio_conversations:项目内的对话会话
Agent执行与并发控制 7 张
maa_bindings:业务会话与Native Maa会话映射、模型版本与未决操作maa_runs:公开Run映射、状态与原生/公开助手证据摘要maa_message_actions:原消息动作及幂等回执maa_interactions:澄清卡片及Run归属maa_interaction_actions:原卡片回答/取消动作maa_model_change_actions:带预期模型版本的切换动作maa_run_stop_actions:停止原Run的幂等动作与观测终态
画布、时间轴与素材引用 5 张
studio_canvases:项目当前画布文档studio_canvas_revisions:历史画布修订studio_video_documents:项目当前时间轴文档studio_timeline_revisions:历史时间轴修订studio_project_asset_refs:项目对用户级素材的引用;不复制素材所有权
媒体生成、结算恢复与导出 6 张
studio_media_requests:用户输入/Agent来源、报价、批准摘要与准入确认studio_media_jobs:已批准媒体任务及状态机studio_media_submission_attempts:一次提交的任务证据与不确定结果studio_media_outputs:受验证的输出与素材映射studio_credit_recovery_intents:积分结算恢复意图;不是用户钱包全账本studio_export_jobs:时间轴导出队列和发布输出
既有generation兼容路径 22 张
generation_jobs:既有generation任务,不等同新PublicMedia任务generation_reservations:既有任务费用预留generation_development_budgets:既有开发测试预算generation_deliveries:既有生成交付回执owner_id:归属用户;不是允许跨用户查询的参数。model_revision:并发准入版本;数据库默认0不能代替Native权威读回。pending_model_change_id:未决模型切换引用,阻止其他writer绕过。studio_users:用户账号记录;不导出密码哈希或任何业务行studio_sessions:登录会话;这里只公开字段结构,不公开会话值studio_assets:用户级素材元数据与存储键结构,项目仅引用素材IDstudio_media_models:公开媒体模型目录结构studio_media_model_versions:媒体模型不可变版本/计价能力结构studio_subscriptions:订阅状态持久化studio_billing_cycles:订阅账期studio_payment_orders:订单记录studio_payment_events:支付事件幂等记录;不代表已有公开支付路由studio_credit_accounts:用户积分账户studio_credit_lots:积分批次studio_credit_authorizations:费用预留与结算授权studio_credit_authorization_allocations:授权对批次的分配studio_credit_ledger_entries:积分流水studio_credit_plan_versions:积分方案不可变版本
品牌库 studio_profile_topview(24 张)
generation_deliveries 既有生成交付回执
CREATE TABLE `generation_deliveries` ( `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `session_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `maa_source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `tool_name` varchar(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `input_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `metadata_json` json NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`job_id`), KEY `generation_delivery_owner_project` (`owner_id`,`project_id`,`session_id`,`job_id`), KEY `generation_delivery_owned_asset` (`owner_id`,`asset_id`), KEY `generation_delivery_session_fk` (`session_id`), CONSTRAINT `generation_delivery_job_fk` FOREIGN KEY (`job_id`) REFERENCES `generation_jobs` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`, `job_id`) REFERENCES `generation_jobs` (`owner_id`, `project_id`, `session_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_session_fk` FOREIGN KEY (`session_id`) REFERENCES `studio_conversations` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_model_tool` CHECK ((((`model` = _ascii'seedance-2.0') and (`tool_name` = _ascii'seedance2_video_generator')) or ((`model` in (_ascii'minimax-h3',_ascii'seedance-2.5')) and (`tool_name` = _ascii'insai_video_generate')))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_development_budgets 既有开发测试预算
CREATE TABLE `generation_development_budgets` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `policy_version` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits_limit` bigint unsigned NOT NULL, `credits_reserved` bigint unsigned NOT NULL DEFAULT '0', `calls_limit` int unsigned NOT NULL, `calls_reserved` int unsigned NOT NULL DEFAULT '0', `expires_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `generation_budget_owner` (`owner_id`,`id`), CONSTRAINT `generation_budget_limits` CHECK (((`credits_limit` between 1 and 1000000000) and (`credits_reserved` <= `credits_limit`) and (`calls_limit` between 1 and 100) and (`calls_reserved` <= `calls_limit`))), CONSTRAINT `generation_budget_policy` CHECK ((`policy_version` = _latin1'operator-test/v1')) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_jobs 既有generation任务,不等同新PublicMedia任务
CREATE TABLE `generation_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `session_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_conversation_id` char(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_run_id` char(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `budget_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_bytes` mediumblob NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits` bigint unsigned NOT NULL, `expires_at` datetime(6) NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempts` int unsigned NOT NULL DEFAULT '0', `result_bytes` mediumblob, `updated_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `generation_job_budget_owner` (`id`,`budget_id`,`owner_id`), UNIQUE KEY `generation_job_owned_scope` (`owner_id`,`project_id`,`session_id`,`id`), KEY `generation_job_owner` (`owner_id`,`project_id`,`session_id`), KEY `generation_job_session` (`session_id`), KEY `generation_job_budget` (`owner_id`,`budget_id`), CONSTRAINT `generation_job_budget` FOREIGN KEY (`owner_id`, `budget_id`) REFERENCES `generation_development_budgets` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_owned_project` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_owned_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_session` FOREIGN KEY (`session_id`) REFERENCES `studio_conversations` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_attempt` CHECK ((((`status` = _ascii'APPROVED') and (`attempts` = 0) and (`result_bytes` is null)) or ((`status` = _ascii'SUBMITTING') and (`attempts` = 1) and (`result_bytes` is null)) or ((`status` in (_ascii'SUCCEEDED',_ascii'FAILED',_ascii'UNKNOWN')) and (`attempts` = 1) and (`result_bytes` is not null)))), CONSTRAINT `generation_job_credit` CHECK ((`credits` between 1 and 1000000000)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_reservations 既有任务费用预留
CREATE TABLE `generation_reservations` ( `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `budget_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits` bigint unsigned NOT NULL, `calls` int unsigned NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, PRIMARY KEY (`job_id`), KEY `generation_reservation_job` (`job_id`,`budget_id`,`owner_id`), CONSTRAINT `generation_reservation_job` FOREIGN KEY (`job_id`, `budget_id`, `owner_id`) REFERENCES `generation_jobs` (`id`, `budget_id`, `owner_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_reservation_fixed` CHECK (((`credits` between 1 and 1000000000) and (`calls` = 1) and (`status` = _latin1'HELD'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_bindings 业务会话与Native Maa会话映射、模型版本与未决操作
CREATE TABLE `maa_bindings` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `model_revision` bigint unsigned NOT NULL DEFAULT '0', `pending_model_change_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_binding_business_scope` (`owner_id`,`project_id`,`conversation_id`), UNIQUE KEY `maa_binding_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `maa_binding_native_identity` (`native_cid`), KEY `maa_model_change_pending_fk` (`owner_id`,`project_id`,`conversation_id`,`id`,`pending_model_change_id`), CONSTRAINT `maa_binding_owned_conversation_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_model_change_pending_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `id`, `pending_model_change_id`) REFERENCES `maa_model_change_actions` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_binding_receipt` CHECK ((((`status` = _ascii'dispatching') and (`native_cid` is null)) or ((`status` = _ascii'bound') and (`native_cid` is not null)))), CONSTRAINT `maa_model_binding_revision` CHECK ((`model_revision` <= 9007199254740991)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_interaction_actions 原卡片回答/取消动作
CREATE TABLE `maa_interaction_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `interaction_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_iid` varchar(124) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `content_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `response_action` varchar(8) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `values_payload` json NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_interaction_action_business_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_interaction_action_one_card` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`interaction_id`), CONSTRAINT `maa_interaction_action_owned_card_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`, `interaction_id`) REFERENCES `maa_interactions` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_interaction_action_kind` CHECK ((`response_action` in (_latin1'submit',_latin1'cancel'))), CONSTRAINT `maa_interaction_action_status` CHECK ((`status` in (_latin1'dispatching',_latin1'accepted'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_interactions 澄清卡片及Run归属
CREATE TABLE `maa_interactions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_iid` varchar(124) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_payload` json NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_interaction_native_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`native_iid`), UNIQUE KEY `maa_interaction_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`id`), CONSTRAINT `maa_interaction_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_message_actions 原消息动作及幂等回执
CREATE TABLE `maa_message_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `content` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `proposed_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_action_business_identity` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), KEY `maa_action_owned_run_fk` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`), CONSTRAINT `maa_action_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_action_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_action_receipt` CHECK ((((`status` = _latin1'dispatching') and (`public_run_id` is null)) or ((`status` = _latin1'accepted') and (`public_run_id` is not null)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_model_change_actions 带预期模型版本的切换动作
CREATE TABLE `maa_model_change_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `expected_revision` bigint unsigned NOT NULL, `from_provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `from_model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `target_provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `target_model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `dispatch_attempt` bigint unsigned NOT NULL, `receipt_payload` json DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_model_change_owned_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_model_change_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`id`), CONSTRAINT `maa_model_change_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_model_change_attempt` CHECK ((`dispatch_attempt` between 1 and 9007199254740991)), CONSTRAINT `maa_model_change_expected` CHECK ((`expected_revision` <= 9007199254740990)), CONSTRAINT `maa_model_change_status` CHECK ((((cast(`status` as char charset binary) = _latin1'dispatching') and (`receipt_payload` is null)) or ((cast(`status` as char charset binary) in (_latin1'accepted',_latin1'rejected')) and (`receipt_payload` is not null) and (json_type(`receipt_payload`) = _latin1'OBJECT')))), CONSTRAINT `maa_model_change_time` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_run_stop_actions 停止原Run的幂等动作与观测终态
CREATE TABLE `maa_run_stop_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_rid` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `stop_action` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempt` bigint unsigned NOT NULL, `terminal_run_status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_stop_owned_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_stop_one_run` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`), CONSTRAINT `maa_stop_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_stop_action` CHECK ((`stop_action` = _latin1'interrupt')), CONSTRAINT `maa_stop_attempt` CHECK ((`attempt` between 1 and 9007199254740991)), CONSTRAINT `maa_stop_state` CHECK ((((`status` = _latin1'unknown') and (`terminal_run_status` is null)) or ((`status` = _latin1'terminal_observed') and (`terminal_run_status` is not null) and (`terminal_run_status` in (_latin1'completed',_latin1'failed',_latin1'cancelled'))))), CONSTRAINT `maa_stop_time` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_runs 公开Run映射、状态与原生/公开助手证据摘要
CREATE TABLE `maa_runs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_rid` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, `native_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `public_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `native_assistant_bytes` bigint unsigned NOT NULL DEFAULT '0', `assistant_event_seq` bigint unsigned NOT NULL DEFAULT '0', `last_event_seq` bigint unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `maa_run_native_identity` (`native_rid`), UNIQUE KEY `maa_run_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`id`), KEY `maa_run_owned_list` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), CONSTRAINT `maa_run_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_run_source_evidence` CHECK ((((`native_assistant_sha256` is null) and (`public_assistant_sha256` is null) and (`native_assistant_bytes` = 0) and (`assistant_event_seq` = 0)) or ((`native_assistant_sha256` is not null) and (`public_assistant_sha256` is not null) and (`native_assistant_bytes` > 0) and (`assistant_event_seq` > 0) and (`assistant_event_seq` <= `last_event_seq`)))), CONSTRAINT `maa_run_status` CHECK ((`status` in (_latin1'queued',_latin1'running',_latin1'waiting_interaction',_latin1'completed',_latin1'failed',_latin1'cancelled'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_canvas_revisions 历史画布修订
CREATE TABLE `studio_canvas_revisions` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_bytes` mediumblob NOT NULL, `state_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `restored_from_revision` bigint unsigned DEFAULT NULL, `recorded_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`,`project_id`,`kind`,`revision`), KEY `studio_canvas_revision_source_fk` (`owner_id`,`project_id`,`kind`,`restored_from_revision`), CONSTRAINT `studio_canvas_revision_head_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_canvases` (`owner_id`, `project_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_canvas_revision_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `kind`, `restored_from_revision`) REFERENCES `studio_canvas_revisions` (`owner_id`, `project_id`, `kind`, `revision`), CONSTRAINT `studio_canvas_revision_bytes` CHECK ((length(`state_bytes`) between 1 and 262144)), CONSTRAINT `studio_canvas_revision_kind` CHECK ((`kind` = _latin1'canvas')), CONSTRAINT `studio_canvas_revision_number` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_canvas_revision_origin` CHECK ((((`origin` in (_latin1'saved',_latin1'backfill')) and (`restored_from_revision` is null)) or ((`origin` = _latin1'restored') and (`restored_from_revision` is not null) and (`restored_from_revision` between 1 and (`revision` - 1))))), CONSTRAINT `studio_canvas_revision_sha` CHECK ((`state_sha256` = lower(sha2(`state_bytes`,256)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_canvases 项目当前画布文档
CREATE TABLE `studio_canvases` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_json` json NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`project_id`), UNIQUE KEY `studio_canvas_owned_head` (`owner_id`,`project_id`), CONSTRAINT `studio_canvas_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_canvas_revision` CHECK ((`revision` between 1 and 2147483647)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_conversations 项目内的对话会话
CREATE TABLE `studio_conversations` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `title` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_conversation_owned_scope` (`owner_id`,`project_id`,`id`), KEY `studio_conversation_list` (`owner_id`,`project_id`,`created_at`,`id`), CONSTRAINT `studio_conversation_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_recovery_intents 积分结算恢复意图;不是用户钱包全账本
CREATE TABLE `studio_credit_recovery_intents` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`kind` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`intent_bytes` mediumblob NOT NULL,
`intent_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`lease_token_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`lease_until` datetime(6) DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_intent_job_kind` (`job_id`,`kind`),
KEY `credit_intent_recovery` (`state`,`updated_at`,`id`),
KEY `credit_intent_owned_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`,`request_sha256`),
CONSTRAINT `credit_intent_owned_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`, `request_sha256`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`),
CONSTRAINT `credit_intent_hashes` CHECK ((regexp_like(`request_sha256`,_latin1'^[a-f0-9]{64}$') and regexp_like(`quote_sha256`,_latin1'^[a-f0-9]{64}$'))),
CONSTRAINT `credit_intent_kind` CHECK (((`kind` in (_latin1'RESERVE_BIND',_latin1'CAPTURE',_latin1'RELEASE')) and (((`kind` = _latin1'RESERVE_BIND') and (`authorization_id` is null)) or ((`kind` in (_latin1'CAPTURE',_latin1'RELEASE')) and (`authorization_id` is not null))))),
CONSTRAINT `credit_intent_lease` CHECK ((((`state` = _latin1'leased') and (`lease_token_sha256` is not null) and regexp_like(`lease_token_sha256`,_latin1'^[a-f0-9]{64}$') and (`lease_until` is not null) and (`lease_until` > `updated_at`) and (`lease_until` <= (`updated_at` + interval 15 minute))) or ((`state` <> _latin1'leased') and (`lease_token_sha256` is null) and (`lease_until` is null)))),
CONSTRAINT `credit_intent_payload_sha` CHECK ((`intent_sha256` = lower(sha2(`intent_bytes`,256)))),
CONSTRAINT `credit_intent_payload_size` CHECK ((length(`intent_bytes`) between 1 and 65536)),
CONSTRAINT `credit_intent_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `credit_intent_state` CHECK ((`state` in (_latin1'pending',_latin1'leased',_latin1'confirmed',_latin1'unknown'))),
CONSTRAINT `credit_intent_times` CHECK ((`updated_at` >= `created_at`))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_export_jobs 时间轴导出队列和发布输出
CREATE TABLE `studio_export_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `document_revision` bigint unsigned NOT NULL, `input_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `input_json` json NOT NULL, `output_json` json DEFAULT NULL, `error_code` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT '', `lease_token_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `lease_until` datetime(6) DEFAULT NULL, `attempts` int unsigned NOT NULL DEFAULT '0', `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_export_input` (`project_id`,`document_revision`,`input_hash`), KEY `studio_export_claim` (`status`,`created_at`,`id`), KEY `studio_export_owner_list` (`owner_id`,`project_id`,`created_at`,`id`), KEY `studio_export_expiry` (`status`,`lease_until`), CONSTRAINT `studio_export_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_export_lease` CHECK ((((`status` = _latin1'running') and (`lease_token_hash` is not null) and (`lease_until` is not null)) or ((`status` <> _latin1'running') and (`lease_token_hash` is null) and (`lease_until` is null)))), CONSTRAINT `studio_export_output` CHECK ((((`status` = _latin1'succeeded') and (`output_json` is not null) and (`error_code` = _latin1'')) or ((`status` in (_latin1'queued',_latin1'running')) and (`output_json` is null) and (`error_code` = _latin1'')) or ((`status` in (_latin1'failed',_latin1'unknown')) and (`output_json` is null) and (`error_code` <> _latin1'')))), CONSTRAINT `studio_export_revision` CHECK ((`document_revision` between 1 and 2147483647)), CONSTRAINT `studio_export_status` CHECK ((`status` in (_latin1'queued',_latin1'running',_latin1'succeeded',_latin1'failed',_latin1'unknown'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_jobs 已批准媒体任务及状态机
CREATE TABLE `studio_media_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_approval_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `approval_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credit_authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `authorization_mode` varchar(24) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `authorization_expires_at` datetime(6) DEFAULT NULL, `status` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `lease_token_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `lease_until` datetime(6) DEFAULT NULL, `provider_task_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `client_cancel_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `cancel_request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `cancel_requested_at` datetime(6) DEFAULT NULL, `staged_asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `staged_asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_job_request` (`request_id`), UNIQUE KEY `studio_media_job_client` (`owner_id`,`client_approval_id`), UNIQUE KEY `studio_media_job_owned` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `studio_media_job_owned_request` (`owner_id`,`project_id`,`conversation_id`,`id`,`request_sha256`), KEY `studio_media_job_page` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), KEY `studio_media_job_queue` (`status`,`updated_at`,`id`), KEY `studio_media_job_request_fk` (`owner_id`,`project_id`,`conversation_id`,`request_id`,`request_sha256`,`quote_sha256`), CONSTRAINT `studio_media_job_request_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `request_id`, `request_sha256`, `quote_sha256`) REFERENCES `studio_media_requests` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`, `quote_sha256`), CONSTRAINT `studio_media_job_authorization` CHECK ((((`credit_authorization_id` is null) and (`authorization_mode` is null) and (`authorization_expires_at` is null) and (`status` in (_latin1'approval_pending',_latin1'cancelled'))) or ((`credit_authorization_id` is not null) and (`authorization_mode` is not null) and (`authorization_mode` in (_latin1'commercial',_latin1'test_allowance')) and (`authorization_expires_at` is not null) and (`authorization_expires_at` > `created_at`) and (`status` <> _latin1'approval_pending')))), CONSTRAINT `studio_media_job_cancel` CHECK ((((`client_cancel_id` is null) and (`cancel_request_sha256` is null) and (`cancel_requested_at` is null)) or ((`client_cancel_id` is not null) and (`cancel_request_sha256` is not null) and (`cancel_requested_at` is not null) and (`cancel_requested_at` between `created_at` and `updated_at`)))), CONSTRAINT `studio_media_job_lease` CHECK ((((`status` in (_latin1'leased',_latin1'submitting')) and (`lease_token_sha256` is not null) and (`lease_until` is not null) and (`lease_until` > `updated_at`) and (`lease_until` <= (`updated_at` + interval 15 minute))) or ((`status` not in (_latin1'leased',_latin1'submitting')) and (`lease_token_sha256` is null) and (`lease_until` is null)))), CONSTRAINT `studio_media_job_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_media_job_staged` CHECK ((((`staged_asset_id` is null) and (`staged_asset_sha256` is null)) or ((`staged_asset_id` is not null) and (`staged_asset_sha256` is not null)))), CONSTRAINT `studio_media_job_status` CHECK ((`status` in (_latin1'approval_pending',_latin1'queued',_latin1'leased',_latin1'submitting',_latin1'running',_latin1'submission_unknown',_latin1'succeeded',_latin1'failed',_latin1'cancelled'))), CONSTRAINT `studio_media_job_task` CHECK (((`status` not in (_latin1'running',_latin1'succeeded')) or (`provider_task_id` is not null))), CONSTRAINT `studio_media_job_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_outputs 受验证的输出与素材映射
CREATE TABLE `studio_media_outputs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `ordinal` int unsigned NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_metadata_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_result_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_output_job` (`job_id`,`ordinal`), KEY `studio_media_output_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`), CONSTRAINT `studio_media_output_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`), CONSTRAINT `studio_media_output_ordinal` CHECK ((`ordinal` = 0)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_requests 用户输入/Agent来源、报价、批准摘要与准入确认
CREATE TABLE `studio_media_requests` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_config_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_bytes` mediumblob NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quote_bytes` mediumblob NOT NULL, `quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quoted_credits` bigint unsigned NOT NULL, `expires_at` datetime(6) NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_snapshot_bytes` mediumblob, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_request_owned` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `studio_media_request_quoted` (`owner_id`,`project_id`,`conversation_id`,`id`,`request_sha256`,`quote_sha256`), UNIQUE KEY `studio_media_request_client` (`owner_id`,`project_id`,`conversation_id`,`client_request_id`), KEY `studio_media_request_page` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), KEY `studio_media_request_source_fk` (`owner_id`,`project_id`,`conversation_id`,`source_binding_id`,`source_run_id`), CONSTRAINT `studio_media_request_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`), CONSTRAINT `studio_media_request_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `source_binding_id`, `source_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`), CONSTRAINT `studio_media_quote_credits` CHECK ((`quoted_credits` between 1 and 1000000000)), CONSTRAINT `studio_media_quote_sha` CHECK ((`quote_sha256` = lower(sha2(`quote_bytes`,256)))), CONSTRAINT `studio_media_quote_times` CHECK (((`expires_at` > `created_at`) and (`expires_at` <= (`created_at` + interval 15 minute)))), CONSTRAINT `studio_media_request_origin` CHECK ((((`origin` in (_latin1'ui',_latin1'user_edit')) and (`source_binding_id` is null) and (`source_run_id` is null) and (`source_assistant_sha256` is null) and (`source_snapshot_bytes` is null)) or ((`origin` = _latin1'agent') and (`source_binding_id` is not null) and (`source_run_id` is not null) and (`source_assistant_sha256` is not null) and (`source_snapshot_bytes` is not null) and (length(`source_snapshot_bytes`) between 1 and 65536) and (`source_assistant_sha256` = lower(sha2(`source_snapshot_bytes`,256)))))), CONSTRAINT `studio_media_request_sha` CHECK ((`request_sha256` = lower(sha2(`request_bytes`,256)))), CONSTRAINT `studio_media_request_size` CHECK (((length(`request_bytes`) between 1 and 65536) and (length(`quote_bytes`) between 1 and 65536))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_submission_attempts 一次提交的任务证据与不确定结果
CREATE TABLE `studio_media_submission_attempts` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempt_no` int unsigned NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_idempotency_key` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `stage` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `dispatch_started_at` datetime(6) DEFAULT NULL, `provider_task_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `receipt_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `terminal_receipt_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `reconciliation_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_attempt_job` (`job_id`,`attempt_no`), UNIQUE KEY `studio_media_attempt_idempotency` (`provider_idempotency_key`), KEY `studio_media_attempt_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`,`request_sha256`), CONSTRAINT `studio_media_attempt_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`, `request_sha256`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`), CONSTRAINT `studio_media_attempt_number` CHECK ((`attempt_no` = 1)), CONSTRAINT `studio_media_attempt_state` CHECK ((((`stage` = _latin1'prepared') and (`dispatch_started_at` is null) and (`provider_task_id` is null) and (`receipt_sha256` is null) and (`reconciliation_sha256` is null) and (`terminal_receipt_sha256` is null)) or ((`stage` in (_latin1'dispatching',_latin1'unknown')) and (`dispatch_started_at` is not null) and (`dispatch_started_at` >= `created_at`) and (`provider_task_id` is null) and (`receipt_sha256` is null) and (`reconciliation_sha256` is null) and (`terminal_receipt_sha256` is null)) or ((`stage` = _latin1'acknowledged') and (`dispatch_started_at` is not null) and (`provider_task_id` is not null) and (`receipt_sha256` is not null) and (`terminal_receipt_sha256` is null)) or ((`stage` in (_latin1'completed',_latin1'failed')) and (`dispatch_started_at` is not null) and (`provider_task_id` is not null) and (`receipt_sha256` is not null) and (`terminal_receipt_sha256` is not null)) or ((`stage` = _latin1'reconciled_not_sent') and (`dispatch_started_at` is not null) and (`provider_task_id` is null) and (`reconciliation_sha256` is not null)))), CONSTRAINT `studio_media_attempt_times` CHECK (((`updated_at` >= `created_at`) and ((`dispatch_started_at` is null) or (`dispatch_started_at` between `created_at` and `updated_at`)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_project_asset_refs 项目对用户级素材的引用;不复制素材所有权
CREATE TABLE `studio_project_asset_refs` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_metadata_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, `detached_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`project_id`,`asset_id`), KEY `studio_project_asset_owned_page` (`owner_id`,`project_id`,`asset_id`), KEY `studio_project_asset_reverse` (`owner_id`,`asset_id`,`project_id`), CONSTRAINT `studio_project_asset_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_project_asset_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_project_asset_state` CHECK ((((`state` = _latin1'attached') and (`detached_at` is null)) or ((`state` = _latin1'detached') and (`detached_at` is not null) and (`detached_at` = `updated_at`)))), CONSTRAINT `studio_project_asset_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_projects 用户拥有的创作项目
CREATE TABLE `studio_projects` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `title` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_project_owner_identity` (`owner_id`,`id`), KEY `studio_project_owner_list` (`owner_id`,`created_at`,`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_timeline_revisions 历史时间轴修订
CREATE TABLE `studio_timeline_revisions` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_bytes` mediumblob NOT NULL, `state_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `restored_from_revision` bigint unsigned DEFAULT NULL, `recorded_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`,`project_id`,`kind`,`revision`), KEY `studio_timeline_revision_source_fk` (`owner_id`,`project_id`,`kind`,`restored_from_revision`), CONSTRAINT `studio_timeline_revision_head_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_video_documents` (`owner_id`, `project_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_timeline_revision_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `kind`, `restored_from_revision`) REFERENCES `studio_timeline_revisions` (`owner_id`, `project_id`, `kind`, `revision`), CONSTRAINT `studio_timeline_revision_bytes` CHECK ((length(`state_bytes`) between 1 and 262144)), CONSTRAINT `studio_timeline_revision_kind` CHECK ((`kind` = _latin1'timeline')), CONSTRAINT `studio_timeline_revision_number` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_timeline_revision_origin` CHECK ((((`origin` in (_latin1'saved',_latin1'backfill')) and (`restored_from_revision` is null)) or ((`origin` = _latin1'restored') and (`restored_from_revision` is not null) and (`restored_from_revision` between 1 and (`revision` - 1))))), CONSTRAINT `studio_timeline_revision_sha` CHECK ((`state_sha256` = lower(sha2(`state_bytes`,256)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_video_documents 项目当前时间轴文档
CREATE TABLE `studio_video_documents` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_json` json NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`project_id`), UNIQUE KEY `studio_timeline_owned_head` (`owner_id`,`project_id`), CONSTRAINT `studio_document_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_document_revision` CHECK ((`revision` between 1 and 2147483647)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
共享身份库(15 张)与积分账本 七个品牌相同,展开查看
studio_assets
CREATE TABLE `studio_assets` (
`id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`metadata_json` json NOT NULL,
`storage_key` varchar(512) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`created_at` datetime(6) NOT NULL,
`publication_state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT 'visible',
PRIMARY KEY (`id`),
UNIQUE KEY `studio_asset_owner_digest` (`owner_id`,`sha256`),
KEY `studio_asset_owner_list` (`owner_id`,`created_at`,`id`),
KEY `studio_asset_visible_list` (`owner_id`,`publication_state`,`created_at`,`id`),
CONSTRAINT `studio_asset_publication_state` CHECK (CAST(publication_state AS BINARY) IN ('pending','visible')),
CONSTRAINT `studio_asset_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_billing_cycles
CREATE TABLE `studio_billing_cycles` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`subscription_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`payment_order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_invoice_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`period_start` datetime(6) NOT NULL,
`period_end` datetime(6) NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`valid_from` datetime(6) NOT NULL,
`expires_at` datetime(6) NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`paid_evidence_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `billing_cycle_owned` (`owner_id`,`id`),
UNIQUE KEY `billing_cycle_period` (`subscription_id`,`period_start`),
UNIQUE KEY `billing_cycle_invoice` (`provider_key`,`provider_account`,`provider_invoice_id`),
UNIQUE KEY `billing_cycle_order` (`payment_order_id`),
KEY `billing_cycle_subscription_fk` (`owner_id`,`subscription_id`,`provider_key`,`provider_account`),
KEY `billing_cycle_order_fk` (`owner_id`,`payment_order_id`,`plan_version_id`),
KEY `billing_cycle_order_provider_fk` (`owner_id`,`payment_order_id`,`provider_key`,`provider_account`),
CONSTRAINT `billing_cycle_order_fk` FOREIGN KEY (`owner_id`, `payment_order_id`, `plan_version_id`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `plan_version_id`),
CONSTRAINT `billing_cycle_order_provider_fk` FOREIGN KEY (`owner_id`, `payment_order_id`, `provider_key`, `provider_account`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `provider_key`, `provider_account`),
CONSTRAINT `billing_cycle_subscription_fk` FOREIGN KEY (`owner_id`, `subscription_id`, `provider_key`, `provider_account`) REFERENCES `studio_subscriptions` (`owner_id`, `id`, `provider_key`, `provider_account`),
CONSTRAINT `billing_cycle_amount` CHECK ((`grant_credits` between 1 and 1000000000)),
CONSTRAINT `billing_cycle_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `billing_cycle_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `billing_cycle_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `billing_cycle_state` CHECK (((`state` in (_latin1'PENDING',_latin1'PAID',_latin1'CLOSED')) and (((`state` = _latin1'PAID') and (`paid_evidence_sha256` is not null) and regexp_like(`paid_evidence_sha256`,_latin1'^[a-f0-9]{64}$')) or ((`state` <> _latin1'PAID') and (`paid_evidence_sha256` is null))))),
CONSTRAINT `billing_cycle_times` CHECK (((`period_end` > `period_start`) and (`expires_at` > `valid_from`) and (`expires_at` <= (`valid_from` + interval 31622400 second)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_credit_accounts
CREATE TABLE `studio_credit_accounts` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `unit` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`), CONSTRAINT `credit_account_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `credit_account_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `credit_account_status` CHECK ((`status` in (_latin1'open',_latin1'suspended'))), CONSTRAINT `credit_account_unit` CHECK ((`unit` = _latin1'credits')) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_authorization_allocations
CREATE TABLE `studio_credit_authorization_allocations` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `lot_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `allocated_credits` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`authorization_id`,`lot_id`), UNIQUE KEY `credit_allocation_owned` (`owner_id`,`authorization_id`,`lot_id`), KEY `credit_allocation_lot` (`owner_id`,`lot_id`,`authorization_id`), CONSTRAINT `credit_allocation_authorization_fk` FOREIGN KEY (`owner_id`, `authorization_id`) REFERENCES `studio_credit_authorizations` (`owner_id`, `id`), CONSTRAINT `credit_allocation_lot_fk` FOREIGN KEY (`owner_id`, `lot_id`) REFERENCES `studio_credit_lots` (`owner_id`, `id`), CONSTRAINT `credit_allocation_amount` CHECK ((`allocated_credits` between 1 and 1000000000)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_authorizations
CREATE TABLE `studio_credit_authorizations` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`profile` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`credits` bigint unsigned NOT NULL,
`expires_at` datetime(6) NOT NULL,
`reservation_bytes` mediumblob NOT NULL,
`reservation_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`policy_bytes` mediumblob NOT NULL,
`policy_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_authorization_owned` (`owner_id`,`id`),
UNIQUE KEY `credit_authorization_job` (`owner_id`,`profile`,`job_id`),
CONSTRAINT `credit_authorization_account_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_credit_accounts` (`owner_id`),
CONSTRAINT `credit_authorization_amount` CHECK ((`credits` between 1 and 1000000000)),
CONSTRAINT `credit_authorization_hashes` CHECK ((regexp_like(`request_sha256`,_latin1'^[a-f0-9]{64}$') and regexp_like(`quote_sha256`,_latin1'^[a-f0-9]{64}$'))),
CONSTRAINT `credit_authorization_policy_sha` CHECK ((`policy_sha256` = lower(sha2(`policy_bytes`,256)))),
CONSTRAINT `credit_authorization_policy_size` CHECK ((length(`policy_bytes`) between 1 and 65536)),
CONSTRAINT `credit_authorization_profile` CHECK ((`profile` in (_latin1'topview',_latin1'pollo',_latin1'invideo',_latin1'libtv',_latin1'flova',_latin1'creatok',_latin1'creatify'))),
CONSTRAINT `credit_authorization_reservation_sha` CHECK ((`reservation_sha256` = lower(sha2(`reservation_bytes`,256)))),
CONSTRAINT `credit_authorization_reservation_size` CHECK ((length(`reservation_bytes`) between 1 and 65536)),
CONSTRAINT `credit_authorization_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `credit_authorization_state` CHECK ((`state` in (_latin1'HELD',_latin1'CAPTURED',_latin1'RELEASED'))),
CONSTRAINT `credit_authorization_times` CHECK (((`expires_at` > `created_at`) and (`expires_at` <= (`created_at` + interval 15 minute)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_credit_ledger_entries
CREATE TABLE `studio_credit_ledger_entries` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `lot_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `operation_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `grant_delta` bigint NOT NULL, `held_delta` bigint NOT NULL, `captured_delta` bigint NOT NULL, `facts_bytes` mediumblob NOT NULL, `facts_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `credit_entry_operation` (`owner_id`,`operation_key`,`lot_id`), KEY `credit_entry_page` (`owner_id`,`created_at`,`id`), KEY `credit_entry_lot_fk` (`owner_id`,`lot_id`), KEY `credit_entry_allocation_fk` (`owner_id`,`authorization_id`,`lot_id`), CONSTRAINT `credit_entry_allocation_fk` FOREIGN KEY (`owner_id`, `authorization_id`, `lot_id`) REFERENCES `studio_credit_authorization_allocations` (`owner_id`, `authorization_id`, `lot_id`), CONSTRAINT `credit_entry_authorization_fk` FOREIGN KEY (`owner_id`, `authorization_id`) REFERENCES `studio_credit_authorizations` (`owner_id`, `id`), CONSTRAINT `credit_entry_lot_fk` FOREIGN KEY (`owner_id`, `lot_id`) REFERENCES `studio_credit_lots` (`owner_id`, `id`), CONSTRAINT `credit_entry_delta` CHECK ((((`kind` = _latin1'grant') and (`authorization_id` is null) and (`grant_delta` between 1 and 1000000000) and (`held_delta` = 0) and (`captured_delta` = 0)) or ((`kind` = _latin1'hold') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`held_delta` between 1 and 1000000000) and (`captured_delta` = 0)) or ((`kind` = _latin1'capture') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`captured_delta` between 1 and 1000000000) and (`held_delta` = -(`captured_delta`))) or ((`kind` = _latin1'release') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`held_delta` between -(1000000000) and -(1)) and (`captured_delta` = 0)))), CONSTRAINT `credit_entry_facts_sha` CHECK ((`facts_sha256` = lower(sha2(`facts_bytes`,256)))), CONSTRAINT `credit_entry_facts_size` CHECK ((length(`facts_bytes`) between 1 and 65536)), CONSTRAINT `credit_entry_operation_key` CHECK ((((`kind` = _latin1'grant') and (`operation_key` = concat(`lot_id`,_latin1':grant'))) or ((`kind` <> _latin1'grant') and (`operation_key` = concat(`authorization_id`,_latin1':',`kind`))))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_lots
CREATE TABLE `studio_credit_lots` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `grant_credits` bigint unsigned NOT NULL, `held_credits` bigint unsigned NOT NULL, `captured_credits` bigint unsigned NOT NULL, `valid_from` datetime(6) NOT NULL, `expires_at` datetime(6) NOT NULL, `eligibility_bytes` mediumblob NOT NULL, `eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_cycle_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `credit_lot_owned` (`owner_id`,`id`), UNIQUE KEY `credit_lot_order` (`source_order_id`), UNIQUE KEY `credit_lot_cycle` (`source_cycle_id`), KEY `credit_lot_eligible` (`owner_id`,`expires_at`,`id`), KEY `credit_lot_order_fk` (`owner_id`,`source_order_id`), KEY `credit_lot_cycle_fk` (`owner_id`,`source_cycle_id`), CONSTRAINT `credit_lot_account_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_credit_accounts` (`owner_id`), CONSTRAINT `credit_lot_cycle_fk` FOREIGN KEY (`owner_id`, `source_cycle_id`) REFERENCES `studio_billing_cycles` (`owner_id`, `id`), CONSTRAINT `credit_lot_order_fk` FOREIGN KEY (`owner_id`, `source_order_id`) REFERENCES `studio_payment_orders` (`owner_id`, `id`), CONSTRAINT `credit_lot_counters` CHECK (((`grant_credits` between 1 and 1000000000) and (`held_credits` <= 1000000000) and (`captured_credits` <= 1000000000) and ((`held_credits` + `captured_credits`) <= `grant_credits`))), CONSTRAINT `credit_lot_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))), CONSTRAINT `credit_lot_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)), CONSTRAINT `credit_lot_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `credit_lot_source` CHECK ((((`source_order_id` is not null) and (`source_cycle_id` is null)) or ((`source_order_id` is null) and (`source_cycle_id` is not null)))), CONSTRAINT `credit_lot_times` CHECK (((`expires_at` > `valid_from`) and (`updated_at` >= `created_at`))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_plan_versions
CREATE TABLE `studio_credit_plan_versions` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`version_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`price_minor` bigint unsigned NOT NULL,
`currency` char(3) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`credit_validity_seconds` int unsigned NOT NULL,
`billing_interval_months` int unsigned NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`published_at` datetime(6) NOT NULL,
`retired_at` datetime(6) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_plan_version_key` (`plan_key`,`version_key`),
CONSTRAINT `credit_plan_amount` CHECK (((`price_minor` between 1 and 1000000000000) and (`grant_credits` between 1 and 1000000000))),
CONSTRAINT `credit_plan_currency` CHECK (regexp_like(`currency`,_latin1'^[A-Z]{3}$')),
CONSTRAINT `credit_plan_duration` CHECK (((`credit_validity_seconds` between 1 and 31622400) and ((`retired_at` is null) or (`retired_at` >= `published_at`)))),
CONSTRAINT `credit_plan_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `credit_plan_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `credit_plan_kind` CHECK (((`kind` in (_latin1'subscription',_latin1'topup')) and (((`kind` = _latin1'subscription') and (`billing_interval_months` in (1,3,12))) or ((`kind` = _latin1'topup') and (`billing_interval_months` = 0)))))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_media_model_versions
CREATE TABLE `studio_media_model_versions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `version_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `config_bytes` mediumblob NOT NULL, `config_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `published_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_version_key` (`model_id`,`version_key`), UNIQUE KEY `studio_media_version_owned_model` (`model_id`,`id`), CONSTRAINT `studio_media_version_model_fk` FOREIGN KEY (`model_id`) REFERENCES `studio_media_models` (`id`), CONSTRAINT `studio_media_version_sha` CHECK ((`config_sha256` = lower(sha2(`config_bytes`,256)))), CONSTRAINT `studio_media_version_size` CHECK ((length(`config_bytes`) between 1 and 65536)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_models
CREATE TABLE `studio_media_models` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `display_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `published_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `revision` bigint unsigned NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_model_key` (`model_key`), KEY `studio_media_model_published_fk` (`id`,`published_version_id`), CONSTRAINT `studio_media_model_published_fk` FOREIGN KEY (`id`, `published_version_id`) REFERENCES `studio_media_model_versions` (`model_id`, `id`), CONSTRAINT `studio_media_model_kind` CHECK ((`kind` = _ascii'video')), CONSTRAINT `studio_media_model_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_media_model_status` CHECK (((`status` in (_ascii'draft',_ascii'active',_ascii'disabled')) and ((`status` <> _ascii'active') or (`published_version_id` is not null)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_payment_events
CREATE TABLE `studio_payment_events` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_event_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `subscription_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `body_bytes` mediumblob NOT NULL, `body_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `payment_event_provider` (`provider_key`,`provider_account`,`provider_event_id`), KEY `payment_event_order_fk` (`owner_id`,`order_id`,`provider_key`,`provider_account`), KEY `payment_event_subscription_fk` (`owner_id`,`subscription_id`,`provider_key`,`provider_account`), CONSTRAINT `payment_event_order_fk` FOREIGN KEY (`owner_id`, `order_id`, `provider_key`, `provider_account`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `provider_key`, `provider_account`), CONSTRAINT `payment_event_subscription_fk` FOREIGN KEY (`owner_id`, `subscription_id`, `provider_key`, `provider_account`) REFERENCES `studio_subscriptions` (`owner_id`, `id`, `provider_key`, `provider_account`), CONSTRAINT `payment_event_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `payment_event_body_sha` CHECK ((`body_sha256` = lower(sha2(`body_bytes`,256)))), CONSTRAINT `payment_event_body_size` CHECK ((length(`body_bytes`) between 1 and 65536)), CONSTRAINT `payment_event_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `payment_event_state` CHECK ((`state` in (_latin1'VERIFIED',_latin1'PROCESSED'))), CONSTRAINT `payment_event_subject` CHECK (((`order_id` is not null) or (`subscription_id` is not null))), CONSTRAINT `payment_event_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_payment_orders
CREATE TABLE `studio_payment_orders` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`price_minor` bigint unsigned NOT NULL,
`currency` char(3) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`valid_from` datetime(6) NOT NULL,
`expires_at` datetime(6) NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_idempotency_key` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_order_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`paid_evidence_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `payment_order_owned` (`owner_id`,`id`),
UNIQUE KEY `payment_order_owned_plan` (`owner_id`,`id`,`plan_version_id`),
UNIQUE KEY `payment_order_owned_provider` (`owner_id`,`id`,`provider_key`,`provider_account`),
UNIQUE KEY `payment_order_client` (`owner_id`,`client_action_id`),
UNIQUE KEY `payment_order_provider_key` (`provider_key`,`provider_account`,`provider_idempotency_key`),
UNIQUE KEY `payment_order_provider_id` (`provider_key`,`provider_account`,`provider_order_id`),
KEY `payment_order_plan_fk` (`plan_version_id`),
CONSTRAINT `payment_order_plan_fk` FOREIGN KEY (`plan_version_id`) REFERENCES `studio_credit_plan_versions` (`id`),
CONSTRAINT `payment_order_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`),
CONSTRAINT `payment_order_amount` CHECK (((`price_minor` between 1 and 1000000000000) and (`grant_credits` between 1 and 1000000000))),
CONSTRAINT `payment_order_currency` CHECK (regexp_like(`currency`,_latin1'^[A-Z]{3}$')),
CONSTRAINT `payment_order_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `payment_order_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `payment_order_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `payment_order_state` CHECK (((`state` in (_latin1'CREATING',_latin1'CREATE_UNKNOWN',_latin1'PENDING',_latin1'PAID',_latin1'CLOSED')) and (((`state` = _latin1'PAID') and (`provider_order_id` is not null) and (`paid_evidence_sha256` is not null) and regexp_like(`paid_evidence_sha256`,_latin1'^[a-f0-9]{64}$')) or ((`state` <> _latin1'PAID') and (`paid_evidence_sha256` is null))))),
CONSTRAINT `payment_order_times` CHECK (((`expires_at` > `valid_from`) and (`expires_at` <= (`valid_from` + interval 31622400 second)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_sessions
CREATE TABLE `studio_sessions` ( `token_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `user_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, `expires_at` datetime(6) NOT NULL, `revoked_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`token_hash`), KEY `studio_session_expiry` (`expires_at`), KEY `studio_session_user` (`user_id`,`expires_at`), CONSTRAINT `studio_session_user_fk` FOREIGN KEY (`user_id`) REFERENCES `studio_users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_session_times` CHECK ((`expires_at` > `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_subscriptions
CREATE TABLE `studio_subscriptions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_subscription_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `period_start` datetime(6) NOT NULL, `period_end` datetime(6) NOT NULL, `cancel_at_period_end` tinyint(1) NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `subscription_owned` (`owner_id`,`id`), UNIQUE KEY `subscription_owned_provider` (`owner_id`,`id`,`provider_key`,`provider_account`), UNIQUE KEY `subscription_provider` (`provider_key`,`provider_account`,`provider_subscription_id`), KEY `subscription_plan_fk` (`plan_version_id`), CONSTRAINT `subscription_plan_fk` FOREIGN KEY (`plan_version_id`) REFERENCES `studio_credit_plan_versions` (`id`), CONSTRAINT `subscription_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `subscription_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `subscription_state` CHECK (((`state` in (_latin1'PENDING',_latin1'ACTIVE',_latin1'PAST_DUE',_latin1'CANCELLED',_latin1'ENDED')) and (`cancel_at_period_end` in (0,1)))), CONSTRAINT `subscription_times` CHECK (((`period_end` > `period_start`) and (`updated_at` >= `created_at`))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_users
CREATE TABLE `studio_users` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `email` varchar(254) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `password_hash` varbinary(72) NOT NULL, `enabled` tinyint(1) NOT NULL DEFAULT '1', `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_user_email` (`email`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
积分账本链路
TopView · 接口清单
共 55 个公开接口,取自源码路由盘点。路径都以 /v1 开头;写操作需要会话 Cookie、可信 Host/Origin 与 CSRF;带品牌的路径用 ?profile=topview;共享的登录、素材、模型目录路径不接受 profile 参数。
Agent/统一动作 7 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/interactions | runInteractions | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/interactions/{interaction_id}/responses | respondInteraction | client_action_id, card_sha256, action, values | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/interaction-actions/{client_action_id} | interactionAction | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/model-changes | changeConversationModel | client_action_id, expected_revision, agent_model, expected_attempt? | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/model-changes/{client_action_id} | modelChangeAction | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/stop | stopRun | client_action_id, expected_attempt? | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/stop-actions/{client_action_id} | stopAction | 200 |
Asset 4 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/assets | listAssets | 200 | |
| POST | /v1/assets | uploadAsset | file | 201 |
| GET | /v1/assets/{asset_id} | getAsset | 200 | |
| GET | /v1/assets/{asset_id}/content | assetContent | 200/206 |
LoginSession 1 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| POST | /v1/auth/logout | logout | 200 |
MaaBinding 5 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/maa/model-options | maaModels | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/messages | sendMaaMessage | client_action_id, content | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/actions/{client_action_id} | getMaaAction | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/state | getMaaState | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/events | maaEvents | 200 |
Media 11 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/media/models | publicMediaModels | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests | createMediaRequest | client_request_id, model_id, model_version_id, prompt, duration_seconds, ratio, resolution, admission? | 200 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests | mediaRequestByClient | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id} | getMediaRequest | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs/{job_id} | getMediaJob | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs/{job_id}/output | getMediaOutput | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id}/job | mediaJobByRequest | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id}/approve | approveMediaRequest | client_approval_id, request_sha256, quote_sha256 | 200 |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/from-maa | createMediaRequestFromMaa | input, source_run_id, source_assistant_sha256, admission? | 200 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs | listMediaJobs | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/intents | listMediaIntents | 200 |
Other 9 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects/{project_id}/canvas/revisions | listCanvasRevisions | 200 | |
| GET | /v1/projects/{project_id}/canvas/revisions/{revision} | getCanvasRevision | 200 | |
| POST | /v1/projects/{project_id}/canvas/revisions/{revision}/restore | restoreCanvasRevision | expected_revision | 200 |
| GET | /v1/projects/{project_id}/document/revisions | listTimelineRevisions | 200 | |
| GET | /v1/projects/{project_id}/document/revisions/{revision} | getTimelineRevision | 200 | |
| POST | /v1/projects/{project_id}/document/revisions/{revision}/restore | restoreTimelineRevision | expected_revision | 200 |
| GET | /v1/projects/{project_id}/assets | listProjectAssets | 200 | |
| POST | /v1/projects/{project_id}/assets | attachProjectAsset | asset_id, expected_revision | 200 |
| POST | /v1/projects/{project_id}/assets/{asset_id}/detach | detachProjectAsset | expected_revision | 200 |
Project 15 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects | listProjects | 200 | |
| POST | /v1/projects | createProject | title | 201 |
| GET | /v1/projects/{project_id} | getProject | 200 | |
| GET | /v1/projects/{project_id}/conversations | listConversations | 200 | |
| POST | /v1/projects/{project_id}/conversations | createConversation | title | 201 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id} | getConversation | 200 | |
| GET | /v1/projects/{project_id}/canvas | getCanvas | 200 | |
| POST | /v1/projects/{project_id}/canvas | saveCanvas | expected_revision, state | 200 |
| GET | /v1/projects/{project_id}/document | getDocument | 200 | |
| POST | /v1/projects/{project_id}/document | saveDocument | expected_revision, state | 200 |
| GET | /v1/projects/{project_id}/export-jobs | listExportJobs | 200 | |
| POST | /v1/projects/{project_id}/export-jobs | queueExport | document_revision, output? | 202 |
| GET | /v1/projects/{project_id}/export-jobs/{job_id} | getExportJob | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/binding | getMaaBinding | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/binding | bindMaa | agent_model XOR use_default:true | 200 |
User 3 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| POST | /v1/auth/register | register | email, password | 201 |
| POST | /v1/auth/login | login | email, password | 200 |
| GET | /v1/auth/session | session | 200 |
TopView 自己公开的接口调用流程(来自其官方资料)
| 步骤 | 调用关系 | 操作 | 证据 |
|---|---|---|---|
| 取得上传身份 | API调用方 → 文件接口 | GET https://api.topview.ai/v1/upload/credential?format=...&needAccelerateUrl=...;请求头 Topview-Uid、Authorization;返回 fileId/uploadUrl。 | A |
| 直传文件字节 | API调用方 → 对象存储 | PUT <返回的 uploadUrl>,Body 为本地文件字节;公开文档示例为 S3 签名 URL。 | A |
| 确认文件可用 | API调用方 → 文件接口 | GET https://api.topview.ai/v1/upload/check?fileId=...;合同示例检查 result=true。 | A |
| 提交预览任务 | API调用方 → 广告接口 | POST https://api.topview.ai/v1/m2v/task/submit;productLink 或 fileIds、preview=true;返回 taskId。 | A |
| 轮询预览结果 | API调用方 → 广告接口 | GET https://api.topview.ai/v1/m2v/task/query?taskId=...&needCloudFrontUrl=...。 | A |
| 审阅修改脚本 | API调用方 → 脚本接口 | GET https://api.topview.ai/v1/m2v/script/list?taskId=...;选择候选后 POST /v1/m2v/script/update,Body:{taskId,scriptId,scriptContents}。 | A |
| 选定版本导出 | API调用方 → 导出接口 | POST https://api.topview.ai/v1/m2v/export;Body:{taskId,scriptId}。 | A |
| 查询最终交付 | API调用方 → 广告接口 | 按 taskId 继续使用 GET https://api.topview.ai/v1/m2v/task/query 查询任务状态与结果;最终资源地址以实际合同响应为准。 | A |
TopView · 代码与下载
0.4 MB · 54 个文件 · SHA-256
2a843ce186fa1db905c5b8a71b20462ffad0b89e30a874f8148d9d2f089b0c6b下载:topview-replica.zip · 后端与合同 · 全部代码
| 目录 | 内容 |
|---|---|
| frontend/ | TopView 前端:<code>candidate-8875-unified-v22.html</code> 及它引用的全部脚本与样式 |
| contracts/ | 本品牌的表结构 SQL、ER(svg / mmd)、外键清单;接口目录(json / csv);共享身份库表结构 |
| README.md | 怎么运行、需要自备什么 |
运行前端
python3 -m http.server -d frontend 8791
# 打开 http://127.0.0.1:8791/agent-integration/apps-production-brand-v14/topview/candidate-8875-unified-v22.htmlbackend-and-contracts.zip;all-brands-code.zip 是全部。包里没有任何凭据、数据库备份或媒体文件,已做敏感串扫描。MAA_AGENT_ROOT)、模型网关与对象存储配置。静态前端单独打开不需要后端,但登录、对话、生成、导出需要整套服务。复刻完成度(审计 2026-10-19)
结论:不是完美复刻。官方资料里的 63 项能力:实测跑通 1、只有通用对话 0、后端有但没跑过 9、没有后端 53。
真正跑通的:创作 Agent。
界面对照(画布编辑器(新建项目后,已登录)):真实页面采集到 38 个控件 / 标题文字,复刻页找到 15 个;位置偏差中位数 0 px(13/15 个在 24 px 内)。缺的有:Navigation menu、Codex参考体验 · 咖啡广告(仅规划)、System Settings、Tutorial、Publish、Credits、Material manager、Collapse、Search names or prompts、Filter、List、Today…。
逐个点击(已登录首页):51 个可点控件,点了有效 7 个,只提示“此功能正在接入” 38 个,没反应或只变样式 3 个,禁用 3 个,未点(发送 / 删除 / 退出等)0 个。
只提示“正在接入”的控件(38 次点击,33 种)
工作区、AI Marketer、Community、Settings、Vidu Q4 Preview ×2、Nano Banana 2.1 ×2、3D Builder ×2、Kling 4 · Coming Soon ×2、Film Festival ×2、Video Agent、Drama Studio、Skills、Motion Video Design、Short Film Scriptwriter、Actor Expression Enhancer、Explainer Video Maker、Video Recast、UGC Ads、More Skills、Short film、Music video、Product film、UGC ads、Explainer video、Video recast、Brand story、Social video、All、Short Film、Marketing、Animation、Social、Explainer
点了没反应或只变样式的控件(3 次点击,3 种)
Home、Film Studio、Seedance 2.5
复刻页自报的绑定状态(页面内嵌的绑定清单):原生工作区控件(新建项目、会话、登录等)7 / 10 个没有绑定到原页面的控件,由统一的工作区条代替;路由都标为本地已确认;输入框 2 个标为“需要修结构”。
Pollo · 总览
- 它是什么:营销批量生成 + 大模板库(63 个技能);Agent 交互:流式事件,可停止,刷新后恢复。
- 我们借鉴:事件带序号可续读;模板与技能做成数据(决策 D8 D9)。
- 复刻现状:9 项已验证,在线试用 http://119.23.106.60:8102/;后端与其余六个品牌共用一套(24 张表、55 个接口),所以 ER / 表结构 / 接口页的通用部分默认折叠。
以 Agent、场景 Skill、多模型生成和营销工具为中心,另提供 Director 多轨编辑、API、MCP、CLI 和原生应用。历史登录仅验证一轮文字 Agent;其余媒体能力按官方说明盘点。
证据:W 官方说明,A 官方接口合同,C 客户端代码,O 实测。“未实测”= 只核对了官方页面,没有上传素材或生成。
80 项,分 12 类
Home / Create / Agent / Templates / Apps
24 张表 · 34 个外键 · 85 个索引
能力目录
Agent 与场景 4 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 自然语言 Agent 创作 | Web Agent 支持文字交互;官网说明可把脚本、图片和链接作为创作输入。 | O | 2026-10-12 历史登录只完成一轮文字回复;多模态仅观察输入菜单与官网描述,未提交图片、链接、脚本或生成媒体。 |
| 场景 Skill 选择 | 按故事、广告、UGC、音乐、讲解、电影、电商和地产选择创作场景。 | O | 2026-10-12 历史登录 UI 已观察 Skill 入口;未逐个执行,不能据入口推断完整工具链。 |
| 质量与执行策略 | Fast/Quality 控制生成策略,Autopilot/Guided 控制自主执行与确认节奏。 | O | 2026-10-12 历史 UI 和 high/guided 请求已观察;UI 档位与服务端实际 mode 映射、成本差异未验证。 |
| 澄清与局部修改 | Agent 可追问缺失条件,并修改指定场景、素材或方向后继续任务。 | W | 官网说明;未亲测中断、批准、修改后的依赖失效与恢复行为。 |
项目与会话 2 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 项目、会话和历史 | 项目下按 Thread 加载历史,单次 Run 有状态、消息和下一步建议。 | O | 2026-10-12 已观察 Project、Thread、Run 与分页请求;跨项目隔离、权限及数据库外键未验证。 |
| 流式回复与恢复入口 | Web 客户端采用 POST SSE 增量回复,并准备取消、重连和会话恢复逻辑。 | C | 2026-10-12 当前公开客户端静态分析;正常 SSE 另有实测,取消、断线续传、恢复保留期未触发。 |
视频生成 16 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 文生视频与提示词辅助 | 文字生成视频,可选画幅、时长、数量、分辨率和种子,并有提示词辅助。 | W | 参数随模型变化;页面中的生成音频选项不代表所有模型均支持。 |
| 图生视频 | 上传静态图片作为起点,描述动作并选择输出设置。 | W | 未实测 |
| 参考图引导视频 | 用角色、物体或场景参考引导视频内容与外观。 | W | 角色一致性是官网能力声明;跨镜头稳定性未做样本测试。 |
| 视频风格转换 | 已有视频作为输入,保留动作结构并改变视觉风格。 | W | 未实测 |
| 动作迁移 | 用参考动作视频驱动角色图片,复用表演与运动方向。 | W | 未实测 |
| 视频文字编辑 | 上传视频,用文字修改画面物体、背景、风格或光线。 | W | 官方文字编辑说明;未生成或核实具体模型的支持范围。 |
| 视频放大 | 提升已有视频的分辨率和清晰度。 | W | 未实测 |
| 视频换脸 | 以人物参考替换目标视频中的面部。 | W | 未实测 |
| 视频去背景 | 从视频中分离主体并移除背景。 | W | 未实测 |
| 视频延长 | 根据已有片段继续生成后续画面。 | W | 未实测 |
| 唇形同步 | 让人物视频的口型与输入声音匹配。 | W | 未实测 |
| 视频去字幕 | 移除画面中已有的烧录字幕。 | W | 未实测 |
| 视频降噪 | 降低视频中的颗粒和噪点。 | W | 未实测 |
| 视频物体移除 | 删除视频画面中的指定物体。 | W | 未实测 |
| 视频重构画幅 | 为不同画幅重新安排视频的取景。 | W | 未实测 |
| 视频主体抠像 | 分离指定视频主体,作为重新合成的素材。 | W | 未实测 |
图片生成与编辑 16 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 多模型图片生成 | 文字生成图片,选择模型、画幅及参考方向,用于设计、角色和商品视觉。 | W | 未实测 |
| 图生图与参考变体 | 输入已有图片生成变化版本,调整内容、风格和细节。 | W | 未实测 |
| 图片文字编辑 | 用编辑指令调整图片内容、布局或风格。 | W | 未实测 |
| 图片水印移除 | 清理图片上的水印或覆盖标记。 | W | 未实测 |
| 图片局部擦除 | 移除图片中的指定物体或区域内容。 | W | 未实测 |
| 图片放大 | 放大图片并增强细节。 | W | 未实测 |
| 图片去背景 | 从图片分离主体并移除背景。 | W | 未实测 |
| 图片换脸 | 用人物参考替换目标照片中的面部。 | W | 未实测 |
| 对话式图片创作 | 通过聊天描述生成或继续修改图片。 | W | 未实测 |
| 图片锐化 | 增强模糊图片的边缘和视觉清晰度。 | W | 未实测 |
| 图片背景生成 | 为主体生成新的场景背景。 | W | 未实测 |
| 图片背景模糊 | 模糊背景以突出主体。 | W | 未实测 |
| 图片背景替换 | 将已有背景替换为指定场景。 | W | 未实测 |
| 图片白底处理 | 将图片背景调整为白色。 | W | 未实测 |
| 图片人物移除 | 从图片中删除选定人物。 | W | 未实测 |
| 面部抠图 | 从人物图片提取面部或头部区域。 | W | 未实测 |
角色与音频 5 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 照片数字人与说话角色 | 单张照片或角色参考生成说话视频,配合语音呈现口播。 | W | 官方页面说明;未创建角色,口型、身份和动作质量未实测。 |
| 多语言文字配音 | 选择语言、口音和音色,将文字转为配音音频。 | W | 未生成配音;音色许可、语言效果和商业使用范围须确认。 |
| 音效生成 | 按声音描述生成音效,为视频补充环境和动作声音。 | W | 未实测 |
| 商品数字人 | 用商品照片生成由数字人展示或讲解商品的视频。 | W | 未实测 |
| 声音克隆 | 用参考音频建立可复用声音。 | W | 未上传声音;克隆授权、样本要求和语言质量须实测。 |
画布与时间轴 4 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| Director 多场景上下文 | 从想法或已有镜头组织作品,复用人物、商品和地点并比较不同 take。 | W | 官网 Director Beta 能力;未登录创建工程,不能据此推断其与 Agent Project 的实体关系。 |
| 多轨时间轴编辑 | 视频、字幕、音频放在多轨时间轴,可裁剪、拆分和重排。 | W | W:当前官网明确展示;未验证工程保存接口、版本冲突、导出结果或与 Canvas 同步。 |
| 字幕编辑 | 修改字幕文字、字体、大小和颜色,可逐条或统一应用。 | W | 官网描述;字幕格式、自动识别准确率和导出兼容性未验证。 |
| 镜头再生成与首末帧 | 镜头保留提示词、参考、模型和参数,按位置再生成并用首末帧衔接。 | W | 官网描述;首末帧连续性与历史版本持久化未验证。 |
素材与品牌 2 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 分类素材与输入来源 | 素材按商品、角色、场景、风格、道具分类;附件支持上传、元素、品牌和作品来源。 | O | 2026-10-12 历史登录 UI 已观察;素材详情、用户级归属、跨项目权限和版本结构未验证。 |
| Brand Kit | 保存品牌标志、颜色、字体和语气,供品牌内容复用。 | W | 官网说明;字段 Schema、自动应用范围与团队共享权限未实测。 |
模板与灵感 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 场景应用和模板 | Apps 与 Marketing Studio 提供按创作目的选择的 Skill、应用与模板。 | W | 目录与模板入口已核实;不把同一生成能力的应用别名重复统计。 |
| 灵感与作品复用 | 浏览示例灵感,并将已认可的参考或生成素材带回创作。 | W | 官网描述;社区投稿、点赞、复制权限及公开作品治理未验证。 |
| 广告灵感库 | Marketing Studio 提供 Ad Library,用于发现和搜索广告参考。 | W | 公开页面正文有限;广告覆盖量、筛选条件、下载与使用权限未知。 |
营销批量创作 18 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 商品链接转视频广告 | 从商品链接提取背景与卖点,形成视频广告任务。 | W | 官网入口;未抓取商品链接,素材采集、授权和广告成片质量未实测。 |
| 参考广告改编 | 以参考广告为起点,为自己的商品复用叙事或展示方式。 | W | 未提交参考广告;相似度、可编辑范围和第三方素材权利未知。 |
| 批量短视频创作 | 按批量任务生成短视频变体。 | W | Web 批量并发、任务数量上限与失败计费未验证;不套用 CLI/MCP 批量上限。 |
| 商品照片生成 | 生成用于展示和宣传商品的照片。 | W | 官方说明;商品细节保持与平台审核结果未实测。 |
| 虚拟试穿视频 | 用服装和人物参考生成穿搭展示视频。 | W | 未实测 |
| 商品照片转视频广告 | 以商品图片作为视频广告的起点。 | W | 未实测 |
| 脚本转视频广告 | 输入已写好的广告脚本生成对应视频。 | W | 未实测 |
| UGC 风格视频广告 | 将商品信息组织为用户分享或口播风格的广告。 | W | 未实测 |
| 商品 Listing 图片套组 | 为商品生成配套展示图片。 | W | 未实测 |
| 商品海报生成 | 把商品信息组合为推广海报。 | W | 未实测 |
| 商品场景布置 | 把商品放进生活或营销展示场景。 | W | 未实测 |
| 服装平铺图 | 将服装参考整理为平铺展示图。 | W | 未实测 |
| 商品图片美化 | 改善已有商品图的展示效果。 | W | 未实测 |
| 服装隐形模特 | 生成保留服装形状的无模特展示图。 | W | 未实测 |
| 商品参考图改编 | 根据参考商品视觉制作自己的商品展示。 | W | 未实测 |
| 图片服装替换 | Marketing Studio 有替换人物服装的工具入口。 | W | 当前公开目录可见工具名;具体输入、数量上限、输出结构和收费未实测。 |
| 商品 A+ 内容 | Marketing Studio 有制作电商 A+ 内容的入口。 | W | 当前公开目录可见工具名;具体输入、数量上限、输出结构和收费未实测。 |
| 批量参考视频改编 | Marketing Studio 有批量改编参考短视频的入口。 | W | 当前公开目录可见工具名;具体输入、数量上限、输出结构和收费未实测。 |
分享与交付 1 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 公开可见性、复制控制与下载 | 生成页有 Public Visibility 与 Copy Protection 选项;成品可下载用于交付。 | W | 只核实入口与官网说明;分享 URL、ACL、复制保护效果及实时协作均未验证。 |
订阅与权益 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 订阅与积分余额 | 订阅发放积分,工具、模型、时长、数量和分辨率影响消耗,可查看余额。 | W | 官网 FAQ 说明订阅积分不结转;不固化价格、当前余额或所有套餐额度。 |
| 升级和加购积分 | 可通过升级或符合条件的积分加购包补充使用额度。 | W | 资格、结算方式与地区价格以当前账号确认;未购买或改变订阅。 |
| 商业使用与无水印权益 | 官方说明付费商业使用及无水印导出权益。 | W | 无水印依据官方地区页,具体工具、模型和套餐应查看当前条款;不作第三方素材版权保证。 |
开放集成与客户端 6 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 统一多模型入口 | 视频、图片和音频能力按模型入口选择,共用产品工具导航。 | W | 模型品牌合并为目录能力;可用版本、参数和输出规格随时间变化。 |
| 异步生成 API | API Key 鉴权提交模型生成任务,返回 taskId 与 pending 状态。 | A | 官方合同未调用;示例和正文存在旧字段表述,集成应以选定模型 Schema 为准。 |
| 任务查询与回调 | 按 taskId 查询生成结果、失败原因和成本,或用 webhook 接收完成通知。 | A | 仅核实合同;回调签名、重试保证、幂等与可用性未验证。 |
| MCP 创作和任务卡片 | 通过 MCP 生成、编辑和增强素材,支持任务状态、费用估算及客户端卡片。 | W | 官方能力说明;未连接 MCP,不假定所有客户端支持同一种交互卡片。 |
| CLI 与本地文件接入 | CLI 通过账号授权调用创作能力,可提交参考文件、批量任务并查询余额和进度。 | W | 官方称单批 1–12 任务;未安装执行,不能套用于 Web 或公开 API。 |
| iOS 与 Android 创作应用 | 原生应用提供生成、编辑、Agent、模板及社交尺寸创作入口。 | W | 只核实官方商店说明,未安装;Director、素材同步和 Web 功能是否完整对应未知。 |
尚不清楚的部分
- 素材跨项目与用户级归属:已见分类和输入菜单,未见有效详情及跨项目权限测试,不能确定 AssetVersion、共享和归属基数。
- Canvas 与 Director 工程关系及保存:存在 CanvasProject 列表和 Director 官网能力,但详情、保存/CAS、版本和双模式同步未验证。
- 实时团队协作、共享 ACL 与审计:下载和 Public Visibility 入口不等于邀请、角色权限或实时共编;未取得合同或有效实测。
- 取消与断线续传保证:客户端具备逻辑,历史文字测试未触发异常,后台继续执行与事件保留期未知。
- Pollo 浏览器扩展:未确认由官方发布的现行扩展,不把其他厂商同名工具计入。
- 原生与 Web 功能及订阅互通:只有官方商店说明;素材同步、Director 对应和跨端权益未登录验证。
竞品技术栈观察
Pollo 可高置信识别此前发布的 Next.js/Turbopack 前端构件;精确框架版本、原始源码语言、Nginx 与后端实现仍未知。Cloudflare/Vercel 只限边缘或子站线索。
| 项目 | 观察到的内容 | 状态 | 置信度 |
|---|---|---|---|
| Nginx 产品及准确版本 | 未确认使用 Nginx;准确版本未知。 | unknown | low |
| 浏览器运行语言 | 已交付浏览器 JavaScript chunks;不是原始 TypeScript 源文件。 | observed | high |
| 前端原始源码语言 | 未知:可能有 JS、TS 或 TSX,但未取得源码证据。 | unknown | low |
| 前端框架及版本 | Next.js 指纹很强;精确 Next.js、React 版本未知。 | inferred | high |
| 构建器、SSR 与渲染模式 | 观察到 TURBOPACK 和 _next 构件;SSR/SSG/ISR 策略与构建器版本未知。 | observed | high |
| 后端语言 | 未知:业务服务、Agent、计费及生成 Worker 的语言均未证实。 | unknown | low |
| 后端框架及版本 | 实际框架未知;仅观察到 tRPC 客户端与 LangGraph 风格 Agent 协议。 | unknown | low |
| CDN、边缘与源站界限 | 先前公网 DNS 落在 Cloudflare 地址段;docs 有 Vercel CNAME。业务源站与地域未知。 | inferred | high |
| 前后端仓库与目录关系 | 未知:同域 API、Next 构件及公开 CLI 仓库不能证明前后端同仓或同目录。 | unknown | low |
竞品服务调用图
真实文字调用链为项目上下文 → Thread → Run POST SSE → 工具消息 → 终态读回。媒体、素材、权益和部署边界另外标注,不能从兼容协议还原服务端实现。
| 节点 | 层 | 职责 | 证据 |
|---|---|---|---|
| Web客户端 | client | 已观察项目列表、场景入口和文字 Agent 交互的浏览器 UI。 | O |
| 公开边缘入口 | entry | 公网 DNS 地址段与 Cloudflare 相符,可能提供产品域入口与缓存。 | I |
| 业务JSON入口 | entry | 实际 tRPC 列表过程的公开调用边界。 | O |
| Agent HTTP入口 | entry | 实际 /api/agent-gateway/agent/v1 Thread/Run 资源与 SSE 入口。 | O |
| 项目会话职责 | domain | 处理 Project/Thread 的身份与项目上下文,组织会话查询。 | I |
| 订阅积分职责 | domain | 提供订阅、使用桶与允许能力的业务视图,可能参与任务额度控制。 | I |
| 素材产物职责 | domain | 用户元素列表及 Thread artifacts 入口反映素材查询、引用或结果整理职责。 | I |
| Agent运行职责 | runtime | Run 状态及工具消息表明存在消息组织与执行编排职责。 | I |
| 文字呈现工具 | runtime | 协议中确实出现名为 message_notify_user 的调用和成功 ToolResult。 | O |
| 媒体任务职责 | runtime | 官网描述由 Agent 生成视频/图片/声音,可能需要组织生成任务与输出。 | I |
| 会话状态保存 | data | GET state 和 conversation 可返回终态消息,可能有缓存、文件或数据库保存。 | I |
| 模型执行边界 | external | 产品和公开生成合同涉及模型选择,可能调用内部模型或外部供方。 | I |
| 文件存储待核实 | data | 媒体或用户文件如何持有、落库和交付尚未确认。 | U |
| 公开生成API | entry | 官方 API 合同定义模型任务提交、查询及 webhook。 | A |
增长与运营机制
复刻状态
| 能力 | 状态 | 依据 |
|---|---|---|
| 登录、注册、会话过期提示、登录入口 | 已验证 | 过期后 8 秒内出现横幅,点「登录」弹登录框,登录后会话自动恢复 |
| Agent 多轮对话、刷新后恢复会话 | 已验证 | 真实 Maa;18 条消息恢复 |
| 根据方案生成视频(报价→批准→生成→素材) | 已验证 | 两次真实 Seedance 2.5 生成,15 积分/次;报价过期后批准被拒,不建任务不扣费 |
| 停止回复 | 已验证 | 修复了 v17 起就存在的缺陷;数据库有停止记录,run=cancelled;对话里显示「已停止回复」 |
| 切换模型 | 已验证 | DeepSeek-V4-Flash,模型版本 0→1 |
| 素材页、Apps/Tools 目录、Templates 页、Create | 已验证 | Apps 为 Agent 模板入口,Tools 标注未接入;Templates 为自写起始提示词 |
| 澄清卡片(HITL) | 已验证(隔离环境) | 没说清商品时 Agent 发出「商品名称」卡,页面渲染卡片,用户回答后同一个 Run 恢复并继续执行,最终给出完整分镜方案(真实 Maa,新对话完整走通)。过程中遇到并修了三个问题:Agent 的 plan-only 策略不给交互工具;业务后端只认哈希形式的卡指纹;前端模型切换层在卡打开时拒绝回答。限制:业务后端只认这一种单字段卡,Agent 侧已限制只能发它;一次恢复后的 Run 因模型偶发「工具调用无法解析」失败,重试后完成。生产实例未启用 |
| 多模型生成(Seedance 2.5 / 2.0 / 2.0 Fast / 2.0 Mini) | 已验证 | 四个模型都真实生成成功并入账(Mini 5 秒 3 积分、Fast 15 秒 10 积分、2.0 5 秒 8 积分、2.5 15 秒 15 积分);每个模型一个独立 worker 进程;对话框的模型下拉按数据显示各自价格。新增模型不改代码:只加一份 SQL,并给该 worker 设环境变量 STUDIO_MEDIA_GATEWAY_EXTRA_MODELS。另试了 Seedance 1.5 Pro(两条供应商路由),网关接收后被供应商判失败且无原因,疑似当前密钥无权限,冻结积分保持“费用待核对”,没有出片 |
| 聊天内附件 | 已验证(隔离环境) | 在隔离实例上点输入框「+」选图→上传→发送,助手回答出图片颜色;上传 201、消息 202。生产实例没有启用:附件与统一品牌实例互斥,且需要带输入文件能力的 Maa 与对应迁移 |
agent-integration/apps-production-brand-v14/pollo/candidate-8891-attachments-v22.html复刻的架构 七个品牌相同,展开查看
flowchart LR U[浏览器] -->|静态页| FE[品牌前端<br/>令牌 + 通用层 + 运行时脚本] FE -->|/v1/* Cookie + CSRF| BFF[BFF 业务服务 Go] BFF --> MY[(MySQL<br/>共享身份库 + 品牌库)] BFF -->|会话 / 消息 / 事件| MAA[Maa Agent] BFF -->|任务| WK[媒体 worker] WK -->|submit_video| GW[模型网关] GW --> MOD[视频模型] MAA --> GW BFF --> OBJ[(素材 / 导出存储)]
?profile=pollo 区分品牌)。品牌差异在前端:令牌(颜色、圆角、字体)、入口与页面结构。Pollo · Agent 交互过程
竞品里观察到的
NOT_RUN_NO_FREE_CONFIRMATION 本轮登录后查看Agent和Director只读工程、素材与时间轴,余额422;新文字回合未发现明确免费承诺,因此未发送。此前17帧SSE文字回合、0媒体/0积分,仅复用历史证据,不冒充本轮完整方案交互。
Pollo 实测的接口
| 方法 | 路径 | 请求 | 用途 |
|---|---|---|---|
| POST | /threads | `metadata:{idempotency_key:string,project_id:string}` | `{code:number,msg:string,data:{thread_id:string}}`,先建立长会话 |
| POST | /threads/{thread_id}/runs/stream | 下节完整结构 | 200 SSE,创建并订阅这一轮 Run |
| POST | /threads/search | `metadata:{project_id:string},limit:number,offset:number` | `data:{threads:ThreadSummary[],total:number}`,按当前 Project 加载历史 |
| POST | /threads/status | `thread_ids:string[]` | `data.threads[]:{thread_id,status,metadata,updated_at}`,批量状态轮询 |
| GET | /threads/{thread_id}/state | 无 Body | `data:{checkpoint,checkpoint_id,parent_checkpoint,parent_checkpoint_id,created_at,interrup |
| GET | /threads/{thread_id}/runs | Query keys `limit,offset,status` | `data.runs:[]`,此处 UI 查询特定状态,不能据空列表推断无历史 Run |
| POST | /threads/{thread_id}/conversation | `{limit:10}` | `data:{messages:Message[],has_more:boolean,next_before_id:number}` |
| POST | /threads/{thread_id}/artifacts | `{}` | `data:{artifact_groups:{}}`,本次无素材 |
| GET | /threads/{thread_id}/suggestions | Query key `turn_id` | `data.items:string[]`,本次返回 3 条下一步建议 |
竞品公开的调用流程
| 步骤 | 调用关系 | 操作 | 证据 |
|---|---|---|---|
| 载入项目上下文 | 浏览器 → 业务入口 | tRPC UI batch:userProject.getListV2、generationModel.list、userElement.list。 | O |
| 读取项目会话 | 浏览器 → Agent入口 | POST /api/agent-gateway/agent/v1/threads/search;metadata.project_id、limit、offset。 | O |
| 创建长会话 | 浏览器 → Agent入口 | POST /api/agent-gateway/agent/v1/threads;metadata:{project_id,idempotency_key} → data.thread_id。 | O |
| 启动当前回合 | 浏览器 → Agent入口 | POST /api/agent-gateway/agent/v1/threads/{thread_id}/runs/stream;input.messages、config.configurable、metadata、stream_mode;返回 text/event-stream。 | O |
| 合并流式消息 | Agent入口 → 浏览器 | SSE metadata(run_id)、values、messages([MessageChunk,ExecutionMetadata])、end;每帧含 event/data/id。 | O |
| 显示工具结果 | Agent入口 → 浏览器 | messages 中出现 message_notify_user:ToolCall.id == ToolResult.tool_call_id;status=success、artifact=[]。 | O |
| 读回持久视图 | 浏览器 → Agent入口 | end success 后:GET /api/agent-gateway/agent/v1/threads/{thread_id}/state;POST .../conversation;POST .../artifacts;GET .../suggestions?turn_id=...。 | O |
| 核对商业视图 | 浏览器 → 业务入口 | 刷新首页可见积分,并读取既有 subLog.getSubLog / subUsage 订阅与用量投影;未取得完整私有 HTTP 路径。 | O |
在本品牌复刻上的测试结果
| 能力 | 状态 | 依据 |
|---|---|---|
| Agent 多轮对话、刷新后恢复会话 | 已验证 | 真实 Maa;18 条消息恢复 |
| 根据方案生成视频(报价→批准→生成→素材) | 已验证 | 两次真实 Seedance 2.5 生成,15 积分/次;报价过期后批准被拒,不建任务不扣费 |
| 停止回复 | 已验证 | 修复了 v17 起就存在的缺陷;数据库有停止记录,run=cancelled;对话里显示「已停止回复」 |
| 切换模型 | 已验证 | DeepSeek-V4-Flash,模型版本 0→1 |
| 澄清卡片(HITL) | 已验证(隔离环境) | 没说清商品时 Agent 发出「商品名称」卡,页面渲染卡片,用户回答后同一个 Run 恢复并继续执行,最终给出完整分镜方案(真实 Maa,新对话完整走通)。过程中遇到并修了三个问题:Agent 的 plan-only 策略不给交互工具;业务后端只认哈希形式的卡指纹;前端模型切换层在卡打开时拒绝回答。限制:业务后端只认这一种单字段卡,Agent 侧已限制只能发它;一次恢复后的 Run 因模型偶发「工具调用无法解析」失败,重试后完成。生产实例未启用 |
| 多模型生成(Seedance 2.5 / 2.0 / 2.0 Fast / 2.0 Mini) | 已验证 | 四个模型都真实生成成功并入账(Mini 5 秒 3 积分、Fast 15 秒 10 积分、2.0 5 秒 8 积分、2.5 15 秒 15 积分);每个模型一个独立 worker 进程;对话框的模型下拉按数据显示各自价格。新增模型不改代码:只加一份 SQL,并给该 worker 设环境变量 STUDIO_MEDIA_GATEWAY_EXTRA_MODELS。另试了 Seedance 1.5 Pro(两条供应商路由),网关接收后被供应商判失败且无原因,疑似当前密钥无权限,冻结积分保持“费用待核对”,没有出片 |
复刻里的 Agent 交互设计(时序图、状态机、规则) 七个品牌相同,展开查看
sequenceDiagram
autonumber
participant B as 浏览器
participant S as BFF
participant DB as MySQL
participant M as Maa Agent
participant W as 媒体 worker
participant G as 模型网关
B->>S: POST /projects, /conversations
B->>S: POST maa/binding
S->>DB: maa_bindings dispatching
S->>M: 创建原生会话
M-->>S: native_cid
S->>DB: maa_bindings bound
B->>S: POST maa/messages {client_action_id, content}
S->>DB: maa_message_actions 幂等回执
S-->>B: 202 + run_id
S->>M: 提交消息
S->>DB: maa_runs queued 到 running
loop 事件游标
B->>S: GET runs/{id}/events
S-->>B: assistant.delta / assistant.message
end
M-->>S: run.completed
S->>DB: 记录助手内容 SHA-256
B->>S: POST media/requests/from-maa {source_run_id, sha256}
S-->>B: 报价 + 有效期 + quote_sha256
B->>S: POST approve {client_approval_id, request_sha256, quote_sha256}
S->>DB: 冻结积分 + 建任务
W->>G: submit_video
G-->>W: 视频
W->>DB: 产出入库 + 扣费
B->>S: GET media/jobs/{id}Run 状态机
stateDiagram-v2 [*] --> queued: POST maa/messages 202 queued --> running running --> waiting_interaction: 需要澄清卡 waiting_interaction --> running: respondInteraction running --> completed running --> failed running --> cancelled: stopRun waiting_interaction --> cancelled completed --> [*] failed --> [*] cancelled --> [*]
媒体任务状态机
stateDiagram-v2 [*] --> quoted quoted --> expired: 约 5 分钟 quoted --> approved: approve approved --> held: 冻结积分 held --> queued queued --> running: worker 领取 running --> succeeded: 产出入库 succeeded --> captured: 扣费确认 running --> failed failed --> 待核对: 供应商已受理后失败,冻结保留,界面写「费用待核对」
交互规则
| 环节 | 规则 | 落库 |
|---|---|---|
| 绑定会话 | bindMaa 传 agent_model 或 use_default;先 dispatching,拿到原生会话号后才 bound(约束保证二者一致) | maa_bindings |
| 发消息 | client_action_id 幂等;返回 202 + run_id;同一个动作 ID 内容不同返回 409 | maa_message_actions, maa_runs |
| 事件 | 按 seq 游标读取;服务端先清洗路径、内部地址和令牌再公开 | maa_runs.last_event_seq |
| 完成证据 | 完成时记录助手内容的两份 SHA-256 与字节数 | maa_runs |
| 澄清卡(HITL) | Run 进入 waiting_interaction;respondInteraction 带 card_sha256;不能恢复两次 | maa_interactions, maa_interaction_actions |
| 停止 | stopRun 幂等,回执只说「已观测到终态」;对话里保留「已停止回复」 | maa_run_stop_actions |
| 切换模型 | 必须带 expected_revision;有未决切换时拒绝发新消息 | maa_model_change_actions |
| 生成视频 | from-maa → 报价 → 批准 → 冻结 → worker → 入库 → 扣费;批准带请求哈希与报价哈希 | studio_media_*, 积分账本 |
| 报价过期 | 批准被拒,不建任务不扣费;界面提示重新报价 | studio_media_requests.expires_at |
| 失败后的积分 | 供应商已受理后失败:冻结保留,界面写「费用待核对」,不自动释放;本部署的账本里还没出现过释放分录(12 笔冻结、8 笔扣费、其余 4 笔仍冻结) | studio_credit_ledger_entries |
| 会话过期 | 每 8 秒检查登录状态;失效时横幅提示,登录后恢复 | — |
Pollo · ER 图
品牌库 studio_profile_pollo:24 张表、34 个真实外键、66 个检查约束、22 个触发器。图由实际表结构生成,箭头从父表指向子表。品牌库与共享身份库之间的 owner_id、asset_id 靠应用层归属检查,不画成外键。
共 61 条关系:一对多 37 条,一对一 10 条,一对多(父可选) 10 条,一对一(父可选) 4 条;多对多 2 组(经关联表)。
用户与登录 素材 积分账本 支付与订阅 模型目录 项目与会话 画布 · 时间轴 · 导出 Agent 交互 生成 · 媒体 · 交付
基数标注(线上的文字,箭头从父表指向子表):1:N 一对多,子表外键必填;0..1:N 一对多,但外键可空,所以父是可选的;1:1 一对一,子表外键上有唯一键;0..1:1 一对一且父可选。红色粗双向线 = N:M 多对多,经带 ⇄ 的关联表(它的主键就是两个外键)。实线 = 数据库真实外键;灰色虚线 = 跨库关系(两个库之间数据库无法建外键,由应用层检查);橙色粗框与粗线 = Agent 交互相关。每张表都带 owner_id(指向用户),为了图清楚没有逐条画线。
全景图:全部实体与关系
默认缩放到页面宽度,先看整体结构;点一下图切换到原始大小(看清表名,在框内上下左右滚动),再点一下缩回。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":26,"rankSpacing":80}}}%%
flowchart LR
subgraph sg_i_user["用户与登录"]
direction TB
t_studio_users["users"]
t_studio_sessions["sessions"]
end
subgraph sg_i_asset["素材"]
direction TB
t_studio_assets["assets"]
end
subgraph sg_i_credit["积分账本"]
direction TB
t_studio_credit_accounts["credit_accounts"]
t_studio_credit_lots["credit_lots"]
t_studio_credit_authorizations["credit_authorizations"]
t_studio_credit_authorization_allocations["⇄ credit_authorization_allocations"]
t_studio_credit_ledger_entries["credit_ledger_entries"]
t_studio_credit_plan_versions["credit_plan_versions"]
t_studio_billing_cycles["billing_cycles"]
end
subgraph sg_i_pay["支付与订阅"]
direction TB
t_studio_payment_orders["payment_orders"]
t_studio_payment_events["payment_events"]
t_studio_subscriptions["subscriptions"]
end
subgraph sg_i_model["模型目录"]
direction TB
t_studio_media_models["media_models"]
t_studio_media_model_versions["media_model_versions"]
end
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_canvas["画布 · 时间轴 · 导出"]
direction TB
t_studio_video_documents["video_documents"]
t_studio_canvases["canvases"]
t_studio_canvas_revisions["canvas_revisions"]
t_studio_timeline_revisions["timeline_revisions"]
t_studio_export_jobs["export_jobs"]
t_studio_project_asset_refs["⇄ project_asset_refs"]
end
subgraph sg_agent["⭕ Agent 交互"]
direction TB
t_maa_bindings["maa_bindings"]
t_maa_runs["maa_runs"]
t_maa_message_actions["maa_message_actions"]
t_maa_interactions["maa_interactions"]
t_maa_interaction_actions["maa_interaction_actions"]
t_maa_model_change_actions["maa_model_change_actions"]
t_maa_run_stop_actions["maa_run_stop_actions"]
end
subgraph sg_media["生成 · 媒体 · 交付"]
direction TB
t_studio_media_requests["media_requests"]
t_studio_media_jobs["media_jobs"]
t_studio_media_submission_attempts["media_submission_attempts"]
t_studio_media_outputs["media_outputs"]
t_generation_jobs["gen_jobs"]
t_generation_reservations["gen_reservations"]
t_generation_deliveries["gen_deliveries"]
t_generation_development_budgets["gen_development_budgets"]
t_studio_credit_recovery_intents["credit_recovery_intents"]
end
t_studio_users -->|"1:N"| t_studio_assets
t_studio_payment_orders -->|"1:1"| t_studio_billing_cycles
t_studio_subscriptions -->|"1:N"| t_studio_billing_cycles
t_studio_users -->|"1:1"| t_studio_credit_accounts
t_studio_credit_authorizations -->|"1:N"| t_studio_credit_authorization_allocations
t_studio_credit_lots -->|"1:N"| t_studio_credit_authorization_allocations
t_studio_credit_accounts -->|"1:N"| t_studio_credit_authorizations
t_studio_credit_authorization_allocations -->|"0..1:N"| t_studio_credit_ledger_entries
t_studio_credit_authorizations -->|"0..1:N"| t_studio_credit_ledger_entries
t_studio_credit_lots -->|"1:N"| t_studio_credit_ledger_entries
t_studio_credit_accounts -->|"1:N"| t_studio_credit_lots
t_studio_billing_cycles -->|"0..1:1"| t_studio_credit_lots
t_studio_payment_orders -->|"0..1:1"| t_studio_credit_lots
t_studio_media_models -->|"1:N"| t_studio_media_model_versions
t_studio_media_model_versions -->|"0..1:1"| t_studio_media_models
t_studio_payment_orders -->|"0..1:N"| t_studio_payment_events
t_studio_subscriptions -->|"0..1:N"| t_studio_payment_events
t_studio_users -->|"1:N"| t_studio_payment_events
t_studio_credit_plan_versions -->|"1:N"| t_studio_payment_orders
t_studio_users -->|"1:N"| t_studio_payment_orders
t_studio_users -->|"1:N"| t_studio_sessions
t_studio_credit_plan_versions -->|"1:N"| t_studio_subscriptions
t_studio_users -->|"1:N"| t_studio_subscriptions
t_generation_jobs -->|"1:1"| t_generation_deliveries
t_studio_projects -->|"1:N"| t_generation_deliveries
t_studio_conversations -->|"1:N"| t_generation_deliveries
t_generation_development_budgets -->|"1:N"| t_generation_jobs
t_studio_projects -->|"1:N"| t_generation_jobs
t_studio_conversations -->|"1:N"| t_generation_jobs
t_generation_jobs -->|"1:1"| t_generation_reservations
t_studio_conversations -->|"1:1"| t_maa_bindings
t_maa_model_change_actions -->|"0..1:1"| t_maa_bindings
t_maa_interactions -->|"1:1"| t_maa_interaction_actions
t_maa_runs -->|"1:N"| t_maa_interactions
t_maa_bindings -->|"1:N"| t_maa_message_actions
t_maa_runs -->|"0..1:N"| t_maa_message_actions
t_maa_bindings -->|"1:N"| t_maa_model_change_actions
t_maa_runs -->|"1:1"| t_maa_run_stop_actions
t_maa_bindings -->|"1:N"| t_maa_runs
t_studio_canvases -->|"1:N"| t_studio_canvas_revisions
t_studio_canvas_revisions -->|"0..1:N"| t_studio_canvas_revisions
t_studio_projects -->|"1:1"| t_studio_canvases
t_studio_projects -->|"1:N"| t_studio_conversations
t_studio_media_jobs -->|"1:N"| t_studio_credit_recovery_intents
t_studio_projects -->|"1:N"| t_studio_export_jobs
t_studio_media_requests -->|"1:1"| t_studio_media_jobs
t_studio_media_jobs -->|"1:N"| t_studio_media_outputs
t_studio_conversations -->|"1:N"| t_studio_media_requests
t_maa_runs -->|"0..1:N"| t_studio_media_requests
t_studio_media_jobs -->|"1:N"| t_studio_media_submission_attempts
t_studio_projects -->|"1:N"| t_studio_project_asset_refs
t_studio_video_documents -->|"1:N"| t_studio_timeline_revisions
t_studio_timeline_revisions -->|"0..1:N"| t_studio_timeline_revisions
t_studio_projects -->|"1:1"| t_studio_video_documents
t_studio_assets -.->|"1:N"| t_studio_project_asset_refs
t_studio_assets -.->|"1:N"| t_studio_media_outputs
t_studio_assets -.->|"1:N"| t_generation_deliveries
t_studio_media_model_versions -.->|"1:N"| t_studio_media_requests
t_studio_media_models -.->|"1:N"| t_studio_media_requests
t_studio_credit_authorizations -.->|"0..1:N"| t_studio_media_jobs
t_studio_credit_authorizations -.->|"0..1:N"| t_studio_credit_recovery_intents
t_studio_credit_authorizations <-.->|"N:M · 经 credit_authorization_allocations"| t_studio_credit_lots
t_studio_projects <-.->|"N:M · 经 project_asset_refs"| t_studio_assets
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_users,t_studio_sessions user
class t_studio_assets asset
class t_studio_credit_accounts,t_studio_credit_lots,t_studio_credit_authorizations,t_studio_credit_authorization_allocations,t_studio_credit_ledger_entries,t_studio_credit_plan_versions,t_studio_billing_cycles credit
class t_studio_payment_orders,t_studio_payment_events,t_studio_subscriptions pay
class t_studio_media_models,t_studio_media_model_versions model
class t_studio_projects,t_studio_conversations project
class t_studio_video_documents,t_studio_canvases,t_studio_canvas_revisions,t_studio_timeline_revisions,t_studio_export_jobs,t_studio_project_asset_refs canvas
class t_maa_bindings,t_maa_runs,t_maa_message_actions,t_maa_interactions,t_maa_interaction_actions,t_maa_model_change_actions,t_maa_run_stop_actions agent
class t_studio_media_requests,t_studio_media_jobs,t_studio_media_submission_attempts,t_studio_media_outputs,t_generation_jobs,t_generation_reservations,t_generation_deliveries,t_generation_development_budgets,t_studio_credit_recovery_intents media
class t_studio_credit_authorization_allocations,t_studio_project_asset_refs junction
style sg_i_user fill:none,stroke:#6b7280,stroke-width:1px,stroke-dasharray:5 4
style sg_i_asset fill:none,stroke:#06b6d4,stroke-width:1px,stroke-dasharray:5 4
style sg_i_credit fill:none,stroke:#eab308,stroke-width:1px,stroke-dasharray:5 4
style sg_i_pay fill:none,stroke:#ec4899,stroke-width:1px,stroke-dasharray:5 4
style sg_i_model fill:none,stroke:#6366f1,stroke-width:1px,stroke-dasharray:5 4
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_canvas fill:none,stroke:#3b82f6,stroke-width:1px
style sg_agent fill:#fff7ed,stroke:#f97316,stroke-width:4px
style sg_media fill:none,stroke:#22c55e,stroke-width:1px
linkStyle 30,31,32,33,34,35,36,37,38,48 stroke:#f97316,stroke-width:2.5px
linkStyle 54,55,56,57,58,59,60 stroke:#64748b,stroke-width:1.5px,stroke-dasharray:4 3
linkStyle 61,62 stroke:#dc2626,stroke-width:3px多对多(N:M)
数据库里没有“多对多”这种列,它总是靠一张关联表表达。下面这几张表的主键由两个外键组成,所以它们两端是多对多:
| 多对多的两端 | 关联表 | 关联表的主键 / 唯一键 |
|---|---|---|
studio_credit_authorizations ⇄ studio_credit_lots | studio_credit_authorization_allocations | owner_id, authorization_id, lot_id |
studio_projects ⇄ studio_assets | studio_project_asset_refs | project_id, asset_id |
Agent 交互相关(圈出来)
绑定 → Run → 消息 / 澄清卡 / 切换模型 / 停止,每个动作一张回执表;线上是“外键列 · 基数”。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":40,"rankSpacing":90}}}%%
flowchart LR
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_agent["⭕ Agent 交互"]
direction TB
t_maa_bindings["maa_bindings"]
t_maa_runs["maa_runs"]
t_maa_message_actions["maa_message_actions"]
t_maa_interactions["maa_interactions"]
t_maa_interaction_actions["maa_interaction_actions"]
t_maa_model_change_actions["maa_model_change_actions"]
t_maa_run_stop_actions["maa_run_stop_actions"]
end
t_studio_conversations -->|"conversation_id · 1:1"| t_maa_bindings
t_maa_model_change_actions -->|"pending_model_change_id · 0..1:1"| t_maa_bindings
t_maa_interactions -->|"interaction_id · 1:1"| t_maa_interaction_actions
t_maa_runs -->|"public_run_id · 1:N"| t_maa_interactions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_message_actions
t_maa_runs -->|"public_run_id · 0..1:N"| t_maa_message_actions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_model_change_actions
t_maa_runs -->|"public_run_id · 1:1"| t_maa_run_stop_actions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_runs
t_studio_projects -->|"project_id · 1:N"| t_studio_conversations
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_projects,t_studio_conversations project
class t_maa_bindings,t_maa_runs,t_maa_message_actions,t_maa_interactions,t_maa_interaction_actions,t_maa_model_change_actions,t_maa_run_stop_actions agent
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_agent fill:#fff7ed,stroke:#f97316,stroke-width:4px
linkStyle 0,1,2,3,4,5,6,7,8 stroke:#f97316,stroke-width:2.5px画布与时间轴
项目下是一份视频文档,画布、画布版本、时间线版本和导出都挂在这份文档上;素材放在共享身份库,项目只记引用,项目与素材是多对多,经 project_asset_refs。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":40,"rankSpacing":90}}}%%
flowchart LR
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_canvas["画布 · 时间轴 · 导出"]
direction TB
t_studio_video_documents["video_documents"]
t_studio_canvases["canvases"]
t_studio_canvas_revisions["canvas_revisions"]
t_studio_timeline_revisions["timeline_revisions"]
t_studio_export_jobs["export_jobs"]
t_studio_project_asset_refs["⇄ project_asset_refs"]
end
subgraph sg_asset["素材(共享身份库)"]
direction TB
t_studio_assets["assets"]
end
t_studio_canvases -->|"project_id · 1:N"| t_studio_canvas_revisions
t_studio_canvas_revisions -->|"restored_from_revision · 0..1:N"| t_studio_canvas_revisions
t_studio_projects -->|"project_id · 1:1"| t_studio_canvases
t_studio_projects -->|"project_id · 1:N"| t_studio_conversations
t_studio_projects -->|"project_id · 1:N"| t_studio_export_jobs
t_studio_projects -->|"project_id · 1:N"| t_studio_project_asset_refs
t_studio_video_documents -->|"project_id · 1:N"| t_studio_timeline_revisions
t_studio_timeline_revisions -->|"restored_from_revision · 0..1:N"| t_studio_timeline_revisions
t_studio_projects -->|"project_id · 1:1"| t_studio_video_documents
t_studio_assets -.->|"asset_id · 1:N"| t_studio_project_asset_refs
t_studio_projects <-.->|"N:M · 经 project_asset_refs"| t_studio_assets
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_projects,t_studio_conversations project
class t_studio_video_documents,t_studio_canvases,t_studio_canvas_revisions,t_studio_timeline_revisions,t_studio_export_jobs,t_studio_project_asset_refs canvas
class t_studio_assets asset
class t_studio_project_asset_refs junction
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_canvas fill:none,stroke:#3b82f6,stroke-width:1px
style sg_asset fill:none,stroke:#06b6d4,stroke-width:1px
linkStyle 9 stroke:#64748b,stroke-width:1.5px,stroke-dasharray:4 3
linkStyle 10 stroke:#dc2626,stroke-width:3px关系清单 逐条 61 条,含基数
| 父表 | 子表 | 外键列(子表里) | 基数 | 约束 | 域 |
|---|---|---|---|---|---|
generation_jobs | generation_deliveries | job_id | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_assets | generation_deliveries | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 生成 · 媒体 · 交付 |
studio_conversations | generation_deliveries | owner_id, project_id, session_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_projects | generation_deliveries | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
generation_development_budgets | generation_jobs | owner_id, budget_id | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_conversations | generation_jobs | owner_id, project_id, session_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_projects | generation_jobs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
generation_jobs | generation_reservations | job_id, budget_id, owner_id | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
maa_model_change_actions | maa_bindings | owner_id, project_id, conversation_id, id, pending_model_change_id | 0..1:1 一对一(父可选) | DB 外键 | Agent 交互 → Agent 交互 |
studio_conversations | maa_bindings | owner_id, project_id, conversation_id | 1:1 一对一 | DB 外键 | 项目与会话 → Agent 交互 |
maa_interactions | maa_interaction_actions | owner_id, project_id, conversation_id, binding_id, public_run_id, interaction_id | 1:1 一对一 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_interactions | owner_id, project_id, conversation_id, binding_id, public_run_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_message_actions | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_message_actions | owner_id, project_id, conversation_id, binding_id, public_run_id | 0..1:N 一对多(父可选) | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_model_change_actions | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_run_stop_actions | owner_id, project_id, conversation_id, binding_id, public_run_id | 1:1 一对一 | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_runs | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
studio_users | studio_assets | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 素材 |
studio_payment_orders | studio_billing_cycles | owner_id, payment_order_id, plan_version_id | 1:1 一对一 | DB 外键 | 支付与订阅 → 积分账本 |
studio_subscriptions | studio_billing_cycles | owner_id, subscription_id, provider_key, provider_account | 1:N 一对多 | DB 外键 | 支付与订阅 → 积分账本 |
studio_canvas_revisions | studio_canvas_revisions | owner_id, project_id, kind, restored_from_revision | 0..1:N 一对多(父可选) | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_canvases | studio_canvas_revisions | owner_id, project_id | 1:N 一对多 | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_projects | studio_canvases | owner_id, project_id | 1:1 一对一 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_projects | studio_conversations | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 项目与会话 |
studio_users | studio_credit_accounts | owner_id | 1:1 一对一 | DB 外键 | 用户与登录 → 积分账本 |
studio_credit_authorizations | studio_credit_authorization_allocations | owner_id, authorization_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_lots | studio_credit_authorization_allocations | owner_id, lot_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_accounts | studio_credit_authorizations | owner_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_authorization_allocations | studio_credit_ledger_entries | owner_id, authorization_id, lot_id | 0..1:N 一对多(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_authorizations | studio_credit_ledger_entries | owner_id, authorization_id | 0..1:N 一对多(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_lots | studio_credit_ledger_entries | owner_id, lot_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_billing_cycles | studio_credit_lots | owner_id, source_cycle_id | 0..1:1 一对一(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_accounts | studio_credit_lots | owner_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_payment_orders | studio_credit_lots | owner_id, source_order_id | 0..1:1 一对一(父可选) | DB 外键 | 支付与订阅 → 积分账本 |
studio_credit_authorizations | studio_credit_recovery_intents | authorization_id | 0..1:N 一对多(父可选) | 跨库(应用层检查) | 积分账本 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_credit_recovery_intents | owner_id, project_id, conversation_id, job_id, request_sha256 | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_projects | studio_export_jobs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_credit_authorizations | studio_media_jobs | credit_authorization_id | 0..1:N 一对多(父可选) | 跨库(应用层检查) | 积分账本 → 生成 · 媒体 · 交付 |
studio_media_requests | studio_media_jobs | owner_id, project_id, conversation_id, request_id, request_sha256, quote_sha256 | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_media_models | studio_media_model_versions | model_id | 1:N 一对多 | DB 外键 | 模型目录 → 模型目录 |
studio_media_model_versions | studio_media_models | id, published_version_id | 0..1:1 一对一(父可选) | DB 外键 | 模型目录 → 模型目录 |
studio_assets | studio_media_outputs | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_media_outputs | owner_id, project_id, conversation_id, job_id | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
maa_runs | studio_media_requests | owner_id, project_id, conversation_id, source_binding_id, source_run_id | 0..1:N 一对多(父可选) | DB 外键 | Agent 交互 → 生成 · 媒体 · 交付 |
studio_conversations | studio_media_requests | owner_id, project_id, conversation_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_media_model_versions | studio_media_requests | model_version_id | 1:N 一对多 | 跨库(应用层检查) | 模型目录 → 生成 · 媒体 · 交付 |
studio_media_models | studio_media_requests | model_id | 1:N 一对多 | 跨库(应用层检查) | 模型目录 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_media_submission_attempts | owner_id, project_id, conversation_id, job_id, request_sha256 | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_payment_orders | studio_payment_events | owner_id, order_id, provider_key, provider_account | 0..1:N 一对多(父可选) | DB 外键 | 支付与订阅 → 支付与订阅 |
studio_subscriptions | studio_payment_events | owner_id, subscription_id, provider_key, provider_account | 0..1:N 一对多(父可选) | DB 外键 | 支付与订阅 → 支付与订阅 |
studio_users | studio_payment_events | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_credit_plan_versions | studio_payment_orders | plan_version_id | 1:N 一对多 | DB 外键 | 积分账本 → 支付与订阅 |
studio_users | studio_payment_orders | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_assets | studio_project_asset_refs | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 画布 · 时间轴 · 导出 |
studio_projects | studio_project_asset_refs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_users | studio_sessions | user_id | 1:N 一对多 | DB 外键 | 用户与登录 → 用户与登录 |
studio_credit_plan_versions | studio_subscriptions | plan_version_id | 1:N 一对多 | DB 外键 | 积分账本 → 支付与订阅 |
studio_users | studio_subscriptions | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_timeline_revisions | studio_timeline_revisions | owner_id, project_id, kind, restored_from_revision | 0..1:N 一对多(父可选) | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_video_documents | studio_timeline_revisions | owner_id, project_id | 1:N 一对多 | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_projects | studio_video_documents | owner_id, project_id | 1:1 一对一 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
完整 ER:39 张表的全部列,带主键 / 外键与基数符号(鸦脚)
erDiagram
studio_assets {
CHAR id PK
CHAR owner_id FK
CHAR sha256
JSON metadata_json
VARCHAR storage_key
DATETIME created_at
VARCHAR publication_state
}
studio_billing_cycles {
CHAR id PK
CHAR owner_id FK
CHAR subscription_id FK
CHAR plan_version_id FK
CHAR payment_order_id FK
VARCHAR provider_key FK
VARCHAR provider_account FK
VARCHAR provider_invoice_id
DATETIME period_start
DATETIME period_end
BIGINT_UNSIGNED grant_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
VARCHAR state
CHAR paid_evidence_sha256
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_accounts {
CHAR owner_id PK
VARCHAR unit
VARCHAR status
BIGINT_UNSIGNED revision
DATETIME updated_at
}
studio_credit_authorization_allocations {
CHAR owner_id FK
CHAR authorization_id PK
CHAR lot_id PK
BIGINT_UNSIGNED allocated_credits
DATETIME created_at
}
studio_credit_authorizations {
CHAR id PK
CHAR owner_id FK
VARCHAR profile
CHAR project_id
CHAR conversation_id
CHAR job_id
CHAR request_id
CHAR request_sha256
CHAR quote_sha256
BIGINT_UNSIGNED credits
DATETIME expires_at
MEDIUMBLOB reservation_bytes
CHAR reservation_sha256
MEDIUMBLOB policy_bytes
CHAR policy_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_ledger_entries {
CHAR id PK
CHAR owner_id FK
CHAR lot_id FK
CHAR authorization_id FK
VARCHAR operation_key
VARCHAR kind
BIGINT grant_delta
BIGINT held_delta
BIGINT captured_delta
MEDIUMBLOB facts_bytes
CHAR facts_sha256
DATETIME created_at
}
studio_credit_lots {
CHAR id PK
CHAR owner_id FK
BIGINT_UNSIGNED grant_credits
BIGINT_UNSIGNED held_credits
BIGINT_UNSIGNED captured_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
CHAR source_order_id FK
CHAR source_cycle_id FK
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_plan_versions {
CHAR id PK
VARCHAR plan_key
VARCHAR version_key
VARCHAR kind
BIGINT_UNSIGNED price_minor
CHAR currency
BIGINT_UNSIGNED grant_credits
INT_UNSIGNED credit_validity_seconds
INT_UNSIGNED billing_interval_months
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
DATETIME published_at
DATETIME retired_at
}
studio_media_model_versions {
CHAR id PK
CHAR model_id FK
VARCHAR version_key
MEDIUMBLOB config_bytes
CHAR config_sha256
DATETIME published_at
}
studio_media_models {
CHAR id PK
VARCHAR model_key
VARCHAR kind
VARCHAR display_name
VARCHAR status
CHAR published_version_id FK
BIGINT_UNSIGNED revision
DATETIME updated_at
}
studio_payment_events {
CHAR id PK
CHAR owner_id FK
VARCHAR provider_key FK
VARCHAR provider_account FK
VARCHAR provider_event_id
CHAR order_id FK
CHAR subscription_id FK
MEDIUMBLOB body_bytes
CHAR body_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_payment_orders {
CHAR id PK
CHAR owner_id FK
CHAR client_action_id
CHAR plan_version_id FK
BIGINT_UNSIGNED price_minor
CHAR currency
BIGINT_UNSIGNED grant_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
VARCHAR provider_key
VARCHAR provider_account
VARCHAR provider_idempotency_key
VARCHAR provider_order_id
VARCHAR state
CHAR paid_evidence_sha256
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_sessions {
CHAR token_hash PK
CHAR user_id FK
DATETIME created_at
DATETIME expires_at
DATETIME revoked_at
}
studio_subscriptions {
CHAR id PK
CHAR owner_id FK
VARCHAR provider_key
VARCHAR provider_account
VARCHAR provider_subscription_id
CHAR plan_version_id FK
VARCHAR state
DATETIME period_start
DATETIME period_end
TINYINT cancel_at_period_end
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_users {
CHAR id PK
VARCHAR email
VARBINARY password_hash
TINYINT enabled
DATETIME created_at
}
generation_deliveries {
CHAR job_id PK
CHAR owner_id FK
CHAR project_id FK
CHAR session_id FK
CHAR asset_id FK
CHAR request_sha256
CHAR maa_source_sha256
CHAR provider_source_sha256
VARCHAR model
VARCHAR tool_name
CHAR input_sha256
JSON metadata_json
DATETIME created_at
}
generation_development_budgets {
CHAR id PK
CHAR owner_id
VARCHAR policy_version
BIGINT_UNSIGNED credits_limit
BIGINT_UNSIGNED credits_reserved
INT_UNSIGNED calls_limit
INT_UNSIGNED calls_reserved
DATETIME expires_at
}
generation_jobs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR session_id FK
CHAR native_conversation_id
CHAR native_run_id
CHAR source_sha256
CHAR budget_id FK
MEDIUMBLOB request_bytes
CHAR request_sha256
BIGINT_UNSIGNED credits
DATETIME expires_at
VARCHAR status
INT_UNSIGNED attempts
MEDIUMBLOB result_bytes
DATETIME updated_at
}
generation_reservations {
CHAR job_id PK
CHAR budget_id FK
CHAR owner_id FK
BIGINT_UNSIGNED credits
INT_UNSIGNED calls
VARCHAR status
}
maa_bindings {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR provider
VARCHAR model_name
VARCHAR status
VARCHAR native_cid
DATETIME created_at
BIGINT_UNSIGNED model_revision
CHAR pending_model_change_id FK
}
maa_interaction_actions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR interaction_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_iid
CHAR client_action_id
CHAR card_sha256
CHAR request_sha256
CHAR content_sha256
VARCHAR response_action
JSON values_payload
VARCHAR status
DATETIME created_at
}
maa_interactions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_iid
CHAR card_sha256
JSON card_payload
DATETIME created_at
}
maa_message_actions {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR client_action_id
CHAR request_sha256
MEDIUMTEXT content
VARCHAR status
CHAR public_run_id FK
CHAR proposed_run_id
DATETIME created_at
}
maa_model_change_actions {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_cid
CHAR client_action_id
CHAR request_sha256
CHAR native_request_sha256
BIGINT_UNSIGNED expected_revision
VARCHAR from_provider
VARCHAR from_model_name
VARCHAR target_provider
VARCHAR target_model_name
VARCHAR status
BIGINT_UNSIGNED dispatch_attempt
JSON receipt_payload
DATETIME created_at
DATETIME updated_at
}
maa_run_stop_actions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_cid
VARCHAR native_rid
CHAR client_action_id
CHAR request_sha256
VARCHAR stop_action
VARCHAR status
BIGINT_UNSIGNED attempt
VARCHAR terminal_run_status
DATETIME created_at
DATETIME updated_at
}
maa_runs {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_rid
VARCHAR status
DATETIME created_at
CHAR native_assistant_sha256
CHAR public_assistant_sha256
BIGINT_UNSIGNED native_assistant_bytes
BIGINT_UNSIGNED assistant_event_seq
BIGINT_UNSIGNED last_event_seq
}
studio_canvas_revisions {
CHAR owner_id PK
CHAR project_id PK
VARCHAR kind PK
BIGINT_UNSIGNED revision PK
MEDIUMBLOB state_bytes
CHAR state_sha256
VARCHAR origin
BIGINT_UNSIGNED restored_from_revision FK
DATETIME recorded_at
}
studio_canvases {
CHAR project_id PK
CHAR owner_id FK
BIGINT_UNSIGNED revision
JSON state_json
DATETIME updated_at
}
studio_conversations {
CHAR id PK
CHAR project_id FK
CHAR owner_id FK
VARCHAR title
DATETIME created_at
}
studio_credit_recovery_intents {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
CHAR request_sha256 FK
CHAR quote_sha256
VARCHAR kind
CHAR authorization_id FK
MEDIUMBLOB intent_bytes
CHAR intent_sha256
VARCHAR state
CHAR lease_token_sha256
DATETIME lease_until
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_export_jobs {
CHAR id PK
CHAR project_id FK
CHAR owner_id FK
BIGINT_UNSIGNED document_revision
CHAR input_hash
VARCHAR status
JSON input_json
JSON output_json
VARCHAR error_code
CHAR lease_token_hash
DATETIME lease_until
INT_UNSIGNED attempts
DATETIME created_at
DATETIME updated_at
}
studio_media_jobs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR request_id FK
CHAR request_sha256 FK
CHAR quote_sha256 FK
CHAR client_approval_id
CHAR approval_sha256
CHAR credit_authorization_id FK
VARCHAR authorization_mode
DATETIME authorization_expires_at
VARCHAR status
BIGINT_UNSIGNED revision
CHAR lease_token_sha256
DATETIME lease_until
VARCHAR provider_task_id
CHAR client_cancel_id
CHAR cancel_request_sha256
DATETIME cancel_requested_at
CHAR staged_asset_id
CHAR staged_asset_sha256
DATETIME created_at
DATETIME updated_at
}
studio_media_outputs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
INT_UNSIGNED ordinal
CHAR asset_id FK
CHAR asset_sha256
CHAR asset_metadata_sha256
CHAR provider_result_sha256
DATETIME created_at
}
studio_media_requests {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR client_request_id
CHAR model_id FK
CHAR model_version_id FK
CHAR model_config_sha256
MEDIUMBLOB request_bytes
CHAR request_sha256
MEDIUMBLOB quote_bytes
CHAR quote_sha256
BIGINT_UNSIGNED quoted_credits
DATETIME expires_at
VARCHAR origin
CHAR source_binding_id FK
CHAR source_run_id FK
CHAR source_assistant_sha256
MEDIUMBLOB source_snapshot_bytes
DATETIME created_at
}
studio_media_submission_attempts {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
INT_UNSIGNED attempt_no
CHAR request_sha256 FK
VARCHAR provider_idempotency_key
VARCHAR stage
DATETIME dispatch_started_at
VARCHAR provider_task_id
CHAR receipt_sha256
CHAR terminal_receipt_sha256
CHAR reconciliation_sha256
DATETIME created_at
DATETIME updated_at
}
studio_project_asset_refs {
CHAR project_id PK
CHAR owner_id FK
CHAR asset_id PK
CHAR asset_sha256
CHAR asset_metadata_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
DATETIME detached_at
}
studio_projects {
CHAR id PK
CHAR owner_id
VARCHAR title
DATETIME created_at
}
studio_timeline_revisions {
CHAR owner_id PK
CHAR project_id PK
VARCHAR kind PK
BIGINT_UNSIGNED revision PK
MEDIUMBLOB state_bytes
CHAR state_sha256
VARCHAR origin
BIGINT_UNSIGNED restored_from_revision FK
DATETIME recorded_at
}
studio_video_documents {
CHAR project_id PK
CHAR owner_id FK
BIGINT_UNSIGNED revision
JSON state_json
DATETIME updated_at
}
studio_users ||--o{ studio_assets : "owner_id"
studio_payment_orders ||--o| studio_billing_cycles : "plan_version_id"
studio_subscriptions ||--o{ studio_billing_cycles : "provider_account"
studio_users ||--o| studio_credit_accounts : "owner_id"
studio_credit_authorizations ||--o{ studio_credit_authorization_allocations : "authorization_id"
studio_credit_lots ||--o{ studio_credit_authorization_allocations : "lot_id"
studio_credit_accounts ||--o{ studio_credit_authorizations : "owner_id"
studio_credit_authorization_allocations |o--o{ studio_credit_ledger_entries : "lot_id"
studio_credit_authorizations |o--o{ studio_credit_ledger_entries : "authorization_id"
studio_credit_lots ||--o{ studio_credit_ledger_entries : "lot_id"
studio_credit_accounts ||--o{ studio_credit_lots : "owner_id"
studio_billing_cycles |o--o| studio_credit_lots : "source_cycle_id"
studio_payment_orders |o--o| studio_credit_lots : "source_order_id"
studio_media_models ||--o{ studio_media_model_versions : "model_id"
studio_media_model_versions |o--o| studio_media_models : "published_version_id"
studio_payment_orders |o--o{ studio_payment_events : "provider_account"
studio_subscriptions |o--o{ studio_payment_events : "provider_account"
studio_users ||--o{ studio_payment_events : "owner_id"
studio_credit_plan_versions ||--o{ studio_payment_orders : "plan_version_id"
studio_users ||--o{ studio_payment_orders : "owner_id"
studio_users ||--o{ studio_sessions : "user_id"
studio_credit_plan_versions ||--o{ studio_subscriptions : "plan_version_id"
studio_users ||--o{ studio_subscriptions : "owner_id"
generation_jobs ||--o| generation_deliveries : "job_id"
studio_projects ||--o{ generation_deliveries : "project_id"
studio_conversations ||--o{ generation_deliveries : "session_id"
generation_development_budgets ||--o{ generation_jobs : "budget_id"
studio_projects ||--o{ generation_jobs : "project_id"
studio_conversations ||--o{ generation_jobs : "session_id"
generation_jobs ||--o| generation_reservations : "budget_id"
studio_conversations ||--o| maa_bindings : "conversation_id"
maa_model_change_actions |o--o| maa_bindings : "pending_model_change_id"
maa_interactions ||--o| maa_interaction_actions : "interaction_id"
maa_runs ||--o{ maa_interactions : "public_run_id"
maa_bindings ||--o{ maa_message_actions : "binding_id"
maa_runs |o--o{ maa_message_actions : "public_run_id"
maa_bindings ||--o{ maa_model_change_actions : "binding_id"
maa_runs ||--o| maa_run_stop_actions : "public_run_id"
maa_bindings ||--o{ maa_runs : "binding_id"
studio_canvases ||--o{ studio_canvas_revisions : "project_id"
studio_canvas_revisions |o--o{ studio_canvas_revisions : "restored_from_revision"
studio_projects ||--o| studio_canvases : "project_id"
studio_projects ||--o{ studio_conversations : "project_id"
studio_media_jobs ||--o{ studio_credit_recovery_intents : "job_id"
studio_projects ||--o{ studio_export_jobs : "project_id"
studio_media_requests ||--o| studio_media_jobs : "request_id"
studio_media_jobs ||--o{ studio_media_outputs : "job_id"
studio_conversations ||--o{ studio_media_requests : "conversation_id"
maa_runs |o--o{ studio_media_requests : "source_run_id"
studio_media_jobs ||--o{ studio_media_submission_attempts : "job_id"
studio_projects ||--o{ studio_project_asset_refs : "project_id"
studio_video_documents ||--o{ studio_timeline_revisions : "project_id"
studio_timeline_revisions |o--o{ studio_timeline_revisions : "restored_from_revision"
studio_projects ||--o| studio_video_documents : "project_id"
studio_assets ||--o{ studio_project_asset_refs : "asset_id"
studio_assets ||--o{ studio_media_outputs : "asset_id"
studio_assets ||--o{ generation_deliveries : "asset_id"
studio_media_model_versions ||--o{ studio_media_requests : "model_version_id"
studio_media_models ||--o{ studio_media_requests : "model_id"
studio_credit_authorizations |o--o{ studio_media_jobs : "credit_authorization_id"
studio_credit_authorizations |o--o{ studio_credit_recovery_intents : "authorization_id"自动生成的整体图(按真实表结构,备查)
共享身份库 ER 图
实测验证与设计原因 七个品牌相同,展开查看
实测验证(本机 MySQL 实库)
对照本机真实运行的数据库 studio_profile_pollo 和 studio_platform_identity,逐项核对本页的表、列、关系与说明。14 / 14 项通过。
查看全部核对项
| 核对项 | 结果 |
|---|---|
| 表数 = 发布值 24 | 通过 |
| 列数 = 289 | 通过 |
| 外键数 = 34 | 通过 |
| 检查约束数 = 66 | 通过 |
| 触发器数 = 22 | 通过 |
| 索引数(含主键) = 85 | 通过 |
| 外键 CSV 行数 = 实库外键数 | 通过 |
| mmd 实体 = 实库表 | 通过 |
| svg 标题 24 tables / 34 actual foreign keys = 实库 | 通过 |
| 参考 SQL 表集合与列顺序 = 实库 | 通过 |
| 15 张表 | 通过 |
| 外键 CSV 行数 = 实库外键数 | 通过 |
| svg 标题与实库一致 | 通过 |
| 参考 SQL 表集合与列顺序 = 实库 | 通过 |
实库里的关系是这样的
- 34 个外键里 31 个是复合外键,且都带着 owner_id,其余 3 个是单列外键;22 张子表都带 owner 外键。所以一行数据不可能指向别的用户的项目或会话。
- 删除与更新规则全部是 RESTRICT / NO ACTION,没有任何级联:被引用的行不能被删除。
- 品牌库与共享身份库之间的关系(owner_id、asset_id、model_id + model_version_id)没有数据库外键,靠应用层检查;我们逐表核对了现有数据,没有孤儿。
主动破坏测试(在事务里尝试,全部回滚)
| 尝试 | 数据库的反应 |
|---|---|
| 外键:导出任务.project_id 改成不存在的项目被拒绝 | 拒绝 |
| 复合外键:项目素材引用.project_id 改成别的用户的项目被拒绝(owner 与 project 必须成对) | 拒绝 |
| 触发器:已提交的消息动作不可改写 | 拒绝 |
| 触发器:媒体产出不可改写 | 拒绝 |
| 外键 RESTRICT:被会话引用的项目不能删除 | 拒绝 |
| 复合外键:被引用的会话不能把 owner 改成别人 | 拒绝 |
| 检查约束:Run 状态只能是约定的六个值 | 拒绝 |
| 触发器:账本分录不可修改 | 拒绝 |
| 触发器:账本分录不可删除 | 拒绝 |
Pollo · 表结构
MySQL 8,字符集 utf8mb4,ID 为 char(36) ascii_bin。点击展开 DDL。
按职责分组
项目与会话 2 张
studio_projects:用户拥有的创作项目studio_conversations:项目内的对话会话
Agent执行与并发控制 7 张
maa_bindings:业务会话与Native Maa会话映射、模型版本与未决操作maa_runs:公开Run映射、状态与原生/公开助手证据摘要maa_message_actions:原消息动作及幂等回执maa_interactions:澄清卡片及Run归属maa_interaction_actions:原卡片回答/取消动作maa_model_change_actions:带预期模型版本的切换动作maa_run_stop_actions:停止原Run的幂等动作与观测终态
画布、时间轴与素材引用 5 张
studio_canvases:项目当前画布文档studio_canvas_revisions:历史画布修订studio_video_documents:项目当前时间轴文档studio_timeline_revisions:历史时间轴修订studio_project_asset_refs:项目对用户级素材的引用;不复制素材所有权
媒体生成、结算恢复与导出 6 张
studio_media_requests:用户输入/Agent来源、报价、批准摘要与准入确认studio_media_jobs:已批准媒体任务及状态机studio_media_submission_attempts:一次提交的任务证据与不确定结果studio_media_outputs:受验证的输出与素材映射studio_credit_recovery_intents:积分结算恢复意图;不是用户钱包全账本studio_export_jobs:时间轴导出队列和发布输出
既有generation兼容路径 22 张
generation_jobs:既有generation任务,不等同新PublicMedia任务generation_reservations:既有任务费用预留generation_development_budgets:既有开发测试预算generation_deliveries:既有生成交付回执owner_id:归属用户;不是允许跨用户查询的参数。model_revision:并发准入版本;数据库默认0不能代替Native权威读回。pending_model_change_id:未决模型切换引用,阻止其他writer绕过。studio_users:用户账号记录;不导出密码哈希或任何业务行studio_sessions:登录会话;这里只公开字段结构,不公开会话值studio_assets:用户级素材元数据与存储键结构,项目仅引用素材IDstudio_media_models:公开媒体模型目录结构studio_media_model_versions:媒体模型不可变版本/计价能力结构studio_subscriptions:订阅状态持久化studio_billing_cycles:订阅账期studio_payment_orders:订单记录studio_payment_events:支付事件幂等记录;不代表已有公开支付路由studio_credit_accounts:用户积分账户studio_credit_lots:积分批次studio_credit_authorizations:费用预留与结算授权studio_credit_authorization_allocations:授权对批次的分配studio_credit_ledger_entries:积分流水studio_credit_plan_versions:积分方案不可变版本
品牌库 studio_profile_pollo(24 张)
generation_deliveries 既有生成交付回执
CREATE TABLE `generation_deliveries` ( `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `session_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `maa_source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `tool_name` varchar(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `input_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `metadata_json` json NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`job_id`), KEY `generation_delivery_owner_project` (`owner_id`,`project_id`,`session_id`,`job_id`), KEY `generation_delivery_owned_asset` (`owner_id`,`asset_id`), KEY `generation_delivery_session_fk` (`session_id`), CONSTRAINT `generation_delivery_job_fk` FOREIGN KEY (`job_id`) REFERENCES `generation_jobs` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`, `job_id`) REFERENCES `generation_jobs` (`owner_id`, `project_id`, `session_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_session_fk` FOREIGN KEY (`session_id`) REFERENCES `studio_conversations` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_model_tool` CHECK ((((`model` = _ascii'seedance-2.0') and (`tool_name` = _ascii'seedance2_video_generator')) or ((`model` in (_ascii'minimax-h3',_ascii'seedance-2.5')) and (`tool_name` = _ascii'insai_video_generate')))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_development_budgets 既有开发测试预算
CREATE TABLE `generation_development_budgets` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `policy_version` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits_limit` bigint unsigned NOT NULL, `credits_reserved` bigint unsigned NOT NULL DEFAULT '0', `calls_limit` int unsigned NOT NULL, `calls_reserved` int unsigned NOT NULL DEFAULT '0', `expires_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `generation_budget_owner` (`owner_id`,`id`), CONSTRAINT `generation_budget_limits` CHECK (((`credits_limit` between 1 and 1000000000) and (`credits_reserved` <= `credits_limit`) and (`calls_limit` between 1 and 100) and (`calls_reserved` <= `calls_limit`))), CONSTRAINT `generation_budget_policy` CHECK ((`policy_version` = _latin1'operator-test/v1')) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_jobs 既有generation任务,不等同新PublicMedia任务
CREATE TABLE `generation_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `session_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_conversation_id` char(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_run_id` char(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `budget_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_bytes` mediumblob NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits` bigint unsigned NOT NULL, `expires_at` datetime(6) NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempts` int unsigned NOT NULL DEFAULT '0', `result_bytes` mediumblob, `updated_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `generation_job_budget_owner` (`id`,`budget_id`,`owner_id`), UNIQUE KEY `generation_job_owned_scope` (`owner_id`,`project_id`,`session_id`,`id`), KEY `generation_job_owner` (`owner_id`,`project_id`,`session_id`), KEY `generation_job_session` (`session_id`), KEY `generation_job_budget` (`owner_id`,`budget_id`), CONSTRAINT `generation_job_budget` FOREIGN KEY (`owner_id`, `budget_id`) REFERENCES `generation_development_budgets` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_owned_project` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_owned_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_session` FOREIGN KEY (`session_id`) REFERENCES `studio_conversations` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_attempt` CHECK ((((`status` = _ascii'APPROVED') and (`attempts` = 0) and (`result_bytes` is null)) or ((`status` = _ascii'SUBMITTING') and (`attempts` = 1) and (`result_bytes` is null)) or ((`status` in (_ascii'SUCCEEDED',_ascii'FAILED',_ascii'UNKNOWN')) and (`attempts` = 1) and (`result_bytes` is not null)))), CONSTRAINT `generation_job_credit` CHECK ((`credits` between 1 and 1000000000)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_reservations 既有任务费用预留
CREATE TABLE `generation_reservations` ( `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `budget_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits` bigint unsigned NOT NULL, `calls` int unsigned NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, PRIMARY KEY (`job_id`), KEY `generation_reservation_job` (`job_id`,`budget_id`,`owner_id`), CONSTRAINT `generation_reservation_job` FOREIGN KEY (`job_id`, `budget_id`, `owner_id`) REFERENCES `generation_jobs` (`id`, `budget_id`, `owner_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_reservation_fixed` CHECK (((`credits` between 1 and 1000000000) and (`calls` = 1) and (`status` = _latin1'HELD'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_bindings 业务会话与Native Maa会话映射、模型版本与未决操作
CREATE TABLE `maa_bindings` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `model_revision` bigint unsigned NOT NULL DEFAULT '0', `pending_model_change_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_binding_business_scope` (`owner_id`,`project_id`,`conversation_id`), UNIQUE KEY `maa_binding_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `maa_binding_native_identity` (`native_cid`), KEY `maa_model_change_pending_fk` (`owner_id`,`project_id`,`conversation_id`,`id`,`pending_model_change_id`), CONSTRAINT `maa_binding_owned_conversation_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_model_change_pending_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `id`, `pending_model_change_id`) REFERENCES `maa_model_change_actions` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_binding_receipt` CHECK ((((`status` = _ascii'dispatching') and (`native_cid` is null)) or ((`status` = _ascii'bound') and (`native_cid` is not null)))), CONSTRAINT `maa_model_binding_revision` CHECK ((`model_revision` <= 9007199254740991)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_interaction_actions 原卡片回答/取消动作
CREATE TABLE `maa_interaction_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `interaction_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_iid` varchar(124) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `content_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `response_action` varchar(8) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `values_payload` json NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_interaction_action_business_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_interaction_action_one_card` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`interaction_id`), CONSTRAINT `maa_interaction_action_owned_card_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`, `interaction_id`) REFERENCES `maa_interactions` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_interaction_action_kind` CHECK ((`response_action` in (_latin1'submit',_latin1'cancel'))), CONSTRAINT `maa_interaction_action_status` CHECK ((`status` in (_latin1'dispatching',_latin1'accepted'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_interactions 澄清卡片及Run归属
CREATE TABLE `maa_interactions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_iid` varchar(124) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_payload` json NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_interaction_native_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`native_iid`), UNIQUE KEY `maa_interaction_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`id`), CONSTRAINT `maa_interaction_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_message_actions 原消息动作及幂等回执
CREATE TABLE `maa_message_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `content` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `proposed_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_action_business_identity` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), KEY `maa_action_owned_run_fk` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`), CONSTRAINT `maa_action_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_action_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_action_receipt` CHECK ((((`status` = _latin1'dispatching') and (`public_run_id` is null)) or ((`status` = _latin1'accepted') and (`public_run_id` is not null)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_model_change_actions 带预期模型版本的切换动作
CREATE TABLE `maa_model_change_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `expected_revision` bigint unsigned NOT NULL, `from_provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `from_model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `target_provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `target_model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `dispatch_attempt` bigint unsigned NOT NULL, `receipt_payload` json DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_model_change_owned_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_model_change_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`id`), CONSTRAINT `maa_model_change_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_model_change_attempt` CHECK ((`dispatch_attempt` between 1 and 9007199254740991)), CONSTRAINT `maa_model_change_expected` CHECK ((`expected_revision` <= 9007199254740990)), CONSTRAINT `maa_model_change_status` CHECK ((((cast(`status` as char charset binary) = _utf8mb4'dispatching') and (`receipt_payload` is null)) or ((cast(`status` as char charset binary) in (_utf8mb4'accepted',_utf8mb4'rejected')) and (`receipt_payload` is not null) and (json_type(`receipt_payload`) = _utf8mb4'OBJECT')))), CONSTRAINT `maa_model_change_time` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_run_stop_actions 停止原Run的幂等动作与观测终态
CREATE TABLE `maa_run_stop_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_rid` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `stop_action` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempt` bigint unsigned NOT NULL, `terminal_run_status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_stop_owned_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_stop_one_run` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`), CONSTRAINT `maa_stop_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_stop_action` CHECK ((`stop_action` = _utf8mb4'interrupt')), CONSTRAINT `maa_stop_attempt` CHECK ((`attempt` between 1 and 9007199254740991)), CONSTRAINT `maa_stop_state` CHECK ((((`status` = _utf8mb4'unknown') and (`terminal_run_status` is null)) or ((`status` = _utf8mb4'terminal_observed') and (`terminal_run_status` is not null) and (`terminal_run_status` in (_utf8mb4'completed',_utf8mb4'failed',_utf8mb4'cancelled'))))), CONSTRAINT `maa_stop_time` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_runs 公开Run映射、状态与原生/公开助手证据摘要
CREATE TABLE `maa_runs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_rid` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, `native_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `public_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `native_assistant_bytes` bigint unsigned NOT NULL DEFAULT '0', `assistant_event_seq` bigint unsigned NOT NULL DEFAULT '0', `last_event_seq` bigint unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `maa_run_native_identity` (`native_rid`), UNIQUE KEY `maa_run_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`id`), KEY `maa_run_owned_list` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), CONSTRAINT `maa_run_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_run_source_evidence` CHECK ((((`native_assistant_sha256` is null) and (`public_assistant_sha256` is null) and (`native_assistant_bytes` = 0) and (`assistant_event_seq` = 0)) or ((`native_assistant_sha256` is not null) and (`public_assistant_sha256` is not null) and (`native_assistant_bytes` > 0) and (`assistant_event_seq` > 0) and (`assistant_event_seq` <= `last_event_seq`)))), CONSTRAINT `maa_run_status` CHECK ((`status` in (_latin1'queued',_latin1'running',_latin1'waiting_interaction',_latin1'completed',_latin1'failed',_latin1'cancelled'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_canvas_revisions 历史画布修订
CREATE TABLE `studio_canvas_revisions` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_bytes` mediumblob NOT NULL, `state_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `restored_from_revision` bigint unsigned DEFAULT NULL, `recorded_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`,`project_id`,`kind`,`revision`), KEY `studio_canvas_revision_source_fk` (`owner_id`,`project_id`,`kind`,`restored_from_revision`), CONSTRAINT `studio_canvas_revision_head_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_canvases` (`owner_id`, `project_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_canvas_revision_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `kind`, `restored_from_revision`) REFERENCES `studio_canvas_revisions` (`owner_id`, `project_id`, `kind`, `revision`), CONSTRAINT `studio_canvas_revision_bytes` CHECK ((length(`state_bytes`) between 1 and 262144)), CONSTRAINT `studio_canvas_revision_kind` CHECK ((`kind` = _latin1'canvas')), CONSTRAINT `studio_canvas_revision_number` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_canvas_revision_origin` CHECK ((((`origin` in (_latin1'saved',_latin1'backfill')) and (`restored_from_revision` is null)) or ((`origin` = _latin1'restored') and (`restored_from_revision` is not null) and (`restored_from_revision` between 1 and (`revision` - 1))))), CONSTRAINT `studio_canvas_revision_sha` CHECK ((`state_sha256` = lower(sha2(`state_bytes`,256)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_canvases 项目当前画布文档
CREATE TABLE `studio_canvases` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_json` json NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`project_id`), UNIQUE KEY `studio_canvas_owned_head` (`owner_id`,`project_id`), CONSTRAINT `studio_canvas_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_canvas_revision` CHECK ((`revision` between 1 and 2147483647)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_conversations 项目内的对话会话
CREATE TABLE `studio_conversations` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `title` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_conversation_owned_scope` (`owner_id`,`project_id`,`id`), KEY `studio_conversation_list` (`owner_id`,`project_id`,`created_at`,`id`), CONSTRAINT `studio_conversation_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_recovery_intents 积分结算恢复意图;不是用户钱包全账本
CREATE TABLE `studio_credit_recovery_intents` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`kind` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`intent_bytes` mediumblob NOT NULL,
`intent_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`lease_token_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`lease_until` datetime(6) DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_intent_job_kind` (`job_id`,`kind`),
KEY `credit_intent_recovery` (`state`,`updated_at`,`id`),
KEY `credit_intent_owned_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`,`request_sha256`),
CONSTRAINT `credit_intent_owned_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`, `request_sha256`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`),
CONSTRAINT `credit_intent_hashes` CHECK ((regexp_like(`request_sha256`,_latin1'^[a-f0-9]{64}$') and regexp_like(`quote_sha256`,_latin1'^[a-f0-9]{64}$'))),
CONSTRAINT `credit_intent_kind` CHECK (((`kind` in (_latin1'RESERVE_BIND',_latin1'CAPTURE',_latin1'RELEASE')) and (((`kind` = _latin1'RESERVE_BIND') and (`authorization_id` is null)) or ((`kind` in (_latin1'CAPTURE',_latin1'RELEASE')) and (`authorization_id` is not null))))),
CONSTRAINT `credit_intent_lease` CHECK ((((`state` = _latin1'leased') and (`lease_token_sha256` is not null) and regexp_like(`lease_token_sha256`,_latin1'^[a-f0-9]{64}$') and (`lease_until` is not null) and (`lease_until` > `updated_at`) and (`lease_until` <= (`updated_at` + interval 15 minute))) or ((`state` <> _latin1'leased') and (`lease_token_sha256` is null) and (`lease_until` is null)))),
CONSTRAINT `credit_intent_payload_sha` CHECK ((`intent_sha256` = lower(sha2(`intent_bytes`,256)))),
CONSTRAINT `credit_intent_payload_size` CHECK ((length(`intent_bytes`) between 1 and 65536)),
CONSTRAINT `credit_intent_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `credit_intent_state` CHECK ((`state` in (_latin1'pending',_latin1'leased',_latin1'confirmed',_latin1'unknown'))),
CONSTRAINT `credit_intent_times` CHECK ((`updated_at` >= `created_at`))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_export_jobs 时间轴导出队列和发布输出
CREATE TABLE `studio_export_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `document_revision` bigint unsigned NOT NULL, `input_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `input_json` json NOT NULL, `output_json` json DEFAULT NULL, `error_code` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT '', `lease_token_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `lease_until` datetime(6) DEFAULT NULL, `attempts` int unsigned NOT NULL DEFAULT '0', `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_export_input` (`project_id`,`document_revision`,`input_hash`), KEY `studio_export_claim` (`status`,`created_at`,`id`), KEY `studio_export_owner_list` (`owner_id`,`project_id`,`created_at`,`id`), KEY `studio_export_expiry` (`status`,`lease_until`), CONSTRAINT `studio_export_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_export_lease` CHECK ((((`status` = _latin1'running') and (`lease_token_hash` is not null) and (`lease_until` is not null)) or ((`status` <> _latin1'running') and (`lease_token_hash` is null) and (`lease_until` is null)))), CONSTRAINT `studio_export_output` CHECK ((((`status` = _latin1'succeeded') and (`output_json` is not null) and (`error_code` = _latin1'')) or ((`status` in (_latin1'queued',_latin1'running')) and (`output_json` is null) and (`error_code` = _latin1'')) or ((`status` in (_latin1'failed',_latin1'unknown')) and (`output_json` is null) and (`error_code` <> _latin1'')))), CONSTRAINT `studio_export_revision` CHECK ((`document_revision` between 1 and 2147483647)), CONSTRAINT `studio_export_status` CHECK ((`status` in (_latin1'queued',_latin1'running',_latin1'succeeded',_latin1'failed',_latin1'unknown'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_jobs 已批准媒体任务及状态机
CREATE TABLE `studio_media_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_approval_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `approval_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credit_authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `authorization_mode` varchar(24) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `authorization_expires_at` datetime(6) DEFAULT NULL, `status` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `lease_token_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `lease_until` datetime(6) DEFAULT NULL, `provider_task_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `client_cancel_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `cancel_request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `cancel_requested_at` datetime(6) DEFAULT NULL, `staged_asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `staged_asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_job_request` (`request_id`), UNIQUE KEY `studio_media_job_client` (`owner_id`,`client_approval_id`), UNIQUE KEY `studio_media_job_owned` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `studio_media_job_owned_request` (`owner_id`,`project_id`,`conversation_id`,`id`,`request_sha256`), KEY `studio_media_job_page` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), KEY `studio_media_job_queue` (`status`,`updated_at`,`id`), KEY `studio_media_job_request_fk` (`owner_id`,`project_id`,`conversation_id`,`request_id`,`request_sha256`,`quote_sha256`), CONSTRAINT `studio_media_job_request_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `request_id`, `request_sha256`, `quote_sha256`) REFERENCES `studio_media_requests` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`, `quote_sha256`), CONSTRAINT `studio_media_job_authorization` CHECK ((((`credit_authorization_id` is null) and (`authorization_mode` is null) and (`authorization_expires_at` is null) and (`status` in (_latin1'approval_pending',_latin1'cancelled'))) or ((`credit_authorization_id` is not null) and (`authorization_mode` is not null) and (`authorization_mode` in (_latin1'commercial',_latin1'test_allowance')) and (`authorization_expires_at` is not null) and (`authorization_expires_at` > `created_at`) and (`status` <> _latin1'approval_pending')))), CONSTRAINT `studio_media_job_cancel` CHECK ((((`client_cancel_id` is null) and (`cancel_request_sha256` is null) and (`cancel_requested_at` is null)) or ((`client_cancel_id` is not null) and (`cancel_request_sha256` is not null) and (`cancel_requested_at` is not null) and (`cancel_requested_at` between `created_at` and `updated_at`)))), CONSTRAINT `studio_media_job_lease` CHECK ((((`status` in (_latin1'leased',_latin1'submitting')) and (`lease_token_sha256` is not null) and (`lease_until` is not null) and (`lease_until` > `updated_at`) and (`lease_until` <= (`updated_at` + interval 15 minute))) or ((`status` not in (_latin1'leased',_latin1'submitting')) and (`lease_token_sha256` is null) and (`lease_until` is null)))), CONSTRAINT `studio_media_job_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_media_job_staged` CHECK ((((`staged_asset_id` is null) and (`staged_asset_sha256` is null)) or ((`staged_asset_id` is not null) and (`staged_asset_sha256` is not null)))), CONSTRAINT `studio_media_job_status` CHECK ((`status` in (_latin1'approval_pending',_latin1'queued',_latin1'leased',_latin1'submitting',_latin1'running',_latin1'submission_unknown',_latin1'succeeded',_latin1'failed',_latin1'cancelled'))), CONSTRAINT `studio_media_job_task` CHECK (((`status` not in (_latin1'running',_latin1'succeeded')) or (`provider_task_id` is not null))), CONSTRAINT `studio_media_job_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_outputs 受验证的输出与素材映射
CREATE TABLE `studio_media_outputs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `ordinal` int unsigned NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_metadata_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_result_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_output_job` (`job_id`,`ordinal`), KEY `studio_media_output_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`), CONSTRAINT `studio_media_output_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`), CONSTRAINT `studio_media_output_ordinal` CHECK ((`ordinal` = 0)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_requests 用户输入/Agent来源、报价、批准摘要与准入确认
CREATE TABLE `studio_media_requests` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_config_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_bytes` mediumblob NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quote_bytes` mediumblob NOT NULL, `quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quoted_credits` bigint unsigned NOT NULL, `expires_at` datetime(6) NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_snapshot_bytes` mediumblob, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_request_owned` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `studio_media_request_quoted` (`owner_id`,`project_id`,`conversation_id`,`id`,`request_sha256`,`quote_sha256`), UNIQUE KEY `studio_media_request_client` (`owner_id`,`project_id`,`conversation_id`,`client_request_id`), KEY `studio_media_request_page` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), KEY `studio_media_request_source_fk` (`owner_id`,`project_id`,`conversation_id`,`source_binding_id`,`source_run_id`), CONSTRAINT `studio_media_request_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`), CONSTRAINT `studio_media_request_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `source_binding_id`, `source_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`), CONSTRAINT `studio_media_quote_credits` CHECK ((`quoted_credits` between 1 and 1000000000)), CONSTRAINT `studio_media_quote_sha` CHECK ((`quote_sha256` = lower(sha2(`quote_bytes`,256)))), CONSTRAINT `studio_media_quote_times` CHECK (((`expires_at` > `created_at`) and (`expires_at` <= (`created_at` + interval 15 minute)))), CONSTRAINT `studio_media_request_origin` CHECK ((((`origin` in (_latin1'ui',_latin1'user_edit')) and (`source_binding_id` is null) and (`source_run_id` is null) and (`source_assistant_sha256` is null) and (`source_snapshot_bytes` is null)) or ((`origin` = _latin1'agent') and (`source_binding_id` is not null) and (`source_run_id` is not null) and (`source_assistant_sha256` is not null) and (`source_snapshot_bytes` is not null) and (length(`source_snapshot_bytes`) between 1 and 65536) and (`source_assistant_sha256` = lower(sha2(`source_snapshot_bytes`,256)))))), CONSTRAINT `studio_media_request_sha` CHECK ((`request_sha256` = lower(sha2(`request_bytes`,256)))), CONSTRAINT `studio_media_request_size` CHECK (((length(`request_bytes`) between 1 and 65536) and (length(`quote_bytes`) between 1 and 65536))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_submission_attempts 一次提交的任务证据与不确定结果
CREATE TABLE `studio_media_submission_attempts` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempt_no` int unsigned NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_idempotency_key` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `stage` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `dispatch_started_at` datetime(6) DEFAULT NULL, `provider_task_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `receipt_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `terminal_receipt_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `reconciliation_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_attempt_job` (`job_id`,`attempt_no`), UNIQUE KEY `studio_media_attempt_idempotency` (`provider_idempotency_key`), KEY `studio_media_attempt_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`,`request_sha256`), CONSTRAINT `studio_media_attempt_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`, `request_sha256`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`), CONSTRAINT `studio_media_attempt_number` CHECK ((`attempt_no` = 1)), CONSTRAINT `studio_media_attempt_state` CHECK ((((`stage` = _latin1'prepared') and (`dispatch_started_at` is null) and (`provider_task_id` is null) and (`receipt_sha256` is null) and (`reconciliation_sha256` is null) and (`terminal_receipt_sha256` is null)) or ((`stage` in (_latin1'dispatching',_latin1'unknown')) and (`dispatch_started_at` is not null) and (`dispatch_started_at` >= `created_at`) and (`provider_task_id` is null) and (`receipt_sha256` is null) and (`reconciliation_sha256` is null) and (`terminal_receipt_sha256` is null)) or ((`stage` = _latin1'acknowledged') and (`dispatch_started_at` is not null) and (`provider_task_id` is not null) and (`receipt_sha256` is not null) and (`terminal_receipt_sha256` is null)) or ((`stage` in (_latin1'completed',_latin1'failed')) and (`dispatch_started_at` is not null) and (`provider_task_id` is not null) and (`receipt_sha256` is not null) and (`terminal_receipt_sha256` is not null)) or ((`stage` = _latin1'reconciled_not_sent') and (`dispatch_started_at` is not null) and (`provider_task_id` is null) and (`reconciliation_sha256` is not null)))), CONSTRAINT `studio_media_attempt_times` CHECK (((`updated_at` >= `created_at`) and ((`dispatch_started_at` is null) or (`dispatch_started_at` between `created_at` and `updated_at`)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_project_asset_refs 项目对用户级素材的引用;不复制素材所有权
CREATE TABLE `studio_project_asset_refs` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_metadata_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, `detached_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`project_id`,`asset_id`), KEY `studio_project_asset_owned_page` (`owner_id`,`project_id`,`asset_id`), KEY `studio_project_asset_reverse` (`owner_id`,`asset_id`,`project_id`), CONSTRAINT `studio_project_asset_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_project_asset_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_project_asset_state` CHECK ((((`state` = _latin1'attached') and (`detached_at` is null)) or ((`state` = _latin1'detached') and (`detached_at` is not null) and (`detached_at` = `updated_at`)))), CONSTRAINT `studio_project_asset_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_projects 用户拥有的创作项目
CREATE TABLE `studio_projects` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `title` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_project_owner_identity` (`owner_id`,`id`), KEY `studio_project_owner_list` (`owner_id`,`created_at`,`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_timeline_revisions 历史时间轴修订
CREATE TABLE `studio_timeline_revisions` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_bytes` mediumblob NOT NULL, `state_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `restored_from_revision` bigint unsigned DEFAULT NULL, `recorded_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`,`project_id`,`kind`,`revision`), KEY `studio_timeline_revision_source_fk` (`owner_id`,`project_id`,`kind`,`restored_from_revision`), CONSTRAINT `studio_timeline_revision_head_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_video_documents` (`owner_id`, `project_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_timeline_revision_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `kind`, `restored_from_revision`) REFERENCES `studio_timeline_revisions` (`owner_id`, `project_id`, `kind`, `revision`), CONSTRAINT `studio_timeline_revision_bytes` CHECK ((length(`state_bytes`) between 1 and 262144)), CONSTRAINT `studio_timeline_revision_kind` CHECK ((`kind` = _latin1'timeline')), CONSTRAINT `studio_timeline_revision_number` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_timeline_revision_origin` CHECK ((((`origin` in (_latin1'saved',_latin1'backfill')) and (`restored_from_revision` is null)) or ((`origin` = _latin1'restored') and (`restored_from_revision` is not null) and (`restored_from_revision` between 1 and (`revision` - 1))))), CONSTRAINT `studio_timeline_revision_sha` CHECK ((`state_sha256` = lower(sha2(`state_bytes`,256)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_video_documents 项目当前时间轴文档
CREATE TABLE `studio_video_documents` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_json` json NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`project_id`), UNIQUE KEY `studio_timeline_owned_head` (`owner_id`,`project_id`), CONSTRAINT `studio_document_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_document_revision` CHECK ((`revision` between 1 and 2147483647)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
共享身份库(15 张)与积分账本 七个品牌相同,展开查看
studio_assets
CREATE TABLE `studio_assets` (
`id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`metadata_json` json NOT NULL,
`storage_key` varchar(512) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`created_at` datetime(6) NOT NULL,
`publication_state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT 'visible',
PRIMARY KEY (`id`),
UNIQUE KEY `studio_asset_owner_digest` (`owner_id`,`sha256`),
KEY `studio_asset_owner_list` (`owner_id`,`created_at`,`id`),
KEY `studio_asset_visible_list` (`owner_id`,`publication_state`,`created_at`,`id`),
CONSTRAINT `studio_asset_publication_state` CHECK (CAST(publication_state AS BINARY) IN ('pending','visible')),
CONSTRAINT `studio_asset_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_billing_cycles
CREATE TABLE `studio_billing_cycles` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`subscription_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`payment_order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_invoice_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`period_start` datetime(6) NOT NULL,
`period_end` datetime(6) NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`valid_from` datetime(6) NOT NULL,
`expires_at` datetime(6) NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`paid_evidence_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `billing_cycle_owned` (`owner_id`,`id`),
UNIQUE KEY `billing_cycle_period` (`subscription_id`,`period_start`),
UNIQUE KEY `billing_cycle_invoice` (`provider_key`,`provider_account`,`provider_invoice_id`),
UNIQUE KEY `billing_cycle_order` (`payment_order_id`),
KEY `billing_cycle_subscription_fk` (`owner_id`,`subscription_id`,`provider_key`,`provider_account`),
KEY `billing_cycle_order_fk` (`owner_id`,`payment_order_id`,`plan_version_id`),
KEY `billing_cycle_order_provider_fk` (`owner_id`,`payment_order_id`,`provider_key`,`provider_account`),
CONSTRAINT `billing_cycle_order_fk` FOREIGN KEY (`owner_id`, `payment_order_id`, `plan_version_id`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `plan_version_id`),
CONSTRAINT `billing_cycle_order_provider_fk` FOREIGN KEY (`owner_id`, `payment_order_id`, `provider_key`, `provider_account`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `provider_key`, `provider_account`),
CONSTRAINT `billing_cycle_subscription_fk` FOREIGN KEY (`owner_id`, `subscription_id`, `provider_key`, `provider_account`) REFERENCES `studio_subscriptions` (`owner_id`, `id`, `provider_key`, `provider_account`),
CONSTRAINT `billing_cycle_amount` CHECK ((`grant_credits` between 1 and 1000000000)),
CONSTRAINT `billing_cycle_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `billing_cycle_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `billing_cycle_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `billing_cycle_state` CHECK (((`state` in (_latin1'PENDING',_latin1'PAID',_latin1'CLOSED')) and (((`state` = _latin1'PAID') and (`paid_evidence_sha256` is not null) and regexp_like(`paid_evidence_sha256`,_latin1'^[a-f0-9]{64}$')) or ((`state` <> _latin1'PAID') and (`paid_evidence_sha256` is null))))),
CONSTRAINT `billing_cycle_times` CHECK (((`period_end` > `period_start`) and (`expires_at` > `valid_from`) and (`expires_at` <= (`valid_from` + interval 31622400 second)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_credit_accounts
CREATE TABLE `studio_credit_accounts` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `unit` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`), CONSTRAINT `credit_account_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `credit_account_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `credit_account_status` CHECK ((`status` in (_latin1'open',_latin1'suspended'))), CONSTRAINT `credit_account_unit` CHECK ((`unit` = _latin1'credits')) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_authorization_allocations
CREATE TABLE `studio_credit_authorization_allocations` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `lot_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `allocated_credits` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`authorization_id`,`lot_id`), UNIQUE KEY `credit_allocation_owned` (`owner_id`,`authorization_id`,`lot_id`), KEY `credit_allocation_lot` (`owner_id`,`lot_id`,`authorization_id`), CONSTRAINT `credit_allocation_authorization_fk` FOREIGN KEY (`owner_id`, `authorization_id`) REFERENCES `studio_credit_authorizations` (`owner_id`, `id`), CONSTRAINT `credit_allocation_lot_fk` FOREIGN KEY (`owner_id`, `lot_id`) REFERENCES `studio_credit_lots` (`owner_id`, `id`), CONSTRAINT `credit_allocation_amount` CHECK ((`allocated_credits` between 1 and 1000000000)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_authorizations
CREATE TABLE `studio_credit_authorizations` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`profile` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`credits` bigint unsigned NOT NULL,
`expires_at` datetime(6) NOT NULL,
`reservation_bytes` mediumblob NOT NULL,
`reservation_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`policy_bytes` mediumblob NOT NULL,
`policy_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_authorization_owned` (`owner_id`,`id`),
UNIQUE KEY `credit_authorization_job` (`owner_id`,`profile`,`job_id`),
CONSTRAINT `credit_authorization_account_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_credit_accounts` (`owner_id`),
CONSTRAINT `credit_authorization_amount` CHECK ((`credits` between 1 and 1000000000)),
CONSTRAINT `credit_authorization_hashes` CHECK ((regexp_like(`request_sha256`,_latin1'^[a-f0-9]{64}$') and regexp_like(`quote_sha256`,_latin1'^[a-f0-9]{64}$'))),
CONSTRAINT `credit_authorization_policy_sha` CHECK ((`policy_sha256` = lower(sha2(`policy_bytes`,256)))),
CONSTRAINT `credit_authorization_policy_size` CHECK ((length(`policy_bytes`) between 1 and 65536)),
CONSTRAINT `credit_authorization_profile` CHECK ((`profile` in (_latin1'topview',_latin1'pollo',_latin1'invideo',_latin1'libtv',_latin1'flova',_latin1'creatok',_latin1'creatify'))),
CONSTRAINT `credit_authorization_reservation_sha` CHECK ((`reservation_sha256` = lower(sha2(`reservation_bytes`,256)))),
CONSTRAINT `credit_authorization_reservation_size` CHECK ((length(`reservation_bytes`) between 1 and 65536)),
CONSTRAINT `credit_authorization_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `credit_authorization_state` CHECK ((`state` in (_latin1'HELD',_latin1'CAPTURED',_latin1'RELEASED'))),
CONSTRAINT `credit_authorization_times` CHECK (((`expires_at` > `created_at`) and (`expires_at` <= (`created_at` + interval 15 minute)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_credit_ledger_entries
CREATE TABLE `studio_credit_ledger_entries` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `lot_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `operation_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `grant_delta` bigint NOT NULL, `held_delta` bigint NOT NULL, `captured_delta` bigint NOT NULL, `facts_bytes` mediumblob NOT NULL, `facts_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `credit_entry_operation` (`owner_id`,`operation_key`,`lot_id`), KEY `credit_entry_page` (`owner_id`,`created_at`,`id`), KEY `credit_entry_lot_fk` (`owner_id`,`lot_id`), KEY `credit_entry_allocation_fk` (`owner_id`,`authorization_id`,`lot_id`), CONSTRAINT `credit_entry_allocation_fk` FOREIGN KEY (`owner_id`, `authorization_id`, `lot_id`) REFERENCES `studio_credit_authorization_allocations` (`owner_id`, `authorization_id`, `lot_id`), CONSTRAINT `credit_entry_authorization_fk` FOREIGN KEY (`owner_id`, `authorization_id`) REFERENCES `studio_credit_authorizations` (`owner_id`, `id`), CONSTRAINT `credit_entry_lot_fk` FOREIGN KEY (`owner_id`, `lot_id`) REFERENCES `studio_credit_lots` (`owner_id`, `id`), CONSTRAINT `credit_entry_delta` CHECK ((((`kind` = _latin1'grant') and (`authorization_id` is null) and (`grant_delta` between 1 and 1000000000) and (`held_delta` = 0) and (`captured_delta` = 0)) or ((`kind` = _latin1'hold') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`held_delta` between 1 and 1000000000) and (`captured_delta` = 0)) or ((`kind` = _latin1'capture') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`captured_delta` between 1 and 1000000000) and (`held_delta` = -(`captured_delta`))) or ((`kind` = _latin1'release') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`held_delta` between -(1000000000) and -(1)) and (`captured_delta` = 0)))), CONSTRAINT `credit_entry_facts_sha` CHECK ((`facts_sha256` = lower(sha2(`facts_bytes`,256)))), CONSTRAINT `credit_entry_facts_size` CHECK ((length(`facts_bytes`) between 1 and 65536)), CONSTRAINT `credit_entry_operation_key` CHECK ((((`kind` = _latin1'grant') and (`operation_key` = concat(`lot_id`,_latin1':grant'))) or ((`kind` <> _latin1'grant') and (`operation_key` = concat(`authorization_id`,_latin1':',`kind`))))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_lots
CREATE TABLE `studio_credit_lots` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `grant_credits` bigint unsigned NOT NULL, `held_credits` bigint unsigned NOT NULL, `captured_credits` bigint unsigned NOT NULL, `valid_from` datetime(6) NOT NULL, `expires_at` datetime(6) NOT NULL, `eligibility_bytes` mediumblob NOT NULL, `eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_cycle_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `credit_lot_owned` (`owner_id`,`id`), UNIQUE KEY `credit_lot_order` (`source_order_id`), UNIQUE KEY `credit_lot_cycle` (`source_cycle_id`), KEY `credit_lot_eligible` (`owner_id`,`expires_at`,`id`), KEY `credit_lot_order_fk` (`owner_id`,`source_order_id`), KEY `credit_lot_cycle_fk` (`owner_id`,`source_cycle_id`), CONSTRAINT `credit_lot_account_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_credit_accounts` (`owner_id`), CONSTRAINT `credit_lot_cycle_fk` FOREIGN KEY (`owner_id`, `source_cycle_id`) REFERENCES `studio_billing_cycles` (`owner_id`, `id`), CONSTRAINT `credit_lot_order_fk` FOREIGN KEY (`owner_id`, `source_order_id`) REFERENCES `studio_payment_orders` (`owner_id`, `id`), CONSTRAINT `credit_lot_counters` CHECK (((`grant_credits` between 1 and 1000000000) and (`held_credits` <= 1000000000) and (`captured_credits` <= 1000000000) and ((`held_credits` + `captured_credits`) <= `grant_credits`))), CONSTRAINT `credit_lot_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))), CONSTRAINT `credit_lot_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)), CONSTRAINT `credit_lot_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `credit_lot_source` CHECK ((((`source_order_id` is not null) and (`source_cycle_id` is null)) or ((`source_order_id` is null) and (`source_cycle_id` is not null)))), CONSTRAINT `credit_lot_times` CHECK (((`expires_at` > `valid_from`) and (`updated_at` >= `created_at`))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_plan_versions
CREATE TABLE `studio_credit_plan_versions` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`version_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`price_minor` bigint unsigned NOT NULL,
`currency` char(3) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`credit_validity_seconds` int unsigned NOT NULL,
`billing_interval_months` int unsigned NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`published_at` datetime(6) NOT NULL,
`retired_at` datetime(6) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_plan_version_key` (`plan_key`,`version_key`),
CONSTRAINT `credit_plan_amount` CHECK (((`price_minor` between 1 and 1000000000000) and (`grant_credits` between 1 and 1000000000))),
CONSTRAINT `credit_plan_currency` CHECK (regexp_like(`currency`,_latin1'^[A-Z]{3}$')),
CONSTRAINT `credit_plan_duration` CHECK (((`credit_validity_seconds` between 1 and 31622400) and ((`retired_at` is null) or (`retired_at` >= `published_at`)))),
CONSTRAINT `credit_plan_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `credit_plan_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `credit_plan_kind` CHECK (((`kind` in (_latin1'subscription',_latin1'topup')) and (((`kind` = _latin1'subscription') and (`billing_interval_months` in (1,3,12))) or ((`kind` = _latin1'topup') and (`billing_interval_months` = 0)))))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_media_model_versions
CREATE TABLE `studio_media_model_versions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `version_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `config_bytes` mediumblob NOT NULL, `config_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `published_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_version_key` (`model_id`,`version_key`), UNIQUE KEY `studio_media_version_owned_model` (`model_id`,`id`), CONSTRAINT `studio_media_version_model_fk` FOREIGN KEY (`model_id`) REFERENCES `studio_media_models` (`id`), CONSTRAINT `studio_media_version_sha` CHECK ((`config_sha256` = lower(sha2(`config_bytes`,256)))), CONSTRAINT `studio_media_version_size` CHECK ((length(`config_bytes`) between 1 and 65536)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_models
CREATE TABLE `studio_media_models` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `display_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `published_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `revision` bigint unsigned NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_model_key` (`model_key`), KEY `studio_media_model_published_fk` (`id`,`published_version_id`), CONSTRAINT `studio_media_model_published_fk` FOREIGN KEY (`id`, `published_version_id`) REFERENCES `studio_media_model_versions` (`model_id`, `id`), CONSTRAINT `studio_media_model_kind` CHECK ((`kind` = _ascii'video')), CONSTRAINT `studio_media_model_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_media_model_status` CHECK (((`status` in (_ascii'draft',_ascii'active',_ascii'disabled')) and ((`status` <> _ascii'active') or (`published_version_id` is not null)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_payment_events
CREATE TABLE `studio_payment_events` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_event_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `subscription_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `body_bytes` mediumblob NOT NULL, `body_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `payment_event_provider` (`provider_key`,`provider_account`,`provider_event_id`), KEY `payment_event_order_fk` (`owner_id`,`order_id`,`provider_key`,`provider_account`), KEY `payment_event_subscription_fk` (`owner_id`,`subscription_id`,`provider_key`,`provider_account`), CONSTRAINT `payment_event_order_fk` FOREIGN KEY (`owner_id`, `order_id`, `provider_key`, `provider_account`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `provider_key`, `provider_account`), CONSTRAINT `payment_event_subscription_fk` FOREIGN KEY (`owner_id`, `subscription_id`, `provider_key`, `provider_account`) REFERENCES `studio_subscriptions` (`owner_id`, `id`, `provider_key`, `provider_account`), CONSTRAINT `payment_event_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `payment_event_body_sha` CHECK ((`body_sha256` = lower(sha2(`body_bytes`,256)))), CONSTRAINT `payment_event_body_size` CHECK ((length(`body_bytes`) between 1 and 65536)), CONSTRAINT `payment_event_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `payment_event_state` CHECK ((`state` in (_latin1'VERIFIED',_latin1'PROCESSED'))), CONSTRAINT `payment_event_subject` CHECK (((`order_id` is not null) or (`subscription_id` is not null))), CONSTRAINT `payment_event_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_payment_orders
CREATE TABLE `studio_payment_orders` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`price_minor` bigint unsigned NOT NULL,
`currency` char(3) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`valid_from` datetime(6) NOT NULL,
`expires_at` datetime(6) NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_idempotency_key` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_order_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`paid_evidence_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `payment_order_owned` (`owner_id`,`id`),
UNIQUE KEY `payment_order_owned_plan` (`owner_id`,`id`,`plan_version_id`),
UNIQUE KEY `payment_order_owned_provider` (`owner_id`,`id`,`provider_key`,`provider_account`),
UNIQUE KEY `payment_order_client` (`owner_id`,`client_action_id`),
UNIQUE KEY `payment_order_provider_key` (`provider_key`,`provider_account`,`provider_idempotency_key`),
UNIQUE KEY `payment_order_provider_id` (`provider_key`,`provider_account`,`provider_order_id`),
KEY `payment_order_plan_fk` (`plan_version_id`),
CONSTRAINT `payment_order_plan_fk` FOREIGN KEY (`plan_version_id`) REFERENCES `studio_credit_plan_versions` (`id`),
CONSTRAINT `payment_order_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`),
CONSTRAINT `payment_order_amount` CHECK (((`price_minor` between 1 and 1000000000000) and (`grant_credits` between 1 and 1000000000))),
CONSTRAINT `payment_order_currency` CHECK (regexp_like(`currency`,_latin1'^[A-Z]{3}$')),
CONSTRAINT `payment_order_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `payment_order_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `payment_order_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `payment_order_state` CHECK (((`state` in (_latin1'CREATING',_latin1'CREATE_UNKNOWN',_latin1'PENDING',_latin1'PAID',_latin1'CLOSED')) and (((`state` = _latin1'PAID') and (`provider_order_id` is not null) and (`paid_evidence_sha256` is not null) and regexp_like(`paid_evidence_sha256`,_latin1'^[a-f0-9]{64}$')) or ((`state` <> _latin1'PAID') and (`paid_evidence_sha256` is null))))),
CONSTRAINT `payment_order_times` CHECK (((`expires_at` > `valid_from`) and (`expires_at` <= (`valid_from` + interval 31622400 second)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_sessions
CREATE TABLE `studio_sessions` ( `token_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `user_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, `expires_at` datetime(6) NOT NULL, `revoked_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`token_hash`), KEY `studio_session_expiry` (`expires_at`), KEY `studio_session_user` (`user_id`,`expires_at`), CONSTRAINT `studio_session_user_fk` FOREIGN KEY (`user_id`) REFERENCES `studio_users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_session_times` CHECK ((`expires_at` > `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_subscriptions
CREATE TABLE `studio_subscriptions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_subscription_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `period_start` datetime(6) NOT NULL, `period_end` datetime(6) NOT NULL, `cancel_at_period_end` tinyint(1) NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `subscription_owned` (`owner_id`,`id`), UNIQUE KEY `subscription_owned_provider` (`owner_id`,`id`,`provider_key`,`provider_account`), UNIQUE KEY `subscription_provider` (`provider_key`,`provider_account`,`provider_subscription_id`), KEY `subscription_plan_fk` (`plan_version_id`), CONSTRAINT `subscription_plan_fk` FOREIGN KEY (`plan_version_id`) REFERENCES `studio_credit_plan_versions` (`id`), CONSTRAINT `subscription_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `subscription_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `subscription_state` CHECK (((`state` in (_latin1'PENDING',_latin1'ACTIVE',_latin1'PAST_DUE',_latin1'CANCELLED',_latin1'ENDED')) and (`cancel_at_period_end` in (0,1)))), CONSTRAINT `subscription_times` CHECK (((`period_end` > `period_start`) and (`updated_at` >= `created_at`))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_users
CREATE TABLE `studio_users` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `email` varchar(254) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `password_hash` varbinary(72) NOT NULL, `enabled` tinyint(1) NOT NULL DEFAULT '1', `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_user_email` (`email`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
积分账本链路
Pollo · 接口清单
共 55 个公开接口,取自源码路由盘点。路径都以 /v1 开头;写操作需要会话 Cookie、可信 Host/Origin 与 CSRF;带品牌的路径用 ?profile=pollo;共享的登录、素材、模型目录路径不接受 profile 参数。
Agent/统一动作 7 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/interactions | runInteractions | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/interactions/{interaction_id}/responses | respondInteraction | client_action_id, card_sha256, action, values | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/interaction-actions/{client_action_id} | interactionAction | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/model-changes | changeConversationModel | client_action_id, expected_revision, agent_model, expected_attempt? | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/model-changes/{client_action_id} | modelChangeAction | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/stop | stopRun | client_action_id, expected_attempt? | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/stop-actions/{client_action_id} | stopAction | 200 |
Asset 4 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/assets | listAssets | 200 | |
| POST | /v1/assets | uploadAsset | file | 201 |
| GET | /v1/assets/{asset_id} | getAsset | 200 | |
| GET | /v1/assets/{asset_id}/content | assetContent | 200/206 |
LoginSession 1 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| POST | /v1/auth/logout | logout | 200 |
MaaBinding 5 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/maa/model-options | maaModels | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/messages | sendMaaMessage | client_action_id, content | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/actions/{client_action_id} | getMaaAction | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/state | getMaaState | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/events | maaEvents | 200 |
Media 11 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/media/models | publicMediaModels | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests | createMediaRequest | client_request_id, model_id, model_version_id, prompt, duration_seconds, ratio, resolution, admission? | 200 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests | mediaRequestByClient | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id} | getMediaRequest | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs/{job_id} | getMediaJob | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs/{job_id}/output | getMediaOutput | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id}/job | mediaJobByRequest | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id}/approve | approveMediaRequest | client_approval_id, request_sha256, quote_sha256 | 200 |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/from-maa | createMediaRequestFromMaa | input, source_run_id, source_assistant_sha256, admission? | 200 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs | listMediaJobs | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/intents | listMediaIntents | 200 |
Other 9 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects/{project_id}/canvas/revisions | listCanvasRevisions | 200 | |
| GET | /v1/projects/{project_id}/canvas/revisions/{revision} | getCanvasRevision | 200 | |
| POST | /v1/projects/{project_id}/canvas/revisions/{revision}/restore | restoreCanvasRevision | expected_revision | 200 |
| GET | /v1/projects/{project_id}/document/revisions | listTimelineRevisions | 200 | |
| GET | /v1/projects/{project_id}/document/revisions/{revision} | getTimelineRevision | 200 | |
| POST | /v1/projects/{project_id}/document/revisions/{revision}/restore | restoreTimelineRevision | expected_revision | 200 |
| GET | /v1/projects/{project_id}/assets | listProjectAssets | 200 | |
| POST | /v1/projects/{project_id}/assets | attachProjectAsset | asset_id, expected_revision | 200 |
| POST | /v1/projects/{project_id}/assets/{asset_id}/detach | detachProjectAsset | expected_revision | 200 |
Project 15 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects | listProjects | 200 | |
| POST | /v1/projects | createProject | title | 201 |
| GET | /v1/projects/{project_id} | getProject | 200 | |
| GET | /v1/projects/{project_id}/conversations | listConversations | 200 | |
| POST | /v1/projects/{project_id}/conversations | createConversation | title | 201 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id} | getConversation | 200 | |
| GET | /v1/projects/{project_id}/canvas | getCanvas | 200 | |
| POST | /v1/projects/{project_id}/canvas | saveCanvas | expected_revision, state | 200 |
| GET | /v1/projects/{project_id}/document | getDocument | 200 | |
| POST | /v1/projects/{project_id}/document | saveDocument | expected_revision, state | 200 |
| GET | /v1/projects/{project_id}/export-jobs | listExportJobs | 200 | |
| POST | /v1/projects/{project_id}/export-jobs | queueExport | document_revision, output? | 202 |
| GET | /v1/projects/{project_id}/export-jobs/{job_id} | getExportJob | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/binding | getMaaBinding | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/binding | bindMaa | agent_model XOR use_default:true | 200 |
User 3 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| POST | /v1/auth/register | register | email, password | 201 |
| POST | /v1/auth/login | login | email, password | 200 |
| GET | /v1/auth/session | session | 200 |
Pollo 自己公开的接口调用流程(来自其官方资料)
| 步骤 | 调用关系 | 操作 | 证据 |
|---|---|---|---|
| 载入项目上下文 | 浏览器 → 业务入口 | tRPC UI batch:userProject.getListV2、generationModel.list、userElement.list。 | O |
| 读取项目会话 | 浏览器 → Agent入口 | POST /api/agent-gateway/agent/v1/threads/search;metadata.project_id、limit、offset。 | O |
| 创建长会话 | 浏览器 → Agent入口 | POST /api/agent-gateway/agent/v1/threads;metadata:{project_id,idempotency_key} → data.thread_id。 | O |
| 启动当前回合 | 浏览器 → Agent入口 | POST /api/agent-gateway/agent/v1/threads/{thread_id}/runs/stream;input.messages、config.configurable、metadata、stream_mode;返回 text/event-stream。 | O |
| 合并流式消息 | Agent入口 → 浏览器 | SSE metadata(run_id)、values、messages([MessageChunk,ExecutionMetadata])、end;每帧含 event/data/id。 | O |
| 显示工具结果 | Agent入口 → 浏览器 | messages 中出现 message_notify_user:ToolCall.id == ToolResult.tool_call_id;status=success、artifact=[]。 | O |
| 读回持久视图 | 浏览器 → Agent入口 | end success 后:GET /api/agent-gateway/agent/v1/threads/{thread_id}/state;POST .../conversation;POST .../artifacts;GET .../suggestions?turn_id=...。 | O |
| 核对商业视图 | 浏览器 → 业务入口 | 刷新首页可见积分,并读取既有 subLog.getSubLog / subUsage 订阅与用量投影;未取得完整私有 HTTP 路径。 | O |
Pollo · 代码与下载
2.7 MB · 78 个文件 · SHA-256
76d911e406f4578a40b0c334faddcd5fc814ead15420990ff1fd7bcd5d0f9d71下载:pollo-replica.zip · 后端与合同 · 全部代码
| 目录 | 内容 |
|---|---|
| frontend/ | Pollo 前端:<code>candidate-8891-attachments-v22.html</code> 及它引用的全部脚本与样式 |
| contracts/ | 本品牌的表结构 SQL、ER(svg / mmd)、外键清单;接口目录(json / csv);共享身份库表结构 |
| README.md | 怎么运行、需要自备什么 |
运行前端
python3 -m http.server -d frontend 8791
# 打开 http://127.0.0.1:8791/agent-integration/apps-production-brand-v14/pollo/candidate-8891-attachments-v22.htmlbackend-and-contracts.zip;all-brands-code.zip 是全部。包里没有任何凭据、数据库备份或媒体文件,已做敏感串扫描。MAA_AGENT_ROOT)、模型网关与对象存储配置。静态前端单独打开不需要后端,但登录、对话、生成、导出需要整套服务。复刻完成度(审计 2026-10-19)
结论:不是完美复刻。官方资料里的 80 项能力:实测跑通 5、仅隔离环境跑通 1、只有通用对话 0、后端有但没跑过 5、没有后端 69。
真正跑通的:自然语言 Agent 创作;澄清与局部修改(隔离环境);项目、会话和历史;流式回复与恢复入口;文生视频与提示词辅助;分类素材与输入来源。
界面对照(首页(已登录)):真实页面采集到 18 个控件 / 标题文字,复刻页找到 15 个;位置偏差中位数 34 px(3/15 个在 24 px 内)。缺的有:Refer & Earn、Text/Image to Video、Pollo 2.0。
界面对照(Agent 页):真实页面采集到 24 个控件 / 标题文字,复刻页找到 12 个;位置偏差中位数 135 px(0/12 个在 24 px 内)。缺的有:Quality · High、More Skills、Got it、Why Create Videos With Pollo Agent、Turn Rough Inputs Into One Complete Video、Change Direction Without Starting Over、Video Workflows Built Around Your Goal、Project Assets Ready to Reuse、Create More With Pollo AI Video Tools、Loved by 10M+ Creators and Marketers Globally、Questions and Answers、YOUR NEXT VIDEO, FULLY PRODUCED。
逐个点击(已登录首页):47 个可点控件,点了有效 14 个,只提示“此功能正在接入” 28 个,没反应或只变样式 3 个,禁用 0 个,未点(发送 / 删除 / 退出等)2 个。
只提示“正在接入”的控件(28 次点击,28 种)
Toggle sidebar、Video、Image、Director、Marketing Studio、Brand Kit、Interactive Video、App、API、MCP、♧ Refer & Earn、Text/Image to Video⌄、WIN IPHONE DUO、POLLO MCP、GET UNLIMITED GPT IMAGE 2.5、AI Video Editor、Video Upscaler、Video Enhancer、Lip Sync AI、Face Swap Video、AI Video Extender、Viral、TVC、Product Shot、Product Image Set、UGC Video Ad、Food & Beverage、Social Media
点了没反应或只变样式的控件(3 次点击,3 种)
Home、Create、Video
复刻页自报的绑定状态(页面内嵌的绑定清单):原生工作区控件(新建项目、会话、登录等)9 / 10 个没有绑定到原页面的控件,由统一的工作区条代替;路由 projects、canvas、assets 缺失或只做了一部分;输入框 2 个标为“需要修结构”。
首屏截图对照(左:真实产品 pollo/source-home-desktop-safe.png;右:复刻页)· 粗粒度差异 27%
真实截图是测试账号登录后的画面,内容(作品、项目、横幅)本来就不同,差异百分比只作参考,重点看布局。
invideo AI · 总览
- 它是什么:一句话让 Agent 出片,再进编辑器;Agent 交互:Agent 产物可在编辑器继续改。
- 我们借鉴:Agent 产出落成可编辑对象(决策 D1)。
- 复刻现状:4 项已验证,在线试用 http://119.23.106.60:8103/;后端与其余六个品牌共用一套(24 张表、55 个接口),所以 ER / 表结构 / 接口页的通用部分默认折叠。
按 12 类盘点当前 Editor、invideo AI、legacy Studio、官方手机 App 与外部 MCP。每条是官方公开能力或合同,使用平台分别标注。
证据:W 官方说明,A 官方接口合同,C 客户端代码,O 实测。“未实测”= 只核对了官方页面,没有上传素材或生成。
58 项,分 12 类
Agent 工作台 + 编辑器
24 张表 · 34 个外键 · 85 个索引
能力目录
Agent 与规划 5 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 自然语言剪辑与追问 | 说明目标片段、时长和保留内容,由 Agent 调整时间轴,再人工修改或继续追问。 | W | 帮助描述工作流,未抓到 Web 会话传输或修改指令的数据包。 |
| 多个专业 Agent 共用项目背景 | 可把选角、场景和音乐分给不同 Agent,共享角色、地点和创作规则。 | W | 公开流程不证明 Agent 数量上限或后台任务调度方式。 |
| 脚本协写与逐镜头规划 | 先写脚本和镜头计划,再审核和调整后进入生成。 | W | 未核实私有接口、质量表现及当前账号的具体额度。 |
| 按画面含义查找素材 | 用自然语言描述要找的片段,由 Agent 从项目素材中定位。 | W | 属于官网能力说明;检索效果和索引实现未实测。 |
| 生成前审批与参数修改 | 可选择直接生成、视频生成前确认或每次确认;审批时可改提示词、模型、时长和比例。 | W | 设置作用范围及所有入口是否一致待实测。 |
项目与会话 2 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 项目中找回时间轴 | 从 Projects 进入项目,在 Notebook 和 Agent Chat 中重新打开保存的时间轴。 | W | UI 层级已说明;项目、Agent、聊天和时间轴的内部 ID 与基数未知。 |
| 已提交工作在云端继续 | 完成上传和提交后可关闭浏览器,再打开项目查看 Agent 的结果。 | W | 不证明失败重试、断流续传或任务恰好执行一次。 |
素材管理 2 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 上传图片视频音频并分文件夹 | 本地上传或拖入素材,用 Media Folders 按场景、机位或类型整理。 | W | 格式、大小和存储额度以登录后的限制为准。 |
| 多机位同步与主音轨选择 | 把不同机位放入文件夹,指定主音频,让 Agent 对齐为时间轴图层。 | W | 支持流程已有帮助;同步精度和异常素材处理待验证。 |
画布与分镜 2 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| Storyboard 与 Canvas 切换 | 旧 Studio 支持在分镜总览和单场景画布之间切换。 | W | 这里的 Canvas 是场景编辑视图,不能据此认定存在节点连线工作流。 |
| 场景与元素独立编辑 | 可增删、复制或重排场景,调整元素图层、显示时间、动画和转场。 | W | 未核实私有接口、质量表现及当前账号的具体额度。 |
时间轴编辑 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 多轨时间轴与可调整面板 | 当前 Editor 有视频和音频轨、播放头、Monitor 和 Inspector,支持调整工作区布局。 | W | 未核实私有接口、质量表现及当前账号的具体额度。 |
| 裁切拆分移动与轨道锁定 | 修剪片段、刀片拆分、调整轨道和位置;关联音频可保持同步。 | W | 快捷键和支持格式需用实际素材验证。 |
| 音量混合与颜色调整 | 在时间轴中平衡对白和背景音乐,调整画面颜色;也可给 Agent 对应编辑指令。 | W | 未核实私有接口、质量表现及当前账号的具体额度。 |
生成与模型 15 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 提示词到完整视频 | 给出内容、平台和风格,让 AI 组织脚本、画面、配音、字幕和音乐,再继续修改。 | W | 该页面包含 AI v3.0 的 Magic Box 流程,不能直接当成当前 Editor 的同一界面。 |
| 文字生成图片 | 用文字描述构图和风格,选择图片模型生成独立素材。 | W | 不采用宣传页中不一致的模型数量;质量和可用模型待验证。 |
| 参考图片生成动态视频 | 上传图片,描述镜头运动并选择模型,生成可继续编辑的片段。 | W | 跨镜头人物和产品一致性是官方能力主张,效果未实测。 |
| 延长或补齐已有场景 | 当前 Editor 可生成镜头前后或中间缺失部分,画面和声音保留为可调整图层。 | W | 官方 2026-10-06 公布最长 30 秒扩展;实际模型准入、扣费和连续性待验。 |
| 图片清晰度增强与放大 | 上传图片选择增强模型,改善清晰度、噪声和曝光,并生成新的结果。 | W | 宣传中的效果、批量吞吐和最大输出规格未实测。 |
| 多模型目录与生成质量档位 | 可选择生成模型;Agent 帮助还区分 Lite、Pro、Ultra 等质量与积分档位。 | W | 模型品牌计为一个目录能力;不同版本的档位和权益不可混用。 |
| 参考图片编辑与风格转换 | 上传原图,用提示词修改局部元素、场景或风格。 | W | 官方工具页说明;模型准入、输出效果和具体额度未实测。 |
| AI 缩略图制作 | 提供标题、视觉要求和参考图,生成用于目标平台的封面。 | W | 不采用宣传中的点击率提升或生成速度保证。 |
| 动画影片工作流 | 选用动画创作流程,组织脚本、生成画面和配音,再用文字修改。 | W | 页面仍描述 AI v3.0 与 Magic Box;不是已验证的逐帧动画编辑器。 |
| 去除背景与透明 PNG | 上传图片分离主体,可下载透明背景 PNG,或继续替换场景。 | W | 官方工具页说明;模型准入、输出效果和具体额度未实测。 |
| 生成可编辑 SVG 矢量图 | 用文字描述生成图标、Logo 或插画,并以 SVG 交付。 | W | 真正矢量路径、编辑性和软件兼容性只有官方声明,未检测输出文件。 |
| 图片尺寸与比例重构 | 上传图片选择目标比例,通过扩图和重新构图适配平台。 | W | 不重复按每种社交平台统计;画面完整性与分辨率待验。 |
| 多图片合并与拼贴 | 用文字指定多图组合,可并排、网格或融合到同一画面。 | W | 官方工具页说明;模型准入、输出效果和具体额度未实测。 |
| 信息图制作与动画化 | 提供数据、步骤或对比要求,生成信息图,再继续制作动态视频。 | W | 数据准确性与文字渲染需核对,不采用宣传准确率作为验收证据。 |
| 图片局部清理 | 用文字移除多余物件、人物或图中文字,生成修补后的结果。 | W | 官方工具页说明;模型准入、输出效果和具体额度未实测。 |
声音人物字幕 10 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 文字配音与情绪声音 | 把脚本转成声音,选择语言、口音和表现方式,生成独立音频或用于视频。 | W | 未核实私有接口、质量表现及当前账号的具体额度。 |
| 多角色对白与场景音频 | 按脚本分配不同说话者,或把对白和环境声组织成场景音频。 | W | 具体声音类型依模型而异,音频分层和质量未实测。 |
| 授权声音克隆 | 上传本人或取得许可的声音样本,建立可用于多语言配音的声音。 | W | 官方要求许可并说明有验证流程;验证环节未实际操作。 |
| 自动字幕与字幕样式 | 上传视频识别语音并对齐字幕,或为生成视频添加、调整字幕样式。 | W | 文字校正、字幕文件格式和导出清晰度的套餐限制待验。 |
| 视频配音与字幕翻译 | 通过目标语言指令调整配音和字幕,制作同一视频的多语言版本。 | W | 该页保留 Magic Box 路线;未证实所有当前 Editor 和 App 入口一致。 |
| AI Twin 与人物口播 | 用自己的影像建立 Twin,或选用人物资源,结合配音制作口播视频。 | W | Express 与 Pro 等路线及人物授权要求不同,不能承诺全套餐可用。 |
| 参考人脸替换视频人物 | 上传原视频和参考人像,生成换脸视频。 | W | 授权审核、真实感和宣传中的批量效果未实测。 |
| 文字生成音效 | 描述需要的声响,生成独立音效。 | W | 官方工具页说明;模型准入、输出效果和具体额度未实测。 |
| 参考视频或音频生成声音 | 把视频或音频与文字指令一起输入,生成相应声音。 | W | 官方工具页说明;模型准入、输出效果和具体额度未实测。 |
| 语音转换为另一声音 | 以已有语音为输入,保留表演节奏和情绪,转换说话声音。 | W | 区别于建立可复用身份的声音克隆;具体模型和授权限制待验。 |
模板品牌广告 5 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 模板与库存媒体组合 | 旧 Studio 按用途查找模板,替换素材、文字和音乐,完成品牌或社交视频。 | W | 未核实私有接口、质量表现及当前账号的具体额度。 |
| 品牌字体颜色与 Logo 预设 | 旧 Studio 可保存品牌素材和样式,供后续编辑使用。 | W | 未核实私有接口、质量表现及当前账号的具体额度。 |
| 商品链接到 UGC 广告 | 读取商品或 App 信息,选定人物,先审核静态镜头,再制作配音和口型动画。 | W | 商品提取、人物一致性和口型同步均为官网流程主张,未运行生成。 |
| 广告开头变体与跨市场复用 | 在同一产品与人物背景下生成不同开头、形式或语言版本。 | W | 官方展示并行广告路线;并发额度、审批和质量比较待验。 |
| 音乐视频场景工作流 | 从音乐视频主题出发组织视觉、配音和音乐,再用文字修改并导出。 | W | 音乐视频制作不等于已经验证能生成独立原创音乐文件。 |
历史审阅协作 5 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 分支里程碑与历史回退 | Branch 用于替代剪辑,Version Tag 标记阶段;History 和撤销用于返回之前的时间轴状态。 | W | 仅有产品语义;版本图、合并、保留期和并发控制合同未知。 |
| 旧 Studio 复制项目与版本回收 | 可复制视频并改变尺寸;旧版本可移入回收站再恢复。 | W | 不证明深拷贝素材或无限保留版本。 |
| Playlist 审阅链接与时间码反馈 | 把时间轴加入 Playlist,分享审阅链接,定位到时间点评论、回复和处理反馈。 | W | 帮助要求评论者登录,产品页称可匿名评论,口径冲突待验;评论不会自动变成 Agent 执行指令。 |
| 当前 Editor 多人实时编辑 | 当前官网公布团队邀请和实时光标,允许成员共同参与编辑与反馈。 | W | 这是当前 Editor 宣传功能;多人冲突、权限和套餐限制未实测,不套用到旧 Studio。 |
| 旧 Studio 共享反馈 | 旧 Studio 提供分享视频和收集意见的协作路线。 | W | 2024 帮助同时明确当时不能多人编辑一个项目,当前是否更新待验证。 |
导出与交付 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 视频音频和静帧分别导出 | 可选择时间范围与输出参数,导出 MP4、独立音频或播放头所在的 PNG 静帧。 | W | 编码、分辨率和响度支持需以实际导出验证。 |
| 交接可继续剪辑的工程 | 支持向 Premiere、Final Cut 或通过 OpenTimelineIO 向其他剪辑软件交接工程。 | W | 跨软件特效、字幕、音色和素材路径的兼容性未实测。 |
| 视频压缩工具 | 上传视频选择压缩质量,下载体积较小的文件。 | W | 官网宣称免注册;本轮未上传文件,也未验证实际格式、大小上限和压缩率。 |
订阅与团队 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 按席位与资源权益售卖 | 当前套餐区分积分、模型准入、库存媒体、存储及团队席位等资源。 | W | 不固定价格、席位数量或额度;旧 Studio、AI 和新 Editor 权益互通未证实。 |
| 按消息和项目查看用量 | 可查看单次 Agent 交换消耗和项目用量,并设置项目积分预算。 | W | 计费账本、失败退款和预算的原子性没有公开合同。 |
| 企业角色项目权限与模型策略 | 企业版公布工作区角色、项目可见范围、模型策略、用量洞察和审计控制。 | W | 企业定制能力以商务合同和账号准入为准,未验证可由普通套餐开启。 |
外部接入与 App 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 远程 MCP 的 OAuth 接入 | 官方入口为 https://mcp.invideo.io/mcp,使用 Streamable HTTP,连接时授权 invideo 账号。 | A | A 仅证明公开接入合同;未授权调用 tools/list,也不证明 Web 聊天采用相同协议。 |
| 外部 Agent 操作同一编辑工程 | 官方说明外部 Agent 可导入和生成媒体,编辑时间轴、标题、转场、颜色和混音。 | W | 能力说明不等于已取得工具参数 schema、实际请求或运行结果。 |
| 官方 iOS 与 Android 创作入口 | 官方商店列有 invideo App,公布 Agent 创作、时间轴编辑、生成和团队反馈能力。 | W | 发布者 Invideo Inc;Android 包名 io.invideo.ai,iOS 商店 ID 6471394316。未安装、取得 IPA/APK 或验证与 Web 的功能和权益互通。 |
尚不清楚的部分
- 当前 Editor / AI / Studio 的工程迁移和订阅互通:官方列有独立入口,未取得实际账号、迁移操作和 entitlement 返回。
- Web Agent 传输与事件恢复:MCP 的 Streamable HTTP 公开合同不能用作 Web 聊天使用相同协议或字段的证据。
- Canvas 是否含节点依赖编排:legacy Canvas 帮助只证明场景画布,当前 Editor 公开资料未给出节点边运行合同。
- 匿名审阅评论:时间轴分享帮助要求登录,反馈产品页称可匿名评论,需实测确认版本和入口。
- 多人编辑一致性、版本合并与保留期:已有实时光标、分支和 History 功能说明,但没有冲突协议、完整历史结构或 SLA。
- 独立原创音乐下载的完整工作流:音乐视频页与模型目录不能证明已经实际生成可单独下载的原创音乐;需登录验证模型和音频导出。
竞品技术栈观察
能支持旧 Studio 的 JavaScript 壳页、公开练习的 React/TypeScript/Vite/Rust-Wasm 技术,以及官方岗位的 Phoenix/Elixir/Rust 工程线索。AI/Editor/Studio 的生产框架、Nginx 版本、仓库布局及源站部署仍未确认。
| 项目 | 观察到的内容 | 状态 | 置信度 |
|---|---|---|---|
| Nginx 与版本 | 是否使用 Nginx、所在层及版本均未确认。 | unknown | low |
| 浏览器运行语言 | 旧 Studio 壳页明确依赖 JavaScript;AI 与当前 Editor 的运行细节未确认。 | observed | high |
| 前端源码语言 | 生产源码语言未确认;官方公开练习有 TSX,TypeScript 声明 ~5.9.3。 | unknown | low |
| 前端框架与版本 | 生产框架未确认;旧 Studio 路径提示 React;公开练习声明 React ^19.2.0。 | unknown | low |
| 构建与 SSR | 生产构建/SSR 未确认;公开练习使用 Vite(声明 ^7.2.4)。 | unknown | low |
| 后端语言 | 官方岗位披露 Elixir 服务与 Rust 组件;各产品实际部署未确认。 | inferred | medium |
| 后端框架与版本 | 官方岗位涉及 Phoenix、Ecto、OTP;对应线上服务与精确版本未知。 | inferred | medium |
| 边缘入口与源站 | AI/静态资源指向 CloudFront;MCP 入口指向 us-west-2 ELB;真实源站与存储未知。 | observed | high |
| 代码仓库与目录 | 生产仓库数量、前后端同目录及发布关系均未知;公开练习的目录不能代表产品。 | unknown | low |
竞品服务调用图
当前 Editor 的项目→Agent→可编辑 Timeline→历史/审阅/导出有官方过程证据;外部 MCP 协议公开。服务图只列逻辑职责,独立候选层、生成适配及真实部署均有明确推断边界。
| 节点 | 层 | 职责 | 证据 |
|---|---|---|---|
| Editor界面 | client | 用户操作 Project、Notebook、Timeline 的客户端。 | W |
| 外部Agent | client | MCP 客户端,例如 Codex/Claude;只作为外部接入者。 | W |
| 外部MCP入口 | entry | 官方公开 Streamable HTTP/OAuth endpoint;同日 DNS 有 ELB 入口线索。 | A |
| 项目访问职责 | domain | 选择账号可访问的 Project、Notebook 与目标 Timeline。 | W |
| 项目素材职责 | domain | 上传、整理媒体并供编辑使用。 | W |
| Agent任务职责 | runtime | 读取项目背景并承接编辑/生成任务。 | W |
| 结果检查职责 | domain | 将 Agent 编辑结果呈现给人检查;是否有独立候选暂存层未证实。 | I |
| 时间轴编辑职责 | domain | 承载人工与 Agent 面向同一 Timeline 的修改。 | W |
| 分支历史职责 | domain | 提供 Branch、Tag 与 History 的产品行为。 | W |
| 审阅分享职责 | domain | Playlist 链接、下载控制和时间码反馈。 | W |
| 导出交付职责 | runtime | 按范围与输出设置交付视频、声音、静帧或工程。 | W |
| 云端执行职责 | runtime | 承接已经提交的 Agent 工作,页面关闭后可继续。 | W |
| 生成适配职责 | runtime | 可能协调媒体生成及积分审批,向编辑任务提供结果。 | I |
增长与运营机制
复刻状态
| 能力 | 状态 | 依据 |
|---|---|---|
| 工作区条、登录框、新建项目框 | 已验证 | 令牌生效;弹窗背景 #212121、主按钮白色 |
| Agent 对话:新建项目与会话、自动选默认模型、发送收回复 | 已验证 | 真实 Maa,收到回复 |
| 停止回复 | 已验证 | maa_run_stop_actions=terminal_observed,run=cancelled |
| Agent 工作台与编辑器布局 | 已加载 | 沿用早期静态页 |
| 生成视频(报价→批准→成片) | 已验证 | 测试部署 119.23.106.60:8103 上真实生成:Seedance 2.0 Mini 5 秒,报价 3 积分,批准后任务成功、产出 MP4(接口级验证;素材页展示未逐项核对) |
agent-integration/apps-production-brand-v14/invideo/candidate-8875-unified-v22.html复刻的架构 七个品牌相同,展开查看
flowchart LR U[浏览器] -->|静态页| FE[品牌前端<br/>令牌 + 通用层 + 运行时脚本] FE -->|/v1/* Cookie + CSRF| BFF[BFF 业务服务 Go] BFF --> MY[(MySQL<br/>共享身份库 + 品牌库)] BFF -->|会话 / 消息 / 事件| MAA[Maa Agent] BFF -->|任务| WK[媒体 worker] WK -->|submit_video| GW[模型网关] GW --> MOD[视频模型] MAA --> GW BFF --> OBJ[(素材 / 导出存储)]
?profile=invideo 区分品牌)。品牌差异在前端:令牌(颜色、圆角、字体)、入口与页面结构。invideo AI · Agent 交互过程
竞品里观察到的
NOT_RUN_COST_GATE 从当前官网仅导航一次Start Creating,实际到注册/登录入口,未到Agent工作台。现行官方说明包含回复对话费用,不满足零积分条件,未发送。
- 当前官网主视觉为agentic video editor,套餐能力可见Agent Two名称。
- Start Creating跳转/signup,页面有Email address、Continue、Log in、Google/Apple入口。
- 未填写邮箱、未注册、未提交登录、未创建项目或发消息。
费用与准入
| 项 | 值 |
|---|---|
| selected_model | not_reached |
| observed_price | 当前工作台未到达;官方说明每次回复可包含对话与媒体积分费用。 |
| available_credits | not_checked_current_agent |
| exact_per_turn_cost | unknown |
| approval | 用户仅授权明确消耗0积分的Agent文字对话,不得花现有积分。 |
| free_only_requirement | true |
| zero_credit_cost_confirmed | false |
| action_taken | no_send |
| reason | 当前产品先遇到登录入口;官方免费套餐为有限credits,不能证明文字回复免费。Always Ask只控制生成批准,不豁免对话计费。 |
| evidence_refs | ["IV-COST-W1", "IV-FREE-W2"] |
竞品公开的调用流程
| 步骤 | 调用关系 | 操作 | 证据 |
|---|---|---|---|
| 打开项目 | 编辑用户 → 项目入口 | 进入 Project,再从 Notebook 的 Agent Chat 找到目标 Timeline。 | W |
| 准备素材 | 编辑用户 → 项目入口 | 上传媒体并用文件夹整理;等待上传完成后再把它用于 Agent 工作。 | W |
| 提交剪辑目标 | 编辑用户 → Agent编排 | 描述片段、长度和保留内容;项目中的 Agent 可共享创作背景并接收各自任务。 | W |
| 检查Agent结果 | Agent编排 → 编辑状态 | Agent 更新剪辑后,用户在 Monitor/Timeline 检查可继续手改的结果;此处候选指待检查的结果。 | W |
| 人工细调 | 编辑用户 → 编辑状态 | 手改剪辑,或把局部修订要求发回 Agent;人工与 Agent 面向同一 Timeline。 | W |
| 保留方向与历史 | 编辑用户 → 编辑状态 | 用 Branch 尝试替代剪辑,Tag 标记阶段,History 返回之前状态。 | W |
| 发送审阅版本 | 编辑用户 → 交付模块 | 选择 Timeline 建 Playlist 审阅链接,设置观看/下载权限并收集时间码反馈。 | W |
| 导出作品 | 编辑用户 → 交付模块 | 选择范围和参数导出视频、音频、静帧或工程,再检查最终文件。 | W |
| 可选外部接入 | 外部Agent → 项目入口 | 经 https://mcp.invideo.io/mcp 授权后使用 Editor 能力;没有调用任何工具或取得参数 schema。 | A |
在本品牌复刻上的测试结果
| 能力 | 状态 | 依据 |
|---|---|---|
| Agent 对话:新建项目与会话、自动选默认模型、发送收回复 | 已验证 | 真实 Maa,收到回复 |
| 停止回复 | 已验证 | maa_run_stop_actions=terminal_observed,run=cancelled |
| Agent 工作台与编辑器布局 | 已加载 | 沿用早期静态页 |
| 生成视频(报价→批准→成片) | 已验证 | 测试部署 119.23.106.60:8103 上真实生成:Seedance 2.0 Mini 5 秒,报价 3 积分,批准后任务成功、产出 MP4(接口级验证;素材页展示未逐项核对) |
复刻里的 Agent 交互设计(时序图、状态机、规则) 七个品牌相同,展开查看
sequenceDiagram
autonumber
participant B as 浏览器
participant S as BFF
participant DB as MySQL
participant M as Maa Agent
participant W as 媒体 worker
participant G as 模型网关
B->>S: POST /projects, /conversations
B->>S: POST maa/binding
S->>DB: maa_bindings dispatching
S->>M: 创建原生会话
M-->>S: native_cid
S->>DB: maa_bindings bound
B->>S: POST maa/messages {client_action_id, content}
S->>DB: maa_message_actions 幂等回执
S-->>B: 202 + run_id
S->>M: 提交消息
S->>DB: maa_runs queued 到 running
loop 事件游标
B->>S: GET runs/{id}/events
S-->>B: assistant.delta / assistant.message
end
M-->>S: run.completed
S->>DB: 记录助手内容 SHA-256
B->>S: POST media/requests/from-maa {source_run_id, sha256}
S-->>B: 报价 + 有效期 + quote_sha256
B->>S: POST approve {client_approval_id, request_sha256, quote_sha256}
S->>DB: 冻结积分 + 建任务
W->>G: submit_video
G-->>W: 视频
W->>DB: 产出入库 + 扣费
B->>S: GET media/jobs/{id}Run 状态机
stateDiagram-v2 [*] --> queued: POST maa/messages 202 queued --> running running --> waiting_interaction: 需要澄清卡 waiting_interaction --> running: respondInteraction running --> completed running --> failed running --> cancelled: stopRun waiting_interaction --> cancelled completed --> [*] failed --> [*] cancelled --> [*]
媒体任务状态机
stateDiagram-v2 [*] --> quoted quoted --> expired: 约 5 分钟 quoted --> approved: approve approved --> held: 冻结积分 held --> queued queued --> running: worker 领取 running --> succeeded: 产出入库 succeeded --> captured: 扣费确认 running --> failed failed --> 待核对: 供应商已受理后失败,冻结保留,界面写「费用待核对」
交互规则
| 环节 | 规则 | 落库 |
|---|---|---|
| 绑定会话 | bindMaa 传 agent_model 或 use_default;先 dispatching,拿到原生会话号后才 bound(约束保证二者一致) | maa_bindings |
| 发消息 | client_action_id 幂等;返回 202 + run_id;同一个动作 ID 内容不同返回 409 | maa_message_actions, maa_runs |
| 事件 | 按 seq 游标读取;服务端先清洗路径、内部地址和令牌再公开 | maa_runs.last_event_seq |
| 完成证据 | 完成时记录助手内容的两份 SHA-256 与字节数 | maa_runs |
| 澄清卡(HITL) | Run 进入 waiting_interaction;respondInteraction 带 card_sha256;不能恢复两次 | maa_interactions, maa_interaction_actions |
| 停止 | stopRun 幂等,回执只说「已观测到终态」;对话里保留「已停止回复」 | maa_run_stop_actions |
| 切换模型 | 必须带 expected_revision;有未决切换时拒绝发新消息 | maa_model_change_actions |
| 生成视频 | from-maa → 报价 → 批准 → 冻结 → worker → 入库 → 扣费;批准带请求哈希与报价哈希 | studio_media_*, 积分账本 |
| 报价过期 | 批准被拒,不建任务不扣费;界面提示重新报价 | studio_media_requests.expires_at |
| 失败后的积分 | 供应商已受理后失败:冻结保留,界面写「费用待核对」,不自动释放;本部署的账本里还没出现过释放分录(12 笔冻结、8 笔扣费、其余 4 笔仍冻结) | studio_credit_ledger_entries |
| 会话过期 | 每 8 秒检查登录状态;失效时横幅提示,登录后恢复 | — |
invideo AI · ER 图
品牌库 studio_profile_invideo:24 张表、34 个真实外键、66 个检查约束、22 个触发器。图由实际表结构生成,箭头从父表指向子表。品牌库与共享身份库之间的 owner_id、asset_id 靠应用层归属检查,不画成外键。
共 61 条关系:一对多 37 条,一对一 10 条,一对多(父可选) 10 条,一对一(父可选) 4 条;多对多 2 组(经关联表)。
用户与登录 素材 积分账本 支付与订阅 模型目录 项目与会话 画布 · 时间轴 · 导出 Agent 交互 生成 · 媒体 · 交付
基数标注(线上的文字,箭头从父表指向子表):1:N 一对多,子表外键必填;0..1:N 一对多,但外键可空,所以父是可选的;1:1 一对一,子表外键上有唯一键;0..1:1 一对一且父可选。红色粗双向线 = N:M 多对多,经带 ⇄ 的关联表(它的主键就是两个外键)。实线 = 数据库真实外键;灰色虚线 = 跨库关系(两个库之间数据库无法建外键,由应用层检查);橙色粗框与粗线 = Agent 交互相关。每张表都带 owner_id(指向用户),为了图清楚没有逐条画线。
全景图:全部实体与关系
默认缩放到页面宽度,先看整体结构;点一下图切换到原始大小(看清表名,在框内上下左右滚动),再点一下缩回。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":26,"rankSpacing":80}}}%%
flowchart LR
subgraph sg_i_user["用户与登录"]
direction TB
t_studio_users["users"]
t_studio_sessions["sessions"]
end
subgraph sg_i_asset["素材"]
direction TB
t_studio_assets["assets"]
end
subgraph sg_i_credit["积分账本"]
direction TB
t_studio_credit_accounts["credit_accounts"]
t_studio_credit_lots["credit_lots"]
t_studio_credit_authorizations["credit_authorizations"]
t_studio_credit_authorization_allocations["⇄ credit_authorization_allocations"]
t_studio_credit_ledger_entries["credit_ledger_entries"]
t_studio_credit_plan_versions["credit_plan_versions"]
t_studio_billing_cycles["billing_cycles"]
end
subgraph sg_i_pay["支付与订阅"]
direction TB
t_studio_payment_orders["payment_orders"]
t_studio_payment_events["payment_events"]
t_studio_subscriptions["subscriptions"]
end
subgraph sg_i_model["模型目录"]
direction TB
t_studio_media_models["media_models"]
t_studio_media_model_versions["media_model_versions"]
end
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_canvas["画布 · 时间轴 · 导出"]
direction TB
t_studio_video_documents["video_documents"]
t_studio_canvases["canvases"]
t_studio_canvas_revisions["canvas_revisions"]
t_studio_timeline_revisions["timeline_revisions"]
t_studio_export_jobs["export_jobs"]
t_studio_project_asset_refs["⇄ project_asset_refs"]
end
subgraph sg_agent["⭕ Agent 交互"]
direction TB
t_maa_bindings["maa_bindings"]
t_maa_runs["maa_runs"]
t_maa_message_actions["maa_message_actions"]
t_maa_interactions["maa_interactions"]
t_maa_interaction_actions["maa_interaction_actions"]
t_maa_model_change_actions["maa_model_change_actions"]
t_maa_run_stop_actions["maa_run_stop_actions"]
end
subgraph sg_media["生成 · 媒体 · 交付"]
direction TB
t_studio_media_requests["media_requests"]
t_studio_media_jobs["media_jobs"]
t_studio_media_submission_attempts["media_submission_attempts"]
t_studio_media_outputs["media_outputs"]
t_generation_jobs["gen_jobs"]
t_generation_reservations["gen_reservations"]
t_generation_deliveries["gen_deliveries"]
t_generation_development_budgets["gen_development_budgets"]
t_studio_credit_recovery_intents["credit_recovery_intents"]
end
t_studio_users -->|"1:N"| t_studio_assets
t_studio_payment_orders -->|"1:1"| t_studio_billing_cycles
t_studio_subscriptions -->|"1:N"| t_studio_billing_cycles
t_studio_users -->|"1:1"| t_studio_credit_accounts
t_studio_credit_authorizations -->|"1:N"| t_studio_credit_authorization_allocations
t_studio_credit_lots -->|"1:N"| t_studio_credit_authorization_allocations
t_studio_credit_accounts -->|"1:N"| t_studio_credit_authorizations
t_studio_credit_authorization_allocations -->|"0..1:N"| t_studio_credit_ledger_entries
t_studio_credit_authorizations -->|"0..1:N"| t_studio_credit_ledger_entries
t_studio_credit_lots -->|"1:N"| t_studio_credit_ledger_entries
t_studio_credit_accounts -->|"1:N"| t_studio_credit_lots
t_studio_billing_cycles -->|"0..1:1"| t_studio_credit_lots
t_studio_payment_orders -->|"0..1:1"| t_studio_credit_lots
t_studio_media_models -->|"1:N"| t_studio_media_model_versions
t_studio_media_model_versions -->|"0..1:1"| t_studio_media_models
t_studio_payment_orders -->|"0..1:N"| t_studio_payment_events
t_studio_subscriptions -->|"0..1:N"| t_studio_payment_events
t_studio_users -->|"1:N"| t_studio_payment_events
t_studio_credit_plan_versions -->|"1:N"| t_studio_payment_orders
t_studio_users -->|"1:N"| t_studio_payment_orders
t_studio_users -->|"1:N"| t_studio_sessions
t_studio_credit_plan_versions -->|"1:N"| t_studio_subscriptions
t_studio_users -->|"1:N"| t_studio_subscriptions
t_generation_jobs -->|"1:1"| t_generation_deliveries
t_studio_projects -->|"1:N"| t_generation_deliveries
t_studio_conversations -->|"1:N"| t_generation_deliveries
t_generation_development_budgets -->|"1:N"| t_generation_jobs
t_studio_projects -->|"1:N"| t_generation_jobs
t_studio_conversations -->|"1:N"| t_generation_jobs
t_generation_jobs -->|"1:1"| t_generation_reservations
t_studio_conversations -->|"1:1"| t_maa_bindings
t_maa_model_change_actions -->|"0..1:1"| t_maa_bindings
t_maa_interactions -->|"1:1"| t_maa_interaction_actions
t_maa_runs -->|"1:N"| t_maa_interactions
t_maa_bindings -->|"1:N"| t_maa_message_actions
t_maa_runs -->|"0..1:N"| t_maa_message_actions
t_maa_bindings -->|"1:N"| t_maa_model_change_actions
t_maa_runs -->|"1:1"| t_maa_run_stop_actions
t_maa_bindings -->|"1:N"| t_maa_runs
t_studio_canvases -->|"1:N"| t_studio_canvas_revisions
t_studio_canvas_revisions -->|"0..1:N"| t_studio_canvas_revisions
t_studio_projects -->|"1:1"| t_studio_canvases
t_studio_projects -->|"1:N"| t_studio_conversations
t_studio_media_jobs -->|"1:N"| t_studio_credit_recovery_intents
t_studio_projects -->|"1:N"| t_studio_export_jobs
t_studio_media_requests -->|"1:1"| t_studio_media_jobs
t_studio_media_jobs -->|"1:N"| t_studio_media_outputs
t_studio_conversations -->|"1:N"| t_studio_media_requests
t_maa_runs -->|"0..1:N"| t_studio_media_requests
t_studio_media_jobs -->|"1:N"| t_studio_media_submission_attempts
t_studio_projects -->|"1:N"| t_studio_project_asset_refs
t_studio_video_documents -->|"1:N"| t_studio_timeline_revisions
t_studio_timeline_revisions -->|"0..1:N"| t_studio_timeline_revisions
t_studio_projects -->|"1:1"| t_studio_video_documents
t_studio_assets -.->|"1:N"| t_studio_project_asset_refs
t_studio_assets -.->|"1:N"| t_studio_media_outputs
t_studio_assets -.->|"1:N"| t_generation_deliveries
t_studio_media_model_versions -.->|"1:N"| t_studio_media_requests
t_studio_media_models -.->|"1:N"| t_studio_media_requests
t_studio_credit_authorizations -.->|"0..1:N"| t_studio_media_jobs
t_studio_credit_authorizations -.->|"0..1:N"| t_studio_credit_recovery_intents
t_studio_credit_authorizations <-.->|"N:M · 经 credit_authorization_allocations"| t_studio_credit_lots
t_studio_projects <-.->|"N:M · 经 project_asset_refs"| t_studio_assets
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_users,t_studio_sessions user
class t_studio_assets asset
class t_studio_credit_accounts,t_studio_credit_lots,t_studio_credit_authorizations,t_studio_credit_authorization_allocations,t_studio_credit_ledger_entries,t_studio_credit_plan_versions,t_studio_billing_cycles credit
class t_studio_payment_orders,t_studio_payment_events,t_studio_subscriptions pay
class t_studio_media_models,t_studio_media_model_versions model
class t_studio_projects,t_studio_conversations project
class t_studio_video_documents,t_studio_canvases,t_studio_canvas_revisions,t_studio_timeline_revisions,t_studio_export_jobs,t_studio_project_asset_refs canvas
class t_maa_bindings,t_maa_runs,t_maa_message_actions,t_maa_interactions,t_maa_interaction_actions,t_maa_model_change_actions,t_maa_run_stop_actions agent
class t_studio_media_requests,t_studio_media_jobs,t_studio_media_submission_attempts,t_studio_media_outputs,t_generation_jobs,t_generation_reservations,t_generation_deliveries,t_generation_development_budgets,t_studio_credit_recovery_intents media
class t_studio_credit_authorization_allocations,t_studio_project_asset_refs junction
style sg_i_user fill:none,stroke:#6b7280,stroke-width:1px,stroke-dasharray:5 4
style sg_i_asset fill:none,stroke:#06b6d4,stroke-width:1px,stroke-dasharray:5 4
style sg_i_credit fill:none,stroke:#eab308,stroke-width:1px,stroke-dasharray:5 4
style sg_i_pay fill:none,stroke:#ec4899,stroke-width:1px,stroke-dasharray:5 4
style sg_i_model fill:none,stroke:#6366f1,stroke-width:1px,stroke-dasharray:5 4
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_canvas fill:none,stroke:#3b82f6,stroke-width:1px
style sg_agent fill:#fff7ed,stroke:#f97316,stroke-width:4px
style sg_media fill:none,stroke:#22c55e,stroke-width:1px
linkStyle 30,31,32,33,34,35,36,37,38,48 stroke:#f97316,stroke-width:2.5px
linkStyle 54,55,56,57,58,59,60 stroke:#64748b,stroke-width:1.5px,stroke-dasharray:4 3
linkStyle 61,62 stroke:#dc2626,stroke-width:3px多对多(N:M)
数据库里没有“多对多”这种列,它总是靠一张关联表表达。下面这几张表的主键由两个外键组成,所以它们两端是多对多:
| 多对多的两端 | 关联表 | 关联表的主键 / 唯一键 |
|---|---|---|
studio_credit_authorizations ⇄ studio_credit_lots | studio_credit_authorization_allocations | owner_id, authorization_id, lot_id |
studio_projects ⇄ studio_assets | studio_project_asset_refs | project_id, asset_id |
Agent 交互相关(圈出来)
绑定 → Run → 消息 / 澄清卡 / 切换模型 / 停止,每个动作一张回执表;线上是“外键列 · 基数”。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":40,"rankSpacing":90}}}%%
flowchart LR
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_agent["⭕ Agent 交互"]
direction TB
t_maa_bindings["maa_bindings"]
t_maa_runs["maa_runs"]
t_maa_message_actions["maa_message_actions"]
t_maa_interactions["maa_interactions"]
t_maa_interaction_actions["maa_interaction_actions"]
t_maa_model_change_actions["maa_model_change_actions"]
t_maa_run_stop_actions["maa_run_stop_actions"]
end
t_studio_conversations -->|"conversation_id · 1:1"| t_maa_bindings
t_maa_model_change_actions -->|"pending_model_change_id · 0..1:1"| t_maa_bindings
t_maa_interactions -->|"interaction_id · 1:1"| t_maa_interaction_actions
t_maa_runs -->|"public_run_id · 1:N"| t_maa_interactions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_message_actions
t_maa_runs -->|"public_run_id · 0..1:N"| t_maa_message_actions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_model_change_actions
t_maa_runs -->|"public_run_id · 1:1"| t_maa_run_stop_actions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_runs
t_studio_projects -->|"project_id · 1:N"| t_studio_conversations
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_projects,t_studio_conversations project
class t_maa_bindings,t_maa_runs,t_maa_message_actions,t_maa_interactions,t_maa_interaction_actions,t_maa_model_change_actions,t_maa_run_stop_actions agent
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_agent fill:#fff7ed,stroke:#f97316,stroke-width:4px
linkStyle 0,1,2,3,4,5,6,7,8 stroke:#f97316,stroke-width:2.5px画布与时间轴
项目下是一份视频文档,画布、画布版本、时间线版本和导出都挂在这份文档上;素材放在共享身份库,项目只记引用,项目与素材是多对多,经 project_asset_refs。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":40,"rankSpacing":90}}}%%
flowchart LR
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_canvas["画布 · 时间轴 · 导出"]
direction TB
t_studio_video_documents["video_documents"]
t_studio_canvases["canvases"]
t_studio_canvas_revisions["canvas_revisions"]
t_studio_timeline_revisions["timeline_revisions"]
t_studio_export_jobs["export_jobs"]
t_studio_project_asset_refs["⇄ project_asset_refs"]
end
subgraph sg_asset["素材(共享身份库)"]
direction TB
t_studio_assets["assets"]
end
t_studio_canvases -->|"project_id · 1:N"| t_studio_canvas_revisions
t_studio_canvas_revisions -->|"restored_from_revision · 0..1:N"| t_studio_canvas_revisions
t_studio_projects -->|"project_id · 1:1"| t_studio_canvases
t_studio_projects -->|"project_id · 1:N"| t_studio_conversations
t_studio_projects -->|"project_id · 1:N"| t_studio_export_jobs
t_studio_projects -->|"project_id · 1:N"| t_studio_project_asset_refs
t_studio_video_documents -->|"project_id · 1:N"| t_studio_timeline_revisions
t_studio_timeline_revisions -->|"restored_from_revision · 0..1:N"| t_studio_timeline_revisions
t_studio_projects -->|"project_id · 1:1"| t_studio_video_documents
t_studio_assets -.->|"asset_id · 1:N"| t_studio_project_asset_refs
t_studio_projects <-.->|"N:M · 经 project_asset_refs"| t_studio_assets
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_projects,t_studio_conversations project
class t_studio_video_documents,t_studio_canvases,t_studio_canvas_revisions,t_studio_timeline_revisions,t_studio_export_jobs,t_studio_project_asset_refs canvas
class t_studio_assets asset
class t_studio_project_asset_refs junction
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_canvas fill:none,stroke:#3b82f6,stroke-width:1px
style sg_asset fill:none,stroke:#06b6d4,stroke-width:1px
linkStyle 9 stroke:#64748b,stroke-width:1.5px,stroke-dasharray:4 3
linkStyle 10 stroke:#dc2626,stroke-width:3px关系清单 逐条 61 条,含基数
| 父表 | 子表 | 外键列(子表里) | 基数 | 约束 | 域 |
|---|---|---|---|---|---|
generation_jobs | generation_deliveries | job_id | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_assets | generation_deliveries | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 生成 · 媒体 · 交付 |
studio_conversations | generation_deliveries | owner_id, project_id, session_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_projects | generation_deliveries | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
generation_development_budgets | generation_jobs | owner_id, budget_id | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_conversations | generation_jobs | owner_id, project_id, session_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_projects | generation_jobs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
generation_jobs | generation_reservations | job_id, budget_id, owner_id | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
maa_model_change_actions | maa_bindings | owner_id, project_id, conversation_id, id, pending_model_change_id | 0..1:1 一对一(父可选) | DB 外键 | Agent 交互 → Agent 交互 |
studio_conversations | maa_bindings | owner_id, project_id, conversation_id | 1:1 一对一 | DB 外键 | 项目与会话 → Agent 交互 |
maa_interactions | maa_interaction_actions | owner_id, project_id, conversation_id, binding_id, public_run_id, interaction_id | 1:1 一对一 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_interactions | owner_id, project_id, conversation_id, binding_id, public_run_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_message_actions | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_message_actions | owner_id, project_id, conversation_id, binding_id, public_run_id | 0..1:N 一对多(父可选) | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_model_change_actions | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_run_stop_actions | owner_id, project_id, conversation_id, binding_id, public_run_id | 1:1 一对一 | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_runs | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
studio_users | studio_assets | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 素材 |
studio_payment_orders | studio_billing_cycles | owner_id, payment_order_id, plan_version_id | 1:1 一对一 | DB 外键 | 支付与订阅 → 积分账本 |
studio_subscriptions | studio_billing_cycles | owner_id, subscription_id, provider_key, provider_account | 1:N 一对多 | DB 外键 | 支付与订阅 → 积分账本 |
studio_canvas_revisions | studio_canvas_revisions | owner_id, project_id, kind, restored_from_revision | 0..1:N 一对多(父可选) | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_canvases | studio_canvas_revisions | owner_id, project_id | 1:N 一对多 | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_projects | studio_canvases | owner_id, project_id | 1:1 一对一 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_projects | studio_conversations | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 项目与会话 |
studio_users | studio_credit_accounts | owner_id | 1:1 一对一 | DB 外键 | 用户与登录 → 积分账本 |
studio_credit_authorizations | studio_credit_authorization_allocations | owner_id, authorization_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_lots | studio_credit_authorization_allocations | owner_id, lot_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_accounts | studio_credit_authorizations | owner_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_authorization_allocations | studio_credit_ledger_entries | owner_id, authorization_id, lot_id | 0..1:N 一对多(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_authorizations | studio_credit_ledger_entries | owner_id, authorization_id | 0..1:N 一对多(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_lots | studio_credit_ledger_entries | owner_id, lot_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_billing_cycles | studio_credit_lots | owner_id, source_cycle_id | 0..1:1 一对一(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_accounts | studio_credit_lots | owner_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_payment_orders | studio_credit_lots | owner_id, source_order_id | 0..1:1 一对一(父可选) | DB 外键 | 支付与订阅 → 积分账本 |
studio_credit_authorizations | studio_credit_recovery_intents | authorization_id | 0..1:N 一对多(父可选) | 跨库(应用层检查) | 积分账本 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_credit_recovery_intents | owner_id, project_id, conversation_id, job_id, request_sha256 | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_projects | studio_export_jobs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_credit_authorizations | studio_media_jobs | credit_authorization_id | 0..1:N 一对多(父可选) | 跨库(应用层检查) | 积分账本 → 生成 · 媒体 · 交付 |
studio_media_requests | studio_media_jobs | owner_id, project_id, conversation_id, request_id, request_sha256, quote_sha256 | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_media_models | studio_media_model_versions | model_id | 1:N 一对多 | DB 外键 | 模型目录 → 模型目录 |
studio_media_model_versions | studio_media_models | id, published_version_id | 0..1:1 一对一(父可选) | DB 外键 | 模型目录 → 模型目录 |
studio_assets | studio_media_outputs | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_media_outputs | owner_id, project_id, conversation_id, job_id | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
maa_runs | studio_media_requests | owner_id, project_id, conversation_id, source_binding_id, source_run_id | 0..1:N 一对多(父可选) | DB 外键 | Agent 交互 → 生成 · 媒体 · 交付 |
studio_conversations | studio_media_requests | owner_id, project_id, conversation_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_media_model_versions | studio_media_requests | model_version_id | 1:N 一对多 | 跨库(应用层检查) | 模型目录 → 生成 · 媒体 · 交付 |
studio_media_models | studio_media_requests | model_id | 1:N 一对多 | 跨库(应用层检查) | 模型目录 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_media_submission_attempts | owner_id, project_id, conversation_id, job_id, request_sha256 | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_payment_orders | studio_payment_events | owner_id, order_id, provider_key, provider_account | 0..1:N 一对多(父可选) | DB 外键 | 支付与订阅 → 支付与订阅 |
studio_subscriptions | studio_payment_events | owner_id, subscription_id, provider_key, provider_account | 0..1:N 一对多(父可选) | DB 外键 | 支付与订阅 → 支付与订阅 |
studio_users | studio_payment_events | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_credit_plan_versions | studio_payment_orders | plan_version_id | 1:N 一对多 | DB 外键 | 积分账本 → 支付与订阅 |
studio_users | studio_payment_orders | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_assets | studio_project_asset_refs | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 画布 · 时间轴 · 导出 |
studio_projects | studio_project_asset_refs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_users | studio_sessions | user_id | 1:N 一对多 | DB 外键 | 用户与登录 → 用户与登录 |
studio_credit_plan_versions | studio_subscriptions | plan_version_id | 1:N 一对多 | DB 外键 | 积分账本 → 支付与订阅 |
studio_users | studio_subscriptions | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_timeline_revisions | studio_timeline_revisions | owner_id, project_id, kind, restored_from_revision | 0..1:N 一对多(父可选) | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_video_documents | studio_timeline_revisions | owner_id, project_id | 1:N 一对多 | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_projects | studio_video_documents | owner_id, project_id | 1:1 一对一 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
完整 ER:39 张表的全部列,带主键 / 外键与基数符号(鸦脚)
erDiagram
studio_assets {
CHAR id PK
CHAR owner_id FK
CHAR sha256
JSON metadata_json
VARCHAR storage_key
DATETIME created_at
VARCHAR publication_state
}
studio_billing_cycles {
CHAR id PK
CHAR owner_id FK
CHAR subscription_id FK
CHAR plan_version_id FK
CHAR payment_order_id FK
VARCHAR provider_key FK
VARCHAR provider_account FK
VARCHAR provider_invoice_id
DATETIME period_start
DATETIME period_end
BIGINT_UNSIGNED grant_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
VARCHAR state
CHAR paid_evidence_sha256
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_accounts {
CHAR owner_id PK
VARCHAR unit
VARCHAR status
BIGINT_UNSIGNED revision
DATETIME updated_at
}
studio_credit_authorization_allocations {
CHAR owner_id FK
CHAR authorization_id PK
CHAR lot_id PK
BIGINT_UNSIGNED allocated_credits
DATETIME created_at
}
studio_credit_authorizations {
CHAR id PK
CHAR owner_id FK
VARCHAR profile
CHAR project_id
CHAR conversation_id
CHAR job_id
CHAR request_id
CHAR request_sha256
CHAR quote_sha256
BIGINT_UNSIGNED credits
DATETIME expires_at
MEDIUMBLOB reservation_bytes
CHAR reservation_sha256
MEDIUMBLOB policy_bytes
CHAR policy_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_ledger_entries {
CHAR id PK
CHAR owner_id FK
CHAR lot_id FK
CHAR authorization_id FK
VARCHAR operation_key
VARCHAR kind
BIGINT grant_delta
BIGINT held_delta
BIGINT captured_delta
MEDIUMBLOB facts_bytes
CHAR facts_sha256
DATETIME created_at
}
studio_credit_lots {
CHAR id PK
CHAR owner_id FK
BIGINT_UNSIGNED grant_credits
BIGINT_UNSIGNED held_credits
BIGINT_UNSIGNED captured_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
CHAR source_order_id FK
CHAR source_cycle_id FK
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_plan_versions {
CHAR id PK
VARCHAR plan_key
VARCHAR version_key
VARCHAR kind
BIGINT_UNSIGNED price_minor
CHAR currency
BIGINT_UNSIGNED grant_credits
INT_UNSIGNED credit_validity_seconds
INT_UNSIGNED billing_interval_months
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
DATETIME published_at
DATETIME retired_at
}
studio_media_model_versions {
CHAR id PK
CHAR model_id FK
VARCHAR version_key
MEDIUMBLOB config_bytes
CHAR config_sha256
DATETIME published_at
}
studio_media_models {
CHAR id PK
VARCHAR model_key
VARCHAR kind
VARCHAR display_name
VARCHAR status
CHAR published_version_id FK
BIGINT_UNSIGNED revision
DATETIME updated_at
}
studio_payment_events {
CHAR id PK
CHAR owner_id FK
VARCHAR provider_key FK
VARCHAR provider_account FK
VARCHAR provider_event_id
CHAR order_id FK
CHAR subscription_id FK
MEDIUMBLOB body_bytes
CHAR body_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_payment_orders {
CHAR id PK
CHAR owner_id FK
CHAR client_action_id
CHAR plan_version_id FK
BIGINT_UNSIGNED price_minor
CHAR currency
BIGINT_UNSIGNED grant_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
VARCHAR provider_key
VARCHAR provider_account
VARCHAR provider_idempotency_key
VARCHAR provider_order_id
VARCHAR state
CHAR paid_evidence_sha256
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_sessions {
CHAR token_hash PK
CHAR user_id FK
DATETIME created_at
DATETIME expires_at
DATETIME revoked_at
}
studio_subscriptions {
CHAR id PK
CHAR owner_id FK
VARCHAR provider_key
VARCHAR provider_account
VARCHAR provider_subscription_id
CHAR plan_version_id FK
VARCHAR state
DATETIME period_start
DATETIME period_end
TINYINT cancel_at_period_end
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_users {
CHAR id PK
VARCHAR email
VARBINARY password_hash
TINYINT enabled
DATETIME created_at
}
generation_deliveries {
CHAR job_id PK
CHAR owner_id FK
CHAR project_id FK
CHAR session_id FK
CHAR asset_id FK
CHAR request_sha256
CHAR maa_source_sha256
CHAR provider_source_sha256
VARCHAR model
VARCHAR tool_name
CHAR input_sha256
JSON metadata_json
DATETIME created_at
}
generation_development_budgets {
CHAR id PK
CHAR owner_id
VARCHAR policy_version
BIGINT_UNSIGNED credits_limit
BIGINT_UNSIGNED credits_reserved
INT_UNSIGNED calls_limit
INT_UNSIGNED calls_reserved
DATETIME expires_at
}
generation_jobs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR session_id FK
CHAR native_conversation_id
CHAR native_run_id
CHAR source_sha256
CHAR budget_id FK
MEDIUMBLOB request_bytes
CHAR request_sha256
BIGINT_UNSIGNED credits
DATETIME expires_at
VARCHAR status
INT_UNSIGNED attempts
MEDIUMBLOB result_bytes
DATETIME updated_at
}
generation_reservations {
CHAR job_id PK
CHAR budget_id FK
CHAR owner_id FK
BIGINT_UNSIGNED credits
INT_UNSIGNED calls
VARCHAR status
}
maa_bindings {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR provider
VARCHAR model_name
VARCHAR status
VARCHAR native_cid
DATETIME created_at
BIGINT_UNSIGNED model_revision
CHAR pending_model_change_id FK
}
maa_interaction_actions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR interaction_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_iid
CHAR client_action_id
CHAR card_sha256
CHAR request_sha256
CHAR content_sha256
VARCHAR response_action
JSON values_payload
VARCHAR status
DATETIME created_at
}
maa_interactions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_iid
CHAR card_sha256
JSON card_payload
DATETIME created_at
}
maa_message_actions {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR client_action_id
CHAR request_sha256
MEDIUMTEXT content
VARCHAR status
CHAR public_run_id FK
CHAR proposed_run_id
DATETIME created_at
}
maa_model_change_actions {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_cid
CHAR client_action_id
CHAR request_sha256
CHAR native_request_sha256
BIGINT_UNSIGNED expected_revision
VARCHAR from_provider
VARCHAR from_model_name
VARCHAR target_provider
VARCHAR target_model_name
VARCHAR status
BIGINT_UNSIGNED dispatch_attempt
JSON receipt_payload
DATETIME created_at
DATETIME updated_at
}
maa_run_stop_actions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_cid
VARCHAR native_rid
CHAR client_action_id
CHAR request_sha256
VARCHAR stop_action
VARCHAR status
BIGINT_UNSIGNED attempt
VARCHAR terminal_run_status
DATETIME created_at
DATETIME updated_at
}
maa_runs {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_rid
VARCHAR status
DATETIME created_at
CHAR native_assistant_sha256
CHAR public_assistant_sha256
BIGINT_UNSIGNED native_assistant_bytes
BIGINT_UNSIGNED assistant_event_seq
BIGINT_UNSIGNED last_event_seq
}
studio_canvas_revisions {
CHAR owner_id PK
CHAR project_id PK
VARCHAR kind PK
BIGINT_UNSIGNED revision PK
MEDIUMBLOB state_bytes
CHAR state_sha256
VARCHAR origin
BIGINT_UNSIGNED restored_from_revision FK
DATETIME recorded_at
}
studio_canvases {
CHAR project_id PK
CHAR owner_id FK
BIGINT_UNSIGNED revision
JSON state_json
DATETIME updated_at
}
studio_conversations {
CHAR id PK
CHAR project_id FK
CHAR owner_id FK
VARCHAR title
DATETIME created_at
}
studio_credit_recovery_intents {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
CHAR request_sha256 FK
CHAR quote_sha256
VARCHAR kind
CHAR authorization_id FK
MEDIUMBLOB intent_bytes
CHAR intent_sha256
VARCHAR state
CHAR lease_token_sha256
DATETIME lease_until
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_export_jobs {
CHAR id PK
CHAR project_id FK
CHAR owner_id FK
BIGINT_UNSIGNED document_revision
CHAR input_hash
VARCHAR status
JSON input_json
JSON output_json
VARCHAR error_code
CHAR lease_token_hash
DATETIME lease_until
INT_UNSIGNED attempts
DATETIME created_at
DATETIME updated_at
}
studio_media_jobs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR request_id FK
CHAR request_sha256 FK
CHAR quote_sha256 FK
CHAR client_approval_id
CHAR approval_sha256
CHAR credit_authorization_id FK
VARCHAR authorization_mode
DATETIME authorization_expires_at
VARCHAR status
BIGINT_UNSIGNED revision
CHAR lease_token_sha256
DATETIME lease_until
VARCHAR provider_task_id
CHAR client_cancel_id
CHAR cancel_request_sha256
DATETIME cancel_requested_at
CHAR staged_asset_id
CHAR staged_asset_sha256
DATETIME created_at
DATETIME updated_at
}
studio_media_outputs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
INT_UNSIGNED ordinal
CHAR asset_id FK
CHAR asset_sha256
CHAR asset_metadata_sha256
CHAR provider_result_sha256
DATETIME created_at
}
studio_media_requests {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR client_request_id
CHAR model_id FK
CHAR model_version_id FK
CHAR model_config_sha256
MEDIUMBLOB request_bytes
CHAR request_sha256
MEDIUMBLOB quote_bytes
CHAR quote_sha256
BIGINT_UNSIGNED quoted_credits
DATETIME expires_at
VARCHAR origin
CHAR source_binding_id FK
CHAR source_run_id FK
CHAR source_assistant_sha256
MEDIUMBLOB source_snapshot_bytes
DATETIME created_at
}
studio_media_submission_attempts {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
INT_UNSIGNED attempt_no
CHAR request_sha256 FK
VARCHAR provider_idempotency_key
VARCHAR stage
DATETIME dispatch_started_at
VARCHAR provider_task_id
CHAR receipt_sha256
CHAR terminal_receipt_sha256
CHAR reconciliation_sha256
DATETIME created_at
DATETIME updated_at
}
studio_project_asset_refs {
CHAR project_id PK
CHAR owner_id FK
CHAR asset_id PK
CHAR asset_sha256
CHAR asset_metadata_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
DATETIME detached_at
}
studio_projects {
CHAR id PK
CHAR owner_id
VARCHAR title
DATETIME created_at
}
studio_timeline_revisions {
CHAR owner_id PK
CHAR project_id PK
VARCHAR kind PK
BIGINT_UNSIGNED revision PK
MEDIUMBLOB state_bytes
CHAR state_sha256
VARCHAR origin
BIGINT_UNSIGNED restored_from_revision FK
DATETIME recorded_at
}
studio_video_documents {
CHAR project_id PK
CHAR owner_id FK
BIGINT_UNSIGNED revision
JSON state_json
DATETIME updated_at
}
studio_users ||--o{ studio_assets : "owner_id"
studio_payment_orders ||--o| studio_billing_cycles : "plan_version_id"
studio_subscriptions ||--o{ studio_billing_cycles : "provider_account"
studio_users ||--o| studio_credit_accounts : "owner_id"
studio_credit_authorizations ||--o{ studio_credit_authorization_allocations : "authorization_id"
studio_credit_lots ||--o{ studio_credit_authorization_allocations : "lot_id"
studio_credit_accounts ||--o{ studio_credit_authorizations : "owner_id"
studio_credit_authorization_allocations |o--o{ studio_credit_ledger_entries : "lot_id"
studio_credit_authorizations |o--o{ studio_credit_ledger_entries : "authorization_id"
studio_credit_lots ||--o{ studio_credit_ledger_entries : "lot_id"
studio_credit_accounts ||--o{ studio_credit_lots : "owner_id"
studio_billing_cycles |o--o| studio_credit_lots : "source_cycle_id"
studio_payment_orders |o--o| studio_credit_lots : "source_order_id"
studio_media_models ||--o{ studio_media_model_versions : "model_id"
studio_media_model_versions |o--o| studio_media_models : "published_version_id"
studio_payment_orders |o--o{ studio_payment_events : "provider_account"
studio_subscriptions |o--o{ studio_payment_events : "provider_account"
studio_users ||--o{ studio_payment_events : "owner_id"
studio_credit_plan_versions ||--o{ studio_payment_orders : "plan_version_id"
studio_users ||--o{ studio_payment_orders : "owner_id"
studio_users ||--o{ studio_sessions : "user_id"
studio_credit_plan_versions ||--o{ studio_subscriptions : "plan_version_id"
studio_users ||--o{ studio_subscriptions : "owner_id"
generation_jobs ||--o| generation_deliveries : "job_id"
studio_projects ||--o{ generation_deliveries : "project_id"
studio_conversations ||--o{ generation_deliveries : "session_id"
generation_development_budgets ||--o{ generation_jobs : "budget_id"
studio_projects ||--o{ generation_jobs : "project_id"
studio_conversations ||--o{ generation_jobs : "session_id"
generation_jobs ||--o| generation_reservations : "budget_id"
studio_conversations ||--o| maa_bindings : "conversation_id"
maa_model_change_actions |o--o| maa_bindings : "pending_model_change_id"
maa_interactions ||--o| maa_interaction_actions : "interaction_id"
maa_runs ||--o{ maa_interactions : "public_run_id"
maa_bindings ||--o{ maa_message_actions : "binding_id"
maa_runs |o--o{ maa_message_actions : "public_run_id"
maa_bindings ||--o{ maa_model_change_actions : "binding_id"
maa_runs ||--o| maa_run_stop_actions : "public_run_id"
maa_bindings ||--o{ maa_runs : "binding_id"
studio_canvases ||--o{ studio_canvas_revisions : "project_id"
studio_canvas_revisions |o--o{ studio_canvas_revisions : "restored_from_revision"
studio_projects ||--o| studio_canvases : "project_id"
studio_projects ||--o{ studio_conversations : "project_id"
studio_media_jobs ||--o{ studio_credit_recovery_intents : "job_id"
studio_projects ||--o{ studio_export_jobs : "project_id"
studio_media_requests ||--o| studio_media_jobs : "request_id"
studio_media_jobs ||--o{ studio_media_outputs : "job_id"
studio_conversations ||--o{ studio_media_requests : "conversation_id"
maa_runs |o--o{ studio_media_requests : "source_run_id"
studio_media_jobs ||--o{ studio_media_submission_attempts : "job_id"
studio_projects ||--o{ studio_project_asset_refs : "project_id"
studio_video_documents ||--o{ studio_timeline_revisions : "project_id"
studio_timeline_revisions |o--o{ studio_timeline_revisions : "restored_from_revision"
studio_projects ||--o| studio_video_documents : "project_id"
studio_assets ||--o{ studio_project_asset_refs : "asset_id"
studio_assets ||--o{ studio_media_outputs : "asset_id"
studio_assets ||--o{ generation_deliveries : "asset_id"
studio_media_model_versions ||--o{ studio_media_requests : "model_version_id"
studio_media_models ||--o{ studio_media_requests : "model_id"
studio_credit_authorizations |o--o{ studio_media_jobs : "credit_authorization_id"
studio_credit_authorizations |o--o{ studio_credit_recovery_intents : "authorization_id"自动生成的整体图(按真实表结构,备查)
共享身份库 ER 图
实测验证与设计原因 七个品牌相同,展开查看
实测验证(本机 MySQL 实库)
对照本机真实运行的数据库 studio_profile_invideo 和 studio_platform_identity,逐项核对本页的表、列、关系与说明。18 / 18 项通过。
查看全部核对项
| 核对项 | 结果 |
|---|---|
| 表数 = 发布值 24 | 通过 |
| 列数 = 289 | 通过 |
| 外键数 = 34 | 通过 |
| 检查约束数 = 66 | 通过 |
| 触发器数 = 22 | 通过 |
| 索引数(含主键) = 85 | 通过 |
| 列定义与 pollo 逐列一致 | 通过 |
| 外键与 pollo 完全一致 | 通过 |
| 索引与 pollo 一致 | 通过 |
| 触发器与 pollo 一致 | 通过 |
| 外键 CSV 行数 = 实库外键数 | 通过 |
| mmd 实体 = 实库表 | 通过 |
| svg 标题 24 tables / 34 actual foreign keys = 实库 | 通过 |
| 参考 SQL 表集合与列顺序 = 实库 | 通过 |
| 15 张表 | 通过 |
| 外键 CSV 行数 = 实库外键数 | 通过 |
| svg 标题与实库一致 | 通过 |
| 参考 SQL 表集合与列顺序 = 实库 | 通过 |
实库里的关系是这样的
- 34 个外键里 31 个是复合外键,且都带着 owner_id,其余 3 个是单列外键;22 张子表都带 owner 外键。所以一行数据不可能指向别的用户的项目或会话。
- 删除与更新规则全部是 RESTRICT / NO ACTION,没有任何级联:被引用的行不能被删除。
- 品牌库与共享身份库之间的关系(owner_id、asset_id、model_id + model_version_id)没有数据库外键,靠应用层检查;我们逐表核对了现有数据,没有孤儿。
主动破坏测试(在事务里尝试,全部回滚)
| 尝试 | 数据库的反应 |
|---|---|
| 外键:导出任务.project_id 改成不存在的项目被拒绝 | 拒绝 |
| 复合外键:项目素材引用.project_id 改成别的用户的项目被拒绝(owner 与 project 必须成对) | 拒绝 |
| 触发器:已提交的消息动作不可改写 | 拒绝 |
| 触发器:媒体产出不可改写 | 拒绝 |
| 外键 RESTRICT:被会话引用的项目不能删除 | 拒绝 |
| 复合外键:被引用的会话不能把 owner 改成别人 | 拒绝 |
| 检查约束:Run 状态只能是约定的六个值 | 拒绝 |
| 触发器:账本分录不可修改 | 拒绝 |
| 触发器:账本分录不可删除 | 拒绝 |
invideo AI · 表结构
MySQL 8,字符集 utf8mb4,ID 为 char(36) ascii_bin。点击展开 DDL。
按职责分组
项目与会话 2 张
studio_projects:用户拥有的创作项目studio_conversations:项目内的对话会话
Agent执行与并发控制 7 张
maa_bindings:业务会话与Native Maa会话映射、模型版本与未决操作maa_runs:公开Run映射、状态与原生/公开助手证据摘要maa_message_actions:原消息动作及幂等回执maa_interactions:澄清卡片及Run归属maa_interaction_actions:原卡片回答/取消动作maa_model_change_actions:带预期模型版本的切换动作maa_run_stop_actions:停止原Run的幂等动作与观测终态
画布、时间轴与素材引用 5 张
studio_canvases:项目当前画布文档studio_canvas_revisions:历史画布修订studio_video_documents:项目当前时间轴文档studio_timeline_revisions:历史时间轴修订studio_project_asset_refs:项目对用户级素材的引用;不复制素材所有权
媒体生成、结算恢复与导出 6 张
studio_media_requests:用户输入/Agent来源、报价、批准摘要与准入确认studio_media_jobs:已批准媒体任务及状态机studio_media_submission_attempts:一次提交的任务证据与不确定结果studio_media_outputs:受验证的输出与素材映射studio_credit_recovery_intents:积分结算恢复意图;不是用户钱包全账本studio_export_jobs:时间轴导出队列和发布输出
既有generation兼容路径 22 张
generation_jobs:既有generation任务,不等同新PublicMedia任务generation_reservations:既有任务费用预留generation_development_budgets:既有开发测试预算generation_deliveries:既有生成交付回执owner_id:归属用户;不是允许跨用户查询的参数。model_revision:并发准入版本;数据库默认0不能代替Native权威读回。pending_model_change_id:未决模型切换引用,阻止其他writer绕过。studio_users:用户账号记录;不导出密码哈希或任何业务行studio_sessions:登录会话;这里只公开字段结构,不公开会话值studio_assets:用户级素材元数据与存储键结构,项目仅引用素材IDstudio_media_models:公开媒体模型目录结构studio_media_model_versions:媒体模型不可变版本/计价能力结构studio_subscriptions:订阅状态持久化studio_billing_cycles:订阅账期studio_payment_orders:订单记录studio_payment_events:支付事件幂等记录;不代表已有公开支付路由studio_credit_accounts:用户积分账户studio_credit_lots:积分批次studio_credit_authorizations:费用预留与结算授权studio_credit_authorization_allocations:授权对批次的分配studio_credit_ledger_entries:积分流水studio_credit_plan_versions:积分方案不可变版本
品牌库 studio_profile_invideo(24 张)
generation_deliveries 既有生成交付回执
CREATE TABLE `generation_deliveries` ( `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `session_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `maa_source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `tool_name` varchar(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `input_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `metadata_json` json NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`job_id`), KEY `generation_delivery_owner_project` (`owner_id`,`project_id`,`session_id`,`job_id`), KEY `generation_delivery_owned_asset` (`owner_id`,`asset_id`), KEY `generation_delivery_session_fk` (`session_id`), CONSTRAINT `generation_delivery_job_fk` FOREIGN KEY (`job_id`) REFERENCES `generation_jobs` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`, `job_id`) REFERENCES `generation_jobs` (`owner_id`, `project_id`, `session_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_session_fk` FOREIGN KEY (`session_id`) REFERENCES `studio_conversations` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_model_tool` CHECK ((((`model` = _ascii'seedance-2.0') and (`tool_name` = _ascii'seedance2_video_generator')) or ((`model` in (_ascii'minimax-h3',_ascii'seedance-2.5')) and (`tool_name` = _ascii'insai_video_generate')))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_development_budgets 既有开发测试预算
CREATE TABLE `generation_development_budgets` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `policy_version` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits_limit` bigint unsigned NOT NULL, `credits_reserved` bigint unsigned NOT NULL DEFAULT '0', `calls_limit` int unsigned NOT NULL, `calls_reserved` int unsigned NOT NULL DEFAULT '0', `expires_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `generation_budget_owner` (`owner_id`,`id`), CONSTRAINT `generation_budget_limits` CHECK (((`credits_limit` between 1 and 1000000000) and (`credits_reserved` <= `credits_limit`) and (`calls_limit` between 1 and 100) and (`calls_reserved` <= `calls_limit`))), CONSTRAINT `generation_budget_policy` CHECK ((`policy_version` = _latin1'operator-test/v1')) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_jobs 既有generation任务,不等同新PublicMedia任务
CREATE TABLE `generation_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `session_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_conversation_id` char(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_run_id` char(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `budget_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_bytes` mediumblob NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits` bigint unsigned NOT NULL, `expires_at` datetime(6) NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempts` int unsigned NOT NULL DEFAULT '0', `result_bytes` mediumblob, `updated_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `generation_job_budget_owner` (`id`,`budget_id`,`owner_id`), UNIQUE KEY `generation_job_owned_scope` (`owner_id`,`project_id`,`session_id`,`id`), KEY `generation_job_owner` (`owner_id`,`project_id`,`session_id`), KEY `generation_job_session` (`session_id`), KEY `generation_job_budget` (`owner_id`,`budget_id`), CONSTRAINT `generation_job_budget` FOREIGN KEY (`owner_id`, `budget_id`) REFERENCES `generation_development_budgets` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_owned_project` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_owned_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_session` FOREIGN KEY (`session_id`) REFERENCES `studio_conversations` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_attempt` CHECK ((((`status` = _ascii'APPROVED') and (`attempts` = 0) and (`result_bytes` is null)) or ((`status` = _ascii'SUBMITTING') and (`attempts` = 1) and (`result_bytes` is null)) or ((`status` in (_ascii'SUCCEEDED',_ascii'FAILED',_ascii'UNKNOWN')) and (`attempts` = 1) and (`result_bytes` is not null)))), CONSTRAINT `generation_job_credit` CHECK ((`credits` between 1 and 1000000000)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_reservations 既有任务费用预留
CREATE TABLE `generation_reservations` ( `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `budget_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits` bigint unsigned NOT NULL, `calls` int unsigned NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, PRIMARY KEY (`job_id`), KEY `generation_reservation_job` (`job_id`,`budget_id`,`owner_id`), CONSTRAINT `generation_reservation_job` FOREIGN KEY (`job_id`, `budget_id`, `owner_id`) REFERENCES `generation_jobs` (`id`, `budget_id`, `owner_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_reservation_fixed` CHECK (((`credits` between 1 and 1000000000) and (`calls` = 1) and (`status` = _latin1'HELD'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_bindings 业务会话与Native Maa会话映射、模型版本与未决操作
CREATE TABLE `maa_bindings` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `model_revision` bigint unsigned NOT NULL DEFAULT '0', `pending_model_change_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_binding_business_scope` (`owner_id`,`project_id`,`conversation_id`), UNIQUE KEY `maa_binding_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `maa_binding_native_identity` (`native_cid`), KEY `maa_model_change_pending_fk` (`owner_id`,`project_id`,`conversation_id`,`id`,`pending_model_change_id`), CONSTRAINT `maa_binding_owned_conversation_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_model_change_pending_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `id`, `pending_model_change_id`) REFERENCES `maa_model_change_actions` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_binding_receipt` CHECK ((((`status` = _ascii'dispatching') and (`native_cid` is null)) or ((`status` = _ascii'bound') and (`native_cid` is not null)))), CONSTRAINT `maa_model_binding_revision` CHECK ((`model_revision` <= 9007199254740991)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_interaction_actions 原卡片回答/取消动作
CREATE TABLE `maa_interaction_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `interaction_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_iid` varchar(124) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `content_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `response_action` varchar(8) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `values_payload` json NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_interaction_action_business_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_interaction_action_one_card` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`interaction_id`), CONSTRAINT `maa_interaction_action_owned_card_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`, `interaction_id`) REFERENCES `maa_interactions` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_interaction_action_kind` CHECK ((`response_action` in (_latin1'submit',_latin1'cancel'))), CONSTRAINT `maa_interaction_action_status` CHECK ((`status` in (_latin1'dispatching',_latin1'accepted'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_interactions 澄清卡片及Run归属
CREATE TABLE `maa_interactions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_iid` varchar(124) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_payload` json NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_interaction_native_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`native_iid`), UNIQUE KEY `maa_interaction_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`id`), CONSTRAINT `maa_interaction_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_message_actions 原消息动作及幂等回执
CREATE TABLE `maa_message_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `content` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `proposed_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_action_business_identity` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), KEY `maa_action_owned_run_fk` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`), CONSTRAINT `maa_action_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_action_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_action_receipt` CHECK ((((`status` = _latin1'dispatching') and (`public_run_id` is null)) or ((`status` = _latin1'accepted') and (`public_run_id` is not null)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_model_change_actions 带预期模型版本的切换动作
CREATE TABLE `maa_model_change_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `expected_revision` bigint unsigned NOT NULL, `from_provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `from_model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `target_provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `target_model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `dispatch_attempt` bigint unsigned NOT NULL, `receipt_payload` json DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_model_change_owned_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_model_change_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`id`), CONSTRAINT `maa_model_change_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_model_change_attempt` CHECK ((`dispatch_attempt` between 1 and 9007199254740991)), CONSTRAINT `maa_model_change_expected` CHECK ((`expected_revision` <= 9007199254740990)), CONSTRAINT `maa_model_change_status` CHECK ((((cast(`status` as char charset binary) = _latin1'dispatching') and (`receipt_payload` is null)) or ((cast(`status` as char charset binary) in (_latin1'accepted',_latin1'rejected')) and (`receipt_payload` is not null) and (json_type(`receipt_payload`) = _latin1'OBJECT')))), CONSTRAINT `maa_model_change_time` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_run_stop_actions 停止原Run的幂等动作与观测终态
CREATE TABLE `maa_run_stop_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_rid` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `stop_action` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempt` bigint unsigned NOT NULL, `terminal_run_status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_stop_owned_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_stop_one_run` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`), CONSTRAINT `maa_stop_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_stop_action` CHECK ((`stop_action` = _latin1'interrupt')), CONSTRAINT `maa_stop_attempt` CHECK ((`attempt` between 1 and 9007199254740991)), CONSTRAINT `maa_stop_state` CHECK ((((`status` = _latin1'unknown') and (`terminal_run_status` is null)) or ((`status` = _latin1'terminal_observed') and (`terminal_run_status` is not null) and (`terminal_run_status` in (_latin1'completed',_latin1'failed',_latin1'cancelled'))))), CONSTRAINT `maa_stop_time` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_runs 公开Run映射、状态与原生/公开助手证据摘要
CREATE TABLE `maa_runs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_rid` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, `native_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `public_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `native_assistant_bytes` bigint unsigned NOT NULL DEFAULT '0', `assistant_event_seq` bigint unsigned NOT NULL DEFAULT '0', `last_event_seq` bigint unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `maa_run_native_identity` (`native_rid`), UNIQUE KEY `maa_run_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`id`), KEY `maa_run_owned_list` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), CONSTRAINT `maa_run_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_run_source_evidence` CHECK ((((`native_assistant_sha256` is null) and (`public_assistant_sha256` is null) and (`native_assistant_bytes` = 0) and (`assistant_event_seq` = 0)) or ((`native_assistant_sha256` is not null) and (`public_assistant_sha256` is not null) and (`native_assistant_bytes` > 0) and (`assistant_event_seq` > 0) and (`assistant_event_seq` <= `last_event_seq`)))), CONSTRAINT `maa_run_status` CHECK ((`status` in (_latin1'queued',_latin1'running',_latin1'waiting_interaction',_latin1'completed',_latin1'failed',_latin1'cancelled'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_canvas_revisions 历史画布修订
CREATE TABLE `studio_canvas_revisions` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_bytes` mediumblob NOT NULL, `state_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `restored_from_revision` bigint unsigned DEFAULT NULL, `recorded_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`,`project_id`,`kind`,`revision`), KEY `studio_canvas_revision_source_fk` (`owner_id`,`project_id`,`kind`,`restored_from_revision`), CONSTRAINT `studio_canvas_revision_head_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_canvases` (`owner_id`, `project_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_canvas_revision_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `kind`, `restored_from_revision`) REFERENCES `studio_canvas_revisions` (`owner_id`, `project_id`, `kind`, `revision`), CONSTRAINT `studio_canvas_revision_bytes` CHECK ((length(`state_bytes`) between 1 and 262144)), CONSTRAINT `studio_canvas_revision_kind` CHECK ((`kind` = _latin1'canvas')), CONSTRAINT `studio_canvas_revision_number` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_canvas_revision_origin` CHECK ((((`origin` in (_latin1'saved',_latin1'backfill')) and (`restored_from_revision` is null)) or ((`origin` = _latin1'restored') and (`restored_from_revision` is not null) and (`restored_from_revision` between 1 and (`revision` - 1))))), CONSTRAINT `studio_canvas_revision_sha` CHECK ((`state_sha256` = lower(sha2(`state_bytes`,256)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_canvases 项目当前画布文档
CREATE TABLE `studio_canvases` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_json` json NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`project_id`), UNIQUE KEY `studio_canvas_owned_head` (`owner_id`,`project_id`), CONSTRAINT `studio_canvas_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_canvas_revision` CHECK ((`revision` between 1 and 2147483647)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_conversations 项目内的对话会话
CREATE TABLE `studio_conversations` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `title` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_conversation_owned_scope` (`owner_id`,`project_id`,`id`), KEY `studio_conversation_list` (`owner_id`,`project_id`,`created_at`,`id`), CONSTRAINT `studio_conversation_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_recovery_intents 积分结算恢复意图;不是用户钱包全账本
CREATE TABLE `studio_credit_recovery_intents` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`kind` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`intent_bytes` mediumblob NOT NULL,
`intent_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`lease_token_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`lease_until` datetime(6) DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_intent_job_kind` (`job_id`,`kind`),
KEY `credit_intent_recovery` (`state`,`updated_at`,`id`),
KEY `credit_intent_owned_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`,`request_sha256`),
CONSTRAINT `credit_intent_owned_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`, `request_sha256`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`),
CONSTRAINT `credit_intent_hashes` CHECK ((regexp_like(`request_sha256`,_latin1'^[a-f0-9]{64}$') and regexp_like(`quote_sha256`,_latin1'^[a-f0-9]{64}$'))),
CONSTRAINT `credit_intent_kind` CHECK (((`kind` in (_latin1'RESERVE_BIND',_latin1'CAPTURE',_latin1'RELEASE')) and (((`kind` = _latin1'RESERVE_BIND') and (`authorization_id` is null)) or ((`kind` in (_latin1'CAPTURE',_latin1'RELEASE')) and (`authorization_id` is not null))))),
CONSTRAINT `credit_intent_lease` CHECK ((((`state` = _latin1'leased') and (`lease_token_sha256` is not null) and regexp_like(`lease_token_sha256`,_latin1'^[a-f0-9]{64}$') and (`lease_until` is not null) and (`lease_until` > `updated_at`) and (`lease_until` <= (`updated_at` + interval 15 minute))) or ((`state` <> _latin1'leased') and (`lease_token_sha256` is null) and (`lease_until` is null)))),
CONSTRAINT `credit_intent_payload_sha` CHECK ((`intent_sha256` = lower(sha2(`intent_bytes`,256)))),
CONSTRAINT `credit_intent_payload_size` CHECK ((length(`intent_bytes`) between 1 and 65536)),
CONSTRAINT `credit_intent_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `credit_intent_state` CHECK ((`state` in (_latin1'pending',_latin1'leased',_latin1'confirmed',_latin1'unknown'))),
CONSTRAINT `credit_intent_times` CHECK ((`updated_at` >= `created_at`))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_export_jobs 时间轴导出队列和发布输出
CREATE TABLE `studio_export_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `document_revision` bigint unsigned NOT NULL, `input_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `input_json` json NOT NULL, `output_json` json DEFAULT NULL, `error_code` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT '', `lease_token_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `lease_until` datetime(6) DEFAULT NULL, `attempts` int unsigned NOT NULL DEFAULT '0', `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_export_input` (`project_id`,`document_revision`,`input_hash`), KEY `studio_export_claim` (`status`,`created_at`,`id`), KEY `studio_export_owner_list` (`owner_id`,`project_id`,`created_at`,`id`), KEY `studio_export_expiry` (`status`,`lease_until`), CONSTRAINT `studio_export_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_export_lease` CHECK ((((`status` = _latin1'running') and (`lease_token_hash` is not null) and (`lease_until` is not null)) or ((`status` <> _latin1'running') and (`lease_token_hash` is null) and (`lease_until` is null)))), CONSTRAINT `studio_export_output` CHECK ((((`status` = _latin1'succeeded') and (`output_json` is not null) and (`error_code` = _latin1'')) or ((`status` in (_latin1'queued',_latin1'running')) and (`output_json` is null) and (`error_code` = _latin1'')) or ((`status` in (_latin1'failed',_latin1'unknown')) and (`output_json` is null) and (`error_code` <> _latin1'')))), CONSTRAINT `studio_export_revision` CHECK ((`document_revision` between 1 and 2147483647)), CONSTRAINT `studio_export_status` CHECK ((`status` in (_latin1'queued',_latin1'running',_latin1'succeeded',_latin1'failed',_latin1'unknown'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_jobs 已批准媒体任务及状态机
CREATE TABLE `studio_media_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_approval_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `approval_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credit_authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `authorization_mode` varchar(24) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `authorization_expires_at` datetime(6) DEFAULT NULL, `status` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `lease_token_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `lease_until` datetime(6) DEFAULT NULL, `provider_task_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `client_cancel_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `cancel_request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `cancel_requested_at` datetime(6) DEFAULT NULL, `staged_asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `staged_asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_job_request` (`request_id`), UNIQUE KEY `studio_media_job_client` (`owner_id`,`client_approval_id`), UNIQUE KEY `studio_media_job_owned` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `studio_media_job_owned_request` (`owner_id`,`project_id`,`conversation_id`,`id`,`request_sha256`), KEY `studio_media_job_page` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), KEY `studio_media_job_queue` (`status`,`updated_at`,`id`), KEY `studio_media_job_request_fk` (`owner_id`,`project_id`,`conversation_id`,`request_id`,`request_sha256`,`quote_sha256`), CONSTRAINT `studio_media_job_request_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `request_id`, `request_sha256`, `quote_sha256`) REFERENCES `studio_media_requests` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`, `quote_sha256`), CONSTRAINT `studio_media_job_authorization` CHECK ((((`credit_authorization_id` is null) and (`authorization_mode` is null) and (`authorization_expires_at` is null) and (`status` in (_latin1'approval_pending',_latin1'cancelled'))) or ((`credit_authorization_id` is not null) and (`authorization_mode` is not null) and (`authorization_mode` in (_latin1'commercial',_latin1'test_allowance')) and (`authorization_expires_at` is not null) and (`authorization_expires_at` > `created_at`) and (`status` <> _latin1'approval_pending')))), CONSTRAINT `studio_media_job_cancel` CHECK ((((`client_cancel_id` is null) and (`cancel_request_sha256` is null) and (`cancel_requested_at` is null)) or ((`client_cancel_id` is not null) and (`cancel_request_sha256` is not null) and (`cancel_requested_at` is not null) and (`cancel_requested_at` between `created_at` and `updated_at`)))), CONSTRAINT `studio_media_job_lease` CHECK ((((`status` in (_latin1'leased',_latin1'submitting')) and (`lease_token_sha256` is not null) and (`lease_until` is not null) and (`lease_until` > `updated_at`) and (`lease_until` <= (`updated_at` + interval 15 minute))) or ((`status` not in (_latin1'leased',_latin1'submitting')) and (`lease_token_sha256` is null) and (`lease_until` is null)))), CONSTRAINT `studio_media_job_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_media_job_staged` CHECK ((((`staged_asset_id` is null) and (`staged_asset_sha256` is null)) or ((`staged_asset_id` is not null) and (`staged_asset_sha256` is not null)))), CONSTRAINT `studio_media_job_status` CHECK ((`status` in (_latin1'approval_pending',_latin1'queued',_latin1'leased',_latin1'submitting',_latin1'running',_latin1'submission_unknown',_latin1'succeeded',_latin1'failed',_latin1'cancelled'))), CONSTRAINT `studio_media_job_task` CHECK (((`status` not in (_latin1'running',_latin1'succeeded')) or (`provider_task_id` is not null))), CONSTRAINT `studio_media_job_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_outputs 受验证的输出与素材映射
CREATE TABLE `studio_media_outputs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `ordinal` int unsigned NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_metadata_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_result_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_output_job` (`job_id`,`ordinal`), KEY `studio_media_output_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`), CONSTRAINT `studio_media_output_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`), CONSTRAINT `studio_media_output_ordinal` CHECK ((`ordinal` = 0)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_requests 用户输入/Agent来源、报价、批准摘要与准入确认
CREATE TABLE `studio_media_requests` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_config_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_bytes` mediumblob NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quote_bytes` mediumblob NOT NULL, `quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quoted_credits` bigint unsigned NOT NULL, `expires_at` datetime(6) NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_snapshot_bytes` mediumblob, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_request_owned` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `studio_media_request_quoted` (`owner_id`,`project_id`,`conversation_id`,`id`,`request_sha256`,`quote_sha256`), UNIQUE KEY `studio_media_request_client` (`owner_id`,`project_id`,`conversation_id`,`client_request_id`), KEY `studio_media_request_page` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), KEY `studio_media_request_source_fk` (`owner_id`,`project_id`,`conversation_id`,`source_binding_id`,`source_run_id`), CONSTRAINT `studio_media_request_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`), CONSTRAINT `studio_media_request_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `source_binding_id`, `source_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`), CONSTRAINT `studio_media_quote_credits` CHECK ((`quoted_credits` between 1 and 1000000000)), CONSTRAINT `studio_media_quote_sha` CHECK ((`quote_sha256` = lower(sha2(`quote_bytes`,256)))), CONSTRAINT `studio_media_quote_times` CHECK (((`expires_at` > `created_at`) and (`expires_at` <= (`created_at` + interval 15 minute)))), CONSTRAINT `studio_media_request_origin` CHECK ((((`origin` in (_latin1'ui',_latin1'user_edit')) and (`source_binding_id` is null) and (`source_run_id` is null) and (`source_assistant_sha256` is null) and (`source_snapshot_bytes` is null)) or ((`origin` = _latin1'agent') and (`source_binding_id` is not null) and (`source_run_id` is not null) and (`source_assistant_sha256` is not null) and (`source_snapshot_bytes` is not null) and (length(`source_snapshot_bytes`) between 1 and 65536) and (`source_assistant_sha256` = lower(sha2(`source_snapshot_bytes`,256)))))), CONSTRAINT `studio_media_request_sha` CHECK ((`request_sha256` = lower(sha2(`request_bytes`,256)))), CONSTRAINT `studio_media_request_size` CHECK (((length(`request_bytes`) between 1 and 65536) and (length(`quote_bytes`) between 1 and 65536))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_submission_attempts 一次提交的任务证据与不确定结果
CREATE TABLE `studio_media_submission_attempts` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempt_no` int unsigned NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_idempotency_key` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `stage` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `dispatch_started_at` datetime(6) DEFAULT NULL, `provider_task_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `receipt_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `terminal_receipt_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `reconciliation_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_attempt_job` (`job_id`,`attempt_no`), UNIQUE KEY `studio_media_attempt_idempotency` (`provider_idempotency_key`), KEY `studio_media_attempt_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`,`request_sha256`), CONSTRAINT `studio_media_attempt_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`, `request_sha256`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`), CONSTRAINT `studio_media_attempt_number` CHECK ((`attempt_no` = 1)), CONSTRAINT `studio_media_attempt_state` CHECK ((((`stage` = _latin1'prepared') and (`dispatch_started_at` is null) and (`provider_task_id` is null) and (`receipt_sha256` is null) and (`reconciliation_sha256` is null) and (`terminal_receipt_sha256` is null)) or ((`stage` in (_latin1'dispatching',_latin1'unknown')) and (`dispatch_started_at` is not null) and (`dispatch_started_at` >= `created_at`) and (`provider_task_id` is null) and (`receipt_sha256` is null) and (`reconciliation_sha256` is null) and (`terminal_receipt_sha256` is null)) or ((`stage` = _latin1'acknowledged') and (`dispatch_started_at` is not null) and (`provider_task_id` is not null) and (`receipt_sha256` is not null) and (`terminal_receipt_sha256` is null)) or ((`stage` in (_latin1'completed',_latin1'failed')) and (`dispatch_started_at` is not null) and (`provider_task_id` is not null) and (`receipt_sha256` is not null) and (`terminal_receipt_sha256` is not null)) or ((`stage` = _latin1'reconciled_not_sent') and (`dispatch_started_at` is not null) and (`provider_task_id` is null) and (`reconciliation_sha256` is not null)))), CONSTRAINT `studio_media_attempt_times` CHECK (((`updated_at` >= `created_at`) and ((`dispatch_started_at` is null) or (`dispatch_started_at` between `created_at` and `updated_at`)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_project_asset_refs 项目对用户级素材的引用;不复制素材所有权
CREATE TABLE `studio_project_asset_refs` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_metadata_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, `detached_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`project_id`,`asset_id`), KEY `studio_project_asset_owned_page` (`owner_id`,`project_id`,`asset_id`), KEY `studio_project_asset_reverse` (`owner_id`,`asset_id`,`project_id`), CONSTRAINT `studio_project_asset_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_project_asset_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_project_asset_state` CHECK ((((`state` = _latin1'attached') and (`detached_at` is null)) or ((`state` = _latin1'detached') and (`detached_at` is not null) and (`detached_at` = `updated_at`)))), CONSTRAINT `studio_project_asset_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_projects 用户拥有的创作项目
CREATE TABLE `studio_projects` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `title` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_project_owner_identity` (`owner_id`,`id`), KEY `studio_project_owner_list` (`owner_id`,`created_at`,`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_timeline_revisions 历史时间轴修订
CREATE TABLE `studio_timeline_revisions` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_bytes` mediumblob NOT NULL, `state_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `restored_from_revision` bigint unsigned DEFAULT NULL, `recorded_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`,`project_id`,`kind`,`revision`), KEY `studio_timeline_revision_source_fk` (`owner_id`,`project_id`,`kind`,`restored_from_revision`), CONSTRAINT `studio_timeline_revision_head_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_video_documents` (`owner_id`, `project_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_timeline_revision_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `kind`, `restored_from_revision`) REFERENCES `studio_timeline_revisions` (`owner_id`, `project_id`, `kind`, `revision`), CONSTRAINT `studio_timeline_revision_bytes` CHECK ((length(`state_bytes`) between 1 and 262144)), CONSTRAINT `studio_timeline_revision_kind` CHECK ((`kind` = _latin1'timeline')), CONSTRAINT `studio_timeline_revision_number` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_timeline_revision_origin` CHECK ((((`origin` in (_latin1'saved',_latin1'backfill')) and (`restored_from_revision` is null)) or ((`origin` = _latin1'restored') and (`restored_from_revision` is not null) and (`restored_from_revision` between 1 and (`revision` - 1))))), CONSTRAINT `studio_timeline_revision_sha` CHECK ((`state_sha256` = lower(sha2(`state_bytes`,256)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_video_documents 项目当前时间轴文档
CREATE TABLE `studio_video_documents` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_json` json NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`project_id`), UNIQUE KEY `studio_timeline_owned_head` (`owner_id`,`project_id`), CONSTRAINT `studio_document_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_document_revision` CHECK ((`revision` between 1 and 2147483647)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
共享身份库(15 张)与积分账本 七个品牌相同,展开查看
studio_assets
CREATE TABLE `studio_assets` (
`id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`metadata_json` json NOT NULL,
`storage_key` varchar(512) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`created_at` datetime(6) NOT NULL,
`publication_state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT 'visible',
PRIMARY KEY (`id`),
UNIQUE KEY `studio_asset_owner_digest` (`owner_id`,`sha256`),
KEY `studio_asset_owner_list` (`owner_id`,`created_at`,`id`),
KEY `studio_asset_visible_list` (`owner_id`,`publication_state`,`created_at`,`id`),
CONSTRAINT `studio_asset_publication_state` CHECK (CAST(publication_state AS BINARY) IN ('pending','visible')),
CONSTRAINT `studio_asset_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_billing_cycles
CREATE TABLE `studio_billing_cycles` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`subscription_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`payment_order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_invoice_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`period_start` datetime(6) NOT NULL,
`period_end` datetime(6) NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`valid_from` datetime(6) NOT NULL,
`expires_at` datetime(6) NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`paid_evidence_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `billing_cycle_owned` (`owner_id`,`id`),
UNIQUE KEY `billing_cycle_period` (`subscription_id`,`period_start`),
UNIQUE KEY `billing_cycle_invoice` (`provider_key`,`provider_account`,`provider_invoice_id`),
UNIQUE KEY `billing_cycle_order` (`payment_order_id`),
KEY `billing_cycle_subscription_fk` (`owner_id`,`subscription_id`,`provider_key`,`provider_account`),
KEY `billing_cycle_order_fk` (`owner_id`,`payment_order_id`,`plan_version_id`),
KEY `billing_cycle_order_provider_fk` (`owner_id`,`payment_order_id`,`provider_key`,`provider_account`),
CONSTRAINT `billing_cycle_order_fk` FOREIGN KEY (`owner_id`, `payment_order_id`, `plan_version_id`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `plan_version_id`),
CONSTRAINT `billing_cycle_order_provider_fk` FOREIGN KEY (`owner_id`, `payment_order_id`, `provider_key`, `provider_account`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `provider_key`, `provider_account`),
CONSTRAINT `billing_cycle_subscription_fk` FOREIGN KEY (`owner_id`, `subscription_id`, `provider_key`, `provider_account`) REFERENCES `studio_subscriptions` (`owner_id`, `id`, `provider_key`, `provider_account`),
CONSTRAINT `billing_cycle_amount` CHECK ((`grant_credits` between 1 and 1000000000)),
CONSTRAINT `billing_cycle_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `billing_cycle_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `billing_cycle_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `billing_cycle_state` CHECK (((`state` in (_latin1'PENDING',_latin1'PAID',_latin1'CLOSED')) and (((`state` = _latin1'PAID') and (`paid_evidence_sha256` is not null) and regexp_like(`paid_evidence_sha256`,_latin1'^[a-f0-9]{64}$')) or ((`state` <> _latin1'PAID') and (`paid_evidence_sha256` is null))))),
CONSTRAINT `billing_cycle_times` CHECK (((`period_end` > `period_start`) and (`expires_at` > `valid_from`) and (`expires_at` <= (`valid_from` + interval 31622400 second)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_credit_accounts
CREATE TABLE `studio_credit_accounts` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `unit` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`), CONSTRAINT `credit_account_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `credit_account_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `credit_account_status` CHECK ((`status` in (_latin1'open',_latin1'suspended'))), CONSTRAINT `credit_account_unit` CHECK ((`unit` = _latin1'credits')) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_authorization_allocations
CREATE TABLE `studio_credit_authorization_allocations` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `lot_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `allocated_credits` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`authorization_id`,`lot_id`), UNIQUE KEY `credit_allocation_owned` (`owner_id`,`authorization_id`,`lot_id`), KEY `credit_allocation_lot` (`owner_id`,`lot_id`,`authorization_id`), CONSTRAINT `credit_allocation_authorization_fk` FOREIGN KEY (`owner_id`, `authorization_id`) REFERENCES `studio_credit_authorizations` (`owner_id`, `id`), CONSTRAINT `credit_allocation_lot_fk` FOREIGN KEY (`owner_id`, `lot_id`) REFERENCES `studio_credit_lots` (`owner_id`, `id`), CONSTRAINT `credit_allocation_amount` CHECK ((`allocated_credits` between 1 and 1000000000)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_authorizations
CREATE TABLE `studio_credit_authorizations` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`profile` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`credits` bigint unsigned NOT NULL,
`expires_at` datetime(6) NOT NULL,
`reservation_bytes` mediumblob NOT NULL,
`reservation_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`policy_bytes` mediumblob NOT NULL,
`policy_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_authorization_owned` (`owner_id`,`id`),
UNIQUE KEY `credit_authorization_job` (`owner_id`,`profile`,`job_id`),
CONSTRAINT `credit_authorization_account_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_credit_accounts` (`owner_id`),
CONSTRAINT `credit_authorization_amount` CHECK ((`credits` between 1 and 1000000000)),
CONSTRAINT `credit_authorization_hashes` CHECK ((regexp_like(`request_sha256`,_latin1'^[a-f0-9]{64}$') and regexp_like(`quote_sha256`,_latin1'^[a-f0-9]{64}$'))),
CONSTRAINT `credit_authorization_policy_sha` CHECK ((`policy_sha256` = lower(sha2(`policy_bytes`,256)))),
CONSTRAINT `credit_authorization_policy_size` CHECK ((length(`policy_bytes`) between 1 and 65536)),
CONSTRAINT `credit_authorization_profile` CHECK ((`profile` in (_latin1'topview',_latin1'pollo',_latin1'invideo',_latin1'libtv',_latin1'flova',_latin1'creatok',_latin1'creatify'))),
CONSTRAINT `credit_authorization_reservation_sha` CHECK ((`reservation_sha256` = lower(sha2(`reservation_bytes`,256)))),
CONSTRAINT `credit_authorization_reservation_size` CHECK ((length(`reservation_bytes`) between 1 and 65536)),
CONSTRAINT `credit_authorization_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `credit_authorization_state` CHECK ((`state` in (_latin1'HELD',_latin1'CAPTURED',_latin1'RELEASED'))),
CONSTRAINT `credit_authorization_times` CHECK (((`expires_at` > `created_at`) and (`expires_at` <= (`created_at` + interval 15 minute)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_credit_ledger_entries
CREATE TABLE `studio_credit_ledger_entries` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `lot_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `operation_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `grant_delta` bigint NOT NULL, `held_delta` bigint NOT NULL, `captured_delta` bigint NOT NULL, `facts_bytes` mediumblob NOT NULL, `facts_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `credit_entry_operation` (`owner_id`,`operation_key`,`lot_id`), KEY `credit_entry_page` (`owner_id`,`created_at`,`id`), KEY `credit_entry_lot_fk` (`owner_id`,`lot_id`), KEY `credit_entry_allocation_fk` (`owner_id`,`authorization_id`,`lot_id`), CONSTRAINT `credit_entry_allocation_fk` FOREIGN KEY (`owner_id`, `authorization_id`, `lot_id`) REFERENCES `studio_credit_authorization_allocations` (`owner_id`, `authorization_id`, `lot_id`), CONSTRAINT `credit_entry_authorization_fk` FOREIGN KEY (`owner_id`, `authorization_id`) REFERENCES `studio_credit_authorizations` (`owner_id`, `id`), CONSTRAINT `credit_entry_lot_fk` FOREIGN KEY (`owner_id`, `lot_id`) REFERENCES `studio_credit_lots` (`owner_id`, `id`), CONSTRAINT `credit_entry_delta` CHECK ((((`kind` = _latin1'grant') and (`authorization_id` is null) and (`grant_delta` between 1 and 1000000000) and (`held_delta` = 0) and (`captured_delta` = 0)) or ((`kind` = _latin1'hold') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`held_delta` between 1 and 1000000000) and (`captured_delta` = 0)) or ((`kind` = _latin1'capture') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`captured_delta` between 1 and 1000000000) and (`held_delta` = -(`captured_delta`))) or ((`kind` = _latin1'release') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`held_delta` between -(1000000000) and -(1)) and (`captured_delta` = 0)))), CONSTRAINT `credit_entry_facts_sha` CHECK ((`facts_sha256` = lower(sha2(`facts_bytes`,256)))), CONSTRAINT `credit_entry_facts_size` CHECK ((length(`facts_bytes`) between 1 and 65536)), CONSTRAINT `credit_entry_operation_key` CHECK ((((`kind` = _latin1'grant') and (`operation_key` = concat(`lot_id`,_latin1':grant'))) or ((`kind` <> _latin1'grant') and (`operation_key` = concat(`authorization_id`,_latin1':',`kind`))))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_lots
CREATE TABLE `studio_credit_lots` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `grant_credits` bigint unsigned NOT NULL, `held_credits` bigint unsigned NOT NULL, `captured_credits` bigint unsigned NOT NULL, `valid_from` datetime(6) NOT NULL, `expires_at` datetime(6) NOT NULL, `eligibility_bytes` mediumblob NOT NULL, `eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_cycle_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `credit_lot_owned` (`owner_id`,`id`), UNIQUE KEY `credit_lot_order` (`source_order_id`), UNIQUE KEY `credit_lot_cycle` (`source_cycle_id`), KEY `credit_lot_eligible` (`owner_id`,`expires_at`,`id`), KEY `credit_lot_order_fk` (`owner_id`,`source_order_id`), KEY `credit_lot_cycle_fk` (`owner_id`,`source_cycle_id`), CONSTRAINT `credit_lot_account_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_credit_accounts` (`owner_id`), CONSTRAINT `credit_lot_cycle_fk` FOREIGN KEY (`owner_id`, `source_cycle_id`) REFERENCES `studio_billing_cycles` (`owner_id`, `id`), CONSTRAINT `credit_lot_order_fk` FOREIGN KEY (`owner_id`, `source_order_id`) REFERENCES `studio_payment_orders` (`owner_id`, `id`), CONSTRAINT `credit_lot_counters` CHECK (((`grant_credits` between 1 and 1000000000) and (`held_credits` <= 1000000000) and (`captured_credits` <= 1000000000) and ((`held_credits` + `captured_credits`) <= `grant_credits`))), CONSTRAINT `credit_lot_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))), CONSTRAINT `credit_lot_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)), CONSTRAINT `credit_lot_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `credit_lot_source` CHECK ((((`source_order_id` is not null) and (`source_cycle_id` is null)) or ((`source_order_id` is null) and (`source_cycle_id` is not null)))), CONSTRAINT `credit_lot_times` CHECK (((`expires_at` > `valid_from`) and (`updated_at` >= `created_at`))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_plan_versions
CREATE TABLE `studio_credit_plan_versions` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`version_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`price_minor` bigint unsigned NOT NULL,
`currency` char(3) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`credit_validity_seconds` int unsigned NOT NULL,
`billing_interval_months` int unsigned NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`published_at` datetime(6) NOT NULL,
`retired_at` datetime(6) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_plan_version_key` (`plan_key`,`version_key`),
CONSTRAINT `credit_plan_amount` CHECK (((`price_minor` between 1 and 1000000000000) and (`grant_credits` between 1 and 1000000000))),
CONSTRAINT `credit_plan_currency` CHECK (regexp_like(`currency`,_latin1'^[A-Z]{3}$')),
CONSTRAINT `credit_plan_duration` CHECK (((`credit_validity_seconds` between 1 and 31622400) and ((`retired_at` is null) or (`retired_at` >= `published_at`)))),
CONSTRAINT `credit_plan_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `credit_plan_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `credit_plan_kind` CHECK (((`kind` in (_latin1'subscription',_latin1'topup')) and (((`kind` = _latin1'subscription') and (`billing_interval_months` in (1,3,12))) or ((`kind` = _latin1'topup') and (`billing_interval_months` = 0)))))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_media_model_versions
CREATE TABLE `studio_media_model_versions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `version_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `config_bytes` mediumblob NOT NULL, `config_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `published_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_version_key` (`model_id`,`version_key`), UNIQUE KEY `studio_media_version_owned_model` (`model_id`,`id`), CONSTRAINT `studio_media_version_model_fk` FOREIGN KEY (`model_id`) REFERENCES `studio_media_models` (`id`), CONSTRAINT `studio_media_version_sha` CHECK ((`config_sha256` = lower(sha2(`config_bytes`,256)))), CONSTRAINT `studio_media_version_size` CHECK ((length(`config_bytes`) between 1 and 65536)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_models
CREATE TABLE `studio_media_models` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `display_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `published_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `revision` bigint unsigned NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_model_key` (`model_key`), KEY `studio_media_model_published_fk` (`id`,`published_version_id`), CONSTRAINT `studio_media_model_published_fk` FOREIGN KEY (`id`, `published_version_id`) REFERENCES `studio_media_model_versions` (`model_id`, `id`), CONSTRAINT `studio_media_model_kind` CHECK ((`kind` = _ascii'video')), CONSTRAINT `studio_media_model_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_media_model_status` CHECK (((`status` in (_ascii'draft',_ascii'active',_ascii'disabled')) and ((`status` <> _ascii'active') or (`published_version_id` is not null)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_payment_events
CREATE TABLE `studio_payment_events` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_event_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `subscription_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `body_bytes` mediumblob NOT NULL, `body_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `payment_event_provider` (`provider_key`,`provider_account`,`provider_event_id`), KEY `payment_event_order_fk` (`owner_id`,`order_id`,`provider_key`,`provider_account`), KEY `payment_event_subscription_fk` (`owner_id`,`subscription_id`,`provider_key`,`provider_account`), CONSTRAINT `payment_event_order_fk` FOREIGN KEY (`owner_id`, `order_id`, `provider_key`, `provider_account`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `provider_key`, `provider_account`), CONSTRAINT `payment_event_subscription_fk` FOREIGN KEY (`owner_id`, `subscription_id`, `provider_key`, `provider_account`) REFERENCES `studio_subscriptions` (`owner_id`, `id`, `provider_key`, `provider_account`), CONSTRAINT `payment_event_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `payment_event_body_sha` CHECK ((`body_sha256` = lower(sha2(`body_bytes`,256)))), CONSTRAINT `payment_event_body_size` CHECK ((length(`body_bytes`) between 1 and 65536)), CONSTRAINT `payment_event_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `payment_event_state` CHECK ((`state` in (_latin1'VERIFIED',_latin1'PROCESSED'))), CONSTRAINT `payment_event_subject` CHECK (((`order_id` is not null) or (`subscription_id` is not null))), CONSTRAINT `payment_event_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_payment_orders
CREATE TABLE `studio_payment_orders` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`price_minor` bigint unsigned NOT NULL,
`currency` char(3) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`valid_from` datetime(6) NOT NULL,
`expires_at` datetime(6) NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_idempotency_key` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_order_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`paid_evidence_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `payment_order_owned` (`owner_id`,`id`),
UNIQUE KEY `payment_order_owned_plan` (`owner_id`,`id`,`plan_version_id`),
UNIQUE KEY `payment_order_owned_provider` (`owner_id`,`id`,`provider_key`,`provider_account`),
UNIQUE KEY `payment_order_client` (`owner_id`,`client_action_id`),
UNIQUE KEY `payment_order_provider_key` (`provider_key`,`provider_account`,`provider_idempotency_key`),
UNIQUE KEY `payment_order_provider_id` (`provider_key`,`provider_account`,`provider_order_id`),
KEY `payment_order_plan_fk` (`plan_version_id`),
CONSTRAINT `payment_order_plan_fk` FOREIGN KEY (`plan_version_id`) REFERENCES `studio_credit_plan_versions` (`id`),
CONSTRAINT `payment_order_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`),
CONSTRAINT `payment_order_amount` CHECK (((`price_minor` between 1 and 1000000000000) and (`grant_credits` between 1 and 1000000000))),
CONSTRAINT `payment_order_currency` CHECK (regexp_like(`currency`,_latin1'^[A-Z]{3}$')),
CONSTRAINT `payment_order_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `payment_order_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `payment_order_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `payment_order_state` CHECK (((`state` in (_latin1'CREATING',_latin1'CREATE_UNKNOWN',_latin1'PENDING',_latin1'PAID',_latin1'CLOSED')) and (((`state` = _latin1'PAID') and (`provider_order_id` is not null) and (`paid_evidence_sha256` is not null) and regexp_like(`paid_evidence_sha256`,_latin1'^[a-f0-9]{64}$')) or ((`state` <> _latin1'PAID') and (`paid_evidence_sha256` is null))))),
CONSTRAINT `payment_order_times` CHECK (((`expires_at` > `valid_from`) and (`expires_at` <= (`valid_from` + interval 31622400 second)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_sessions
CREATE TABLE `studio_sessions` ( `token_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `user_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, `expires_at` datetime(6) NOT NULL, `revoked_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`token_hash`), KEY `studio_session_expiry` (`expires_at`), KEY `studio_session_user` (`user_id`,`expires_at`), CONSTRAINT `studio_session_user_fk` FOREIGN KEY (`user_id`) REFERENCES `studio_users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_session_times` CHECK ((`expires_at` > `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_subscriptions
CREATE TABLE `studio_subscriptions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_subscription_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `period_start` datetime(6) NOT NULL, `period_end` datetime(6) NOT NULL, `cancel_at_period_end` tinyint(1) NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `subscription_owned` (`owner_id`,`id`), UNIQUE KEY `subscription_owned_provider` (`owner_id`,`id`,`provider_key`,`provider_account`), UNIQUE KEY `subscription_provider` (`provider_key`,`provider_account`,`provider_subscription_id`), KEY `subscription_plan_fk` (`plan_version_id`), CONSTRAINT `subscription_plan_fk` FOREIGN KEY (`plan_version_id`) REFERENCES `studio_credit_plan_versions` (`id`), CONSTRAINT `subscription_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `subscription_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `subscription_state` CHECK (((`state` in (_latin1'PENDING',_latin1'ACTIVE',_latin1'PAST_DUE',_latin1'CANCELLED',_latin1'ENDED')) and (`cancel_at_period_end` in (0,1)))), CONSTRAINT `subscription_times` CHECK (((`period_end` > `period_start`) and (`updated_at` >= `created_at`))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_users
CREATE TABLE `studio_users` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `email` varchar(254) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `password_hash` varbinary(72) NOT NULL, `enabled` tinyint(1) NOT NULL DEFAULT '1', `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_user_email` (`email`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
积分账本链路
invideo AI · 接口清单
共 55 个公开接口,取自源码路由盘点。路径都以 /v1 开头;写操作需要会话 Cookie、可信 Host/Origin 与 CSRF;带品牌的路径用 ?profile=invideo;共享的登录、素材、模型目录路径不接受 profile 参数。
Agent/统一动作 7 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/interactions | runInteractions | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/interactions/{interaction_id}/responses | respondInteraction | client_action_id, card_sha256, action, values | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/interaction-actions/{client_action_id} | interactionAction | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/model-changes | changeConversationModel | client_action_id, expected_revision, agent_model, expected_attempt? | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/model-changes/{client_action_id} | modelChangeAction | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/stop | stopRun | client_action_id, expected_attempt? | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/stop-actions/{client_action_id} | stopAction | 200 |
Asset 4 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/assets | listAssets | 200 | |
| POST | /v1/assets | uploadAsset | file | 201 |
| GET | /v1/assets/{asset_id} | getAsset | 200 | |
| GET | /v1/assets/{asset_id}/content | assetContent | 200/206 |
LoginSession 1 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| POST | /v1/auth/logout | logout | 200 |
MaaBinding 5 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/maa/model-options | maaModels | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/messages | sendMaaMessage | client_action_id, content | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/actions/{client_action_id} | getMaaAction | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/state | getMaaState | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/events | maaEvents | 200 |
Media 11 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/media/models | publicMediaModels | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests | createMediaRequest | client_request_id, model_id, model_version_id, prompt, duration_seconds, ratio, resolution, admission? | 200 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests | mediaRequestByClient | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id} | getMediaRequest | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs/{job_id} | getMediaJob | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs/{job_id}/output | getMediaOutput | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id}/job | mediaJobByRequest | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id}/approve | approveMediaRequest | client_approval_id, request_sha256, quote_sha256 | 200 |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/from-maa | createMediaRequestFromMaa | input, source_run_id, source_assistant_sha256, admission? | 200 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs | listMediaJobs | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/intents | listMediaIntents | 200 |
Other 9 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects/{project_id}/canvas/revisions | listCanvasRevisions | 200 | |
| GET | /v1/projects/{project_id}/canvas/revisions/{revision} | getCanvasRevision | 200 | |
| POST | /v1/projects/{project_id}/canvas/revisions/{revision}/restore | restoreCanvasRevision | expected_revision | 200 |
| GET | /v1/projects/{project_id}/document/revisions | listTimelineRevisions | 200 | |
| GET | /v1/projects/{project_id}/document/revisions/{revision} | getTimelineRevision | 200 | |
| POST | /v1/projects/{project_id}/document/revisions/{revision}/restore | restoreTimelineRevision | expected_revision | 200 |
| GET | /v1/projects/{project_id}/assets | listProjectAssets | 200 | |
| POST | /v1/projects/{project_id}/assets | attachProjectAsset | asset_id, expected_revision | 200 |
| POST | /v1/projects/{project_id}/assets/{asset_id}/detach | detachProjectAsset | expected_revision | 200 |
Project 15 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects | listProjects | 200 | |
| POST | /v1/projects | createProject | title | 201 |
| GET | /v1/projects/{project_id} | getProject | 200 | |
| GET | /v1/projects/{project_id}/conversations | listConversations | 200 | |
| POST | /v1/projects/{project_id}/conversations | createConversation | title | 201 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id} | getConversation | 200 | |
| GET | /v1/projects/{project_id}/canvas | getCanvas | 200 | |
| POST | /v1/projects/{project_id}/canvas | saveCanvas | expected_revision, state | 200 |
| GET | /v1/projects/{project_id}/document | getDocument | 200 | |
| POST | /v1/projects/{project_id}/document | saveDocument | expected_revision, state | 200 |
| GET | /v1/projects/{project_id}/export-jobs | listExportJobs | 200 | |
| POST | /v1/projects/{project_id}/export-jobs | queueExport | document_revision, output? | 202 |
| GET | /v1/projects/{project_id}/export-jobs/{job_id} | getExportJob | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/binding | getMaaBinding | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/binding | bindMaa | agent_model XOR use_default:true | 200 |
User 3 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| POST | /v1/auth/register | register | email, password | 201 |
| POST | /v1/auth/login | login | email, password | 200 |
| GET | /v1/auth/session | session | 200 |
invideo AI 自己公开的接口调用流程(来自其官方资料)
| 步骤 | 调用关系 | 操作 | 证据 |
|---|---|---|---|
| 打开项目 | 编辑用户 → 项目入口 | 进入 Project,再从 Notebook 的 Agent Chat 找到目标 Timeline。 | W |
| 准备素材 | 编辑用户 → 项目入口 | 上传媒体并用文件夹整理;等待上传完成后再把它用于 Agent 工作。 | W |
| 提交剪辑目标 | 编辑用户 → Agent编排 | 描述片段、长度和保留内容;项目中的 Agent 可共享创作背景并接收各自任务。 | W |
| 检查Agent结果 | Agent编排 → 编辑状态 | Agent 更新剪辑后,用户在 Monitor/Timeline 检查可继续手改的结果;此处候选指待检查的结果。 | W |
| 人工细调 | 编辑用户 → 编辑状态 | 手改剪辑,或把局部修订要求发回 Agent;人工与 Agent 面向同一 Timeline。 | W |
| 保留方向与历史 | 编辑用户 → 编辑状态 | 用 Branch 尝试替代剪辑,Tag 标记阶段,History 返回之前状态。 | W |
| 发送审阅版本 | 编辑用户 → 交付模块 | 选择 Timeline 建 Playlist 审阅链接,设置观看/下载权限并收集时间码反馈。 | W |
| 导出作品 | 编辑用户 → 交付模块 | 选择范围和参数导出视频、音频、静帧或工程,再检查最终文件。 | W |
| 可选外部接入 | 外部Agent → 项目入口 | 经 https://mcp.invideo.io/mcp 授权后使用 Editor 能力;没有调用任何工具或取得参数 schema。 | A |
invideo AI · 代码与下载
1.1 MB · 54 个文件 · SHA-256
93e68e0022be0bf46af283e3389b8932b5f058b1eb2537e972770fa65051ecdc下载:invideo-replica.zip · 后端与合同 · 全部代码
| 目录 | 内容 |
|---|---|
| frontend/ | invideo AI 前端:<code>candidate-8875-unified-v22.html</code> 及它引用的全部脚本与样式 |
| contracts/ | 本品牌的表结构 SQL、ER(svg / mmd)、外键清单;接口目录(json / csv);共享身份库表结构 |
| README.md | 怎么运行、需要自备什么 |
运行前端
python3 -m http.server -d frontend 8791
# 打开 http://127.0.0.1:8791/agent-integration/apps-production-brand-v14/invideo/candidate-8875-unified-v22.htmlbackend-and-contracts.zip;all-brands-code.zip 是全部。包里没有任何凭据、数据库备份或媒体文件,已做敏感串扫描。MAA_AGENT_ROOT)、模型网关与对象存储配置。静态前端单独打开不需要后端,但登录、对话、生成、导出需要整套服务。复刻完成度(审计 2026-10-19)
结论:不是完美复刻。官方资料里的 58 项能力:实测跑通 1、只有通用对话 1、后端有但没跑过 11、没有后端 45。
真正跑通的:脚本协写与逐镜头规划。
界面对照(首页(已登录 Agent Two)):真实页面采集到 18 个控件 / 标题文字,复刻页找到 17 个;位置偏差中位数 200 px(1/17 个在 24 px 内)。缺的有:Agent Two Lite。
逐个点击(已登录首页):123 个可点控件,点了有效 20 个,只提示“此功能正在接入” 10 个,没反应或只变样式 89 个,禁用 4 个,未点(发送 / 删除 / 退出等)0 个。
只提示“正在接入”的控件(10 次点击,10 种)
Upgrade、Agent、Editor、Product Ads、Create AI shorts、Use my script、Agents & models、Projects、Workflows、Explore
点了没反应或只变样式的控件(89 次点击,30 种)
Upgrade with 55% off、Dismiss offer banner、Create a first cut、Use my Premiere Pro / DaVinci Resolve project、Home ×2、(图标) ×23、Library ×2、Explore ×2、You ×2、Create new、See all ×5、Seedance 2.5 ×3、Premium video with reference images, video & audio ×2、Seedance 2.0 ×3、GPT Image 2.5 Sunburst ×4、OpenAI's most capable image generation and editing、GPT Image 2.5 Flare ×3、OpenAI's fastest high-quality image model、MiniMax H3 Max ×3、fal's post-trained MiniMax-H3, tuned for prompt ad、GPT Image 2 ×4、Seed Audio 1.0 ×4、Prompt-driven audio scenes in 20 languages — voice、New agent ×2、Looks ×3、Boards ×2、Angles ×3、Bold Text Behind ×3、Difference Text ×2、Gradient Center Text ×3
复刻页自报的绑定状态(页面内嵌的绑定清单):原生工作区控件(新建项目、会话、登录等)8 / 10 个没有绑定到原页面的控件,由统一的工作区条代替;路由 canvas、timeline、assets 缺失或只做了一部分;
首屏截图对照(左:真实产品 invideo/auth-core/home.jpg;右:复刻页)· 粗粒度差异 11%
真实截图是测试账号登录后的画面,内容(作品、项目、横幅)本来就不同,差异百分比只作参考,重点看布局。
LibTV · 总览
- 它是什么:画布 + 故事板 + Agent;技能社区;Agent 交互:技能固定版本绑定会话;预算只提醒。
- 我们借鉴:技能版本固定。<b>不采纳</b>“只提醒不拦截”的预算(决策 D1 D9)。
- 复刻现状:5 项已验证,在线试用 http://119.23.106.60:8104/;后端与其余六个品牌共用一套(24 张表、55 个接口),所以 ER / 表结构 / 接口页的通用部分默认折叠。
以 Agent、Skill 社区和节点画布承载影视创作;公开页面可见多类生成和影视工具,客户端代码显示独立项目、会话、素材、任务及版本。
证据:W 官方说明,A 官方接口合同,C 客户端代码,O 实测。“未实测”= 只核对了官方页面,没有上传素材或生成。
34 项,分 11 类
首页 + 节点画布 + TV Director
24 张表 · 34 个外键 · 85 个索引
能力目录
智能 Agent 与 Skill 6 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| LibTV Agent BETA | 在影视创作中提供 Agent 对话入口。 | W | Beta 运行能力、任务权限和计费未测 |
| 流式回复与断线恢复 | 客户端先补会话历史再接续实时消息。 | C | 静态 WS 解析,不是已抓到登录帧;seq/replay 保证未知 |
| 生成审批模式 | 会话存在审批模式更新能力。 | C | approvalMode 枚举与何种动作需审批未知 |
| 固定版本 Skill 绑定会话 | 建会话时客户端携带 Skill 标识和版本。 | C | 没有执行创建,版本是否锁定及升级行为未知 |
| 剧本生成 | 提供文字剧本创作入口。 | W | 长篇一致性与分镜合同未测 |
| 剧本原创与改编 | 为原创或改编影视文本提供工具。 | W | 没有运行,输入边界与输出结构未知 |
项目与会话 7 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| Agent 项目多会话 | 按项目列会话并建立不同创作对话。 | C | projectId/sessionId 请求构造可见;未创建项目 |
| 历史消息查询 | 按会话或序号获取历史消息。 | C | 保留期、分页上限、删除与分叉未知 |
| 画布项目与视口保存 | 存储画布草稿、配置及视口位置。 | C | Agent Project 与 Canvas UUID 映射未登录核实 |
| 画布版本读取 | 按项目和 versionId 读取版本快照。 | C | 仅确认版本查询;不认定可一键恢复/分叉或不可变存储 |
| 节点和连线编辑 | 画布组织节点及连接形成创作流程。 | C | 节点类型全集与可连端口规则未确认 |
| 节点和连线批量提交 | 一次提交多项创建、更新或删除。 | C | 带 requestId 不证明后端原子性/幂等 |
| 独立编辑会话上下文 | 画布修改携带编辑 session 与时间戳。 | C | 不能把画布编辑会话并入 Agent 聊天会话;冲突处理未测 |
模板与社区 6 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| Skill 分类与搜索 | 搜索或按影视、广告等分类找 Skill。 | O | 分类文案在不同页面渲染有差异,不固定全部标签 |
| Skill 收藏与我的入口 | 公开 Skill 页面提供收藏和个人区。 | O | 不能由入口推断匿名可收藏或后台 CRUD 合同 |
| Skill 案例与版本信息 | 模板带版本、snapshot 与案例媒体引用。 | O | 案例可有画布或成品链接,字段不是物理表 |
| Skill 草稿与发布 | 客户端存在创建、改草稿、应用和发布路径。 | C | 发布审查、权限、版本冲突与下架规则未知 |
| TV Show 案例与精选画布 | 展示公开作品及场景分类参考。 | O | 作品仅示例;画布复用、发布及分享权限未执行 |
| 学院、教程与版本更新 | 提供创作学习及产品更新入口。 | W | 活动是否仍接收报名不由历史入口推断 |
素材与商品 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 个人素材库 | 客户端提供素材创建与列表能力。 | C | 文件归属、上传审核和删除回收未测 |
| 任务生成结果列表 | 从任务查询生成的媒体产物。 | C | Artifact 列表存在;是否自动入素材库未知 |
| 生成任务进度 | 客户端查询任务运行进度。 | C | 进度状态、重试、取消及并发上限未知 |
协作与权益 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 素材复制到团队 | 存在个人素材复制到团队范围的操作。 | C | 只确认范围转换,不推测共享素材外键/成员完整角色 |
| 生成费用预估 | 客户端有任务费用计算入口。 | C | 未实际查询价格,不当成预占/结算保证 |
| 会员与限时优惠入口 | 首页展示会员及模型相关限时优惠。 | W | 促销不是完整订阅方案;积分结算、价格和到期规则待登录核实 |
视频生成 2 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 视频生成 | 提供 AI 视频生成入口。 | W | 各模型输入、片段上限、价格与可用性依账号 |
| 导演执导 | 提供导演构思和影视创作工具入口。 | W | 具体镜头/调度参数及任务流程未执行 |
图片生成 2 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 图片生成 | 提供 AI 图片生成入口。 | W | 未确认所有模型或高级参数 |
| 3D-BOX | 官方提供名为 3D-BOX 的创作工具。 | W | 仅确定工具名;不补造 3D 引擎/视角/格式实现 |
声音与人物 2 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 音频生成 | 提供音频生成入口。 | W | TTS、音色克隆及声音授权范围未知 |
| 角色造型室 | 提供角色形象准备入口。 | W | 跨镜头一致性与人物版本机制未知 |
编辑与导出 1 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 智能剪辑 | 提供智能剪辑入口。 | W | 不等于确认传统多轨时间轴;导出格式未知 |
发现与分析 1 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 作品分类与搜索 | 按作品类型筛选并检索案例。 | O | 只确认入口,没有批量查询用户数据 |
开放接入与客户端 1 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| Web 独立窗口声明 | manifest 声明 standalone Web 展示。 | O | 这是 Web 声明,不是 APK/IPA 或可安装性已验证 |
尚不清楚的部分
- 传统时间轴、字幕、音轨、镜头细节及导出:当前只确定智能剪辑入口,账号内编辑器及格式未实测。
- 团队协作与分享完整权限:静态素材团队复制和 team_id 不足以确认邀请角色、评论、分享链接。
- 收藏、社区发布与模板复用实际能力:存在入口或客户端路径,但未执行登录写入或发布。
- 模型完整目录和订阅权益矩阵:首页可见部分模型/促销入口,不凑型号数,也不转成永久价格。
- 外部账号授权、广告投放及发布排期:没有官方直接证据,不能由竞赛投稿导航补造社交发布。
- 公开 API、CLI 或 MCP:已观察的是 Web 私有业务路径和 WS 客户端;没有公开稳定接入合同。
竞品技术栈观察
当前Web公开构件直接标注Next.js16.3.4、React19.3.0-canary-cbb046ab-20260731,采用App Router/Flight和Turbopack,并出现TypeScript源路径。网关及静态CDN与业务后端分别标注。
| 项目 | 观察到的内容 | 状态 | 置信度 |
|---|---|---|---|
| Nginx 与代理版本 | 入口banner为istio-envoy;静态CDN为Tengine。Nginx本身是否部署及准确版本未确认。 | unknown | medium |
| 前端运行语言 | 浏览器交付并加载JavaScript;当前公开构件包含React与Next运行时。 | observed | high |
| 前端源码语言 | 公开构件出现apps/liblibtv/src下多个.ts源路径,可确认部分业务前端源文件采用TypeScript。 | observed | high |
| 前端框架与版本 | 当前公开构件:Next.js16.3.4;React19.3.0-canary-cbb046ab-20260731。 | observed | high |
| 构建与服务端渲染 | Turbopack运行时;Next App Router/appDir:true及Flight载荷;返回预渲染HTML。 | observed | high |
| 业务后端语言 | api.liblib.tv与im.liblib.tv业务后端语言未知;Next前端不能证明全部业务API为Node.js。 | unknown | low |
| 业务后端框架 | 业务后端框架与版本未知;istio-envoy只说明入口banner,不说明应用框架。 | unknown | low |
| 分发层与源站线索 | Web/API入口域分别指向北京命名的阿里API Gateway/NLB;静态与媒体走独立CDN。上游源站未知。 | observed | high |
| 代码仓库与目录关系 | apps/liblibtv/src是前端路径线索,可能采用多应用目录;前后端是否同仓或同目录未知。 | inferred | medium |
竞品服务调用图
一次匿名Skill查询证明JSON目录;公开客户端分别定义Canvas HTTP、Agent会话HTTP和IM WebSocket。运行/生成职责仅推断,两个Project及两类Session映射仍未知。
| 节点 | 层 | 职责 | 证据 |
|---|---|---|---|
| Web浏览器 | client | Skill、Canvas和Agent的发布客户端。 | C |
| Web入口网关 | entry | www.liblib.tv匿名HTML入口;API Gateway DNS与istio-envoy banner。 | O |
| 静态脚本CDN | entry | 独立官方静态JS入口与Tengine/cache响应。 | O |
| 业务HTTP入口 | entry | api.liblib.tv承接已观测Skill请求及客户端业务路由基址。 | O |
| IM与WS入口 | entry | im.liblib.tv的会话HTTP与/ws客户端连接入口。 | C |
| Skill目录资料 | domain | 匿名列表包含Skill身份、version/snapshotId和案例。 | O |
| Canvas编辑职责 | domain | projectUuid、nodes/connections、draft/config与版本路由的逻辑职责。 | C |
| 会话消息资料 | data | AgentProject、ChatSession、Message与afterSeq的客户端资源关系。 | C |
| Agent执行职责 | runtime | 解释run事件与增量消息的可能运行或代理职责。 | I |
| 生成处理职责 | runtime | 解释generation任务、进度与产物结果的可能执行/代理职责。 | I |
| 素材产物资料 | data | 媒体资源、个人/团队复制与artifact列表的逻辑结果模型。 | C |
| 媒体分发入口 | external | libtv-res.liblib.art公开媒体CNAME及客户端资源地址线索。 | O |
增长与运营机制
复刻状态
| 能力 | 状态 | 依据 |
|---|---|---|
| 首页与顶栏(会员入口 + 免费使用/账号) | 已验证 | 去掉不属于实站的促销条;登录前显示「免费使用」并打开登录框 |
| 工作区条、登录框、新建项目/会话框 | 已验证 | 统一为 LibTV 深色令牌 |
| TV Director 对话 | 已验证 | 新建项目→新建会话→自动选默认模型→发送→收到回复 |
| 停止回复与「已停止」标记 | 已验证 | maa_run_stop_actions=terminal_observed,run=cancelled |
| 节点画布、故事板、Skill 社区 | 已加载 | 沿用早期静态页,没有对照实站逐项核对 |
| 生成视频(报价→批准→成片) | 已验证 | 测试部署 119.23.106.60:8104 上真实生成:Seedance 2.0 Mini 5 秒,报价 3 积分,批准后任务成功、产出 MP4(接口级验证;素材页展示未逐项核对) |
| 素材页 | 未验证 | 没有对照实站逐项核对 |
agent-integration/apps-production-brand-v14/libtv/candidate-8875-unified-v22.html复刻的架构 七个品牌相同,展开查看
flowchart LR U[浏览器] -->|静态页| FE[品牌前端<br/>令牌 + 通用层 + 运行时脚本] FE -->|/v1/* Cookie + CSRF| BFF[BFF 业务服务 Go] BFF --> MY[(MySQL<br/>共享身份库 + 品牌库)] BFF -->|会话 / 消息 / 事件| MAA[Maa Agent] BFF -->|任务| WK[媒体 worker] WK -->|submit_video| GW[模型网关] GW --> MOD[视频模型] MAA --> GW BFF --> OBJ[(素材 / 导出存储)]
?profile=libtv 区分品牌)。品牌差异在前端:令牌(颜色、圆角、字体)、入口与页面结构。LibTV · Agent 交互过程
竞品里观察到的
NOT_RUN_COST_GATE 已登录独立虚构测试画布中准备纯文字对话。
| 编号 | 操作 | 结果 |
|---|---|---|
| LT11-D01 | 打开 TV Director 全局设置 | 推理实时消耗积分,素材生成积分另计;普通文字不能当免费。 |
| LT11-D02 | 查看执行与预算设置 | 自动生成关闭;预算开启,阈值1000。说明达到阈值提醒,非硬预算阻断。没有改变任何开关或阈值。 |
| LT11-D03 | 填写统一纯文字需求 | 输入成功且Send可用,未提交。 |
| LT11-D04 | 停止收费入口体验并清空准备的输入 | 输入框已清空,没有发送。保持原预算提醒阈值及自动生成设置;20积分未变。 |
对话维度
| 维度 | 观察 |
|---|---|
| clarification | NOT_RUN |
| plan | NOT_RUN |
| action_confirmation | 只观察手动/自动菜单,不是对话执行确认 |
| targeted_revision | NOT_RUN |
| tool_calls | NOT_RUN |
| artifacts | NOT_RUN |
| history_resume | 本轮没有对话生成历史可恢复 |
费用与准入
| 项 | 值 |
|---|---|
| before_visible_credits | 20 |
| after_visible_credits | 20 |
| ledger_verified | false |
| text_inference_free | false |
| automatic_media_enabled | false |
| budget_reminder_enabled | true |
| observed_reminder_threshold | 1000 |
| hard_cap_verified | false |
| authorized_spend | 0 |
| observed_cost_statement | TV Director 推理将实时消耗积分,素材生成积分另计。 |
对我们设计的启示
| 结论 | 内容 | 做法 / 原因 |
|---|---|---|
| adapt | 向用户分别展示文字推理成本与媒体任务成本,不标文字为免费。 | 须将现有 LLM 用量与媒体预扣账本在 UI 分开展示,并在平台内落实硬预算。 |
| reject | 不复制仅提醒阈值作为本平台最大预算约束。 | 达到提醒阈值不等于阻止下一笔扣费或取消在途费用。 |
竞品公开的调用流程
| 步骤 | 调用关系 | 操作 | 证据 |
|---|---|---|---|
| 加载Web与脚本 | 浏览器 → Web入口 | GET https://www.liblib.tv/;返回HTML并加载liblibai-web-static.liblib.cloud官方JS;入口与静态资源响应分别为istio-envoy/Tengine。 | O |
| 查询Skill模板 | 浏览器 → 业务HTTP入口 | POST https://api.liblib.tv/api/community/skill/template/feed/stream;body含page/pageSize/query/tagId;返回JSON list/hasMore/total与skillKey/version/snapshot | O |
| 读取Canvas上下文 | 浏览器 → 业务HTTP入口 | 客户端GET /api/canvas/project/detail,uuid来自projectUuid;Skill引用在session create中可携带skillKey/skillVersion,画布draft与版本由独立路由管理。 | C |
| 加载或创建会话 | 浏览器 → IM入口 | GET https://im.liblib.tv/api/v1/project/session/list含projectId/type;POST /api/v1/project/session/create含projectId/name及可选canvasId/nodeKey/skillKey/ski | C |
| 发送Agent消息 | 浏览器 → IM入口 | 客户端构造wss://im.liblib.tv/ws;query字段名含token/project_id及可选canvas_id/team_id;上行JSON有threadId/messages/forwardedProps.extra。 | C |
| 消费增量事件 | IM入口 → 浏览器 | 客户端消费RUN_STARTED、TEXT_MESSAGE_START/CONTENT/END及type/seq/runId/messageId/role/delta;处理ping/pong、重连与缓存入站事件。 | C |
| 保存画布修改 | 浏览器 → 业务HTTP入口 | POST /api/canvas/nodes/batch含projectUuid/requestId/nodes与connections增改删;POST draft/update含draftJson/canvasConfigJson/viewport坐标;编辑上下文可带sessionId/times | C |
| 读取生成与产物 | 浏览器 → 业务HTTP入口 | 客户端存在/api/task/generation/create、progress、power/calculator与/api/task/artifact/list,以及媒体创建/list/copy-to-team等路径。 | C |
在本品牌复刻上的测试结果
| 能力 | 状态 | 依据 |
|---|---|---|
| TV Director 对话 | 已验证 | 新建项目→新建会话→自动选默认模型→发送→收到回复 |
| 停止回复与「已停止」标记 | 已验证 | maa_run_stop_actions=terminal_observed,run=cancelled |
| 生成视频(报价→批准→成片) | 已验证 | 测试部署 119.23.106.60:8104 上真实生成:Seedance 2.0 Mini 5 秒,报价 3 积分,批准后任务成功、产出 MP4(接口级验证;素材页展示未逐项核对) |
复刻里的 Agent 交互设计(时序图、状态机、规则) 七个品牌相同,展开查看
sequenceDiagram
autonumber
participant B as 浏览器
participant S as BFF
participant DB as MySQL
participant M as Maa Agent
participant W as 媒体 worker
participant G as 模型网关
B->>S: POST /projects, /conversations
B->>S: POST maa/binding
S->>DB: maa_bindings dispatching
S->>M: 创建原生会话
M-->>S: native_cid
S->>DB: maa_bindings bound
B->>S: POST maa/messages {client_action_id, content}
S->>DB: maa_message_actions 幂等回执
S-->>B: 202 + run_id
S->>M: 提交消息
S->>DB: maa_runs queued 到 running
loop 事件游标
B->>S: GET runs/{id}/events
S-->>B: assistant.delta / assistant.message
end
M-->>S: run.completed
S->>DB: 记录助手内容 SHA-256
B->>S: POST media/requests/from-maa {source_run_id, sha256}
S-->>B: 报价 + 有效期 + quote_sha256
B->>S: POST approve {client_approval_id, request_sha256, quote_sha256}
S->>DB: 冻结积分 + 建任务
W->>G: submit_video
G-->>W: 视频
W->>DB: 产出入库 + 扣费
B->>S: GET media/jobs/{id}Run 状态机
stateDiagram-v2 [*] --> queued: POST maa/messages 202 queued --> running running --> waiting_interaction: 需要澄清卡 waiting_interaction --> running: respondInteraction running --> completed running --> failed running --> cancelled: stopRun waiting_interaction --> cancelled completed --> [*] failed --> [*] cancelled --> [*]
媒体任务状态机
stateDiagram-v2 [*] --> quoted quoted --> expired: 约 5 分钟 quoted --> approved: approve approved --> held: 冻结积分 held --> queued queued --> running: worker 领取 running --> succeeded: 产出入库 succeeded --> captured: 扣费确认 running --> failed failed --> 待核对: 供应商已受理后失败,冻结保留,界面写「费用待核对」
交互规则
| 环节 | 规则 | 落库 |
|---|---|---|
| 绑定会话 | bindMaa 传 agent_model 或 use_default;先 dispatching,拿到原生会话号后才 bound(约束保证二者一致) | maa_bindings |
| 发消息 | client_action_id 幂等;返回 202 + run_id;同一个动作 ID 内容不同返回 409 | maa_message_actions, maa_runs |
| 事件 | 按 seq 游标读取;服务端先清洗路径、内部地址和令牌再公开 | maa_runs.last_event_seq |
| 完成证据 | 完成时记录助手内容的两份 SHA-256 与字节数 | maa_runs |
| 澄清卡(HITL) | Run 进入 waiting_interaction;respondInteraction 带 card_sha256;不能恢复两次 | maa_interactions, maa_interaction_actions |
| 停止 | stopRun 幂等,回执只说「已观测到终态」;对话里保留「已停止回复」 | maa_run_stop_actions |
| 切换模型 | 必须带 expected_revision;有未决切换时拒绝发新消息 | maa_model_change_actions |
| 生成视频 | from-maa → 报价 → 批准 → 冻结 → worker → 入库 → 扣费;批准带请求哈希与报价哈希 | studio_media_*, 积分账本 |
| 报价过期 | 批准被拒,不建任务不扣费;界面提示重新报价 | studio_media_requests.expires_at |
| 失败后的积分 | 供应商已受理后失败:冻结保留,界面写「费用待核对」,不自动释放;本部署的账本里还没出现过释放分录(12 笔冻结、8 笔扣费、其余 4 笔仍冻结) | studio_credit_ledger_entries |
| 会话过期 | 每 8 秒检查登录状态;失效时横幅提示,登录后恢复 | — |
LibTV · ER 图
品牌库 studio_profile_libtv:24 张表、34 个真实外键、66 个检查约束、22 个触发器。图由实际表结构生成,箭头从父表指向子表。品牌库与共享身份库之间的 owner_id、asset_id 靠应用层归属检查,不画成外键。
共 61 条关系:一对多 37 条,一对一 10 条,一对多(父可选) 10 条,一对一(父可选) 4 条;多对多 2 组(经关联表)。
用户与登录 素材 积分账本 支付与订阅 模型目录 项目与会话 画布 · 时间轴 · 导出 Agent 交互 生成 · 媒体 · 交付
基数标注(线上的文字,箭头从父表指向子表):1:N 一对多,子表外键必填;0..1:N 一对多,但外键可空,所以父是可选的;1:1 一对一,子表外键上有唯一键;0..1:1 一对一且父可选。红色粗双向线 = N:M 多对多,经带 ⇄ 的关联表(它的主键就是两个外键)。实线 = 数据库真实外键;灰色虚线 = 跨库关系(两个库之间数据库无法建外键,由应用层检查);橙色粗框与粗线 = Agent 交互相关。每张表都带 owner_id(指向用户),为了图清楚没有逐条画线。
全景图:全部实体与关系
默认缩放到页面宽度,先看整体结构;点一下图切换到原始大小(看清表名,在框内上下左右滚动),再点一下缩回。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":26,"rankSpacing":80}}}%%
flowchart LR
subgraph sg_i_user["用户与登录"]
direction TB
t_studio_users["users"]
t_studio_sessions["sessions"]
end
subgraph sg_i_asset["素材"]
direction TB
t_studio_assets["assets"]
end
subgraph sg_i_credit["积分账本"]
direction TB
t_studio_credit_accounts["credit_accounts"]
t_studio_credit_lots["credit_lots"]
t_studio_credit_authorizations["credit_authorizations"]
t_studio_credit_authorization_allocations["⇄ credit_authorization_allocations"]
t_studio_credit_ledger_entries["credit_ledger_entries"]
t_studio_credit_plan_versions["credit_plan_versions"]
t_studio_billing_cycles["billing_cycles"]
end
subgraph sg_i_pay["支付与订阅"]
direction TB
t_studio_payment_orders["payment_orders"]
t_studio_payment_events["payment_events"]
t_studio_subscriptions["subscriptions"]
end
subgraph sg_i_model["模型目录"]
direction TB
t_studio_media_models["media_models"]
t_studio_media_model_versions["media_model_versions"]
end
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_canvas["画布 · 时间轴 · 导出"]
direction TB
t_studio_video_documents["video_documents"]
t_studio_canvases["canvases"]
t_studio_canvas_revisions["canvas_revisions"]
t_studio_timeline_revisions["timeline_revisions"]
t_studio_export_jobs["export_jobs"]
t_studio_project_asset_refs["⇄ project_asset_refs"]
end
subgraph sg_agent["⭕ Agent 交互"]
direction TB
t_maa_bindings["maa_bindings"]
t_maa_runs["maa_runs"]
t_maa_message_actions["maa_message_actions"]
t_maa_interactions["maa_interactions"]
t_maa_interaction_actions["maa_interaction_actions"]
t_maa_model_change_actions["maa_model_change_actions"]
t_maa_run_stop_actions["maa_run_stop_actions"]
end
subgraph sg_media["生成 · 媒体 · 交付"]
direction TB
t_studio_media_requests["media_requests"]
t_studio_media_jobs["media_jobs"]
t_studio_media_submission_attempts["media_submission_attempts"]
t_studio_media_outputs["media_outputs"]
t_generation_jobs["gen_jobs"]
t_generation_reservations["gen_reservations"]
t_generation_deliveries["gen_deliveries"]
t_generation_development_budgets["gen_development_budgets"]
t_studio_credit_recovery_intents["credit_recovery_intents"]
end
t_studio_users -->|"1:N"| t_studio_assets
t_studio_payment_orders -->|"1:1"| t_studio_billing_cycles
t_studio_subscriptions -->|"1:N"| t_studio_billing_cycles
t_studio_users -->|"1:1"| t_studio_credit_accounts
t_studio_credit_authorizations -->|"1:N"| t_studio_credit_authorization_allocations
t_studio_credit_lots -->|"1:N"| t_studio_credit_authorization_allocations
t_studio_credit_accounts -->|"1:N"| t_studio_credit_authorizations
t_studio_credit_authorization_allocations -->|"0..1:N"| t_studio_credit_ledger_entries
t_studio_credit_authorizations -->|"0..1:N"| t_studio_credit_ledger_entries
t_studio_credit_lots -->|"1:N"| t_studio_credit_ledger_entries
t_studio_credit_accounts -->|"1:N"| t_studio_credit_lots
t_studio_billing_cycles -->|"0..1:1"| t_studio_credit_lots
t_studio_payment_orders -->|"0..1:1"| t_studio_credit_lots
t_studio_media_models -->|"1:N"| t_studio_media_model_versions
t_studio_media_model_versions -->|"0..1:1"| t_studio_media_models
t_studio_payment_orders -->|"0..1:N"| t_studio_payment_events
t_studio_subscriptions -->|"0..1:N"| t_studio_payment_events
t_studio_users -->|"1:N"| t_studio_payment_events
t_studio_credit_plan_versions -->|"1:N"| t_studio_payment_orders
t_studio_users -->|"1:N"| t_studio_payment_orders
t_studio_users -->|"1:N"| t_studio_sessions
t_studio_credit_plan_versions -->|"1:N"| t_studio_subscriptions
t_studio_users -->|"1:N"| t_studio_subscriptions
t_generation_jobs -->|"1:1"| t_generation_deliveries
t_studio_projects -->|"1:N"| t_generation_deliveries
t_studio_conversations -->|"1:N"| t_generation_deliveries
t_generation_development_budgets -->|"1:N"| t_generation_jobs
t_studio_projects -->|"1:N"| t_generation_jobs
t_studio_conversations -->|"1:N"| t_generation_jobs
t_generation_jobs -->|"1:1"| t_generation_reservations
t_studio_conversations -->|"1:1"| t_maa_bindings
t_maa_model_change_actions -->|"0..1:1"| t_maa_bindings
t_maa_interactions -->|"1:1"| t_maa_interaction_actions
t_maa_runs -->|"1:N"| t_maa_interactions
t_maa_bindings -->|"1:N"| t_maa_message_actions
t_maa_runs -->|"0..1:N"| t_maa_message_actions
t_maa_bindings -->|"1:N"| t_maa_model_change_actions
t_maa_runs -->|"1:1"| t_maa_run_stop_actions
t_maa_bindings -->|"1:N"| t_maa_runs
t_studio_canvases -->|"1:N"| t_studio_canvas_revisions
t_studio_canvas_revisions -->|"0..1:N"| t_studio_canvas_revisions
t_studio_projects -->|"1:1"| t_studio_canvases
t_studio_projects -->|"1:N"| t_studio_conversations
t_studio_media_jobs -->|"1:N"| t_studio_credit_recovery_intents
t_studio_projects -->|"1:N"| t_studio_export_jobs
t_studio_media_requests -->|"1:1"| t_studio_media_jobs
t_studio_media_jobs -->|"1:N"| t_studio_media_outputs
t_studio_conversations -->|"1:N"| t_studio_media_requests
t_maa_runs -->|"0..1:N"| t_studio_media_requests
t_studio_media_jobs -->|"1:N"| t_studio_media_submission_attempts
t_studio_projects -->|"1:N"| t_studio_project_asset_refs
t_studio_video_documents -->|"1:N"| t_studio_timeline_revisions
t_studio_timeline_revisions -->|"0..1:N"| t_studio_timeline_revisions
t_studio_projects -->|"1:1"| t_studio_video_documents
t_studio_assets -.->|"1:N"| t_studio_project_asset_refs
t_studio_assets -.->|"1:N"| t_studio_media_outputs
t_studio_assets -.->|"1:N"| t_generation_deliveries
t_studio_media_model_versions -.->|"1:N"| t_studio_media_requests
t_studio_media_models -.->|"1:N"| t_studio_media_requests
t_studio_credit_authorizations -.->|"0..1:N"| t_studio_media_jobs
t_studio_credit_authorizations -.->|"0..1:N"| t_studio_credit_recovery_intents
t_studio_credit_authorizations <-.->|"N:M · 经 credit_authorization_allocations"| t_studio_credit_lots
t_studio_projects <-.->|"N:M · 经 project_asset_refs"| t_studio_assets
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_users,t_studio_sessions user
class t_studio_assets asset
class t_studio_credit_accounts,t_studio_credit_lots,t_studio_credit_authorizations,t_studio_credit_authorization_allocations,t_studio_credit_ledger_entries,t_studio_credit_plan_versions,t_studio_billing_cycles credit
class t_studio_payment_orders,t_studio_payment_events,t_studio_subscriptions pay
class t_studio_media_models,t_studio_media_model_versions model
class t_studio_projects,t_studio_conversations project
class t_studio_video_documents,t_studio_canvases,t_studio_canvas_revisions,t_studio_timeline_revisions,t_studio_export_jobs,t_studio_project_asset_refs canvas
class t_maa_bindings,t_maa_runs,t_maa_message_actions,t_maa_interactions,t_maa_interaction_actions,t_maa_model_change_actions,t_maa_run_stop_actions agent
class t_studio_media_requests,t_studio_media_jobs,t_studio_media_submission_attempts,t_studio_media_outputs,t_generation_jobs,t_generation_reservations,t_generation_deliveries,t_generation_development_budgets,t_studio_credit_recovery_intents media
class t_studio_credit_authorization_allocations,t_studio_project_asset_refs junction
style sg_i_user fill:none,stroke:#6b7280,stroke-width:1px,stroke-dasharray:5 4
style sg_i_asset fill:none,stroke:#06b6d4,stroke-width:1px,stroke-dasharray:5 4
style sg_i_credit fill:none,stroke:#eab308,stroke-width:1px,stroke-dasharray:5 4
style sg_i_pay fill:none,stroke:#ec4899,stroke-width:1px,stroke-dasharray:5 4
style sg_i_model fill:none,stroke:#6366f1,stroke-width:1px,stroke-dasharray:5 4
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_canvas fill:none,stroke:#3b82f6,stroke-width:1px
style sg_agent fill:#fff7ed,stroke:#f97316,stroke-width:4px
style sg_media fill:none,stroke:#22c55e,stroke-width:1px
linkStyle 30,31,32,33,34,35,36,37,38,48 stroke:#f97316,stroke-width:2.5px
linkStyle 54,55,56,57,58,59,60 stroke:#64748b,stroke-width:1.5px,stroke-dasharray:4 3
linkStyle 61,62 stroke:#dc2626,stroke-width:3px多对多(N:M)
数据库里没有“多对多”这种列,它总是靠一张关联表表达。下面这几张表的主键由两个外键组成,所以它们两端是多对多:
| 多对多的两端 | 关联表 | 关联表的主键 / 唯一键 |
|---|---|---|
studio_credit_authorizations ⇄ studio_credit_lots | studio_credit_authorization_allocations | owner_id, authorization_id, lot_id |
studio_projects ⇄ studio_assets | studio_project_asset_refs | project_id, asset_id |
Agent 交互相关(圈出来)
绑定 → Run → 消息 / 澄清卡 / 切换模型 / 停止,每个动作一张回执表;线上是“外键列 · 基数”。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":40,"rankSpacing":90}}}%%
flowchart LR
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_agent["⭕ Agent 交互"]
direction TB
t_maa_bindings["maa_bindings"]
t_maa_runs["maa_runs"]
t_maa_message_actions["maa_message_actions"]
t_maa_interactions["maa_interactions"]
t_maa_interaction_actions["maa_interaction_actions"]
t_maa_model_change_actions["maa_model_change_actions"]
t_maa_run_stop_actions["maa_run_stop_actions"]
end
t_studio_conversations -->|"conversation_id · 1:1"| t_maa_bindings
t_maa_model_change_actions -->|"pending_model_change_id · 0..1:1"| t_maa_bindings
t_maa_interactions -->|"interaction_id · 1:1"| t_maa_interaction_actions
t_maa_runs -->|"public_run_id · 1:N"| t_maa_interactions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_message_actions
t_maa_runs -->|"public_run_id · 0..1:N"| t_maa_message_actions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_model_change_actions
t_maa_runs -->|"public_run_id · 1:1"| t_maa_run_stop_actions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_runs
t_studio_projects -->|"project_id · 1:N"| t_studio_conversations
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_projects,t_studio_conversations project
class t_maa_bindings,t_maa_runs,t_maa_message_actions,t_maa_interactions,t_maa_interaction_actions,t_maa_model_change_actions,t_maa_run_stop_actions agent
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_agent fill:#fff7ed,stroke:#f97316,stroke-width:4px
linkStyle 0,1,2,3,4,5,6,7,8 stroke:#f97316,stroke-width:2.5px画布与时间轴
项目下是一份视频文档,画布、画布版本、时间线版本和导出都挂在这份文档上;素材放在共享身份库,项目只记引用,项目与素材是多对多,经 project_asset_refs。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":40,"rankSpacing":90}}}%%
flowchart LR
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_canvas["画布 · 时间轴 · 导出"]
direction TB
t_studio_video_documents["video_documents"]
t_studio_canvases["canvases"]
t_studio_canvas_revisions["canvas_revisions"]
t_studio_timeline_revisions["timeline_revisions"]
t_studio_export_jobs["export_jobs"]
t_studio_project_asset_refs["⇄ project_asset_refs"]
end
subgraph sg_asset["素材(共享身份库)"]
direction TB
t_studio_assets["assets"]
end
t_studio_canvases -->|"project_id · 1:N"| t_studio_canvas_revisions
t_studio_canvas_revisions -->|"restored_from_revision · 0..1:N"| t_studio_canvas_revisions
t_studio_projects -->|"project_id · 1:1"| t_studio_canvases
t_studio_projects -->|"project_id · 1:N"| t_studio_conversations
t_studio_projects -->|"project_id · 1:N"| t_studio_export_jobs
t_studio_projects -->|"project_id · 1:N"| t_studio_project_asset_refs
t_studio_video_documents -->|"project_id · 1:N"| t_studio_timeline_revisions
t_studio_timeline_revisions -->|"restored_from_revision · 0..1:N"| t_studio_timeline_revisions
t_studio_projects -->|"project_id · 1:1"| t_studio_video_documents
t_studio_assets -.->|"asset_id · 1:N"| t_studio_project_asset_refs
t_studio_projects <-.->|"N:M · 经 project_asset_refs"| t_studio_assets
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_projects,t_studio_conversations project
class t_studio_video_documents,t_studio_canvases,t_studio_canvas_revisions,t_studio_timeline_revisions,t_studio_export_jobs,t_studio_project_asset_refs canvas
class t_studio_assets asset
class t_studio_project_asset_refs junction
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_canvas fill:none,stroke:#3b82f6,stroke-width:1px
style sg_asset fill:none,stroke:#06b6d4,stroke-width:1px
linkStyle 9 stroke:#64748b,stroke-width:1.5px,stroke-dasharray:4 3
linkStyle 10 stroke:#dc2626,stroke-width:3px关系清单 逐条 61 条,含基数
| 父表 | 子表 | 外键列(子表里) | 基数 | 约束 | 域 |
|---|---|---|---|---|---|
generation_jobs | generation_deliveries | job_id | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_assets | generation_deliveries | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 生成 · 媒体 · 交付 |
studio_conversations | generation_deliveries | owner_id, project_id, session_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_projects | generation_deliveries | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
generation_development_budgets | generation_jobs | owner_id, budget_id | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_conversations | generation_jobs | owner_id, project_id, session_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_projects | generation_jobs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
generation_jobs | generation_reservations | job_id, budget_id, owner_id | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
maa_model_change_actions | maa_bindings | owner_id, project_id, conversation_id, id, pending_model_change_id | 0..1:1 一对一(父可选) | DB 外键 | Agent 交互 → Agent 交互 |
studio_conversations | maa_bindings | owner_id, project_id, conversation_id | 1:1 一对一 | DB 外键 | 项目与会话 → Agent 交互 |
maa_interactions | maa_interaction_actions | owner_id, project_id, conversation_id, binding_id, public_run_id, interaction_id | 1:1 一对一 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_interactions | owner_id, project_id, conversation_id, binding_id, public_run_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_message_actions | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_message_actions | owner_id, project_id, conversation_id, binding_id, public_run_id | 0..1:N 一对多(父可选) | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_model_change_actions | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_run_stop_actions | owner_id, project_id, conversation_id, binding_id, public_run_id | 1:1 一对一 | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_runs | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
studio_users | studio_assets | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 素材 |
studio_payment_orders | studio_billing_cycles | owner_id, payment_order_id, plan_version_id | 1:1 一对一 | DB 外键 | 支付与订阅 → 积分账本 |
studio_subscriptions | studio_billing_cycles | owner_id, subscription_id, provider_key, provider_account | 1:N 一对多 | DB 外键 | 支付与订阅 → 积分账本 |
studio_canvas_revisions | studio_canvas_revisions | owner_id, project_id, kind, restored_from_revision | 0..1:N 一对多(父可选) | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_canvases | studio_canvas_revisions | owner_id, project_id | 1:N 一对多 | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_projects | studio_canvases | owner_id, project_id | 1:1 一对一 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_projects | studio_conversations | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 项目与会话 |
studio_users | studio_credit_accounts | owner_id | 1:1 一对一 | DB 外键 | 用户与登录 → 积分账本 |
studio_credit_authorizations | studio_credit_authorization_allocations | owner_id, authorization_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_lots | studio_credit_authorization_allocations | owner_id, lot_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_accounts | studio_credit_authorizations | owner_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_authorization_allocations | studio_credit_ledger_entries | owner_id, authorization_id, lot_id | 0..1:N 一对多(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_authorizations | studio_credit_ledger_entries | owner_id, authorization_id | 0..1:N 一对多(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_lots | studio_credit_ledger_entries | owner_id, lot_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_billing_cycles | studio_credit_lots | owner_id, source_cycle_id | 0..1:1 一对一(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_accounts | studio_credit_lots | owner_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_payment_orders | studio_credit_lots | owner_id, source_order_id | 0..1:1 一对一(父可选) | DB 外键 | 支付与订阅 → 积分账本 |
studio_credit_authorizations | studio_credit_recovery_intents | authorization_id | 0..1:N 一对多(父可选) | 跨库(应用层检查) | 积分账本 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_credit_recovery_intents | owner_id, project_id, conversation_id, job_id, request_sha256 | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_projects | studio_export_jobs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_credit_authorizations | studio_media_jobs | credit_authorization_id | 0..1:N 一对多(父可选) | 跨库(应用层检查) | 积分账本 → 生成 · 媒体 · 交付 |
studio_media_requests | studio_media_jobs | owner_id, project_id, conversation_id, request_id, request_sha256, quote_sha256 | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_media_models | studio_media_model_versions | model_id | 1:N 一对多 | DB 外键 | 模型目录 → 模型目录 |
studio_media_model_versions | studio_media_models | id, published_version_id | 0..1:1 一对一(父可选) | DB 外键 | 模型目录 → 模型目录 |
studio_assets | studio_media_outputs | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_media_outputs | owner_id, project_id, conversation_id, job_id | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
maa_runs | studio_media_requests | owner_id, project_id, conversation_id, source_binding_id, source_run_id | 0..1:N 一对多(父可选) | DB 外键 | Agent 交互 → 生成 · 媒体 · 交付 |
studio_conversations | studio_media_requests | owner_id, project_id, conversation_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_media_model_versions | studio_media_requests | model_version_id | 1:N 一对多 | 跨库(应用层检查) | 模型目录 → 生成 · 媒体 · 交付 |
studio_media_models | studio_media_requests | model_id | 1:N 一对多 | 跨库(应用层检查) | 模型目录 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_media_submission_attempts | owner_id, project_id, conversation_id, job_id, request_sha256 | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_payment_orders | studio_payment_events | owner_id, order_id, provider_key, provider_account | 0..1:N 一对多(父可选) | DB 外键 | 支付与订阅 → 支付与订阅 |
studio_subscriptions | studio_payment_events | owner_id, subscription_id, provider_key, provider_account | 0..1:N 一对多(父可选) | DB 外键 | 支付与订阅 → 支付与订阅 |
studio_users | studio_payment_events | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_credit_plan_versions | studio_payment_orders | plan_version_id | 1:N 一对多 | DB 外键 | 积分账本 → 支付与订阅 |
studio_users | studio_payment_orders | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_assets | studio_project_asset_refs | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 画布 · 时间轴 · 导出 |
studio_projects | studio_project_asset_refs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_users | studio_sessions | user_id | 1:N 一对多 | DB 外键 | 用户与登录 → 用户与登录 |
studio_credit_plan_versions | studio_subscriptions | plan_version_id | 1:N 一对多 | DB 外键 | 积分账本 → 支付与订阅 |
studio_users | studio_subscriptions | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_timeline_revisions | studio_timeline_revisions | owner_id, project_id, kind, restored_from_revision | 0..1:N 一对多(父可选) | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_video_documents | studio_timeline_revisions | owner_id, project_id | 1:N 一对多 | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_projects | studio_video_documents | owner_id, project_id | 1:1 一对一 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
完整 ER:39 张表的全部列,带主键 / 外键与基数符号(鸦脚)
erDiagram
studio_assets {
CHAR id PK
CHAR owner_id FK
CHAR sha256
JSON metadata_json
VARCHAR storage_key
DATETIME created_at
VARCHAR publication_state
}
studio_billing_cycles {
CHAR id PK
CHAR owner_id FK
CHAR subscription_id FK
CHAR plan_version_id FK
CHAR payment_order_id FK
VARCHAR provider_key FK
VARCHAR provider_account FK
VARCHAR provider_invoice_id
DATETIME period_start
DATETIME period_end
BIGINT_UNSIGNED grant_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
VARCHAR state
CHAR paid_evidence_sha256
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_accounts {
CHAR owner_id PK
VARCHAR unit
VARCHAR status
BIGINT_UNSIGNED revision
DATETIME updated_at
}
studio_credit_authorization_allocations {
CHAR owner_id FK
CHAR authorization_id PK
CHAR lot_id PK
BIGINT_UNSIGNED allocated_credits
DATETIME created_at
}
studio_credit_authorizations {
CHAR id PK
CHAR owner_id FK
VARCHAR profile
CHAR project_id
CHAR conversation_id
CHAR job_id
CHAR request_id
CHAR request_sha256
CHAR quote_sha256
BIGINT_UNSIGNED credits
DATETIME expires_at
MEDIUMBLOB reservation_bytes
CHAR reservation_sha256
MEDIUMBLOB policy_bytes
CHAR policy_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_ledger_entries {
CHAR id PK
CHAR owner_id FK
CHAR lot_id FK
CHAR authorization_id FK
VARCHAR operation_key
VARCHAR kind
BIGINT grant_delta
BIGINT held_delta
BIGINT captured_delta
MEDIUMBLOB facts_bytes
CHAR facts_sha256
DATETIME created_at
}
studio_credit_lots {
CHAR id PK
CHAR owner_id FK
BIGINT_UNSIGNED grant_credits
BIGINT_UNSIGNED held_credits
BIGINT_UNSIGNED captured_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
CHAR source_order_id FK
CHAR source_cycle_id FK
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_plan_versions {
CHAR id PK
VARCHAR plan_key
VARCHAR version_key
VARCHAR kind
BIGINT_UNSIGNED price_minor
CHAR currency
BIGINT_UNSIGNED grant_credits
INT_UNSIGNED credit_validity_seconds
INT_UNSIGNED billing_interval_months
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
DATETIME published_at
DATETIME retired_at
}
studio_media_model_versions {
CHAR id PK
CHAR model_id FK
VARCHAR version_key
MEDIUMBLOB config_bytes
CHAR config_sha256
DATETIME published_at
}
studio_media_models {
CHAR id PK
VARCHAR model_key
VARCHAR kind
VARCHAR display_name
VARCHAR status
CHAR published_version_id FK
BIGINT_UNSIGNED revision
DATETIME updated_at
}
studio_payment_events {
CHAR id PK
CHAR owner_id FK
VARCHAR provider_key FK
VARCHAR provider_account FK
VARCHAR provider_event_id
CHAR order_id FK
CHAR subscription_id FK
MEDIUMBLOB body_bytes
CHAR body_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_payment_orders {
CHAR id PK
CHAR owner_id FK
CHAR client_action_id
CHAR plan_version_id FK
BIGINT_UNSIGNED price_minor
CHAR currency
BIGINT_UNSIGNED grant_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
VARCHAR provider_key
VARCHAR provider_account
VARCHAR provider_idempotency_key
VARCHAR provider_order_id
VARCHAR state
CHAR paid_evidence_sha256
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_sessions {
CHAR token_hash PK
CHAR user_id FK
DATETIME created_at
DATETIME expires_at
DATETIME revoked_at
}
studio_subscriptions {
CHAR id PK
CHAR owner_id FK
VARCHAR provider_key
VARCHAR provider_account
VARCHAR provider_subscription_id
CHAR plan_version_id FK
VARCHAR state
DATETIME period_start
DATETIME period_end
TINYINT cancel_at_period_end
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_users {
CHAR id PK
VARCHAR email
VARBINARY password_hash
TINYINT enabled
DATETIME created_at
}
generation_deliveries {
CHAR job_id PK
CHAR owner_id FK
CHAR project_id FK
CHAR session_id FK
CHAR asset_id FK
CHAR request_sha256
CHAR maa_source_sha256
CHAR provider_source_sha256
VARCHAR model
VARCHAR tool_name
CHAR input_sha256
JSON metadata_json
DATETIME created_at
}
generation_development_budgets {
CHAR id PK
CHAR owner_id
VARCHAR policy_version
BIGINT_UNSIGNED credits_limit
BIGINT_UNSIGNED credits_reserved
INT_UNSIGNED calls_limit
INT_UNSIGNED calls_reserved
DATETIME expires_at
}
generation_jobs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR session_id FK
CHAR native_conversation_id
CHAR native_run_id
CHAR source_sha256
CHAR budget_id FK
MEDIUMBLOB request_bytes
CHAR request_sha256
BIGINT_UNSIGNED credits
DATETIME expires_at
VARCHAR status
INT_UNSIGNED attempts
MEDIUMBLOB result_bytes
DATETIME updated_at
}
generation_reservations {
CHAR job_id PK
CHAR budget_id FK
CHAR owner_id FK
BIGINT_UNSIGNED credits
INT_UNSIGNED calls
VARCHAR status
}
maa_bindings {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR provider
VARCHAR model_name
VARCHAR status
VARCHAR native_cid
DATETIME created_at
BIGINT_UNSIGNED model_revision
CHAR pending_model_change_id FK
}
maa_interaction_actions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR interaction_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_iid
CHAR client_action_id
CHAR card_sha256
CHAR request_sha256
CHAR content_sha256
VARCHAR response_action
JSON values_payload
VARCHAR status
DATETIME created_at
}
maa_interactions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_iid
CHAR card_sha256
JSON card_payload
DATETIME created_at
}
maa_message_actions {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR client_action_id
CHAR request_sha256
MEDIUMTEXT content
VARCHAR status
CHAR public_run_id FK
CHAR proposed_run_id
DATETIME created_at
}
maa_model_change_actions {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_cid
CHAR client_action_id
CHAR request_sha256
CHAR native_request_sha256
BIGINT_UNSIGNED expected_revision
VARCHAR from_provider
VARCHAR from_model_name
VARCHAR target_provider
VARCHAR target_model_name
VARCHAR status
BIGINT_UNSIGNED dispatch_attempt
JSON receipt_payload
DATETIME created_at
DATETIME updated_at
}
maa_run_stop_actions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_cid
VARCHAR native_rid
CHAR client_action_id
CHAR request_sha256
VARCHAR stop_action
VARCHAR status
BIGINT_UNSIGNED attempt
VARCHAR terminal_run_status
DATETIME created_at
DATETIME updated_at
}
maa_runs {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_rid
VARCHAR status
DATETIME created_at
CHAR native_assistant_sha256
CHAR public_assistant_sha256
BIGINT_UNSIGNED native_assistant_bytes
BIGINT_UNSIGNED assistant_event_seq
BIGINT_UNSIGNED last_event_seq
}
studio_canvas_revisions {
CHAR owner_id PK
CHAR project_id PK
VARCHAR kind PK
BIGINT_UNSIGNED revision PK
MEDIUMBLOB state_bytes
CHAR state_sha256
VARCHAR origin
BIGINT_UNSIGNED restored_from_revision FK
DATETIME recorded_at
}
studio_canvases {
CHAR project_id PK
CHAR owner_id FK
BIGINT_UNSIGNED revision
JSON state_json
DATETIME updated_at
}
studio_conversations {
CHAR id PK
CHAR project_id FK
CHAR owner_id FK
VARCHAR title
DATETIME created_at
}
studio_credit_recovery_intents {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
CHAR request_sha256 FK
CHAR quote_sha256
VARCHAR kind
CHAR authorization_id FK
MEDIUMBLOB intent_bytes
CHAR intent_sha256
VARCHAR state
CHAR lease_token_sha256
DATETIME lease_until
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_export_jobs {
CHAR id PK
CHAR project_id FK
CHAR owner_id FK
BIGINT_UNSIGNED document_revision
CHAR input_hash
VARCHAR status
JSON input_json
JSON output_json
VARCHAR error_code
CHAR lease_token_hash
DATETIME lease_until
INT_UNSIGNED attempts
DATETIME created_at
DATETIME updated_at
}
studio_media_jobs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR request_id FK
CHAR request_sha256 FK
CHAR quote_sha256 FK
CHAR client_approval_id
CHAR approval_sha256
CHAR credit_authorization_id FK
VARCHAR authorization_mode
DATETIME authorization_expires_at
VARCHAR status
BIGINT_UNSIGNED revision
CHAR lease_token_sha256
DATETIME lease_until
VARCHAR provider_task_id
CHAR client_cancel_id
CHAR cancel_request_sha256
DATETIME cancel_requested_at
CHAR staged_asset_id
CHAR staged_asset_sha256
DATETIME created_at
DATETIME updated_at
}
studio_media_outputs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
INT_UNSIGNED ordinal
CHAR asset_id FK
CHAR asset_sha256
CHAR asset_metadata_sha256
CHAR provider_result_sha256
DATETIME created_at
}
studio_media_requests {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR client_request_id
CHAR model_id FK
CHAR model_version_id FK
CHAR model_config_sha256
MEDIUMBLOB request_bytes
CHAR request_sha256
MEDIUMBLOB quote_bytes
CHAR quote_sha256
BIGINT_UNSIGNED quoted_credits
DATETIME expires_at
VARCHAR origin
CHAR source_binding_id FK
CHAR source_run_id FK
CHAR source_assistant_sha256
MEDIUMBLOB source_snapshot_bytes
DATETIME created_at
}
studio_media_submission_attempts {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
INT_UNSIGNED attempt_no
CHAR request_sha256 FK
VARCHAR provider_idempotency_key
VARCHAR stage
DATETIME dispatch_started_at
VARCHAR provider_task_id
CHAR receipt_sha256
CHAR terminal_receipt_sha256
CHAR reconciliation_sha256
DATETIME created_at
DATETIME updated_at
}
studio_project_asset_refs {
CHAR project_id PK
CHAR owner_id FK
CHAR asset_id PK
CHAR asset_sha256
CHAR asset_metadata_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
DATETIME detached_at
}
studio_projects {
CHAR id PK
CHAR owner_id
VARCHAR title
DATETIME created_at
}
studio_timeline_revisions {
CHAR owner_id PK
CHAR project_id PK
VARCHAR kind PK
BIGINT_UNSIGNED revision PK
MEDIUMBLOB state_bytes
CHAR state_sha256
VARCHAR origin
BIGINT_UNSIGNED restored_from_revision FK
DATETIME recorded_at
}
studio_video_documents {
CHAR project_id PK
CHAR owner_id FK
BIGINT_UNSIGNED revision
JSON state_json
DATETIME updated_at
}
studio_users ||--o{ studio_assets : "owner_id"
studio_payment_orders ||--o| studio_billing_cycles : "plan_version_id"
studio_subscriptions ||--o{ studio_billing_cycles : "provider_account"
studio_users ||--o| studio_credit_accounts : "owner_id"
studio_credit_authorizations ||--o{ studio_credit_authorization_allocations : "authorization_id"
studio_credit_lots ||--o{ studio_credit_authorization_allocations : "lot_id"
studio_credit_accounts ||--o{ studio_credit_authorizations : "owner_id"
studio_credit_authorization_allocations |o--o{ studio_credit_ledger_entries : "lot_id"
studio_credit_authorizations |o--o{ studio_credit_ledger_entries : "authorization_id"
studio_credit_lots ||--o{ studio_credit_ledger_entries : "lot_id"
studio_credit_accounts ||--o{ studio_credit_lots : "owner_id"
studio_billing_cycles |o--o| studio_credit_lots : "source_cycle_id"
studio_payment_orders |o--o| studio_credit_lots : "source_order_id"
studio_media_models ||--o{ studio_media_model_versions : "model_id"
studio_media_model_versions |o--o| studio_media_models : "published_version_id"
studio_payment_orders |o--o{ studio_payment_events : "provider_account"
studio_subscriptions |o--o{ studio_payment_events : "provider_account"
studio_users ||--o{ studio_payment_events : "owner_id"
studio_credit_plan_versions ||--o{ studio_payment_orders : "plan_version_id"
studio_users ||--o{ studio_payment_orders : "owner_id"
studio_users ||--o{ studio_sessions : "user_id"
studio_credit_plan_versions ||--o{ studio_subscriptions : "plan_version_id"
studio_users ||--o{ studio_subscriptions : "owner_id"
generation_jobs ||--o| generation_deliveries : "job_id"
studio_projects ||--o{ generation_deliveries : "project_id"
studio_conversations ||--o{ generation_deliveries : "session_id"
generation_development_budgets ||--o{ generation_jobs : "budget_id"
studio_projects ||--o{ generation_jobs : "project_id"
studio_conversations ||--o{ generation_jobs : "session_id"
generation_jobs ||--o| generation_reservations : "budget_id"
studio_conversations ||--o| maa_bindings : "conversation_id"
maa_model_change_actions |o--o| maa_bindings : "pending_model_change_id"
maa_interactions ||--o| maa_interaction_actions : "interaction_id"
maa_runs ||--o{ maa_interactions : "public_run_id"
maa_bindings ||--o{ maa_message_actions : "binding_id"
maa_runs |o--o{ maa_message_actions : "public_run_id"
maa_bindings ||--o{ maa_model_change_actions : "binding_id"
maa_runs ||--o| maa_run_stop_actions : "public_run_id"
maa_bindings ||--o{ maa_runs : "binding_id"
studio_canvases ||--o{ studio_canvas_revisions : "project_id"
studio_canvas_revisions |o--o{ studio_canvas_revisions : "restored_from_revision"
studio_projects ||--o| studio_canvases : "project_id"
studio_projects ||--o{ studio_conversations : "project_id"
studio_media_jobs ||--o{ studio_credit_recovery_intents : "job_id"
studio_projects ||--o{ studio_export_jobs : "project_id"
studio_media_requests ||--o| studio_media_jobs : "request_id"
studio_media_jobs ||--o{ studio_media_outputs : "job_id"
studio_conversations ||--o{ studio_media_requests : "conversation_id"
maa_runs |o--o{ studio_media_requests : "source_run_id"
studio_media_jobs ||--o{ studio_media_submission_attempts : "job_id"
studio_projects ||--o{ studio_project_asset_refs : "project_id"
studio_video_documents ||--o{ studio_timeline_revisions : "project_id"
studio_timeline_revisions |o--o{ studio_timeline_revisions : "restored_from_revision"
studio_projects ||--o| studio_video_documents : "project_id"
studio_assets ||--o{ studio_project_asset_refs : "asset_id"
studio_assets ||--o{ studio_media_outputs : "asset_id"
studio_assets ||--o{ generation_deliveries : "asset_id"
studio_media_model_versions ||--o{ studio_media_requests : "model_version_id"
studio_media_models ||--o{ studio_media_requests : "model_id"
studio_credit_authorizations |o--o{ studio_media_jobs : "credit_authorization_id"
studio_credit_authorizations |o--o{ studio_credit_recovery_intents : "authorization_id"自动生成的整体图(按真实表结构,备查)
共享身份库 ER 图
实测验证与设计原因 七个品牌相同,展开查看
实测验证(本机 MySQL 实库)
对照本机真实运行的数据库 studio_profile_libtv 和 studio_platform_identity,逐项核对本页的表、列、关系与说明。18 / 18 项通过。
查看全部核对项
| 核对项 | 结果 |
|---|---|
| 表数 = 发布值 24 | 通过 |
| 列数 = 289 | 通过 |
| 外键数 = 34 | 通过 |
| 检查约束数 = 66 | 通过 |
| 触发器数 = 22 | 通过 |
| 索引数(含主键) = 85 | 通过 |
| 列定义与 pollo 逐列一致 | 通过 |
| 外键与 pollo 完全一致 | 通过 |
| 索引与 pollo 一致 | 通过 |
| 触发器与 pollo 一致 | 通过 |
| 外键 CSV 行数 = 实库外键数 | 通过 |
| mmd 实体 = 实库表 | 通过 |
| svg 标题 24 tables / 34 actual foreign keys = 实库 | 通过 |
| 参考 SQL 表集合与列顺序 = 实库 | 通过 |
| 15 张表 | 通过 |
| 外键 CSV 行数 = 实库外键数 | 通过 |
| svg 标题与实库一致 | 通过 |
| 参考 SQL 表集合与列顺序 = 实库 | 通过 |
实库里的关系是这样的
- 34 个外键里 31 个是复合外键,且都带着 owner_id,其余 3 个是单列外键;22 张子表都带 owner 外键。所以一行数据不可能指向别的用户的项目或会话。
- 删除与更新规则全部是 RESTRICT / NO ACTION,没有任何级联:被引用的行不能被删除。
- 品牌库与共享身份库之间的关系(owner_id、asset_id、model_id + model_version_id)没有数据库外键,靠应用层检查;我们逐表核对了现有数据,没有孤儿。
主动破坏测试(在事务里尝试,全部回滚)
| 尝试 | 数据库的反应 |
|---|---|
| 外键:导出任务.project_id 改成不存在的项目被拒绝 | 拒绝 |
| 复合外键:项目素材引用.project_id 改成别的用户的项目被拒绝(owner 与 project 必须成对) | 拒绝 |
| 触发器:已提交的消息动作不可改写 | 拒绝 |
| 触发器:媒体产出不可改写 | 拒绝 |
| 外键 RESTRICT:被会话引用的项目不能删除 | 拒绝 |
| 复合外键:被引用的会话不能把 owner 改成别人 | 拒绝 |
| 检查约束:Run 状态只能是约定的六个值 | 拒绝 |
| 触发器:账本分录不可修改 | 拒绝 |
| 触发器:账本分录不可删除 | 拒绝 |
LibTV · 表结构
MySQL 8,字符集 utf8mb4,ID 为 char(36) ascii_bin。点击展开 DDL。
按职责分组
项目与会话 2 张
studio_projects:用户拥有的创作项目studio_conversations:项目内的对话会话
Agent执行与并发控制 7 张
maa_bindings:业务会话与Native Maa会话映射、模型版本与未决操作maa_runs:公开Run映射、状态与原生/公开助手证据摘要maa_message_actions:原消息动作及幂等回执maa_interactions:澄清卡片及Run归属maa_interaction_actions:原卡片回答/取消动作maa_model_change_actions:带预期模型版本的切换动作maa_run_stop_actions:停止原Run的幂等动作与观测终态
画布、时间轴与素材引用 5 张
studio_canvases:项目当前画布文档studio_canvas_revisions:历史画布修订studio_video_documents:项目当前时间轴文档studio_timeline_revisions:历史时间轴修订studio_project_asset_refs:项目对用户级素材的引用;不复制素材所有权
媒体生成、结算恢复与导出 6 张
studio_media_requests:用户输入/Agent来源、报价、批准摘要与准入确认studio_media_jobs:已批准媒体任务及状态机studio_media_submission_attempts:一次提交的任务证据与不确定结果studio_media_outputs:受验证的输出与素材映射studio_credit_recovery_intents:积分结算恢复意图;不是用户钱包全账本studio_export_jobs:时间轴导出队列和发布输出
既有generation兼容路径 22 张
generation_jobs:既有generation任务,不等同新PublicMedia任务generation_reservations:既有任务费用预留generation_development_budgets:既有开发测试预算generation_deliveries:既有生成交付回执owner_id:归属用户;不是允许跨用户查询的参数。model_revision:并发准入版本;数据库默认0不能代替Native权威读回。pending_model_change_id:未决模型切换引用,阻止其他writer绕过。studio_users:用户账号记录;不导出密码哈希或任何业务行studio_sessions:登录会话;这里只公开字段结构,不公开会话值studio_assets:用户级素材元数据与存储键结构,项目仅引用素材IDstudio_media_models:公开媒体模型目录结构studio_media_model_versions:媒体模型不可变版本/计价能力结构studio_subscriptions:订阅状态持久化studio_billing_cycles:订阅账期studio_payment_orders:订单记录studio_payment_events:支付事件幂等记录;不代表已有公开支付路由studio_credit_accounts:用户积分账户studio_credit_lots:积分批次studio_credit_authorizations:费用预留与结算授权studio_credit_authorization_allocations:授权对批次的分配studio_credit_ledger_entries:积分流水studio_credit_plan_versions:积分方案不可变版本
品牌库 studio_profile_libtv(24 张)
generation_deliveries 既有生成交付回执
CREATE TABLE `generation_deliveries` ( `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `session_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `maa_source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `tool_name` varchar(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `input_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `metadata_json` json NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`job_id`), KEY `generation_delivery_owner_project` (`owner_id`,`project_id`,`session_id`,`job_id`), KEY `generation_delivery_owned_asset` (`owner_id`,`asset_id`), KEY `generation_delivery_session_fk` (`session_id`), CONSTRAINT `generation_delivery_job_fk` FOREIGN KEY (`job_id`) REFERENCES `generation_jobs` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`, `job_id`) REFERENCES `generation_jobs` (`owner_id`, `project_id`, `session_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_session_fk` FOREIGN KEY (`session_id`) REFERENCES `studio_conversations` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_model_tool` CHECK ((((`model` = _ascii'seedance-2.0') and (`tool_name` = _ascii'seedance2_video_generator')) or ((`model` in (_ascii'minimax-h3',_ascii'seedance-2.5')) and (`tool_name` = _ascii'insai_video_generate')))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_development_budgets 既有开发测试预算
CREATE TABLE `generation_development_budgets` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `policy_version` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits_limit` bigint unsigned NOT NULL, `credits_reserved` bigint unsigned NOT NULL DEFAULT '0', `calls_limit` int unsigned NOT NULL, `calls_reserved` int unsigned NOT NULL DEFAULT '0', `expires_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `generation_budget_owner` (`owner_id`,`id`), CONSTRAINT `generation_budget_limits` CHECK (((`credits_limit` between 1 and 1000000000) and (`credits_reserved` <= `credits_limit`) and (`calls_limit` between 1 and 100) and (`calls_reserved` <= `calls_limit`))), CONSTRAINT `generation_budget_policy` CHECK ((`policy_version` = _latin1'operator-test/v1')) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_jobs 既有generation任务,不等同新PublicMedia任务
CREATE TABLE `generation_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `session_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_conversation_id` char(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_run_id` char(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `budget_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_bytes` mediumblob NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits` bigint unsigned NOT NULL, `expires_at` datetime(6) NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempts` int unsigned NOT NULL DEFAULT '0', `result_bytes` mediumblob, `updated_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `generation_job_budget_owner` (`id`,`budget_id`,`owner_id`), UNIQUE KEY `generation_job_owned_scope` (`owner_id`,`project_id`,`session_id`,`id`), KEY `generation_job_owner` (`owner_id`,`project_id`,`session_id`), KEY `generation_job_session` (`session_id`), KEY `generation_job_budget` (`owner_id`,`budget_id`), CONSTRAINT `generation_job_budget` FOREIGN KEY (`owner_id`, `budget_id`) REFERENCES `generation_development_budgets` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_owned_project` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_owned_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_session` FOREIGN KEY (`session_id`) REFERENCES `studio_conversations` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_attempt` CHECK ((((`status` = _ascii'APPROVED') and (`attempts` = 0) and (`result_bytes` is null)) or ((`status` = _ascii'SUBMITTING') and (`attempts` = 1) and (`result_bytes` is null)) or ((`status` in (_ascii'SUCCEEDED',_ascii'FAILED',_ascii'UNKNOWN')) and (`attempts` = 1) and (`result_bytes` is not null)))), CONSTRAINT `generation_job_credit` CHECK ((`credits` between 1 and 1000000000)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_reservations 既有任务费用预留
CREATE TABLE `generation_reservations` ( `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `budget_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits` bigint unsigned NOT NULL, `calls` int unsigned NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, PRIMARY KEY (`job_id`), KEY `generation_reservation_job` (`job_id`,`budget_id`,`owner_id`), CONSTRAINT `generation_reservation_job` FOREIGN KEY (`job_id`, `budget_id`, `owner_id`) REFERENCES `generation_jobs` (`id`, `budget_id`, `owner_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_reservation_fixed` CHECK (((`credits` between 1 and 1000000000) and (`calls` = 1) and (`status` = _latin1'HELD'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_bindings 业务会话与Native Maa会话映射、模型版本与未决操作
CREATE TABLE `maa_bindings` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `model_revision` bigint unsigned NOT NULL DEFAULT '0', `pending_model_change_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_binding_business_scope` (`owner_id`,`project_id`,`conversation_id`), UNIQUE KEY `maa_binding_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `maa_binding_native_identity` (`native_cid`), KEY `maa_model_change_pending_fk` (`owner_id`,`project_id`,`conversation_id`,`id`,`pending_model_change_id`), CONSTRAINT `maa_binding_owned_conversation_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_model_change_pending_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `id`, `pending_model_change_id`) REFERENCES `maa_model_change_actions` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_binding_receipt` CHECK ((((`status` = _ascii'dispatching') and (`native_cid` is null)) or ((`status` = _ascii'bound') and (`native_cid` is not null)))), CONSTRAINT `maa_model_binding_revision` CHECK ((`model_revision` <= 9007199254740991)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_interaction_actions 原卡片回答/取消动作
CREATE TABLE `maa_interaction_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `interaction_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_iid` varchar(124) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `content_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `response_action` varchar(8) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `values_payload` json NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_interaction_action_business_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_interaction_action_one_card` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`interaction_id`), CONSTRAINT `maa_interaction_action_owned_card_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`, `interaction_id`) REFERENCES `maa_interactions` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_interaction_action_kind` CHECK ((`response_action` in (_latin1'submit',_latin1'cancel'))), CONSTRAINT `maa_interaction_action_status` CHECK ((`status` in (_latin1'dispatching',_latin1'accepted'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_interactions 澄清卡片及Run归属
CREATE TABLE `maa_interactions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_iid` varchar(124) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_payload` json NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_interaction_native_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`native_iid`), UNIQUE KEY `maa_interaction_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`id`), CONSTRAINT `maa_interaction_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_message_actions 原消息动作及幂等回执
CREATE TABLE `maa_message_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `content` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `proposed_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_action_business_identity` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), KEY `maa_action_owned_run_fk` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`), CONSTRAINT `maa_action_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_action_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_action_receipt` CHECK ((((`status` = _latin1'dispatching') and (`public_run_id` is null)) or ((`status` = _latin1'accepted') and (`public_run_id` is not null)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_model_change_actions 带预期模型版本的切换动作
CREATE TABLE `maa_model_change_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `expected_revision` bigint unsigned NOT NULL, `from_provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `from_model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `target_provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `target_model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `dispatch_attempt` bigint unsigned NOT NULL, `receipt_payload` json DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_model_change_owned_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_model_change_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`id`), CONSTRAINT `maa_model_change_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_model_change_attempt` CHECK ((`dispatch_attempt` between 1 and 9007199254740991)), CONSTRAINT `maa_model_change_expected` CHECK ((`expected_revision` <= 9007199254740990)), CONSTRAINT `maa_model_change_status` CHECK ((((cast(`status` as char charset binary) = _latin1'dispatching') and (`receipt_payload` is null)) or ((cast(`status` as char charset binary) in (_latin1'accepted',_latin1'rejected')) and (`receipt_payload` is not null) and (json_type(`receipt_payload`) = _latin1'OBJECT')))), CONSTRAINT `maa_model_change_time` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_run_stop_actions 停止原Run的幂等动作与观测终态
CREATE TABLE `maa_run_stop_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_rid` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `stop_action` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempt` bigint unsigned NOT NULL, `terminal_run_status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_stop_owned_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_stop_one_run` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`), CONSTRAINT `maa_stop_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_stop_action` CHECK ((`stop_action` = _latin1'interrupt')), CONSTRAINT `maa_stop_attempt` CHECK ((`attempt` between 1 and 9007199254740991)), CONSTRAINT `maa_stop_state` CHECK ((((`status` = _latin1'unknown') and (`terminal_run_status` is null)) or ((`status` = _latin1'terminal_observed') and (`terminal_run_status` is not null) and (`terminal_run_status` in (_latin1'completed',_latin1'failed',_latin1'cancelled'))))), CONSTRAINT `maa_stop_time` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_runs 公开Run映射、状态与原生/公开助手证据摘要
CREATE TABLE `maa_runs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_rid` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, `native_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `public_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `native_assistant_bytes` bigint unsigned NOT NULL DEFAULT '0', `assistant_event_seq` bigint unsigned NOT NULL DEFAULT '0', `last_event_seq` bigint unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `maa_run_native_identity` (`native_rid`), UNIQUE KEY `maa_run_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`id`), KEY `maa_run_owned_list` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), CONSTRAINT `maa_run_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_run_source_evidence` CHECK ((((`native_assistant_sha256` is null) and (`public_assistant_sha256` is null) and (`native_assistant_bytes` = 0) and (`assistant_event_seq` = 0)) or ((`native_assistant_sha256` is not null) and (`public_assistant_sha256` is not null) and (`native_assistant_bytes` > 0) and (`assistant_event_seq` > 0) and (`assistant_event_seq` <= `last_event_seq`)))), CONSTRAINT `maa_run_status` CHECK ((`status` in (_latin1'queued',_latin1'running',_latin1'waiting_interaction',_latin1'completed',_latin1'failed',_latin1'cancelled'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_canvas_revisions 历史画布修订
CREATE TABLE `studio_canvas_revisions` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_bytes` mediumblob NOT NULL, `state_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `restored_from_revision` bigint unsigned DEFAULT NULL, `recorded_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`,`project_id`,`kind`,`revision`), KEY `studio_canvas_revision_source_fk` (`owner_id`,`project_id`,`kind`,`restored_from_revision`), CONSTRAINT `studio_canvas_revision_head_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_canvases` (`owner_id`, `project_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_canvas_revision_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `kind`, `restored_from_revision`) REFERENCES `studio_canvas_revisions` (`owner_id`, `project_id`, `kind`, `revision`), CONSTRAINT `studio_canvas_revision_bytes` CHECK ((length(`state_bytes`) between 1 and 262144)), CONSTRAINT `studio_canvas_revision_kind` CHECK ((`kind` = _latin1'canvas')), CONSTRAINT `studio_canvas_revision_number` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_canvas_revision_origin` CHECK ((((`origin` in (_latin1'saved',_latin1'backfill')) and (`restored_from_revision` is null)) or ((`origin` = _latin1'restored') and (`restored_from_revision` is not null) and (`restored_from_revision` between 1 and (`revision` - 1))))), CONSTRAINT `studio_canvas_revision_sha` CHECK ((`state_sha256` = lower(sha2(`state_bytes`,256)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_canvases 项目当前画布文档
CREATE TABLE `studio_canvases` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_json` json NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`project_id`), UNIQUE KEY `studio_canvas_owned_head` (`owner_id`,`project_id`), CONSTRAINT `studio_canvas_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_canvas_revision` CHECK ((`revision` between 1 and 2147483647)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_conversations 项目内的对话会话
CREATE TABLE `studio_conversations` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `title` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_conversation_owned_scope` (`owner_id`,`project_id`,`id`), KEY `studio_conversation_list` (`owner_id`,`project_id`,`created_at`,`id`), CONSTRAINT `studio_conversation_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_recovery_intents 积分结算恢复意图;不是用户钱包全账本
CREATE TABLE `studio_credit_recovery_intents` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`kind` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`intent_bytes` mediumblob NOT NULL,
`intent_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`lease_token_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`lease_until` datetime(6) DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_intent_job_kind` (`job_id`,`kind`),
KEY `credit_intent_recovery` (`state`,`updated_at`,`id`),
KEY `credit_intent_owned_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`,`request_sha256`),
CONSTRAINT `credit_intent_owned_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`, `request_sha256`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`),
CONSTRAINT `credit_intent_hashes` CHECK ((regexp_like(`request_sha256`,_latin1'^[a-f0-9]{64}$') and regexp_like(`quote_sha256`,_latin1'^[a-f0-9]{64}$'))),
CONSTRAINT `credit_intent_kind` CHECK (((`kind` in (_latin1'RESERVE_BIND',_latin1'CAPTURE',_latin1'RELEASE')) and (((`kind` = _latin1'RESERVE_BIND') and (`authorization_id` is null)) or ((`kind` in (_latin1'CAPTURE',_latin1'RELEASE')) and (`authorization_id` is not null))))),
CONSTRAINT `credit_intent_lease` CHECK ((((`state` = _latin1'leased') and (`lease_token_sha256` is not null) and regexp_like(`lease_token_sha256`,_latin1'^[a-f0-9]{64}$') and (`lease_until` is not null) and (`lease_until` > `updated_at`) and (`lease_until` <= (`updated_at` + interval 15 minute))) or ((`state` <> _latin1'leased') and (`lease_token_sha256` is null) and (`lease_until` is null)))),
CONSTRAINT `credit_intent_payload_sha` CHECK ((`intent_sha256` = lower(sha2(`intent_bytes`,256)))),
CONSTRAINT `credit_intent_payload_size` CHECK ((length(`intent_bytes`) between 1 and 65536)),
CONSTRAINT `credit_intent_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `credit_intent_state` CHECK ((`state` in (_latin1'pending',_latin1'leased',_latin1'confirmed',_latin1'unknown'))),
CONSTRAINT `credit_intent_times` CHECK ((`updated_at` >= `created_at`))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_export_jobs 时间轴导出队列和发布输出
CREATE TABLE `studio_export_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `document_revision` bigint unsigned NOT NULL, `input_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `input_json` json NOT NULL, `output_json` json DEFAULT NULL, `error_code` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT '', `lease_token_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `lease_until` datetime(6) DEFAULT NULL, `attempts` int unsigned NOT NULL DEFAULT '0', `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_export_input` (`project_id`,`document_revision`,`input_hash`), KEY `studio_export_claim` (`status`,`created_at`,`id`), KEY `studio_export_owner_list` (`owner_id`,`project_id`,`created_at`,`id`), KEY `studio_export_expiry` (`status`,`lease_until`), CONSTRAINT `studio_export_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_export_lease` CHECK ((((`status` = _latin1'running') and (`lease_token_hash` is not null) and (`lease_until` is not null)) or ((`status` <> _latin1'running') and (`lease_token_hash` is null) and (`lease_until` is null)))), CONSTRAINT `studio_export_output` CHECK ((((`status` = _latin1'succeeded') and (`output_json` is not null) and (`error_code` = _latin1'')) or ((`status` in (_latin1'queued',_latin1'running')) and (`output_json` is null) and (`error_code` = _latin1'')) or ((`status` in (_latin1'failed',_latin1'unknown')) and (`output_json` is null) and (`error_code` <> _latin1'')))), CONSTRAINT `studio_export_revision` CHECK ((`document_revision` between 1 and 2147483647)), CONSTRAINT `studio_export_status` CHECK ((`status` in (_latin1'queued',_latin1'running',_latin1'succeeded',_latin1'failed',_latin1'unknown'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_jobs 已批准媒体任务及状态机
CREATE TABLE `studio_media_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_approval_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `approval_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credit_authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `authorization_mode` varchar(24) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `authorization_expires_at` datetime(6) DEFAULT NULL, `status` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `lease_token_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `lease_until` datetime(6) DEFAULT NULL, `provider_task_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `client_cancel_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `cancel_request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `cancel_requested_at` datetime(6) DEFAULT NULL, `staged_asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `staged_asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_job_request` (`request_id`), UNIQUE KEY `studio_media_job_client` (`owner_id`,`client_approval_id`), UNIQUE KEY `studio_media_job_owned` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `studio_media_job_owned_request` (`owner_id`,`project_id`,`conversation_id`,`id`,`request_sha256`), KEY `studio_media_job_page` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), KEY `studio_media_job_queue` (`status`,`updated_at`,`id`), KEY `studio_media_job_request_fk` (`owner_id`,`project_id`,`conversation_id`,`request_id`,`request_sha256`,`quote_sha256`), CONSTRAINT `studio_media_job_request_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `request_id`, `request_sha256`, `quote_sha256`) REFERENCES `studio_media_requests` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`, `quote_sha256`), CONSTRAINT `studio_media_job_authorization` CHECK ((((`credit_authorization_id` is null) and (`authorization_mode` is null) and (`authorization_expires_at` is null) and (`status` in (_latin1'approval_pending',_latin1'cancelled'))) or ((`credit_authorization_id` is not null) and (`authorization_mode` is not null) and (`authorization_mode` in (_latin1'commercial',_latin1'test_allowance')) and (`authorization_expires_at` is not null) and (`authorization_expires_at` > `created_at`) and (`status` <> _latin1'approval_pending')))), CONSTRAINT `studio_media_job_cancel` CHECK ((((`client_cancel_id` is null) and (`cancel_request_sha256` is null) and (`cancel_requested_at` is null)) or ((`client_cancel_id` is not null) and (`cancel_request_sha256` is not null) and (`cancel_requested_at` is not null) and (`cancel_requested_at` between `created_at` and `updated_at`)))), CONSTRAINT `studio_media_job_lease` CHECK ((((`status` in (_latin1'leased',_latin1'submitting')) and (`lease_token_sha256` is not null) and (`lease_until` is not null) and (`lease_until` > `updated_at`) and (`lease_until` <= (`updated_at` + interval 15 minute))) or ((`status` not in (_latin1'leased',_latin1'submitting')) and (`lease_token_sha256` is null) and (`lease_until` is null)))), CONSTRAINT `studio_media_job_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_media_job_staged` CHECK ((((`staged_asset_id` is null) and (`staged_asset_sha256` is null)) or ((`staged_asset_id` is not null) and (`staged_asset_sha256` is not null)))), CONSTRAINT `studio_media_job_status` CHECK ((`status` in (_latin1'approval_pending',_latin1'queued',_latin1'leased',_latin1'submitting',_latin1'running',_latin1'submission_unknown',_latin1'succeeded',_latin1'failed',_latin1'cancelled'))), CONSTRAINT `studio_media_job_task` CHECK (((`status` not in (_latin1'running',_latin1'succeeded')) or (`provider_task_id` is not null))), CONSTRAINT `studio_media_job_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_outputs 受验证的输出与素材映射
CREATE TABLE `studio_media_outputs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `ordinal` int unsigned NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_metadata_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_result_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_output_job` (`job_id`,`ordinal`), KEY `studio_media_output_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`), CONSTRAINT `studio_media_output_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`), CONSTRAINT `studio_media_output_ordinal` CHECK ((`ordinal` = 0)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_requests 用户输入/Agent来源、报价、批准摘要与准入确认
CREATE TABLE `studio_media_requests` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_config_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_bytes` mediumblob NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quote_bytes` mediumblob NOT NULL, `quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quoted_credits` bigint unsigned NOT NULL, `expires_at` datetime(6) NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_snapshot_bytes` mediumblob, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_request_owned` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `studio_media_request_quoted` (`owner_id`,`project_id`,`conversation_id`,`id`,`request_sha256`,`quote_sha256`), UNIQUE KEY `studio_media_request_client` (`owner_id`,`project_id`,`conversation_id`,`client_request_id`), KEY `studio_media_request_page` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), KEY `studio_media_request_source_fk` (`owner_id`,`project_id`,`conversation_id`,`source_binding_id`,`source_run_id`), CONSTRAINT `studio_media_request_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`), CONSTRAINT `studio_media_request_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `source_binding_id`, `source_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`), CONSTRAINT `studio_media_quote_credits` CHECK ((`quoted_credits` between 1 and 1000000000)), CONSTRAINT `studio_media_quote_sha` CHECK ((`quote_sha256` = lower(sha2(`quote_bytes`,256)))), CONSTRAINT `studio_media_quote_times` CHECK (((`expires_at` > `created_at`) and (`expires_at` <= (`created_at` + interval 15 minute)))), CONSTRAINT `studio_media_request_origin` CHECK ((((`origin` in (_latin1'ui',_latin1'user_edit')) and (`source_binding_id` is null) and (`source_run_id` is null) and (`source_assistant_sha256` is null) and (`source_snapshot_bytes` is null)) or ((`origin` = _latin1'agent') and (`source_binding_id` is not null) and (`source_run_id` is not null) and (`source_assistant_sha256` is not null) and (`source_snapshot_bytes` is not null) and (length(`source_snapshot_bytes`) between 1 and 65536) and (`source_assistant_sha256` = lower(sha2(`source_snapshot_bytes`,256)))))), CONSTRAINT `studio_media_request_sha` CHECK ((`request_sha256` = lower(sha2(`request_bytes`,256)))), CONSTRAINT `studio_media_request_size` CHECK (((length(`request_bytes`) between 1 and 65536) and (length(`quote_bytes`) between 1 and 65536))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_submission_attempts 一次提交的任务证据与不确定结果
CREATE TABLE `studio_media_submission_attempts` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempt_no` int unsigned NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_idempotency_key` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `stage` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `dispatch_started_at` datetime(6) DEFAULT NULL, `provider_task_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `receipt_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `terminal_receipt_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `reconciliation_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_attempt_job` (`job_id`,`attempt_no`), UNIQUE KEY `studio_media_attempt_idempotency` (`provider_idempotency_key`), KEY `studio_media_attempt_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`,`request_sha256`), CONSTRAINT `studio_media_attempt_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`, `request_sha256`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`), CONSTRAINT `studio_media_attempt_number` CHECK ((`attempt_no` = 1)), CONSTRAINT `studio_media_attempt_state` CHECK ((((`stage` = _latin1'prepared') and (`dispatch_started_at` is null) and (`provider_task_id` is null) and (`receipt_sha256` is null) and (`reconciliation_sha256` is null) and (`terminal_receipt_sha256` is null)) or ((`stage` in (_latin1'dispatching',_latin1'unknown')) and (`dispatch_started_at` is not null) and (`dispatch_started_at` >= `created_at`) and (`provider_task_id` is null) and (`receipt_sha256` is null) and (`reconciliation_sha256` is null) and (`terminal_receipt_sha256` is null)) or ((`stage` = _latin1'acknowledged') and (`dispatch_started_at` is not null) and (`provider_task_id` is not null) and (`receipt_sha256` is not null) and (`terminal_receipt_sha256` is null)) or ((`stage` in (_latin1'completed',_latin1'failed')) and (`dispatch_started_at` is not null) and (`provider_task_id` is not null) and (`receipt_sha256` is not null) and (`terminal_receipt_sha256` is not null)) or ((`stage` = _latin1'reconciled_not_sent') and (`dispatch_started_at` is not null) and (`provider_task_id` is null) and (`reconciliation_sha256` is not null)))), CONSTRAINT `studio_media_attempt_times` CHECK (((`updated_at` >= `created_at`) and ((`dispatch_started_at` is null) or (`dispatch_started_at` between `created_at` and `updated_at`)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_project_asset_refs 项目对用户级素材的引用;不复制素材所有权
CREATE TABLE `studio_project_asset_refs` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_metadata_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, `detached_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`project_id`,`asset_id`), KEY `studio_project_asset_owned_page` (`owner_id`,`project_id`,`asset_id`), KEY `studio_project_asset_reverse` (`owner_id`,`asset_id`,`project_id`), CONSTRAINT `studio_project_asset_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_project_asset_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_project_asset_state` CHECK ((((`state` = _latin1'attached') and (`detached_at` is null)) or ((`state` = _latin1'detached') and (`detached_at` is not null) and (`detached_at` = `updated_at`)))), CONSTRAINT `studio_project_asset_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_projects 用户拥有的创作项目
CREATE TABLE `studio_projects` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `title` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_project_owner_identity` (`owner_id`,`id`), KEY `studio_project_owner_list` (`owner_id`,`created_at`,`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_timeline_revisions 历史时间轴修订
CREATE TABLE `studio_timeline_revisions` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_bytes` mediumblob NOT NULL, `state_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `restored_from_revision` bigint unsigned DEFAULT NULL, `recorded_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`,`project_id`,`kind`,`revision`), KEY `studio_timeline_revision_source_fk` (`owner_id`,`project_id`,`kind`,`restored_from_revision`), CONSTRAINT `studio_timeline_revision_head_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_video_documents` (`owner_id`, `project_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_timeline_revision_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `kind`, `restored_from_revision`) REFERENCES `studio_timeline_revisions` (`owner_id`, `project_id`, `kind`, `revision`), CONSTRAINT `studio_timeline_revision_bytes` CHECK ((length(`state_bytes`) between 1 and 262144)), CONSTRAINT `studio_timeline_revision_kind` CHECK ((`kind` = _latin1'timeline')), CONSTRAINT `studio_timeline_revision_number` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_timeline_revision_origin` CHECK ((((`origin` in (_latin1'saved',_latin1'backfill')) and (`restored_from_revision` is null)) or ((`origin` = _latin1'restored') and (`restored_from_revision` is not null) and (`restored_from_revision` between 1 and (`revision` - 1))))), CONSTRAINT `studio_timeline_revision_sha` CHECK ((`state_sha256` = lower(sha2(`state_bytes`,256)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_video_documents 项目当前时间轴文档
CREATE TABLE `studio_video_documents` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_json` json NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`project_id`), UNIQUE KEY `studio_timeline_owned_head` (`owner_id`,`project_id`), CONSTRAINT `studio_document_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_document_revision` CHECK ((`revision` between 1 and 2147483647)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
共享身份库(15 张)与积分账本 七个品牌相同,展开查看
studio_assets
CREATE TABLE `studio_assets` (
`id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`metadata_json` json NOT NULL,
`storage_key` varchar(512) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`created_at` datetime(6) NOT NULL,
`publication_state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT 'visible',
PRIMARY KEY (`id`),
UNIQUE KEY `studio_asset_owner_digest` (`owner_id`,`sha256`),
KEY `studio_asset_owner_list` (`owner_id`,`created_at`,`id`),
KEY `studio_asset_visible_list` (`owner_id`,`publication_state`,`created_at`,`id`),
CONSTRAINT `studio_asset_publication_state` CHECK (CAST(publication_state AS BINARY) IN ('pending','visible')),
CONSTRAINT `studio_asset_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_billing_cycles
CREATE TABLE `studio_billing_cycles` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`subscription_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`payment_order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_invoice_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`period_start` datetime(6) NOT NULL,
`period_end` datetime(6) NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`valid_from` datetime(6) NOT NULL,
`expires_at` datetime(6) NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`paid_evidence_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `billing_cycle_owned` (`owner_id`,`id`),
UNIQUE KEY `billing_cycle_period` (`subscription_id`,`period_start`),
UNIQUE KEY `billing_cycle_invoice` (`provider_key`,`provider_account`,`provider_invoice_id`),
UNIQUE KEY `billing_cycle_order` (`payment_order_id`),
KEY `billing_cycle_subscription_fk` (`owner_id`,`subscription_id`,`provider_key`,`provider_account`),
KEY `billing_cycle_order_fk` (`owner_id`,`payment_order_id`,`plan_version_id`),
KEY `billing_cycle_order_provider_fk` (`owner_id`,`payment_order_id`,`provider_key`,`provider_account`),
CONSTRAINT `billing_cycle_order_fk` FOREIGN KEY (`owner_id`, `payment_order_id`, `plan_version_id`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `plan_version_id`),
CONSTRAINT `billing_cycle_order_provider_fk` FOREIGN KEY (`owner_id`, `payment_order_id`, `provider_key`, `provider_account`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `provider_key`, `provider_account`),
CONSTRAINT `billing_cycle_subscription_fk` FOREIGN KEY (`owner_id`, `subscription_id`, `provider_key`, `provider_account`) REFERENCES `studio_subscriptions` (`owner_id`, `id`, `provider_key`, `provider_account`),
CONSTRAINT `billing_cycle_amount` CHECK ((`grant_credits` between 1 and 1000000000)),
CONSTRAINT `billing_cycle_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `billing_cycle_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `billing_cycle_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `billing_cycle_state` CHECK (((`state` in (_latin1'PENDING',_latin1'PAID',_latin1'CLOSED')) and (((`state` = _latin1'PAID') and (`paid_evidence_sha256` is not null) and regexp_like(`paid_evidence_sha256`,_latin1'^[a-f0-9]{64}$')) or ((`state` <> _latin1'PAID') and (`paid_evidence_sha256` is null))))),
CONSTRAINT `billing_cycle_times` CHECK (((`period_end` > `period_start`) and (`expires_at` > `valid_from`) and (`expires_at` <= (`valid_from` + interval 31622400 second)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_credit_accounts
CREATE TABLE `studio_credit_accounts` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `unit` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`), CONSTRAINT `credit_account_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `credit_account_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `credit_account_status` CHECK ((`status` in (_latin1'open',_latin1'suspended'))), CONSTRAINT `credit_account_unit` CHECK ((`unit` = _latin1'credits')) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_authorization_allocations
CREATE TABLE `studio_credit_authorization_allocations` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `lot_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `allocated_credits` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`authorization_id`,`lot_id`), UNIQUE KEY `credit_allocation_owned` (`owner_id`,`authorization_id`,`lot_id`), KEY `credit_allocation_lot` (`owner_id`,`lot_id`,`authorization_id`), CONSTRAINT `credit_allocation_authorization_fk` FOREIGN KEY (`owner_id`, `authorization_id`) REFERENCES `studio_credit_authorizations` (`owner_id`, `id`), CONSTRAINT `credit_allocation_lot_fk` FOREIGN KEY (`owner_id`, `lot_id`) REFERENCES `studio_credit_lots` (`owner_id`, `id`), CONSTRAINT `credit_allocation_amount` CHECK ((`allocated_credits` between 1 and 1000000000)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_authorizations
CREATE TABLE `studio_credit_authorizations` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`profile` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`credits` bigint unsigned NOT NULL,
`expires_at` datetime(6) NOT NULL,
`reservation_bytes` mediumblob NOT NULL,
`reservation_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`policy_bytes` mediumblob NOT NULL,
`policy_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_authorization_owned` (`owner_id`,`id`),
UNIQUE KEY `credit_authorization_job` (`owner_id`,`profile`,`job_id`),
CONSTRAINT `credit_authorization_account_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_credit_accounts` (`owner_id`),
CONSTRAINT `credit_authorization_amount` CHECK ((`credits` between 1 and 1000000000)),
CONSTRAINT `credit_authorization_hashes` CHECK ((regexp_like(`request_sha256`,_latin1'^[a-f0-9]{64}$') and regexp_like(`quote_sha256`,_latin1'^[a-f0-9]{64}$'))),
CONSTRAINT `credit_authorization_policy_sha` CHECK ((`policy_sha256` = lower(sha2(`policy_bytes`,256)))),
CONSTRAINT `credit_authorization_policy_size` CHECK ((length(`policy_bytes`) between 1 and 65536)),
CONSTRAINT `credit_authorization_profile` CHECK ((`profile` in (_latin1'topview',_latin1'pollo',_latin1'invideo',_latin1'libtv',_latin1'flova',_latin1'creatok',_latin1'creatify'))),
CONSTRAINT `credit_authorization_reservation_sha` CHECK ((`reservation_sha256` = lower(sha2(`reservation_bytes`,256)))),
CONSTRAINT `credit_authorization_reservation_size` CHECK ((length(`reservation_bytes`) between 1 and 65536)),
CONSTRAINT `credit_authorization_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `credit_authorization_state` CHECK ((`state` in (_latin1'HELD',_latin1'CAPTURED',_latin1'RELEASED'))),
CONSTRAINT `credit_authorization_times` CHECK (((`expires_at` > `created_at`) and (`expires_at` <= (`created_at` + interval 15 minute)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_credit_ledger_entries
CREATE TABLE `studio_credit_ledger_entries` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `lot_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `operation_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `grant_delta` bigint NOT NULL, `held_delta` bigint NOT NULL, `captured_delta` bigint NOT NULL, `facts_bytes` mediumblob NOT NULL, `facts_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `credit_entry_operation` (`owner_id`,`operation_key`,`lot_id`), KEY `credit_entry_page` (`owner_id`,`created_at`,`id`), KEY `credit_entry_lot_fk` (`owner_id`,`lot_id`), KEY `credit_entry_allocation_fk` (`owner_id`,`authorization_id`,`lot_id`), CONSTRAINT `credit_entry_allocation_fk` FOREIGN KEY (`owner_id`, `authorization_id`, `lot_id`) REFERENCES `studio_credit_authorization_allocations` (`owner_id`, `authorization_id`, `lot_id`), CONSTRAINT `credit_entry_authorization_fk` FOREIGN KEY (`owner_id`, `authorization_id`) REFERENCES `studio_credit_authorizations` (`owner_id`, `id`), CONSTRAINT `credit_entry_lot_fk` FOREIGN KEY (`owner_id`, `lot_id`) REFERENCES `studio_credit_lots` (`owner_id`, `id`), CONSTRAINT `credit_entry_delta` CHECK ((((`kind` = _latin1'grant') and (`authorization_id` is null) and (`grant_delta` between 1 and 1000000000) and (`held_delta` = 0) and (`captured_delta` = 0)) or ((`kind` = _latin1'hold') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`held_delta` between 1 and 1000000000) and (`captured_delta` = 0)) or ((`kind` = _latin1'capture') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`captured_delta` between 1 and 1000000000) and (`held_delta` = -(`captured_delta`))) or ((`kind` = _latin1'release') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`held_delta` between -(1000000000) and -(1)) and (`captured_delta` = 0)))), CONSTRAINT `credit_entry_facts_sha` CHECK ((`facts_sha256` = lower(sha2(`facts_bytes`,256)))), CONSTRAINT `credit_entry_facts_size` CHECK ((length(`facts_bytes`) between 1 and 65536)), CONSTRAINT `credit_entry_operation_key` CHECK ((((`kind` = _latin1'grant') and (`operation_key` = concat(`lot_id`,_latin1':grant'))) or ((`kind` <> _latin1'grant') and (`operation_key` = concat(`authorization_id`,_latin1':',`kind`))))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_lots
CREATE TABLE `studio_credit_lots` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `grant_credits` bigint unsigned NOT NULL, `held_credits` bigint unsigned NOT NULL, `captured_credits` bigint unsigned NOT NULL, `valid_from` datetime(6) NOT NULL, `expires_at` datetime(6) NOT NULL, `eligibility_bytes` mediumblob NOT NULL, `eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_cycle_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `credit_lot_owned` (`owner_id`,`id`), UNIQUE KEY `credit_lot_order` (`source_order_id`), UNIQUE KEY `credit_lot_cycle` (`source_cycle_id`), KEY `credit_lot_eligible` (`owner_id`,`expires_at`,`id`), KEY `credit_lot_order_fk` (`owner_id`,`source_order_id`), KEY `credit_lot_cycle_fk` (`owner_id`,`source_cycle_id`), CONSTRAINT `credit_lot_account_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_credit_accounts` (`owner_id`), CONSTRAINT `credit_lot_cycle_fk` FOREIGN KEY (`owner_id`, `source_cycle_id`) REFERENCES `studio_billing_cycles` (`owner_id`, `id`), CONSTRAINT `credit_lot_order_fk` FOREIGN KEY (`owner_id`, `source_order_id`) REFERENCES `studio_payment_orders` (`owner_id`, `id`), CONSTRAINT `credit_lot_counters` CHECK (((`grant_credits` between 1 and 1000000000) and (`held_credits` <= 1000000000) and (`captured_credits` <= 1000000000) and ((`held_credits` + `captured_credits`) <= `grant_credits`))), CONSTRAINT `credit_lot_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))), CONSTRAINT `credit_lot_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)), CONSTRAINT `credit_lot_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `credit_lot_source` CHECK ((((`source_order_id` is not null) and (`source_cycle_id` is null)) or ((`source_order_id` is null) and (`source_cycle_id` is not null)))), CONSTRAINT `credit_lot_times` CHECK (((`expires_at` > `valid_from`) and (`updated_at` >= `created_at`))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_plan_versions
CREATE TABLE `studio_credit_plan_versions` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`version_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`price_minor` bigint unsigned NOT NULL,
`currency` char(3) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`credit_validity_seconds` int unsigned NOT NULL,
`billing_interval_months` int unsigned NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`published_at` datetime(6) NOT NULL,
`retired_at` datetime(6) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_plan_version_key` (`plan_key`,`version_key`),
CONSTRAINT `credit_plan_amount` CHECK (((`price_minor` between 1 and 1000000000000) and (`grant_credits` between 1 and 1000000000))),
CONSTRAINT `credit_plan_currency` CHECK (regexp_like(`currency`,_latin1'^[A-Z]{3}$')),
CONSTRAINT `credit_plan_duration` CHECK (((`credit_validity_seconds` between 1 and 31622400) and ((`retired_at` is null) or (`retired_at` >= `published_at`)))),
CONSTRAINT `credit_plan_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `credit_plan_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `credit_plan_kind` CHECK (((`kind` in (_latin1'subscription',_latin1'topup')) and (((`kind` = _latin1'subscription') and (`billing_interval_months` in (1,3,12))) or ((`kind` = _latin1'topup') and (`billing_interval_months` = 0)))))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_media_model_versions
CREATE TABLE `studio_media_model_versions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `version_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `config_bytes` mediumblob NOT NULL, `config_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `published_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_version_key` (`model_id`,`version_key`), UNIQUE KEY `studio_media_version_owned_model` (`model_id`,`id`), CONSTRAINT `studio_media_version_model_fk` FOREIGN KEY (`model_id`) REFERENCES `studio_media_models` (`id`), CONSTRAINT `studio_media_version_sha` CHECK ((`config_sha256` = lower(sha2(`config_bytes`,256)))), CONSTRAINT `studio_media_version_size` CHECK ((length(`config_bytes`) between 1 and 65536)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_models
CREATE TABLE `studio_media_models` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `display_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `published_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `revision` bigint unsigned NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_model_key` (`model_key`), KEY `studio_media_model_published_fk` (`id`,`published_version_id`), CONSTRAINT `studio_media_model_published_fk` FOREIGN KEY (`id`, `published_version_id`) REFERENCES `studio_media_model_versions` (`model_id`, `id`), CONSTRAINT `studio_media_model_kind` CHECK ((`kind` = _ascii'video')), CONSTRAINT `studio_media_model_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_media_model_status` CHECK (((`status` in (_ascii'draft',_ascii'active',_ascii'disabled')) and ((`status` <> _ascii'active') or (`published_version_id` is not null)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_payment_events
CREATE TABLE `studio_payment_events` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_event_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `subscription_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `body_bytes` mediumblob NOT NULL, `body_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `payment_event_provider` (`provider_key`,`provider_account`,`provider_event_id`), KEY `payment_event_order_fk` (`owner_id`,`order_id`,`provider_key`,`provider_account`), KEY `payment_event_subscription_fk` (`owner_id`,`subscription_id`,`provider_key`,`provider_account`), CONSTRAINT `payment_event_order_fk` FOREIGN KEY (`owner_id`, `order_id`, `provider_key`, `provider_account`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `provider_key`, `provider_account`), CONSTRAINT `payment_event_subscription_fk` FOREIGN KEY (`owner_id`, `subscription_id`, `provider_key`, `provider_account`) REFERENCES `studio_subscriptions` (`owner_id`, `id`, `provider_key`, `provider_account`), CONSTRAINT `payment_event_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `payment_event_body_sha` CHECK ((`body_sha256` = lower(sha2(`body_bytes`,256)))), CONSTRAINT `payment_event_body_size` CHECK ((length(`body_bytes`) between 1 and 65536)), CONSTRAINT `payment_event_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `payment_event_state` CHECK ((`state` in (_latin1'VERIFIED',_latin1'PROCESSED'))), CONSTRAINT `payment_event_subject` CHECK (((`order_id` is not null) or (`subscription_id` is not null))), CONSTRAINT `payment_event_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_payment_orders
CREATE TABLE `studio_payment_orders` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`price_minor` bigint unsigned NOT NULL,
`currency` char(3) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`valid_from` datetime(6) NOT NULL,
`expires_at` datetime(6) NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_idempotency_key` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_order_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`paid_evidence_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `payment_order_owned` (`owner_id`,`id`),
UNIQUE KEY `payment_order_owned_plan` (`owner_id`,`id`,`plan_version_id`),
UNIQUE KEY `payment_order_owned_provider` (`owner_id`,`id`,`provider_key`,`provider_account`),
UNIQUE KEY `payment_order_client` (`owner_id`,`client_action_id`),
UNIQUE KEY `payment_order_provider_key` (`provider_key`,`provider_account`,`provider_idempotency_key`),
UNIQUE KEY `payment_order_provider_id` (`provider_key`,`provider_account`,`provider_order_id`),
KEY `payment_order_plan_fk` (`plan_version_id`),
CONSTRAINT `payment_order_plan_fk` FOREIGN KEY (`plan_version_id`) REFERENCES `studio_credit_plan_versions` (`id`),
CONSTRAINT `payment_order_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`),
CONSTRAINT `payment_order_amount` CHECK (((`price_minor` between 1 and 1000000000000) and (`grant_credits` between 1 and 1000000000))),
CONSTRAINT `payment_order_currency` CHECK (regexp_like(`currency`,_latin1'^[A-Z]{3}$')),
CONSTRAINT `payment_order_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `payment_order_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `payment_order_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `payment_order_state` CHECK (((`state` in (_latin1'CREATING',_latin1'CREATE_UNKNOWN',_latin1'PENDING',_latin1'PAID',_latin1'CLOSED')) and (((`state` = _latin1'PAID') and (`provider_order_id` is not null) and (`paid_evidence_sha256` is not null) and regexp_like(`paid_evidence_sha256`,_latin1'^[a-f0-9]{64}$')) or ((`state` <> _latin1'PAID') and (`paid_evidence_sha256` is null))))),
CONSTRAINT `payment_order_times` CHECK (((`expires_at` > `valid_from`) and (`expires_at` <= (`valid_from` + interval 31622400 second)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_sessions
CREATE TABLE `studio_sessions` ( `token_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `user_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, `expires_at` datetime(6) NOT NULL, `revoked_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`token_hash`), KEY `studio_session_expiry` (`expires_at`), KEY `studio_session_user` (`user_id`,`expires_at`), CONSTRAINT `studio_session_user_fk` FOREIGN KEY (`user_id`) REFERENCES `studio_users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_session_times` CHECK ((`expires_at` > `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_subscriptions
CREATE TABLE `studio_subscriptions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_subscription_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `period_start` datetime(6) NOT NULL, `period_end` datetime(6) NOT NULL, `cancel_at_period_end` tinyint(1) NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `subscription_owned` (`owner_id`,`id`), UNIQUE KEY `subscription_owned_provider` (`owner_id`,`id`,`provider_key`,`provider_account`), UNIQUE KEY `subscription_provider` (`provider_key`,`provider_account`,`provider_subscription_id`), KEY `subscription_plan_fk` (`plan_version_id`), CONSTRAINT `subscription_plan_fk` FOREIGN KEY (`plan_version_id`) REFERENCES `studio_credit_plan_versions` (`id`), CONSTRAINT `subscription_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `subscription_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `subscription_state` CHECK (((`state` in (_latin1'PENDING',_latin1'ACTIVE',_latin1'PAST_DUE',_latin1'CANCELLED',_latin1'ENDED')) and (`cancel_at_period_end` in (0,1)))), CONSTRAINT `subscription_times` CHECK (((`period_end` > `period_start`) and (`updated_at` >= `created_at`))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_users
CREATE TABLE `studio_users` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `email` varchar(254) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `password_hash` varbinary(72) NOT NULL, `enabled` tinyint(1) NOT NULL DEFAULT '1', `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_user_email` (`email`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
积分账本链路
LibTV · 接口清单
共 55 个公开接口,取自源码路由盘点。路径都以 /v1 开头;写操作需要会话 Cookie、可信 Host/Origin 与 CSRF;带品牌的路径用 ?profile=libtv;共享的登录、素材、模型目录路径不接受 profile 参数。
Agent/统一动作 7 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/interactions | runInteractions | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/interactions/{interaction_id}/responses | respondInteraction | client_action_id, card_sha256, action, values | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/interaction-actions/{client_action_id} | interactionAction | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/model-changes | changeConversationModel | client_action_id, expected_revision, agent_model, expected_attempt? | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/model-changes/{client_action_id} | modelChangeAction | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/stop | stopRun | client_action_id, expected_attempt? | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/stop-actions/{client_action_id} | stopAction | 200 |
Asset 4 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/assets | listAssets | 200 | |
| POST | /v1/assets | uploadAsset | file | 201 |
| GET | /v1/assets/{asset_id} | getAsset | 200 | |
| GET | /v1/assets/{asset_id}/content | assetContent | 200/206 |
LoginSession 1 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| POST | /v1/auth/logout | logout | 200 |
MaaBinding 5 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/maa/model-options | maaModels | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/messages | sendMaaMessage | client_action_id, content | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/actions/{client_action_id} | getMaaAction | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/state | getMaaState | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/events | maaEvents | 200 |
Media 11 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/media/models | publicMediaModels | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests | createMediaRequest | client_request_id, model_id, model_version_id, prompt, duration_seconds, ratio, resolution, admission? | 200 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests | mediaRequestByClient | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id} | getMediaRequest | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs/{job_id} | getMediaJob | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs/{job_id}/output | getMediaOutput | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id}/job | mediaJobByRequest | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id}/approve | approveMediaRequest | client_approval_id, request_sha256, quote_sha256 | 200 |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/from-maa | createMediaRequestFromMaa | input, source_run_id, source_assistant_sha256, admission? | 200 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs | listMediaJobs | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/intents | listMediaIntents | 200 |
Other 9 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects/{project_id}/canvas/revisions | listCanvasRevisions | 200 | |
| GET | /v1/projects/{project_id}/canvas/revisions/{revision} | getCanvasRevision | 200 | |
| POST | /v1/projects/{project_id}/canvas/revisions/{revision}/restore | restoreCanvasRevision | expected_revision | 200 |
| GET | /v1/projects/{project_id}/document/revisions | listTimelineRevisions | 200 | |
| GET | /v1/projects/{project_id}/document/revisions/{revision} | getTimelineRevision | 200 | |
| POST | /v1/projects/{project_id}/document/revisions/{revision}/restore | restoreTimelineRevision | expected_revision | 200 |
| GET | /v1/projects/{project_id}/assets | listProjectAssets | 200 | |
| POST | /v1/projects/{project_id}/assets | attachProjectAsset | asset_id, expected_revision | 200 |
| POST | /v1/projects/{project_id}/assets/{asset_id}/detach | detachProjectAsset | expected_revision | 200 |
Project 15 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects | listProjects | 200 | |
| POST | /v1/projects | createProject | title | 201 |
| GET | /v1/projects/{project_id} | getProject | 200 | |
| GET | /v1/projects/{project_id}/conversations | listConversations | 200 | |
| POST | /v1/projects/{project_id}/conversations | createConversation | title | 201 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id} | getConversation | 200 | |
| GET | /v1/projects/{project_id}/canvas | getCanvas | 200 | |
| POST | /v1/projects/{project_id}/canvas | saveCanvas | expected_revision, state | 200 |
| GET | /v1/projects/{project_id}/document | getDocument | 200 | |
| POST | /v1/projects/{project_id}/document | saveDocument | expected_revision, state | 200 |
| GET | /v1/projects/{project_id}/export-jobs | listExportJobs | 200 | |
| POST | /v1/projects/{project_id}/export-jobs | queueExport | document_revision, output? | 202 |
| GET | /v1/projects/{project_id}/export-jobs/{job_id} | getExportJob | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/binding | getMaaBinding | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/binding | bindMaa | agent_model XOR use_default:true | 200 |
User 3 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| POST | /v1/auth/register | register | email, password | 201 |
| POST | /v1/auth/login | login | email, password | 200 |
| GET | /v1/auth/session | session | 200 |
LibTV 自己公开的接口调用流程(来自其官方资料)
| 步骤 | 调用关系 | 操作 | 证据 |
|---|---|---|---|
| 加载Web与脚本 | 浏览器 → Web入口 | GET https://www.liblib.tv/;返回HTML并加载liblibai-web-static.liblib.cloud官方JS;入口与静态资源响应分别为istio-envoy/Tengine。 | O |
| 查询Skill模板 | 浏览器 → 业务HTTP入口 | POST https://api.liblib.tv/api/community/skill/template/feed/stream;body含page/pageSize/query/tagId;返回JSON list/hasMore/total与skillKey/version/snapshot | O |
| 读取Canvas上下文 | 浏览器 → 业务HTTP入口 | 客户端GET /api/canvas/project/detail,uuid来自projectUuid;Skill引用在session create中可携带skillKey/skillVersion,画布draft与版本由独立路由管理。 | C |
| 加载或创建会话 | 浏览器 → IM入口 | GET https://im.liblib.tv/api/v1/project/session/list含projectId/type;POST /api/v1/project/session/create含projectId/name及可选canvasId/nodeKey/skillKey/ski | C |
| 发送Agent消息 | 浏览器 → IM入口 | 客户端构造wss://im.liblib.tv/ws;query字段名含token/project_id及可选canvas_id/team_id;上行JSON有threadId/messages/forwardedProps.extra。 | C |
| 消费增量事件 | IM入口 → 浏览器 | 客户端消费RUN_STARTED、TEXT_MESSAGE_START/CONTENT/END及type/seq/runId/messageId/role/delta;处理ping/pong、重连与缓存入站事件。 | C |
| 保存画布修改 | 浏览器 → 业务HTTP入口 | POST /api/canvas/nodes/batch含projectUuid/requestId/nodes与connections增改删;POST draft/update含draftJson/canvasConfigJson/viewport坐标;编辑上下文可带sessionId/times | C |
| 读取生成与产物 | 浏览器 → 业务HTTP入口 | 客户端存在/api/task/generation/create、progress、power/calculator与/api/task/artifact/list,以及媒体创建/list/copy-to-team等路径。 | C |
LibTV · 代码与下载
1.4 MB · 54 个文件 · SHA-256
1e333b70c1b66eac71ed5b15c5f508dcce4b0249ce0455701824ff232fcb426b下载:libtv-replica.zip · 后端与合同 · 全部代码
| 目录 | 内容 |
|---|---|
| frontend/ | LibTV 前端:<code>candidate-8875-unified-v22.html</code> 及它引用的全部脚本与样式 |
| contracts/ | 本品牌的表结构 SQL、ER(svg / mmd)、外键清单;接口目录(json / csv);共享身份库表结构 |
| README.md | 怎么运行、需要自备什么 |
运行前端
python3 -m http.server -d frontend 8791
# 打开 http://127.0.0.1:8791/agent-integration/apps-production-brand-v14/libtv/candidate-8875-unified-v22.htmlbackend-and-contracts.zip;all-brands-code.zip 是全部。包里没有任何凭据、数据库备份或媒体文件,已做敏感串扫描。MAA_AGENT_ROOT)、模型网关与对象存储配置。静态前端单独打开不需要后端,但登录、对话、生成、导出需要整套服务。复刻完成度(审计 2026-10-19)
结论:不是完美复刻。官方资料里的 34 项能力:实测跑通 3、只有通用对话 2、后端有但没跑过 9、没有后端 20。
真正跑通的:LibTV Agent BETA;Agent 项目多会话;导演执导。
界面对照(首页(已登录)):真实页面采集到 59 个控件 / 标题文字,复刻页找到 29 个;位置偏差中位数 88 px(5/29 个在 24 px 内)。缺的有:LibTV Agent BETA、学院 大师开讲、TV Show 全网爆款、创作者挑战赛 王者大赛、版本更新记录 v1.5、积分超市、查看全部、王者荣耀联名投稿活动 进行中、昔年、Flicker2045、炖捣像素、Nibgnahz…。
逐个点击(已登录首页):45 个可点控件,点了有效 15 个,只提示“此功能正在接入” 26 个,没反应或只变样式 0 个,禁用 0 个,未点(发送 / 删除 / 退出等)4 个。
只提示“正在接入”的控件(26 次点击,26 种)
开通会员、账号、首页、插件、学院、TV Show、创作者挑战赛、(图标)、↺ 版本更新记录、王者荣耀联名投稿活动、3D-BOX、全部、LibTV·「X小时之后」AI短片黑客松、全网爆款、王者无界剧场计划、精选画布、专业影视、短剧漫剧、商业广告、动漫游戏、教育生活、TV工具箱、降解师、抵达之前 before arrive、她能预知未来、聊斋系列之《鸦头》
复刻页自报的绑定状态(页面内嵌的绑定清单):原生工作区控件(新建项目、会话、登录等)8 / 10 个没有绑定到原页面的控件,由统一的工作区条代替;路由 projects、timeline、assets 缺失或只做了一部分;
首屏截图对照(左:真实产品 libtv/source-desktop-top-safe.png;右:复刻页)· 粗粒度差异 5%
真实截图是测试账号登录后的画面,内容(作品、项目、横幅)本来就不同,差异百分比只作参考,重点看布局。
Flova · 总览
- 它是什么:画布 / 分镜 / 时间轴三视图;Agent 交互:发送前就提示积分够不够。
- 我们借鉴:发送前说明准入;三视图共用一份项目(决策 D1 D7)。
- 复刻现状:4 项已验证,在线试用 http://119.23.106.60:8105/;后端与其余六个品牌共用一套(24 张表、55 个接口),所以 ER / 表结构 / 接口页的通用部分默认折叠。
按 12 类盘点 Agent、会话、素材、画布、分镜、时间轴、生成、Skill、文档、导出、订阅团队及外部 CLI/MCP。最新更新日志仅按官方公告 W 标注。
证据:W 官方说明,A 官方接口合同,C 客户端代码,O 实测。“未实测”= 只核对了官方页面,没有上传素材或生成。
63 项,分 12 类
首页 + 画布/分镜/时间轴
24 张表 · 34 个外键 · 85 个索引
能力目录
Agent 与规划 6 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 从需求形成创作方案 | Agent 结合项目状态理解需求,组织剧本、分镜、生成和剪辑。 | W | 未核实私有接口、质量表现及当前账号的具体额度。 |
| 生成前确认提示词 | 项目可设自动或先确认。 | W | 未运行。 |
| 显示进度并停止调整 | 可查看执行过程,停止任务后补充信息,再让 Agent 继续;手工编辑可并行进行。 | W | 停止与恢复的任务状态、扣费和取消语义没有公开合同。 |
| 运行中管理消息队列 | 排队消息可编辑或重试。 | W | 未运行。 |
| 主动搜索参考资料 | 检索参考并保存为项目文档。 | W | 待登录验证。 |
| 选项卡片澄清需求 | 用单选或多选卡片补充需求。 | W | 待登录验证。 |
项目与会话 4 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 创建项目与继续历史工作 | Web 快速开始与 CLI 指南都说明新建或继续已有项目,可从目标或 Skill 开始。 | W | 快速开始采用本轮官方检索正文;直读链接失败。项目与会话的内部关联未证实。 |
| 从消息恢复或另起分支项目 | 可返回某次 AI 回复的项目状态,或从该时点创建新项目继续探索。 | W | 这是产品层的恢复和另起项目语义,不能推断数据库版本 DAG 或合并算法。 |
| 画布局部多轮会话 | 局部追问、参考和历史。 | W | 未运行。 |
| 旧项目迁移至新版 | 旧项目可迁入新版工作区。 | W | 历史兼容性待验。 |
素材管理 5 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 多类型素材和文档上传 | 项目接收图片、视频、音频和文档,供 Agent 与手工创作引用。 | W | 不同入口的格式、尺寸和访问权限待验证。 |
| Asset 内保留 Media 版本 | 同一创作意图可收纳多份 Media,通过默认选择或收藏使用合适结果。 | W | 公开 UI 语义不证明 Asset、Media 的数据库结构或物理文件去重方式。 |
| 移动拆分与批量管理素材 | 文件可移动到其他 Asset、拆成新 Asset;支持选取、删除、下载或继续上传。 | W | 未核实私有接口、质量表现及当前账号的具体额度。 |
| 跨项目 Asset Library | 复用素材与生产文档。 | W | 授权边界待验。 |
| 裁剪素材为新 Asset | 裁剪图片、视频或音频为新素材。 | W | 未运行。 |
画布与分镜 4 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 素材画布与预览列表 | Media Space 可自由排列素材,也可用预览列表按故事顺序浏览。 | W | 素材画布不等于已验证具有可执行节点边和依赖工作流。 |
| 分镜元素与镜头编辑 | 可编辑或增删角色元素、镜头和音频卡片,调整顺序并放入聊天上下文。 | W | 未核实私有接口、质量表现及当前账号的具体额度。 |
| Asset 绑定分镜并区分用途 | 同一 Asset 可关联多个分镜,区分参考、关键帧和最终媒体等用途。 | W | 官方说明替换 Asset 的 Media 会更新引用位置;我方版本绑定策略需独立设计。 |
| 画布缩放与对齐 | 缩放、翻转、旋转和吸附。 | W | 操作对象待验。 |
时间轴编辑 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| Agent 初剪与人工精修 | Agent 先组织剪辑,用户继续调整;时间轴和分镜分别描述节奏与镜头意图。 | W | 调整时间轴不等于改写分镜文本,二者同步边界需登录验证。 |
| 裁切替换速度与音量调整 | 手工调整片段顺序、时长、速度、音量和视听同步。 | W | 未核实私有接口、质量表现及当前账号的具体额度。 |
| 片段拆分淡入与撤销 | 拆分音视频片段、淡入和撤销。 | W | 操作组合待验。 |
生成与模型 13 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 模型参数与多模态参考 | 在手工生成工具中选择模型、改提示词和参数,添加参考素材后重新生成版本。 | W | 模型的参考类型和参数支持不同,不把品牌数量当成功能数量。 |
| 图片放大 | 对图片进行清晰度升级,保留为新媒体版本。 | W | 是否扣费、分辨率和套餐准入以当前估价和账号为准。 |
| 涂画标注指导再生成 | 部分模型支持图片涂画参考。 | W | 限指定模型。 |
| 视频延长 | 指定模型可续接并沿用原设置。 | W | 限支持模型。 |
| 提取视频静帧 | 从视频当前画面提取图片,建立新的素材。 | W | 画面尺寸和输出格式待实际检查。 |
| 针对单份素材评论生成 | 对素材描述问题后生成新结果,不必重做整个项目;结果按意图归入原 Asset 或新 Asset。 | W | 这里是局部生成反馈,不能据此称为多人审阅评论系统。 |
| 视频放大 | 对视频进行清晰度升级,保留为新媒体版本。 | W | 会员和费用以当前参数预估为准;输出清晰度与帧率待验。 |
| 视频字幕去除 | 指定模型可移除烧录字幕并保留新版本。 | W | 帮助明确 Seedance 2.0 结果;更新日志另列 Seedance 2.5,不推广到所有模型。 |
| 可编辑 Prompt Draft 卡片 | 先修改草稿卡片,再付费生成。 | W | 不等于全局审批设置。 |
| 文字生成图片 | 以描述生成独立图片素材。 | W | 具体模型、参数和费用待账号确认。 |
| 文字生成视频 | 用文字描述生成视频。 | W | 限支持模型。 |
| 图片生成视频 | 参考图片生成视频。 | W | 限支持模型。 |
| 多媒体参考生成视频 | 组合多类参考生成视频。 | W | 参考限制依模型。 |
声音人物字幕 4 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 音乐生成 | 让 Agent 生成音乐,并用于项目分镜与时间轴。 | W | 音乐质量、版权条件和可用模型需按账号验证。 |
| 语音输入创作指令 | 聊天支持语音输入。 | W | 识别语言待验。 |
| 配音与旁白声音选择 | Agent 生成配音,旁白可选声音和情绪。 | W | 克隆与口型同步未知。 |
| 提取视频音频 | 从视频抽取音轨供后续复用。 | W | 单击抽取入口未实测。 |
Skill 与模板 5 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 官方社区与个人 Skill | 可发现官方或社区工作流,选用 Skill 开始项目,并保存到个人库。 | W | Skills 采用本轮官方检索正文;直读链接失败。未验证执行版本和公开审核流程。 |
| 自定义和复制 Skill | 让 Agent 创建或修改创作流程,查看结构化文档,再保存为自己的 Skill。 | W | 未核实私有接口、质量表现及当前账号的具体额度。 |
| 分享复制和撤销 Skill 链接 | 分享链接供他人预览并复制;撤销旧链接不收回已经保存的副本。 | W | 采用官方检索正文;未发布或撤销分享。权限和付费门槛待验。 |
| 发布 Skill 固定引用素材 | 固定版本并带入素材副本。 | W | 未运行。 |
| Flova TV 作品关联创作流程 | 公开作品可关联 Skill,用于继续同类创作。 | W | 发布权限待验。 |
文档与版本 4 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 项目文档和参考原件 | 项目可创建编辑文档;上传的参考原件可供阅读,生成的 Markdown 可继续修改。 | W | 未核实私有接口、质量表现及当前账号的具体额度。 |
| 局部文档加入 Agent 上下文 | 选择文档片段放入聊天,维护 FinalVideoSpec 或 Skill 指令,聚焦修改目标。 | W | 未核实私有接口、质量表现及当前账号的具体额度。 |
| 文档和 Skill 修改对比 | 查看 Agent 修改差异。 | W | 未运行。 |
| 并行修改时选择保留版本 | 用户与 Agent 处理同一内容产生冲突时,可在界面选择要保留的结果。 | W | 不证明字段级自动合并、锁协议或数据库 CAS。 |
导出与交付 4 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 后台导出当前时间轴 | 导出当前剪辑,查看状态,完成后下载;失败可在界面重试。 | W | 导出耗时、重试扣费和幂等合同未验证。 |
| 交接外部剪辑工程 | 可导出含素材的剪辑工程包,交给 Premiere、Final Cut 或区域对应的剪映/CapCut。 | W | 各软件支持条件不同,媒体路径、转场和音频兼容性需真实导入验证。 |
| 项目与素材多种下载 | 支持项目媒体 ZIP、单个文件、Asset 多版本及所选素材批量下载。 | W | 批量只包含已成功生成的内容;不能据此认定为完整审计备份。 |
| 截取时间轴静帧 | 可把播放头对应的画面保存为图片。 | W | 未核实私有接口、质量表现及当前账号的具体额度。 |
订阅与团队 6 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 模型费用估算与积分用量 | 积分随模型、参数和素材变化;账号可查余额、消耗与估价,生成受限时有原因说明。 | W | 不写固定价格或额度;失败返还、有效期和账单结算需按具体订单核实。 |
| 订阅分层与资源权益 | 会员权益涵盖模型、并发、清晰度、放大、素材容量、去水印等,支持管理续费和升级。 | W | 个人和团队、地区及活动权益可能不同;商业许可按素材与模型条款核验。 |
| 个人团队工作区与资源管理 | 切换工作区、席位和积分管理。 | W | 多人编辑待验。 |
| 订单发票与处理状态 | 查看、开具或重发订单发票。 | W | 退款订单关闭入口。 |
| 邀请奖励与邀请记录 | 查看邀请条件、奖励和历史。 | W | 资格和期限以账号为准。 |
| 反馈中心持续对话 | 补充问题并查看官方回复。 | W | 不自动修复项目。 |
外部接入与 App 5 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| CLI 创建继续与检查项目 | 外部 Agent 可经 CLI 登录,创建或继续项目,读状态、上传素材、使用 Skill 并导出。 | W | 仅阅读指南,未安装或授权;CLI 不是 Web 会话协议证据。 |
| CLI 分阶段执行与费用阻塞处理 | CLI 指南支持阶段确认、复用已批准结果,以及积分不足时暂停和读取状态后继续处理。 | W | 监控中断后读状态不等于已证明模型任务自动续跑或跨进程恰好执行一次。 |
| 官方公布 MCP 授权接入 | 查建项目、上传、运行、恢复、导出。 | W | 仅 W 公告;工具 schema 和 Web 协议未知。 |
| 浏览器或 API Key 授权 | 外部 Agent 接入支持两种授权。 | W | 未取得授权范围和撤销合同。 |
| CLI 引用 Skill 分享码 | 外部 Agent 可引用 Skill 分享码。 | W | 未运行。 |
尚不清楚的部分
- MCP 地址、授权详情与工具 schema:2026-08-17 更新日志公布 MCP 项目接入能力,未提供本轮可核验的 endpoint、tools/list 或运行报文。
- Web Agent 的传输、会话 ID 与恢复包:官方工作流和外部 CLI 不能证明 Web 使用 SSE、WebSocket 或哪种事件结构。
- 自动字幕、配音克隆、口型同步与数字人:已确认音乐配音及指定模型字幕去除,未取得足够官方完整流程证明这些额外能力。
- 同项目多人实时编辑和审阅权限:团队工作区、席位及项目复制已公告,不能据此推断实时多人光标、冲突合并或审阅角色体系。
- 素材库的账号级权限和版本传播范围:官方说明跨项目复用及 Asset 关联更新,但复用副本、团队授权和运行时快照边界未实测。
- 分支历史、恢复保留期及取消结算:回到消息、新项目分支和冲突选择有文档,服务端版本结构、状态原子性与费用处理未知。
竞品技术栈观察
当前能支持公开页面壳、CLI 项目接入的官方说明及 flova.tv 的入口 CNAME。没有当前生产脚本或编译元数据,无法确认 Nginx、前后端语言/框架/版本、源站区域及仓库布局。
| 项目 | 观察到的内容 | 状态 | 置信度 |
|---|---|---|---|
| Nginx 与版本 | 是否使用 Nginx、所在层及版本均未确认。 | unknown | low |
| 浏览器运行语言 | 公开 Web 壳可读取;业务 JavaScript/Wasm 的具体运行实现未取得。 | unknown | low |
| 前端源码语言 | Web 源码语言及 CLI 实现语言均未确认。 | unknown | low |
| 前端框架与版本 | React、Next.js 等框架及版本均未确认。 | unknown | low |
| 构建与 SSR | SSR、构建器和 hydration 方案未确认。 | unknown | low |
| 后端语言 | Web 后端语言未确认;CLI 合同不代表 Web 后端实现。 | unknown | low |
| 后端框架与版本 | Web 后端框架、数据库驱动与版本均未确认。 | unknown | low |
| 边缘入口与源站 | flova.tv CNAME 指向 kunlunaq 域;边缘供应商、区域及真实源站未确认。 | observed | high |
| 代码仓库与目录 | 前后端同目录、仓库数量及 CLI 与 Web 是否共享仓库均未知。 | unknown | low |
竞品服务调用图
当前官方 Web 过程支持项目、Agent、素材/分镜、Timeline 与导出;历史 v0.0.10 CLI 合同提供 Project/Run/Action/Resource/ExportTask 字段。图只表达逻辑职责与合同边界,当前 Web 包结构和部署拓扑未知。
| 节点 | 层 | 职责 | 证据 |
|---|---|---|---|
| Web创作界面 | client | 展示 Agent、Media Space/Canvas、Timeline 与 Docs。 | W |
| 外部CLI接入 | client | 历史 CLI 命令客户端,操作完整 Flova 项目。 | A |
| Web公开入口 | entry | flova.tv 公共入口,有同日 kunlunaq CNAME 记录。 | O |
| 项目上下文职责 | domain | 提供同一项目的规格、Skill、分镜、媒体、文档及 Timeline。 | W |
| Agent执行职责 | runtime | 历史 Run 合同区分 project_id 与 stream_chat_id,并返回执行结果。 | A |
| 待决项职责 | domain | 历史 pending_actions 对应当前消息边界与选项。 | A |
| 素材组织职责 | domain | Asset 收纳媒体版本,Canvas/预览及用途绑定用于组织素材。 | W |
| 资源状态职责 | domain | 历史资源合同提供状态、预览 URL、错误与不透明版本。 | A |
| 分镜编辑职责 | domain | 维护叙事、镜头与素材用途关系。 | W |
| 时间轴编辑职责 | domain | 编排最终顺序、时长和声音,人工可继续细调。 | W |
| 历史恢复职责 | domain | 历史合同以消息定位 restore 或复制新 Project 的 branch。 | A |
| 导出任务职责 | runtime | 历史 ExportTask 与 Run 分开;最终视频使用 export_url。 | A |
| 项目状态保留 | data | 可能保存可重新读取的项目、历史与资源定位信息。 | I |
增长与运营机制
复刻状态
| 能力 | 状态 | 依据 |
|---|---|---|
| 令牌与通用层加载、新建项目与会话 | 已验证 | 页面上的「+ 新建项目」按钮能打开对话框 |
| Agent 对话:自动选默认模型、发送收回复 | 已验证 | 真实 Maa,收到回复 |
| 停止回复 | 已验证 | maa_run_stop_actions=terminal_observed,run=cancelled |
| 画布、分镜、时间轴布局 | 已加载 | 沿用早期静态页 |
| 生成视频(报价→批准→成片) | 已验证 | 测试部署 119.23.106.60:8105 上真实生成:Seedance 2.0 Mini 5 秒,报价 3 积分,批准后任务成功、产出 MP4(接口级验证;素材页展示未逐项核对) |
agent-integration/apps-production-brand-v14/flova/candidate-8875-unified-v22.html复刻的架构 七个品牌相同,展开查看
flowchart LR U[浏览器] -->|静态页| FE[品牌前端<br/>令牌 + 通用层 + 运行时脚本] FE -->|/v1/* Cookie + CSRF| BFF[BFF 业务服务 Go] BFF --> MY[(MySQL<br/>共享身份库 + 品牌库)] BFF -->|会话 / 消息 / 事件| MAA[Maa Agent] BFF -->|任务| WK[媒体 worker] WK -->|submit_video| GW[模型网关] GW --> MOD[视频模型] MAA --> GW BFF --> OBJ[(素材 / 导出存储)]
?profile=flova 区分品牌)。品牌差异在前端:令牌(颜色、圆角、字体)、入口与页面结构。Flova · Agent 交互过程
竞品里观察到的
NOT_RUN_CREDIT_GATE 聊天区在发送前明确提示积分不足,并显示购买入口;0积分下未实际Send,不把手工Markdown文档当Agent计划。
| 编号 | 操作 | 结果 |
|---|---|---|
| 打开既有空测试工程的对话区 | 暂无消息;积分不足,购买;消息为空时生成按钮禁用。 |
费用与准入
| 项 | 值 |
|---|---|
| plan | Free |
| visible_balance | 0 |
| chat_gate | 积分不足 |
| charged | false |
| top_up | false |
对我们设计的启示
| 结论 | 内容 | 做法 / 原因 |
|---|---|---|
| 发送前即可显示准入门槛与明确原因,保留手写文档及当前工程,不把用户引导到反复重试。 |
竞品公开的调用流程
| 步骤 | 调用关系 | 操作 | 证据 |
|---|---|---|---|
| 连接账号 | 创作者 → 接入端 | 从 Web 或外部 CLI 进入账号;CLI 官方指南使用浏览器账号授权。 | W |
| 建立项目上下文 | 接入端 → 项目上下文 | 历史 CLI:project create --name --description 返回 project_id/project_url;已有项目按 ID 读取上下文。 | A |
| 附上参考素材 | 接入端 → 项目上下文 | 历史 CLI 上传先获得文件对象;随后通过 run 的 --file-from 附给本次输入。 | A |
| 启动创作Run | 接入端 → Agent执行 | 历史 CLI:run PROJECT_ID --content;结果含 project_id、stream_chat_id、terminal、assistant_messages、pending_actions。 | A |
| 报告进度与待决项 | Agent执行 → 接入端 | 返回消息与 pending_actions;Action 字段有 action_id、resume_message_id、blocking、options[].id/effect。 | A |
| 形成可用资源 | Agent执行 → 资源与编辑 | 历史 Resource 含 resource_id、media_type、artifact_role、status、resource_url、error、state_version;官方 Web 把结果展示在相应面板。 | A |
| 检查并细调工程 | 创作者 → 资源与编辑 | 检查 Media Space/Canvas 与分镜,手改 Timeline;需要时从消息恢复或在新 Project 分叉。 | W |
| 提交并检查导出 | 接入端 → 导出任务 | 历史 CLI 导出/打包另有 task_id 与 terminal,视频交付含 export_url;官方 Web 导出当前 Timeline。 | A |
在本品牌复刻上的测试结果
| 能力 | 状态 | 依据 |
|---|---|---|
| Agent 对话:自动选默认模型、发送收回复 | 已验证 | 真实 Maa,收到回复 |
| 停止回复 | 已验证 | maa_run_stop_actions=terminal_observed,run=cancelled |
| 生成视频(报价→批准→成片) | 已验证 | 测试部署 119.23.106.60:8105 上真实生成:Seedance 2.0 Mini 5 秒,报价 3 积分,批准后任务成功、产出 MP4(接口级验证;素材页展示未逐项核对) |
复刻里的 Agent 交互设计(时序图、状态机、规则) 七个品牌相同,展开查看
sequenceDiagram
autonumber
participant B as 浏览器
participant S as BFF
participant DB as MySQL
participant M as Maa Agent
participant W as 媒体 worker
participant G as 模型网关
B->>S: POST /projects, /conversations
B->>S: POST maa/binding
S->>DB: maa_bindings dispatching
S->>M: 创建原生会话
M-->>S: native_cid
S->>DB: maa_bindings bound
B->>S: POST maa/messages {client_action_id, content}
S->>DB: maa_message_actions 幂等回执
S-->>B: 202 + run_id
S->>M: 提交消息
S->>DB: maa_runs queued 到 running
loop 事件游标
B->>S: GET runs/{id}/events
S-->>B: assistant.delta / assistant.message
end
M-->>S: run.completed
S->>DB: 记录助手内容 SHA-256
B->>S: POST media/requests/from-maa {source_run_id, sha256}
S-->>B: 报价 + 有效期 + quote_sha256
B->>S: POST approve {client_approval_id, request_sha256, quote_sha256}
S->>DB: 冻结积分 + 建任务
W->>G: submit_video
G-->>W: 视频
W->>DB: 产出入库 + 扣费
B->>S: GET media/jobs/{id}Run 状态机
stateDiagram-v2 [*] --> queued: POST maa/messages 202 queued --> running running --> waiting_interaction: 需要澄清卡 waiting_interaction --> running: respondInteraction running --> completed running --> failed running --> cancelled: stopRun waiting_interaction --> cancelled completed --> [*] failed --> [*] cancelled --> [*]
媒体任务状态机
stateDiagram-v2 [*] --> quoted quoted --> expired: 约 5 分钟 quoted --> approved: approve approved --> held: 冻结积分 held --> queued queued --> running: worker 领取 running --> succeeded: 产出入库 succeeded --> captured: 扣费确认 running --> failed failed --> 待核对: 供应商已受理后失败,冻结保留,界面写「费用待核对」
交互规则
| 环节 | 规则 | 落库 |
|---|---|---|
| 绑定会话 | bindMaa 传 agent_model 或 use_default;先 dispatching,拿到原生会话号后才 bound(约束保证二者一致) | maa_bindings |
| 发消息 | client_action_id 幂等;返回 202 + run_id;同一个动作 ID 内容不同返回 409 | maa_message_actions, maa_runs |
| 事件 | 按 seq 游标读取;服务端先清洗路径、内部地址和令牌再公开 | maa_runs.last_event_seq |
| 完成证据 | 完成时记录助手内容的两份 SHA-256 与字节数 | maa_runs |
| 澄清卡(HITL) | Run 进入 waiting_interaction;respondInteraction 带 card_sha256;不能恢复两次 | maa_interactions, maa_interaction_actions |
| 停止 | stopRun 幂等,回执只说「已观测到终态」;对话里保留「已停止回复」 | maa_run_stop_actions |
| 切换模型 | 必须带 expected_revision;有未决切换时拒绝发新消息 | maa_model_change_actions |
| 生成视频 | from-maa → 报价 → 批准 → 冻结 → worker → 入库 → 扣费;批准带请求哈希与报价哈希 | studio_media_*, 积分账本 |
| 报价过期 | 批准被拒,不建任务不扣费;界面提示重新报价 | studio_media_requests.expires_at |
| 失败后的积分 | 供应商已受理后失败:冻结保留,界面写「费用待核对」,不自动释放;本部署的账本里还没出现过释放分录(12 笔冻结、8 笔扣费、其余 4 笔仍冻结) | studio_credit_ledger_entries |
| 会话过期 | 每 8 秒检查登录状态;失效时横幅提示,登录后恢复 | — |
Flova · ER 图
品牌库 studio_profile_flova:24 张表、34 个真实外键、66 个检查约束、22 个触发器。图由实际表结构生成,箭头从父表指向子表。品牌库与共享身份库之间的 owner_id、asset_id 靠应用层归属检查,不画成外键。
共 61 条关系:一对多 37 条,一对一 10 条,一对多(父可选) 10 条,一对一(父可选) 4 条;多对多 2 组(经关联表)。
用户与登录 素材 积分账本 支付与订阅 模型目录 项目与会话 画布 · 时间轴 · 导出 Agent 交互 生成 · 媒体 · 交付
基数标注(线上的文字,箭头从父表指向子表):1:N 一对多,子表外键必填;0..1:N 一对多,但外键可空,所以父是可选的;1:1 一对一,子表外键上有唯一键;0..1:1 一对一且父可选。红色粗双向线 = N:M 多对多,经带 ⇄ 的关联表(它的主键就是两个外键)。实线 = 数据库真实外键;灰色虚线 = 跨库关系(两个库之间数据库无法建外键,由应用层检查);橙色粗框与粗线 = Agent 交互相关。每张表都带 owner_id(指向用户),为了图清楚没有逐条画线。
全景图:全部实体与关系
默认缩放到页面宽度,先看整体结构;点一下图切换到原始大小(看清表名,在框内上下左右滚动),再点一下缩回。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":26,"rankSpacing":80}}}%%
flowchart LR
subgraph sg_i_user["用户与登录"]
direction TB
t_studio_users["users"]
t_studio_sessions["sessions"]
end
subgraph sg_i_asset["素材"]
direction TB
t_studio_assets["assets"]
end
subgraph sg_i_credit["积分账本"]
direction TB
t_studio_credit_accounts["credit_accounts"]
t_studio_credit_lots["credit_lots"]
t_studio_credit_authorizations["credit_authorizations"]
t_studio_credit_authorization_allocations["⇄ credit_authorization_allocations"]
t_studio_credit_ledger_entries["credit_ledger_entries"]
t_studio_credit_plan_versions["credit_plan_versions"]
t_studio_billing_cycles["billing_cycles"]
end
subgraph sg_i_pay["支付与订阅"]
direction TB
t_studio_payment_orders["payment_orders"]
t_studio_payment_events["payment_events"]
t_studio_subscriptions["subscriptions"]
end
subgraph sg_i_model["模型目录"]
direction TB
t_studio_media_models["media_models"]
t_studio_media_model_versions["media_model_versions"]
end
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_canvas["画布 · 时间轴 · 导出"]
direction TB
t_studio_video_documents["video_documents"]
t_studio_canvases["canvases"]
t_studio_canvas_revisions["canvas_revisions"]
t_studio_timeline_revisions["timeline_revisions"]
t_studio_export_jobs["export_jobs"]
t_studio_project_asset_refs["⇄ project_asset_refs"]
end
subgraph sg_agent["⭕ Agent 交互"]
direction TB
t_maa_bindings["maa_bindings"]
t_maa_runs["maa_runs"]
t_maa_message_actions["maa_message_actions"]
t_maa_interactions["maa_interactions"]
t_maa_interaction_actions["maa_interaction_actions"]
t_maa_model_change_actions["maa_model_change_actions"]
t_maa_run_stop_actions["maa_run_stop_actions"]
end
subgraph sg_media["生成 · 媒体 · 交付"]
direction TB
t_studio_media_requests["media_requests"]
t_studio_media_jobs["media_jobs"]
t_studio_media_submission_attempts["media_submission_attempts"]
t_studio_media_outputs["media_outputs"]
t_generation_jobs["gen_jobs"]
t_generation_reservations["gen_reservations"]
t_generation_deliveries["gen_deliveries"]
t_generation_development_budgets["gen_development_budgets"]
t_studio_credit_recovery_intents["credit_recovery_intents"]
end
t_studio_users -->|"1:N"| t_studio_assets
t_studio_payment_orders -->|"1:1"| t_studio_billing_cycles
t_studio_subscriptions -->|"1:N"| t_studio_billing_cycles
t_studio_users -->|"1:1"| t_studio_credit_accounts
t_studio_credit_authorizations -->|"1:N"| t_studio_credit_authorization_allocations
t_studio_credit_lots -->|"1:N"| t_studio_credit_authorization_allocations
t_studio_credit_accounts -->|"1:N"| t_studio_credit_authorizations
t_studio_credit_authorization_allocations -->|"0..1:N"| t_studio_credit_ledger_entries
t_studio_credit_authorizations -->|"0..1:N"| t_studio_credit_ledger_entries
t_studio_credit_lots -->|"1:N"| t_studio_credit_ledger_entries
t_studio_credit_accounts -->|"1:N"| t_studio_credit_lots
t_studio_billing_cycles -->|"0..1:1"| t_studio_credit_lots
t_studio_payment_orders -->|"0..1:1"| t_studio_credit_lots
t_studio_media_models -->|"1:N"| t_studio_media_model_versions
t_studio_media_model_versions -->|"0..1:1"| t_studio_media_models
t_studio_payment_orders -->|"0..1:N"| t_studio_payment_events
t_studio_subscriptions -->|"0..1:N"| t_studio_payment_events
t_studio_users -->|"1:N"| t_studio_payment_events
t_studio_credit_plan_versions -->|"1:N"| t_studio_payment_orders
t_studio_users -->|"1:N"| t_studio_payment_orders
t_studio_users -->|"1:N"| t_studio_sessions
t_studio_credit_plan_versions -->|"1:N"| t_studio_subscriptions
t_studio_users -->|"1:N"| t_studio_subscriptions
t_generation_jobs -->|"1:1"| t_generation_deliveries
t_studio_projects -->|"1:N"| t_generation_deliveries
t_studio_conversations -->|"1:N"| t_generation_deliveries
t_generation_development_budgets -->|"1:N"| t_generation_jobs
t_studio_projects -->|"1:N"| t_generation_jobs
t_studio_conversations -->|"1:N"| t_generation_jobs
t_generation_jobs -->|"1:1"| t_generation_reservations
t_studio_conversations -->|"1:1"| t_maa_bindings
t_maa_model_change_actions -->|"0..1:1"| t_maa_bindings
t_maa_interactions -->|"1:1"| t_maa_interaction_actions
t_maa_runs -->|"1:N"| t_maa_interactions
t_maa_bindings -->|"1:N"| t_maa_message_actions
t_maa_runs -->|"0..1:N"| t_maa_message_actions
t_maa_bindings -->|"1:N"| t_maa_model_change_actions
t_maa_runs -->|"1:1"| t_maa_run_stop_actions
t_maa_bindings -->|"1:N"| t_maa_runs
t_studio_canvases -->|"1:N"| t_studio_canvas_revisions
t_studio_canvas_revisions -->|"0..1:N"| t_studio_canvas_revisions
t_studio_projects -->|"1:1"| t_studio_canvases
t_studio_projects -->|"1:N"| t_studio_conversations
t_studio_media_jobs -->|"1:N"| t_studio_credit_recovery_intents
t_studio_projects -->|"1:N"| t_studio_export_jobs
t_studio_media_requests -->|"1:1"| t_studio_media_jobs
t_studio_media_jobs -->|"1:N"| t_studio_media_outputs
t_studio_conversations -->|"1:N"| t_studio_media_requests
t_maa_runs -->|"0..1:N"| t_studio_media_requests
t_studio_media_jobs -->|"1:N"| t_studio_media_submission_attempts
t_studio_projects -->|"1:N"| t_studio_project_asset_refs
t_studio_video_documents -->|"1:N"| t_studio_timeline_revisions
t_studio_timeline_revisions -->|"0..1:N"| t_studio_timeline_revisions
t_studio_projects -->|"1:1"| t_studio_video_documents
t_studio_assets -.->|"1:N"| t_studio_project_asset_refs
t_studio_assets -.->|"1:N"| t_studio_media_outputs
t_studio_assets -.->|"1:N"| t_generation_deliveries
t_studio_media_model_versions -.->|"1:N"| t_studio_media_requests
t_studio_media_models -.->|"1:N"| t_studio_media_requests
t_studio_credit_authorizations -.->|"0..1:N"| t_studio_media_jobs
t_studio_credit_authorizations -.->|"0..1:N"| t_studio_credit_recovery_intents
t_studio_credit_authorizations <-.->|"N:M · 经 credit_authorization_allocations"| t_studio_credit_lots
t_studio_projects <-.->|"N:M · 经 project_asset_refs"| t_studio_assets
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_users,t_studio_sessions user
class t_studio_assets asset
class t_studio_credit_accounts,t_studio_credit_lots,t_studio_credit_authorizations,t_studio_credit_authorization_allocations,t_studio_credit_ledger_entries,t_studio_credit_plan_versions,t_studio_billing_cycles credit
class t_studio_payment_orders,t_studio_payment_events,t_studio_subscriptions pay
class t_studio_media_models,t_studio_media_model_versions model
class t_studio_projects,t_studio_conversations project
class t_studio_video_documents,t_studio_canvases,t_studio_canvas_revisions,t_studio_timeline_revisions,t_studio_export_jobs,t_studio_project_asset_refs canvas
class t_maa_bindings,t_maa_runs,t_maa_message_actions,t_maa_interactions,t_maa_interaction_actions,t_maa_model_change_actions,t_maa_run_stop_actions agent
class t_studio_media_requests,t_studio_media_jobs,t_studio_media_submission_attempts,t_studio_media_outputs,t_generation_jobs,t_generation_reservations,t_generation_deliveries,t_generation_development_budgets,t_studio_credit_recovery_intents media
class t_studio_credit_authorization_allocations,t_studio_project_asset_refs junction
style sg_i_user fill:none,stroke:#6b7280,stroke-width:1px,stroke-dasharray:5 4
style sg_i_asset fill:none,stroke:#06b6d4,stroke-width:1px,stroke-dasharray:5 4
style sg_i_credit fill:none,stroke:#eab308,stroke-width:1px,stroke-dasharray:5 4
style sg_i_pay fill:none,stroke:#ec4899,stroke-width:1px,stroke-dasharray:5 4
style sg_i_model fill:none,stroke:#6366f1,stroke-width:1px,stroke-dasharray:5 4
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_canvas fill:none,stroke:#3b82f6,stroke-width:1px
style sg_agent fill:#fff7ed,stroke:#f97316,stroke-width:4px
style sg_media fill:none,stroke:#22c55e,stroke-width:1px
linkStyle 30,31,32,33,34,35,36,37,38,48 stroke:#f97316,stroke-width:2.5px
linkStyle 54,55,56,57,58,59,60 stroke:#64748b,stroke-width:1.5px,stroke-dasharray:4 3
linkStyle 61,62 stroke:#dc2626,stroke-width:3px多对多(N:M)
数据库里没有“多对多”这种列,它总是靠一张关联表表达。下面这几张表的主键由两个外键组成,所以它们两端是多对多:
| 多对多的两端 | 关联表 | 关联表的主键 / 唯一键 |
|---|---|---|
studio_credit_authorizations ⇄ studio_credit_lots | studio_credit_authorization_allocations | owner_id, authorization_id, lot_id |
studio_projects ⇄ studio_assets | studio_project_asset_refs | project_id, asset_id |
Agent 交互相关(圈出来)
绑定 → Run → 消息 / 澄清卡 / 切换模型 / 停止,每个动作一张回执表;线上是“外键列 · 基数”。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":40,"rankSpacing":90}}}%%
flowchart LR
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_agent["⭕ Agent 交互"]
direction TB
t_maa_bindings["maa_bindings"]
t_maa_runs["maa_runs"]
t_maa_message_actions["maa_message_actions"]
t_maa_interactions["maa_interactions"]
t_maa_interaction_actions["maa_interaction_actions"]
t_maa_model_change_actions["maa_model_change_actions"]
t_maa_run_stop_actions["maa_run_stop_actions"]
end
t_studio_conversations -->|"conversation_id · 1:1"| t_maa_bindings
t_maa_model_change_actions -->|"pending_model_change_id · 0..1:1"| t_maa_bindings
t_maa_interactions -->|"interaction_id · 1:1"| t_maa_interaction_actions
t_maa_runs -->|"public_run_id · 1:N"| t_maa_interactions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_message_actions
t_maa_runs -->|"public_run_id · 0..1:N"| t_maa_message_actions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_model_change_actions
t_maa_runs -->|"public_run_id · 1:1"| t_maa_run_stop_actions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_runs
t_studio_projects -->|"project_id · 1:N"| t_studio_conversations
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_projects,t_studio_conversations project
class t_maa_bindings,t_maa_runs,t_maa_message_actions,t_maa_interactions,t_maa_interaction_actions,t_maa_model_change_actions,t_maa_run_stop_actions agent
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_agent fill:#fff7ed,stroke:#f97316,stroke-width:4px
linkStyle 0,1,2,3,4,5,6,7,8 stroke:#f97316,stroke-width:2.5px画布与时间轴
项目下是一份视频文档,画布、画布版本、时间线版本和导出都挂在这份文档上;素材放在共享身份库,项目只记引用,项目与素材是多对多,经 project_asset_refs。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":40,"rankSpacing":90}}}%%
flowchart LR
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_canvas["画布 · 时间轴 · 导出"]
direction TB
t_studio_video_documents["video_documents"]
t_studio_canvases["canvases"]
t_studio_canvas_revisions["canvas_revisions"]
t_studio_timeline_revisions["timeline_revisions"]
t_studio_export_jobs["export_jobs"]
t_studio_project_asset_refs["⇄ project_asset_refs"]
end
subgraph sg_asset["素材(共享身份库)"]
direction TB
t_studio_assets["assets"]
end
t_studio_canvases -->|"project_id · 1:N"| t_studio_canvas_revisions
t_studio_canvas_revisions -->|"restored_from_revision · 0..1:N"| t_studio_canvas_revisions
t_studio_projects -->|"project_id · 1:1"| t_studio_canvases
t_studio_projects -->|"project_id · 1:N"| t_studio_conversations
t_studio_projects -->|"project_id · 1:N"| t_studio_export_jobs
t_studio_projects -->|"project_id · 1:N"| t_studio_project_asset_refs
t_studio_video_documents -->|"project_id · 1:N"| t_studio_timeline_revisions
t_studio_timeline_revisions -->|"restored_from_revision · 0..1:N"| t_studio_timeline_revisions
t_studio_projects -->|"project_id · 1:1"| t_studio_video_documents
t_studio_assets -.->|"asset_id · 1:N"| t_studio_project_asset_refs
t_studio_projects <-.->|"N:M · 经 project_asset_refs"| t_studio_assets
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_projects,t_studio_conversations project
class t_studio_video_documents,t_studio_canvases,t_studio_canvas_revisions,t_studio_timeline_revisions,t_studio_export_jobs,t_studio_project_asset_refs canvas
class t_studio_assets asset
class t_studio_project_asset_refs junction
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_canvas fill:none,stroke:#3b82f6,stroke-width:1px
style sg_asset fill:none,stroke:#06b6d4,stroke-width:1px
linkStyle 9 stroke:#64748b,stroke-width:1.5px,stroke-dasharray:4 3
linkStyle 10 stroke:#dc2626,stroke-width:3px关系清单 逐条 61 条,含基数
| 父表 | 子表 | 外键列(子表里) | 基数 | 约束 | 域 |
|---|---|---|---|---|---|
generation_jobs | generation_deliveries | job_id | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_assets | generation_deliveries | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 生成 · 媒体 · 交付 |
studio_conversations | generation_deliveries | owner_id, project_id, session_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_projects | generation_deliveries | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
generation_development_budgets | generation_jobs | owner_id, budget_id | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_conversations | generation_jobs | owner_id, project_id, session_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_projects | generation_jobs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
generation_jobs | generation_reservations | job_id, budget_id, owner_id | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
maa_model_change_actions | maa_bindings | owner_id, project_id, conversation_id, id, pending_model_change_id | 0..1:1 一对一(父可选) | DB 外键 | Agent 交互 → Agent 交互 |
studio_conversations | maa_bindings | owner_id, project_id, conversation_id | 1:1 一对一 | DB 外键 | 项目与会话 → Agent 交互 |
maa_interactions | maa_interaction_actions | owner_id, project_id, conversation_id, binding_id, public_run_id, interaction_id | 1:1 一对一 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_interactions | owner_id, project_id, conversation_id, binding_id, public_run_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_message_actions | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_message_actions | owner_id, project_id, conversation_id, binding_id, public_run_id | 0..1:N 一对多(父可选) | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_model_change_actions | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_run_stop_actions | owner_id, project_id, conversation_id, binding_id, public_run_id | 1:1 一对一 | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_runs | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
studio_users | studio_assets | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 素材 |
studio_payment_orders | studio_billing_cycles | owner_id, payment_order_id, plan_version_id | 1:1 一对一 | DB 外键 | 支付与订阅 → 积分账本 |
studio_subscriptions | studio_billing_cycles | owner_id, subscription_id, provider_key, provider_account | 1:N 一对多 | DB 外键 | 支付与订阅 → 积分账本 |
studio_canvas_revisions | studio_canvas_revisions | owner_id, project_id, kind, restored_from_revision | 0..1:N 一对多(父可选) | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_canvases | studio_canvas_revisions | owner_id, project_id | 1:N 一对多 | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_projects | studio_canvases | owner_id, project_id | 1:1 一对一 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_projects | studio_conversations | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 项目与会话 |
studio_users | studio_credit_accounts | owner_id | 1:1 一对一 | DB 外键 | 用户与登录 → 积分账本 |
studio_credit_authorizations | studio_credit_authorization_allocations | owner_id, authorization_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_lots | studio_credit_authorization_allocations | owner_id, lot_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_accounts | studio_credit_authorizations | owner_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_authorization_allocations | studio_credit_ledger_entries | owner_id, authorization_id, lot_id | 0..1:N 一对多(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_authorizations | studio_credit_ledger_entries | owner_id, authorization_id | 0..1:N 一对多(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_lots | studio_credit_ledger_entries | owner_id, lot_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_billing_cycles | studio_credit_lots | owner_id, source_cycle_id | 0..1:1 一对一(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_accounts | studio_credit_lots | owner_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_payment_orders | studio_credit_lots | owner_id, source_order_id | 0..1:1 一对一(父可选) | DB 外键 | 支付与订阅 → 积分账本 |
studio_credit_authorizations | studio_credit_recovery_intents | authorization_id | 0..1:N 一对多(父可选) | 跨库(应用层检查) | 积分账本 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_credit_recovery_intents | owner_id, project_id, conversation_id, job_id, request_sha256 | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_projects | studio_export_jobs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_credit_authorizations | studio_media_jobs | credit_authorization_id | 0..1:N 一对多(父可选) | 跨库(应用层检查) | 积分账本 → 生成 · 媒体 · 交付 |
studio_media_requests | studio_media_jobs | owner_id, project_id, conversation_id, request_id, request_sha256, quote_sha256 | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_media_models | studio_media_model_versions | model_id | 1:N 一对多 | DB 外键 | 模型目录 → 模型目录 |
studio_media_model_versions | studio_media_models | id, published_version_id | 0..1:1 一对一(父可选) | DB 外键 | 模型目录 → 模型目录 |
studio_assets | studio_media_outputs | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_media_outputs | owner_id, project_id, conversation_id, job_id | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
maa_runs | studio_media_requests | owner_id, project_id, conversation_id, source_binding_id, source_run_id | 0..1:N 一对多(父可选) | DB 外键 | Agent 交互 → 生成 · 媒体 · 交付 |
studio_conversations | studio_media_requests | owner_id, project_id, conversation_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_media_model_versions | studio_media_requests | model_version_id | 1:N 一对多 | 跨库(应用层检查) | 模型目录 → 生成 · 媒体 · 交付 |
studio_media_models | studio_media_requests | model_id | 1:N 一对多 | 跨库(应用层检查) | 模型目录 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_media_submission_attempts | owner_id, project_id, conversation_id, job_id, request_sha256 | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_payment_orders | studio_payment_events | owner_id, order_id, provider_key, provider_account | 0..1:N 一对多(父可选) | DB 外键 | 支付与订阅 → 支付与订阅 |
studio_subscriptions | studio_payment_events | owner_id, subscription_id, provider_key, provider_account | 0..1:N 一对多(父可选) | DB 外键 | 支付与订阅 → 支付与订阅 |
studio_users | studio_payment_events | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_credit_plan_versions | studio_payment_orders | plan_version_id | 1:N 一对多 | DB 外键 | 积分账本 → 支付与订阅 |
studio_users | studio_payment_orders | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_assets | studio_project_asset_refs | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 画布 · 时间轴 · 导出 |
studio_projects | studio_project_asset_refs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_users | studio_sessions | user_id | 1:N 一对多 | DB 外键 | 用户与登录 → 用户与登录 |
studio_credit_plan_versions | studio_subscriptions | plan_version_id | 1:N 一对多 | DB 外键 | 积分账本 → 支付与订阅 |
studio_users | studio_subscriptions | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_timeline_revisions | studio_timeline_revisions | owner_id, project_id, kind, restored_from_revision | 0..1:N 一对多(父可选) | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_video_documents | studio_timeline_revisions | owner_id, project_id | 1:N 一对多 | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_projects | studio_video_documents | owner_id, project_id | 1:1 一对一 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
完整 ER:39 张表的全部列,带主键 / 外键与基数符号(鸦脚)
erDiagram
studio_assets {
CHAR id PK
CHAR owner_id FK
CHAR sha256
JSON metadata_json
VARCHAR storage_key
DATETIME created_at
VARCHAR publication_state
}
studio_billing_cycles {
CHAR id PK
CHAR owner_id FK
CHAR subscription_id FK
CHAR plan_version_id FK
CHAR payment_order_id FK
VARCHAR provider_key FK
VARCHAR provider_account FK
VARCHAR provider_invoice_id
DATETIME period_start
DATETIME period_end
BIGINT_UNSIGNED grant_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
VARCHAR state
CHAR paid_evidence_sha256
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_accounts {
CHAR owner_id PK
VARCHAR unit
VARCHAR status
BIGINT_UNSIGNED revision
DATETIME updated_at
}
studio_credit_authorization_allocations {
CHAR owner_id FK
CHAR authorization_id PK
CHAR lot_id PK
BIGINT_UNSIGNED allocated_credits
DATETIME created_at
}
studio_credit_authorizations {
CHAR id PK
CHAR owner_id FK
VARCHAR profile
CHAR project_id
CHAR conversation_id
CHAR job_id
CHAR request_id
CHAR request_sha256
CHAR quote_sha256
BIGINT_UNSIGNED credits
DATETIME expires_at
MEDIUMBLOB reservation_bytes
CHAR reservation_sha256
MEDIUMBLOB policy_bytes
CHAR policy_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_ledger_entries {
CHAR id PK
CHAR owner_id FK
CHAR lot_id FK
CHAR authorization_id FK
VARCHAR operation_key
VARCHAR kind
BIGINT grant_delta
BIGINT held_delta
BIGINT captured_delta
MEDIUMBLOB facts_bytes
CHAR facts_sha256
DATETIME created_at
}
studio_credit_lots {
CHAR id PK
CHAR owner_id FK
BIGINT_UNSIGNED grant_credits
BIGINT_UNSIGNED held_credits
BIGINT_UNSIGNED captured_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
CHAR source_order_id FK
CHAR source_cycle_id FK
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_plan_versions {
CHAR id PK
VARCHAR plan_key
VARCHAR version_key
VARCHAR kind
BIGINT_UNSIGNED price_minor
CHAR currency
BIGINT_UNSIGNED grant_credits
INT_UNSIGNED credit_validity_seconds
INT_UNSIGNED billing_interval_months
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
DATETIME published_at
DATETIME retired_at
}
studio_media_model_versions {
CHAR id PK
CHAR model_id FK
VARCHAR version_key
MEDIUMBLOB config_bytes
CHAR config_sha256
DATETIME published_at
}
studio_media_models {
CHAR id PK
VARCHAR model_key
VARCHAR kind
VARCHAR display_name
VARCHAR status
CHAR published_version_id FK
BIGINT_UNSIGNED revision
DATETIME updated_at
}
studio_payment_events {
CHAR id PK
CHAR owner_id FK
VARCHAR provider_key FK
VARCHAR provider_account FK
VARCHAR provider_event_id
CHAR order_id FK
CHAR subscription_id FK
MEDIUMBLOB body_bytes
CHAR body_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_payment_orders {
CHAR id PK
CHAR owner_id FK
CHAR client_action_id
CHAR plan_version_id FK
BIGINT_UNSIGNED price_minor
CHAR currency
BIGINT_UNSIGNED grant_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
VARCHAR provider_key
VARCHAR provider_account
VARCHAR provider_idempotency_key
VARCHAR provider_order_id
VARCHAR state
CHAR paid_evidence_sha256
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_sessions {
CHAR token_hash PK
CHAR user_id FK
DATETIME created_at
DATETIME expires_at
DATETIME revoked_at
}
studio_subscriptions {
CHAR id PK
CHAR owner_id FK
VARCHAR provider_key
VARCHAR provider_account
VARCHAR provider_subscription_id
CHAR plan_version_id FK
VARCHAR state
DATETIME period_start
DATETIME period_end
TINYINT cancel_at_period_end
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_users {
CHAR id PK
VARCHAR email
VARBINARY password_hash
TINYINT enabled
DATETIME created_at
}
generation_deliveries {
CHAR job_id PK
CHAR owner_id FK
CHAR project_id FK
CHAR session_id FK
CHAR asset_id FK
CHAR request_sha256
CHAR maa_source_sha256
CHAR provider_source_sha256
VARCHAR model
VARCHAR tool_name
CHAR input_sha256
JSON metadata_json
DATETIME created_at
}
generation_development_budgets {
CHAR id PK
CHAR owner_id
VARCHAR policy_version
BIGINT_UNSIGNED credits_limit
BIGINT_UNSIGNED credits_reserved
INT_UNSIGNED calls_limit
INT_UNSIGNED calls_reserved
DATETIME expires_at
}
generation_jobs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR session_id FK
CHAR native_conversation_id
CHAR native_run_id
CHAR source_sha256
CHAR budget_id FK
MEDIUMBLOB request_bytes
CHAR request_sha256
BIGINT_UNSIGNED credits
DATETIME expires_at
VARCHAR status
INT_UNSIGNED attempts
MEDIUMBLOB result_bytes
DATETIME updated_at
}
generation_reservations {
CHAR job_id PK
CHAR budget_id FK
CHAR owner_id FK
BIGINT_UNSIGNED credits
INT_UNSIGNED calls
VARCHAR status
}
maa_bindings {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR provider
VARCHAR model_name
VARCHAR status
VARCHAR native_cid
DATETIME created_at
BIGINT_UNSIGNED model_revision
CHAR pending_model_change_id FK
}
maa_interaction_actions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR interaction_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_iid
CHAR client_action_id
CHAR card_sha256
CHAR request_sha256
CHAR content_sha256
VARCHAR response_action
JSON values_payload
VARCHAR status
DATETIME created_at
}
maa_interactions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_iid
CHAR card_sha256
JSON card_payload
DATETIME created_at
}
maa_message_actions {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR client_action_id
CHAR request_sha256
MEDIUMTEXT content
VARCHAR status
CHAR public_run_id FK
CHAR proposed_run_id
DATETIME created_at
}
maa_model_change_actions {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_cid
CHAR client_action_id
CHAR request_sha256
CHAR native_request_sha256
BIGINT_UNSIGNED expected_revision
VARCHAR from_provider
VARCHAR from_model_name
VARCHAR target_provider
VARCHAR target_model_name
VARCHAR status
BIGINT_UNSIGNED dispatch_attempt
JSON receipt_payload
DATETIME created_at
DATETIME updated_at
}
maa_run_stop_actions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_cid
VARCHAR native_rid
CHAR client_action_id
CHAR request_sha256
VARCHAR stop_action
VARCHAR status
BIGINT_UNSIGNED attempt
VARCHAR terminal_run_status
DATETIME created_at
DATETIME updated_at
}
maa_runs {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_rid
VARCHAR status
DATETIME created_at
CHAR native_assistant_sha256
CHAR public_assistant_sha256
BIGINT_UNSIGNED native_assistant_bytes
BIGINT_UNSIGNED assistant_event_seq
BIGINT_UNSIGNED last_event_seq
}
studio_canvas_revisions {
CHAR owner_id PK
CHAR project_id PK
VARCHAR kind PK
BIGINT_UNSIGNED revision PK
MEDIUMBLOB state_bytes
CHAR state_sha256
VARCHAR origin
BIGINT_UNSIGNED restored_from_revision FK
DATETIME recorded_at
}
studio_canvases {
CHAR project_id PK
CHAR owner_id FK
BIGINT_UNSIGNED revision
JSON state_json
DATETIME updated_at
}
studio_conversations {
CHAR id PK
CHAR project_id FK
CHAR owner_id FK
VARCHAR title
DATETIME created_at
}
studio_credit_recovery_intents {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
CHAR request_sha256 FK
CHAR quote_sha256
VARCHAR kind
CHAR authorization_id FK
MEDIUMBLOB intent_bytes
CHAR intent_sha256
VARCHAR state
CHAR lease_token_sha256
DATETIME lease_until
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_export_jobs {
CHAR id PK
CHAR project_id FK
CHAR owner_id FK
BIGINT_UNSIGNED document_revision
CHAR input_hash
VARCHAR status
JSON input_json
JSON output_json
VARCHAR error_code
CHAR lease_token_hash
DATETIME lease_until
INT_UNSIGNED attempts
DATETIME created_at
DATETIME updated_at
}
studio_media_jobs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR request_id FK
CHAR request_sha256 FK
CHAR quote_sha256 FK
CHAR client_approval_id
CHAR approval_sha256
CHAR credit_authorization_id FK
VARCHAR authorization_mode
DATETIME authorization_expires_at
VARCHAR status
BIGINT_UNSIGNED revision
CHAR lease_token_sha256
DATETIME lease_until
VARCHAR provider_task_id
CHAR client_cancel_id
CHAR cancel_request_sha256
DATETIME cancel_requested_at
CHAR staged_asset_id
CHAR staged_asset_sha256
DATETIME created_at
DATETIME updated_at
}
studio_media_outputs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
INT_UNSIGNED ordinal
CHAR asset_id FK
CHAR asset_sha256
CHAR asset_metadata_sha256
CHAR provider_result_sha256
DATETIME created_at
}
studio_media_requests {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR client_request_id
CHAR model_id FK
CHAR model_version_id FK
CHAR model_config_sha256
MEDIUMBLOB request_bytes
CHAR request_sha256
MEDIUMBLOB quote_bytes
CHAR quote_sha256
BIGINT_UNSIGNED quoted_credits
DATETIME expires_at
VARCHAR origin
CHAR source_binding_id FK
CHAR source_run_id FK
CHAR source_assistant_sha256
MEDIUMBLOB source_snapshot_bytes
DATETIME created_at
}
studio_media_submission_attempts {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
INT_UNSIGNED attempt_no
CHAR request_sha256 FK
VARCHAR provider_idempotency_key
VARCHAR stage
DATETIME dispatch_started_at
VARCHAR provider_task_id
CHAR receipt_sha256
CHAR terminal_receipt_sha256
CHAR reconciliation_sha256
DATETIME created_at
DATETIME updated_at
}
studio_project_asset_refs {
CHAR project_id PK
CHAR owner_id FK
CHAR asset_id PK
CHAR asset_sha256
CHAR asset_metadata_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
DATETIME detached_at
}
studio_projects {
CHAR id PK
CHAR owner_id
VARCHAR title
DATETIME created_at
}
studio_timeline_revisions {
CHAR owner_id PK
CHAR project_id PK
VARCHAR kind PK
BIGINT_UNSIGNED revision PK
MEDIUMBLOB state_bytes
CHAR state_sha256
VARCHAR origin
BIGINT_UNSIGNED restored_from_revision FK
DATETIME recorded_at
}
studio_video_documents {
CHAR project_id PK
CHAR owner_id FK
BIGINT_UNSIGNED revision
JSON state_json
DATETIME updated_at
}
studio_users ||--o{ studio_assets : "owner_id"
studio_payment_orders ||--o| studio_billing_cycles : "plan_version_id"
studio_subscriptions ||--o{ studio_billing_cycles : "provider_account"
studio_users ||--o| studio_credit_accounts : "owner_id"
studio_credit_authorizations ||--o{ studio_credit_authorization_allocations : "authorization_id"
studio_credit_lots ||--o{ studio_credit_authorization_allocations : "lot_id"
studio_credit_accounts ||--o{ studio_credit_authorizations : "owner_id"
studio_credit_authorization_allocations |o--o{ studio_credit_ledger_entries : "lot_id"
studio_credit_authorizations |o--o{ studio_credit_ledger_entries : "authorization_id"
studio_credit_lots ||--o{ studio_credit_ledger_entries : "lot_id"
studio_credit_accounts ||--o{ studio_credit_lots : "owner_id"
studio_billing_cycles |o--o| studio_credit_lots : "source_cycle_id"
studio_payment_orders |o--o| studio_credit_lots : "source_order_id"
studio_media_models ||--o{ studio_media_model_versions : "model_id"
studio_media_model_versions |o--o| studio_media_models : "published_version_id"
studio_payment_orders |o--o{ studio_payment_events : "provider_account"
studio_subscriptions |o--o{ studio_payment_events : "provider_account"
studio_users ||--o{ studio_payment_events : "owner_id"
studio_credit_plan_versions ||--o{ studio_payment_orders : "plan_version_id"
studio_users ||--o{ studio_payment_orders : "owner_id"
studio_users ||--o{ studio_sessions : "user_id"
studio_credit_plan_versions ||--o{ studio_subscriptions : "plan_version_id"
studio_users ||--o{ studio_subscriptions : "owner_id"
generation_jobs ||--o| generation_deliveries : "job_id"
studio_projects ||--o{ generation_deliveries : "project_id"
studio_conversations ||--o{ generation_deliveries : "session_id"
generation_development_budgets ||--o{ generation_jobs : "budget_id"
studio_projects ||--o{ generation_jobs : "project_id"
studio_conversations ||--o{ generation_jobs : "session_id"
generation_jobs ||--o| generation_reservations : "budget_id"
studio_conversations ||--o| maa_bindings : "conversation_id"
maa_model_change_actions |o--o| maa_bindings : "pending_model_change_id"
maa_interactions ||--o| maa_interaction_actions : "interaction_id"
maa_runs ||--o{ maa_interactions : "public_run_id"
maa_bindings ||--o{ maa_message_actions : "binding_id"
maa_runs |o--o{ maa_message_actions : "public_run_id"
maa_bindings ||--o{ maa_model_change_actions : "binding_id"
maa_runs ||--o| maa_run_stop_actions : "public_run_id"
maa_bindings ||--o{ maa_runs : "binding_id"
studio_canvases ||--o{ studio_canvas_revisions : "project_id"
studio_canvas_revisions |o--o{ studio_canvas_revisions : "restored_from_revision"
studio_projects ||--o| studio_canvases : "project_id"
studio_projects ||--o{ studio_conversations : "project_id"
studio_media_jobs ||--o{ studio_credit_recovery_intents : "job_id"
studio_projects ||--o{ studio_export_jobs : "project_id"
studio_media_requests ||--o| studio_media_jobs : "request_id"
studio_media_jobs ||--o{ studio_media_outputs : "job_id"
studio_conversations ||--o{ studio_media_requests : "conversation_id"
maa_runs |o--o{ studio_media_requests : "source_run_id"
studio_media_jobs ||--o{ studio_media_submission_attempts : "job_id"
studio_projects ||--o{ studio_project_asset_refs : "project_id"
studio_video_documents ||--o{ studio_timeline_revisions : "project_id"
studio_timeline_revisions |o--o{ studio_timeline_revisions : "restored_from_revision"
studio_projects ||--o| studio_video_documents : "project_id"
studio_assets ||--o{ studio_project_asset_refs : "asset_id"
studio_assets ||--o{ studio_media_outputs : "asset_id"
studio_assets ||--o{ generation_deliveries : "asset_id"
studio_media_model_versions ||--o{ studio_media_requests : "model_version_id"
studio_media_models ||--o{ studio_media_requests : "model_id"
studio_credit_authorizations |o--o{ studio_media_jobs : "credit_authorization_id"
studio_credit_authorizations |o--o{ studio_credit_recovery_intents : "authorization_id"自动生成的整体图(按真实表结构,备查)
共享身份库 ER 图
实测验证与设计原因 七个品牌相同,展开查看
实测验证(本机 MySQL 实库)
对照本机真实运行的数据库 studio_profile_flova 和 studio_platform_identity,逐项核对本页的表、列、关系与说明。18 / 18 项通过。
查看全部核对项
| 核对项 | 结果 |
|---|---|
| 表数 = 发布值 24 | 通过 |
| 列数 = 289 | 通过 |
| 外键数 = 34 | 通过 |
| 检查约束数 = 66 | 通过 |
| 触发器数 = 22 | 通过 |
| 索引数(含主键) = 85 | 通过 |
| 列定义与 pollo 逐列一致 | 通过 |
| 外键与 pollo 完全一致 | 通过 |
| 索引与 pollo 一致 | 通过 |
| 触发器与 pollo 一致 | 通过 |
| 外键 CSV 行数 = 实库外键数 | 通过 |
| mmd 实体 = 实库表 | 通过 |
| svg 标题 24 tables / 34 actual foreign keys = 实库 | 通过 |
| 参考 SQL 表集合与列顺序 = 实库 | 通过 |
| 15 张表 | 通过 |
| 外键 CSV 行数 = 实库外键数 | 通过 |
| svg 标题与实库一致 | 通过 |
| 参考 SQL 表集合与列顺序 = 实库 | 通过 |
实库里的关系是这样的
- 34 个外键里 31 个是复合外键,且都带着 owner_id,其余 3 个是单列外键;22 张子表都带 owner 外键。所以一行数据不可能指向别的用户的项目或会话。
- 删除与更新规则全部是 RESTRICT / NO ACTION,没有任何级联:被引用的行不能被删除。
- 品牌库与共享身份库之间的关系(owner_id、asset_id、model_id + model_version_id)没有数据库外键,靠应用层检查;我们逐表核对了现有数据,没有孤儿。
主动破坏测试(在事务里尝试,全部回滚)
| 尝试 | 数据库的反应 |
|---|---|
| 外键:导出任务.project_id 改成不存在的项目被拒绝 | 拒绝 |
| 复合外键:项目素材引用.project_id 改成别的用户的项目被拒绝(owner 与 project 必须成对) | 拒绝 |
| 触发器:已提交的消息动作不可改写 | 拒绝 |
| 触发器:媒体产出不可改写 | 拒绝 |
| 外键 RESTRICT:被会话引用的项目不能删除 | 拒绝 |
| 复合外键:被引用的会话不能把 owner 改成别人 | 拒绝 |
| 检查约束:Run 状态只能是约定的六个值 | 拒绝 |
| 触发器:账本分录不可修改 | 拒绝 |
| 触发器:账本分录不可删除 | 拒绝 |
Flova · 表结构
MySQL 8,字符集 utf8mb4,ID 为 char(36) ascii_bin。点击展开 DDL。
按职责分组
项目与会话 2 张
studio_projects:用户拥有的创作项目studio_conversations:项目内的对话会话
Agent执行与并发控制 7 张
maa_bindings:业务会话与Native Maa会话映射、模型版本与未决操作maa_runs:公开Run映射、状态与原生/公开助手证据摘要maa_message_actions:原消息动作及幂等回执maa_interactions:澄清卡片及Run归属maa_interaction_actions:原卡片回答/取消动作maa_model_change_actions:带预期模型版本的切换动作maa_run_stop_actions:停止原Run的幂等动作与观测终态
画布、时间轴与素材引用 5 张
studio_canvases:项目当前画布文档studio_canvas_revisions:历史画布修订studio_video_documents:项目当前时间轴文档studio_timeline_revisions:历史时间轴修订studio_project_asset_refs:项目对用户级素材的引用;不复制素材所有权
媒体生成、结算恢复与导出 6 张
studio_media_requests:用户输入/Agent来源、报价、批准摘要与准入确认studio_media_jobs:已批准媒体任务及状态机studio_media_submission_attempts:一次提交的任务证据与不确定结果studio_media_outputs:受验证的输出与素材映射studio_credit_recovery_intents:积分结算恢复意图;不是用户钱包全账本studio_export_jobs:时间轴导出队列和发布输出
既有generation兼容路径 22 张
generation_jobs:既有generation任务,不等同新PublicMedia任务generation_reservations:既有任务费用预留generation_development_budgets:既有开发测试预算generation_deliveries:既有生成交付回执owner_id:归属用户;不是允许跨用户查询的参数。model_revision:并发准入版本;数据库默认0不能代替Native权威读回。pending_model_change_id:未决模型切换引用,阻止其他writer绕过。studio_users:用户账号记录;不导出密码哈希或任何业务行studio_sessions:登录会话;这里只公开字段结构,不公开会话值studio_assets:用户级素材元数据与存储键结构,项目仅引用素材IDstudio_media_models:公开媒体模型目录结构studio_media_model_versions:媒体模型不可变版本/计价能力结构studio_subscriptions:订阅状态持久化studio_billing_cycles:订阅账期studio_payment_orders:订单记录studio_payment_events:支付事件幂等记录;不代表已有公开支付路由studio_credit_accounts:用户积分账户studio_credit_lots:积分批次studio_credit_authorizations:费用预留与结算授权studio_credit_authorization_allocations:授权对批次的分配studio_credit_ledger_entries:积分流水studio_credit_plan_versions:积分方案不可变版本
品牌库 studio_profile_flova(24 张)
generation_deliveries 既有生成交付回执
CREATE TABLE `generation_deliveries` ( `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `session_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `maa_source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `tool_name` varchar(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `input_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `metadata_json` json NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`job_id`), KEY `generation_delivery_owner_project` (`owner_id`,`project_id`,`session_id`,`job_id`), KEY `generation_delivery_owned_asset` (`owner_id`,`asset_id`), KEY `generation_delivery_session_fk` (`session_id`), CONSTRAINT `generation_delivery_job_fk` FOREIGN KEY (`job_id`) REFERENCES `generation_jobs` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`, `job_id`) REFERENCES `generation_jobs` (`owner_id`, `project_id`, `session_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_session_fk` FOREIGN KEY (`session_id`) REFERENCES `studio_conversations` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_model_tool` CHECK ((((`model` = _ascii'seedance-2.0') and (`tool_name` = _ascii'seedance2_video_generator')) or ((`model` in (_ascii'minimax-h3',_ascii'seedance-2.5')) and (`tool_name` = _ascii'insai_video_generate')))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_development_budgets 既有开发测试预算
CREATE TABLE `generation_development_budgets` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `policy_version` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits_limit` bigint unsigned NOT NULL, `credits_reserved` bigint unsigned NOT NULL DEFAULT '0', `calls_limit` int unsigned NOT NULL, `calls_reserved` int unsigned NOT NULL DEFAULT '0', `expires_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `generation_budget_owner` (`owner_id`,`id`), CONSTRAINT `generation_budget_limits` CHECK (((`credits_limit` between 1 and 1000000000) and (`credits_reserved` <= `credits_limit`) and (`calls_limit` between 1 and 100) and (`calls_reserved` <= `calls_limit`))), CONSTRAINT `generation_budget_policy` CHECK ((`policy_version` = _latin1'operator-test/v1')) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_jobs 既有generation任务,不等同新PublicMedia任务
CREATE TABLE `generation_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `session_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_conversation_id` char(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_run_id` char(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `budget_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_bytes` mediumblob NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits` bigint unsigned NOT NULL, `expires_at` datetime(6) NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempts` int unsigned NOT NULL DEFAULT '0', `result_bytes` mediumblob, `updated_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `generation_job_budget_owner` (`id`,`budget_id`,`owner_id`), UNIQUE KEY `generation_job_owned_scope` (`owner_id`,`project_id`,`session_id`,`id`), KEY `generation_job_owner` (`owner_id`,`project_id`,`session_id`), KEY `generation_job_session` (`session_id`), KEY `generation_job_budget` (`owner_id`,`budget_id`), CONSTRAINT `generation_job_budget` FOREIGN KEY (`owner_id`, `budget_id`) REFERENCES `generation_development_budgets` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_owned_project` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_owned_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_session` FOREIGN KEY (`session_id`) REFERENCES `studio_conversations` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_attempt` CHECK ((((`status` = _ascii'APPROVED') and (`attempts` = 0) and (`result_bytes` is null)) or ((`status` = _ascii'SUBMITTING') and (`attempts` = 1) and (`result_bytes` is null)) or ((`status` in (_ascii'SUCCEEDED',_ascii'FAILED',_ascii'UNKNOWN')) and (`attempts` = 1) and (`result_bytes` is not null)))), CONSTRAINT `generation_job_credit` CHECK ((`credits` between 1 and 1000000000)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_reservations 既有任务费用预留
CREATE TABLE `generation_reservations` ( `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `budget_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits` bigint unsigned NOT NULL, `calls` int unsigned NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, PRIMARY KEY (`job_id`), KEY `generation_reservation_job` (`job_id`,`budget_id`,`owner_id`), CONSTRAINT `generation_reservation_job` FOREIGN KEY (`job_id`, `budget_id`, `owner_id`) REFERENCES `generation_jobs` (`id`, `budget_id`, `owner_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_reservation_fixed` CHECK (((`credits` between 1 and 1000000000) and (`calls` = 1) and (`status` = _latin1'HELD'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_bindings 业务会话与Native Maa会话映射、模型版本与未决操作
CREATE TABLE `maa_bindings` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `model_revision` bigint unsigned NOT NULL DEFAULT '0', `pending_model_change_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_binding_business_scope` (`owner_id`,`project_id`,`conversation_id`), UNIQUE KEY `maa_binding_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `maa_binding_native_identity` (`native_cid`), KEY `maa_model_change_pending_fk` (`owner_id`,`project_id`,`conversation_id`,`id`,`pending_model_change_id`), CONSTRAINT `maa_binding_owned_conversation_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_model_change_pending_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `id`, `pending_model_change_id`) REFERENCES `maa_model_change_actions` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_binding_receipt` CHECK ((((`status` = _ascii'dispatching') and (`native_cid` is null)) or ((`status` = _ascii'bound') and (`native_cid` is not null)))), CONSTRAINT `maa_model_binding_revision` CHECK ((`model_revision` <= 9007199254740991)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_interaction_actions 原卡片回答/取消动作
CREATE TABLE `maa_interaction_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `interaction_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_iid` varchar(124) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `content_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `response_action` varchar(8) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `values_payload` json NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_interaction_action_business_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_interaction_action_one_card` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`interaction_id`), CONSTRAINT `maa_interaction_action_owned_card_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`, `interaction_id`) REFERENCES `maa_interactions` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_interaction_action_kind` CHECK ((`response_action` in (_latin1'submit',_latin1'cancel'))), CONSTRAINT `maa_interaction_action_status` CHECK ((`status` in (_latin1'dispatching',_latin1'accepted'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_interactions 澄清卡片及Run归属
CREATE TABLE `maa_interactions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_iid` varchar(124) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_payload` json NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_interaction_native_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`native_iid`), UNIQUE KEY `maa_interaction_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`id`), CONSTRAINT `maa_interaction_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_message_actions 原消息动作及幂等回执
CREATE TABLE `maa_message_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `content` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `proposed_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_action_business_identity` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), KEY `maa_action_owned_run_fk` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`), CONSTRAINT `maa_action_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_action_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_action_receipt` CHECK ((((`status` = _latin1'dispatching') and (`public_run_id` is null)) or ((`status` = _latin1'accepted') and (`public_run_id` is not null)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_model_change_actions 带预期模型版本的切换动作
CREATE TABLE `maa_model_change_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `expected_revision` bigint unsigned NOT NULL, `from_provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `from_model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `target_provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `target_model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `dispatch_attempt` bigint unsigned NOT NULL, `receipt_payload` json DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_model_change_owned_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_model_change_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`id`), CONSTRAINT `maa_model_change_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_model_change_attempt` CHECK ((`dispatch_attempt` between 1 and 9007199254740991)), CONSTRAINT `maa_model_change_expected` CHECK ((`expected_revision` <= 9007199254740990)), CONSTRAINT `maa_model_change_status` CHECK ((((cast(`status` as char charset binary) = _latin1'dispatching') and (`receipt_payload` is null)) or ((cast(`status` as char charset binary) in (_latin1'accepted',_latin1'rejected')) and (`receipt_payload` is not null) and (json_type(`receipt_payload`) = _latin1'OBJECT')))), CONSTRAINT `maa_model_change_time` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_run_stop_actions 停止原Run的幂等动作与观测终态
CREATE TABLE `maa_run_stop_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_rid` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `stop_action` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempt` bigint unsigned NOT NULL, `terminal_run_status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_stop_owned_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_stop_one_run` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`), CONSTRAINT `maa_stop_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_stop_action` CHECK ((`stop_action` = _latin1'interrupt')), CONSTRAINT `maa_stop_attempt` CHECK ((`attempt` between 1 and 9007199254740991)), CONSTRAINT `maa_stop_state` CHECK ((((`status` = _latin1'unknown') and (`terminal_run_status` is null)) or ((`status` = _latin1'terminal_observed') and (`terminal_run_status` is not null) and (`terminal_run_status` in (_latin1'completed',_latin1'failed',_latin1'cancelled'))))), CONSTRAINT `maa_stop_time` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_runs 公开Run映射、状态与原生/公开助手证据摘要
CREATE TABLE `maa_runs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_rid` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, `native_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `public_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `native_assistant_bytes` bigint unsigned NOT NULL DEFAULT '0', `assistant_event_seq` bigint unsigned NOT NULL DEFAULT '0', `last_event_seq` bigint unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `maa_run_native_identity` (`native_rid`), UNIQUE KEY `maa_run_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`id`), KEY `maa_run_owned_list` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), CONSTRAINT `maa_run_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_run_source_evidence` CHECK ((((`native_assistant_sha256` is null) and (`public_assistant_sha256` is null) and (`native_assistant_bytes` = 0) and (`assistant_event_seq` = 0)) or ((`native_assistant_sha256` is not null) and (`public_assistant_sha256` is not null) and (`native_assistant_bytes` > 0) and (`assistant_event_seq` > 0) and (`assistant_event_seq` <= `last_event_seq`)))), CONSTRAINT `maa_run_status` CHECK ((`status` in (_latin1'queued',_latin1'running',_latin1'waiting_interaction',_latin1'completed',_latin1'failed',_latin1'cancelled'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_canvas_revisions 历史画布修订
CREATE TABLE `studio_canvas_revisions` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_bytes` mediumblob NOT NULL, `state_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `restored_from_revision` bigint unsigned DEFAULT NULL, `recorded_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`,`project_id`,`kind`,`revision`), KEY `studio_canvas_revision_source_fk` (`owner_id`,`project_id`,`kind`,`restored_from_revision`), CONSTRAINT `studio_canvas_revision_head_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_canvases` (`owner_id`, `project_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_canvas_revision_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `kind`, `restored_from_revision`) REFERENCES `studio_canvas_revisions` (`owner_id`, `project_id`, `kind`, `revision`), CONSTRAINT `studio_canvas_revision_bytes` CHECK ((length(`state_bytes`) between 1 and 262144)), CONSTRAINT `studio_canvas_revision_kind` CHECK ((`kind` = _latin1'canvas')), CONSTRAINT `studio_canvas_revision_number` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_canvas_revision_origin` CHECK ((((`origin` in (_latin1'saved',_latin1'backfill')) and (`restored_from_revision` is null)) or ((`origin` = _latin1'restored') and (`restored_from_revision` is not null) and (`restored_from_revision` between 1 and (`revision` - 1))))), CONSTRAINT `studio_canvas_revision_sha` CHECK ((`state_sha256` = lower(sha2(`state_bytes`,256)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_canvases 项目当前画布文档
CREATE TABLE `studio_canvases` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_json` json NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`project_id`), UNIQUE KEY `studio_canvas_owned_head` (`owner_id`,`project_id`), CONSTRAINT `studio_canvas_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_canvas_revision` CHECK ((`revision` between 1 and 2147483647)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_conversations 项目内的对话会话
CREATE TABLE `studio_conversations` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `title` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_conversation_owned_scope` (`owner_id`,`project_id`,`id`), KEY `studio_conversation_list` (`owner_id`,`project_id`,`created_at`,`id`), CONSTRAINT `studio_conversation_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_recovery_intents 积分结算恢复意图;不是用户钱包全账本
CREATE TABLE `studio_credit_recovery_intents` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`kind` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`intent_bytes` mediumblob NOT NULL,
`intent_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`lease_token_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`lease_until` datetime(6) DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_intent_job_kind` (`job_id`,`kind`),
KEY `credit_intent_recovery` (`state`,`updated_at`,`id`),
KEY `credit_intent_owned_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`,`request_sha256`),
CONSTRAINT `credit_intent_owned_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`, `request_sha256`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`),
CONSTRAINT `credit_intent_hashes` CHECK ((regexp_like(`request_sha256`,_latin1'^[a-f0-9]{64}$') and regexp_like(`quote_sha256`,_latin1'^[a-f0-9]{64}$'))),
CONSTRAINT `credit_intent_kind` CHECK (((`kind` in (_latin1'RESERVE_BIND',_latin1'CAPTURE',_latin1'RELEASE')) and (((`kind` = _latin1'RESERVE_BIND') and (`authorization_id` is null)) or ((`kind` in (_latin1'CAPTURE',_latin1'RELEASE')) and (`authorization_id` is not null))))),
CONSTRAINT `credit_intent_lease` CHECK ((((`state` = _latin1'leased') and (`lease_token_sha256` is not null) and regexp_like(`lease_token_sha256`,_latin1'^[a-f0-9]{64}$') and (`lease_until` is not null) and (`lease_until` > `updated_at`) and (`lease_until` <= (`updated_at` + interval 15 minute))) or ((`state` <> _latin1'leased') and (`lease_token_sha256` is null) and (`lease_until` is null)))),
CONSTRAINT `credit_intent_payload_sha` CHECK ((`intent_sha256` = lower(sha2(`intent_bytes`,256)))),
CONSTRAINT `credit_intent_payload_size` CHECK ((length(`intent_bytes`) between 1 and 65536)),
CONSTRAINT `credit_intent_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `credit_intent_state` CHECK ((`state` in (_latin1'pending',_latin1'leased',_latin1'confirmed',_latin1'unknown'))),
CONSTRAINT `credit_intent_times` CHECK ((`updated_at` >= `created_at`))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_export_jobs 时间轴导出队列和发布输出
CREATE TABLE `studio_export_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `document_revision` bigint unsigned NOT NULL, `input_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `input_json` json NOT NULL, `output_json` json DEFAULT NULL, `error_code` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT '', `lease_token_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `lease_until` datetime(6) DEFAULT NULL, `attempts` int unsigned NOT NULL DEFAULT '0', `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_export_input` (`project_id`,`document_revision`,`input_hash`), KEY `studio_export_claim` (`status`,`created_at`,`id`), KEY `studio_export_owner_list` (`owner_id`,`project_id`,`created_at`,`id`), KEY `studio_export_expiry` (`status`,`lease_until`), CONSTRAINT `studio_export_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_export_lease` CHECK ((((`status` = _latin1'running') and (`lease_token_hash` is not null) and (`lease_until` is not null)) or ((`status` <> _latin1'running') and (`lease_token_hash` is null) and (`lease_until` is null)))), CONSTRAINT `studio_export_output` CHECK ((((`status` = _latin1'succeeded') and (`output_json` is not null) and (`error_code` = _latin1'')) or ((`status` in (_latin1'queued',_latin1'running')) and (`output_json` is null) and (`error_code` = _latin1'')) or ((`status` in (_latin1'failed',_latin1'unknown')) and (`output_json` is null) and (`error_code` <> _latin1'')))), CONSTRAINT `studio_export_revision` CHECK ((`document_revision` between 1 and 2147483647)), CONSTRAINT `studio_export_status` CHECK ((`status` in (_latin1'queued',_latin1'running',_latin1'succeeded',_latin1'failed',_latin1'unknown'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_jobs 已批准媒体任务及状态机
CREATE TABLE `studio_media_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_approval_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `approval_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credit_authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `authorization_mode` varchar(24) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `authorization_expires_at` datetime(6) DEFAULT NULL, `status` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `lease_token_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `lease_until` datetime(6) DEFAULT NULL, `provider_task_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `client_cancel_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `cancel_request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `cancel_requested_at` datetime(6) DEFAULT NULL, `staged_asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `staged_asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_job_request` (`request_id`), UNIQUE KEY `studio_media_job_client` (`owner_id`,`client_approval_id`), UNIQUE KEY `studio_media_job_owned` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `studio_media_job_owned_request` (`owner_id`,`project_id`,`conversation_id`,`id`,`request_sha256`), KEY `studio_media_job_page` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), KEY `studio_media_job_queue` (`status`,`updated_at`,`id`), KEY `studio_media_job_request_fk` (`owner_id`,`project_id`,`conversation_id`,`request_id`,`request_sha256`,`quote_sha256`), CONSTRAINT `studio_media_job_request_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `request_id`, `request_sha256`, `quote_sha256`) REFERENCES `studio_media_requests` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`, `quote_sha256`), CONSTRAINT `studio_media_job_authorization` CHECK ((((`credit_authorization_id` is null) and (`authorization_mode` is null) and (`authorization_expires_at` is null) and (`status` in (_latin1'approval_pending',_latin1'cancelled'))) or ((`credit_authorization_id` is not null) and (`authorization_mode` is not null) and (`authorization_mode` in (_latin1'commercial',_latin1'test_allowance')) and (`authorization_expires_at` is not null) and (`authorization_expires_at` > `created_at`) and (`status` <> _latin1'approval_pending')))), CONSTRAINT `studio_media_job_cancel` CHECK ((((`client_cancel_id` is null) and (`cancel_request_sha256` is null) and (`cancel_requested_at` is null)) or ((`client_cancel_id` is not null) and (`cancel_request_sha256` is not null) and (`cancel_requested_at` is not null) and (`cancel_requested_at` between `created_at` and `updated_at`)))), CONSTRAINT `studio_media_job_lease` CHECK ((((`status` in (_latin1'leased',_latin1'submitting')) and (`lease_token_sha256` is not null) and (`lease_until` is not null) and (`lease_until` > `updated_at`) and (`lease_until` <= (`updated_at` + interval 15 minute))) or ((`status` not in (_latin1'leased',_latin1'submitting')) and (`lease_token_sha256` is null) and (`lease_until` is null)))), CONSTRAINT `studio_media_job_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_media_job_staged` CHECK ((((`staged_asset_id` is null) and (`staged_asset_sha256` is null)) or ((`staged_asset_id` is not null) and (`staged_asset_sha256` is not null)))), CONSTRAINT `studio_media_job_status` CHECK ((`status` in (_latin1'approval_pending',_latin1'queued',_latin1'leased',_latin1'submitting',_latin1'running',_latin1'submission_unknown',_latin1'succeeded',_latin1'failed',_latin1'cancelled'))), CONSTRAINT `studio_media_job_task` CHECK (((`status` not in (_latin1'running',_latin1'succeeded')) or (`provider_task_id` is not null))), CONSTRAINT `studio_media_job_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_outputs 受验证的输出与素材映射
CREATE TABLE `studio_media_outputs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `ordinal` int unsigned NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_metadata_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_result_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_output_job` (`job_id`,`ordinal`), KEY `studio_media_output_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`), CONSTRAINT `studio_media_output_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`), CONSTRAINT `studio_media_output_ordinal` CHECK ((`ordinal` = 0)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_requests 用户输入/Agent来源、报价、批准摘要与准入确认
CREATE TABLE `studio_media_requests` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_config_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_bytes` mediumblob NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quote_bytes` mediumblob NOT NULL, `quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quoted_credits` bigint unsigned NOT NULL, `expires_at` datetime(6) NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_snapshot_bytes` mediumblob, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_request_owned` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `studio_media_request_quoted` (`owner_id`,`project_id`,`conversation_id`,`id`,`request_sha256`,`quote_sha256`), UNIQUE KEY `studio_media_request_client` (`owner_id`,`project_id`,`conversation_id`,`client_request_id`), KEY `studio_media_request_page` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), KEY `studio_media_request_source_fk` (`owner_id`,`project_id`,`conversation_id`,`source_binding_id`,`source_run_id`), CONSTRAINT `studio_media_request_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`), CONSTRAINT `studio_media_request_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `source_binding_id`, `source_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`), CONSTRAINT `studio_media_quote_credits` CHECK ((`quoted_credits` between 1 and 1000000000)), CONSTRAINT `studio_media_quote_sha` CHECK ((`quote_sha256` = lower(sha2(`quote_bytes`,256)))), CONSTRAINT `studio_media_quote_times` CHECK (((`expires_at` > `created_at`) and (`expires_at` <= (`created_at` + interval 15 minute)))), CONSTRAINT `studio_media_request_origin` CHECK ((((`origin` in (_latin1'ui',_latin1'user_edit')) and (`source_binding_id` is null) and (`source_run_id` is null) and (`source_assistant_sha256` is null) and (`source_snapshot_bytes` is null)) or ((`origin` = _latin1'agent') and (`source_binding_id` is not null) and (`source_run_id` is not null) and (`source_assistant_sha256` is not null) and (`source_snapshot_bytes` is not null) and (length(`source_snapshot_bytes`) between 1 and 65536) and (`source_assistant_sha256` = lower(sha2(`source_snapshot_bytes`,256)))))), CONSTRAINT `studio_media_request_sha` CHECK ((`request_sha256` = lower(sha2(`request_bytes`,256)))), CONSTRAINT `studio_media_request_size` CHECK (((length(`request_bytes`) between 1 and 65536) and (length(`quote_bytes`) between 1 and 65536))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_submission_attempts 一次提交的任务证据与不确定结果
CREATE TABLE `studio_media_submission_attempts` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempt_no` int unsigned NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_idempotency_key` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `stage` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `dispatch_started_at` datetime(6) DEFAULT NULL, `provider_task_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `receipt_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `terminal_receipt_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `reconciliation_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_attempt_job` (`job_id`,`attempt_no`), UNIQUE KEY `studio_media_attempt_idempotency` (`provider_idempotency_key`), KEY `studio_media_attempt_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`,`request_sha256`), CONSTRAINT `studio_media_attempt_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`, `request_sha256`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`), CONSTRAINT `studio_media_attempt_number` CHECK ((`attempt_no` = 1)), CONSTRAINT `studio_media_attempt_state` CHECK ((((`stage` = _latin1'prepared') and (`dispatch_started_at` is null) and (`provider_task_id` is null) and (`receipt_sha256` is null) and (`reconciliation_sha256` is null) and (`terminal_receipt_sha256` is null)) or ((`stage` in (_latin1'dispatching',_latin1'unknown')) and (`dispatch_started_at` is not null) and (`dispatch_started_at` >= `created_at`) and (`provider_task_id` is null) and (`receipt_sha256` is null) and (`reconciliation_sha256` is null) and (`terminal_receipt_sha256` is null)) or ((`stage` = _latin1'acknowledged') and (`dispatch_started_at` is not null) and (`provider_task_id` is not null) and (`receipt_sha256` is not null) and (`terminal_receipt_sha256` is null)) or ((`stage` in (_latin1'completed',_latin1'failed')) and (`dispatch_started_at` is not null) and (`provider_task_id` is not null) and (`receipt_sha256` is not null) and (`terminal_receipt_sha256` is not null)) or ((`stage` = _latin1'reconciled_not_sent') and (`dispatch_started_at` is not null) and (`provider_task_id` is null) and (`reconciliation_sha256` is not null)))), CONSTRAINT `studio_media_attempt_times` CHECK (((`updated_at` >= `created_at`) and ((`dispatch_started_at` is null) or (`dispatch_started_at` between `created_at` and `updated_at`)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_project_asset_refs 项目对用户级素材的引用;不复制素材所有权
CREATE TABLE `studio_project_asset_refs` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_metadata_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, `detached_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`project_id`,`asset_id`), KEY `studio_project_asset_owned_page` (`owner_id`,`project_id`,`asset_id`), KEY `studio_project_asset_reverse` (`owner_id`,`asset_id`,`project_id`), CONSTRAINT `studio_project_asset_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_project_asset_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_project_asset_state` CHECK ((((`state` = _latin1'attached') and (`detached_at` is null)) or ((`state` = _latin1'detached') and (`detached_at` is not null) and (`detached_at` = `updated_at`)))), CONSTRAINT `studio_project_asset_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_projects 用户拥有的创作项目
CREATE TABLE `studio_projects` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `title` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_project_owner_identity` (`owner_id`,`id`), KEY `studio_project_owner_list` (`owner_id`,`created_at`,`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_timeline_revisions 历史时间轴修订
CREATE TABLE `studio_timeline_revisions` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_bytes` mediumblob NOT NULL, `state_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `restored_from_revision` bigint unsigned DEFAULT NULL, `recorded_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`,`project_id`,`kind`,`revision`), KEY `studio_timeline_revision_source_fk` (`owner_id`,`project_id`,`kind`,`restored_from_revision`), CONSTRAINT `studio_timeline_revision_head_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_video_documents` (`owner_id`, `project_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_timeline_revision_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `kind`, `restored_from_revision`) REFERENCES `studio_timeline_revisions` (`owner_id`, `project_id`, `kind`, `revision`), CONSTRAINT `studio_timeline_revision_bytes` CHECK ((length(`state_bytes`) between 1 and 262144)), CONSTRAINT `studio_timeline_revision_kind` CHECK ((`kind` = _latin1'timeline')), CONSTRAINT `studio_timeline_revision_number` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_timeline_revision_origin` CHECK ((((`origin` in (_latin1'saved',_latin1'backfill')) and (`restored_from_revision` is null)) or ((`origin` = _latin1'restored') and (`restored_from_revision` is not null) and (`restored_from_revision` between 1 and (`revision` - 1))))), CONSTRAINT `studio_timeline_revision_sha` CHECK ((`state_sha256` = lower(sha2(`state_bytes`,256)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_video_documents 项目当前时间轴文档
CREATE TABLE `studio_video_documents` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_json` json NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`project_id`), UNIQUE KEY `studio_timeline_owned_head` (`owner_id`,`project_id`), CONSTRAINT `studio_document_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_document_revision` CHECK ((`revision` between 1 and 2147483647)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
共享身份库(15 张)与积分账本 七个品牌相同,展开查看
studio_assets
CREATE TABLE `studio_assets` (
`id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`metadata_json` json NOT NULL,
`storage_key` varchar(512) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`created_at` datetime(6) NOT NULL,
`publication_state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT 'visible',
PRIMARY KEY (`id`),
UNIQUE KEY `studio_asset_owner_digest` (`owner_id`,`sha256`),
KEY `studio_asset_owner_list` (`owner_id`,`created_at`,`id`),
KEY `studio_asset_visible_list` (`owner_id`,`publication_state`,`created_at`,`id`),
CONSTRAINT `studio_asset_publication_state` CHECK (CAST(publication_state AS BINARY) IN ('pending','visible')),
CONSTRAINT `studio_asset_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_billing_cycles
CREATE TABLE `studio_billing_cycles` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`subscription_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`payment_order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_invoice_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`period_start` datetime(6) NOT NULL,
`period_end` datetime(6) NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`valid_from` datetime(6) NOT NULL,
`expires_at` datetime(6) NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`paid_evidence_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `billing_cycle_owned` (`owner_id`,`id`),
UNIQUE KEY `billing_cycle_period` (`subscription_id`,`period_start`),
UNIQUE KEY `billing_cycle_invoice` (`provider_key`,`provider_account`,`provider_invoice_id`),
UNIQUE KEY `billing_cycle_order` (`payment_order_id`),
KEY `billing_cycle_subscription_fk` (`owner_id`,`subscription_id`,`provider_key`,`provider_account`),
KEY `billing_cycle_order_fk` (`owner_id`,`payment_order_id`,`plan_version_id`),
KEY `billing_cycle_order_provider_fk` (`owner_id`,`payment_order_id`,`provider_key`,`provider_account`),
CONSTRAINT `billing_cycle_order_fk` FOREIGN KEY (`owner_id`, `payment_order_id`, `plan_version_id`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `plan_version_id`),
CONSTRAINT `billing_cycle_order_provider_fk` FOREIGN KEY (`owner_id`, `payment_order_id`, `provider_key`, `provider_account`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `provider_key`, `provider_account`),
CONSTRAINT `billing_cycle_subscription_fk` FOREIGN KEY (`owner_id`, `subscription_id`, `provider_key`, `provider_account`) REFERENCES `studio_subscriptions` (`owner_id`, `id`, `provider_key`, `provider_account`),
CONSTRAINT `billing_cycle_amount` CHECK ((`grant_credits` between 1 and 1000000000)),
CONSTRAINT `billing_cycle_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `billing_cycle_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `billing_cycle_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `billing_cycle_state` CHECK (((`state` in (_latin1'PENDING',_latin1'PAID',_latin1'CLOSED')) and (((`state` = _latin1'PAID') and (`paid_evidence_sha256` is not null) and regexp_like(`paid_evidence_sha256`,_latin1'^[a-f0-9]{64}$')) or ((`state` <> _latin1'PAID') and (`paid_evidence_sha256` is null))))),
CONSTRAINT `billing_cycle_times` CHECK (((`period_end` > `period_start`) and (`expires_at` > `valid_from`) and (`expires_at` <= (`valid_from` + interval 31622400 second)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_credit_accounts
CREATE TABLE `studio_credit_accounts` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `unit` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`), CONSTRAINT `credit_account_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `credit_account_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `credit_account_status` CHECK ((`status` in (_latin1'open',_latin1'suspended'))), CONSTRAINT `credit_account_unit` CHECK ((`unit` = _latin1'credits')) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_authorization_allocations
CREATE TABLE `studio_credit_authorization_allocations` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `lot_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `allocated_credits` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`authorization_id`,`lot_id`), UNIQUE KEY `credit_allocation_owned` (`owner_id`,`authorization_id`,`lot_id`), KEY `credit_allocation_lot` (`owner_id`,`lot_id`,`authorization_id`), CONSTRAINT `credit_allocation_authorization_fk` FOREIGN KEY (`owner_id`, `authorization_id`) REFERENCES `studio_credit_authorizations` (`owner_id`, `id`), CONSTRAINT `credit_allocation_lot_fk` FOREIGN KEY (`owner_id`, `lot_id`) REFERENCES `studio_credit_lots` (`owner_id`, `id`), CONSTRAINT `credit_allocation_amount` CHECK ((`allocated_credits` between 1 and 1000000000)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_authorizations
CREATE TABLE `studio_credit_authorizations` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`profile` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`credits` bigint unsigned NOT NULL,
`expires_at` datetime(6) NOT NULL,
`reservation_bytes` mediumblob NOT NULL,
`reservation_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`policy_bytes` mediumblob NOT NULL,
`policy_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_authorization_owned` (`owner_id`,`id`),
UNIQUE KEY `credit_authorization_job` (`owner_id`,`profile`,`job_id`),
CONSTRAINT `credit_authorization_account_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_credit_accounts` (`owner_id`),
CONSTRAINT `credit_authorization_amount` CHECK ((`credits` between 1 and 1000000000)),
CONSTRAINT `credit_authorization_hashes` CHECK ((regexp_like(`request_sha256`,_latin1'^[a-f0-9]{64}$') and regexp_like(`quote_sha256`,_latin1'^[a-f0-9]{64}$'))),
CONSTRAINT `credit_authorization_policy_sha` CHECK ((`policy_sha256` = lower(sha2(`policy_bytes`,256)))),
CONSTRAINT `credit_authorization_policy_size` CHECK ((length(`policy_bytes`) between 1 and 65536)),
CONSTRAINT `credit_authorization_profile` CHECK ((`profile` in (_latin1'topview',_latin1'pollo',_latin1'invideo',_latin1'libtv',_latin1'flova',_latin1'creatok',_latin1'creatify'))),
CONSTRAINT `credit_authorization_reservation_sha` CHECK ((`reservation_sha256` = lower(sha2(`reservation_bytes`,256)))),
CONSTRAINT `credit_authorization_reservation_size` CHECK ((length(`reservation_bytes`) between 1 and 65536)),
CONSTRAINT `credit_authorization_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `credit_authorization_state` CHECK ((`state` in (_latin1'HELD',_latin1'CAPTURED',_latin1'RELEASED'))),
CONSTRAINT `credit_authorization_times` CHECK (((`expires_at` > `created_at`) and (`expires_at` <= (`created_at` + interval 15 minute)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_credit_ledger_entries
CREATE TABLE `studio_credit_ledger_entries` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `lot_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `operation_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `grant_delta` bigint NOT NULL, `held_delta` bigint NOT NULL, `captured_delta` bigint NOT NULL, `facts_bytes` mediumblob NOT NULL, `facts_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `credit_entry_operation` (`owner_id`,`operation_key`,`lot_id`), KEY `credit_entry_page` (`owner_id`,`created_at`,`id`), KEY `credit_entry_lot_fk` (`owner_id`,`lot_id`), KEY `credit_entry_allocation_fk` (`owner_id`,`authorization_id`,`lot_id`), CONSTRAINT `credit_entry_allocation_fk` FOREIGN KEY (`owner_id`, `authorization_id`, `lot_id`) REFERENCES `studio_credit_authorization_allocations` (`owner_id`, `authorization_id`, `lot_id`), CONSTRAINT `credit_entry_authorization_fk` FOREIGN KEY (`owner_id`, `authorization_id`) REFERENCES `studio_credit_authorizations` (`owner_id`, `id`), CONSTRAINT `credit_entry_lot_fk` FOREIGN KEY (`owner_id`, `lot_id`) REFERENCES `studio_credit_lots` (`owner_id`, `id`), CONSTRAINT `credit_entry_delta` CHECK ((((`kind` = _latin1'grant') and (`authorization_id` is null) and (`grant_delta` between 1 and 1000000000) and (`held_delta` = 0) and (`captured_delta` = 0)) or ((`kind` = _latin1'hold') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`held_delta` between 1 and 1000000000) and (`captured_delta` = 0)) or ((`kind` = _latin1'capture') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`captured_delta` between 1 and 1000000000) and (`held_delta` = -(`captured_delta`))) or ((`kind` = _latin1'release') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`held_delta` between -(1000000000) and -(1)) and (`captured_delta` = 0)))), CONSTRAINT `credit_entry_facts_sha` CHECK ((`facts_sha256` = lower(sha2(`facts_bytes`,256)))), CONSTRAINT `credit_entry_facts_size` CHECK ((length(`facts_bytes`) between 1 and 65536)), CONSTRAINT `credit_entry_operation_key` CHECK ((((`kind` = _latin1'grant') and (`operation_key` = concat(`lot_id`,_latin1':grant'))) or ((`kind` <> _latin1'grant') and (`operation_key` = concat(`authorization_id`,_latin1':',`kind`))))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_lots
CREATE TABLE `studio_credit_lots` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `grant_credits` bigint unsigned NOT NULL, `held_credits` bigint unsigned NOT NULL, `captured_credits` bigint unsigned NOT NULL, `valid_from` datetime(6) NOT NULL, `expires_at` datetime(6) NOT NULL, `eligibility_bytes` mediumblob NOT NULL, `eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_cycle_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `credit_lot_owned` (`owner_id`,`id`), UNIQUE KEY `credit_lot_order` (`source_order_id`), UNIQUE KEY `credit_lot_cycle` (`source_cycle_id`), KEY `credit_lot_eligible` (`owner_id`,`expires_at`,`id`), KEY `credit_lot_order_fk` (`owner_id`,`source_order_id`), KEY `credit_lot_cycle_fk` (`owner_id`,`source_cycle_id`), CONSTRAINT `credit_lot_account_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_credit_accounts` (`owner_id`), CONSTRAINT `credit_lot_cycle_fk` FOREIGN KEY (`owner_id`, `source_cycle_id`) REFERENCES `studio_billing_cycles` (`owner_id`, `id`), CONSTRAINT `credit_lot_order_fk` FOREIGN KEY (`owner_id`, `source_order_id`) REFERENCES `studio_payment_orders` (`owner_id`, `id`), CONSTRAINT `credit_lot_counters` CHECK (((`grant_credits` between 1 and 1000000000) and (`held_credits` <= 1000000000) and (`captured_credits` <= 1000000000) and ((`held_credits` + `captured_credits`) <= `grant_credits`))), CONSTRAINT `credit_lot_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))), CONSTRAINT `credit_lot_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)), CONSTRAINT `credit_lot_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `credit_lot_source` CHECK ((((`source_order_id` is not null) and (`source_cycle_id` is null)) or ((`source_order_id` is null) and (`source_cycle_id` is not null)))), CONSTRAINT `credit_lot_times` CHECK (((`expires_at` > `valid_from`) and (`updated_at` >= `created_at`))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_plan_versions
CREATE TABLE `studio_credit_plan_versions` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`version_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`price_minor` bigint unsigned NOT NULL,
`currency` char(3) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`credit_validity_seconds` int unsigned NOT NULL,
`billing_interval_months` int unsigned NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`published_at` datetime(6) NOT NULL,
`retired_at` datetime(6) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_plan_version_key` (`plan_key`,`version_key`),
CONSTRAINT `credit_plan_amount` CHECK (((`price_minor` between 1 and 1000000000000) and (`grant_credits` between 1 and 1000000000))),
CONSTRAINT `credit_plan_currency` CHECK (regexp_like(`currency`,_latin1'^[A-Z]{3}$')),
CONSTRAINT `credit_plan_duration` CHECK (((`credit_validity_seconds` between 1 and 31622400) and ((`retired_at` is null) or (`retired_at` >= `published_at`)))),
CONSTRAINT `credit_plan_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `credit_plan_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `credit_plan_kind` CHECK (((`kind` in (_latin1'subscription',_latin1'topup')) and (((`kind` = _latin1'subscription') and (`billing_interval_months` in (1,3,12))) or ((`kind` = _latin1'topup') and (`billing_interval_months` = 0)))))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_media_model_versions
CREATE TABLE `studio_media_model_versions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `version_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `config_bytes` mediumblob NOT NULL, `config_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `published_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_version_key` (`model_id`,`version_key`), UNIQUE KEY `studio_media_version_owned_model` (`model_id`,`id`), CONSTRAINT `studio_media_version_model_fk` FOREIGN KEY (`model_id`) REFERENCES `studio_media_models` (`id`), CONSTRAINT `studio_media_version_sha` CHECK ((`config_sha256` = lower(sha2(`config_bytes`,256)))), CONSTRAINT `studio_media_version_size` CHECK ((length(`config_bytes`) between 1 and 65536)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_models
CREATE TABLE `studio_media_models` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `display_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `published_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `revision` bigint unsigned NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_model_key` (`model_key`), KEY `studio_media_model_published_fk` (`id`,`published_version_id`), CONSTRAINT `studio_media_model_published_fk` FOREIGN KEY (`id`, `published_version_id`) REFERENCES `studio_media_model_versions` (`model_id`, `id`), CONSTRAINT `studio_media_model_kind` CHECK ((`kind` = _ascii'video')), CONSTRAINT `studio_media_model_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_media_model_status` CHECK (((`status` in (_ascii'draft',_ascii'active',_ascii'disabled')) and ((`status` <> _ascii'active') or (`published_version_id` is not null)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_payment_events
CREATE TABLE `studio_payment_events` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_event_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `subscription_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `body_bytes` mediumblob NOT NULL, `body_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `payment_event_provider` (`provider_key`,`provider_account`,`provider_event_id`), KEY `payment_event_order_fk` (`owner_id`,`order_id`,`provider_key`,`provider_account`), KEY `payment_event_subscription_fk` (`owner_id`,`subscription_id`,`provider_key`,`provider_account`), CONSTRAINT `payment_event_order_fk` FOREIGN KEY (`owner_id`, `order_id`, `provider_key`, `provider_account`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `provider_key`, `provider_account`), CONSTRAINT `payment_event_subscription_fk` FOREIGN KEY (`owner_id`, `subscription_id`, `provider_key`, `provider_account`) REFERENCES `studio_subscriptions` (`owner_id`, `id`, `provider_key`, `provider_account`), CONSTRAINT `payment_event_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `payment_event_body_sha` CHECK ((`body_sha256` = lower(sha2(`body_bytes`,256)))), CONSTRAINT `payment_event_body_size` CHECK ((length(`body_bytes`) between 1 and 65536)), CONSTRAINT `payment_event_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `payment_event_state` CHECK ((`state` in (_latin1'VERIFIED',_latin1'PROCESSED'))), CONSTRAINT `payment_event_subject` CHECK (((`order_id` is not null) or (`subscription_id` is not null))), CONSTRAINT `payment_event_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_payment_orders
CREATE TABLE `studio_payment_orders` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`price_minor` bigint unsigned NOT NULL,
`currency` char(3) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`valid_from` datetime(6) NOT NULL,
`expires_at` datetime(6) NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_idempotency_key` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_order_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`paid_evidence_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `payment_order_owned` (`owner_id`,`id`),
UNIQUE KEY `payment_order_owned_plan` (`owner_id`,`id`,`plan_version_id`),
UNIQUE KEY `payment_order_owned_provider` (`owner_id`,`id`,`provider_key`,`provider_account`),
UNIQUE KEY `payment_order_client` (`owner_id`,`client_action_id`),
UNIQUE KEY `payment_order_provider_key` (`provider_key`,`provider_account`,`provider_idempotency_key`),
UNIQUE KEY `payment_order_provider_id` (`provider_key`,`provider_account`,`provider_order_id`),
KEY `payment_order_plan_fk` (`plan_version_id`),
CONSTRAINT `payment_order_plan_fk` FOREIGN KEY (`plan_version_id`) REFERENCES `studio_credit_plan_versions` (`id`),
CONSTRAINT `payment_order_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`),
CONSTRAINT `payment_order_amount` CHECK (((`price_minor` between 1 and 1000000000000) and (`grant_credits` between 1 and 1000000000))),
CONSTRAINT `payment_order_currency` CHECK (regexp_like(`currency`,_latin1'^[A-Z]{3}$')),
CONSTRAINT `payment_order_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `payment_order_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `payment_order_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `payment_order_state` CHECK (((`state` in (_latin1'CREATING',_latin1'CREATE_UNKNOWN',_latin1'PENDING',_latin1'PAID',_latin1'CLOSED')) and (((`state` = _latin1'PAID') and (`provider_order_id` is not null) and (`paid_evidence_sha256` is not null) and regexp_like(`paid_evidence_sha256`,_latin1'^[a-f0-9]{64}$')) or ((`state` <> _latin1'PAID') and (`paid_evidence_sha256` is null))))),
CONSTRAINT `payment_order_times` CHECK (((`expires_at` > `valid_from`) and (`expires_at` <= (`valid_from` + interval 31622400 second)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_sessions
CREATE TABLE `studio_sessions` ( `token_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `user_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, `expires_at` datetime(6) NOT NULL, `revoked_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`token_hash`), KEY `studio_session_expiry` (`expires_at`), KEY `studio_session_user` (`user_id`,`expires_at`), CONSTRAINT `studio_session_user_fk` FOREIGN KEY (`user_id`) REFERENCES `studio_users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_session_times` CHECK ((`expires_at` > `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_subscriptions
CREATE TABLE `studio_subscriptions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_subscription_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `period_start` datetime(6) NOT NULL, `period_end` datetime(6) NOT NULL, `cancel_at_period_end` tinyint(1) NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `subscription_owned` (`owner_id`,`id`), UNIQUE KEY `subscription_owned_provider` (`owner_id`,`id`,`provider_key`,`provider_account`), UNIQUE KEY `subscription_provider` (`provider_key`,`provider_account`,`provider_subscription_id`), KEY `subscription_plan_fk` (`plan_version_id`), CONSTRAINT `subscription_plan_fk` FOREIGN KEY (`plan_version_id`) REFERENCES `studio_credit_plan_versions` (`id`), CONSTRAINT `subscription_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `subscription_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `subscription_state` CHECK (((`state` in (_latin1'PENDING',_latin1'ACTIVE',_latin1'PAST_DUE',_latin1'CANCELLED',_latin1'ENDED')) and (`cancel_at_period_end` in (0,1)))), CONSTRAINT `subscription_times` CHECK (((`period_end` > `period_start`) and (`updated_at` >= `created_at`))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_users
CREATE TABLE `studio_users` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `email` varchar(254) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `password_hash` varbinary(72) NOT NULL, `enabled` tinyint(1) NOT NULL DEFAULT '1', `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_user_email` (`email`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
积分账本链路
Flova · 接口清单
共 55 个公开接口,取自源码路由盘点。路径都以 /v1 开头;写操作需要会话 Cookie、可信 Host/Origin 与 CSRF;带品牌的路径用 ?profile=flova;共享的登录、素材、模型目录路径不接受 profile 参数。
Agent/统一动作 7 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/interactions | runInteractions | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/interactions/{interaction_id}/responses | respondInteraction | client_action_id, card_sha256, action, values | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/interaction-actions/{client_action_id} | interactionAction | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/model-changes | changeConversationModel | client_action_id, expected_revision, agent_model, expected_attempt? | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/model-changes/{client_action_id} | modelChangeAction | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/stop | stopRun | client_action_id, expected_attempt? | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/stop-actions/{client_action_id} | stopAction | 200 |
Asset 4 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/assets | listAssets | 200 | |
| POST | /v1/assets | uploadAsset | file | 201 |
| GET | /v1/assets/{asset_id} | getAsset | 200 | |
| GET | /v1/assets/{asset_id}/content | assetContent | 200/206 |
LoginSession 1 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| POST | /v1/auth/logout | logout | 200 |
MaaBinding 5 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/maa/model-options | maaModels | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/messages | sendMaaMessage | client_action_id, content | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/actions/{client_action_id} | getMaaAction | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/state | getMaaState | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/events | maaEvents | 200 |
Media 11 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/media/models | publicMediaModels | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests | createMediaRequest | client_request_id, model_id, model_version_id, prompt, duration_seconds, ratio, resolution, admission? | 200 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests | mediaRequestByClient | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id} | getMediaRequest | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs/{job_id} | getMediaJob | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs/{job_id}/output | getMediaOutput | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id}/job | mediaJobByRequest | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id}/approve | approveMediaRequest | client_approval_id, request_sha256, quote_sha256 | 200 |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/from-maa | createMediaRequestFromMaa | input, source_run_id, source_assistant_sha256, admission? | 200 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs | listMediaJobs | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/intents | listMediaIntents | 200 |
Other 9 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects/{project_id}/canvas/revisions | listCanvasRevisions | 200 | |
| GET | /v1/projects/{project_id}/canvas/revisions/{revision} | getCanvasRevision | 200 | |
| POST | /v1/projects/{project_id}/canvas/revisions/{revision}/restore | restoreCanvasRevision | expected_revision | 200 |
| GET | /v1/projects/{project_id}/document/revisions | listTimelineRevisions | 200 | |
| GET | /v1/projects/{project_id}/document/revisions/{revision} | getTimelineRevision | 200 | |
| POST | /v1/projects/{project_id}/document/revisions/{revision}/restore | restoreTimelineRevision | expected_revision | 200 |
| GET | /v1/projects/{project_id}/assets | listProjectAssets | 200 | |
| POST | /v1/projects/{project_id}/assets | attachProjectAsset | asset_id, expected_revision | 200 |
| POST | /v1/projects/{project_id}/assets/{asset_id}/detach | detachProjectAsset | expected_revision | 200 |
Project 15 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects | listProjects | 200 | |
| POST | /v1/projects | createProject | title | 201 |
| GET | /v1/projects/{project_id} | getProject | 200 | |
| GET | /v1/projects/{project_id}/conversations | listConversations | 200 | |
| POST | /v1/projects/{project_id}/conversations | createConversation | title | 201 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id} | getConversation | 200 | |
| GET | /v1/projects/{project_id}/canvas | getCanvas | 200 | |
| POST | /v1/projects/{project_id}/canvas | saveCanvas | expected_revision, state | 200 |
| GET | /v1/projects/{project_id}/document | getDocument | 200 | |
| POST | /v1/projects/{project_id}/document | saveDocument | expected_revision, state | 200 |
| GET | /v1/projects/{project_id}/export-jobs | listExportJobs | 200 | |
| POST | /v1/projects/{project_id}/export-jobs | queueExport | document_revision, output? | 202 |
| GET | /v1/projects/{project_id}/export-jobs/{job_id} | getExportJob | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/binding | getMaaBinding | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/binding | bindMaa | agent_model XOR use_default:true | 200 |
User 3 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| POST | /v1/auth/register | register | email, password | 201 |
| POST | /v1/auth/login | login | email, password | 200 |
| GET | /v1/auth/session | session | 200 |
Flova 自己公开的接口调用流程(来自其官方资料)
| 步骤 | 调用关系 | 操作 | 证据 |
|---|---|---|---|
| 连接账号 | 创作者 → 接入端 | 从 Web 或外部 CLI 进入账号;CLI 官方指南使用浏览器账号授权。 | W |
| 建立项目上下文 | 接入端 → 项目上下文 | 历史 CLI:project create --name --description 返回 project_id/project_url;已有项目按 ID 读取上下文。 | A |
| 附上参考素材 | 接入端 → 项目上下文 | 历史 CLI 上传先获得文件对象;随后通过 run 的 --file-from 附给本次输入。 | A |
| 启动创作Run | 接入端 → Agent执行 | 历史 CLI:run PROJECT_ID --content;结果含 project_id、stream_chat_id、terminal、assistant_messages、pending_actions。 | A |
| 报告进度与待决项 | Agent执行 → 接入端 | 返回消息与 pending_actions;Action 字段有 action_id、resume_message_id、blocking、options[].id/effect。 | A |
| 形成可用资源 | Agent执行 → 资源与编辑 | 历史 Resource 含 resource_id、media_type、artifact_role、status、resource_url、error、state_version;官方 Web 把结果展示在相应面板。 | A |
| 检查并细调工程 | 创作者 → 资源与编辑 | 检查 Media Space/Canvas 与分镜,手改 Timeline;需要时从消息恢复或在新 Project 分叉。 | W |
| 提交并检查导出 | 接入端 → 导出任务 | 历史 CLI 导出/打包另有 task_id 与 terminal,视频交付含 export_url;官方 Web 导出当前 Timeline。 | A |
Flova · 代码与下载
1.2 MB · 53 个文件 · SHA-256
19a1f4b8d12e909d188666e4a346dfe0484d7c4d17e544129f43a764a91e4d67下载:flova-replica.zip · 后端与合同 · 全部代码
| 目录 | 内容 |
|---|---|
| frontend/ | Flova 前端:<code>candidate-8875-unified-v22.html</code> 及它引用的全部脚本与样式 |
| contracts/ | 本品牌的表结构 SQL、ER(svg / mmd)、外键清单;接口目录(json / csv);共享身份库表结构 |
| README.md | 怎么运行、需要自备什么 |
运行前端
python3 -m http.server -d frontend 8791
# 打开 http://127.0.0.1:8791/agent-integration/apps-production-brand-v14/flova/candidate-8875-unified-v22.htmlbackend-and-contracts.zip;all-brands-code.zip 是全部。包里没有任何凭据、数据库备份或媒体文件,已做敏感串扫描。MAA_AGENT_ROOT)、模型网关与对象存储配置。静态前端单独打开不需要后端,但登录、对话、生成、导出需要整套服务。复刻完成度(审计 2026-10-19)
结论:不是完美复刻。官方资料里的 63 项能力:实测跑通 2、只有通用对话 0、后端有但没跑过 18、没有后端 43。
真正跑通的:从需求形成创作方案;显示进度并停止调整。
界面对照(首页):真实页面采集到 17 个控件 / 标题文字,复刻页找到 11 个;位置偏差中位数 45 px(5/11 个在 24 px 内)。缺的有:✌️、新、城市英雄大片、探索名画背后的故事(360°环绕视角)、万物皆战场、查看全部。
逐个点击(已登录首页):36 个可点控件,点了有效 7 个,只提示“此功能正在接入” 21 个,没反应或只变样式 1 个,禁用 3 个,未点(发送 / 删除 / 退出等)4 个。
只提示“正在接入”的控件(21 次点击,20 种)
FlovaSkill创作人招募中、Skill ×2、FlovaTV、教程、Flova CLI、添加文件、流程 默认、语音输入、热门玩法、剧情短片、商业广告、音乐/MV、更多 Skill ›、剧本生视频(需上传剧本)、故事驱动型视频、多宫格生视频、3D国漫古装精品短剧、玄幻漫剧武打片段、古风甜宠短剧、剧本杀故事视频
点了没反应或只变样式的控件(1 次点击,1 种)
首页
复刻页自报的绑定状态(页面内嵌的绑定清单):原生工作区控件(新建项目、会话、登录等)8 / 10 个没有绑定到原页面的控件,由统一的工作区条代替;路由 assets 缺失或只做了一部分;
首屏截图对照(左:真实产品 flova/reference-desktop.jpg;右:复刻页)· 粗粒度差异 5%
真实截图是测试账号登录后的画面,内容(作品、项目、横幅)本来就不同,差异百分比只作参考,重点看布局。
CreaTok · 总览
- 它是什么:缺信息时弹结构化表单;方案是 3 镜头表格;Agent 交互:只改第 2 镜头,其余不动。
- 我们借鉴:澄清卡(必填/单选)和镜头局部修改(决策 D5 D6)。
- 复刻现状:4 项已验证,在线试用 http://119.23.106.60:8106/;后端与其余六个品牌共用一套(24 张表、55 个接口),所以 ER / 表结构 / 接口页的通用部分默认折叠。
围绕商品内容建立发现、Agent/Canvas 创作、TikTok 发布和效果复盘闭环;Web、Chrome 扩展及 CLI/API 分开标注。
证据:W 官方说明,A 官方接口合同,C 客户端代码,O 实测。“未实测”= 只核对了官方页面,没有上传素材或生成。
45 项,分 12 类
首页(浅色)+ Agent 任务页
24 张表 · 34 个外键 · 85 个索引
能力目录
智能 Agent 与 Skill 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 多步骤创作 Agent 与审批 | 对话提出创作计划,用户批准后再生成。 | W | 未确认审批事件协议、取消和失败恢复 |
| 销售脚本 Agent | 面向商品销售生成脚本与提示词。 | W | 未核实脚本版本与会话保存规则 |
| 脚本转分镜 | 把脚本或商品构想组织成分镜图。 | W | 分镜与最终视频字段映射未知 |
项目与会话 2 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| Canvas 项目管理 | 公开页显示个人、团队项目及 New Flow。 | O | 仅确认入口,项目 CRUD 与权限未测试 |
| 节点画布和局部重跑 | 连接图像、视频、声音步骤并调整单步。 | W | 未核实连接类型、节点状态与版本恢复 |
素材与商品 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 工作区素材与商品复用 | 集中使用素材及商品信息辅助创作。 | W | 上传、删除和素材归属未实测 |
| 外部内容收藏及商品采集 | 扩展保存帖子、商品媒体和卖点到工作区。 | C | 帖子内部 UID 与外部 postId 分离;只读包证据,未调用写接口 |
| TikTok 视频与照片下载 | 下载公开视频或照片组供后续参考。 | W | 可访问性及原内容权限仍依来源 |
发现与分析 4 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 热门内容和竞品发现 | 浏览带货内容、账号及品类趋势。 | W | 数据覆盖地区、更新频率未知 |
| TikTok 创作者分析 | 查看创作者及视频表现信息。 | W | 具体指标完整性和限额未测试 |
| 视频文案提取及结构分析 | 从 TikTok 链接提取文案并拆解内容。 | W | 未提交生成,效果、耗时和当前费用未验证 |
| 视频反推提示词 | 从参考视频得到创作提示词。 | W | 未提交生成,效果、耗时和当前费用未验证 |
视频生成 4 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 参考视频复刻 | 以自己的商品重构参考视频。 | W | 没有提交参考媒体,保真度与结果未测 |
| 商品链接转视频 | 导入商品链接或素材制作电商短片。 | W | 商品抓取支持范围及脚本确认步骤未测 |
| 多模型视频生成入口 | 按任务选择视频模型及输入方式。 | W | 首尾帧、参考音频、编辑等能力按模型不同;不认定全部通用 |
| 参考动作迁移 | 把参考视频动作迁移到新角色。 | W | 未提交生成,效果、耗时和当前费用未验证 |
声音与人物 4 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 视频换人 | 用目标人物替换原视频主体。 | W | 未提交生成,效果、耗时和当前费用未验证 |
| 音频驱动口型 | 将音频与视频人物口型对齐。 | W | 未提交生成,效果、耗时和当前费用未验证 |
| 文字转语音 | 把脚本文字转成声音。 | W | 语种、音色与长度限制未实测 |
| 声音克隆 | 从声音样本建立目标音色。 | W | 样本要求、授权记录及存续规则未知 |
编辑与导出 9 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 视频配音与字幕翻译 | 进行视频语言转换及配音处理。 | W | 语种、字幕及口型能力以所选任务为准 |
| 图片文字翻译 | 翻译图中文字并保留排版。 | W | 未提交生成,效果、耗时和当前费用未验证 |
| 背景移除 | 移除图片背景并输出透明素材。 | W | 未提交生成,效果、耗时和当前费用未验证 |
| 图像分层 | 拆分图片前景层与背景用于编辑。 | W | 未核实分层文件格式和下载组织 |
| 图像超分 | 提升图片输出分辨率。 | W | 未提交生成,效果、耗时和当前费用未验证 |
| 视频字幕擦除 | 清除视频中的已烧录字幕。 | W | 未提交生成,效果、耗时和当前费用未验证 |
| 视频水印擦除 | 对选定视频内容进行水印清理。 | W | 未提交生成,效果、耗时和当前费用未验证 |
| 视频超分 | 提高视频分辨率与视觉质量。 | W | 分辨率档位视任务,不保证所有输入均可达最高档 |
| Amazon AI 人物元数据标注 | 本地写入标记,读回验证后下载副本。 | W | 素材库批量需登录;声明本地处理,未独立审计实现 |
图片生成 6 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 图像生成与编辑 | 用文本或参考图制作、修改图片。 | W | 每个模型输入格式和参数不同 |
| 商品图、详情页与 A+ 内容 | 生成商品主图、长详情图及 A+ 图。 | W | 三个专用工具归为一组;不认定为自动发布商品页 |
| 带货图文轮播 | 制作 TikTok Shop 风格的商品图组。 | W | 图组数量与发布约束未测试 |
| 商品多角度图 | 由单张商品图生成不同视角。 | W | 角度一致性及批量上限未测试 |
| 图片构图批量参考 | 参考布局批量制作商品图片。 | W | 批量任务状态及部分失败处理未知 |
| 虚拟试穿 | 输入模特图与衣服图生成试穿结果。 | W | 未提交生成,效果、耗时和当前费用未验证 |
发布与运营 4 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| TikTok Shop 授权与商品预检 | 连接账号、同步商品、挂商品并可预检。 | W | 权限随账号类型、市场及 TikTok 规则;预检不是发布批准 |
| 多账号批量排期及状态 | 按时区安排任务,逐条跟踪发布状态。 | W | 失败重试和任务状态协议未测试 |
| 普通 TikTok 视频与照片发布 | 支持无商品锚点的普通内容发布。 | W | 和 Shop 共用账号额度,具体设置按平台支持 |
| 带货视频及商品效果复盘 | 从已发布任务查看观看、点击和销售表现。 | W | 数据周期、地区和授权影响覆盖;示例数据不是实测结果 |
协作与权益 2 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 团队工作区、角色与成员额度 | 邀请成员,共用素材、商品和账号并控制额度。 | W | 只确认 Owner/Admin/Member 展示,完整权限表未知 |
| 订阅、生成积分与发布账号额度 | 生成受方案和积分限制,发布采用账号额度。 | W | 官方发布页称发布不扣积分;额度归成员并跨工作区计数,未用账号验证 |
模板与社区 1 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 社区流程模板和作品案例 | 按场景搜索模板或浏览公开案例。 | O | 入口存在不证明已有所有分类模板,复用未执行 |
开放接入与客户端 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| CLI、Open API 与 Agent Skills | 用 API Key 和 Skills 接入本地 AI Agent。 | W | 未安装 CLI;公开 Skills 不是完整服务端源代码 |
| 官方 Chrome 侧栏扩展 | 在内容网站提取、收藏、分析并辅助创作。 | C | 扩展流式接口不能当主 Web Agent 协议;密钥值不保留 |
| Lark 中的 Agent | 从 Lark 对话提交想法并审批创作。 | W | 没有授权 Lark;机器人事件、租户与会话对应未知 |
尚不清楚的部分
- Web 时间轴编辑器:当前官方目录和匿名 Canvas 没确认传统多轨时间轴,不能补造。
- 会话历史、分叉、自动保存协议:主 Agent 未登录,历史和实时服务合同未观察。
- 用户自建 Skill 的版本/发布市场:公开外部 Agent Skills 与社区流程模板不能推为 Web 用户 Skill 管理。
- Web 全量导出与分享权限:局部工具有下载,未核实工程导出、协作链接、有效期和权限。
- 原生移动和桌面客户端:确认 Web、Chrome 扩展、CLI、Lark;未取得官方 APK/IPA/DMG/EXE。
- 官方 MCP 服务:当前 CLI 页证明 Skills/CLI/Open API;没有核实独立 MCP 合同。
竞品技术栈观察
公开Web取包受网络超时限制;官方扩展可确认React18.3.1和TSX源路径,并出现Plasmo/Parcel标记。扩展技术不能外推业务Web或后端。
| 项目 | 观察到的内容 | 状态 | 置信度 |
|---|---|---|---|
| Nginx 与代理版本 | Web入口本轮无响应banner;Nginx产品与准确版本均未知。 | unknown | low |
| 前端运行语言 | 扩展交付JavaScript并运行于浏览器;Web页面本轮未取得可执行构件。 | observed | high |
| 前端源码语言 | 扩展包含popup.tsx、sidepanel.tsx源路径;Web源码语言及TypeScript版本未知。 | observed | high |
| 前端框架与版本 | 扩展React18.3.1;出现Plasmo构件标记。Web框架和版本未知。 | observed | high |
| 构建与服务端渲染 | 扩展有Parcel运行时与Plasmo构建标记;Web打包器、SSR模式和版本未知。 | inferred | medium |
| 业务后端语言 | 业务后端语言未知;CLI、扩展JavaScript和同域API都不能证明服务端语言。 | unknown | low |
| 业务后端框架 | 业务后端框架及准确版本未知。 | unknown | low |
| 分发层与源站线索 | 媒体CNAME为volcgslb;历史政策披露Vercel托管/分析。应用源站、数据库和生成节点未知。 | observed | medium |
| 代码仓库与目录关系 | 扩展包有src/popup.tsx等路径;Web与后端同仓、同目录、同进程关系未知。 | unknown | low |
竞品服务调用图
扩展的面板→后台→Cookie API→SSE中继可由静态代码解释;Web Agent、Canvas与TikTok发布仅按官方流程表示,实际执行协议仍未知。
| 节点 | 层 | 职责 | 证据 |
|---|---|---|---|
| 扩展面板 | client | 读取外部页面选定材料并展示分析事件。 | C |
| 扩展后台 | client | Manifest V3 background中继HTTP及流消息。 | C |
| Web创作界面 | client | Agent批准生成与Canvas节点入口。 | W |
| Web与API入口 | entry | www.creatok.ai为扩展Web/API共同请求基址。 | C |
| 账号上下文 | domain | 处理Cookie会话与扩展me读取的逻辑职责。 | I |
| 素材分析处理 | runtime | 解释分析/翻译端点及SSE结果的处理职责。 | I |
| 收藏资料 | domain | 内部uid与外部platformPostId的收藏接口资源。 | C |
| 商品资料 | domain | 来源身份、卖点与用户选择媒体的接口资源。 | C |
| 创作编排职责 | runtime | 从脚本建议、批准到后续生成的可能协调职责。 | I |
| 生成执行职责 | runtime | 批准方案后执行生成或转发生成请求的逻辑职责。 | I |
| 发布与表现 | domain | 账号、商品锚点、排期、预检和表现回看的产品职责。 | W |
| TikTok平台 | external | 发布授权与视频/商品表现的外部业务平台。 | W |
| 公开媒体入口 | external | content.creatok.com媒体地址及分发CNAME线索。 | O |
增长与运营机制
复刻状态
| 能力 | 状态 | 依据 |
|---|---|---|
| 浅色令牌、登录框、新建项目框 | 已验证 | 弹窗白底、主按钮 #18181b;与该品牌浅色界面一致 |
| Agent 对话:新建项目与会话、自动选默认模型、发送收回复 | 已验证 | 真实 Maa,收到回复;输入框在页面下方,窄视口需滚动到可见 |
| 停止回复 | 已验证 | maa_run_stop_actions=terminal_observed,run=cancelled |
| 首页与 Agent 任务页布局 | 已加载 | 沿用早期静态页(文件 12 MB,含内嵌素材) |
| 生成视频(报价→批准→成片) | 已验证 | 测试部署 119.23.106.60:8106 上真实生成:Seedance 2.0 Mini 5 秒,报价 3 积分,批准后任务成功、产出 MP4(接口级验证;素材页展示未逐项核对) |
agent-integration/apps-production-brand-v14/creatok/candidate-8875-unified-v22.html复刻的架构 七个品牌相同,展开查看
flowchart LR U[浏览器] -->|静态页| FE[品牌前端<br/>令牌 + 通用层 + 运行时脚本] FE -->|/v1/* Cookie + CSRF| BFF[BFF 业务服务 Go] BFF --> MY[(MySQL<br/>共享身份库 + 品牌库)] BFF -->|会话 / 消息 / 事件| MAA[Maa Agent] BFF -->|任务| WK[媒体 worker] WK -->|submit_video| GW[模型网关] GW --> MOD[视频模型] MAA --> GW BFF --> OBJ[(素材 / 导出存储)]
?profile=creatok 区分品牌)。品牌差异在前端:令牌(颜色、圆角、字体)、入口与页面结构。CreaTok · Agent 交互过程
竞品里观察到的
COMPLETED_TWO_TEXT_TURNS 本轮真实完成两轮套餐内文字对话:4题澄清→3镜头文字方案→只改第2镜头→刷新恢复;积分6→6,日额度0%→10%,额外用量关闭。未执行媒体生成;下载按钮未确认文件。
| 编号 | 操作 | 结果 |
|---|---|---|
| CK11-D01 | 打开独立新 Agent 任务 | 已登录,任务页支持 / 技能和 @ 素材。未读取或操作既有任务。 |
| CK11-D02 | 打开每日 Agent 额度 | 已用0%;额外用量OFF,说明额度用完后继续使用按用量扣积分;余额6。 |
| CK11-D03 | Send 统一文字需求 | 进入运行中/思考中,约10s UI变为需要输入,出现4题澄清卡;未出现媒体生成报价。 |
| CK11-D04 | 补齐四题并提交 | 问商品/卖点/目标/场景,语言,可选人物,可选场景。多题选择中文后自动进入下一题,可回上一题。 |
| CK11-D05 | 读取第一轮结果 | 明确无需再补充,输出3镜头表格和复制Markdown/下载表格入口;UI已处理12s。 |
| CK11-D06 | Send 只改第2镜头的追问 | 约6s UI完成;1/3画面、时间、字幕、镜头转场一致,仅旁白引号排版变化;第2改为咖啡粉落空杯。 |
| CK11-D07 | 复核每日额度与余额 | 已用10%,额外用量仍OFF,余额6;只证明当前页面统计,未对账流水。 |
| CK11-D08 | 点击 Download table | 已实际点击;download事件6s内没有可读取文件路径,文件下载成功未证实。 |
| CK11-D09 | 重载独立研究标签 | 两个表格与两轮消息恢复;第二个表格逐单元格与重载前一致。 |
对话维度
| 维度 | 观察 |
|---|---|
| clarification | O:四题结构化用户输入卡,不是普通聊天段落。 |
| plan | O:15秒3镜头消息表格,时间/画面/旁白/字幕/镜头方式。 |
| action_confirmation | 没有媒体任务或费用批准卡;无批准任何付费动作。 |
| targeted_revision | O:自然语言只改第2镜头,结果对比通过场景/时间/字幕/转场保留检查。 |
| tool_calls | UI说加载短视频脚本流程;具体tool ID、网络调用、Skill版本和所有隐藏工具未抓取。 |
| artifacts | O:两轮各一个消息内表格,复制/下载控件可见;下载只尝试未取得成功证据。 |
| history_resume | O:自身标签reload后两表格及消息恢复,不宣称跨设备。 |
费用与准入
| 项 | 值 |
|---|---|
| before_visible_credits | 6 |
| after_visible_credits | 6 |
| before_daily_usage_percent | 0 |
| after_daily_usage_percent | 10 |
| extra_usage_before | false |
| extra_usage_after | false |
| media_generated | false |
| media_generation_approval_given | false |
| ledger_verified | false |
| scope | 当前账号套餐内Agent额度;不推断其他用户或套餐的文字计费。 |
对我们设计的启示
| 结论 | 内容 | 做法 / 原因 |
|---|---|---|
| adopt | 缺信息时使用有ID、必填/可选、单选/文本、可回退的澄清卡,回答后继续原Run。 | 一张pending交互卡汇总必要信息,用户补齐并提交,服务端验状态/摘要后恢复Run。 |
| adopt | 将文字方案呈现为可比对的镜头表格,保留上一版结果。 | PLAN输出用镜头稳定键、时段/画面/对白/字幕/转场渲染;复制/下载为用户明确动作。 |
| adapt | 区分套餐内Agent额度与额外扣分开关,展示媒体费用单独授权。 | |
| adapt | 局部修改保持目标范围,同时提示前后镜头的连续性影响。 | |
| reject | 不把消息表格的完整重发当成对现有时间轴无条件覆盖,也不从Download按钮可见推出媒体导出成功。 | 本轮没有编辑器绑定/媒体导出实测;需用已有Output/Selection/CAS协议明确采纳。 |
竞品公开的调用流程
| 步骤 | 调用关系 | 操作 | 证据 |
|---|---|---|---|
| 面板提交请求 | 扩展面板 → 扩展后台 | chrome.runtime消息API_REQUEST携带path/method/body/query/headers;流请求API_STREAM_REQUEST另带streamId。 | C |
| 读取账号上下文 | 扩展后台 → Web入口 | GET https://www.creatok.ai/api/extension/me;fetch credentials:include;客户端处理code===0/data与ApiError。 | C |
| 发起视觉分析 | 扩展后台 → Web入口 | POST /api/extension/tiktok-transcript-generator/decompose-video-script;body含video_id、locale、analysis_contract:visual_v1;Accept:text/event-stream。 | C |
| 中继分析事件 | 扩展后台 → 扩展面板 | 后台读取response.body并发送API_STREAM_EVENT;payload含streamId、type:chunk|done|error;UI按空行解析data JSON的partial/final/error/done。 | C |
| 保存收藏身份 | 扩展后台 → Web入口 | POST /api/extension/collections/posts;提交submittedUrl、contentType、postSnapshot、locale等;返回post.uid与platformPostId。 | C |
| 导入商品资料 | 扩展后台 → Web入口 | POST /api/extension/products/analyze-selling-points与/api/extension/products;来源platform/externalProductId、卖点与已选media[]分别提交。 | C |
| 批准脚本并生成 | 创作界面 → Web入口 | 官方Web Agent先给脚本和生成方案,用户批准后进入生成;对应HTTP方法、URL、body与事件格式未取得。 | W |
| 画布局部重跑 | 创作界面 → Web入口 | 官方Canvas支持节点组合与局部重跑;节点保存、连线编辑、版本、运行接口均未核实。 | W |
| 排期发布与回看 | Web入口 → 发布平台 | 官方流程为TikTok授权、商品锚点/预检、立即或排期发布、状态与表现回收;具体TikTok调用与内部发布API合同未知。 | W |
在本品牌复刻上的测试结果
| 能力 | 状态 | 依据 |
|---|---|---|
| Agent 对话:新建项目与会话、自动选默认模型、发送收回复 | 已验证 | 真实 Maa,收到回复;输入框在页面下方,窄视口需滚动到可见 |
| 停止回复 | 已验证 | maa_run_stop_actions=terminal_observed,run=cancelled |
| 首页与 Agent 任务页布局 | 已加载 | 沿用早期静态页(文件 12 MB,含内嵌素材) |
| 生成视频(报价→批准→成片) | 已验证 | 测试部署 119.23.106.60:8106 上真实生成:Seedance 2.0 Mini 5 秒,报价 3 积分,批准后任务成功、产出 MP4(接口级验证;素材页展示未逐项核对) |
复刻里的 Agent 交互设计(时序图、状态机、规则) 七个品牌相同,展开查看
sequenceDiagram
autonumber
participant B as 浏览器
participant S as BFF
participant DB as MySQL
participant M as Maa Agent
participant W as 媒体 worker
participant G as 模型网关
B->>S: POST /projects, /conversations
B->>S: POST maa/binding
S->>DB: maa_bindings dispatching
S->>M: 创建原生会话
M-->>S: native_cid
S->>DB: maa_bindings bound
B->>S: POST maa/messages {client_action_id, content}
S->>DB: maa_message_actions 幂等回执
S-->>B: 202 + run_id
S->>M: 提交消息
S->>DB: maa_runs queued 到 running
loop 事件游标
B->>S: GET runs/{id}/events
S-->>B: assistant.delta / assistant.message
end
M-->>S: run.completed
S->>DB: 记录助手内容 SHA-256
B->>S: POST media/requests/from-maa {source_run_id, sha256}
S-->>B: 报价 + 有效期 + quote_sha256
B->>S: POST approve {client_approval_id, request_sha256, quote_sha256}
S->>DB: 冻结积分 + 建任务
W->>G: submit_video
G-->>W: 视频
W->>DB: 产出入库 + 扣费
B->>S: GET media/jobs/{id}Run 状态机
stateDiagram-v2 [*] --> queued: POST maa/messages 202 queued --> running running --> waiting_interaction: 需要澄清卡 waiting_interaction --> running: respondInteraction running --> completed running --> failed running --> cancelled: stopRun waiting_interaction --> cancelled completed --> [*] failed --> [*] cancelled --> [*]
媒体任务状态机
stateDiagram-v2 [*] --> quoted quoted --> expired: 约 5 分钟 quoted --> approved: approve approved --> held: 冻结积分 held --> queued queued --> running: worker 领取 running --> succeeded: 产出入库 succeeded --> captured: 扣费确认 running --> failed failed --> 待核对: 供应商已受理后失败,冻结保留,界面写「费用待核对」
交互规则
| 环节 | 规则 | 落库 |
|---|---|---|
| 绑定会话 | bindMaa 传 agent_model 或 use_default;先 dispatching,拿到原生会话号后才 bound(约束保证二者一致) | maa_bindings |
| 发消息 | client_action_id 幂等;返回 202 + run_id;同一个动作 ID 内容不同返回 409 | maa_message_actions, maa_runs |
| 事件 | 按 seq 游标读取;服务端先清洗路径、内部地址和令牌再公开 | maa_runs.last_event_seq |
| 完成证据 | 完成时记录助手内容的两份 SHA-256 与字节数 | maa_runs |
| 澄清卡(HITL) | Run 进入 waiting_interaction;respondInteraction 带 card_sha256;不能恢复两次 | maa_interactions, maa_interaction_actions |
| 停止 | stopRun 幂等,回执只说「已观测到终态」;对话里保留「已停止回复」 | maa_run_stop_actions |
| 切换模型 | 必须带 expected_revision;有未决切换时拒绝发新消息 | maa_model_change_actions |
| 生成视频 | from-maa → 报价 → 批准 → 冻结 → worker → 入库 → 扣费;批准带请求哈希与报价哈希 | studio_media_*, 积分账本 |
| 报价过期 | 批准被拒,不建任务不扣费;界面提示重新报价 | studio_media_requests.expires_at |
| 失败后的积分 | 供应商已受理后失败:冻结保留,界面写「费用待核对」,不自动释放;本部署的账本里还没出现过释放分录(12 笔冻结、8 笔扣费、其余 4 笔仍冻结) | studio_credit_ledger_entries |
| 会话过期 | 每 8 秒检查登录状态;失效时横幅提示,登录后恢复 | — |
CreaTok · ER 图
品牌库 studio_profile_creatok:24 张表、34 个真实外键、66 个检查约束、22 个触发器。图由实际表结构生成,箭头从父表指向子表。品牌库与共享身份库之间的 owner_id、asset_id 靠应用层归属检查,不画成外键。
共 61 条关系:一对多 37 条,一对一 10 条,一对多(父可选) 10 条,一对一(父可选) 4 条;多对多 2 组(经关联表)。
用户与登录 素材 积分账本 支付与订阅 模型目录 项目与会话 画布 · 时间轴 · 导出 Agent 交互 生成 · 媒体 · 交付
基数标注(线上的文字,箭头从父表指向子表):1:N 一对多,子表外键必填;0..1:N 一对多,但外键可空,所以父是可选的;1:1 一对一,子表外键上有唯一键;0..1:1 一对一且父可选。红色粗双向线 = N:M 多对多,经带 ⇄ 的关联表(它的主键就是两个外键)。实线 = 数据库真实外键;灰色虚线 = 跨库关系(两个库之间数据库无法建外键,由应用层检查);橙色粗框与粗线 = Agent 交互相关。每张表都带 owner_id(指向用户),为了图清楚没有逐条画线。
全景图:全部实体与关系
默认缩放到页面宽度,先看整体结构;点一下图切换到原始大小(看清表名,在框内上下左右滚动),再点一下缩回。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":26,"rankSpacing":80}}}%%
flowchart LR
subgraph sg_i_user["用户与登录"]
direction TB
t_studio_users["users"]
t_studio_sessions["sessions"]
end
subgraph sg_i_asset["素材"]
direction TB
t_studio_assets["assets"]
end
subgraph sg_i_credit["积分账本"]
direction TB
t_studio_credit_accounts["credit_accounts"]
t_studio_credit_lots["credit_lots"]
t_studio_credit_authorizations["credit_authorizations"]
t_studio_credit_authorization_allocations["⇄ credit_authorization_allocations"]
t_studio_credit_ledger_entries["credit_ledger_entries"]
t_studio_credit_plan_versions["credit_plan_versions"]
t_studio_billing_cycles["billing_cycles"]
end
subgraph sg_i_pay["支付与订阅"]
direction TB
t_studio_payment_orders["payment_orders"]
t_studio_payment_events["payment_events"]
t_studio_subscriptions["subscriptions"]
end
subgraph sg_i_model["模型目录"]
direction TB
t_studio_media_models["media_models"]
t_studio_media_model_versions["media_model_versions"]
end
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_canvas["画布 · 时间轴 · 导出"]
direction TB
t_studio_video_documents["video_documents"]
t_studio_canvases["canvases"]
t_studio_canvas_revisions["canvas_revisions"]
t_studio_timeline_revisions["timeline_revisions"]
t_studio_export_jobs["export_jobs"]
t_studio_project_asset_refs["⇄ project_asset_refs"]
end
subgraph sg_agent["⭕ Agent 交互"]
direction TB
t_maa_bindings["maa_bindings"]
t_maa_runs["maa_runs"]
t_maa_message_actions["maa_message_actions"]
t_maa_interactions["maa_interactions"]
t_maa_interaction_actions["maa_interaction_actions"]
t_maa_model_change_actions["maa_model_change_actions"]
t_maa_run_stop_actions["maa_run_stop_actions"]
end
subgraph sg_media["生成 · 媒体 · 交付"]
direction TB
t_studio_media_requests["media_requests"]
t_studio_media_jobs["media_jobs"]
t_studio_media_submission_attempts["media_submission_attempts"]
t_studio_media_outputs["media_outputs"]
t_generation_jobs["gen_jobs"]
t_generation_reservations["gen_reservations"]
t_generation_deliveries["gen_deliveries"]
t_generation_development_budgets["gen_development_budgets"]
t_studio_credit_recovery_intents["credit_recovery_intents"]
end
t_studio_users -->|"1:N"| t_studio_assets
t_studio_payment_orders -->|"1:1"| t_studio_billing_cycles
t_studio_subscriptions -->|"1:N"| t_studio_billing_cycles
t_studio_users -->|"1:1"| t_studio_credit_accounts
t_studio_credit_authorizations -->|"1:N"| t_studio_credit_authorization_allocations
t_studio_credit_lots -->|"1:N"| t_studio_credit_authorization_allocations
t_studio_credit_accounts -->|"1:N"| t_studio_credit_authorizations
t_studio_credit_authorization_allocations -->|"0..1:N"| t_studio_credit_ledger_entries
t_studio_credit_authorizations -->|"0..1:N"| t_studio_credit_ledger_entries
t_studio_credit_lots -->|"1:N"| t_studio_credit_ledger_entries
t_studio_credit_accounts -->|"1:N"| t_studio_credit_lots
t_studio_billing_cycles -->|"0..1:1"| t_studio_credit_lots
t_studio_payment_orders -->|"0..1:1"| t_studio_credit_lots
t_studio_media_models -->|"1:N"| t_studio_media_model_versions
t_studio_media_model_versions -->|"0..1:1"| t_studio_media_models
t_studio_payment_orders -->|"0..1:N"| t_studio_payment_events
t_studio_subscriptions -->|"0..1:N"| t_studio_payment_events
t_studio_users -->|"1:N"| t_studio_payment_events
t_studio_credit_plan_versions -->|"1:N"| t_studio_payment_orders
t_studio_users -->|"1:N"| t_studio_payment_orders
t_studio_users -->|"1:N"| t_studio_sessions
t_studio_credit_plan_versions -->|"1:N"| t_studio_subscriptions
t_studio_users -->|"1:N"| t_studio_subscriptions
t_generation_jobs -->|"1:1"| t_generation_deliveries
t_studio_projects -->|"1:N"| t_generation_deliveries
t_studio_conversations -->|"1:N"| t_generation_deliveries
t_generation_development_budgets -->|"1:N"| t_generation_jobs
t_studio_projects -->|"1:N"| t_generation_jobs
t_studio_conversations -->|"1:N"| t_generation_jobs
t_generation_jobs -->|"1:1"| t_generation_reservations
t_studio_conversations -->|"1:1"| t_maa_bindings
t_maa_model_change_actions -->|"0..1:1"| t_maa_bindings
t_maa_interactions -->|"1:1"| t_maa_interaction_actions
t_maa_runs -->|"1:N"| t_maa_interactions
t_maa_bindings -->|"1:N"| t_maa_message_actions
t_maa_runs -->|"0..1:N"| t_maa_message_actions
t_maa_bindings -->|"1:N"| t_maa_model_change_actions
t_maa_runs -->|"1:1"| t_maa_run_stop_actions
t_maa_bindings -->|"1:N"| t_maa_runs
t_studio_canvases -->|"1:N"| t_studio_canvas_revisions
t_studio_canvas_revisions -->|"0..1:N"| t_studio_canvas_revisions
t_studio_projects -->|"1:1"| t_studio_canvases
t_studio_projects -->|"1:N"| t_studio_conversations
t_studio_media_jobs -->|"1:N"| t_studio_credit_recovery_intents
t_studio_projects -->|"1:N"| t_studio_export_jobs
t_studio_media_requests -->|"1:1"| t_studio_media_jobs
t_studio_media_jobs -->|"1:N"| t_studio_media_outputs
t_studio_conversations -->|"1:N"| t_studio_media_requests
t_maa_runs -->|"0..1:N"| t_studio_media_requests
t_studio_media_jobs -->|"1:N"| t_studio_media_submission_attempts
t_studio_projects -->|"1:N"| t_studio_project_asset_refs
t_studio_video_documents -->|"1:N"| t_studio_timeline_revisions
t_studio_timeline_revisions -->|"0..1:N"| t_studio_timeline_revisions
t_studio_projects -->|"1:1"| t_studio_video_documents
t_studio_assets -.->|"1:N"| t_studio_project_asset_refs
t_studio_assets -.->|"1:N"| t_studio_media_outputs
t_studio_assets -.->|"1:N"| t_generation_deliveries
t_studio_media_model_versions -.->|"1:N"| t_studio_media_requests
t_studio_media_models -.->|"1:N"| t_studio_media_requests
t_studio_credit_authorizations -.->|"0..1:N"| t_studio_media_jobs
t_studio_credit_authorizations -.->|"0..1:N"| t_studio_credit_recovery_intents
t_studio_credit_authorizations <-.->|"N:M · 经 credit_authorization_allocations"| t_studio_credit_lots
t_studio_projects <-.->|"N:M · 经 project_asset_refs"| t_studio_assets
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_users,t_studio_sessions user
class t_studio_assets asset
class t_studio_credit_accounts,t_studio_credit_lots,t_studio_credit_authorizations,t_studio_credit_authorization_allocations,t_studio_credit_ledger_entries,t_studio_credit_plan_versions,t_studio_billing_cycles credit
class t_studio_payment_orders,t_studio_payment_events,t_studio_subscriptions pay
class t_studio_media_models,t_studio_media_model_versions model
class t_studio_projects,t_studio_conversations project
class t_studio_video_documents,t_studio_canvases,t_studio_canvas_revisions,t_studio_timeline_revisions,t_studio_export_jobs,t_studio_project_asset_refs canvas
class t_maa_bindings,t_maa_runs,t_maa_message_actions,t_maa_interactions,t_maa_interaction_actions,t_maa_model_change_actions,t_maa_run_stop_actions agent
class t_studio_media_requests,t_studio_media_jobs,t_studio_media_submission_attempts,t_studio_media_outputs,t_generation_jobs,t_generation_reservations,t_generation_deliveries,t_generation_development_budgets,t_studio_credit_recovery_intents media
class t_studio_credit_authorization_allocations,t_studio_project_asset_refs junction
style sg_i_user fill:none,stroke:#6b7280,stroke-width:1px,stroke-dasharray:5 4
style sg_i_asset fill:none,stroke:#06b6d4,stroke-width:1px,stroke-dasharray:5 4
style sg_i_credit fill:none,stroke:#eab308,stroke-width:1px,stroke-dasharray:5 4
style sg_i_pay fill:none,stroke:#ec4899,stroke-width:1px,stroke-dasharray:5 4
style sg_i_model fill:none,stroke:#6366f1,stroke-width:1px,stroke-dasharray:5 4
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_canvas fill:none,stroke:#3b82f6,stroke-width:1px
style sg_agent fill:#fff7ed,stroke:#f97316,stroke-width:4px
style sg_media fill:none,stroke:#22c55e,stroke-width:1px
linkStyle 30,31,32,33,34,35,36,37,38,48 stroke:#f97316,stroke-width:2.5px
linkStyle 54,55,56,57,58,59,60 stroke:#64748b,stroke-width:1.5px,stroke-dasharray:4 3
linkStyle 61,62 stroke:#dc2626,stroke-width:3px多对多(N:M)
数据库里没有“多对多”这种列,它总是靠一张关联表表达。下面这几张表的主键由两个外键组成,所以它们两端是多对多:
| 多对多的两端 | 关联表 | 关联表的主键 / 唯一键 |
|---|---|---|
studio_credit_authorizations ⇄ studio_credit_lots | studio_credit_authorization_allocations | owner_id, authorization_id, lot_id |
studio_projects ⇄ studio_assets | studio_project_asset_refs | project_id, asset_id |
Agent 交互相关(圈出来)
绑定 → Run → 消息 / 澄清卡 / 切换模型 / 停止,每个动作一张回执表;线上是“外键列 · 基数”。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":40,"rankSpacing":90}}}%%
flowchart LR
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_agent["⭕ Agent 交互"]
direction TB
t_maa_bindings["maa_bindings"]
t_maa_runs["maa_runs"]
t_maa_message_actions["maa_message_actions"]
t_maa_interactions["maa_interactions"]
t_maa_interaction_actions["maa_interaction_actions"]
t_maa_model_change_actions["maa_model_change_actions"]
t_maa_run_stop_actions["maa_run_stop_actions"]
end
t_studio_conversations -->|"conversation_id · 1:1"| t_maa_bindings
t_maa_model_change_actions -->|"pending_model_change_id · 0..1:1"| t_maa_bindings
t_maa_interactions -->|"interaction_id · 1:1"| t_maa_interaction_actions
t_maa_runs -->|"public_run_id · 1:N"| t_maa_interactions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_message_actions
t_maa_runs -->|"public_run_id · 0..1:N"| t_maa_message_actions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_model_change_actions
t_maa_runs -->|"public_run_id · 1:1"| t_maa_run_stop_actions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_runs
t_studio_projects -->|"project_id · 1:N"| t_studio_conversations
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_projects,t_studio_conversations project
class t_maa_bindings,t_maa_runs,t_maa_message_actions,t_maa_interactions,t_maa_interaction_actions,t_maa_model_change_actions,t_maa_run_stop_actions agent
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_agent fill:#fff7ed,stroke:#f97316,stroke-width:4px
linkStyle 0,1,2,3,4,5,6,7,8 stroke:#f97316,stroke-width:2.5px画布与时间轴
项目下是一份视频文档,画布、画布版本、时间线版本和导出都挂在这份文档上;素材放在共享身份库,项目只记引用,项目与素材是多对多,经 project_asset_refs。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":40,"rankSpacing":90}}}%%
flowchart LR
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_canvas["画布 · 时间轴 · 导出"]
direction TB
t_studio_video_documents["video_documents"]
t_studio_canvases["canvases"]
t_studio_canvas_revisions["canvas_revisions"]
t_studio_timeline_revisions["timeline_revisions"]
t_studio_export_jobs["export_jobs"]
t_studio_project_asset_refs["⇄ project_asset_refs"]
end
subgraph sg_asset["素材(共享身份库)"]
direction TB
t_studio_assets["assets"]
end
t_studio_canvases -->|"project_id · 1:N"| t_studio_canvas_revisions
t_studio_canvas_revisions -->|"restored_from_revision · 0..1:N"| t_studio_canvas_revisions
t_studio_projects -->|"project_id · 1:1"| t_studio_canvases
t_studio_projects -->|"project_id · 1:N"| t_studio_conversations
t_studio_projects -->|"project_id · 1:N"| t_studio_export_jobs
t_studio_projects -->|"project_id · 1:N"| t_studio_project_asset_refs
t_studio_video_documents -->|"project_id · 1:N"| t_studio_timeline_revisions
t_studio_timeline_revisions -->|"restored_from_revision · 0..1:N"| t_studio_timeline_revisions
t_studio_projects -->|"project_id · 1:1"| t_studio_video_documents
t_studio_assets -.->|"asset_id · 1:N"| t_studio_project_asset_refs
t_studio_projects <-.->|"N:M · 经 project_asset_refs"| t_studio_assets
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_projects,t_studio_conversations project
class t_studio_video_documents,t_studio_canvases,t_studio_canvas_revisions,t_studio_timeline_revisions,t_studio_export_jobs,t_studio_project_asset_refs canvas
class t_studio_assets asset
class t_studio_project_asset_refs junction
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_canvas fill:none,stroke:#3b82f6,stroke-width:1px
style sg_asset fill:none,stroke:#06b6d4,stroke-width:1px
linkStyle 9 stroke:#64748b,stroke-width:1.5px,stroke-dasharray:4 3
linkStyle 10 stroke:#dc2626,stroke-width:3px关系清单 逐条 61 条,含基数
| 父表 | 子表 | 外键列(子表里) | 基数 | 约束 | 域 |
|---|---|---|---|---|---|
generation_jobs | generation_deliveries | job_id | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_assets | generation_deliveries | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 生成 · 媒体 · 交付 |
studio_conversations | generation_deliveries | owner_id, project_id, session_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_projects | generation_deliveries | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
generation_development_budgets | generation_jobs | owner_id, budget_id | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_conversations | generation_jobs | owner_id, project_id, session_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_projects | generation_jobs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
generation_jobs | generation_reservations | job_id, budget_id, owner_id | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
maa_model_change_actions | maa_bindings | owner_id, project_id, conversation_id, id, pending_model_change_id | 0..1:1 一对一(父可选) | DB 外键 | Agent 交互 → Agent 交互 |
studio_conversations | maa_bindings | owner_id, project_id, conversation_id | 1:1 一对一 | DB 外键 | 项目与会话 → Agent 交互 |
maa_interactions | maa_interaction_actions | owner_id, project_id, conversation_id, binding_id, public_run_id, interaction_id | 1:1 一对一 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_interactions | owner_id, project_id, conversation_id, binding_id, public_run_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_message_actions | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_message_actions | owner_id, project_id, conversation_id, binding_id, public_run_id | 0..1:N 一对多(父可选) | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_model_change_actions | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_run_stop_actions | owner_id, project_id, conversation_id, binding_id, public_run_id | 1:1 一对一 | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_runs | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
studio_users | studio_assets | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 素材 |
studio_payment_orders | studio_billing_cycles | owner_id, payment_order_id, plan_version_id | 1:1 一对一 | DB 外键 | 支付与订阅 → 积分账本 |
studio_subscriptions | studio_billing_cycles | owner_id, subscription_id, provider_key, provider_account | 1:N 一对多 | DB 外键 | 支付与订阅 → 积分账本 |
studio_canvas_revisions | studio_canvas_revisions | owner_id, project_id, kind, restored_from_revision | 0..1:N 一对多(父可选) | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_canvases | studio_canvas_revisions | owner_id, project_id | 1:N 一对多 | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_projects | studio_canvases | owner_id, project_id | 1:1 一对一 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_projects | studio_conversations | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 项目与会话 |
studio_users | studio_credit_accounts | owner_id | 1:1 一对一 | DB 外键 | 用户与登录 → 积分账本 |
studio_credit_authorizations | studio_credit_authorization_allocations | owner_id, authorization_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_lots | studio_credit_authorization_allocations | owner_id, lot_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_accounts | studio_credit_authorizations | owner_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_authorization_allocations | studio_credit_ledger_entries | owner_id, authorization_id, lot_id | 0..1:N 一对多(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_authorizations | studio_credit_ledger_entries | owner_id, authorization_id | 0..1:N 一对多(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_lots | studio_credit_ledger_entries | owner_id, lot_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_billing_cycles | studio_credit_lots | owner_id, source_cycle_id | 0..1:1 一对一(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_accounts | studio_credit_lots | owner_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_payment_orders | studio_credit_lots | owner_id, source_order_id | 0..1:1 一对一(父可选) | DB 外键 | 支付与订阅 → 积分账本 |
studio_credit_authorizations | studio_credit_recovery_intents | authorization_id | 0..1:N 一对多(父可选) | 跨库(应用层检查) | 积分账本 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_credit_recovery_intents | owner_id, project_id, conversation_id, job_id, request_sha256 | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_projects | studio_export_jobs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_credit_authorizations | studio_media_jobs | credit_authorization_id | 0..1:N 一对多(父可选) | 跨库(应用层检查) | 积分账本 → 生成 · 媒体 · 交付 |
studio_media_requests | studio_media_jobs | owner_id, project_id, conversation_id, request_id, request_sha256, quote_sha256 | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_media_models | studio_media_model_versions | model_id | 1:N 一对多 | DB 外键 | 模型目录 → 模型目录 |
studio_media_model_versions | studio_media_models | id, published_version_id | 0..1:1 一对一(父可选) | DB 外键 | 模型目录 → 模型目录 |
studio_assets | studio_media_outputs | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_media_outputs | owner_id, project_id, conversation_id, job_id | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
maa_runs | studio_media_requests | owner_id, project_id, conversation_id, source_binding_id, source_run_id | 0..1:N 一对多(父可选) | DB 外键 | Agent 交互 → 生成 · 媒体 · 交付 |
studio_conversations | studio_media_requests | owner_id, project_id, conversation_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_media_model_versions | studio_media_requests | model_version_id | 1:N 一对多 | 跨库(应用层检查) | 模型目录 → 生成 · 媒体 · 交付 |
studio_media_models | studio_media_requests | model_id | 1:N 一对多 | 跨库(应用层检查) | 模型目录 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_media_submission_attempts | owner_id, project_id, conversation_id, job_id, request_sha256 | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_payment_orders | studio_payment_events | owner_id, order_id, provider_key, provider_account | 0..1:N 一对多(父可选) | DB 外键 | 支付与订阅 → 支付与订阅 |
studio_subscriptions | studio_payment_events | owner_id, subscription_id, provider_key, provider_account | 0..1:N 一对多(父可选) | DB 外键 | 支付与订阅 → 支付与订阅 |
studio_users | studio_payment_events | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_credit_plan_versions | studio_payment_orders | plan_version_id | 1:N 一对多 | DB 外键 | 积分账本 → 支付与订阅 |
studio_users | studio_payment_orders | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_assets | studio_project_asset_refs | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 画布 · 时间轴 · 导出 |
studio_projects | studio_project_asset_refs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_users | studio_sessions | user_id | 1:N 一对多 | DB 外键 | 用户与登录 → 用户与登录 |
studio_credit_plan_versions | studio_subscriptions | plan_version_id | 1:N 一对多 | DB 外键 | 积分账本 → 支付与订阅 |
studio_users | studio_subscriptions | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_timeline_revisions | studio_timeline_revisions | owner_id, project_id, kind, restored_from_revision | 0..1:N 一对多(父可选) | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_video_documents | studio_timeline_revisions | owner_id, project_id | 1:N 一对多 | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_projects | studio_video_documents | owner_id, project_id | 1:1 一对一 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
完整 ER:39 张表的全部列,带主键 / 外键与基数符号(鸦脚)
erDiagram
studio_assets {
CHAR id PK
CHAR owner_id FK
CHAR sha256
JSON metadata_json
VARCHAR storage_key
DATETIME created_at
VARCHAR publication_state
}
studio_billing_cycles {
CHAR id PK
CHAR owner_id FK
CHAR subscription_id FK
CHAR plan_version_id FK
CHAR payment_order_id FK
VARCHAR provider_key FK
VARCHAR provider_account FK
VARCHAR provider_invoice_id
DATETIME period_start
DATETIME period_end
BIGINT_UNSIGNED grant_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
VARCHAR state
CHAR paid_evidence_sha256
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_accounts {
CHAR owner_id PK
VARCHAR unit
VARCHAR status
BIGINT_UNSIGNED revision
DATETIME updated_at
}
studio_credit_authorization_allocations {
CHAR owner_id FK
CHAR authorization_id PK
CHAR lot_id PK
BIGINT_UNSIGNED allocated_credits
DATETIME created_at
}
studio_credit_authorizations {
CHAR id PK
CHAR owner_id FK
VARCHAR profile
CHAR project_id
CHAR conversation_id
CHAR job_id
CHAR request_id
CHAR request_sha256
CHAR quote_sha256
BIGINT_UNSIGNED credits
DATETIME expires_at
MEDIUMBLOB reservation_bytes
CHAR reservation_sha256
MEDIUMBLOB policy_bytes
CHAR policy_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_ledger_entries {
CHAR id PK
CHAR owner_id FK
CHAR lot_id FK
CHAR authorization_id FK
VARCHAR operation_key
VARCHAR kind
BIGINT grant_delta
BIGINT held_delta
BIGINT captured_delta
MEDIUMBLOB facts_bytes
CHAR facts_sha256
DATETIME created_at
}
studio_credit_lots {
CHAR id PK
CHAR owner_id FK
BIGINT_UNSIGNED grant_credits
BIGINT_UNSIGNED held_credits
BIGINT_UNSIGNED captured_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
CHAR source_order_id FK
CHAR source_cycle_id FK
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_plan_versions {
CHAR id PK
VARCHAR plan_key
VARCHAR version_key
VARCHAR kind
BIGINT_UNSIGNED price_minor
CHAR currency
BIGINT_UNSIGNED grant_credits
INT_UNSIGNED credit_validity_seconds
INT_UNSIGNED billing_interval_months
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
DATETIME published_at
DATETIME retired_at
}
studio_media_model_versions {
CHAR id PK
CHAR model_id FK
VARCHAR version_key
MEDIUMBLOB config_bytes
CHAR config_sha256
DATETIME published_at
}
studio_media_models {
CHAR id PK
VARCHAR model_key
VARCHAR kind
VARCHAR display_name
VARCHAR status
CHAR published_version_id FK
BIGINT_UNSIGNED revision
DATETIME updated_at
}
studio_payment_events {
CHAR id PK
CHAR owner_id FK
VARCHAR provider_key FK
VARCHAR provider_account FK
VARCHAR provider_event_id
CHAR order_id FK
CHAR subscription_id FK
MEDIUMBLOB body_bytes
CHAR body_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_payment_orders {
CHAR id PK
CHAR owner_id FK
CHAR client_action_id
CHAR plan_version_id FK
BIGINT_UNSIGNED price_minor
CHAR currency
BIGINT_UNSIGNED grant_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
VARCHAR provider_key
VARCHAR provider_account
VARCHAR provider_idempotency_key
VARCHAR provider_order_id
VARCHAR state
CHAR paid_evidence_sha256
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_sessions {
CHAR token_hash PK
CHAR user_id FK
DATETIME created_at
DATETIME expires_at
DATETIME revoked_at
}
studio_subscriptions {
CHAR id PK
CHAR owner_id FK
VARCHAR provider_key
VARCHAR provider_account
VARCHAR provider_subscription_id
CHAR plan_version_id FK
VARCHAR state
DATETIME period_start
DATETIME period_end
TINYINT cancel_at_period_end
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_users {
CHAR id PK
VARCHAR email
VARBINARY password_hash
TINYINT enabled
DATETIME created_at
}
generation_deliveries {
CHAR job_id PK
CHAR owner_id FK
CHAR project_id FK
CHAR session_id FK
CHAR asset_id FK
CHAR request_sha256
CHAR maa_source_sha256
CHAR provider_source_sha256
VARCHAR model
VARCHAR tool_name
CHAR input_sha256
JSON metadata_json
DATETIME created_at
}
generation_development_budgets {
CHAR id PK
CHAR owner_id
VARCHAR policy_version
BIGINT_UNSIGNED credits_limit
BIGINT_UNSIGNED credits_reserved
INT_UNSIGNED calls_limit
INT_UNSIGNED calls_reserved
DATETIME expires_at
}
generation_jobs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR session_id FK
CHAR native_conversation_id
CHAR native_run_id
CHAR source_sha256
CHAR budget_id FK
MEDIUMBLOB request_bytes
CHAR request_sha256
BIGINT_UNSIGNED credits
DATETIME expires_at
VARCHAR status
INT_UNSIGNED attempts
MEDIUMBLOB result_bytes
DATETIME updated_at
}
generation_reservations {
CHAR job_id PK
CHAR budget_id FK
CHAR owner_id FK
BIGINT_UNSIGNED credits
INT_UNSIGNED calls
VARCHAR status
}
maa_bindings {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR provider
VARCHAR model_name
VARCHAR status
VARCHAR native_cid
DATETIME created_at
BIGINT_UNSIGNED model_revision
CHAR pending_model_change_id FK
}
maa_interaction_actions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR interaction_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_iid
CHAR client_action_id
CHAR card_sha256
CHAR request_sha256
CHAR content_sha256
VARCHAR response_action
JSON values_payload
VARCHAR status
DATETIME created_at
}
maa_interactions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_iid
CHAR card_sha256
JSON card_payload
DATETIME created_at
}
maa_message_actions {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR client_action_id
CHAR request_sha256
MEDIUMTEXT content
VARCHAR status
CHAR public_run_id FK
CHAR proposed_run_id
DATETIME created_at
}
maa_model_change_actions {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_cid
CHAR client_action_id
CHAR request_sha256
CHAR native_request_sha256
BIGINT_UNSIGNED expected_revision
VARCHAR from_provider
VARCHAR from_model_name
VARCHAR target_provider
VARCHAR target_model_name
VARCHAR status
BIGINT_UNSIGNED dispatch_attempt
JSON receipt_payload
DATETIME created_at
DATETIME updated_at
}
maa_run_stop_actions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_cid
VARCHAR native_rid
CHAR client_action_id
CHAR request_sha256
VARCHAR stop_action
VARCHAR status
BIGINT_UNSIGNED attempt
VARCHAR terminal_run_status
DATETIME created_at
DATETIME updated_at
}
maa_runs {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_rid
VARCHAR status
DATETIME created_at
CHAR native_assistant_sha256
CHAR public_assistant_sha256
BIGINT_UNSIGNED native_assistant_bytes
BIGINT_UNSIGNED assistant_event_seq
BIGINT_UNSIGNED last_event_seq
}
studio_canvas_revisions {
CHAR owner_id PK
CHAR project_id PK
VARCHAR kind PK
BIGINT_UNSIGNED revision PK
MEDIUMBLOB state_bytes
CHAR state_sha256
VARCHAR origin
BIGINT_UNSIGNED restored_from_revision FK
DATETIME recorded_at
}
studio_canvases {
CHAR project_id PK
CHAR owner_id FK
BIGINT_UNSIGNED revision
JSON state_json
DATETIME updated_at
}
studio_conversations {
CHAR id PK
CHAR project_id FK
CHAR owner_id FK
VARCHAR title
DATETIME created_at
}
studio_credit_recovery_intents {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
CHAR request_sha256 FK
CHAR quote_sha256
VARCHAR kind
CHAR authorization_id FK
MEDIUMBLOB intent_bytes
CHAR intent_sha256
VARCHAR state
CHAR lease_token_sha256
DATETIME lease_until
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_export_jobs {
CHAR id PK
CHAR project_id FK
CHAR owner_id FK
BIGINT_UNSIGNED document_revision
CHAR input_hash
VARCHAR status
JSON input_json
JSON output_json
VARCHAR error_code
CHAR lease_token_hash
DATETIME lease_until
INT_UNSIGNED attempts
DATETIME created_at
DATETIME updated_at
}
studio_media_jobs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR request_id FK
CHAR request_sha256 FK
CHAR quote_sha256 FK
CHAR client_approval_id
CHAR approval_sha256
CHAR credit_authorization_id FK
VARCHAR authorization_mode
DATETIME authorization_expires_at
VARCHAR status
BIGINT_UNSIGNED revision
CHAR lease_token_sha256
DATETIME lease_until
VARCHAR provider_task_id
CHAR client_cancel_id
CHAR cancel_request_sha256
DATETIME cancel_requested_at
CHAR staged_asset_id
CHAR staged_asset_sha256
DATETIME created_at
DATETIME updated_at
}
studio_media_outputs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
INT_UNSIGNED ordinal
CHAR asset_id FK
CHAR asset_sha256
CHAR asset_metadata_sha256
CHAR provider_result_sha256
DATETIME created_at
}
studio_media_requests {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR client_request_id
CHAR model_id FK
CHAR model_version_id FK
CHAR model_config_sha256
MEDIUMBLOB request_bytes
CHAR request_sha256
MEDIUMBLOB quote_bytes
CHAR quote_sha256
BIGINT_UNSIGNED quoted_credits
DATETIME expires_at
VARCHAR origin
CHAR source_binding_id FK
CHAR source_run_id FK
CHAR source_assistant_sha256
MEDIUMBLOB source_snapshot_bytes
DATETIME created_at
}
studio_media_submission_attempts {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
INT_UNSIGNED attempt_no
CHAR request_sha256 FK
VARCHAR provider_idempotency_key
VARCHAR stage
DATETIME dispatch_started_at
VARCHAR provider_task_id
CHAR receipt_sha256
CHAR terminal_receipt_sha256
CHAR reconciliation_sha256
DATETIME created_at
DATETIME updated_at
}
studio_project_asset_refs {
CHAR project_id PK
CHAR owner_id FK
CHAR asset_id PK
CHAR asset_sha256
CHAR asset_metadata_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
DATETIME detached_at
}
studio_projects {
CHAR id PK
CHAR owner_id
VARCHAR title
DATETIME created_at
}
studio_timeline_revisions {
CHAR owner_id PK
CHAR project_id PK
VARCHAR kind PK
BIGINT_UNSIGNED revision PK
MEDIUMBLOB state_bytes
CHAR state_sha256
VARCHAR origin
BIGINT_UNSIGNED restored_from_revision FK
DATETIME recorded_at
}
studio_video_documents {
CHAR project_id PK
CHAR owner_id FK
BIGINT_UNSIGNED revision
JSON state_json
DATETIME updated_at
}
studio_users ||--o{ studio_assets : "owner_id"
studio_payment_orders ||--o| studio_billing_cycles : "plan_version_id"
studio_subscriptions ||--o{ studio_billing_cycles : "provider_account"
studio_users ||--o| studio_credit_accounts : "owner_id"
studio_credit_authorizations ||--o{ studio_credit_authorization_allocations : "authorization_id"
studio_credit_lots ||--o{ studio_credit_authorization_allocations : "lot_id"
studio_credit_accounts ||--o{ studio_credit_authorizations : "owner_id"
studio_credit_authorization_allocations |o--o{ studio_credit_ledger_entries : "lot_id"
studio_credit_authorizations |o--o{ studio_credit_ledger_entries : "authorization_id"
studio_credit_lots ||--o{ studio_credit_ledger_entries : "lot_id"
studio_credit_accounts ||--o{ studio_credit_lots : "owner_id"
studio_billing_cycles |o--o| studio_credit_lots : "source_cycle_id"
studio_payment_orders |o--o| studio_credit_lots : "source_order_id"
studio_media_models ||--o{ studio_media_model_versions : "model_id"
studio_media_model_versions |o--o| studio_media_models : "published_version_id"
studio_payment_orders |o--o{ studio_payment_events : "provider_account"
studio_subscriptions |o--o{ studio_payment_events : "provider_account"
studio_users ||--o{ studio_payment_events : "owner_id"
studio_credit_plan_versions ||--o{ studio_payment_orders : "plan_version_id"
studio_users ||--o{ studio_payment_orders : "owner_id"
studio_users ||--o{ studio_sessions : "user_id"
studio_credit_plan_versions ||--o{ studio_subscriptions : "plan_version_id"
studio_users ||--o{ studio_subscriptions : "owner_id"
generation_jobs ||--o| generation_deliveries : "job_id"
studio_projects ||--o{ generation_deliveries : "project_id"
studio_conversations ||--o{ generation_deliveries : "session_id"
generation_development_budgets ||--o{ generation_jobs : "budget_id"
studio_projects ||--o{ generation_jobs : "project_id"
studio_conversations ||--o{ generation_jobs : "session_id"
generation_jobs ||--o| generation_reservations : "budget_id"
studio_conversations ||--o| maa_bindings : "conversation_id"
maa_model_change_actions |o--o| maa_bindings : "pending_model_change_id"
maa_interactions ||--o| maa_interaction_actions : "interaction_id"
maa_runs ||--o{ maa_interactions : "public_run_id"
maa_bindings ||--o{ maa_message_actions : "binding_id"
maa_runs |o--o{ maa_message_actions : "public_run_id"
maa_bindings ||--o{ maa_model_change_actions : "binding_id"
maa_runs ||--o| maa_run_stop_actions : "public_run_id"
maa_bindings ||--o{ maa_runs : "binding_id"
studio_canvases ||--o{ studio_canvas_revisions : "project_id"
studio_canvas_revisions |o--o{ studio_canvas_revisions : "restored_from_revision"
studio_projects ||--o| studio_canvases : "project_id"
studio_projects ||--o{ studio_conversations : "project_id"
studio_media_jobs ||--o{ studio_credit_recovery_intents : "job_id"
studio_projects ||--o{ studio_export_jobs : "project_id"
studio_media_requests ||--o| studio_media_jobs : "request_id"
studio_media_jobs ||--o{ studio_media_outputs : "job_id"
studio_conversations ||--o{ studio_media_requests : "conversation_id"
maa_runs |o--o{ studio_media_requests : "source_run_id"
studio_media_jobs ||--o{ studio_media_submission_attempts : "job_id"
studio_projects ||--o{ studio_project_asset_refs : "project_id"
studio_video_documents ||--o{ studio_timeline_revisions : "project_id"
studio_timeline_revisions |o--o{ studio_timeline_revisions : "restored_from_revision"
studio_projects ||--o| studio_video_documents : "project_id"
studio_assets ||--o{ studio_project_asset_refs : "asset_id"
studio_assets ||--o{ studio_media_outputs : "asset_id"
studio_assets ||--o{ generation_deliveries : "asset_id"
studio_media_model_versions ||--o{ studio_media_requests : "model_version_id"
studio_media_models ||--o{ studio_media_requests : "model_id"
studio_credit_authorizations |o--o{ studio_media_jobs : "credit_authorization_id"
studio_credit_authorizations |o--o{ studio_credit_recovery_intents : "authorization_id"自动生成的整体图(按真实表结构,备查)
共享身份库 ER 图
实测验证与设计原因 七个品牌相同,展开查看
实测验证(本机 MySQL 实库)
对照本机真实运行的数据库 studio_profile_creatok 和 studio_platform_identity,逐项核对本页的表、列、关系与说明。18 / 18 项通过。
查看全部核对项
| 核对项 | 结果 |
|---|---|
| 表数 = 发布值 24 | 通过 |
| 列数 = 289 | 通过 |
| 外键数 = 34 | 通过 |
| 检查约束数 = 66 | 通过 |
| 触发器数 = 22 | 通过 |
| 索引数(含主键) = 85 | 通过 |
| 列定义与 pollo 逐列一致 | 通过 |
| 外键与 pollo 完全一致 | 通过 |
| 索引与 pollo 一致 | 通过 |
| 触发器与 pollo 一致 | 通过 |
| 外键 CSV 行数 = 实库外键数 | 通过 |
| mmd 实体 = 实库表 | 通过 |
| svg 标题 24 tables / 34 actual foreign keys = 实库 | 通过 |
| 参考 SQL 表集合与列顺序 = 实库 | 通过 |
| 15 张表 | 通过 |
| 外键 CSV 行数 = 实库外键数 | 通过 |
| svg 标题与实库一致 | 通过 |
| 参考 SQL 表集合与列顺序 = 实库 | 通过 |
实库里的关系是这样的
- 34 个外键里 31 个是复合外键,且都带着 owner_id,其余 3 个是单列外键;22 张子表都带 owner 外键。所以一行数据不可能指向别的用户的项目或会话。
- 删除与更新规则全部是 RESTRICT / NO ACTION,没有任何级联:被引用的行不能被删除。
- 品牌库与共享身份库之间的关系(owner_id、asset_id、model_id + model_version_id)没有数据库外键,靠应用层检查;我们逐表核对了现有数据,没有孤儿。
主动破坏测试(在事务里尝试,全部回滚)
| 尝试 | 数据库的反应 |
|---|---|
| 外键:导出任务.project_id 改成不存在的项目被拒绝 | 拒绝 |
| 复合外键:项目素材引用.project_id 改成别的用户的项目被拒绝(owner 与 project 必须成对) | 拒绝 |
| 触发器:已提交的消息动作不可改写 | 拒绝 |
| 触发器:媒体产出不可改写 | 拒绝 |
| 外键 RESTRICT:被会话引用的项目不能删除 | 拒绝 |
| 复合外键:被引用的会话不能把 owner 改成别人 | 拒绝 |
| 检查约束:Run 状态只能是约定的六个值 | 拒绝 |
| 触发器:账本分录不可修改 | 拒绝 |
| 触发器:账本分录不可删除 | 拒绝 |
CreaTok · 表结构
MySQL 8,字符集 utf8mb4,ID 为 char(36) ascii_bin。点击展开 DDL。
按职责分组
项目与会话 2 张
studio_projects:用户拥有的创作项目studio_conversations:项目内的对话会话
Agent执行与并发控制 7 张
maa_bindings:业务会话与Native Maa会话映射、模型版本与未决操作maa_runs:公开Run映射、状态与原生/公开助手证据摘要maa_message_actions:原消息动作及幂等回执maa_interactions:澄清卡片及Run归属maa_interaction_actions:原卡片回答/取消动作maa_model_change_actions:带预期模型版本的切换动作maa_run_stop_actions:停止原Run的幂等动作与观测终态
画布、时间轴与素材引用 5 张
studio_canvases:项目当前画布文档studio_canvas_revisions:历史画布修订studio_video_documents:项目当前时间轴文档studio_timeline_revisions:历史时间轴修订studio_project_asset_refs:项目对用户级素材的引用;不复制素材所有权
媒体生成、结算恢复与导出 6 张
studio_media_requests:用户输入/Agent来源、报价、批准摘要与准入确认studio_media_jobs:已批准媒体任务及状态机studio_media_submission_attempts:一次提交的任务证据与不确定结果studio_media_outputs:受验证的输出与素材映射studio_credit_recovery_intents:积分结算恢复意图;不是用户钱包全账本studio_export_jobs:时间轴导出队列和发布输出
既有generation兼容路径 22 张
generation_jobs:既有generation任务,不等同新PublicMedia任务generation_reservations:既有任务费用预留generation_development_budgets:既有开发测试预算generation_deliveries:既有生成交付回执owner_id:归属用户;不是允许跨用户查询的参数。model_revision:并发准入版本;数据库默认0不能代替Native权威读回。pending_model_change_id:未决模型切换引用,阻止其他writer绕过。studio_users:用户账号记录;不导出密码哈希或任何业务行studio_sessions:登录会话;这里只公开字段结构,不公开会话值studio_assets:用户级素材元数据与存储键结构,项目仅引用素材IDstudio_media_models:公开媒体模型目录结构studio_media_model_versions:媒体模型不可变版本/计价能力结构studio_subscriptions:订阅状态持久化studio_billing_cycles:订阅账期studio_payment_orders:订单记录studio_payment_events:支付事件幂等记录;不代表已有公开支付路由studio_credit_accounts:用户积分账户studio_credit_lots:积分批次studio_credit_authorizations:费用预留与结算授权studio_credit_authorization_allocations:授权对批次的分配studio_credit_ledger_entries:积分流水studio_credit_plan_versions:积分方案不可变版本
品牌库 studio_profile_creatok(24 张)
generation_deliveries 既有生成交付回执
CREATE TABLE `generation_deliveries` ( `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `session_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `maa_source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `tool_name` varchar(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `input_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `metadata_json` json NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`job_id`), KEY `generation_delivery_owner_project` (`owner_id`,`project_id`,`session_id`,`job_id`), KEY `generation_delivery_owned_asset` (`owner_id`,`asset_id`), KEY `generation_delivery_session_fk` (`session_id`), CONSTRAINT `generation_delivery_job_fk` FOREIGN KEY (`job_id`) REFERENCES `generation_jobs` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`, `job_id`) REFERENCES `generation_jobs` (`owner_id`, `project_id`, `session_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_session_fk` FOREIGN KEY (`session_id`) REFERENCES `studio_conversations` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_model_tool` CHECK ((((`model` = _ascii'seedance-2.0') and (`tool_name` = _ascii'seedance2_video_generator')) or ((`model` in (_ascii'minimax-h3',_ascii'seedance-2.5')) and (`tool_name` = _ascii'insai_video_generate')))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_development_budgets 既有开发测试预算
CREATE TABLE `generation_development_budgets` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `policy_version` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits_limit` bigint unsigned NOT NULL, `credits_reserved` bigint unsigned NOT NULL DEFAULT '0', `calls_limit` int unsigned NOT NULL, `calls_reserved` int unsigned NOT NULL DEFAULT '0', `expires_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `generation_budget_owner` (`owner_id`,`id`), CONSTRAINT `generation_budget_limits` CHECK (((`credits_limit` between 1 and 1000000000) and (`credits_reserved` <= `credits_limit`) and (`calls_limit` between 1 and 100) and (`calls_reserved` <= `calls_limit`))), CONSTRAINT `generation_budget_policy` CHECK ((`policy_version` = _latin1'operator-test/v1')) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_jobs 既有generation任务,不等同新PublicMedia任务
CREATE TABLE `generation_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `session_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_conversation_id` char(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_run_id` char(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `budget_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_bytes` mediumblob NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits` bigint unsigned NOT NULL, `expires_at` datetime(6) NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempts` int unsigned NOT NULL DEFAULT '0', `result_bytes` mediumblob, `updated_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `generation_job_budget_owner` (`id`,`budget_id`,`owner_id`), UNIQUE KEY `generation_job_owned_scope` (`owner_id`,`project_id`,`session_id`,`id`), KEY `generation_job_owner` (`owner_id`,`project_id`,`session_id`), KEY `generation_job_session` (`session_id`), KEY `generation_job_budget` (`owner_id`,`budget_id`), CONSTRAINT `generation_job_budget` FOREIGN KEY (`owner_id`, `budget_id`) REFERENCES `generation_development_budgets` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_owned_project` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_owned_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_session` FOREIGN KEY (`session_id`) REFERENCES `studio_conversations` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_attempt` CHECK ((((`status` = _ascii'APPROVED') and (`attempts` = 0) and (`result_bytes` is null)) or ((`status` = _ascii'SUBMITTING') and (`attempts` = 1) and (`result_bytes` is null)) or ((`status` in (_ascii'SUCCEEDED',_ascii'FAILED',_ascii'UNKNOWN')) and (`attempts` = 1) and (`result_bytes` is not null)))), CONSTRAINT `generation_job_credit` CHECK ((`credits` between 1 and 1000000000)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_reservations 既有任务费用预留
CREATE TABLE `generation_reservations` ( `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `budget_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits` bigint unsigned NOT NULL, `calls` int unsigned NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, PRIMARY KEY (`job_id`), KEY `generation_reservation_job` (`job_id`,`budget_id`,`owner_id`), CONSTRAINT `generation_reservation_job` FOREIGN KEY (`job_id`, `budget_id`, `owner_id`) REFERENCES `generation_jobs` (`id`, `budget_id`, `owner_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_reservation_fixed` CHECK (((`credits` between 1 and 1000000000) and (`calls` = 1) and (`status` = _latin1'HELD'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_bindings 业务会话与Native Maa会话映射、模型版本与未决操作
CREATE TABLE `maa_bindings` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `model_revision` bigint unsigned NOT NULL DEFAULT '0', `pending_model_change_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_binding_business_scope` (`owner_id`,`project_id`,`conversation_id`), UNIQUE KEY `maa_binding_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `maa_binding_native_identity` (`native_cid`), KEY `maa_model_change_pending_fk` (`owner_id`,`project_id`,`conversation_id`,`id`,`pending_model_change_id`), CONSTRAINT `maa_binding_owned_conversation_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_model_change_pending_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `id`, `pending_model_change_id`) REFERENCES `maa_model_change_actions` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_binding_receipt` CHECK ((((`status` = _ascii'dispatching') and (`native_cid` is null)) or ((`status` = _ascii'bound') and (`native_cid` is not null)))), CONSTRAINT `maa_model_binding_revision` CHECK ((`model_revision` <= 9007199254740991)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_interaction_actions 原卡片回答/取消动作
CREATE TABLE `maa_interaction_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `interaction_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_iid` varchar(124) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `content_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `response_action` varchar(8) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `values_payload` json NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_interaction_action_business_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_interaction_action_one_card` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`interaction_id`), CONSTRAINT `maa_interaction_action_owned_card_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`, `interaction_id`) REFERENCES `maa_interactions` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_interaction_action_kind` CHECK ((`response_action` in (_latin1'submit',_latin1'cancel'))), CONSTRAINT `maa_interaction_action_status` CHECK ((`status` in (_latin1'dispatching',_latin1'accepted'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_interactions 澄清卡片及Run归属
CREATE TABLE `maa_interactions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_iid` varchar(124) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_payload` json NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_interaction_native_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`native_iid`), UNIQUE KEY `maa_interaction_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`id`), CONSTRAINT `maa_interaction_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_message_actions 原消息动作及幂等回执
CREATE TABLE `maa_message_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `content` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `proposed_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_action_business_identity` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), KEY `maa_action_owned_run_fk` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`), CONSTRAINT `maa_action_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_action_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_action_receipt` CHECK ((((`status` = _latin1'dispatching') and (`public_run_id` is null)) or ((`status` = _latin1'accepted') and (`public_run_id` is not null)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_model_change_actions 带预期模型版本的切换动作
CREATE TABLE `maa_model_change_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `expected_revision` bigint unsigned NOT NULL, `from_provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `from_model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `target_provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `target_model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `dispatch_attempt` bigint unsigned NOT NULL, `receipt_payload` json DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_model_change_owned_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_model_change_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`id`), CONSTRAINT `maa_model_change_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_model_change_attempt` CHECK ((`dispatch_attempt` between 1 and 9007199254740991)), CONSTRAINT `maa_model_change_expected` CHECK ((`expected_revision` <= 9007199254740990)), CONSTRAINT `maa_model_change_status` CHECK ((((cast(`status` as char charset binary) = _latin1'dispatching') and (`receipt_payload` is null)) or ((cast(`status` as char charset binary) in (_latin1'accepted',_latin1'rejected')) and (`receipt_payload` is not null) and (json_type(`receipt_payload`) = _latin1'OBJECT')))), CONSTRAINT `maa_model_change_time` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_run_stop_actions 停止原Run的幂等动作与观测终态
CREATE TABLE `maa_run_stop_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_rid` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `stop_action` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempt` bigint unsigned NOT NULL, `terminal_run_status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_stop_owned_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_stop_one_run` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`), CONSTRAINT `maa_stop_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_stop_action` CHECK ((`stop_action` = _latin1'interrupt')), CONSTRAINT `maa_stop_attempt` CHECK ((`attempt` between 1 and 9007199254740991)), CONSTRAINT `maa_stop_state` CHECK ((((`status` = _latin1'unknown') and (`terminal_run_status` is null)) or ((`status` = _latin1'terminal_observed') and (`terminal_run_status` is not null) and (`terminal_run_status` in (_latin1'completed',_latin1'failed',_latin1'cancelled'))))), CONSTRAINT `maa_stop_time` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_runs 公开Run映射、状态与原生/公开助手证据摘要
CREATE TABLE `maa_runs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_rid` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, `native_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `public_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `native_assistant_bytes` bigint unsigned NOT NULL DEFAULT '0', `assistant_event_seq` bigint unsigned NOT NULL DEFAULT '0', `last_event_seq` bigint unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `maa_run_native_identity` (`native_rid`), UNIQUE KEY `maa_run_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`id`), KEY `maa_run_owned_list` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), CONSTRAINT `maa_run_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_run_source_evidence` CHECK ((((`native_assistant_sha256` is null) and (`public_assistant_sha256` is null) and (`native_assistant_bytes` = 0) and (`assistant_event_seq` = 0)) or ((`native_assistant_sha256` is not null) and (`public_assistant_sha256` is not null) and (`native_assistant_bytes` > 0) and (`assistant_event_seq` > 0) and (`assistant_event_seq` <= `last_event_seq`)))), CONSTRAINT `maa_run_status` CHECK ((`status` in (_latin1'queued',_latin1'running',_latin1'waiting_interaction',_latin1'completed',_latin1'failed',_latin1'cancelled'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_canvas_revisions 历史画布修订
CREATE TABLE `studio_canvas_revisions` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_bytes` mediumblob NOT NULL, `state_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `restored_from_revision` bigint unsigned DEFAULT NULL, `recorded_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`,`project_id`,`kind`,`revision`), KEY `studio_canvas_revision_source_fk` (`owner_id`,`project_id`,`kind`,`restored_from_revision`), CONSTRAINT `studio_canvas_revision_head_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_canvases` (`owner_id`, `project_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_canvas_revision_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `kind`, `restored_from_revision`) REFERENCES `studio_canvas_revisions` (`owner_id`, `project_id`, `kind`, `revision`), CONSTRAINT `studio_canvas_revision_bytes` CHECK ((length(`state_bytes`) between 1 and 262144)), CONSTRAINT `studio_canvas_revision_kind` CHECK ((`kind` = _latin1'canvas')), CONSTRAINT `studio_canvas_revision_number` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_canvas_revision_origin` CHECK ((((`origin` in (_latin1'saved',_latin1'backfill')) and (`restored_from_revision` is null)) or ((`origin` = _latin1'restored') and (`restored_from_revision` is not null) and (`restored_from_revision` between 1 and (`revision` - 1))))), CONSTRAINT `studio_canvas_revision_sha` CHECK ((`state_sha256` = lower(sha2(`state_bytes`,256)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_canvases 项目当前画布文档
CREATE TABLE `studio_canvases` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_json` json NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`project_id`), UNIQUE KEY `studio_canvas_owned_head` (`owner_id`,`project_id`), CONSTRAINT `studio_canvas_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_canvas_revision` CHECK ((`revision` between 1 and 2147483647)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_conversations 项目内的对话会话
CREATE TABLE `studio_conversations` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `title` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_conversation_owned_scope` (`owner_id`,`project_id`,`id`), KEY `studio_conversation_list` (`owner_id`,`project_id`,`created_at`,`id`), CONSTRAINT `studio_conversation_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_recovery_intents 积分结算恢复意图;不是用户钱包全账本
CREATE TABLE `studio_credit_recovery_intents` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`kind` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`intent_bytes` mediumblob NOT NULL,
`intent_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`lease_token_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`lease_until` datetime(6) DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_intent_job_kind` (`job_id`,`kind`),
KEY `credit_intent_recovery` (`state`,`updated_at`,`id`),
KEY `credit_intent_owned_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`,`request_sha256`),
CONSTRAINT `credit_intent_owned_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`, `request_sha256`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`),
CONSTRAINT `credit_intent_hashes` CHECK ((regexp_like(`request_sha256`,_latin1'^[a-f0-9]{64}$') and regexp_like(`quote_sha256`,_latin1'^[a-f0-9]{64}$'))),
CONSTRAINT `credit_intent_kind` CHECK (((`kind` in (_latin1'RESERVE_BIND',_latin1'CAPTURE',_latin1'RELEASE')) and (((`kind` = _latin1'RESERVE_BIND') and (`authorization_id` is null)) or ((`kind` in (_latin1'CAPTURE',_latin1'RELEASE')) and (`authorization_id` is not null))))),
CONSTRAINT `credit_intent_lease` CHECK ((((`state` = _latin1'leased') and (`lease_token_sha256` is not null) and regexp_like(`lease_token_sha256`,_latin1'^[a-f0-9]{64}$') and (`lease_until` is not null) and (`lease_until` > `updated_at`) and (`lease_until` <= (`updated_at` + interval 15 minute))) or ((`state` <> _latin1'leased') and (`lease_token_sha256` is null) and (`lease_until` is null)))),
CONSTRAINT `credit_intent_payload_sha` CHECK ((`intent_sha256` = lower(sha2(`intent_bytes`,256)))),
CONSTRAINT `credit_intent_payload_size` CHECK ((length(`intent_bytes`) between 1 and 65536)),
CONSTRAINT `credit_intent_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `credit_intent_state` CHECK ((`state` in (_latin1'pending',_latin1'leased',_latin1'confirmed',_latin1'unknown'))),
CONSTRAINT `credit_intent_times` CHECK ((`updated_at` >= `created_at`))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_export_jobs 时间轴导出队列和发布输出
CREATE TABLE `studio_export_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `document_revision` bigint unsigned NOT NULL, `input_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `input_json` json NOT NULL, `output_json` json DEFAULT NULL, `error_code` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT '', `lease_token_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `lease_until` datetime(6) DEFAULT NULL, `attempts` int unsigned NOT NULL DEFAULT '0', `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_export_input` (`project_id`,`document_revision`,`input_hash`), KEY `studio_export_claim` (`status`,`created_at`,`id`), KEY `studio_export_owner_list` (`owner_id`,`project_id`,`created_at`,`id`), KEY `studio_export_expiry` (`status`,`lease_until`), CONSTRAINT `studio_export_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_export_lease` CHECK ((((`status` = _latin1'running') and (`lease_token_hash` is not null) and (`lease_until` is not null)) or ((`status` <> _latin1'running') and (`lease_token_hash` is null) and (`lease_until` is null)))), CONSTRAINT `studio_export_output` CHECK ((((`status` = _latin1'succeeded') and (`output_json` is not null) and (`error_code` = _latin1'')) or ((`status` in (_latin1'queued',_latin1'running')) and (`output_json` is null) and (`error_code` = _latin1'')) or ((`status` in (_latin1'failed',_latin1'unknown')) and (`output_json` is null) and (`error_code` <> _latin1'')))), CONSTRAINT `studio_export_revision` CHECK ((`document_revision` between 1 and 2147483647)), CONSTRAINT `studio_export_status` CHECK ((`status` in (_latin1'queued',_latin1'running',_latin1'succeeded',_latin1'failed',_latin1'unknown'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_jobs 已批准媒体任务及状态机
CREATE TABLE `studio_media_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_approval_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `approval_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credit_authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `authorization_mode` varchar(24) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `authorization_expires_at` datetime(6) DEFAULT NULL, `status` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `lease_token_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `lease_until` datetime(6) DEFAULT NULL, `provider_task_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `client_cancel_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `cancel_request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `cancel_requested_at` datetime(6) DEFAULT NULL, `staged_asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `staged_asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_job_request` (`request_id`), UNIQUE KEY `studio_media_job_client` (`owner_id`,`client_approval_id`), UNIQUE KEY `studio_media_job_owned` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `studio_media_job_owned_request` (`owner_id`,`project_id`,`conversation_id`,`id`,`request_sha256`), KEY `studio_media_job_page` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), KEY `studio_media_job_queue` (`status`,`updated_at`,`id`), KEY `studio_media_job_request_fk` (`owner_id`,`project_id`,`conversation_id`,`request_id`,`request_sha256`,`quote_sha256`), CONSTRAINT `studio_media_job_request_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `request_id`, `request_sha256`, `quote_sha256`) REFERENCES `studio_media_requests` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`, `quote_sha256`), CONSTRAINT `studio_media_job_authorization` CHECK ((((`credit_authorization_id` is null) and (`authorization_mode` is null) and (`authorization_expires_at` is null) and (`status` in (_latin1'approval_pending',_latin1'cancelled'))) or ((`credit_authorization_id` is not null) and (`authorization_mode` is not null) and (`authorization_mode` in (_latin1'commercial',_latin1'test_allowance')) and (`authorization_expires_at` is not null) and (`authorization_expires_at` > `created_at`) and (`status` <> _latin1'approval_pending')))), CONSTRAINT `studio_media_job_cancel` CHECK ((((`client_cancel_id` is null) and (`cancel_request_sha256` is null) and (`cancel_requested_at` is null)) or ((`client_cancel_id` is not null) and (`cancel_request_sha256` is not null) and (`cancel_requested_at` is not null) and (`cancel_requested_at` between `created_at` and `updated_at`)))), CONSTRAINT `studio_media_job_lease` CHECK ((((`status` in (_latin1'leased',_latin1'submitting')) and (`lease_token_sha256` is not null) and (`lease_until` is not null) and (`lease_until` > `updated_at`) and (`lease_until` <= (`updated_at` + interval 15 minute))) or ((`status` not in (_latin1'leased',_latin1'submitting')) and (`lease_token_sha256` is null) and (`lease_until` is null)))), CONSTRAINT `studio_media_job_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_media_job_staged` CHECK ((((`staged_asset_id` is null) and (`staged_asset_sha256` is null)) or ((`staged_asset_id` is not null) and (`staged_asset_sha256` is not null)))), CONSTRAINT `studio_media_job_status` CHECK ((`status` in (_latin1'approval_pending',_latin1'queued',_latin1'leased',_latin1'submitting',_latin1'running',_latin1'submission_unknown',_latin1'succeeded',_latin1'failed',_latin1'cancelled'))), CONSTRAINT `studio_media_job_task` CHECK (((`status` not in (_latin1'running',_latin1'succeeded')) or (`provider_task_id` is not null))), CONSTRAINT `studio_media_job_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_outputs 受验证的输出与素材映射
CREATE TABLE `studio_media_outputs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `ordinal` int unsigned NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_metadata_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_result_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_output_job` (`job_id`,`ordinal`), KEY `studio_media_output_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`), CONSTRAINT `studio_media_output_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`), CONSTRAINT `studio_media_output_ordinal` CHECK ((`ordinal` = 0)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_requests 用户输入/Agent来源、报价、批准摘要与准入确认
CREATE TABLE `studio_media_requests` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_config_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_bytes` mediumblob NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quote_bytes` mediumblob NOT NULL, `quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quoted_credits` bigint unsigned NOT NULL, `expires_at` datetime(6) NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_snapshot_bytes` mediumblob, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_request_owned` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `studio_media_request_quoted` (`owner_id`,`project_id`,`conversation_id`,`id`,`request_sha256`,`quote_sha256`), UNIQUE KEY `studio_media_request_client` (`owner_id`,`project_id`,`conversation_id`,`client_request_id`), KEY `studio_media_request_page` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), KEY `studio_media_request_source_fk` (`owner_id`,`project_id`,`conversation_id`,`source_binding_id`,`source_run_id`), CONSTRAINT `studio_media_request_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`), CONSTRAINT `studio_media_request_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `source_binding_id`, `source_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`), CONSTRAINT `studio_media_quote_credits` CHECK ((`quoted_credits` between 1 and 1000000000)), CONSTRAINT `studio_media_quote_sha` CHECK ((`quote_sha256` = lower(sha2(`quote_bytes`,256)))), CONSTRAINT `studio_media_quote_times` CHECK (((`expires_at` > `created_at`) and (`expires_at` <= (`created_at` + interval 15 minute)))), CONSTRAINT `studio_media_request_origin` CHECK ((((`origin` in (_latin1'ui',_latin1'user_edit')) and (`source_binding_id` is null) and (`source_run_id` is null) and (`source_assistant_sha256` is null) and (`source_snapshot_bytes` is null)) or ((`origin` = _latin1'agent') and (`source_binding_id` is not null) and (`source_run_id` is not null) and (`source_assistant_sha256` is not null) and (`source_snapshot_bytes` is not null) and (length(`source_snapshot_bytes`) between 1 and 65536) and (`source_assistant_sha256` = lower(sha2(`source_snapshot_bytes`,256)))))), CONSTRAINT `studio_media_request_sha` CHECK ((`request_sha256` = lower(sha2(`request_bytes`,256)))), CONSTRAINT `studio_media_request_size` CHECK (((length(`request_bytes`) between 1 and 65536) and (length(`quote_bytes`) between 1 and 65536))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_submission_attempts 一次提交的任务证据与不确定结果
CREATE TABLE `studio_media_submission_attempts` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempt_no` int unsigned NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_idempotency_key` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `stage` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `dispatch_started_at` datetime(6) DEFAULT NULL, `provider_task_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `receipt_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `terminal_receipt_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `reconciliation_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_attempt_job` (`job_id`,`attempt_no`), UNIQUE KEY `studio_media_attempt_idempotency` (`provider_idempotency_key`), KEY `studio_media_attempt_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`,`request_sha256`), CONSTRAINT `studio_media_attempt_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`, `request_sha256`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`), CONSTRAINT `studio_media_attempt_number` CHECK ((`attempt_no` = 1)), CONSTRAINT `studio_media_attempt_state` CHECK ((((`stage` = _latin1'prepared') and (`dispatch_started_at` is null) and (`provider_task_id` is null) and (`receipt_sha256` is null) and (`reconciliation_sha256` is null) and (`terminal_receipt_sha256` is null)) or ((`stage` in (_latin1'dispatching',_latin1'unknown')) and (`dispatch_started_at` is not null) and (`dispatch_started_at` >= `created_at`) and (`provider_task_id` is null) and (`receipt_sha256` is null) and (`reconciliation_sha256` is null) and (`terminal_receipt_sha256` is null)) or ((`stage` = _latin1'acknowledged') and (`dispatch_started_at` is not null) and (`provider_task_id` is not null) and (`receipt_sha256` is not null) and (`terminal_receipt_sha256` is null)) or ((`stage` in (_latin1'completed',_latin1'failed')) and (`dispatch_started_at` is not null) and (`provider_task_id` is not null) and (`receipt_sha256` is not null) and (`terminal_receipt_sha256` is not null)) or ((`stage` = _latin1'reconciled_not_sent') and (`dispatch_started_at` is not null) and (`provider_task_id` is null) and (`reconciliation_sha256` is not null)))), CONSTRAINT `studio_media_attempt_times` CHECK (((`updated_at` >= `created_at`) and ((`dispatch_started_at` is null) or (`dispatch_started_at` between `created_at` and `updated_at`)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_project_asset_refs 项目对用户级素材的引用;不复制素材所有权
CREATE TABLE `studio_project_asset_refs` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_metadata_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, `detached_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`project_id`,`asset_id`), KEY `studio_project_asset_owned_page` (`owner_id`,`project_id`,`asset_id`), KEY `studio_project_asset_reverse` (`owner_id`,`asset_id`,`project_id`), CONSTRAINT `studio_project_asset_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_project_asset_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_project_asset_state` CHECK ((((`state` = _latin1'attached') and (`detached_at` is null)) or ((`state` = _latin1'detached') and (`detached_at` is not null) and (`detached_at` = `updated_at`)))), CONSTRAINT `studio_project_asset_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_projects 用户拥有的创作项目
CREATE TABLE `studio_projects` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `title` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_project_owner_identity` (`owner_id`,`id`), KEY `studio_project_owner_list` (`owner_id`,`created_at`,`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_timeline_revisions 历史时间轴修订
CREATE TABLE `studio_timeline_revisions` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_bytes` mediumblob NOT NULL, `state_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `restored_from_revision` bigint unsigned DEFAULT NULL, `recorded_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`,`project_id`,`kind`,`revision`), KEY `studio_timeline_revision_source_fk` (`owner_id`,`project_id`,`kind`,`restored_from_revision`), CONSTRAINT `studio_timeline_revision_head_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_video_documents` (`owner_id`, `project_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_timeline_revision_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `kind`, `restored_from_revision`) REFERENCES `studio_timeline_revisions` (`owner_id`, `project_id`, `kind`, `revision`), CONSTRAINT `studio_timeline_revision_bytes` CHECK ((length(`state_bytes`) between 1 and 262144)), CONSTRAINT `studio_timeline_revision_kind` CHECK ((`kind` = _latin1'timeline')), CONSTRAINT `studio_timeline_revision_number` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_timeline_revision_origin` CHECK ((((`origin` in (_latin1'saved',_latin1'backfill')) and (`restored_from_revision` is null)) or ((`origin` = _latin1'restored') and (`restored_from_revision` is not null) and (`restored_from_revision` between 1 and (`revision` - 1))))), CONSTRAINT `studio_timeline_revision_sha` CHECK ((`state_sha256` = lower(sha2(`state_bytes`,256)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_video_documents 项目当前时间轴文档
CREATE TABLE `studio_video_documents` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_json` json NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`project_id`), UNIQUE KEY `studio_timeline_owned_head` (`owner_id`,`project_id`), CONSTRAINT `studio_document_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_document_revision` CHECK ((`revision` between 1 and 2147483647)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
共享身份库(15 张)与积分账本 七个品牌相同,展开查看
studio_assets
CREATE TABLE `studio_assets` (
`id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`metadata_json` json NOT NULL,
`storage_key` varchar(512) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`created_at` datetime(6) NOT NULL,
`publication_state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT 'visible',
PRIMARY KEY (`id`),
UNIQUE KEY `studio_asset_owner_digest` (`owner_id`,`sha256`),
KEY `studio_asset_owner_list` (`owner_id`,`created_at`,`id`),
KEY `studio_asset_visible_list` (`owner_id`,`publication_state`,`created_at`,`id`),
CONSTRAINT `studio_asset_publication_state` CHECK (CAST(publication_state AS BINARY) IN ('pending','visible')),
CONSTRAINT `studio_asset_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_billing_cycles
CREATE TABLE `studio_billing_cycles` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`subscription_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`payment_order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_invoice_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`period_start` datetime(6) NOT NULL,
`period_end` datetime(6) NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`valid_from` datetime(6) NOT NULL,
`expires_at` datetime(6) NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`paid_evidence_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `billing_cycle_owned` (`owner_id`,`id`),
UNIQUE KEY `billing_cycle_period` (`subscription_id`,`period_start`),
UNIQUE KEY `billing_cycle_invoice` (`provider_key`,`provider_account`,`provider_invoice_id`),
UNIQUE KEY `billing_cycle_order` (`payment_order_id`),
KEY `billing_cycle_subscription_fk` (`owner_id`,`subscription_id`,`provider_key`,`provider_account`),
KEY `billing_cycle_order_fk` (`owner_id`,`payment_order_id`,`plan_version_id`),
KEY `billing_cycle_order_provider_fk` (`owner_id`,`payment_order_id`,`provider_key`,`provider_account`),
CONSTRAINT `billing_cycle_order_fk` FOREIGN KEY (`owner_id`, `payment_order_id`, `plan_version_id`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `plan_version_id`),
CONSTRAINT `billing_cycle_order_provider_fk` FOREIGN KEY (`owner_id`, `payment_order_id`, `provider_key`, `provider_account`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `provider_key`, `provider_account`),
CONSTRAINT `billing_cycle_subscription_fk` FOREIGN KEY (`owner_id`, `subscription_id`, `provider_key`, `provider_account`) REFERENCES `studio_subscriptions` (`owner_id`, `id`, `provider_key`, `provider_account`),
CONSTRAINT `billing_cycle_amount` CHECK ((`grant_credits` between 1 and 1000000000)),
CONSTRAINT `billing_cycle_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `billing_cycle_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `billing_cycle_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `billing_cycle_state` CHECK (((`state` in (_latin1'PENDING',_latin1'PAID',_latin1'CLOSED')) and (((`state` = _latin1'PAID') and (`paid_evidence_sha256` is not null) and regexp_like(`paid_evidence_sha256`,_latin1'^[a-f0-9]{64}$')) or ((`state` <> _latin1'PAID') and (`paid_evidence_sha256` is null))))),
CONSTRAINT `billing_cycle_times` CHECK (((`period_end` > `period_start`) and (`expires_at` > `valid_from`) and (`expires_at` <= (`valid_from` + interval 31622400 second)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_credit_accounts
CREATE TABLE `studio_credit_accounts` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `unit` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`), CONSTRAINT `credit_account_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `credit_account_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `credit_account_status` CHECK ((`status` in (_latin1'open',_latin1'suspended'))), CONSTRAINT `credit_account_unit` CHECK ((`unit` = _latin1'credits')) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_authorization_allocations
CREATE TABLE `studio_credit_authorization_allocations` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `lot_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `allocated_credits` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`authorization_id`,`lot_id`), UNIQUE KEY `credit_allocation_owned` (`owner_id`,`authorization_id`,`lot_id`), KEY `credit_allocation_lot` (`owner_id`,`lot_id`,`authorization_id`), CONSTRAINT `credit_allocation_authorization_fk` FOREIGN KEY (`owner_id`, `authorization_id`) REFERENCES `studio_credit_authorizations` (`owner_id`, `id`), CONSTRAINT `credit_allocation_lot_fk` FOREIGN KEY (`owner_id`, `lot_id`) REFERENCES `studio_credit_lots` (`owner_id`, `id`), CONSTRAINT `credit_allocation_amount` CHECK ((`allocated_credits` between 1 and 1000000000)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_authorizations
CREATE TABLE `studio_credit_authorizations` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`profile` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`credits` bigint unsigned NOT NULL,
`expires_at` datetime(6) NOT NULL,
`reservation_bytes` mediumblob NOT NULL,
`reservation_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`policy_bytes` mediumblob NOT NULL,
`policy_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_authorization_owned` (`owner_id`,`id`),
UNIQUE KEY `credit_authorization_job` (`owner_id`,`profile`,`job_id`),
CONSTRAINT `credit_authorization_account_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_credit_accounts` (`owner_id`),
CONSTRAINT `credit_authorization_amount` CHECK ((`credits` between 1 and 1000000000)),
CONSTRAINT `credit_authorization_hashes` CHECK ((regexp_like(`request_sha256`,_latin1'^[a-f0-9]{64}$') and regexp_like(`quote_sha256`,_latin1'^[a-f0-9]{64}$'))),
CONSTRAINT `credit_authorization_policy_sha` CHECK ((`policy_sha256` = lower(sha2(`policy_bytes`,256)))),
CONSTRAINT `credit_authorization_policy_size` CHECK ((length(`policy_bytes`) between 1 and 65536)),
CONSTRAINT `credit_authorization_profile` CHECK ((`profile` in (_latin1'topview',_latin1'pollo',_latin1'invideo',_latin1'libtv',_latin1'flova',_latin1'creatok',_latin1'creatify'))),
CONSTRAINT `credit_authorization_reservation_sha` CHECK ((`reservation_sha256` = lower(sha2(`reservation_bytes`,256)))),
CONSTRAINT `credit_authorization_reservation_size` CHECK ((length(`reservation_bytes`) between 1 and 65536)),
CONSTRAINT `credit_authorization_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `credit_authorization_state` CHECK ((`state` in (_latin1'HELD',_latin1'CAPTURED',_latin1'RELEASED'))),
CONSTRAINT `credit_authorization_times` CHECK (((`expires_at` > `created_at`) and (`expires_at` <= (`created_at` + interval 15 minute)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_credit_ledger_entries
CREATE TABLE `studio_credit_ledger_entries` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `lot_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `operation_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `grant_delta` bigint NOT NULL, `held_delta` bigint NOT NULL, `captured_delta` bigint NOT NULL, `facts_bytes` mediumblob NOT NULL, `facts_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `credit_entry_operation` (`owner_id`,`operation_key`,`lot_id`), KEY `credit_entry_page` (`owner_id`,`created_at`,`id`), KEY `credit_entry_lot_fk` (`owner_id`,`lot_id`), KEY `credit_entry_allocation_fk` (`owner_id`,`authorization_id`,`lot_id`), CONSTRAINT `credit_entry_allocation_fk` FOREIGN KEY (`owner_id`, `authorization_id`, `lot_id`) REFERENCES `studio_credit_authorization_allocations` (`owner_id`, `authorization_id`, `lot_id`), CONSTRAINT `credit_entry_authorization_fk` FOREIGN KEY (`owner_id`, `authorization_id`) REFERENCES `studio_credit_authorizations` (`owner_id`, `id`), CONSTRAINT `credit_entry_lot_fk` FOREIGN KEY (`owner_id`, `lot_id`) REFERENCES `studio_credit_lots` (`owner_id`, `id`), CONSTRAINT `credit_entry_delta` CHECK ((((`kind` = _latin1'grant') and (`authorization_id` is null) and (`grant_delta` between 1 and 1000000000) and (`held_delta` = 0) and (`captured_delta` = 0)) or ((`kind` = _latin1'hold') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`held_delta` between 1 and 1000000000) and (`captured_delta` = 0)) or ((`kind` = _latin1'capture') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`captured_delta` between 1 and 1000000000) and (`held_delta` = -(`captured_delta`))) or ((`kind` = _latin1'release') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`held_delta` between -(1000000000) and -(1)) and (`captured_delta` = 0)))), CONSTRAINT `credit_entry_facts_sha` CHECK ((`facts_sha256` = lower(sha2(`facts_bytes`,256)))), CONSTRAINT `credit_entry_facts_size` CHECK ((length(`facts_bytes`) between 1 and 65536)), CONSTRAINT `credit_entry_operation_key` CHECK ((((`kind` = _latin1'grant') and (`operation_key` = concat(`lot_id`,_latin1':grant'))) or ((`kind` <> _latin1'grant') and (`operation_key` = concat(`authorization_id`,_latin1':',`kind`))))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_lots
CREATE TABLE `studio_credit_lots` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `grant_credits` bigint unsigned NOT NULL, `held_credits` bigint unsigned NOT NULL, `captured_credits` bigint unsigned NOT NULL, `valid_from` datetime(6) NOT NULL, `expires_at` datetime(6) NOT NULL, `eligibility_bytes` mediumblob NOT NULL, `eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_cycle_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `credit_lot_owned` (`owner_id`,`id`), UNIQUE KEY `credit_lot_order` (`source_order_id`), UNIQUE KEY `credit_lot_cycle` (`source_cycle_id`), KEY `credit_lot_eligible` (`owner_id`,`expires_at`,`id`), KEY `credit_lot_order_fk` (`owner_id`,`source_order_id`), KEY `credit_lot_cycle_fk` (`owner_id`,`source_cycle_id`), CONSTRAINT `credit_lot_account_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_credit_accounts` (`owner_id`), CONSTRAINT `credit_lot_cycle_fk` FOREIGN KEY (`owner_id`, `source_cycle_id`) REFERENCES `studio_billing_cycles` (`owner_id`, `id`), CONSTRAINT `credit_lot_order_fk` FOREIGN KEY (`owner_id`, `source_order_id`) REFERENCES `studio_payment_orders` (`owner_id`, `id`), CONSTRAINT `credit_lot_counters` CHECK (((`grant_credits` between 1 and 1000000000) and (`held_credits` <= 1000000000) and (`captured_credits` <= 1000000000) and ((`held_credits` + `captured_credits`) <= `grant_credits`))), CONSTRAINT `credit_lot_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))), CONSTRAINT `credit_lot_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)), CONSTRAINT `credit_lot_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `credit_lot_source` CHECK ((((`source_order_id` is not null) and (`source_cycle_id` is null)) or ((`source_order_id` is null) and (`source_cycle_id` is not null)))), CONSTRAINT `credit_lot_times` CHECK (((`expires_at` > `valid_from`) and (`updated_at` >= `created_at`))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_plan_versions
CREATE TABLE `studio_credit_plan_versions` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`version_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`price_minor` bigint unsigned NOT NULL,
`currency` char(3) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`credit_validity_seconds` int unsigned NOT NULL,
`billing_interval_months` int unsigned NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`published_at` datetime(6) NOT NULL,
`retired_at` datetime(6) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_plan_version_key` (`plan_key`,`version_key`),
CONSTRAINT `credit_plan_amount` CHECK (((`price_minor` between 1 and 1000000000000) and (`grant_credits` between 1 and 1000000000))),
CONSTRAINT `credit_plan_currency` CHECK (regexp_like(`currency`,_latin1'^[A-Z]{3}$')),
CONSTRAINT `credit_plan_duration` CHECK (((`credit_validity_seconds` between 1 and 31622400) and ((`retired_at` is null) or (`retired_at` >= `published_at`)))),
CONSTRAINT `credit_plan_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `credit_plan_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `credit_plan_kind` CHECK (((`kind` in (_latin1'subscription',_latin1'topup')) and (((`kind` = _latin1'subscription') and (`billing_interval_months` in (1,3,12))) or ((`kind` = _latin1'topup') and (`billing_interval_months` = 0)))))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_media_model_versions
CREATE TABLE `studio_media_model_versions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `version_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `config_bytes` mediumblob NOT NULL, `config_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `published_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_version_key` (`model_id`,`version_key`), UNIQUE KEY `studio_media_version_owned_model` (`model_id`,`id`), CONSTRAINT `studio_media_version_model_fk` FOREIGN KEY (`model_id`) REFERENCES `studio_media_models` (`id`), CONSTRAINT `studio_media_version_sha` CHECK ((`config_sha256` = lower(sha2(`config_bytes`,256)))), CONSTRAINT `studio_media_version_size` CHECK ((length(`config_bytes`) between 1 and 65536)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_models
CREATE TABLE `studio_media_models` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `display_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `published_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `revision` bigint unsigned NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_model_key` (`model_key`), KEY `studio_media_model_published_fk` (`id`,`published_version_id`), CONSTRAINT `studio_media_model_published_fk` FOREIGN KEY (`id`, `published_version_id`) REFERENCES `studio_media_model_versions` (`model_id`, `id`), CONSTRAINT `studio_media_model_kind` CHECK ((`kind` = _ascii'video')), CONSTRAINT `studio_media_model_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_media_model_status` CHECK (((`status` in (_ascii'draft',_ascii'active',_ascii'disabled')) and ((`status` <> _ascii'active') or (`published_version_id` is not null)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_payment_events
CREATE TABLE `studio_payment_events` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_event_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `subscription_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `body_bytes` mediumblob NOT NULL, `body_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `payment_event_provider` (`provider_key`,`provider_account`,`provider_event_id`), KEY `payment_event_order_fk` (`owner_id`,`order_id`,`provider_key`,`provider_account`), KEY `payment_event_subscription_fk` (`owner_id`,`subscription_id`,`provider_key`,`provider_account`), CONSTRAINT `payment_event_order_fk` FOREIGN KEY (`owner_id`, `order_id`, `provider_key`, `provider_account`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `provider_key`, `provider_account`), CONSTRAINT `payment_event_subscription_fk` FOREIGN KEY (`owner_id`, `subscription_id`, `provider_key`, `provider_account`) REFERENCES `studio_subscriptions` (`owner_id`, `id`, `provider_key`, `provider_account`), CONSTRAINT `payment_event_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `payment_event_body_sha` CHECK ((`body_sha256` = lower(sha2(`body_bytes`,256)))), CONSTRAINT `payment_event_body_size` CHECK ((length(`body_bytes`) between 1 and 65536)), CONSTRAINT `payment_event_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `payment_event_state` CHECK ((`state` in (_latin1'VERIFIED',_latin1'PROCESSED'))), CONSTRAINT `payment_event_subject` CHECK (((`order_id` is not null) or (`subscription_id` is not null))), CONSTRAINT `payment_event_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_payment_orders
CREATE TABLE `studio_payment_orders` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`price_minor` bigint unsigned NOT NULL,
`currency` char(3) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`valid_from` datetime(6) NOT NULL,
`expires_at` datetime(6) NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_idempotency_key` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_order_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`paid_evidence_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `payment_order_owned` (`owner_id`,`id`),
UNIQUE KEY `payment_order_owned_plan` (`owner_id`,`id`,`plan_version_id`),
UNIQUE KEY `payment_order_owned_provider` (`owner_id`,`id`,`provider_key`,`provider_account`),
UNIQUE KEY `payment_order_client` (`owner_id`,`client_action_id`),
UNIQUE KEY `payment_order_provider_key` (`provider_key`,`provider_account`,`provider_idempotency_key`),
UNIQUE KEY `payment_order_provider_id` (`provider_key`,`provider_account`,`provider_order_id`),
KEY `payment_order_plan_fk` (`plan_version_id`),
CONSTRAINT `payment_order_plan_fk` FOREIGN KEY (`plan_version_id`) REFERENCES `studio_credit_plan_versions` (`id`),
CONSTRAINT `payment_order_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`),
CONSTRAINT `payment_order_amount` CHECK (((`price_minor` between 1 and 1000000000000) and (`grant_credits` between 1 and 1000000000))),
CONSTRAINT `payment_order_currency` CHECK (regexp_like(`currency`,_latin1'^[A-Z]{3}$')),
CONSTRAINT `payment_order_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `payment_order_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `payment_order_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `payment_order_state` CHECK (((`state` in (_latin1'CREATING',_latin1'CREATE_UNKNOWN',_latin1'PENDING',_latin1'PAID',_latin1'CLOSED')) and (((`state` = _latin1'PAID') and (`provider_order_id` is not null) and (`paid_evidence_sha256` is not null) and regexp_like(`paid_evidence_sha256`,_latin1'^[a-f0-9]{64}$')) or ((`state` <> _latin1'PAID') and (`paid_evidence_sha256` is null))))),
CONSTRAINT `payment_order_times` CHECK (((`expires_at` > `valid_from`) and (`expires_at` <= (`valid_from` + interval 31622400 second)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_sessions
CREATE TABLE `studio_sessions` ( `token_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `user_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, `expires_at` datetime(6) NOT NULL, `revoked_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`token_hash`), KEY `studio_session_expiry` (`expires_at`), KEY `studio_session_user` (`user_id`,`expires_at`), CONSTRAINT `studio_session_user_fk` FOREIGN KEY (`user_id`) REFERENCES `studio_users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_session_times` CHECK ((`expires_at` > `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_subscriptions
CREATE TABLE `studio_subscriptions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_subscription_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `period_start` datetime(6) NOT NULL, `period_end` datetime(6) NOT NULL, `cancel_at_period_end` tinyint(1) NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `subscription_owned` (`owner_id`,`id`), UNIQUE KEY `subscription_owned_provider` (`owner_id`,`id`,`provider_key`,`provider_account`), UNIQUE KEY `subscription_provider` (`provider_key`,`provider_account`,`provider_subscription_id`), KEY `subscription_plan_fk` (`plan_version_id`), CONSTRAINT `subscription_plan_fk` FOREIGN KEY (`plan_version_id`) REFERENCES `studio_credit_plan_versions` (`id`), CONSTRAINT `subscription_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `subscription_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `subscription_state` CHECK (((`state` in (_latin1'PENDING',_latin1'ACTIVE',_latin1'PAST_DUE',_latin1'CANCELLED',_latin1'ENDED')) and (`cancel_at_period_end` in (0,1)))), CONSTRAINT `subscription_times` CHECK (((`period_end` > `period_start`) and (`updated_at` >= `created_at`))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_users
CREATE TABLE `studio_users` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `email` varchar(254) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `password_hash` varbinary(72) NOT NULL, `enabled` tinyint(1) NOT NULL DEFAULT '1', `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_user_email` (`email`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
积分账本链路
CreaTok · 接口清单
共 55 个公开接口,取自源码路由盘点。路径都以 /v1 开头;写操作需要会话 Cookie、可信 Host/Origin 与 CSRF;带品牌的路径用 ?profile=creatok;共享的登录、素材、模型目录路径不接受 profile 参数。
Agent/统一动作 7 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/interactions | runInteractions | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/interactions/{interaction_id}/responses | respondInteraction | client_action_id, card_sha256, action, values | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/interaction-actions/{client_action_id} | interactionAction | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/model-changes | changeConversationModel | client_action_id, expected_revision, agent_model, expected_attempt? | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/model-changes/{client_action_id} | modelChangeAction | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/stop | stopRun | client_action_id, expected_attempt? | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/stop-actions/{client_action_id} | stopAction | 200 |
Asset 4 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/assets | listAssets | 200 | |
| POST | /v1/assets | uploadAsset | file | 201 |
| GET | /v1/assets/{asset_id} | getAsset | 200 | |
| GET | /v1/assets/{asset_id}/content | assetContent | 200/206 |
LoginSession 1 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| POST | /v1/auth/logout | logout | 200 |
MaaBinding 5 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/maa/model-options | maaModels | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/messages | sendMaaMessage | client_action_id, content | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/actions/{client_action_id} | getMaaAction | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/state | getMaaState | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/events | maaEvents | 200 |
Media 11 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/media/models | publicMediaModels | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests | createMediaRequest | client_request_id, model_id, model_version_id, prompt, duration_seconds, ratio, resolution, admission? | 200 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests | mediaRequestByClient | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id} | getMediaRequest | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs/{job_id} | getMediaJob | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs/{job_id}/output | getMediaOutput | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id}/job | mediaJobByRequest | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id}/approve | approveMediaRequest | client_approval_id, request_sha256, quote_sha256 | 200 |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/from-maa | createMediaRequestFromMaa | input, source_run_id, source_assistant_sha256, admission? | 200 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs | listMediaJobs | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/intents | listMediaIntents | 200 |
Other 9 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects/{project_id}/canvas/revisions | listCanvasRevisions | 200 | |
| GET | /v1/projects/{project_id}/canvas/revisions/{revision} | getCanvasRevision | 200 | |
| POST | /v1/projects/{project_id}/canvas/revisions/{revision}/restore | restoreCanvasRevision | expected_revision | 200 |
| GET | /v1/projects/{project_id}/document/revisions | listTimelineRevisions | 200 | |
| GET | /v1/projects/{project_id}/document/revisions/{revision} | getTimelineRevision | 200 | |
| POST | /v1/projects/{project_id}/document/revisions/{revision}/restore | restoreTimelineRevision | expected_revision | 200 |
| GET | /v1/projects/{project_id}/assets | listProjectAssets | 200 | |
| POST | /v1/projects/{project_id}/assets | attachProjectAsset | asset_id, expected_revision | 200 |
| POST | /v1/projects/{project_id}/assets/{asset_id}/detach | detachProjectAsset | expected_revision | 200 |
Project 15 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects | listProjects | 200 | |
| POST | /v1/projects | createProject | title | 201 |
| GET | /v1/projects/{project_id} | getProject | 200 | |
| GET | /v1/projects/{project_id}/conversations | listConversations | 200 | |
| POST | /v1/projects/{project_id}/conversations | createConversation | title | 201 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id} | getConversation | 200 | |
| GET | /v1/projects/{project_id}/canvas | getCanvas | 200 | |
| POST | /v1/projects/{project_id}/canvas | saveCanvas | expected_revision, state | 200 |
| GET | /v1/projects/{project_id}/document | getDocument | 200 | |
| POST | /v1/projects/{project_id}/document | saveDocument | expected_revision, state | 200 |
| GET | /v1/projects/{project_id}/export-jobs | listExportJobs | 200 | |
| POST | /v1/projects/{project_id}/export-jobs | queueExport | document_revision, output? | 202 |
| GET | /v1/projects/{project_id}/export-jobs/{job_id} | getExportJob | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/binding | getMaaBinding | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/binding | bindMaa | agent_model XOR use_default:true | 200 |
User 3 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| POST | /v1/auth/register | register | email, password | 201 |
| POST | /v1/auth/login | login | email, password | 200 |
| GET | /v1/auth/session | session | 200 |
CreaTok 自己公开的接口调用流程(来自其官方资料)
| 步骤 | 调用关系 | 操作 | 证据 |
|---|---|---|---|
| 面板提交请求 | 扩展面板 → 扩展后台 | chrome.runtime消息API_REQUEST携带path/method/body/query/headers;流请求API_STREAM_REQUEST另带streamId。 | C |
| 读取账号上下文 | 扩展后台 → Web入口 | GET https://www.creatok.ai/api/extension/me;fetch credentials:include;客户端处理code===0/data与ApiError。 | C |
| 发起视觉分析 | 扩展后台 → Web入口 | POST /api/extension/tiktok-transcript-generator/decompose-video-script;body含video_id、locale、analysis_contract:visual_v1;Accept:text/event-stream。 | C |
| 中继分析事件 | 扩展后台 → 扩展面板 | 后台读取response.body并发送API_STREAM_EVENT;payload含streamId、type:chunk|done|error;UI按空行解析data JSON的partial/final/error/done。 | C |
| 保存收藏身份 | 扩展后台 → Web入口 | POST /api/extension/collections/posts;提交submittedUrl、contentType、postSnapshot、locale等;返回post.uid与platformPostId。 | C |
| 导入商品资料 | 扩展后台 → Web入口 | POST /api/extension/products/analyze-selling-points与/api/extension/products;来源platform/externalProductId、卖点与已选media[]分别提交。 | C |
| 批准脚本并生成 | 创作界面 → Web入口 | 官方Web Agent先给脚本和生成方案,用户批准后进入生成;对应HTTP方法、URL、body与事件格式未取得。 | W |
| 画布局部重跑 | 创作界面 → Web入口 | 官方Canvas支持节点组合与局部重跑;节点保存、连线编辑、版本、运行接口均未核实。 | W |
| 排期发布与回看 | Web入口 → 发布平台 | 官方流程为TikTok授权、商品锚点/预检、立即或排期发布、状态与表现回收;具体TikTok调用与内部发布API合同未知。 | W |
CreaTok · 代码与下载
7.6 MB · 53 个文件 · SHA-256
e44a352895b04785e4e911274fe112e2d69d54e435792cc2d586199273ac9400下载:creatok-replica.zip · 后端与合同 · 全部代码
| 目录 | 内容 |
|---|---|
| frontend/ | CreaTok 前端:<code>candidate-8875-unified-v22.html</code> 及它引用的全部脚本与样式 |
| contracts/ | 本品牌的表结构 SQL、ER(svg / mmd)、外键清单;接口目录(json / csv);共享身份库表结构 |
| README.md | 怎么运行、需要自备什么 |
运行前端
python3 -m http.server -d frontend 8791
# 打开 http://127.0.0.1:8791/agent-integration/apps-production-brand-v14/creatok/candidate-8875-unified-v22.htmlbackend-and-contracts.zip;all-brands-code.zip 是全部。包里没有任何凭据、数据库备份或媒体文件,已做敏感串扫描。MAA_AGENT_ROOT)、模型网关与对象存储配置。静态前端单独打开不需要后端,但登录、对话、生成、导出需要整套服务。复刻完成度(审计 2026-10-19)
结论:不是完美复刻。官方资料里的 45 项能力:实测跑通 1、只有通用对话 3、后端有但没跑过 2、没有后端 39。
真正跑通的:Canvas 项目管理。
界面对照(工作台首页(已登录)):真实页面采集到 65 个控件 / 标题文字,复刻页找到 55 个。缺的有:爆款趋势 图文、视频/图文发布 CLI、灵感库 New、Skills/CLI、Google Chrome、客服、本地演示账号 个人空间、快速生成 精准编辑、限时优惠 8 折、限时优惠 9 折。
逐个点击(已登录首页):78 个可点控件,点了有效 4 个,只提示“此功能正在接入” 64 个,没反应或只变样式 2 个,禁用 4 个,未点(发送 / 删除 / 退出等)1 个。
只提示“正在接入”的控件(64 次点击,57 种)
视频分析、爆款趋势 ×2、视频 ×3、图片 ×2、音频、工具、视频/图文发布、灵感库 ×2、Toggle Sidebar、反馈、限时优惠、带货图文,从灵感到发布、Nano Banana 2.1、Chrome 扩展、略胜 Nano 2、下一张 ×2、Agent、添加附件、技能、每日 Agent 额度、拆解视频/图文、复刻视频、创作带货视频、视频转提示词、复刻带货图文、创作带货图文、爆款复刻 ×2、提示词反推、去字幕、画质提升、商品套图、A+内容、去水印、图片去背景、文字转语音(TTS)、TikTok 脚本提取、图片翻译、图片复刻、精选、资产库、商品库、图文、超高货车广告、概念与成品、Seedance 提示词、荒诞钩子、H3 提示词、子弹时间广告、一键创作、蛛丝牵引产品、穿搭种草、展开更多、带货图文复刻、图文带货、电商图提示词、商品套图策划、辛普森轮播
点了没反应或只变样式的控件(2 次点击,2 种)
选择项目 / 选择会话、首页
复刻页自报的绑定状态(页面内嵌的绑定清单):原生工作区控件(新建项目、会话、登录等)9 / 10 个没有绑定到原页面的控件,由统一的工作区条代替;路由 projects、timeline 缺失或只做了一部分;
首屏截图对照(左:真实产品 creatok/source-dashboard-safe.png;右:复刻页)· 粗粒度差异 66%
真实截图是测试账号登录后的画面,内容(作品、项目、横幅)本来就不同,差异百分比只作参考,重点看布局。
Creatify · 总览
- 它是什么:URL → 视频,入口最短;Agent 交互:入口多,内核同一套。
- 我们借鉴:多个入口汇成同一个“创作意图”(决策 D11)。
- 复刻现状:5 项已验证,在线试用 http://119.23.106.60:8107/;后端与其余六个品牌共用一套(24 张表、55 个接口),所以 ER / 表结构 / 接口页的通用部分默认折叠。
广告素材生产、AdFlow 节点流程、效果 Agent 与投放集成共同构成广告闭环;同时提供独立的公开生成 API。
证据:W 官方说明,A 官方接口合同,C 客户端代码,O 实测。“未实测”= 只核对了官方页面,没有上传素材或生成。
45 项,分 12 类
首页 + 创作工作台
24 张表 · 34 个外键 · 85 个索引
能力目录
智能 Agent 与 Skill 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 创作 Co-Pilot 与计划确认 | 对话讨论角度、分镜和理由,确认后搭建画布。 | W | 未观察主 Agent 协议与会话持久化 |
| Performance Agent 与预设营销任务 | 对话分析投放,提供审计、本地化和创意评估入口。 | W | 操作审核方式、权限和预算保护未实测;预设 prompt 与内部技能标签不是用户 Skill 发布系统 |
| 广告脚本候选及自写脚本 | 生成多个文案候选或采用自写脚本。 | W | 脚本审核与版本规则未测 |
项目与会话 4 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 品牌空间 | 把不同品牌的工作上下文分开。 | W | 空间内实体与跨空间素材规则未知 |
| 团队工作区及权限 | 通过 Admin/Editor/Viewer 管理成员访问。 | W | 帮助页较旧;不采用旧席位配额,权限执行未测 |
| AdFlow 节点编排与局部迭代 | 连接制作步骤,并替换单个模型或部件。 | W | 未实测节点执行协议与类型约束;受依赖步骤如何失效、是否自动重跑未知 |
| 流程分支、复用及团队回放 | 从共同基础建立变体并回看生成过程。 | W | 不是数据库不可变快照或 Git 分支证明 |
素材与商品 4 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 商品 URL 导入 | 提取商品资料和媒体用于广告制作。 | A | 外层 Link ID 与嵌套商品 ID 不应混用 |
| 模型参数 Schema 查询 | 查询模型输入定义再构造生成参数。 | A | 未核实 Web 是否动态使用相同 schema |
| 异步生成、历史查询与回调 | 查询任务历史和进度,或通过回调接收结果。 | A | 回调重试/签名与任务超时未实测;创建时间筛选不是状态变化时间;没有用户数据调用 |
| Smart Assets 素材容量 | 工作区具备素材保存容量权益。 | W | 文件类型、删除回收和个人/团队归属未知 |
视频生成 5 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 多风格预览后选成片 | 异步生成预览,选择一个 media_job 渲染。 | A | 预览与成片是不同步骤;没有实际调用 |
| 商品图片转广告视频 | 从商品图片制作演示或广告片段。 | W | 没有生成或投放,成本、效果与运行时数据未知 |
| 文图及参考素材生成视频 | 由提示词、图片或参考媒体制作片段。 | A | 视频编辑、首尾帧和声音参数依具体模型 |
| 批量广告变体 | 组合多个脚本、视觉风格和演员。 | W | 最大批次、部分失败与耗费未知 |
| Ad Clone | 用参考广告链接制作新的广告版本。 | W | 输入支持范围、重构步骤未测试 |
声音与人物 7 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| AI 演员库 | 选择预置人物用于口播广告。 | W | 演员数量随套餐,不以宣传总数当账号可用数 |
| 自定义人物 Avatar | 从自己的素材建立自定义人物。 | W | 输入素材及制作周期按具体入口;未提交真人素材 |
| 品牌 AI Influencer | 制作可持续使用的品牌虚拟人物。 | W | 跨作品一致性只为官方说明,未测 |
| 多场景口播与透明人物输出 | 组合人物口播场景,API 可输出透明 WebM。 | A | 具体 API 文档已读;Web 对应入口与背景/格式权限未执行 |
| 文字配音、音色与语种 | 选择声音、语言及语音表达生成配音。 | W | 语种与音色随产品和套餐,未测音频输出 |
| 音乐生成 | 按音乐需求生成歌曲或器乐素材。 | A | 单个音乐模型页本次工具无法取得;只确认任务类别与官方目录,不推测时长/价格 |
| 声音克隆与克隆音色管理 | 从音频样本建立可复用的 voice ID。 | A | 提供方决定额度及模型适用,未将接口配额外推 Web 套餐 |
图片生成 2 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| AI 图片素材生成与编辑 | 制作或编辑广告图,Web Image Ad 支持商品 URL。 | W | Web URL-to-Image 仅官方文档说明;API 图片适配接收已有图,二者不相同 |
| IAB 多尺寸广告图适配 | 以现有广告图重绘多种标准横幅。 | A | 不是像素级缩放;API 不含 Web 商品 URL 转图流程 |
编辑与导出 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 脚本、人物与 B-roll 编辑 | 修改脚本、配音、演员和画面组合。 | W | 免费编辑和付费最终生成应分开理解 |
| 字幕、音乐、贴纸与 CTA | 编辑字幕及广告画面装饰和行动引导。 | W | 是否有独立多轨时间轴未核实 |
| 画幅调整、下载和成片导出 | 调整展示比例并导出可发布媒体。 | W | 分辨率、工程导出和各分享路径未知 |
模板与社区 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| Ad Inspiration 模板 | 按广告场景选择创作模板。 | W | 模板名称、数量及席位权益随方案,未逐项体验 |
| 自定义模板 API | 以模板和业务数据生成预览及视频。 | A | 不能由 API 文档推断 Web 模板编辑入口 |
| 官方教学、案例和更新 | 提供使用教程、客户案例及产品更新。 | W | 案例是官方展示,未复核宣传结果 |
发现与分析 4 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 广告发现与筛选 | 查询社交广告内容寻找创意参考。 | W | 数据源完整性和覆盖周期未实测 |
| 参考广告收藏与分享 | 保存参考广告并与他人分享。 | W | 收藏权限及分享链接有效期未知 |
| 品牌广告跟踪 | 关注竞争品牌并查看广告变化。 | W | 跟踪限额与实时性以账号为准 |
| 广告元素分析与评分 | 拆解 hook、人物、卖点和 CTA。 | W | 分析分数不是实际投放收益保证 |
发布与运营 4 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 广告平台账号和数据连接 | 连接投放账号、店铺与分析数据。 | W | 连接器覆盖与授权范围按账号及地区;不声明已连接 |
| 广告创建与投放 | 建立创意、预算和定向后发布广告。 | W | 未执行外部动作;投放审核、消耗上限未知 |
| 投放审计和优化建议 | 定位低效消耗及可扩量内容。 | W | 没有对真实广告账户执行审计 |
| 持续监控与自动化 | 监控表现并回流到下一轮创作。 | W | 执行频率、批准方式、预算自动调节未测 |
协作与权益 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 订阅、积分、并发及无水印权益 | 方案区分额度、水印、并发、时长和资源权限。 | W | 不抄录固定价格;方案会变化,结账才确认;不把套餐时长当单个视频模型片段上限 |
| 失败退款与输出保存 | API 失败退积分;成品需自行长期保存。 | A | 只适用文档所述接口,不外推整个 Web 退款政策 |
| 企业定制和服务 | 提供定制额度、模型调优、白标及 SLA。 | W | 具体合同、交付和可用 API 权益未取得 |
开放接入与客户端 3 项
| 能力 | 说明 | 证据 | 限制 |
|---|---|---|---|
| 生成 REST API 与 API Key | 用官方认证接入商品、声音、人物和任务。 | A | 未发业务调用;API 可用性不等于 Web 套餐通用 |
| Creatify MCP | 向 Claude/ChatGPT 提供产品接入能力。 | W | 没有取得 MCP server/tool schema,不推测工具名 |
| HTML 互动广告生成入口 | 官方索引列出商品页转 playable HTML 广告。 | A | 仅索引及目录证据;未验证执行、参数、包体或广告平台兼容性 |
尚不清楚的部分
- 完整项目/会话历史、恢复与分叉协议:Co-Pilot 是对话入口,但未登录观察 session/run/history 实际合同。
- 用户自建 Skill 与版本市场:只有预设营销任务和内部标签,未证明用户发布 Skill。
- 传统时间轴与工程格式:编辑器有编辑操作;未确认轨道结构、时间码评论或工程导出。
- 原生移动/桌面应用及浏览器扩展:没有可信 creatify.ai 官方商店或下载合同;同名其他发布者产品排除。
- 官方 CLI:当前确定 REST API 与 MCP 权益,未确认独立官方 CLI 下载/合同。
- MCP 工具列表、实时传输与权限:仅权益说明;未实际连接 MCP。
竞品技术栈观察
官网有历史Framer平台证据;官方招聘要求React/Python及Django或Flask,仅能作为团队选型线索。当前App取包超时;API域DNS指向us-west-2命名的AWS ELB入口。
| 项目 | 观察到的内容 | 状态 | 置信度 |
|---|---|---|---|
| Nginx 与代理版本 | 官网及App本轮无响应banner;Nginx产品及准确版本未知。 | unknown | low |
| 前端运行语言 | 当前官网/App脚本未取到,具体运行构件未知;招聘提React只是辅助线索。 | unknown | low |
| 前端源码语言 | 营销站和业务App原始源码语言与版本未知;公开SDK、Skill仓库不等于产品源码。 | unknown | low |
| 前端框架与版本 | 营销站:2025年Framer官方画廊收录;业务App:React为招聘线索,当前框架版本未证实。 | inferred | medium |
| 构建与服务端渲染 | 官网历史Framer构建线索;App打包器、SSR/SPA模式和准确版本未知。 | inferred | low |
| 业务后端语言 | Python为官方全栈岗位要求;当前业务API/生成Worker的运行语言未直接确认。 | inferred | medium |
| 业务后端框架 | 官方岗位提Django或Flask;具体生产框架、服务归属和版本均未直接确认。 | inferred | low |
| 分发层与源站线索 | API域CNAME指向AWS us-west-2命名ELB;只确认入口线索,官网/App与上游源站位置未知。 | observed | high |
| 代码仓库与目录关系 | 官网与业务App有不同域名与技术线索;是否同仓、目录关系及后端源码布局未知。 | unknown | low |
竞品服务调用图
公开API链明确区分Link、脚本任务、预览media_job、渲染输出和通用模型生成;异步协调/执行是有来源的逻辑推断。Web Agent/AdFlow实际接口独立未知。
| 节点 | 层 | 职责 | 证据 |
|---|---|---|---|
| API接入程序 | client | 持有调用凭据并发起公开REST请求的客户侧程序。 | A |
| Web Agent画布 | client | 官方Agent/AdFlow产品入口,与公开API合同单列。 | W |
| 公共API入口 | entry | api.creatify.ai的公开接口与当前ELB DNS入口线索。 | A |
| Link商品资料 | domain | Link外层资源和内层抓取/编辑资料的合同对象。 | A |
| 脚本候选任务 | domain | 脚本任务及生成文本候选的公开资源。 | A |
| 预览渲染任务 | domain | LinkToVideo、Preview media_job和每个Output的合同职责。 | A |
| 模型参数合同 | domain | 按model_name提供输入Schema的公开目录职责。 | A |
| 通用生成任务 | domain | model_name/input_params提交与生成任务id资源。 | A |
| 异步编排职责 | runtime | 解释异步预览、渲染和通用任务状态变化的可能协调职责。 | I |
| 模型执行职责 | runtime | 产生预览、视频或asset结果的执行/转发职责。 | I |
| 任务与产物记录 | data | API返回的状态、media_job和Asset身份的逻辑结果模型。 | A |
| 结果分发示例 | external | 文档结果URL示例为CloudFront,接入方按URL读取资源。 | A |
| 客户回调接收方 | external | 配置webhook_url的客户侧HTTPS接收端。 | A |
增长与运营机制
复刻状态
| 能力 | 状态 | 依据 |
|---|---|---|
| 令牌与通用层加载,强调色 #6161ff | 已验证 | 页面加载后令牌生效 |
| 新建项目 | 已验证 | 页面自己的「+ New project」按钮原本不连运行时;运行时把「新建项目」绑到了无关的 AdFlow 工具块并隐藏。已让该按钮转发到运行时的新建项目框,首次点击偶尔无反应,已加一次重试,重试效果未再单独复测 |
| Agent 对话:新建会话、自动选默认模型、发送收回复 | 已验证 | 真实 Maa,收到回复 |
| 停止回复 | 已验证 | maa_run_stop_actions=terminal_observed,run=cancelled |
| 首页与创作工作台布局 | 已加载 | 沿用早期静态页 |
| 生成视频(报价→批准→成片) | 已验证 | 测试部署 119.23.106.60:8107 上真实生成:Seedance 2.0 Mini 5 秒,报价 3 积分,批准后任务成功、产出 MP4(接口级验证;素材页展示未逐项核对) |
agent-integration/apps-production-brand-v14/creatify/candidate-8875-unified-v22.html复刻的架构 七个品牌相同,展开查看
flowchart LR U[浏览器] -->|静态页| FE[品牌前端<br/>令牌 + 通用层 + 运行时脚本] FE -->|/v1/* Cookie + CSRF| BFF[BFF 业务服务 Go] BFF --> MY[(MySQL<br/>共享身份库 + 品牌库)] BFF -->|会话 / 消息 / 事件| MAA[Maa Agent] BFF -->|任务| WK[媒体 worker] WK -->|submit_video| GW[模型网关] GW --> MOD[视频模型] MAA --> GW BFF --> OBJ[(素材 / 导出存储)]
?profile=creatify 区分品牌)。品牌差异在前端:令牌(颜色、圆角、字体)、入口与页面结构。Creatify · Agent 交互过程
竞品里观察到的
NOT_RUN_COST_GATE 已确认登录工作台与空测试工程;按用户明确“只做明确免费Agent对话、不能花现有积分”的限制,没有发送任何Agent消息。
- Project→Chats层级
- 项目级Instructions
- Skills导入ZIP/在聊天创建入口
- Connectors目录入口
- Files & sources跨会话参考说明
- 独立生成Assets页
- 输入框附件与模型开关入口
费用与准入
| 项 | 值 |
|---|---|
| selected_model | 默认Agent模型未公开 |
| observed_price | Upgrade旁显示10;未见文字回合明确价格或免费声明。 |
| available_credits | 10 |
| exact_per_turn_cost | unknown |
| approval | 用户已明确只做确认零积分费用的Agent对话;本轮不得消耗现有积分,先前10积分预算询问不构成授权。 |
| action_taken | no_send |
| reason | 官方回复计费说明与有限免费credits均不满足零积分条件;只文字规划也可能产生费用。 |
| free_only_requirement | true |
| zero_credit_cost_confirmed | false |
| official_policy | 当前官方Creative Agent帮助明确每次Agent响应或生成动作有对应积分成本。Web Ad Agent本账号单回合价仍未知,不能推定为零。 |
竞品公开的调用流程
| 步骤 | 调用关系 | 操作 | 证据 |
|---|---|---|---|
| 导入商品链接 | 接入程序 → 公共API | POST https://api.creatify.ai/api/links/,body含url;鉴权字段X-API-ID/X-API-KEY;保留Link.id和link.id。 | A |
| 修订商品资料 | 接入程序 → 公共API | PUT /api/links/{id}/修订产品资料;编辑字段和路径id规则以官方schema为准。 | A |
| 生成脚本候选 | 接入程序 → 公共API | POST /api/ai_scripts/;返回脚本任务id、workspace/product引用、status及generated_scripts[].paragraphs/script_name/script_style/title。 | A |
| 请求多个预览 | 接入程序 → 公共API | POST /api/link_to_videos/preview_list_async/;link引用外层Link.id,可传visual_styles[]、video_length、aspect_ratio等;返回任务id与previews[].media_job。 | A |
| 选中候选渲染 | 接入程序 → 公共API | POST /api/link_to_videos/{id}/render_single_preview/;path为LinkToVideo.id,body为media_job:UUID。 | A |
| 查询每个输出 | 接入程序 → 公共API | GET /api/link_to_videos/{id}/;检查outputs[].status、progress、failed_reason和video_output,不仅检查顶层status。 | A |
| 读取模型参数 | 接入程序 → 公共API | GET /api/asset_generator/schemas/?model_name=...;返回model_name、generation_type与input_params_schema及UI扩展字段。 | A |
| 提交通用生成 | 接入程序 → 公共API | POST /api/asset_generator/;body含model_name、input_params、可选webhook_url;返回生成任务id。 | A |
| 收取产物状态 | 接入程序 → 公共API | GET /api/asset_generator/{id}/按任务id取status与assets[]{id,type,url,thumbnail_url,name};可选由服务向客户webhook_url发送回调。 | A |
在本品牌复刻上的测试结果
| 能力 | 状态 | 依据 |
|---|---|---|
| Agent 对话:新建会话、自动选默认模型、发送收回复 | 已验证 | 真实 Maa,收到回复 |
| 停止回复 | 已验证 | maa_run_stop_actions=terminal_observed,run=cancelled |
| 生成视频(报价→批准→成片) | 已验证 | 测试部署 119.23.106.60:8107 上真实生成:Seedance 2.0 Mini 5 秒,报价 3 积分,批准后任务成功、产出 MP4(接口级验证;素材页展示未逐项核对) |
复刻里的 Agent 交互设计(时序图、状态机、规则) 七个品牌相同,展开查看
sequenceDiagram
autonumber
participant B as 浏览器
participant S as BFF
participant DB as MySQL
participant M as Maa Agent
participant W as 媒体 worker
participant G as 模型网关
B->>S: POST /projects, /conversations
B->>S: POST maa/binding
S->>DB: maa_bindings dispatching
S->>M: 创建原生会话
M-->>S: native_cid
S->>DB: maa_bindings bound
B->>S: POST maa/messages {client_action_id, content}
S->>DB: maa_message_actions 幂等回执
S-->>B: 202 + run_id
S->>M: 提交消息
S->>DB: maa_runs queued 到 running
loop 事件游标
B->>S: GET runs/{id}/events
S-->>B: assistant.delta / assistant.message
end
M-->>S: run.completed
S->>DB: 记录助手内容 SHA-256
B->>S: POST media/requests/from-maa {source_run_id, sha256}
S-->>B: 报价 + 有效期 + quote_sha256
B->>S: POST approve {client_approval_id, request_sha256, quote_sha256}
S->>DB: 冻结积分 + 建任务
W->>G: submit_video
G-->>W: 视频
W->>DB: 产出入库 + 扣费
B->>S: GET media/jobs/{id}Run 状态机
stateDiagram-v2 [*] --> queued: POST maa/messages 202 queued --> running running --> waiting_interaction: 需要澄清卡 waiting_interaction --> running: respondInteraction running --> completed running --> failed running --> cancelled: stopRun waiting_interaction --> cancelled completed --> [*] failed --> [*] cancelled --> [*]
媒体任务状态机
stateDiagram-v2 [*] --> quoted quoted --> expired: 约 5 分钟 quoted --> approved: approve approved --> held: 冻结积分 held --> queued queued --> running: worker 领取 running --> succeeded: 产出入库 succeeded --> captured: 扣费确认 running --> failed failed --> 待核对: 供应商已受理后失败,冻结保留,界面写「费用待核对」
交互规则
| 环节 | 规则 | 落库 |
|---|---|---|
| 绑定会话 | bindMaa 传 agent_model 或 use_default;先 dispatching,拿到原生会话号后才 bound(约束保证二者一致) | maa_bindings |
| 发消息 | client_action_id 幂等;返回 202 + run_id;同一个动作 ID 内容不同返回 409 | maa_message_actions, maa_runs |
| 事件 | 按 seq 游标读取;服务端先清洗路径、内部地址和令牌再公开 | maa_runs.last_event_seq |
| 完成证据 | 完成时记录助手内容的两份 SHA-256 与字节数 | maa_runs |
| 澄清卡(HITL) | Run 进入 waiting_interaction;respondInteraction 带 card_sha256;不能恢复两次 | maa_interactions, maa_interaction_actions |
| 停止 | stopRun 幂等,回执只说「已观测到终态」;对话里保留「已停止回复」 | maa_run_stop_actions |
| 切换模型 | 必须带 expected_revision;有未决切换时拒绝发新消息 | maa_model_change_actions |
| 生成视频 | from-maa → 报价 → 批准 → 冻结 → worker → 入库 → 扣费;批准带请求哈希与报价哈希 | studio_media_*, 积分账本 |
| 报价过期 | 批准被拒,不建任务不扣费;界面提示重新报价 | studio_media_requests.expires_at |
| 失败后的积分 | 供应商已受理后失败:冻结保留,界面写「费用待核对」,不自动释放;本部署的账本里还没出现过释放分录(12 笔冻结、8 笔扣费、其余 4 笔仍冻结) | studio_credit_ledger_entries |
| 会话过期 | 每 8 秒检查登录状态;失效时横幅提示,登录后恢复 | — |
Creatify · ER 图
品牌库 studio_profile_creatify:24 张表、34 个真实外键、66 个检查约束、22 个触发器。图由实际表结构生成,箭头从父表指向子表。品牌库与共享身份库之间的 owner_id、asset_id 靠应用层归属检查,不画成外键。
共 61 条关系:一对多 37 条,一对一 10 条,一对多(父可选) 10 条,一对一(父可选) 4 条;多对多 2 组(经关联表)。
用户与登录 素材 积分账本 支付与订阅 模型目录 项目与会话 画布 · 时间轴 · 导出 Agent 交互 生成 · 媒体 · 交付
基数标注(线上的文字,箭头从父表指向子表):1:N 一对多,子表外键必填;0..1:N 一对多,但外键可空,所以父是可选的;1:1 一对一,子表外键上有唯一键;0..1:1 一对一且父可选。红色粗双向线 = N:M 多对多,经带 ⇄ 的关联表(它的主键就是两个外键)。实线 = 数据库真实外键;灰色虚线 = 跨库关系(两个库之间数据库无法建外键,由应用层检查);橙色粗框与粗线 = Agent 交互相关。每张表都带 owner_id(指向用户),为了图清楚没有逐条画线。
全景图:全部实体与关系
默认缩放到页面宽度,先看整体结构;点一下图切换到原始大小(看清表名,在框内上下左右滚动),再点一下缩回。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":26,"rankSpacing":80}}}%%
flowchart LR
subgraph sg_i_user["用户与登录"]
direction TB
t_studio_users["users"]
t_studio_sessions["sessions"]
end
subgraph sg_i_asset["素材"]
direction TB
t_studio_assets["assets"]
end
subgraph sg_i_credit["积分账本"]
direction TB
t_studio_credit_accounts["credit_accounts"]
t_studio_credit_lots["credit_lots"]
t_studio_credit_authorizations["credit_authorizations"]
t_studio_credit_authorization_allocations["⇄ credit_authorization_allocations"]
t_studio_credit_ledger_entries["credit_ledger_entries"]
t_studio_credit_plan_versions["credit_plan_versions"]
t_studio_billing_cycles["billing_cycles"]
end
subgraph sg_i_pay["支付与订阅"]
direction TB
t_studio_payment_orders["payment_orders"]
t_studio_payment_events["payment_events"]
t_studio_subscriptions["subscriptions"]
end
subgraph sg_i_model["模型目录"]
direction TB
t_studio_media_models["media_models"]
t_studio_media_model_versions["media_model_versions"]
end
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_canvas["画布 · 时间轴 · 导出"]
direction TB
t_studio_video_documents["video_documents"]
t_studio_canvases["canvases"]
t_studio_canvas_revisions["canvas_revisions"]
t_studio_timeline_revisions["timeline_revisions"]
t_studio_export_jobs["export_jobs"]
t_studio_project_asset_refs["⇄ project_asset_refs"]
end
subgraph sg_agent["⭕ Agent 交互"]
direction TB
t_maa_bindings["maa_bindings"]
t_maa_runs["maa_runs"]
t_maa_message_actions["maa_message_actions"]
t_maa_interactions["maa_interactions"]
t_maa_interaction_actions["maa_interaction_actions"]
t_maa_model_change_actions["maa_model_change_actions"]
t_maa_run_stop_actions["maa_run_stop_actions"]
end
subgraph sg_media["生成 · 媒体 · 交付"]
direction TB
t_studio_media_requests["media_requests"]
t_studio_media_jobs["media_jobs"]
t_studio_media_submission_attempts["media_submission_attempts"]
t_studio_media_outputs["media_outputs"]
t_generation_jobs["gen_jobs"]
t_generation_reservations["gen_reservations"]
t_generation_deliveries["gen_deliveries"]
t_generation_development_budgets["gen_development_budgets"]
t_studio_credit_recovery_intents["credit_recovery_intents"]
end
t_studio_users -->|"1:N"| t_studio_assets
t_studio_payment_orders -->|"1:1"| t_studio_billing_cycles
t_studio_subscriptions -->|"1:N"| t_studio_billing_cycles
t_studio_users -->|"1:1"| t_studio_credit_accounts
t_studio_credit_authorizations -->|"1:N"| t_studio_credit_authorization_allocations
t_studio_credit_lots -->|"1:N"| t_studio_credit_authorization_allocations
t_studio_credit_accounts -->|"1:N"| t_studio_credit_authorizations
t_studio_credit_authorization_allocations -->|"0..1:N"| t_studio_credit_ledger_entries
t_studio_credit_authorizations -->|"0..1:N"| t_studio_credit_ledger_entries
t_studio_credit_lots -->|"1:N"| t_studio_credit_ledger_entries
t_studio_credit_accounts -->|"1:N"| t_studio_credit_lots
t_studio_billing_cycles -->|"0..1:1"| t_studio_credit_lots
t_studio_payment_orders -->|"0..1:1"| t_studio_credit_lots
t_studio_media_models -->|"1:N"| t_studio_media_model_versions
t_studio_media_model_versions -->|"0..1:1"| t_studio_media_models
t_studio_payment_orders -->|"0..1:N"| t_studio_payment_events
t_studio_subscriptions -->|"0..1:N"| t_studio_payment_events
t_studio_users -->|"1:N"| t_studio_payment_events
t_studio_credit_plan_versions -->|"1:N"| t_studio_payment_orders
t_studio_users -->|"1:N"| t_studio_payment_orders
t_studio_users -->|"1:N"| t_studio_sessions
t_studio_credit_plan_versions -->|"1:N"| t_studio_subscriptions
t_studio_users -->|"1:N"| t_studio_subscriptions
t_generation_jobs -->|"1:1"| t_generation_deliveries
t_studio_projects -->|"1:N"| t_generation_deliveries
t_studio_conversations -->|"1:N"| t_generation_deliveries
t_generation_development_budgets -->|"1:N"| t_generation_jobs
t_studio_projects -->|"1:N"| t_generation_jobs
t_studio_conversations -->|"1:N"| t_generation_jobs
t_generation_jobs -->|"1:1"| t_generation_reservations
t_studio_conversations -->|"1:1"| t_maa_bindings
t_maa_model_change_actions -->|"0..1:1"| t_maa_bindings
t_maa_interactions -->|"1:1"| t_maa_interaction_actions
t_maa_runs -->|"1:N"| t_maa_interactions
t_maa_bindings -->|"1:N"| t_maa_message_actions
t_maa_runs -->|"0..1:N"| t_maa_message_actions
t_maa_bindings -->|"1:N"| t_maa_model_change_actions
t_maa_runs -->|"1:1"| t_maa_run_stop_actions
t_maa_bindings -->|"1:N"| t_maa_runs
t_studio_canvases -->|"1:N"| t_studio_canvas_revisions
t_studio_canvas_revisions -->|"0..1:N"| t_studio_canvas_revisions
t_studio_projects -->|"1:1"| t_studio_canvases
t_studio_projects -->|"1:N"| t_studio_conversations
t_studio_media_jobs -->|"1:N"| t_studio_credit_recovery_intents
t_studio_projects -->|"1:N"| t_studio_export_jobs
t_studio_media_requests -->|"1:1"| t_studio_media_jobs
t_studio_media_jobs -->|"1:N"| t_studio_media_outputs
t_studio_conversations -->|"1:N"| t_studio_media_requests
t_maa_runs -->|"0..1:N"| t_studio_media_requests
t_studio_media_jobs -->|"1:N"| t_studio_media_submission_attempts
t_studio_projects -->|"1:N"| t_studio_project_asset_refs
t_studio_video_documents -->|"1:N"| t_studio_timeline_revisions
t_studio_timeline_revisions -->|"0..1:N"| t_studio_timeline_revisions
t_studio_projects -->|"1:1"| t_studio_video_documents
t_studio_assets -.->|"1:N"| t_studio_project_asset_refs
t_studio_assets -.->|"1:N"| t_studio_media_outputs
t_studio_assets -.->|"1:N"| t_generation_deliveries
t_studio_media_model_versions -.->|"1:N"| t_studio_media_requests
t_studio_media_models -.->|"1:N"| t_studio_media_requests
t_studio_credit_authorizations -.->|"0..1:N"| t_studio_media_jobs
t_studio_credit_authorizations -.->|"0..1:N"| t_studio_credit_recovery_intents
t_studio_credit_authorizations <-.->|"N:M · 经 credit_authorization_allocations"| t_studio_credit_lots
t_studio_projects <-.->|"N:M · 经 project_asset_refs"| t_studio_assets
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_users,t_studio_sessions user
class t_studio_assets asset
class t_studio_credit_accounts,t_studio_credit_lots,t_studio_credit_authorizations,t_studio_credit_authorization_allocations,t_studio_credit_ledger_entries,t_studio_credit_plan_versions,t_studio_billing_cycles credit
class t_studio_payment_orders,t_studio_payment_events,t_studio_subscriptions pay
class t_studio_media_models,t_studio_media_model_versions model
class t_studio_projects,t_studio_conversations project
class t_studio_video_documents,t_studio_canvases,t_studio_canvas_revisions,t_studio_timeline_revisions,t_studio_export_jobs,t_studio_project_asset_refs canvas
class t_maa_bindings,t_maa_runs,t_maa_message_actions,t_maa_interactions,t_maa_interaction_actions,t_maa_model_change_actions,t_maa_run_stop_actions agent
class t_studio_media_requests,t_studio_media_jobs,t_studio_media_submission_attempts,t_studio_media_outputs,t_generation_jobs,t_generation_reservations,t_generation_deliveries,t_generation_development_budgets,t_studio_credit_recovery_intents media
class t_studio_credit_authorization_allocations,t_studio_project_asset_refs junction
style sg_i_user fill:none,stroke:#6b7280,stroke-width:1px,stroke-dasharray:5 4
style sg_i_asset fill:none,stroke:#06b6d4,stroke-width:1px,stroke-dasharray:5 4
style sg_i_credit fill:none,stroke:#eab308,stroke-width:1px,stroke-dasharray:5 4
style sg_i_pay fill:none,stroke:#ec4899,stroke-width:1px,stroke-dasharray:5 4
style sg_i_model fill:none,stroke:#6366f1,stroke-width:1px,stroke-dasharray:5 4
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_canvas fill:none,stroke:#3b82f6,stroke-width:1px
style sg_agent fill:#fff7ed,stroke:#f97316,stroke-width:4px
style sg_media fill:none,stroke:#22c55e,stroke-width:1px
linkStyle 30,31,32,33,34,35,36,37,38,48 stroke:#f97316,stroke-width:2.5px
linkStyle 54,55,56,57,58,59,60 stroke:#64748b,stroke-width:1.5px,stroke-dasharray:4 3
linkStyle 61,62 stroke:#dc2626,stroke-width:3px多对多(N:M)
数据库里没有“多对多”这种列,它总是靠一张关联表表达。下面这几张表的主键由两个外键组成,所以它们两端是多对多:
| 多对多的两端 | 关联表 | 关联表的主键 / 唯一键 |
|---|---|---|
studio_credit_authorizations ⇄ studio_credit_lots | studio_credit_authorization_allocations | owner_id, authorization_id, lot_id |
studio_projects ⇄ studio_assets | studio_project_asset_refs | project_id, asset_id |
Agent 交互相关(圈出来)
绑定 → Run → 消息 / 澄清卡 / 切换模型 / 停止,每个动作一张回执表;线上是“外键列 · 基数”。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":40,"rankSpacing":90}}}%%
flowchart LR
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_agent["⭕ Agent 交互"]
direction TB
t_maa_bindings["maa_bindings"]
t_maa_runs["maa_runs"]
t_maa_message_actions["maa_message_actions"]
t_maa_interactions["maa_interactions"]
t_maa_interaction_actions["maa_interaction_actions"]
t_maa_model_change_actions["maa_model_change_actions"]
t_maa_run_stop_actions["maa_run_stop_actions"]
end
t_studio_conversations -->|"conversation_id · 1:1"| t_maa_bindings
t_maa_model_change_actions -->|"pending_model_change_id · 0..1:1"| t_maa_bindings
t_maa_interactions -->|"interaction_id · 1:1"| t_maa_interaction_actions
t_maa_runs -->|"public_run_id · 1:N"| t_maa_interactions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_message_actions
t_maa_runs -->|"public_run_id · 0..1:N"| t_maa_message_actions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_model_change_actions
t_maa_runs -->|"public_run_id · 1:1"| t_maa_run_stop_actions
t_maa_bindings -->|"binding_id · 1:N"| t_maa_runs
t_studio_projects -->|"project_id · 1:N"| t_studio_conversations
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_projects,t_studio_conversations project
class t_maa_bindings,t_maa_runs,t_maa_message_actions,t_maa_interactions,t_maa_interaction_actions,t_maa_model_change_actions,t_maa_run_stop_actions agent
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_agent fill:#fff7ed,stroke:#f97316,stroke-width:4px
linkStyle 0,1,2,3,4,5,6,7,8 stroke:#f97316,stroke-width:2.5px画布与时间轴
项目下是一份视频文档,画布、画布版本、时间线版本和导出都挂在这份文档上;素材放在共享身份库,项目只记引用,项目与素材是多对多,经 project_asset_refs。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":40,"rankSpacing":90}}}%%
flowchart LR
subgraph sg_project["项目与会话"]
direction TB
t_studio_projects["projects"]
t_studio_conversations["conversations"]
end
subgraph sg_canvas["画布 · 时间轴 · 导出"]
direction TB
t_studio_video_documents["video_documents"]
t_studio_canvases["canvases"]
t_studio_canvas_revisions["canvas_revisions"]
t_studio_timeline_revisions["timeline_revisions"]
t_studio_export_jobs["export_jobs"]
t_studio_project_asset_refs["⇄ project_asset_refs"]
end
subgraph sg_asset["素材(共享身份库)"]
direction TB
t_studio_assets["assets"]
end
t_studio_canvases -->|"project_id · 1:N"| t_studio_canvas_revisions
t_studio_canvas_revisions -->|"restored_from_revision · 0..1:N"| t_studio_canvas_revisions
t_studio_projects -->|"project_id · 1:1"| t_studio_canvases
t_studio_projects -->|"project_id · 1:N"| t_studio_conversations
t_studio_projects -->|"project_id · 1:N"| t_studio_export_jobs
t_studio_projects -->|"project_id · 1:N"| t_studio_project_asset_refs
t_studio_video_documents -->|"project_id · 1:N"| t_studio_timeline_revisions
t_studio_timeline_revisions -->|"restored_from_revision · 0..1:N"| t_studio_timeline_revisions
t_studio_projects -->|"project_id · 1:1"| t_studio_video_documents
t_studio_assets -.->|"asset_id · 1:N"| t_studio_project_asset_refs
t_studio_projects <-.->|"N:M · 经 project_asset_refs"| t_studio_assets
classDef project fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef canvas fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef media fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef user fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef credit fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef pay fill:#fce7f3,stroke:#ec4899,color:#111,stroke-width:1.5px
classDef model fill:#e0e7ff,stroke:#6366f1,color:#111,stroke-width:1.5px
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_studio_projects,t_studio_conversations project
class t_studio_video_documents,t_studio_canvases,t_studio_canvas_revisions,t_studio_timeline_revisions,t_studio_export_jobs,t_studio_project_asset_refs canvas
class t_studio_assets asset
class t_studio_project_asset_refs junction
style sg_project fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_canvas fill:none,stroke:#3b82f6,stroke-width:1px
style sg_asset fill:none,stroke:#06b6d4,stroke-width:1px
linkStyle 9 stroke:#64748b,stroke-width:1.5px,stroke-dasharray:4 3
linkStyle 10 stroke:#dc2626,stroke-width:3px关系清单 逐条 61 条,含基数
| 父表 | 子表 | 外键列(子表里) | 基数 | 约束 | 域 |
|---|---|---|---|---|---|
generation_jobs | generation_deliveries | job_id | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_assets | generation_deliveries | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 生成 · 媒体 · 交付 |
studio_conversations | generation_deliveries | owner_id, project_id, session_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_projects | generation_deliveries | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
generation_development_budgets | generation_jobs | owner_id, budget_id | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_conversations | generation_jobs | owner_id, project_id, session_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_projects | generation_jobs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
generation_jobs | generation_reservations | job_id, budget_id, owner_id | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
maa_model_change_actions | maa_bindings | owner_id, project_id, conversation_id, id, pending_model_change_id | 0..1:1 一对一(父可选) | DB 外键 | Agent 交互 → Agent 交互 |
studio_conversations | maa_bindings | owner_id, project_id, conversation_id | 1:1 一对一 | DB 外键 | 项目与会话 → Agent 交互 |
maa_interactions | maa_interaction_actions | owner_id, project_id, conversation_id, binding_id, public_run_id, interaction_id | 1:1 一对一 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_interactions | owner_id, project_id, conversation_id, binding_id, public_run_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_message_actions | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_message_actions | owner_id, project_id, conversation_id, binding_id, public_run_id | 0..1:N 一对多(父可选) | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_model_change_actions | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
maa_runs | maa_run_stop_actions | owner_id, project_id, conversation_id, binding_id, public_run_id | 1:1 一对一 | DB 外键 | Agent 交互 → Agent 交互 |
maa_bindings | maa_runs | owner_id, project_id, conversation_id, binding_id | 1:N 一对多 | DB 外键 | Agent 交互 → Agent 交互 |
studio_users | studio_assets | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 素材 |
studio_payment_orders | studio_billing_cycles | owner_id, payment_order_id, plan_version_id | 1:1 一对一 | DB 外键 | 支付与订阅 → 积分账本 |
studio_subscriptions | studio_billing_cycles | owner_id, subscription_id, provider_key, provider_account | 1:N 一对多 | DB 外键 | 支付与订阅 → 积分账本 |
studio_canvas_revisions | studio_canvas_revisions | owner_id, project_id, kind, restored_from_revision | 0..1:N 一对多(父可选) | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_canvases | studio_canvas_revisions | owner_id, project_id | 1:N 一对多 | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_projects | studio_canvases | owner_id, project_id | 1:1 一对一 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_projects | studio_conversations | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 项目与会话 |
studio_users | studio_credit_accounts | owner_id | 1:1 一对一 | DB 外键 | 用户与登录 → 积分账本 |
studio_credit_authorizations | studio_credit_authorization_allocations | owner_id, authorization_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_lots | studio_credit_authorization_allocations | owner_id, lot_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_accounts | studio_credit_authorizations | owner_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_credit_authorization_allocations | studio_credit_ledger_entries | owner_id, authorization_id, lot_id | 0..1:N 一对多(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_authorizations | studio_credit_ledger_entries | owner_id, authorization_id | 0..1:N 一对多(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_lots | studio_credit_ledger_entries | owner_id, lot_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_billing_cycles | studio_credit_lots | owner_id, source_cycle_id | 0..1:1 一对一(父可选) | DB 外键 | 积分账本 → 积分账本 |
studio_credit_accounts | studio_credit_lots | owner_id | 1:N 一对多 | DB 外键 | 积分账本 → 积分账本 |
studio_payment_orders | studio_credit_lots | owner_id, source_order_id | 0..1:1 一对一(父可选) | DB 外键 | 支付与订阅 → 积分账本 |
studio_credit_authorizations | studio_credit_recovery_intents | authorization_id | 0..1:N 一对多(父可选) | 跨库(应用层检查) | 积分账本 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_credit_recovery_intents | owner_id, project_id, conversation_id, job_id, request_sha256 | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_projects | studio_export_jobs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_credit_authorizations | studio_media_jobs | credit_authorization_id | 0..1:N 一对多(父可选) | 跨库(应用层检查) | 积分账本 → 生成 · 媒体 · 交付 |
studio_media_requests | studio_media_jobs | owner_id, project_id, conversation_id, request_id, request_sha256, quote_sha256 | 1:1 一对一 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_media_models | studio_media_model_versions | model_id | 1:N 一对多 | DB 外键 | 模型目录 → 模型目录 |
studio_media_model_versions | studio_media_models | id, published_version_id | 0..1:1 一对一(父可选) | DB 外键 | 模型目录 → 模型目录 |
studio_assets | studio_media_outputs | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_media_outputs | owner_id, project_id, conversation_id, job_id | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
maa_runs | studio_media_requests | owner_id, project_id, conversation_id, source_binding_id, source_run_id | 0..1:N 一对多(父可选) | DB 外键 | Agent 交互 → 生成 · 媒体 · 交付 |
studio_conversations | studio_media_requests | owner_id, project_id, conversation_id | 1:N 一对多 | DB 外键 | 项目与会话 → 生成 · 媒体 · 交付 |
studio_media_model_versions | studio_media_requests | model_version_id | 1:N 一对多 | 跨库(应用层检查) | 模型目录 → 生成 · 媒体 · 交付 |
studio_media_models | studio_media_requests | model_id | 1:N 一对多 | 跨库(应用层检查) | 模型目录 → 生成 · 媒体 · 交付 |
studio_media_jobs | studio_media_submission_attempts | owner_id, project_id, conversation_id, job_id, request_sha256 | 1:N 一对多 | DB 外键 | 生成 · 媒体 · 交付 → 生成 · 媒体 · 交付 |
studio_payment_orders | studio_payment_events | owner_id, order_id, provider_key, provider_account | 0..1:N 一对多(父可选) | DB 外键 | 支付与订阅 → 支付与订阅 |
studio_subscriptions | studio_payment_events | owner_id, subscription_id, provider_key, provider_account | 0..1:N 一对多(父可选) | DB 外键 | 支付与订阅 → 支付与订阅 |
studio_users | studio_payment_events | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_credit_plan_versions | studio_payment_orders | plan_version_id | 1:N 一对多 | DB 外键 | 积分账本 → 支付与订阅 |
studio_users | studio_payment_orders | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_assets | studio_project_asset_refs | asset_id | 1:N 一对多 | 跨库(应用层检查) | 素材 → 画布 · 时间轴 · 导出 |
studio_projects | studio_project_asset_refs | owner_id, project_id | 1:N 一对多 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
studio_users | studio_sessions | user_id | 1:N 一对多 | DB 外键 | 用户与登录 → 用户与登录 |
studio_credit_plan_versions | studio_subscriptions | plan_version_id | 1:N 一对多 | DB 外键 | 积分账本 → 支付与订阅 |
studio_users | studio_subscriptions | owner_id | 1:N 一对多 | DB 外键 | 用户与登录 → 支付与订阅 |
studio_timeline_revisions | studio_timeline_revisions | owner_id, project_id, kind, restored_from_revision | 0..1:N 一对多(父可选) | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_video_documents | studio_timeline_revisions | owner_id, project_id | 1:N 一对多 | DB 外键 | 画布 · 时间轴 · 导出 → 画布 · 时间轴 · 导出 |
studio_projects | studio_video_documents | owner_id, project_id | 1:1 一对一 | DB 外键 | 项目与会话 → 画布 · 时间轴 · 导出 |
完整 ER:39 张表的全部列,带主键 / 外键与基数符号(鸦脚)
erDiagram
studio_assets {
CHAR id PK
CHAR owner_id FK
CHAR sha256
JSON metadata_json
VARCHAR storage_key
DATETIME created_at
VARCHAR publication_state
}
studio_billing_cycles {
CHAR id PK
CHAR owner_id FK
CHAR subscription_id FK
CHAR plan_version_id FK
CHAR payment_order_id FK
VARCHAR provider_key FK
VARCHAR provider_account FK
VARCHAR provider_invoice_id
DATETIME period_start
DATETIME period_end
BIGINT_UNSIGNED grant_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
VARCHAR state
CHAR paid_evidence_sha256
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_accounts {
CHAR owner_id PK
VARCHAR unit
VARCHAR status
BIGINT_UNSIGNED revision
DATETIME updated_at
}
studio_credit_authorization_allocations {
CHAR owner_id FK
CHAR authorization_id PK
CHAR lot_id PK
BIGINT_UNSIGNED allocated_credits
DATETIME created_at
}
studio_credit_authorizations {
CHAR id PK
CHAR owner_id FK
VARCHAR profile
CHAR project_id
CHAR conversation_id
CHAR job_id
CHAR request_id
CHAR request_sha256
CHAR quote_sha256
BIGINT_UNSIGNED credits
DATETIME expires_at
MEDIUMBLOB reservation_bytes
CHAR reservation_sha256
MEDIUMBLOB policy_bytes
CHAR policy_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_ledger_entries {
CHAR id PK
CHAR owner_id FK
CHAR lot_id FK
CHAR authorization_id FK
VARCHAR operation_key
VARCHAR kind
BIGINT grant_delta
BIGINT held_delta
BIGINT captured_delta
MEDIUMBLOB facts_bytes
CHAR facts_sha256
DATETIME created_at
}
studio_credit_lots {
CHAR id PK
CHAR owner_id FK
BIGINT_UNSIGNED grant_credits
BIGINT_UNSIGNED held_credits
BIGINT_UNSIGNED captured_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
CHAR source_order_id FK
CHAR source_cycle_id FK
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_credit_plan_versions {
CHAR id PK
VARCHAR plan_key
VARCHAR version_key
VARCHAR kind
BIGINT_UNSIGNED price_minor
CHAR currency
BIGINT_UNSIGNED grant_credits
INT_UNSIGNED credit_validity_seconds
INT_UNSIGNED billing_interval_months
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
DATETIME published_at
DATETIME retired_at
}
studio_media_model_versions {
CHAR id PK
CHAR model_id FK
VARCHAR version_key
MEDIUMBLOB config_bytes
CHAR config_sha256
DATETIME published_at
}
studio_media_models {
CHAR id PK
VARCHAR model_key
VARCHAR kind
VARCHAR display_name
VARCHAR status
CHAR published_version_id FK
BIGINT_UNSIGNED revision
DATETIME updated_at
}
studio_payment_events {
CHAR id PK
CHAR owner_id FK
VARCHAR provider_key FK
VARCHAR provider_account FK
VARCHAR provider_event_id
CHAR order_id FK
CHAR subscription_id FK
MEDIUMBLOB body_bytes
CHAR body_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_payment_orders {
CHAR id PK
CHAR owner_id FK
CHAR client_action_id
CHAR plan_version_id FK
BIGINT_UNSIGNED price_minor
CHAR currency
BIGINT_UNSIGNED grant_credits
DATETIME valid_from
DATETIME expires_at
MEDIUMBLOB eligibility_bytes
CHAR eligibility_sha256
VARCHAR provider_key
VARCHAR provider_account
VARCHAR provider_idempotency_key
VARCHAR provider_order_id
VARCHAR state
CHAR paid_evidence_sha256
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_sessions {
CHAR token_hash PK
CHAR user_id FK
DATETIME created_at
DATETIME expires_at
DATETIME revoked_at
}
studio_subscriptions {
CHAR id PK
CHAR owner_id FK
VARCHAR provider_key
VARCHAR provider_account
VARCHAR provider_subscription_id
CHAR plan_version_id FK
VARCHAR state
DATETIME period_start
DATETIME period_end
TINYINT cancel_at_period_end
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_users {
CHAR id PK
VARCHAR email
VARBINARY password_hash
TINYINT enabled
DATETIME created_at
}
generation_deliveries {
CHAR job_id PK
CHAR owner_id FK
CHAR project_id FK
CHAR session_id FK
CHAR asset_id FK
CHAR request_sha256
CHAR maa_source_sha256
CHAR provider_source_sha256
VARCHAR model
VARCHAR tool_name
CHAR input_sha256
JSON metadata_json
DATETIME created_at
}
generation_development_budgets {
CHAR id PK
CHAR owner_id
VARCHAR policy_version
BIGINT_UNSIGNED credits_limit
BIGINT_UNSIGNED credits_reserved
INT_UNSIGNED calls_limit
INT_UNSIGNED calls_reserved
DATETIME expires_at
}
generation_jobs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR session_id FK
CHAR native_conversation_id
CHAR native_run_id
CHAR source_sha256
CHAR budget_id FK
MEDIUMBLOB request_bytes
CHAR request_sha256
BIGINT_UNSIGNED credits
DATETIME expires_at
VARCHAR status
INT_UNSIGNED attempts
MEDIUMBLOB result_bytes
DATETIME updated_at
}
generation_reservations {
CHAR job_id PK
CHAR budget_id FK
CHAR owner_id FK
BIGINT_UNSIGNED credits
INT_UNSIGNED calls
VARCHAR status
}
maa_bindings {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR provider
VARCHAR model_name
VARCHAR status
VARCHAR native_cid
DATETIME created_at
BIGINT_UNSIGNED model_revision
CHAR pending_model_change_id FK
}
maa_interaction_actions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR interaction_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_iid
CHAR client_action_id
CHAR card_sha256
CHAR request_sha256
CHAR content_sha256
VARCHAR response_action
JSON values_payload
VARCHAR status
DATETIME created_at
}
maa_interactions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_iid
CHAR card_sha256
JSON card_payload
DATETIME created_at
}
maa_message_actions {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR client_action_id
CHAR request_sha256
MEDIUMTEXT content
VARCHAR status
CHAR public_run_id FK
CHAR proposed_run_id
DATETIME created_at
}
maa_model_change_actions {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_cid
CHAR client_action_id
CHAR request_sha256
CHAR native_request_sha256
BIGINT_UNSIGNED expected_revision
VARCHAR from_provider
VARCHAR from_model_name
VARCHAR target_provider
VARCHAR target_model_name
VARCHAR status
BIGINT_UNSIGNED dispatch_attempt
JSON receipt_payload
DATETIME created_at
DATETIME updated_at
}
maa_run_stop_actions {
CHAR id PK
CHAR binding_id FK
CHAR public_run_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_cid
VARCHAR native_rid
CHAR client_action_id
CHAR request_sha256
VARCHAR stop_action
VARCHAR status
BIGINT_UNSIGNED attempt
VARCHAR terminal_run_status
DATETIME created_at
DATETIME updated_at
}
maa_runs {
CHAR id PK
CHAR binding_id FK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
VARCHAR native_rid
VARCHAR status
DATETIME created_at
CHAR native_assistant_sha256
CHAR public_assistant_sha256
BIGINT_UNSIGNED native_assistant_bytes
BIGINT_UNSIGNED assistant_event_seq
BIGINT_UNSIGNED last_event_seq
}
studio_canvas_revisions {
CHAR owner_id PK
CHAR project_id PK
VARCHAR kind PK
BIGINT_UNSIGNED revision PK
MEDIUMBLOB state_bytes
CHAR state_sha256
VARCHAR origin
BIGINT_UNSIGNED restored_from_revision FK
DATETIME recorded_at
}
studio_canvases {
CHAR project_id PK
CHAR owner_id FK
BIGINT_UNSIGNED revision
JSON state_json
DATETIME updated_at
}
studio_conversations {
CHAR id PK
CHAR project_id FK
CHAR owner_id FK
VARCHAR title
DATETIME created_at
}
studio_credit_recovery_intents {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
CHAR request_sha256 FK
CHAR quote_sha256
VARCHAR kind
CHAR authorization_id FK
MEDIUMBLOB intent_bytes
CHAR intent_sha256
VARCHAR state
CHAR lease_token_sha256
DATETIME lease_until
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
}
studio_export_jobs {
CHAR id PK
CHAR project_id FK
CHAR owner_id FK
BIGINT_UNSIGNED document_revision
CHAR input_hash
VARCHAR status
JSON input_json
JSON output_json
VARCHAR error_code
CHAR lease_token_hash
DATETIME lease_until
INT_UNSIGNED attempts
DATETIME created_at
DATETIME updated_at
}
studio_media_jobs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR request_id FK
CHAR request_sha256 FK
CHAR quote_sha256 FK
CHAR client_approval_id
CHAR approval_sha256
CHAR credit_authorization_id FK
VARCHAR authorization_mode
DATETIME authorization_expires_at
VARCHAR status
BIGINT_UNSIGNED revision
CHAR lease_token_sha256
DATETIME lease_until
VARCHAR provider_task_id
CHAR client_cancel_id
CHAR cancel_request_sha256
DATETIME cancel_requested_at
CHAR staged_asset_id
CHAR staged_asset_sha256
DATETIME created_at
DATETIME updated_at
}
studio_media_outputs {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
INT_UNSIGNED ordinal
CHAR asset_id FK
CHAR asset_sha256
CHAR asset_metadata_sha256
CHAR provider_result_sha256
DATETIME created_at
}
studio_media_requests {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR client_request_id
CHAR model_id FK
CHAR model_version_id FK
CHAR model_config_sha256
MEDIUMBLOB request_bytes
CHAR request_sha256
MEDIUMBLOB quote_bytes
CHAR quote_sha256
BIGINT_UNSIGNED quoted_credits
DATETIME expires_at
VARCHAR origin
CHAR source_binding_id FK
CHAR source_run_id FK
CHAR source_assistant_sha256
MEDIUMBLOB source_snapshot_bytes
DATETIME created_at
}
studio_media_submission_attempts {
CHAR id PK
CHAR owner_id FK
CHAR project_id FK
CHAR conversation_id FK
CHAR job_id FK
INT_UNSIGNED attempt_no
CHAR request_sha256 FK
VARCHAR provider_idempotency_key
VARCHAR stage
DATETIME dispatch_started_at
VARCHAR provider_task_id
CHAR receipt_sha256
CHAR terminal_receipt_sha256
CHAR reconciliation_sha256
DATETIME created_at
DATETIME updated_at
}
studio_project_asset_refs {
CHAR project_id PK
CHAR owner_id FK
CHAR asset_id PK
CHAR asset_sha256
CHAR asset_metadata_sha256
VARCHAR state
BIGINT_UNSIGNED revision
DATETIME created_at
DATETIME updated_at
DATETIME detached_at
}
studio_projects {
CHAR id PK
CHAR owner_id
VARCHAR title
DATETIME created_at
}
studio_timeline_revisions {
CHAR owner_id PK
CHAR project_id PK
VARCHAR kind PK
BIGINT_UNSIGNED revision PK
MEDIUMBLOB state_bytes
CHAR state_sha256
VARCHAR origin
BIGINT_UNSIGNED restored_from_revision FK
DATETIME recorded_at
}
studio_video_documents {
CHAR project_id PK
CHAR owner_id FK
BIGINT_UNSIGNED revision
JSON state_json
DATETIME updated_at
}
studio_users ||--o{ studio_assets : "owner_id"
studio_payment_orders ||--o| studio_billing_cycles : "plan_version_id"
studio_subscriptions ||--o{ studio_billing_cycles : "provider_account"
studio_users ||--o| studio_credit_accounts : "owner_id"
studio_credit_authorizations ||--o{ studio_credit_authorization_allocations : "authorization_id"
studio_credit_lots ||--o{ studio_credit_authorization_allocations : "lot_id"
studio_credit_accounts ||--o{ studio_credit_authorizations : "owner_id"
studio_credit_authorization_allocations |o--o{ studio_credit_ledger_entries : "lot_id"
studio_credit_authorizations |o--o{ studio_credit_ledger_entries : "authorization_id"
studio_credit_lots ||--o{ studio_credit_ledger_entries : "lot_id"
studio_credit_accounts ||--o{ studio_credit_lots : "owner_id"
studio_billing_cycles |o--o| studio_credit_lots : "source_cycle_id"
studio_payment_orders |o--o| studio_credit_lots : "source_order_id"
studio_media_models ||--o{ studio_media_model_versions : "model_id"
studio_media_model_versions |o--o| studio_media_models : "published_version_id"
studio_payment_orders |o--o{ studio_payment_events : "provider_account"
studio_subscriptions |o--o{ studio_payment_events : "provider_account"
studio_users ||--o{ studio_payment_events : "owner_id"
studio_credit_plan_versions ||--o{ studio_payment_orders : "plan_version_id"
studio_users ||--o{ studio_payment_orders : "owner_id"
studio_users ||--o{ studio_sessions : "user_id"
studio_credit_plan_versions ||--o{ studio_subscriptions : "plan_version_id"
studio_users ||--o{ studio_subscriptions : "owner_id"
generation_jobs ||--o| generation_deliveries : "job_id"
studio_projects ||--o{ generation_deliveries : "project_id"
studio_conversations ||--o{ generation_deliveries : "session_id"
generation_development_budgets ||--o{ generation_jobs : "budget_id"
studio_projects ||--o{ generation_jobs : "project_id"
studio_conversations ||--o{ generation_jobs : "session_id"
generation_jobs ||--o| generation_reservations : "budget_id"
studio_conversations ||--o| maa_bindings : "conversation_id"
maa_model_change_actions |o--o| maa_bindings : "pending_model_change_id"
maa_interactions ||--o| maa_interaction_actions : "interaction_id"
maa_runs ||--o{ maa_interactions : "public_run_id"
maa_bindings ||--o{ maa_message_actions : "binding_id"
maa_runs |o--o{ maa_message_actions : "public_run_id"
maa_bindings ||--o{ maa_model_change_actions : "binding_id"
maa_runs ||--o| maa_run_stop_actions : "public_run_id"
maa_bindings ||--o{ maa_runs : "binding_id"
studio_canvases ||--o{ studio_canvas_revisions : "project_id"
studio_canvas_revisions |o--o{ studio_canvas_revisions : "restored_from_revision"
studio_projects ||--o| studio_canvases : "project_id"
studio_projects ||--o{ studio_conversations : "project_id"
studio_media_jobs ||--o{ studio_credit_recovery_intents : "job_id"
studio_projects ||--o{ studio_export_jobs : "project_id"
studio_media_requests ||--o| studio_media_jobs : "request_id"
studio_media_jobs ||--o{ studio_media_outputs : "job_id"
studio_conversations ||--o{ studio_media_requests : "conversation_id"
maa_runs |o--o{ studio_media_requests : "source_run_id"
studio_media_jobs ||--o{ studio_media_submission_attempts : "job_id"
studio_projects ||--o{ studio_project_asset_refs : "project_id"
studio_video_documents ||--o{ studio_timeline_revisions : "project_id"
studio_timeline_revisions |o--o{ studio_timeline_revisions : "restored_from_revision"
studio_projects ||--o| studio_video_documents : "project_id"
studio_assets ||--o{ studio_project_asset_refs : "asset_id"
studio_assets ||--o{ studio_media_outputs : "asset_id"
studio_assets ||--o{ generation_deliveries : "asset_id"
studio_media_model_versions ||--o{ studio_media_requests : "model_version_id"
studio_media_models ||--o{ studio_media_requests : "model_id"
studio_credit_authorizations |o--o{ studio_media_jobs : "credit_authorization_id"
studio_credit_authorizations |o--o{ studio_credit_recovery_intents : "authorization_id"自动生成的整体图(按真实表结构,备查)
共享身份库 ER 图
实测验证与设计原因 七个品牌相同,展开查看
实测验证(本机 MySQL 实库)
对照本机真实运行的数据库 studio_profile_creatify 和 studio_platform_identity,逐项核对本页的表、列、关系与说明。18 / 18 项通过。
查看全部核对项
| 核对项 | 结果 |
|---|---|
| 表数 = 发布值 24 | 通过 |
| 列数 = 289 | 通过 |
| 外键数 = 34 | 通过 |
| 检查约束数 = 66 | 通过 |
| 触发器数 = 22 | 通过 |
| 索引数(含主键) = 85 | 通过 |
| 列定义与 pollo 逐列一致 | 通过 |
| 外键与 pollo 完全一致 | 通过 |
| 索引与 pollo 一致 | 通过 |
| 触发器与 pollo 一致 | 通过 |
| 外键 CSV 行数 = 实库外键数 | 通过 |
| mmd 实体 = 实库表 | 通过 |
| svg 标题 24 tables / 34 actual foreign keys = 实库 | 通过 |
| 参考 SQL 表集合与列顺序 = 实库 | 通过 |
| 15 张表 | 通过 |
| 外键 CSV 行数 = 实库外键数 | 通过 |
| svg 标题与实库一致 | 通过 |
| 参考 SQL 表集合与列顺序 = 实库 | 通过 |
实库里的关系是这样的
- 34 个外键里 31 个是复合外键,且都带着 owner_id,其余 3 个是单列外键;22 张子表都带 owner 外键。所以一行数据不可能指向别的用户的项目或会话。
- 删除与更新规则全部是 RESTRICT / NO ACTION,没有任何级联:被引用的行不能被删除。
- 品牌库与共享身份库之间的关系(owner_id、asset_id、model_id + model_version_id)没有数据库外键,靠应用层检查;我们逐表核对了现有数据,没有孤儿。
主动破坏测试(在事务里尝试,全部回滚)
| 尝试 | 数据库的反应 |
|---|---|
| 外键:导出任务.project_id 改成不存在的项目被拒绝 | 拒绝 |
| 复合外键:项目素材引用.project_id 改成别的用户的项目被拒绝(owner 与 project 必须成对) | 拒绝 |
| 触发器:已提交的消息动作不可改写 | 拒绝 |
| 触发器:媒体产出不可改写 | 拒绝 |
| 外键 RESTRICT:被会话引用的项目不能删除 | 拒绝 |
| 复合外键:被引用的会话不能把 owner 改成别人 | 拒绝 |
| 检查约束:Run 状态只能是约定的六个值 | 拒绝 |
| 触发器:账本分录不可修改 | 拒绝 |
| 触发器:账本分录不可删除 | 拒绝 |
Creatify · 表结构
MySQL 8,字符集 utf8mb4,ID 为 char(36) ascii_bin。点击展开 DDL。
按职责分组
项目与会话 2 张
studio_projects:用户拥有的创作项目studio_conversations:项目内的对话会话
Agent执行与并发控制 7 张
maa_bindings:业务会话与Native Maa会话映射、模型版本与未决操作maa_runs:公开Run映射、状态与原生/公开助手证据摘要maa_message_actions:原消息动作及幂等回执maa_interactions:澄清卡片及Run归属maa_interaction_actions:原卡片回答/取消动作maa_model_change_actions:带预期模型版本的切换动作maa_run_stop_actions:停止原Run的幂等动作与观测终态
画布、时间轴与素材引用 5 张
studio_canvases:项目当前画布文档studio_canvas_revisions:历史画布修订studio_video_documents:项目当前时间轴文档studio_timeline_revisions:历史时间轴修订studio_project_asset_refs:项目对用户级素材的引用;不复制素材所有权
媒体生成、结算恢复与导出 6 张
studio_media_requests:用户输入/Agent来源、报价、批准摘要与准入确认studio_media_jobs:已批准媒体任务及状态机studio_media_submission_attempts:一次提交的任务证据与不确定结果studio_media_outputs:受验证的输出与素材映射studio_credit_recovery_intents:积分结算恢复意图;不是用户钱包全账本studio_export_jobs:时间轴导出队列和发布输出
既有generation兼容路径 22 张
generation_jobs:既有generation任务,不等同新PublicMedia任务generation_reservations:既有任务费用预留generation_development_budgets:既有开发测试预算generation_deliveries:既有生成交付回执owner_id:归属用户;不是允许跨用户查询的参数。model_revision:并发准入版本;数据库默认0不能代替Native权威读回。pending_model_change_id:未决模型切换引用,阻止其他writer绕过。studio_users:用户账号记录;不导出密码哈希或任何业务行studio_sessions:登录会话;这里只公开字段结构,不公开会话值studio_assets:用户级素材元数据与存储键结构,项目仅引用素材IDstudio_media_models:公开媒体模型目录结构studio_media_model_versions:媒体模型不可变版本/计价能力结构studio_subscriptions:订阅状态持久化studio_billing_cycles:订阅账期studio_payment_orders:订单记录studio_payment_events:支付事件幂等记录;不代表已有公开支付路由studio_credit_accounts:用户积分账户studio_credit_lots:积分批次studio_credit_authorizations:费用预留与结算授权studio_credit_authorization_allocations:授权对批次的分配studio_credit_ledger_entries:积分流水studio_credit_plan_versions:积分方案不可变版本
品牌库 studio_profile_creatify(24 张)
generation_deliveries 既有生成交付回执
CREATE TABLE `generation_deliveries` ( `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `session_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `maa_source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `tool_name` varchar(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `input_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `metadata_json` json NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`job_id`), KEY `generation_delivery_owner_project` (`owner_id`,`project_id`,`session_id`,`job_id`), KEY `generation_delivery_owned_asset` (`owner_id`,`asset_id`), KEY `generation_delivery_session_fk` (`session_id`), CONSTRAINT `generation_delivery_job_fk` FOREIGN KEY (`job_id`) REFERENCES `generation_jobs` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`, `job_id`) REFERENCES `generation_jobs` (`owner_id`, `project_id`, `session_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_owned_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_session_fk` FOREIGN KEY (`session_id`) REFERENCES `studio_conversations` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_delivery_model_tool` CHECK ((((`model` = _ascii'seedance-2.0') and (`tool_name` = _ascii'seedance2_video_generator')) or ((`model` in (_ascii'minimax-h3',_ascii'seedance-2.5')) and (`tool_name` = _ascii'insai_video_generate')))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_development_budgets 既有开发测试预算
CREATE TABLE `generation_development_budgets` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `policy_version` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits_limit` bigint unsigned NOT NULL, `credits_reserved` bigint unsigned NOT NULL DEFAULT '0', `calls_limit` int unsigned NOT NULL, `calls_reserved` int unsigned NOT NULL DEFAULT '0', `expires_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `generation_budget_owner` (`owner_id`,`id`), CONSTRAINT `generation_budget_limits` CHECK (((`credits_limit` between 1 and 1000000000) and (`credits_reserved` <= `credits_limit`) and (`calls_limit` between 1 and 100) and (`calls_reserved` <= `calls_limit`))), CONSTRAINT `generation_budget_policy` CHECK ((`policy_version` = _latin1'operator-test/v1')) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_jobs 既有generation任务,不等同新PublicMedia任务
CREATE TABLE `generation_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `session_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_conversation_id` char(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_run_id` char(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `budget_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_bytes` mediumblob NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits` bigint unsigned NOT NULL, `expires_at` datetime(6) NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempts` int unsigned NOT NULL DEFAULT '0', `result_bytes` mediumblob, `updated_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `generation_job_budget_owner` (`id`,`budget_id`,`owner_id`), UNIQUE KEY `generation_job_owned_scope` (`owner_id`,`project_id`,`session_id`,`id`), KEY `generation_job_owner` (`owner_id`,`project_id`,`session_id`), KEY `generation_job_session` (`session_id`), KEY `generation_job_budget` (`owner_id`,`budget_id`), CONSTRAINT `generation_job_budget` FOREIGN KEY (`owner_id`, `budget_id`) REFERENCES `generation_development_budgets` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_owned_project` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_owned_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `session_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_session` FOREIGN KEY (`session_id`) REFERENCES `studio_conversations` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_job_attempt` CHECK ((((`status` = _ascii'APPROVED') and (`attempts` = 0) and (`result_bytes` is null)) or ((`status` = _ascii'SUBMITTING') and (`attempts` = 1) and (`result_bytes` is null)) or ((`status` in (_ascii'SUCCEEDED',_ascii'FAILED',_ascii'UNKNOWN')) and (`attempts` = 1) and (`result_bytes` is not null)))), CONSTRAINT `generation_job_credit` CHECK ((`credits` between 1 and 1000000000)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
generation_reservations 既有任务费用预留
CREATE TABLE `generation_reservations` ( `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `budget_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credits` bigint unsigned NOT NULL, `calls` int unsigned NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, PRIMARY KEY (`job_id`), KEY `generation_reservation_job` (`job_id`,`budget_id`,`owner_id`), CONSTRAINT `generation_reservation_job` FOREIGN KEY (`job_id`, `budget_id`, `owner_id`) REFERENCES `generation_jobs` (`id`, `budget_id`, `owner_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `generation_reservation_fixed` CHECK (((`credits` between 1 and 1000000000) and (`calls` = 1) and (`status` = _latin1'HELD'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_bindings 业务会话与Native Maa会话映射、模型版本与未决操作
CREATE TABLE `maa_bindings` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `model_revision` bigint unsigned NOT NULL DEFAULT '0', `pending_model_change_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_binding_business_scope` (`owner_id`,`project_id`,`conversation_id`), UNIQUE KEY `maa_binding_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `maa_binding_native_identity` (`native_cid`), KEY `maa_model_change_pending_fk` (`owner_id`,`project_id`,`conversation_id`,`id`,`pending_model_change_id`), CONSTRAINT `maa_binding_owned_conversation_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_model_change_pending_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `id`, `pending_model_change_id`) REFERENCES `maa_model_change_actions` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_binding_receipt` CHECK ((((`status` = _ascii'dispatching') and (`native_cid` is null)) or ((`status` = _ascii'bound') and (`native_cid` is not null)))), CONSTRAINT `maa_model_binding_revision` CHECK ((`model_revision` <= 9007199254740991)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_interaction_actions 原卡片回答/取消动作
CREATE TABLE `maa_interaction_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `interaction_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_iid` varchar(124) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `content_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `response_action` varchar(8) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `values_payload` json NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_interaction_action_business_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_interaction_action_one_card` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`interaction_id`), CONSTRAINT `maa_interaction_action_owned_card_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`, `interaction_id`) REFERENCES `maa_interactions` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_interaction_action_kind` CHECK ((`response_action` in (_latin1'submit',_latin1'cancel'))), CONSTRAINT `maa_interaction_action_status` CHECK ((`status` in (_latin1'dispatching',_latin1'accepted'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_interactions 澄清卡片及Run归属
CREATE TABLE `maa_interactions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_iid` varchar(124) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `card_payload` json NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_interaction_native_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`native_iid`), UNIQUE KEY `maa_interaction_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`,`id`), CONSTRAINT `maa_interaction_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_message_actions 原消息动作及幂等回执
CREATE TABLE `maa_message_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `content` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `proposed_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_action_business_identity` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), KEY `maa_action_owned_run_fk` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`), CONSTRAINT `maa_action_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_action_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_action_receipt` CHECK ((((`status` = _latin1'dispatching') and (`public_run_id` is null)) or ((`status` = _latin1'accepted') and (`public_run_id` is not null)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_model_change_actions 带预期模型版本的切换动作
CREATE TABLE `maa_model_change_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `expected_revision` bigint unsigned NOT NULL, `from_provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `from_model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `target_provider` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `target_model_name` varchar(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `dispatch_attempt` bigint unsigned NOT NULL, `receipt_payload` json DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_model_change_owned_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_model_change_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`id`), CONSTRAINT `maa_model_change_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_model_change_attempt` CHECK ((`dispatch_attempt` between 1 and 9007199254740991)), CONSTRAINT `maa_model_change_expected` CHECK ((`expected_revision` <= 9007199254740990)), CONSTRAINT `maa_model_change_status` CHECK ((((cast(`status` as char charset binary) = _latin1'dispatching') and (`receipt_payload` is null)) or ((cast(`status` as char charset binary) in (_latin1'accepted',_latin1'rejected')) and (`receipt_payload` is not null) and (json_type(`receipt_payload`) = _latin1'OBJECT')))), CONSTRAINT `maa_model_change_time` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_run_stop_actions 停止原Run的幂等动作与观测终态
CREATE TABLE `maa_run_stop_actions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `public_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_cid` varchar(41) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_rid` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `stop_action` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempt` bigint unsigned NOT NULL, `terminal_run_status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `maa_stop_owned_key` (`owner_id`,`project_id`,`conversation_id`,`client_action_id`), UNIQUE KEY `maa_stop_one_run` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`public_run_id`), CONSTRAINT `maa_stop_owned_run_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `public_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_stop_action` CHECK ((`stop_action` = _latin1'interrupt')), CONSTRAINT `maa_stop_attempt` CHECK ((`attempt` between 1 and 9007199254740991)), CONSTRAINT `maa_stop_state` CHECK ((((`status` = _latin1'unknown') and (`terminal_run_status` is null)) or ((`status` = _latin1'terminal_observed') and (`terminal_run_status` is not null) and (`terminal_run_status` in (_latin1'completed',_latin1'failed',_latin1'cancelled'))))), CONSTRAINT `maa_stop_time` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
maa_runs 公开Run映射、状态与原生/公开助手证据摘要
CREATE TABLE `maa_runs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `native_rid` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, `native_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `public_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `native_assistant_bytes` bigint unsigned NOT NULL DEFAULT '0', `assistant_event_seq` bigint unsigned NOT NULL DEFAULT '0', `last_event_seq` bigint unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `maa_run_native_identity` (`native_rid`), UNIQUE KEY `maa_run_owned_identity` (`owner_id`,`project_id`,`conversation_id`,`binding_id`,`id`), KEY `maa_run_owned_list` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), CONSTRAINT `maa_run_owned_binding_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `binding_id`) REFERENCES `maa_bindings` (`owner_id`, `project_id`, `conversation_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `maa_run_source_evidence` CHECK ((((`native_assistant_sha256` is null) and (`public_assistant_sha256` is null) and (`native_assistant_bytes` = 0) and (`assistant_event_seq` = 0)) or ((`native_assistant_sha256` is not null) and (`public_assistant_sha256` is not null) and (`native_assistant_bytes` > 0) and (`assistant_event_seq` > 0) and (`assistant_event_seq` <= `last_event_seq`)))), CONSTRAINT `maa_run_status` CHECK ((`status` in (_latin1'queued',_latin1'running',_latin1'waiting_interaction',_latin1'completed',_latin1'failed',_latin1'cancelled'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_canvas_revisions 历史画布修订
CREATE TABLE `studio_canvas_revisions` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_bytes` mediumblob NOT NULL, `state_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `restored_from_revision` bigint unsigned DEFAULT NULL, `recorded_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`,`project_id`,`kind`,`revision`), KEY `studio_canvas_revision_source_fk` (`owner_id`,`project_id`,`kind`,`restored_from_revision`), CONSTRAINT `studio_canvas_revision_head_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_canvases` (`owner_id`, `project_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_canvas_revision_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `kind`, `restored_from_revision`) REFERENCES `studio_canvas_revisions` (`owner_id`, `project_id`, `kind`, `revision`), CONSTRAINT `studio_canvas_revision_bytes` CHECK ((length(`state_bytes`) between 1 and 262144)), CONSTRAINT `studio_canvas_revision_kind` CHECK ((`kind` = _latin1'canvas')), CONSTRAINT `studio_canvas_revision_number` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_canvas_revision_origin` CHECK ((((`origin` in (_latin1'saved',_latin1'backfill')) and (`restored_from_revision` is null)) or ((`origin` = _latin1'restored') and (`restored_from_revision` is not null) and (`restored_from_revision` between 1 and (`revision` - 1))))), CONSTRAINT `studio_canvas_revision_sha` CHECK ((`state_sha256` = lower(sha2(`state_bytes`,256)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_canvases 项目当前画布文档
CREATE TABLE `studio_canvases` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_json` json NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`project_id`), UNIQUE KEY `studio_canvas_owned_head` (`owner_id`,`project_id`), CONSTRAINT `studio_canvas_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_canvas_revision` CHECK ((`revision` between 1 and 2147483647)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_conversations 项目内的对话会话
CREATE TABLE `studio_conversations` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `title` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_conversation_owned_scope` (`owner_id`,`project_id`,`id`), KEY `studio_conversation_list` (`owner_id`,`project_id`,`created_at`,`id`), CONSTRAINT `studio_conversation_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_recovery_intents 积分结算恢复意图;不是用户钱包全账本
CREATE TABLE `studio_credit_recovery_intents` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`kind` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`intent_bytes` mediumblob NOT NULL,
`intent_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`lease_token_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`lease_until` datetime(6) DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_intent_job_kind` (`job_id`,`kind`),
KEY `credit_intent_recovery` (`state`,`updated_at`,`id`),
KEY `credit_intent_owned_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`,`request_sha256`),
CONSTRAINT `credit_intent_owned_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`, `request_sha256`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`),
CONSTRAINT `credit_intent_hashes` CHECK ((regexp_like(`request_sha256`,_latin1'^[a-f0-9]{64}$') and regexp_like(`quote_sha256`,_latin1'^[a-f0-9]{64}$'))),
CONSTRAINT `credit_intent_kind` CHECK (((`kind` in (_latin1'RESERVE_BIND',_latin1'CAPTURE',_latin1'RELEASE')) and (((`kind` = _latin1'RESERVE_BIND') and (`authorization_id` is null)) or ((`kind` in (_latin1'CAPTURE',_latin1'RELEASE')) and (`authorization_id` is not null))))),
CONSTRAINT `credit_intent_lease` CHECK ((((`state` = _latin1'leased') and (`lease_token_sha256` is not null) and regexp_like(`lease_token_sha256`,_latin1'^[a-f0-9]{64}$') and (`lease_until` is not null) and (`lease_until` > `updated_at`) and (`lease_until` <= (`updated_at` + interval 15 minute))) or ((`state` <> _latin1'leased') and (`lease_token_sha256` is null) and (`lease_until` is null)))),
CONSTRAINT `credit_intent_payload_sha` CHECK ((`intent_sha256` = lower(sha2(`intent_bytes`,256)))),
CONSTRAINT `credit_intent_payload_size` CHECK ((length(`intent_bytes`) between 1 and 65536)),
CONSTRAINT `credit_intent_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `credit_intent_state` CHECK ((`state` in (_latin1'pending',_latin1'leased',_latin1'confirmed',_latin1'unknown'))),
CONSTRAINT `credit_intent_times` CHECK ((`updated_at` >= `created_at`))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_export_jobs 时间轴导出队列和发布输出
CREATE TABLE `studio_export_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `document_revision` bigint unsigned NOT NULL, `input_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `input_json` json NOT NULL, `output_json` json DEFAULT NULL, `error_code` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT '', `lease_token_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `lease_until` datetime(6) DEFAULT NULL, `attempts` int unsigned NOT NULL DEFAULT '0', `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_export_input` (`project_id`,`document_revision`,`input_hash`), KEY `studio_export_claim` (`status`,`created_at`,`id`), KEY `studio_export_owner_list` (`owner_id`,`project_id`,`created_at`,`id`), KEY `studio_export_expiry` (`status`,`lease_until`), CONSTRAINT `studio_export_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_export_lease` CHECK ((((`status` = _latin1'running') and (`lease_token_hash` is not null) and (`lease_until` is not null)) or ((`status` <> _latin1'running') and (`lease_token_hash` is null) and (`lease_until` is null)))), CONSTRAINT `studio_export_output` CHECK ((((`status` = _latin1'succeeded') and (`output_json` is not null) and (`error_code` = _latin1'')) or ((`status` in (_latin1'queued',_latin1'running')) and (`output_json` is null) and (`error_code` = _latin1'')) or ((`status` in (_latin1'failed',_latin1'unknown')) and (`output_json` is null) and (`error_code` <> _latin1'')))), CONSTRAINT `studio_export_revision` CHECK ((`document_revision` between 1 and 2147483647)), CONSTRAINT `studio_export_status` CHECK ((`status` in (_latin1'queued',_latin1'running',_latin1'succeeded',_latin1'failed',_latin1'unknown'))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_jobs 已批准媒体任务及状态机
CREATE TABLE `studio_media_jobs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_approval_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `approval_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `credit_authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `authorization_mode` varchar(24) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `authorization_expires_at` datetime(6) DEFAULT NULL, `status` varchar(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `lease_token_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `lease_until` datetime(6) DEFAULT NULL, `provider_task_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `client_cancel_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `cancel_request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `cancel_requested_at` datetime(6) DEFAULT NULL, `staged_asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `staged_asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_job_request` (`request_id`), UNIQUE KEY `studio_media_job_client` (`owner_id`,`client_approval_id`), UNIQUE KEY `studio_media_job_owned` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `studio_media_job_owned_request` (`owner_id`,`project_id`,`conversation_id`,`id`,`request_sha256`), KEY `studio_media_job_page` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), KEY `studio_media_job_queue` (`status`,`updated_at`,`id`), KEY `studio_media_job_request_fk` (`owner_id`,`project_id`,`conversation_id`,`request_id`,`request_sha256`,`quote_sha256`), CONSTRAINT `studio_media_job_request_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `request_id`, `request_sha256`, `quote_sha256`) REFERENCES `studio_media_requests` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`, `quote_sha256`), CONSTRAINT `studio_media_job_authorization` CHECK ((((`credit_authorization_id` is null) and (`authorization_mode` is null) and (`authorization_expires_at` is null) and (`status` in (_latin1'approval_pending',_latin1'cancelled'))) or ((`credit_authorization_id` is not null) and (`authorization_mode` is not null) and (`authorization_mode` in (_latin1'commercial',_latin1'test_allowance')) and (`authorization_expires_at` is not null) and (`authorization_expires_at` > `created_at`) and (`status` <> _latin1'approval_pending')))), CONSTRAINT `studio_media_job_cancel` CHECK ((((`client_cancel_id` is null) and (`cancel_request_sha256` is null) and (`cancel_requested_at` is null)) or ((`client_cancel_id` is not null) and (`cancel_request_sha256` is not null) and (`cancel_requested_at` is not null) and (`cancel_requested_at` between `created_at` and `updated_at`)))), CONSTRAINT `studio_media_job_lease` CHECK ((((`status` in (_latin1'leased',_latin1'submitting')) and (`lease_token_sha256` is not null) and (`lease_until` is not null) and (`lease_until` > `updated_at`) and (`lease_until` <= (`updated_at` + interval 15 minute))) or ((`status` not in (_latin1'leased',_latin1'submitting')) and (`lease_token_sha256` is null) and (`lease_until` is null)))), CONSTRAINT `studio_media_job_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_media_job_staged` CHECK ((((`staged_asset_id` is null) and (`staged_asset_sha256` is null)) or ((`staged_asset_id` is not null) and (`staged_asset_sha256` is not null)))), CONSTRAINT `studio_media_job_status` CHECK ((`status` in (_latin1'approval_pending',_latin1'queued',_latin1'leased',_latin1'submitting',_latin1'running',_latin1'submission_unknown',_latin1'succeeded',_latin1'failed',_latin1'cancelled'))), CONSTRAINT `studio_media_job_task` CHECK (((`status` not in (_latin1'running',_latin1'succeeded')) or (`provider_task_id` is not null))), CONSTRAINT `studio_media_job_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_outputs 受验证的输出与素材映射
CREATE TABLE `studio_media_outputs` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `ordinal` int unsigned NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_metadata_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_result_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_output_job` (`job_id`,`ordinal`), KEY `studio_media_output_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`), CONSTRAINT `studio_media_output_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`), CONSTRAINT `studio_media_output_ordinal` CHECK ((`ordinal` = 0)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_requests 用户输入/Agent来源、报价、批准摘要与准入确认
CREATE TABLE `studio_media_requests` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `client_request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_config_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `request_bytes` mediumblob NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quote_bytes` mediumblob NOT NULL, `quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `quoted_credits` bigint unsigned NOT NULL, `expires_at` datetime(6) NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_binding_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_run_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_assistant_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_snapshot_bytes` mediumblob, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_request_owned` (`owner_id`,`project_id`,`conversation_id`,`id`), UNIQUE KEY `studio_media_request_quoted` (`owner_id`,`project_id`,`conversation_id`,`id`,`request_sha256`,`quote_sha256`), UNIQUE KEY `studio_media_request_client` (`owner_id`,`project_id`,`conversation_id`,`client_request_id`), KEY `studio_media_request_page` (`owner_id`,`project_id`,`conversation_id`,`created_at`,`id`), KEY `studio_media_request_source_fk` (`owner_id`,`project_id`,`conversation_id`,`source_binding_id`,`source_run_id`), CONSTRAINT `studio_media_request_session_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`) REFERENCES `studio_conversations` (`owner_id`, `project_id`, `id`), CONSTRAINT `studio_media_request_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `source_binding_id`, `source_run_id`) REFERENCES `maa_runs` (`owner_id`, `project_id`, `conversation_id`, `binding_id`, `id`), CONSTRAINT `studio_media_quote_credits` CHECK ((`quoted_credits` between 1 and 1000000000)), CONSTRAINT `studio_media_quote_sha` CHECK ((`quote_sha256` = lower(sha2(`quote_bytes`,256)))), CONSTRAINT `studio_media_quote_times` CHECK (((`expires_at` > `created_at`) and (`expires_at` <= (`created_at` + interval 15 minute)))), CONSTRAINT `studio_media_request_origin` CHECK ((((`origin` in (_latin1'ui',_latin1'user_edit')) and (`source_binding_id` is null) and (`source_run_id` is null) and (`source_assistant_sha256` is null) and (`source_snapshot_bytes` is null)) or ((`origin` = _latin1'agent') and (`source_binding_id` is not null) and (`source_run_id` is not null) and (`source_assistant_sha256` is not null) and (`source_snapshot_bytes` is not null) and (length(`source_snapshot_bytes`) between 1 and 65536) and (`source_assistant_sha256` = lower(sha2(`source_snapshot_bytes`,256)))))), CONSTRAINT `studio_media_request_sha` CHECK ((`request_sha256` = lower(sha2(`request_bytes`,256)))), CONSTRAINT `studio_media_request_size` CHECK (((length(`request_bytes`) between 1 and 65536) and (length(`quote_bytes`) between 1 and 65536))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_submission_attempts 一次提交的任务证据与不确定结果
CREATE TABLE `studio_media_submission_attempts` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `attempt_no` int unsigned NOT NULL, `request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_idempotency_key` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `stage` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `dispatch_started_at` datetime(6) DEFAULT NULL, `provider_task_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `receipt_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `terminal_receipt_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `reconciliation_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_attempt_job` (`job_id`,`attempt_no`), UNIQUE KEY `studio_media_attempt_idempotency` (`provider_idempotency_key`), KEY `studio_media_attempt_job_fk` (`owner_id`,`project_id`,`conversation_id`,`job_id`,`request_sha256`), CONSTRAINT `studio_media_attempt_job_fk` FOREIGN KEY (`owner_id`, `project_id`, `conversation_id`, `job_id`, `request_sha256`) REFERENCES `studio_media_jobs` (`owner_id`, `project_id`, `conversation_id`, `id`, `request_sha256`), CONSTRAINT `studio_media_attempt_number` CHECK ((`attempt_no` = 1)), CONSTRAINT `studio_media_attempt_state` CHECK ((((`stage` = _latin1'prepared') and (`dispatch_started_at` is null) and (`provider_task_id` is null) and (`receipt_sha256` is null) and (`reconciliation_sha256` is null) and (`terminal_receipt_sha256` is null)) or ((`stage` in (_latin1'dispatching',_latin1'unknown')) and (`dispatch_started_at` is not null) and (`dispatch_started_at` >= `created_at`) and (`provider_task_id` is null) and (`receipt_sha256` is null) and (`reconciliation_sha256` is null) and (`terminal_receipt_sha256` is null)) or ((`stage` = _latin1'acknowledged') and (`dispatch_started_at` is not null) and (`provider_task_id` is not null) and (`receipt_sha256` is not null) and (`terminal_receipt_sha256` is null)) or ((`stage` in (_latin1'completed',_latin1'failed')) and (`dispatch_started_at` is not null) and (`provider_task_id` is not null) and (`receipt_sha256` is not null) and (`terminal_receipt_sha256` is not null)) or ((`stage` = _latin1'reconciled_not_sent') and (`dispatch_started_at` is not null) and (`provider_task_id` is null) and (`reconciliation_sha256` is not null)))), CONSTRAINT `studio_media_attempt_times` CHECK (((`updated_at` >= `created_at`) and ((`dispatch_started_at` is null) or (`dispatch_started_at` between `created_at` and `updated_at`)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_project_asset_refs 项目对用户级素材的引用;不复制素材所有权
CREATE TABLE `studio_project_asset_refs` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `asset_metadata_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, `detached_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`project_id`,`asset_id`), KEY `studio_project_asset_owned_page` (`owner_id`,`project_id`,`asset_id`), KEY `studio_project_asset_reverse` (`owner_id`,`asset_id`,`project_id`), CONSTRAINT `studio_project_asset_owned_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_project_asset_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_project_asset_state` CHECK ((((`state` = _latin1'attached') and (`detached_at` is null)) or ((`state` = _latin1'detached') and (`detached_at` is not null) and (`detached_at` = `updated_at`)))), CONSTRAINT `studio_project_asset_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_projects 用户拥有的创作项目
CREATE TABLE `studio_projects` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `title` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_project_owner_identity` (`owner_id`,`id`), KEY `studio_project_owner_list` (`owner_id`,`created_at`,`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_timeline_revisions 历史时间轴修订
CREATE TABLE `studio_timeline_revisions` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_bytes` mediumblob NOT NULL, `state_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `origin` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `restored_from_revision` bigint unsigned DEFAULT NULL, `recorded_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`,`project_id`,`kind`,`revision`), KEY `studio_timeline_revision_source_fk` (`owner_id`,`project_id`,`kind`,`restored_from_revision`), CONSTRAINT `studio_timeline_revision_head_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_video_documents` (`owner_id`, `project_id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_timeline_revision_source_fk` FOREIGN KEY (`owner_id`, `project_id`, `kind`, `restored_from_revision`) REFERENCES `studio_timeline_revisions` (`owner_id`, `project_id`, `kind`, `revision`), CONSTRAINT `studio_timeline_revision_bytes` CHECK ((length(`state_bytes`) between 1 and 262144)), CONSTRAINT `studio_timeline_revision_kind` CHECK ((`kind` = _latin1'timeline')), CONSTRAINT `studio_timeline_revision_number` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_timeline_revision_origin` CHECK ((((`origin` in (_latin1'saved',_latin1'backfill')) and (`restored_from_revision` is null)) or ((`origin` = _latin1'restored') and (`restored_from_revision` is not null) and (`restored_from_revision` between 1 and (`revision` - 1))))), CONSTRAINT `studio_timeline_revision_sha` CHECK ((`state_sha256` = lower(sha2(`state_bytes`,256)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_video_documents 项目当前时间轴文档
CREATE TABLE `studio_video_documents` ( `project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `state_json` json NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`project_id`), UNIQUE KEY `studio_timeline_owned_head` (`owner_id`,`project_id`), CONSTRAINT `studio_document_project_fk` FOREIGN KEY (`owner_id`, `project_id`) REFERENCES `studio_projects` (`owner_id`, `id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_document_revision` CHECK ((`revision` between 1 and 2147483647)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
共享身份库(15 张)与积分账本 七个品牌相同,展开查看
studio_assets
CREATE TABLE `studio_assets` (
`id` char(32) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`metadata_json` json NOT NULL,
`storage_key` varchar(512) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`created_at` datetime(6) NOT NULL,
`publication_state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT 'visible',
PRIMARY KEY (`id`),
UNIQUE KEY `studio_asset_owner_digest` (`owner_id`,`sha256`),
KEY `studio_asset_owner_list` (`owner_id`,`created_at`,`id`),
KEY `studio_asset_visible_list` (`owner_id`,`publication_state`,`created_at`,`id`),
CONSTRAINT `studio_asset_publication_state` CHECK (CAST(publication_state AS BINARY) IN ('pending','visible')),
CONSTRAINT `studio_asset_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_billing_cycles
CREATE TABLE `studio_billing_cycles` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`subscription_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`payment_order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_invoice_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`period_start` datetime(6) NOT NULL,
`period_end` datetime(6) NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`valid_from` datetime(6) NOT NULL,
`expires_at` datetime(6) NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`paid_evidence_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `billing_cycle_owned` (`owner_id`,`id`),
UNIQUE KEY `billing_cycle_period` (`subscription_id`,`period_start`),
UNIQUE KEY `billing_cycle_invoice` (`provider_key`,`provider_account`,`provider_invoice_id`),
UNIQUE KEY `billing_cycle_order` (`payment_order_id`),
KEY `billing_cycle_subscription_fk` (`owner_id`,`subscription_id`,`provider_key`,`provider_account`),
KEY `billing_cycle_order_fk` (`owner_id`,`payment_order_id`,`plan_version_id`),
KEY `billing_cycle_order_provider_fk` (`owner_id`,`payment_order_id`,`provider_key`,`provider_account`),
CONSTRAINT `billing_cycle_order_fk` FOREIGN KEY (`owner_id`, `payment_order_id`, `plan_version_id`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `plan_version_id`),
CONSTRAINT `billing_cycle_order_provider_fk` FOREIGN KEY (`owner_id`, `payment_order_id`, `provider_key`, `provider_account`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `provider_key`, `provider_account`),
CONSTRAINT `billing_cycle_subscription_fk` FOREIGN KEY (`owner_id`, `subscription_id`, `provider_key`, `provider_account`) REFERENCES `studio_subscriptions` (`owner_id`, `id`, `provider_key`, `provider_account`),
CONSTRAINT `billing_cycle_amount` CHECK ((`grant_credits` between 1 and 1000000000)),
CONSTRAINT `billing_cycle_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `billing_cycle_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `billing_cycle_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `billing_cycle_state` CHECK (((`state` in (_latin1'PENDING',_latin1'PAID',_latin1'CLOSED')) and (((`state` = _latin1'PAID') and (`paid_evidence_sha256` is not null) and regexp_like(`paid_evidence_sha256`,_latin1'^[a-f0-9]{64}$')) or ((`state` <> _latin1'PAID') and (`paid_evidence_sha256` is null))))),
CONSTRAINT `billing_cycle_times` CHECK (((`period_end` > `period_start`) and (`expires_at` > `valid_from`) and (`expires_at` <= (`valid_from` + interval 31622400 second)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_credit_accounts
CREATE TABLE `studio_credit_accounts` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `unit` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`owner_id`), CONSTRAINT `credit_account_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `credit_account_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `credit_account_status` CHECK ((`status` in (_latin1'open',_latin1'suspended'))), CONSTRAINT `credit_account_unit` CHECK ((`unit` = _latin1'credits')) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_authorization_allocations
CREATE TABLE `studio_credit_authorization_allocations` ( `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `lot_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `allocated_credits` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`authorization_id`,`lot_id`), UNIQUE KEY `credit_allocation_owned` (`owner_id`,`authorization_id`,`lot_id`), KEY `credit_allocation_lot` (`owner_id`,`lot_id`,`authorization_id`), CONSTRAINT `credit_allocation_authorization_fk` FOREIGN KEY (`owner_id`, `authorization_id`) REFERENCES `studio_credit_authorizations` (`owner_id`, `id`), CONSTRAINT `credit_allocation_lot_fk` FOREIGN KEY (`owner_id`, `lot_id`) REFERENCES `studio_credit_lots` (`owner_id`, `id`), CONSTRAINT `credit_allocation_amount` CHECK ((`allocated_credits` between 1 and 1000000000)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_authorizations
CREATE TABLE `studio_credit_authorizations` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`profile` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`project_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`conversation_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`job_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`request_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`quote_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`credits` bigint unsigned NOT NULL,
`expires_at` datetime(6) NOT NULL,
`reservation_bytes` mediumblob NOT NULL,
`reservation_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`policy_bytes` mediumblob NOT NULL,
`policy_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`state` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_authorization_owned` (`owner_id`,`id`),
UNIQUE KEY `credit_authorization_job` (`owner_id`,`profile`,`job_id`),
CONSTRAINT `credit_authorization_account_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_credit_accounts` (`owner_id`),
CONSTRAINT `credit_authorization_amount` CHECK ((`credits` between 1 and 1000000000)),
CONSTRAINT `credit_authorization_hashes` CHECK ((regexp_like(`request_sha256`,_latin1'^[a-f0-9]{64}$') and regexp_like(`quote_sha256`,_latin1'^[a-f0-9]{64}$'))),
CONSTRAINT `credit_authorization_policy_sha` CHECK ((`policy_sha256` = lower(sha2(`policy_bytes`,256)))),
CONSTRAINT `credit_authorization_policy_size` CHECK ((length(`policy_bytes`) between 1 and 65536)),
CONSTRAINT `credit_authorization_profile` CHECK ((`profile` in (_latin1'topview',_latin1'pollo',_latin1'invideo',_latin1'libtv',_latin1'flova',_latin1'creatok',_latin1'creatify'))),
CONSTRAINT `credit_authorization_reservation_sha` CHECK ((`reservation_sha256` = lower(sha2(`reservation_bytes`,256)))),
CONSTRAINT `credit_authorization_reservation_size` CHECK ((length(`reservation_bytes`) between 1 and 65536)),
CONSTRAINT `credit_authorization_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `credit_authorization_state` CHECK ((`state` in (_latin1'HELD',_latin1'CAPTURED',_latin1'RELEASED'))),
CONSTRAINT `credit_authorization_times` CHECK (((`expires_at` > `created_at`) and (`expires_at` <= (`created_at` + interval 15 minute)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_credit_ledger_entries
CREATE TABLE `studio_credit_ledger_entries` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `lot_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `authorization_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `operation_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `grant_delta` bigint NOT NULL, `held_delta` bigint NOT NULL, `captured_delta` bigint NOT NULL, `facts_bytes` mediumblob NOT NULL, `facts_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `credit_entry_operation` (`owner_id`,`operation_key`,`lot_id`), KEY `credit_entry_page` (`owner_id`,`created_at`,`id`), KEY `credit_entry_lot_fk` (`owner_id`,`lot_id`), KEY `credit_entry_allocation_fk` (`owner_id`,`authorization_id`,`lot_id`), CONSTRAINT `credit_entry_allocation_fk` FOREIGN KEY (`owner_id`, `authorization_id`, `lot_id`) REFERENCES `studio_credit_authorization_allocations` (`owner_id`, `authorization_id`, `lot_id`), CONSTRAINT `credit_entry_authorization_fk` FOREIGN KEY (`owner_id`, `authorization_id`) REFERENCES `studio_credit_authorizations` (`owner_id`, `id`), CONSTRAINT `credit_entry_lot_fk` FOREIGN KEY (`owner_id`, `lot_id`) REFERENCES `studio_credit_lots` (`owner_id`, `id`), CONSTRAINT `credit_entry_delta` CHECK ((((`kind` = _latin1'grant') and (`authorization_id` is null) and (`grant_delta` between 1 and 1000000000) and (`held_delta` = 0) and (`captured_delta` = 0)) or ((`kind` = _latin1'hold') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`held_delta` between 1 and 1000000000) and (`captured_delta` = 0)) or ((`kind` = _latin1'capture') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`captured_delta` between 1 and 1000000000) and (`held_delta` = -(`captured_delta`))) or ((`kind` = _latin1'release') and (`authorization_id` is not null) and (`grant_delta` = 0) and (`held_delta` between -(1000000000) and -(1)) and (`captured_delta` = 0)))), CONSTRAINT `credit_entry_facts_sha` CHECK ((`facts_sha256` = lower(sha2(`facts_bytes`,256)))), CONSTRAINT `credit_entry_facts_size` CHECK ((length(`facts_bytes`) between 1 and 65536)), CONSTRAINT `credit_entry_operation_key` CHECK ((((`kind` = _latin1'grant') and (`operation_key` = concat(`lot_id`,_latin1':grant'))) or ((`kind` <> _latin1'grant') and (`operation_key` = concat(`authorization_id`,_latin1':',`kind`))))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_lots
CREATE TABLE `studio_credit_lots` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `grant_credits` bigint unsigned NOT NULL, `held_credits` bigint unsigned NOT NULL, `captured_credits` bigint unsigned NOT NULL, `valid_from` datetime(6) NOT NULL, `expires_at` datetime(6) NOT NULL, `eligibility_bytes` mediumblob NOT NULL, `eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `source_order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `source_cycle_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `credit_lot_owned` (`owner_id`,`id`), UNIQUE KEY `credit_lot_order` (`source_order_id`), UNIQUE KEY `credit_lot_cycle` (`source_cycle_id`), KEY `credit_lot_eligible` (`owner_id`,`expires_at`,`id`), KEY `credit_lot_order_fk` (`owner_id`,`source_order_id`), KEY `credit_lot_cycle_fk` (`owner_id`,`source_cycle_id`), CONSTRAINT `credit_lot_account_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_credit_accounts` (`owner_id`), CONSTRAINT `credit_lot_cycle_fk` FOREIGN KEY (`owner_id`, `source_cycle_id`) REFERENCES `studio_billing_cycles` (`owner_id`, `id`), CONSTRAINT `credit_lot_order_fk` FOREIGN KEY (`owner_id`, `source_order_id`) REFERENCES `studio_payment_orders` (`owner_id`, `id`), CONSTRAINT `credit_lot_counters` CHECK (((`grant_credits` between 1 and 1000000000) and (`held_credits` <= 1000000000) and (`captured_credits` <= 1000000000) and ((`held_credits` + `captured_credits`) <= `grant_credits`))), CONSTRAINT `credit_lot_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))), CONSTRAINT `credit_lot_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)), CONSTRAINT `credit_lot_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `credit_lot_source` CHECK ((((`source_order_id` is not null) and (`source_cycle_id` is null)) or ((`source_order_id` is null) and (`source_cycle_id` is not null)))), CONSTRAINT `credit_lot_times` CHECK (((`expires_at` > `valid_from`) and (`updated_at` >= `created_at`))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_credit_plan_versions
CREATE TABLE `studio_credit_plan_versions` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`version_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`price_minor` bigint unsigned NOT NULL,
`currency` char(3) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`credit_validity_seconds` int unsigned NOT NULL,
`billing_interval_months` int unsigned NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`published_at` datetime(6) NOT NULL,
`retired_at` datetime(6) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `credit_plan_version_key` (`plan_key`,`version_key`),
CONSTRAINT `credit_plan_amount` CHECK (((`price_minor` between 1 and 1000000000000) and (`grant_credits` between 1 and 1000000000))),
CONSTRAINT `credit_plan_currency` CHECK (regexp_like(`currency`,_latin1'^[A-Z]{3}$')),
CONSTRAINT `credit_plan_duration` CHECK (((`credit_validity_seconds` between 1 and 31622400) and ((`retired_at` is null) or (`retired_at` >= `published_at`)))),
CONSTRAINT `credit_plan_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `credit_plan_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `credit_plan_kind` CHECK (((`kind` in (_latin1'subscription',_latin1'topup')) and (((`kind` = _latin1'subscription') and (`billing_interval_months` in (1,3,12))) or ((`kind` = _latin1'topup') and (`billing_interval_months` = 0)))))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_media_model_versions
CREATE TABLE `studio_media_model_versions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `version_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `config_bytes` mediumblob NOT NULL, `config_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `published_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_version_key` (`model_id`,`version_key`), UNIQUE KEY `studio_media_version_owned_model` (`model_id`,`id`), CONSTRAINT `studio_media_version_model_fk` FOREIGN KEY (`model_id`) REFERENCES `studio_media_models` (`id`), CONSTRAINT `studio_media_version_sha` CHECK ((`config_sha256` = lower(sha2(`config_bytes`,256)))), CONSTRAINT `studio_media_version_size` CHECK ((length(`config_bytes`) between 1 and 65536)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_media_models
CREATE TABLE `studio_media_models` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `model_key` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `kind` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `display_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, `status` varchar(16) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `published_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `revision` bigint unsigned NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_media_model_key` (`model_key`), KEY `studio_media_model_published_fk` (`id`,`published_version_id`), CONSTRAINT `studio_media_model_published_fk` FOREIGN KEY (`id`, `published_version_id`) REFERENCES `studio_media_model_versions` (`model_id`, `id`), CONSTRAINT `studio_media_model_kind` CHECK ((`kind` = _ascii'video')), CONSTRAINT `studio_media_model_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `studio_media_model_status` CHECK (((`status` in (_ascii'draft',_ascii'active',_ascii'disabled')) and ((`status` <> _ascii'active') or (`published_version_id` is not null)))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_payment_events
CREATE TABLE `studio_payment_events` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_event_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `order_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `subscription_id` char(36) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL, `body_bytes` mediumblob NOT NULL, `body_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `payment_event_provider` (`provider_key`,`provider_account`,`provider_event_id`), KEY `payment_event_order_fk` (`owner_id`,`order_id`,`provider_key`,`provider_account`), KEY `payment_event_subscription_fk` (`owner_id`,`subscription_id`,`provider_key`,`provider_account`), CONSTRAINT `payment_event_order_fk` FOREIGN KEY (`owner_id`, `order_id`, `provider_key`, `provider_account`) REFERENCES `studio_payment_orders` (`owner_id`, `id`, `provider_key`, `provider_account`), CONSTRAINT `payment_event_subscription_fk` FOREIGN KEY (`owner_id`, `subscription_id`, `provider_key`, `provider_account`) REFERENCES `studio_subscriptions` (`owner_id`, `id`, `provider_key`, `provider_account`), CONSTRAINT `payment_event_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `payment_event_body_sha` CHECK ((`body_sha256` = lower(sha2(`body_bytes`,256)))), CONSTRAINT `payment_event_body_size` CHECK ((length(`body_bytes`) between 1 and 65536)), CONSTRAINT `payment_event_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `payment_event_state` CHECK ((`state` in (_latin1'VERIFIED',_latin1'PROCESSED'))), CONSTRAINT `payment_event_subject` CHECK (((`order_id` is not null) or (`subscription_id` is not null))), CONSTRAINT `payment_event_times` CHECK ((`updated_at` >= `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_payment_orders
CREATE TABLE `studio_payment_orders` (
`id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`client_action_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`price_minor` bigint unsigned NOT NULL,
`currency` char(3) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`grant_credits` bigint unsigned NOT NULL,
`valid_from` datetime(6) NOT NULL,
`expires_at` datetime(6) NOT NULL,
`eligibility_bytes` mediumblob NOT NULL,
`eligibility_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_idempotency_key` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`provider_order_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
`paid_evidence_sha256` char(64) CHARACTER SET ascii COLLATE ascii_bin DEFAULT NULL,
`revision` bigint unsigned NOT NULL,
`created_at` datetime(6) NOT NULL,
`updated_at` datetime(6) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `payment_order_owned` (`owner_id`,`id`),
UNIQUE KEY `payment_order_owned_plan` (`owner_id`,`id`,`plan_version_id`),
UNIQUE KEY `payment_order_owned_provider` (`owner_id`,`id`,`provider_key`,`provider_account`),
UNIQUE KEY `payment_order_client` (`owner_id`,`client_action_id`),
UNIQUE KEY `payment_order_provider_key` (`provider_key`,`provider_account`,`provider_idempotency_key`),
UNIQUE KEY `payment_order_provider_id` (`provider_key`,`provider_account`,`provider_order_id`),
KEY `payment_order_plan_fk` (`plan_version_id`),
CONSTRAINT `payment_order_plan_fk` FOREIGN KEY (`plan_version_id`) REFERENCES `studio_credit_plan_versions` (`id`),
CONSTRAINT `payment_order_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`),
CONSTRAINT `payment_order_amount` CHECK (((`price_minor` between 1 and 1000000000000) and (`grant_credits` between 1 and 1000000000))),
CONSTRAINT `payment_order_currency` CHECK (regexp_like(`currency`,_latin1'^[A-Z]{3}$')),
CONSTRAINT `payment_order_eligibility_sha` CHECK ((`eligibility_sha256` = lower(sha2(`eligibility_bytes`,256)))),
CONSTRAINT `payment_order_eligibility_size` CHECK ((length(`eligibility_bytes`) between 1 and 65536)),
CONSTRAINT `payment_order_revision` CHECK ((`revision` between 1 and 2147483647)),
CONSTRAINT `payment_order_state` CHECK (((`state` in (_latin1'CREATING',_latin1'CREATE_UNKNOWN',_latin1'PENDING',_latin1'PAID',_latin1'CLOSED')) and (((`state` = _latin1'PAID') and (`provider_order_id` is not null) and (`paid_evidence_sha256` is not null) and regexp_like(`paid_evidence_sha256`,_latin1'^[a-f0-9]{64}$')) or ((`state` <> _latin1'PAID') and (`paid_evidence_sha256` is null))))),
CONSTRAINT `payment_order_times` CHECK (((`expires_at` > `valid_from`) and (`expires_at` <= (`valid_from` + interval 31622400 second)) and (`updated_at` >= `created_at`)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;studio_sessions
CREATE TABLE `studio_sessions` ( `token_hash` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `user_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created_at` datetime(6) NOT NULL, `expires_at` datetime(6) NOT NULL, `revoked_at` datetime(6) DEFAULT NULL, PRIMARY KEY (`token_hash`), KEY `studio_session_expiry` (`expires_at`), KEY `studio_session_user` (`user_id`,`expires_at`), CONSTRAINT `studio_session_user_fk` FOREIGN KEY (`user_id`) REFERENCES `studio_users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT, CONSTRAINT `studio_session_times` CHECK ((`expires_at` > `created_at`)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_subscriptions
CREATE TABLE `studio_subscriptions` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `owner_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_key` varchar(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_account` varchar(80) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `provider_subscription_id` varchar(128) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `plan_version_id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `state` varchar(24) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `period_start` datetime(6) NOT NULL, `period_end` datetime(6) NOT NULL, `cancel_at_period_end` tinyint(1) NOT NULL, `revision` bigint unsigned NOT NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `subscription_owned` (`owner_id`,`id`), UNIQUE KEY `subscription_owned_provider` (`owner_id`,`id`,`provider_key`,`provider_account`), UNIQUE KEY `subscription_provider` (`provider_key`,`provider_account`,`provider_subscription_id`), KEY `subscription_plan_fk` (`plan_version_id`), CONSTRAINT `subscription_plan_fk` FOREIGN KEY (`plan_version_id`) REFERENCES `studio_credit_plan_versions` (`id`), CONSTRAINT `subscription_user_fk` FOREIGN KEY (`owner_id`) REFERENCES `studio_users` (`id`), CONSTRAINT `subscription_revision` CHECK ((`revision` between 1 and 2147483647)), CONSTRAINT `subscription_state` CHECK (((`state` in (_latin1'PENDING',_latin1'ACTIVE',_latin1'PAST_DUE',_latin1'CANCELLED',_latin1'ENDED')) and (`cancel_at_period_end` in (0,1)))), CONSTRAINT `subscription_times` CHECK (((`period_end` > `period_start`) and (`updated_at` >= `created_at`))) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
studio_users
CREATE TABLE `studio_users` ( `id` char(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `email` varchar(254) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `password_hash` varbinary(72) NOT NULL, `enabled` tinyint(1) NOT NULL DEFAULT '1', `created_at` datetime(6) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `studio_user_email` (`email`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
积分账本链路
Creatify · 接口清单
共 55 个公开接口,取自源码路由盘点。路径都以 /v1 开头;写操作需要会话 Cookie、可信 Host/Origin 与 CSRF;带品牌的路径用 ?profile=creatify;共享的登录、素材、模型目录路径不接受 profile 参数。
Agent/统一动作 7 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/interactions | runInteractions | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/interactions/{interaction_id}/responses | respondInteraction | client_action_id, card_sha256, action, values | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/interaction-actions/{client_action_id} | interactionAction | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/model-changes | changeConversationModel | client_action_id, expected_revision, agent_model, expected_attempt? | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/model-changes/{client_action_id} | modelChangeAction | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/stop | stopRun | client_action_id, expected_attempt? | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/stop-actions/{client_action_id} | stopAction | 200 |
Asset 4 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/assets | listAssets | 200 | |
| POST | /v1/assets | uploadAsset | file | 201 |
| GET | /v1/assets/{asset_id} | getAsset | 200 | |
| GET | /v1/assets/{asset_id}/content | assetContent | 200/206 |
LoginSession 1 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| POST | /v1/auth/logout | logout | 200 |
MaaBinding 5 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/maa/model-options | maaModels | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/messages | sendMaaMessage | client_action_id, content | 202 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/actions/{client_action_id} | getMaaAction | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/state | getMaaState | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/runs/{run_id}/events | maaEvents | 200 |
Media 11 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/media/models | publicMediaModels | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests | createMediaRequest | client_request_id, model_id, model_version_id, prompt, duration_seconds, ratio, resolution, admission? | 200 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests | mediaRequestByClient | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id} | getMediaRequest | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs/{job_id} | getMediaJob | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs/{job_id}/output | getMediaOutput | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id}/job | mediaJobByRequest | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/{request_id}/approve | approveMediaRequest | client_approval_id, request_sha256, quote_sha256 | 200 |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/media/requests/from-maa | createMediaRequestFromMaa | input, source_run_id, source_assistant_sha256, admission? | 200 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/jobs | listMediaJobs | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/media/intents | listMediaIntents | 200 |
Other 9 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects/{project_id}/canvas/revisions | listCanvasRevisions | 200 | |
| GET | /v1/projects/{project_id}/canvas/revisions/{revision} | getCanvasRevision | 200 | |
| POST | /v1/projects/{project_id}/canvas/revisions/{revision}/restore | restoreCanvasRevision | expected_revision | 200 |
| GET | /v1/projects/{project_id}/document/revisions | listTimelineRevisions | 200 | |
| GET | /v1/projects/{project_id}/document/revisions/{revision} | getTimelineRevision | 200 | |
| POST | /v1/projects/{project_id}/document/revisions/{revision}/restore | restoreTimelineRevision | expected_revision | 200 |
| GET | /v1/projects/{project_id}/assets | listProjectAssets | 200 | |
| POST | /v1/projects/{project_id}/assets | attachProjectAsset | asset_id, expected_revision | 200 |
| POST | /v1/projects/{project_id}/assets/{asset_id}/detach | detachProjectAsset | expected_revision | 200 |
Project 15 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| GET | /v1/projects | listProjects | 200 | |
| POST | /v1/projects | createProject | title | 201 |
| GET | /v1/projects/{project_id} | getProject | 200 | |
| GET | /v1/projects/{project_id}/conversations | listConversations | 200 | |
| POST | /v1/projects/{project_id}/conversations | createConversation | title | 201 |
| GET | /v1/projects/{project_id}/conversations/{conversation_id} | getConversation | 200 | |
| GET | /v1/projects/{project_id}/canvas | getCanvas | 200 | |
| POST | /v1/projects/{project_id}/canvas | saveCanvas | expected_revision, state | 200 |
| GET | /v1/projects/{project_id}/document | getDocument | 200 | |
| POST | /v1/projects/{project_id}/document | saveDocument | expected_revision, state | 200 |
| GET | /v1/projects/{project_id}/export-jobs | listExportJobs | 200 | |
| POST | /v1/projects/{project_id}/export-jobs | queueExport | document_revision, output? | 202 |
| GET | /v1/projects/{project_id}/export-jobs/{job_id} | getExportJob | 200 | |
| GET | /v1/projects/{project_id}/conversations/{conversation_id}/maa/binding | getMaaBinding | 200 | |
| POST | /v1/projects/{project_id}/conversations/{conversation_id}/maa/binding | bindMaa | agent_model XOR use_default:true | 200 |
User 3 个
| 方法 | 路径 | operationId | 请求字段 | 成功 |
|---|---|---|---|---|
| POST | /v1/auth/register | register | email, password | 201 |
| POST | /v1/auth/login | login | email, password | 200 |
| GET | /v1/auth/session | session | 200 |
Creatify 自己公开的接口调用流程(来自其官方资料)
| 步骤 | 调用关系 | 操作 | 证据 |
|---|---|---|---|
| 导入商品链接 | 接入程序 → 公共API | POST https://api.creatify.ai/api/links/,body含url;鉴权字段X-API-ID/X-API-KEY;保留Link.id和link.id。 | A |
| 修订商品资料 | 接入程序 → 公共API | PUT /api/links/{id}/修订产品资料;编辑字段和路径id规则以官方schema为准。 | A |
| 生成脚本候选 | 接入程序 → 公共API | POST /api/ai_scripts/;返回脚本任务id、workspace/product引用、status及generated_scripts[].paragraphs/script_name/script_style/title。 | A |
| 请求多个预览 | 接入程序 → 公共API | POST /api/link_to_videos/preview_list_async/;link引用外层Link.id,可传visual_styles[]、video_length、aspect_ratio等;返回任务id与previews[].media_job。 | A |
| 选中候选渲染 | 接入程序 → 公共API | POST /api/link_to_videos/{id}/render_single_preview/;path为LinkToVideo.id,body为media_job:UUID。 | A |
| 查询每个输出 | 接入程序 → 公共API | GET /api/link_to_videos/{id}/;检查outputs[].status、progress、failed_reason和video_output,不仅检查顶层status。 | A |
| 读取模型参数 | 接入程序 → 公共API | GET /api/asset_generator/schemas/?model_name=...;返回model_name、generation_type与input_params_schema及UI扩展字段。 | A |
| 提交通用生成 | 接入程序 → 公共API | POST /api/asset_generator/;body含model_name、input_params、可选webhook_url;返回生成任务id。 | A |
| 收取产物状态 | 接入程序 → 公共API | GET /api/asset_generator/{id}/按任务id取status与assets[]{id,type,url,thumbnail_url,name};可选由服务向客户webhook_url发送回调。 | A |
Creatify · 代码与下载
0.3 MB · 54 个文件 · SHA-256
d74028b901345ea8c6fafda5fcb7c274e6dd59cdd8dd2532ce7931cc1364a07f下载:creatify-replica.zip · 后端与合同 · 全部代码
| 目录 | 内容 |
|---|---|
| frontend/ | Creatify 前端:<code>candidate-8875-unified-v22.html</code> 及它引用的全部脚本与样式 |
| contracts/ | 本品牌的表结构 SQL、ER(svg / mmd)、外键清单;接口目录(json / csv);共享身份库表结构 |
| README.md | 怎么运行、需要自备什么 |
运行前端
python3 -m http.server -d frontend 8791
# 打开 http://127.0.0.1:8791/agent-integration/apps-production-brand-v14/creatify/candidate-8875-unified-v22.htmlbackend-and-contracts.zip;all-brands-code.zip 是全部。包里没有任何凭据、数据库备份或媒体文件,已做敏感串扫描。MAA_AGENT_ROOT)、模型网关与对象存储配置。静态前端单独打开不需要后端,但登录、对话、生成、导出需要整套服务。复刻完成度(审计 2026-10-19)
结论:不是完美复刻。官方资料里的 45 项能力:实测跑通 0、只有通用对话 1、后端有但没跑过 5、没有后端 39。
界面对照(Agent 首页(已登录)):真实页面采集到 20 个控件 / 标题文字,复刻页找到 3 个;位置偏差中位数 35 px(0/3 个在 24 px 内)。缺的有:Creatify API、Help & Feedback、Open notifications、Resize sidebar、Hide history、More、Create project、Codex参考体验 · 咖啡广告(仅计划)、Settings、Filter、Tips、Create, analyze, and scale your ads, Demo…。
逐个点击(已登录首页):27 个可点控件,点了有效 4 个,只提示“此功能正在接入” 15 个,没反应或只变样式 3 个,禁用 5 个,未点(发送 / 删除 / 退出等)0 个。
只提示“正在接入”的控件(15 次点击,15 种)
Apps、My Brand、Studio、MCP、API、Help、◧、+、☰、(图标)、←、→、Launch Video、Product Demo、UGC Ad
点了没反应或只变样式的控件(3 次点击,3 种)
Creatify home、Ad Agent、(图标)
复刻页自报的绑定状态(页面内嵌的绑定清单):原生工作区控件(新建项目、会话、登录等)6 / 10 个没有绑定到原页面的控件,由统一的工作区条代替;路由都标为本地已确认;输入框 2 个标为“需要修结构”。
最终设计 · 总览与架构
- Go 模块化单体 core + 6 个独立服务(Agent 运行时、模型网关、渲染、采集、实时推送、分析);品牌和入口是配置,不是代码分支。
- 对话、画布、时间线共用一份项目文档,Agent 只改一个镜头不会误伤其他镜头。
- Agent、API、MCP 同一套工具面:鉴权、审批、计费只做一遍。
我们的最终设计叫 Lumen。它不是七个竞品的拼盘,而是先把七个竞品逐一复刻、逐项测试,再把真实跑过的做法和踩过的坑归纳成一套设计:保留每一家最有效的一件事,去掉重复和不安全的部分。
flowchart TB
subgraph Client[客户端]
WEB[Web 工作台<br/>对话 · 画布 · 时间线]
EXT[外部 Agent / MCP / API]
end
subgraph Core[核心服务 Go 模块化单体]
PRJ[项目 · 文档<br/>doc_version]
AGT[Agent 编排接入]
BIL[账务 · 报价 · 冻结]
AST[素材]
INT[创作意图 intent<br/>入口适配器]
end
subgraph Runtime[运行时]
RUN[Agent Runtime Python]
TMP[Temporal 工作流]
GWY[模型网关<br/>注册表 + 适配器]
RND[渲染集群]
end
WEB --> PRJ
WEB --> AGT
EXT --> AGT
AGT --> RUN
INT --> AGT
RUN -->|同一套工具面| PRJ
RUN --> BIL
BIL --> TMP
TMP --> GWY
TMP --> RND
GWY --> M[(视频 / 图片 / 声音模型)]
PRJ --- DB[(PostgreSQL)]
BIL --- DB
AST --- DB- 一个核心,多个入口。七个竞品的后端结构在我们的实测里几乎一致(同样的 24 张表、同样的 55 个接口形状),区别只在入口、模板和视觉。所以内核只做一份,品牌与入口都是配置和适配器。
- 对话、画布、时间线共用一份文档。这是 TopView、LibTV、Flova、invideo 各自走向的同一个终点,把它做对一次,Agent 才能只改一个镜头。
- Agent、API、MCP 用同一套工具面。外部 Agent 接入几乎零成本,计费、审批、审计只做一遍。
本页涉及的决策
D1 一个项目、三种视图共用一份文档 · D9 Skill 与模板有版本,会话固定绑定版本 · D10 模型靠注册表和适配器接入 · D11 不同入口汇成同一个「创作意图」 · D14 能力对内外一致:Agent、API、MCP 用同一套工具面 · D15 不展示做不到的功能 · D17 一个共享内核加品牌配置,而不是七套代码 (借鉴来源与原因见“设计取舍与原因”)
原架构细节(已按最终设计改写,展开查看)
2.1 架构原则
- 模块化单体 + 少量独立服务:业务域强耦合部分(项目/画布/账务/素材)放在一个 Go 单体内按模块分层;只有"生命周期、伸缩特性、语言栈"明显不同的部分独立:Agent Runtime(Python)、模型网关、渲染集群、采集器,以及容量模型不同的实时推送与分析,共 6 个(见 2.3)。
- 异步任务全部走持久化工作流:生成/渲染/采集一律由 Temporal 编排,不再自造租约与轮询。
- 单一事实来源:PostgreSQL 为唯一业务库;所有状态机显式建模,状态只前进;副作用经 outbox 外发。
- 账务先于调用:先报价、由用户批准,批准时冻结积分,再调用供应商;结果确定后结算或释放,状态不明时保持冻结、人工核对。
- 画布即数据:Agent 的每个产物都是画布节点,用户与 Agent 编辑同一份文档(版本化)。
- 供应商可替换:业务代码只依赖"能力(capability)",不依赖具体模型名。
2.2 总体分层
flowchart TB
subgraph Client[客户端]
W[Web 应用 Next.js
画布 / 时间线 / 对话]
O[开放平台
REST · Webhook · MCP · Skill]
end
subgraph Edge[接入层]
GW[API Gateway / BFF
鉴权 · 限流 · WAF]
RT[实时通道
SSE / WebSocket]
end
subgraph Core[核心域服务 Go 模块化单体]
ID[Identity & Org]
PR[Project & Canvas]
AS[Asset & Library]
BL[Billing & Ledger]
SF[Safety]
TK[Task Facade]
ADM[Admin & Config]
end
subgraph Agent[Agent 域 Python]
AR[Agent Runtime
LangGraph]
SK[Skill Registry]
TL[Tool Servers MCP]
end
subgraph Gen[生成域]
MG[Model Gateway]
RN[Render Service
FFmpeg · GPU]
CR[Crawler / Collector]
end
subgraph Plat[平台层]
TP[Temporal]
PG[(PostgreSQL)]
RD[(Redis)]
KF[(Kafka)]
OS[(COS/S3 + CDN)]
CH[(ClickHouse)]
VS[(pgvector)]
end
W --> GW
O --> GW
W --> RT
GW --> Core
GW --> AR
Core --> TP
AR --> TP
TP --> MG
TP --> RN
TP --> CR
AR --> TL
TL --> Core
MG --> Vendors[(模型供应商
Seedance · Kling · Wan · Veo · GPT-Image ...)]
Core --> PG
Core --> RD
Core --> KF
RN --> OS
KF --> CH
AS --> VS
2.3 服务清单与边界
| 服务 | 语言 | 职责 | 伸缩特性 | 独立理由 |
|---|---|---|---|---|
core(单体) | Go | Identity、Org、Project、Canvas、Asset、Billing、Safety、Admin、Task Facade | 水平扩展,无状态 | 强事务边界,合并部署降低分布式事务成本 |
agent-runtime | Python | LangGraph 执行、Skill 加载、HITL 暂停恢复、事件发布 | 按活跃会话伸缩;CPU/内存型 | LLM 生态在 Python;崩溃隔离 |
model-gateway | Go | 能力路由、供应商适配器、限额、回调/轮询、成本记录 | 按并发生成数伸缩;I/O 型 | 供应商变化快,独立发布;可对外售卖 |
render | Go + FFmpeg | 时间线合成、转码、字幕烧录、封面;Worker 池 | CPU/GPU Pool,Spot 实例 | 资源画像完全不同 |
collector | Python/Playwright | 电商链接/社媒视频采集、解析 | 浏览器池,IP 池 | 反爬、合规与隔离网络 |
realtime | Go | SSE/WS 事件推送,基于 Redis Stream 与 Kafka 订阅 | 连接数伸缩 | 长连接与普通 API 容量模型不同 |
analytics | Go + ClickHouse | 埋点、用量、成本、漏斗 | 写吞吐型 | OLAP 与 OLTP 隔离 |
core 内部模块与依赖规则
core/
├── identity/ 用户、组织、工作区、角色、API Key、OAuth
├── project/ 项目、画布文档、节点、版本、协作锁
├── asset/ 素材、解析、打标、向量检索、角色资产(asset.kind = character_ref)
├── billing/ 账本、冻结/结算、订阅、订单、支付、发票
├── safety/ 审核策略、违禁词、风控规则
├── taskfacade/ 对外统一"生成任务"视图,屏蔽 Temporal/Gateway 细节
├── admin/ 模型目录、价格、限额、配置、审计
└── platform/ db、cache、outbox、event、temporal client、telemetry(只被上面引用)
规则:模块间只通过 Go interface(每个模块的 api 包)调用;禁止跨模块直接读表;
CI 里用 depguard + archunit 风格测试强制,违反即失败。
2.4 领域模型(限界上下文)
下图由最终 DDL 生成,用的是真实表名和真实基数(鸦脚符号)。原设计这里画的 CANVAS 实体在最终版不单独建表:画布 = project + node + edge;原图里“一个工作区一个账本账户”也不对,最终版每个工作区按用途有多个账户(UNIQUE(workspace_id, kind))。完整 46 张表见 ER 图页。
erDiagram
workspace ||--o{ member : "workspace_id"
workspace ||--o{ project : "workspace_id"
asset |o--o{ project : "cover_asset_id"
project ||--o{ node : "project_id"
workspace ||--o{ node : "workspace_id"
node |o--o{ node : "parent_id"
node ||--o{ node_version : "node_id"
asset |o--o{ node_version : "output_asset_id"
generation_task |o--o{ node_version : "task_id"
project ||--o{ edge : "project_id"
node ||--o{ edge : "src_node_id"
node ||--o{ edge : "dst_node_id"
project ||--o{ timeline : "project_id"
workspace ||--o{ timeline : "workspace_id"
workspace ||--o{ export_job : "workspace_id"
timeline ||--o{ export_job : "timeline_id"
asset |o--o{ export_job : "output_asset_id"
hold |o--o| export_job : "hold_id"
project ||--o{ agent_session : "project_id"
workspace ||--o{ agent_session : "workspace_id"
agent_session ||--o{ agent_run : "session_id"
workspace ||--o{ agent_run : "workspace_id"
agent_run ||--o{ run_event : "run_id"
agent_run ||--o{ interaction : "run_id"
workspace ||--o{ generation_task : "workspace_id"
project |o--o{ generation_task : "project_id"
node |o--o{ generation_task : "node_id"
agent_run |o--o{ generation_task : "run_id"
hold |o--o| generation_task : "hold_id"
generation_task ||--o{ task_attempt : "task_id"
workspace ||--o{ asset : "workspace_id"
generation_task |o--o{ asset : "origin_task_id"
workspace |o--o{ ledger_account : "workspace_id"
ledger_account ||--o{ ledger_entry : "account_id"
point_lot |o--o{ ledger_entry : "lot_id"
workspace ||--o{ point_lot : "workspace_id"
workspace ||--o{ hold : "workspace_id"
generation_quote ||--o{ generation_approval : "quote_id"
generation_task |o--o{ generation_approval : "task_id"
org ||--o{ workspace : "org_id"
app_user ||--o{ member : "user_id"
app_user ||--o{ agent_session : "user_id"
app_user ||--o{ project : "owner_id"
skill ||--o{ skill_version : "skill_id"
skill ||--o{ agent_session : "skill_id"
workspace |o--o{ skill : "owner_workspace_id"
workspace ||--o{ generation_quote : "workspace_id"
agent_run |o--o{ generation_quote : "source_run_id"
project ||--o{ project_asset_ref : "project_id"
asset ||--o{ project_asset_ref : "asset_id"
timeline ||--o{ timeline_version : "timeline_id"
2.5 关键架构决策(ADR 摘要)
| 编号 | 决策 | 备选 | 理由 | 代价/风险 |
|---|---|---|---|---|
| ADR-01 | 模块化单体 + 6 个独立服务(2.3) | 全微服务;全单体 | 团队规模 20–30 人,事务边界集中于项目/账务 | 单体需严格依赖规则防腐烂 |
| ADR-02 | Temporal 作为唯一长任务编排 | 自研租约+轮询(旧方案);Celery;Argo | 旧系统两套任务模型(租约 supervisor、outbox+Redis Streams)维护成本高;Temporal 内建重试、定时、信号、可见性 | 引入新基础设施,需要团队学习;Worker 代码必须确定性 |
| ADR-03 | 画布文档 = 节点/边表 + 版本表(非 CRDT) | Yjs CRDT 全文档 | 节点粒度冲突少,服务端校验与计费需要结构化数据;画布协同用节点级乐观锁 + 在线提示 | 多人同节点编辑体验弱于 CRDT,可接受 |
| ADR-04 | 统一能力(capability)抽象而非模型名 | 业务直接选模型 | 供应商频繁换代,业务层不应改代码 | 能力矩阵需要运营持续维护 |
| ADR-05 | 积分账本复式记账 + 冻结 | 余额字段加减 | 旧系统出现过修数据 SQL 与退款处置补丁 | 实现复杂度更高,但换来可审计 |
| ADR-06 | 事件:Kafka(业务事件)+ Redis Stream(会话实时流) | 统一用 Kafka | 实时流需低延迟、短保留、按会话订阅 | 两套中间件,用统一事件信封规范抹平 |
| ADR-07 | PostgreSQL 唯一业务库,禁用数据库外键 | MySQL;加外键 | 沿用旧系统"无外键、应用层保证"的经验以便分库;PG 提供 JSONB、pgvector、部分唯一索引 | 一致性靠应用与对账任务 |
| ADR-08 | Agent Runtime 用 LangGraph,产物写回画布 | 自研 Agent 循环 | 旧 maa_agent 已验证 interrupt/checkpoint 价值;可迁移 Skill 资产 | 框架升级风险,通过适配层隔离 |
| ADR-09 | 双 Region(国内 / 海外)数据隔离部署 | 单 Region 全球 | 合规、供应商可用性、延迟 | 运维成本翻倍;两 Region 共享代码、独立数据 |
2.6 Agent 架构
flowchart LR U[用户消息/链接/参考视频] --> O[Orchestrator] O -->|plan| P[Plan 节点
可编辑] O --> E1[采集专家] O --> E2[策略/脚本专家] O --> E3[分镜专家] O --> E4[生产专家] O --> E5[后期专家] E1 & E2 & E3 & E4 & E5 -->|MCP tool call| T[(Tool Servers)] T --> C[Canvas API] T --> G[Generation API] T --> A[Asset API] E4 -->|提交| TF[Task Facade] O <-->|interrupt / resume| H[HITL 卡片] O --> CP[(Checkpoint PG)]
- Skill 包:目录结构
skill.yaml + prompts/ + tools.json + evals/,版本化(skill_version)、可发布到开放平台(POST /skills);会话创建时固定一个版本。灰度发布没有单独建模。旧ad-video-editing / viral-ad-replication / product-link-collection等能力包直接作为初始 Skill 迁移。 - 工具通过 MCP:Core 与 Gateway 各暴露 MCP Server,Agent 与外部 Agent 使用同一套工具,避免"内部一套外部一套"。
- 产物溯源:每个视频节点的版本(
node_version)必须记录task_id;经task_attempt可追到provider_task_id,经generation_task.request_hash可追到输入。Agent 不能凭空写入成片 URL(继承旧系统硬规则)。 - 预算守卫:Run 持有
budget_centi(预算)与spent_centi(已花);接近上限发budget.warning,超限进入waiting_user由用户决定。
2.7 部署视图(单 Region)
flowchart TB CDN[CDN] --> LB[LB / Ingress] LB --> AP[core ×N] LB --> RTM[realtime ×N] LB --> AG[agent-runtime ×N] AP --> PGM[(PG 主)] PGM --> PGR[(PG 只读副本 ×2)] AP --> RDS[(Redis Cluster)] AP --> KFK[(Kafka 3 节点)] AP --> TPS[Temporal 集群] TPS --> WK1[workflow worker] WK1 --> MGW[model-gateway ×N] WK1 --> RNW[render worker
CPU Pool + GPU Pool] WK1 --> COL[collector 浏览器池] RNW --> COS[(对象存储)] KFK --> CHS[(ClickHouse)]
最终设计 · Agent 交互过程设计
- 一条链:发送前说明准入 → 澄清卡补信息 → 方案落成镜头节点 → 先报价再批准 → 生成。
- 批准是硬门槛且带哈希:用户看到的价格和提示词就是实际执行的;报价过期就拒绝,不建任务不扣费。
- 每个动作都有回执、每个事件都有序号:断线、刷新、重复点击都安全。
- 打开或刷新会话先读快照、再接事件流:进度、停止键、未答的卡片、写到一半的回复都能恢复;停止后的半截回复保存为“已停止”。
下面的过程把竞品里最好的几件事串成一条链:发送前说明准入(Flova)→ 结构化澄清卡(CreaTok)→ 方案落成镜头节点(CreaTok、LibTV)→ 先报价再批准,批准带哈希(我们复刻里跑通;否决 LibTV 的只提醒)→ 生成、停止、恢复都幂等(Pollo 的流式事件 + 我们的修复)。
sequenceDiagram
autonumber
participant U as 用户
participant W as 工作台
participant C as Core
participant R as Agent Runtime
participant B as 账务
participant T as Temporal
participant G as 模型网关
U->>W: 输入需求(可 / 选 Skill,@ 引用素材)
W->>C: GET admission(额度、积分、原因)
C-->>W: 可用 / 不足 + 下一步
W->>C: POST messages {client_action_id}
C->>R: 创建 Run
R->>C: 事件(每条带递增 seq)
C-->>W: 事件流(SSE,经实时通道,断线按 seq 续读)
R->>C: 需要补充信息 → interaction(card_sha256)
C-->>W: 澄清卡(必填 / 可选)
U->>W: 提交答案
W->>C: respond {card_sha256, values}
C->>R: 恢复同一个 Run
R->>C: 写入 scene / shot 节点(node_version)
C-->>W: 画布与对话同步出现镜头
U->>W: 只改第 2 个镜头
R->>C: 新 node_version,其余镜头不变
U->>W: 生成
W->>C: POST generations:quote
C->>B: 计算报价
B-->>W: quote_id + 两个哈希 + expires_at
U->>W: 批准
W->>C: POST generations {quote_id, client_approval_id, 哈希}
C->>B: 冻结额度
C->>T: 启动工作流
T->>G: submit
G-->>T: 结果
T->>B: 结算 / 失败释放
C-->>W: 任务完成,素材入库- 准入前置(Flova):失败发生在发送之后用户会反复重试;提前说明一次,少一次无效请求。
- 澄清是对象不是段落(CreaTok 已真实跑通两轮):必填校验、刷新后仍在、过期有明确状态,同一个 Run 恢复不会恢复两次。
- 方案落成节点:只改第 2 个镜头就只产生一个新版本,其余镜头保持,重生成只为改动的镜头计费。
- 批准是硬门槛且带哈希:LibTV 的预算只在达到阈值时提醒,不阻止下一笔扣费;哈希绑定保证用户看到的价格和提示词就是实际执行的。我们的真实测试里,报价过期后批准被拒,没有建任务也没有扣费。
- 动作都有回执:长回复必然遇到断线、刷新和重复点击;序号和幂等让这些情况安全。
对话状态与恢复规则
同一会话里的消息、运行、卡片和事件都以服务端为准;浏览器只保存未提交的卡片草稿。
| 场景 | 用户看到 / 能做什么 | 前端 | 后端 | 保存 | 接口 / 事件 | 验收 |
|---|---|---|---|---|---|---|
| 首次发送 | 用户气泡立即出现;发送键变为停止键;回复区显示“处理中 0s”计时 | 先用临时 id 渲染气泡;收到 202 后换成服务端 message_id;URL 改为 /projects/{pid}/agent/{session_id} | 写用户消息与 run_action;创建 run(queued);返回 run_id、message_id | agent_message(user)、agent_run、run_action;agent_session.last_message_at | POST /sessions/{id}/messages → 202;事件 run.started、user.message | AGT-01 |
| 执行中展示 | 过程区逐行出现步骤(自然语言标题 + 状态),正文逐字出现;输入框上方“任务进度 n/m” | 按 (run_id, seq) 去重;只渲染 session_id 等于当前会话的事件;正文以 assistant.message 为最终版本 | Runtime 为每个工具调用写一句用户可读的 title;回复文字每 ≤2 秒落库一次 | run_event(工具、计划事件);agent_message.content / content_seq | 事件 tool.started/completed/failed(含 title)、plan.updated、assistant.delta、assistant.message | AGT-01、AGT-13 |
| 运行中再发消息 | 消息显示为用户气泡,标签“已补充到当前任务”;停止键仍在,输入框有字时按钮为发送 | 发送同一接口;收到 mode=guidance 时加标签 | 追加到当前 run 的下一步输入;不新建 run | agent_message(delivery=guidance) | POST messages → 202 mode=guidance | AGT-02 |
| 等待用户补充 / 确认 | 卡片占据输入框位置:一次一题、分页“1 / N”、必填带 *、选项 + 自由输入、取消 / 继续;历史列表该会话标“需要输入” | 已填答案存浏览器草稿(卡片 id + card_sha256),刷新不丢;提交一次带全部答案 | run 进入 waiting_user,同一时刻只有一张未关闭的卡;答案按卡片 schema 校验后恢复同一个 run | interaction(pending → resolved) | 事件 interaction.requested / resolved;POST interactions/{id}:respond | AGT-05、06、07、17 |
| 积分不足暂停 | 卡片“积分不足,还差 X 积分 · 去充值 / 我已充值,继续”;历史标“需要输入” | “去充值”打开购买页;“我已充值,继续”调用 respond | 付费步骤前做准入检查;不足则发 kind=payment_required 的卡;respond 时再查一次,够则恢复同一个 run,不够返回 402 并保留卡片 | interaction(payment_required) | GET admission;POST respond → 200 / 402 insufficient_points | AGT-14 |
| 停止 | 停止后保留已输出的文字,标“已停止”;刷新后仍是同样内容 | 点击即禁用停止键,等回执;回执 unknown 时提示“正在确认是否已停止”并轮询 run | 幂等停止;把已输出文字存为 stopped 消息;未关闭的卡片 cancelled;已批准的生成任务不取消 | agent_message(stopped)、run_action(stop) | POST /runs/{id}:stop;事件 assistant.message(status=stopped)、run.cancelled | AGT-03、12 |
| 失败与超时 | 回复下方显示错误原因和“重试” | 重试 = 用新的 client_action_id 再发上一条用户消息 | 运行 30 分钟无结束事件判超时:run failed(run_timeout),流式消息 failed,未提交任务的冻结释放 | agent_run.error_code;agent_message(failed) | 事件 run.failed | AGT-19 |
| 重复提交 | 同一条消息只出现一次 | 每次点击发送生成一个 client_action_id;网络重试沿用同一个 | 同 id 同内容返回原回执;同 id 不同内容 409 | run_action、agent_message UNIQUE(session_id, client_action_id) | POST messages → 202 / 409 idempotency_conflict | AGT-01 |
| 刷新 / 离开后重新进入 | 回到同一会话:历史消息、进行中的进度和停止键、未答的卡片、写到一半的回复都在 | 先 GET /sessions/{id} 渲染,再用 Last-Event-ID = run_id:last_seq 接事件流 | 快照里返回流式消息已保存的文字和 active_run.last_seq;接流时若缺少未落库的增量,先发 assistant.snapshot | 同上(全部来自库,不依赖浏览器) | GET /sessions/{id};GET /sessions/{id}/events | AGT-11 |
| 断线重连 | 顶部提示“连接中断,正在重试”,带“重试”按钮;恢复后提示消失 | 指数退避重连 3 次;仍失败则每 5 秒轮询 GET /runs/{id} 直到连上 | 事件按 seq 补发,恰好一次、有序 | — | GET /sessions/{id}/events(Last-Event-ID) | AGT-04、18 |
| 多个会话同时运行 | 历史列表里运行中的会话带转圈标记,等待用户的带“需要输入” | 每个页面只订阅当前会话的事件流;历史列表打开时拉取一次、之后每 30 秒刷新 | 同一会话最多 1 个活跃 run;同一工作区并发上限按套餐 2 / 6 / 20,超出 429 run_busy | agent_run(one_active_run_per_session) | GET /projects/{id}/sessions(active_run、needs_action) | AGT-15 |
stateDiagram-v2 [*] --> queued: POST messages(新任务) queued --> running: 工作流启动 running --> waiting_user: 发出卡片(含 payment_required) waiting_user --> running: respond(同一个 run) waiting_user --> cancelled: 卡片过期 / 用户直接发新消息 / 停止 running --> succeeded: assistant.message + run.completed running --> failed: 出错 / 30 分钟超时 running --> cancelled: stop(已输出文字存为“已停止”)
消息的组成与呈现
| 组成部分 | 数据来源 | 呈现规则 |
|---|---|---|
| 用户消息 | agent_message(role=user) | 右侧气泡,附件显示缩略图;操作:复制。补充指令带“已补充到当前任务”标签。 |
| 过程区 | tool.* 事件的 title + status;run.started 的时间 | 运行中展开:“处理中 Ns”计时,每步一行“标题 + 状态”(进行中 / 完成 / 失败)。结束后折叠为“已处理 N 步 · 用时 Ns”,可展开。只显示 Runtime 写的 title,不显示原始工具名,也不显示模型原始思考。 |
| 任务进度 | plan.updated | 输入框上方“任务进度 n/m”,当前项高亮,可收起;run 结束后消失。 |
| 正文 | assistant.delta → assistant.message | Markdown:标题、列表、表格。流式期间末尾显示光标;收到 assistant.message 后整段替换为最终文本。 |
| 卡片 | interaction | 显示在输入框位置(见上表“等待用户补充”);一次一题,最多 5 题。 |
| 产物 | node.created / node.updated、task.progress、asset | 标签形式(镜头、文档、图片、视频),点击定位到画布节点或素材;生成中显示进度百分比。 |
| 后续建议 | assistant.message.suggestions | 只在最新一条助手消息下方显示,最多 3 条,点击即作为新消息发送。 |
| 消息底栏 | agent_message.status、completed_at | 时间 + 复制;stopped 显示“已停止”;failed 显示错误和“重试”。 |
| 会话用量 | ledger_entry(ref_type=run,决策 D4)按会话汇总,随快照返回 usage_centi | 输入框下方“本会话已用 X 积分”;首次发送前提示一次“对话推理按用量扣积分,生成素材另计”。 |
回复内容规范
- 开头一句复述已知条件(产品、时长、画幅、语言);缺的信息先用默认值并写明,例如“画幅先按 9:16”,或用
[品牌名]这样的占位符。 - 不编造卖点、功效、价格和数据;没有依据时写明“以下只依据你提供的信息”。
- 能先给方案就先给。只有缺少会改变结果的必填信息(如产品名、口播语言)时才发卡片,一张卡最多 5 题。
- 方案型回复的固定结构:标题(含时长与画幅)→ 核心创意一句 → 分镜表(镜头 · 时长 · 画面 · 运镜 · 字幕 / 旁白 · 声音)→ 制作提示(模型最短时长、一致性参考图、字幕后期叠加)→ 最多 2 个下一步问题。
- 回复语言跟随用户最近一条消息;不输出内部指令、工具名和原始推理。
竞品对话样式参考 2026-10-20 同一任务实测;invideo 未取得回复
| 竞品 | 整体 | 执行中 | 后续建议 | 等待 / 确认 |
|---|---|---|---|---|
| Pollo | 深色;右侧用户气泡;正文 Markdown + 表格 | “Completed ⌄ · Thinking complete ›”+ 自然语言步骤 | “What’s next” 3 条 | 积分不足时输入框上方卡片“Purchase completed? / I’ve paid, continue” |
| CreaTok | 浅色,Geist 字体,正文 14px / 20px #0a0a0a | “处理中 Ns”计时,左边线缩进的叙述 + ✓ 步骤,结束折叠为“已处理 Ns” | 无 | 卡片替换输入框,一次一题“1 / 7”,必填 *,取消 Esc / 继续 ↵ |
| Creatify | 深色,正文衬线体 Source Serif 4 / Noto Serif SC 16px / 26px;用户气泡 #131414、1.5px 边框、10px 圆角 | “Making sense of it… Ns”→“Working ⌄”步骤 →“Writing the reply…” | “Suggested follow-ups” 3 条 | 无卡片:先出方案,用 [方括号] 占位,最后列出要补充的信息;输入框下显示本次花费 |
| TopView | 深色侧栏 Agent | “Planning shot sequence…”+ 骨架卡 | 无 | 结果是分镜卡(时长 · 画幅 · 分段),卡上“Use Prompt / Generate Storyboard / Generate Video”,确认前不改时间线 |
| LibTV | 深色画布侧栏 TV Director | “思考中…”直接展开模型原始推理(含内部指令,不应照搬) | 无 | 首次发送前确认:推理实时扣积分、自动生成默认关闭、预算提醒阈值 |
| Flova | 深色项目工作区 | “已处理 N 项”,每步“动作 + 状态 · 对象”,涉及的文件以标签显示;结束后折叠 | 无(回复下方“这个结果怎么样?”) | 方案写进项目文档,对话里同时给出全文和文档标签 |
本页涉及的决策
D2 先报价,再批准,批准带哈希 · D4 文字推理成本和媒体成本分开显示 · D5 缺信息时用结构化澄清卡 · D6 方案是结构化实体,不是一大段文字 · D7 发送前就说明准入条件 · D8 事件流带游标,可停止、可恢复 · D16 登录与会话状态要有可见入口 (借鉴来源与原因见“设计取舍与原因”)
本页相关接口 15 条,完整清单在“接口清单”
| 方法 | 路径 | 说明 | 来源 |
|---|---|---|---|
| POST | /v1/generations:quote | 报价,不扣费;返回 quote_id、request_sha256、quote_sha256、expires_at | 决策 D2 |
| POST | /v1/generations | 批准并创建任务:body 带 quote_id、client_approval_id、两个哈希;重放返回同一任务;报价过期返回 409 quote_expired | 决策 D2 |
| POST | /v1/sessions/{id}/messages | 请求头 / body 带 client_action_id;返回 202 + run_id;同 ID 不同内容 409 | 决策 D8 |
| POST | /v1/runs/{id}:stop | 幂等停止;回执 status=terminal_observed | unknown;已输出的文字保存为一条 status=stopped 的助手消息;不承诺供应商侧已取消计费 | 决策 D8 |
| GET | /v1/projects/{id}/sessions | 会话列表(历史):按 last_message_at 倒序,q 搜索标题;每项带 active_run {id, status} 与 needs_action(等用户回答卡片或充值时为 true) | 决策 D8 |
| GET | /v1/sessions/{id} | 打开或刷新会话:返回会话、最近 50 条消息、进行中的 run(状态、last_seq、计划、未关闭的卡片);前端先按它渲染,再从 last_seq 接事件流 | 决策 D8 |
| GET | /v1/sessions/{id}/messages | 向上翻历史:before=<message_id>&limit≤50,按时间倒序 | 决策 D8 |
| POST | /v1/interactions/{id}:respond | 带 card_sha256;答案按卡片 schema 校验;已恢复过的卡再提交返回原回执 | 决策 D5 |
| GET | /v1/workspaces/{id}/admission | 发送前准入:额度/积分是否够用、原因、下一步(购买/升级/打开额外用量) | 决策 D7 |
| PUT | /v1/workspaces/{id}/approval-policy | Ask First / Always Allow(带单次与每日上限) | 决策 D2 |
| POST | /v1/intents | 创建创作意图:adapter + source_ref(URL、商品、脚本、参考视频) | 决策 D11 |
| GET | /v1/capabilities | 能力注册表:每项能力状态(可用/灰度/未接入),界面只渲染可用项 | 决策 D15 |
| GET | /v1/timelines/{id}/versions | 时间线版本历史(每次保存一条) | 决策 D13 |
| POST | /v1/timelines/{id}/versions/{v}:restore | 恢复到某个版本:以旧内容新建一个版本,不覆盖历史 | 决策 D13 |
| GET | /v1/models | 模型清单:版本、约束、价格表(来自 model_version) | 决策 D10 |
全部业务流程、Temporal 工作流、并发规则 已按“先报价再批准”改写,展开查看
6.1 流程清单
F1 积分冻结 → 生成 → 结算(最核心)
sequenceDiagram
autonumber
participant C as 客户端
participant API as core.taskfacade
participant B as core.billing
participant S as core.safety
participant PG as PostgreSQL
participant TP as Temporal
participant W as GenWorkflow
participant G as model-gateway
participant V as 供应商
participant A as core.asset
C->>API: POST /generations:quote
API->>S: 输入审核(prompt+参考图)
S-->>API: pass
API->>G: Route(capability,params)
G-->>API: model_version + 价格
API->>PG: INSERT generation_quote(request_sha256, quote_sha256, expires_at)
API-->>C: quote_id + 两个哈希 + expires_at(不扣费)
C->>API: POST /generations {quote_id, client_approval_id, 两个哈希}
API->>PG: 校验报价未过期、哈希一致(重放同一批准返回同一任务)
rect rgb(40,60,90)
note over API,PG: 单个本地事务
API->>B: Reserve(ref=task_id, amount=quoted)
B->>PG: 选 lot → hold(active) → 分录
API->>PG: INSERT generation_approval + generation_task(held→queued) + outbox(start_workflow)
end
API-->>C: 201 queued
PG-->>TP: outbox relay → StartWorkflow(task_id)
TP->>W: run
W->>G: Submit(task_id, attempt=1)
G->>V: 创建视频任务
V-->>G: provider_task_id
G-->>W: ACCEPTED
loop 回调优先,轮询兜底
V-->>G: webhook / 轮询 Query
G-->>W: Signal(progress)
end
V-->>G: 成功 + 视频URL
W->>A: 下载转存 COS,生成缩略图,审核
A-->>W: asset_id(pass)
W->>B: Settle(hold, actual)
B->>PG: hold=settled,分录:held→revenue/cogs,差额返还
W->>PG: task=succeeded + 节点新版本 + 事件
PG-->>C: SSE task.completed / node.updated
要点:① 积分冻结与任务创建同事务,不会出现"扣了没任务"或"有任务没扣";② Workflow 里每一步是 Activity,失败自动重试(带退避),结算与释放都是幂等的(以 hold 的 UNIQUE(ref_type, ref_id) 保证);③ 视频必须转存到自有存储后才视为成功,供应商链接通常 24h 失效;④ 任务只能由批准创建:先 generations:quote,再带 quote_id 与两个哈希调用 POST /generations,报价过期或哈希不一致都不会建任务、不会扣费。
F2 提交不确定(submit_uncertain)
sequenceDiagram
participant W as GenWorkflow
participant G as Gateway
participant V as 供应商
W->>G: Submit(task, attempt=1)
G->>V: POST create (带 client_token=task:attempt)
Note over G,V: 超时/连接重置
G-->>W: UNCERTAIN
W->>W: task=submit_uncertain (保持冻结)
loop 最多 N 次, 间隔递增
W->>G: Query(by client_token)
G->>V: 按 token 查询 / 列表对账
end
alt 供应商确认受理
G-->>W: ACCEPTED(provider_task_id)
W->>W: → running
else 确认未受理
G-->>W: NOT_FOUND
W->>W: attempt=2 (可换供应商) → queued
else 无法确认(超过 T_max)
W->>W: 标记 needs_manual, 保持冻结, 告警
Note right of W: 运营对账后 release 或 settle
end
F3 URL → 广告视频(Agent 全流程)
sequenceDiagram
autonumber
participant U as 用户
participant O as Orchestrator
participant CO as 采集专家
participant ST as 策略/脚本专家
participant SB as 分镜专家
participant PD as 生产专家
participant PP as 后期专家
participant K as Canvas/Task API
U->>O: 商品链接 + "3 条 15s TikTok 广告"
O->>CO: collect_url
CO->>K: collector job → 商品信息/图片
CO-->>O: product 节点 (标题/卖点/价格/图)
O->>ST: 提炼卖点+受众+3 个创意角度
ST-->>O: script 节点 ×3
O-->>U: interaction: review_script (HITL)
U-->>O: 选定/修改
O->>SB: 分镜(每条 4-6 镜头)+角色+首帧图
SB->>K: shot 节点 + 首帧 t2i 任务
SB-->>O: storyboard 节点
O->>K: POST /generations:quote ×N(逐镜头报价)
O-->>U: interaction: confirm_cost(Σ报价 = N 积分)
U-->>O: 批准
O->>PD: 并发生成所有 shot(i2v) + TTS + 字幕
PD->>K: POST /generations ×N {quote_id, client_approval_id, 哈希}
K-->>PD: task 完成事件
PD-->>O: shot_assets(溯源齐全)
O->>PP: 合成时间线(BGM,转场,字幕,混音)
PP->>K: 写 timeline + 创建 export
PP-->>O: final_video
O-->>U: 成片 + 可编辑画布
溯源规则(硬约束):final_video 的每个镜头片段必须引用 node_version.task_id 对应的 succeeded 任务;写入工具校验,不通过则拒绝,Agent 无法伪造成片。
F4 HITL 暂停与恢复
sequenceDiagram
participant AR as agent-runtime
participant WF as RunWorkflow
participant PG as PG
participant RT as realtime
participant U as 用户
AR->>WF: interrupt(kind, request)
WF->>PG: INSERT interaction(pending) + run=waiting_user + event (同事务)
PG-->>RT: outbox → interaction.requested
RT-->>U: SSE 卡片
Note over WF: 等待 Signal (最长 TTL, 无资源占用)
U->>PG: POST respond (client_action_id)
PG->>PG: 校验幂等/状态, interaction=resolved
PG->>WF: Signal(response)
WF->>AR: resume(thread_id, response)
AR-->>WF: 继续执行
alt 超时
WF->>PG: interaction=expired, run=cancelled, release holds
end
F5 单镜头重生成
flowchart LR
A[用户点击重生成<br/>可改 prompt/参考] --> B[quote 报价]
B --> C{余额足够?}
C -- 否 --> D[402 引导充值]
C -- 是 --> B2[用户批准报价<br/>quote_id + 哈希]
B2 --> E[冻结 + 新建 task<br/>base=旧版本上下文]
E --> F[读取: 角色参考图<br/>前后镜头尾帧/首帧<br/>风格种子]
F --> G[提交生成]
G --> H[成功: node_version+1<br/>旧版本保留]
H --> I[标记下游 timeline clip 为 outdated<br/>可一键替换]
H --> J[旧任务费用不退<br/>新任务单独计费]
F6 时间线导出
sequenceDiagram
participant C as 客户端
participant API as core
participant WF as ExportWorkflow
participant R as render worker
participant S as COS
C->>API: POST /timelines/{id}/exports (version=V)
API->>API: 校验所有 clip 素材可用/审核通过
API->>API: 冻结导出积分(可为0)
API->>WF: start (timeline snapshot V 固化)
WF->>R: 拆分: 分段渲染 (每段 ≤10s)
par 并行分段
R->>S: 读源素材(分段区间)
R->>R: FFmpeg filter_complex 合成
R->>S: 写分段
end
WF->>R: 拼接+混音+字幕烧录+封面
R->>S: 写成片
WF->>API: asset 入库 + export=succeeded
API-->>C: SSE export.succeeded
分段并行把 60s 1080p 的导出压缩到约 40–90s;失败只重试失败的分段;timeline 在提交时固化快照,导出期间用户继续编辑不影响结果。
F7 充值 / 订阅
sequenceDiagram
participant U as 用户
participant API as billing
participant PSP as Stripe/微信
participant PG as PG
U->>API: POST /billing/checkout (sku)
API->>PG: order(created)
API->>PSP: 创建支付会话
PSP-->>U: 跳转支付
PSP->>API: webhook payment.succeeded (event_id)
API->>PG: INSERT payment_event ON CONFLICT DO NOTHING
alt 首次处理
API->>PG: 事务: order=paid, point_lot(purchase), 分录(revenue→wallet_paid)
else 重复事件
API-->>PSP: 200(幂等忽略)
end
API-->>U: SSE billing.balance_changed
Note over API,PG: 退款: 先 hold 对应剩余积分,不足则标记欠费并限制使用
F8 爆款复刻
flowchart TB
A[参考视频 URL/文件] --> B[采集+转存+审核]
B --> C[镜头切分<br/>PySceneDetect]
C --> D[逐镜 VLM 理解:<br/>景别/运镜/主体/台词/情绪]
D --> E[ASR+文案结构化<br/>钩子/卖点/CTA 时间轴]
E --> F[节奏提取: 镜头时长、BGM 节拍]
F --> G[生成 blueprint 节点<br/>可编辑]
G --> H{用户确认}
H --> I[套入新商品:<br/>替换主体/文案/素材]
I --> J[进入 F3 生产段]
F9 批量变体
flowchart LR
A[母版项目 + 变量矩阵<br/>风格×角色×语种×CTA] --> B[展开为 N 个子项目]
B --> B2[逐个报价,用户一次批准整批<br/>每个子项目一个 quote_id]
B2 --> C[预算校验: Σ报价 ≤ 余额<br/>冻结总额]
C --> D[Child Workflow ×N<br/>限并发 K]
D --> E{单个失败?}
E -- 是 --> F[自动重试 ≤2 次<br/>仍失败释放该份冻结]
E -- 否 --> G[产物回收]
D --> H[进度聚合: 暂停/继续/取消]
F10 素材上传与解析
sequenceDiagram
participant C as 客户端
participant API as asset
participant S as COS
participant WF as AssetWorkflow
C->>API: POST /assets:init-upload (size,mime,sha256)
API->>API: 配额校验,sha256 命中 → 直接复用(秒传)
API-->>C: 预签名 URL (分片)
C->>S: 直传
C->>API: POST /assets/{id}:complete
API->>WF: start
WF->>WF: 病毒/格式校验 → 转码代理 → 抽帧/镜头切分
WF->>WF: 审核 (图像/视频/ASR 文本)
WF->>WF: VLM 描述 + 标签 + embedding
WF->>API: asset 可用 (moderation=pass)
F11 内容审核分层
| 阶段 | 对象 | 动作 | 延迟预算 |
|---|---|---|---|
| L0 报价时(输入) | prompt/文案 | 违禁词(Aho-Corasick)+ 文本审核模型 | <100ms 同步 |
| L1 报价时(参考素材) | 参考图/视频 | 图像审核(人脸/名人/成人/暴力) | <800ms 同步(图),视频异步 |
| L2 供应商侧 | 请求 | 供应商自带的审核结果记在 task_attempt(error_code = content_rejected,原因在 error_message),任务失败并释放积分 | — |
| L3 产出后 | 生成视频 | 抽帧审核 + ASR 文本审核;未通过不入库、不可分享 | 异步 <30s |
| L4 发布前 | 对外发布/直发 | 复审 + 平台政策检查 | 同步 |
| L5 人工 | 中风险队列 | 运营后台复核,SLA 4h | — |
6.2 Temporal 工作流设计
| Workflow | Task Queue | 关键 Activity | 超时/重试 | 信号/查询 |
|---|---|---|---|---|
| GenerationWorkflow | gen | Submit, PollOrAwaitCallback, Ingest, Settle/Release(路由在报价时完成,冻结在批准时与建任务同事务完成) | Submit 3 次(退避 2s→30s);整体 timeout=模型 timeout+10m | Signal: cancel, provider_callback;Query: state |
| AgentRunWorkflow | agent | RunGraphStep(LangGraph 单步), PersistEvents | 步级重试 2 次;run 总时长 ≤ 6h | Signal: guidance, interaction_response, cancel |
| ExportWorkflow | render | Plan, RenderSegment×N, Concat, Ingest | 分段 5m 超时,重试 3 次 | Signal: cancel |
| AssetWorkflow | asset | Probe, Transcode, SceneSplit, Moderate, Embed | 每步 10m | — |
| BatchWorkflow | batch | ExpandMatrix, StartChildren | Child 失败策略可配 | Signal: pause/resume/cancel |
| HoldSweeper (Schedule) | billing | ReleaseExpiredHolds(跳过 submit_uncertain 与待人工核对的任务,它们保持冻结) | 每分钟 | — |
| Reconcile (Schedule) | billing | LedgerInvariants, ProviderCostReconcile | 每日 03:00 | — |
| OrphanSweeper (Schedule) | gen | 找出 DB 活跃但无 Workflow 的任务并补启动 | 每 5 分钟 | — |
6.3 并发与一致性规则
- 每工作区并发上限:按套餐(Free 2 / Pro 6 / Team 20)+ 每模型全局并发(来自
model_catalog.max_concurrency);Redis 令牌桶 + 排队,超出进入queued而非拒绝。 - 公平调度:Gateway 提交队列按
workspace_id加权轮询,防止大客户批量任务饿死其他租户。 - 画布并发:
graph:patch使用base_version乐观锁;Agent 写入与用户编辑冲突时,Agent 侧收到 409 后 rebase 并重试一次,仍冲突则以用户版本为准。 - 事件顺序:run 内 seq 由 Workflow 单点分配;同一 run 的事件只由其 Workflow 写入。
最终设计 · ER 图
- 46 张表,按 7 个域划分;先看全景图,再看下面圈出的 Agent 交互和画布两块。
- 按设计不建数据库外键:74 条关系靠应用事务、唯一索引和对账保证;租户边界是
workspace_id。
46 张表 · 405 列 · 76 条关系 = 原 30 张核心表 + 吸收竞品新增 7 张 + 补全 9 张(原设计引用了却没给表)。图由 PostgreSQL 16 上实际执行最终 DDL 后读回的结构生成,与表结构、DDL 一致。
租户与成员 画布 · 时间轴(项目文档) Agent 交互 生成 · 报价批准 · 模型 素材 积分账本 · 订阅 · 额度 平台
基数标注(线上的文字,箭头从父表指向子表):1:N 一对多,子表外键必填(NOT NULL);0..1:N 一对多,但外键可空,所以父是可选的;1:1 一对一,子表外键上有唯一键;0..1:1 一对一且父可选。红色粗双向线 = N:M 多对多,经带 ⇄ 的关联表。★ = 吸收竞品后新增的 7 张表;◆ = 补全的 9 张表(原设计提到或被别的表、接口、决策引用,但没给 DDL);橙色粗线与橙色粗框 = Agent 交互相关。本设计沿用“不建数据库外键”的约定,所以基数取自库里真实存在的约束:外键列是否 NOT NULL、是否有单列唯一键。
租户边界:workspace 是租户,下面 21 张表都带 workspace_id、都属于某一个工作区。为了让图清楚,全景图没有把这 21 条线逐条画出,它们都列在下面的“关系清单”里。
全景图:全部实体与关系
默认缩放到页面宽度,先看整体结构;点一下图切换到原始大小(看清表名,在框内上下左右滚动),再点一下缩回。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":28,"rankSpacing":70}}}%%
flowchart TB
subgraph sg_tenant["租户与成员"]
direction TB
t_org["org ◆"]
t_app_user["app_user ◆"]
t_session_token["session_token ◆"]
t_plan["plan"]
t_workspace["workspace"]
t_member["⇄ member"]
t_api_key["api_key"]
end
subgraph sg_canvas["画布 · 时间轴(项目文档)"]
direction TB
t_project["project"]
t_project_asset_ref["⇄ project_asset_ref ◆"]
t_node["node"]
t_node_version["node_version"]
t_edge["⇄ edge"]
t_timeline["timeline"]
t_timeline_version["timeline_version ◆"]
t_export_job["export_job"]
t_intent["intent ★"]
end
subgraph sg_agent["⭕ Agent 交互"]
direction TB
t_agent_session["agent_session"]
t_agent_message["agent_message ◆"]
t_agent_run["agent_run"]
t_run_event["run_event"]
t_interaction["interaction"]
t_run_action["run_action ★"]
t_skill["skill ◆"]
t_skill_version["skill_version ◆"]
end
subgraph sg_gen["生成 · 报价批准 · 模型"]
direction TB
t_model_catalog["model_catalog"]
t_model_version["model_version ★"]
t_price_rule["price_rule"]
t_generation_quote["generation_quote ★"]
t_generation_approval["generation_approval ★"]
t_generation_task["generation_task"]
t_task_attempt["task_attempt"]
end
subgraph sg_asset["素材"]
direction TB
t_asset["asset"]
t_asset_embedding["asset_embedding"]
t_retrieval_seen["retrieval_seen"]
end
subgraph sg_billing["积分账本 · 订阅 · 额度"]
direction TB
t_ledger_account["ledger_account"]
t_ledger_entry["ledger_entry"]
t_point_lot["point_lot"]
t_hold["hold"]
t_quota_window["quota_window ★"]
t_approval_policy["approval_policy ★"]
t_subscription["subscription"]
t_purchase_order["purchase_order"]
t_payment_event["payment_event"]
end
subgraph sg_platform["平台"]
direction TB
t_outbox["outbox"]
t_webhook_endpoint["webhook_endpoint ◆"]
t_audit_log["audit_log"]
end
t_plan -->|"1:N"| t_workspace
t_workspace -->|"1:N"| t_member
t_workspace -->|"1:N"| t_api_key
t_asset -->|"0..1:N"| t_project
t_project -->|"1:N"| t_node
t_node -->|"0..1:N"| t_node
t_node -->|"1:N"| t_node_version
t_asset -->|"0..1:N"| t_node_version
t_generation_task -->|"0..1:N"| t_node_version
t_project -->|"1:N"| t_edge
t_node -->|"1:N"| t_edge
t_node -->|"1:N"| t_edge
t_project -->|"1:N"| t_timeline
t_timeline -->|"1:N"| t_export_job
t_asset -->|"0..1:N"| t_export_job
t_hold -->|"0..1:1"| t_export_job
t_project -->|"1:N"| t_agent_session
t_agent_session -->|"1:N"| t_agent_run
t_agent_run -->|"1:N"| t_run_event
t_agent_run -->|"1:N"| t_interaction
t_model_catalog -->|"1:N"| t_price_rule
t_project -->|"0..1:N"| t_generation_task
t_node -->|"0..1:N"| t_generation_task
t_agent_run -->|"0..1:N"| t_generation_task
t_api_key -->|"0..1:N"| t_generation_task
t_model_catalog -->|"0..1:N"| t_generation_task
t_hold -->|"0..1:1"| t_generation_task
t_generation_task -->|"1:N"| t_task_attempt
t_model_catalog -->|"1:N"| t_task_attempt
t_generation_task -->|"0..1:N"| t_asset
t_asset -->|"1:N"| t_asset_embedding
t_asset -->|"1:N"| t_retrieval_seen
t_ledger_account -->|"1:N"| t_ledger_entry
t_point_lot -->|"0..1:N"| t_ledger_entry
t_plan -->|"1:N"| t_subscription
t_generation_quote -->|"1:N"| t_generation_approval
t_generation_task -->|"0..1:N"| t_generation_approval
t_model_version -->|"1:N"| t_generation_quote
t_model_catalog -->|"1:N"| t_model_version
t_project -->|"1:N"| t_intent
t_agent_run -->|"1:N"| t_run_action
t_org -->|"1:N"| t_workspace
t_app_user -->|"1:N"| t_member
t_app_user -->|"1:N"| t_agent_session
t_app_user -->|"1:N"| t_project
t_app_user -->|"1:N"| t_session_token
t_skill -->|"1:N"| t_skill_version
t_skill -->|"1:N"| t_agent_session
t_skill -->|"0..1:N"| t_intent
t_agent_run -->|"0..1:N"| t_generation_quote
t_member -->|"0..1:N"| t_approval_policy
t_project -->|"1:N"| t_project_asset_ref
t_agent_session -->|"1:N"| t_agent_message
t_agent_run -->|"0..1:N"| t_agent_message
t_asset -->|"1:N"| t_project_asset_ref
t_timeline -->|"1:N"| t_timeline_version
t_node <-.->|"N:M · 经 edge"| t_node
t_workspace <-.->|"N:M · 经 member"| t_app_user
t_project <-.->|"N:M · 经 project_asset_ref"| t_asset
classDef tenant fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef canvas fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef gen fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef billing fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef platform fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
class t_api_key,t_app_user,t_member,t_org,t_plan,t_session_token,t_workspace tenant
class t_edge,t_export_job,t_intent,t_node,t_node_version,t_project,t_project_asset_ref,t_timeline,t_timeline_version canvas
class t_agent_message,t_agent_run,t_agent_session,t_interaction,t_run_action,t_run_event,t_skill,t_skill_version agent
class t_generation_approval,t_generation_quote,t_generation_task,t_model_catalog,t_model_version,t_price_rule,t_task_attempt gen
class t_asset,t_asset_embedding,t_retrieval_seen asset
class t_approval_policy,t_hold,t_ledger_account,t_ledger_entry,t_payment_event,t_point_lot,t_purchase_order,t_quota_window,t_subscription billing
class t_audit_log,t_outbox,t_webhook_endpoint platform
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_edge,t_member,t_project_asset_ref junction
style sg_tenant fill:none,stroke:#3b82f6,stroke-width:1px,stroke-dasharray:5 4
style sg_canvas fill:none,stroke:#8b5cf6,stroke-width:1px,stroke-dasharray:5 4
style sg_agent fill:#fff7ed,stroke:#f97316,stroke-width:4px,stroke-dasharray:0
style sg_gen fill:none,stroke:#22c55e,stroke-width:1px,stroke-dasharray:5 4
style sg_asset fill:none,stroke:#06b6d4,stroke-width:1px,stroke-dasharray:5 4
style sg_billing fill:none,stroke:#eab308,stroke-width:1px,stroke-dasharray:5 4
style sg_platform fill:none,stroke:#6b7280,stroke-width:1px,stroke-dasharray:5 4
linkStyle 16,17,18,19,23,40,43,46,47,48,49,52,53 stroke:#f97316,stroke-width:2.5px
linkStyle 56,57,58 stroke:#dc2626,stroke-width:3pxAgent 交互相关(圈出来)
会话 → Run → 事件流 / 澄清卡 / 动作回执;Run 产生生成任务。线上是“外键列 · 基数”。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":40,"rankSpacing":80}}}%%
flowchart LR
subgraph sg_agent["⭕ Agent 交互"]
direction TB
t_agent_session["agent_session"]
t_agent_message["agent_message ◆"]
t_agent_run["agent_run"]
t_run_event["run_event"]
t_interaction["interaction"]
t_run_action["run_action ★"]
t_skill["skill ◆"]
t_skill_version["skill_version ◆"]
end
subgraph sg_tenant["租户与成员"]
direction TB
t_workspace["workspace"]
end
subgraph sg_canvas["画布 · 时间轴(项目文档)"]
direction TB
t_project["project"]
end
subgraph sg_gen["生成 · 报价批准 · 模型"]
direction TB
t_generation_task["generation_task"]
end
t_workspace -->|"workspace_id · 1:N"| t_project
t_project -->|"project_id · 1:N"| t_agent_session
t_workspace -->|"workspace_id · 1:N"| t_agent_session
t_agent_session -->|"session_id · 1:N"| t_agent_run
t_workspace -->|"workspace_id · 1:N"| t_agent_run
t_agent_run -->|"run_id · 1:N"| t_run_event
t_agent_run -->|"run_id · 1:N"| t_interaction
t_workspace -->|"workspace_id · 1:N"| t_generation_task
t_project -->|"project_id · 0..1:N"| t_generation_task
t_agent_run -->|"run_id · 0..1:N"| t_generation_task
t_agent_run -->|"run_id · 1:N"| t_run_action
t_skill -->|"skill_id · 1:N"| t_skill_version
t_skill -->|"skill_id · 1:N"| t_agent_session
t_workspace -->|"owner_workspace_id · 0..1:N"| t_skill
t_agent_session -->|"session_id · 1:N"| t_agent_message
t_agent_run -->|"run_id · 0..1:N"| t_agent_message
classDef tenant fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef canvas fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef gen fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef billing fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef platform fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
class t_workspace tenant
class t_project canvas
class t_run_event,t_run_action,t_agent_message,t_agent_run,t_interaction,t_agent_session,t_skill_version,t_skill agent
class t_generation_task gen
classDef junction stroke-dasharray:4 3,stroke-width:3px
style sg_tenant fill:none,stroke:#3b82f6,stroke-width:1px
style sg_canvas fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_agent fill:#fff7ed,stroke:#f97316,stroke-width:4px
style sg_gen fill:none,stroke:#22c55e,stroke-width:1px
linkStyle 1,2,3,4,5,6,9,10,11,12,13,14,15 stroke:#f97316,stroke-width:2.5px- agent_session 挂在 project 下:对话不是独立的聊天记录,而是项目的一部分,Agent 的产出才能落到画布。
- run_action 独立成表:发消息、停止、切换模型、回答卡片共用一套幂等机制。
- interaction 带 card_sha256 与 schema:澄清卡是有状态对象,答案按原卡校验。
- run_event 按序号追加:断线后用序号续读,不丢不重。
画布与时间轴
项目是一份文档:node 是画布上的节点(可自引用成层级,parent_id),edge 连接两个节点,node_version 记录每次修改与产出素材;timeline 是同一项目的时间轴,导出走 export_job。
%%{init:{"flowchart":{"useMaxWidth":false,"nodeSpacing":40,"rankSpacing":80}}}%%
flowchart LR
subgraph sg_canvas["画布 · 时间轴(项目文档)"]
direction TB
t_project["project"]
t_node["node"]
t_node_version["node_version"]
t_edge["⇄ edge"]
t_timeline["timeline"]
t_export_job["export_job"]
t_intent["intent ★"]
end
subgraph sg_asset["素材"]
direction TB
t_asset["asset"]
end
subgraph sg_gen["生成 · 报价批准 · 模型"]
direction TB
t_generation_task["generation_task"]
end
subgraph sg_billing["积分账本 · 订阅 · 额度"]
direction TB
t_hold["hold"]
end
t_asset -->|"cover_asset_id · 0..1:N"| t_project
t_project -->|"project_id · 1:N"| t_node
t_node -->|"parent_id · 0..1:N"| t_node
t_node -->|"node_id · 1:N"| t_node_version
t_asset -->|"output_asset_id · 0..1:N"| t_node_version
t_generation_task -->|"task_id · 0..1:N"| t_node_version
t_project -->|"project_id · 1:N"| t_edge
t_node -->|"src_node_id · 1:N"| t_edge
t_node -->|"dst_node_id · 1:N"| t_edge
t_project -->|"project_id · 1:N"| t_timeline
t_timeline -->|"timeline_id · 1:N"| t_export_job
t_asset -->|"output_asset_id · 0..1:N"| t_export_job
t_hold -->|"hold_id · 0..1:1"| t_export_job
t_project -->|"project_id · 0..1:N"| t_generation_task
t_node -->|"node_id · 0..1:N"| t_generation_task
t_hold -->|"hold_id · 0..1:1"| t_generation_task
t_generation_task -->|"origin_task_id · 0..1:N"| t_asset
t_project -->|"project_id · 1:N"| t_intent
t_node <-.->|"N:M · 经 edge"| t_node
t_project <-.->|"N:M · 经 project_asset_ref"| t_asset
classDef tenant fill:#dbeafe,stroke:#3b82f6,color:#111,stroke-width:1.5px
classDef canvas fill:#ede9fe,stroke:#8b5cf6,color:#111,stroke-width:1.5px
classDef agent fill:#ffedd5,stroke:#f97316,color:#111,stroke-width:1.5px
classDef gen fill:#dcfce7,stroke:#22c55e,color:#111,stroke-width:1.5px
classDef asset fill:#cffafe,stroke:#06b6d4,color:#111,stroke-width:1.5px
classDef billing fill:#fef9c3,stroke:#eab308,color:#111,stroke-width:1.5px
classDef platform fill:#e5e7eb,stroke:#6b7280,color:#111,stroke-width:1.5px
class t_node,t_node_version,t_export_job,t_edge,t_intent,t_project,t_timeline canvas
class t_generation_task gen
class t_asset asset
class t_hold billing
classDef junction stroke-dasharray:4 3,stroke-width:3px
class t_edge junction
style sg_canvas fill:none,stroke:#8b5cf6,stroke-width:1px
style sg_gen fill:none,stroke:#22c55e,stroke-width:1px
style sg_asset fill:none,stroke:#06b6d4,stroke-width:1px
style sg_billing fill:none,stroke:#eab308,stroke-width:1px
linkStyle 18,19 stroke:#dc2626,stroke-width:3px- 画布与时间轴共用 project:同一份文档的两种视图,改一处另一处同步。
- node_version 独立:撤销、对比、只对改动镜头重新计费。
- edge 用 src / dst 两个节点列:一条边就是一次依赖,批量图变更接口一次提交。
多对多(N:M)
数据库里没有“多对多”这种列,它总是靠一张关联表表达。最终设计里有 3 组多对多,其余关系都是一对多或一对一:
| 多对多的两端 | 关联表 | 关联表的唯一键 | 含义 |
|---|---|---|---|
node ⇄ node | edge | src_node_id, dst_node_id, kind | 节点与节点:一条连线(src、dst)连起两个节点,一个节点可以有多条入边和出边 |
workspace ⇄ app_user | member | workspace_id, user_id | 工作区与用户:一个用户可以加入多个工作区,一个工作区有多个成员 |
project ⇄ asset | project_asset_ref | project_id, asset_id | 项目与素材:素材归工作区,一个素材可被多个项目引用,一个项目引用多个素材 |
关系清单 逐条 76 条,含基数
一对多 54 条,一对多(父可选) 20 条,一对一(父可选) 2 条;多对多 3 组。
| 父表 | 子表 | 外键列(在子表) | 基数 | 域 |
|---|---|---|---|---|
agent_run | agent_message | run_id | 0..1:N 一对多(父可选) | Agent 交互 → Agent 交互 |
agent_session | agent_message | session_id | 1:N 一对多 | Agent 交互 → Agent 交互 |
agent_session | agent_run | session_id | 1:N 一对多 | Agent 交互 → Agent 交互 |
workspace | agent_run | workspace_id | 1:N 一对多 | 租户与成员 → Agent 交互 |
app_user | agent_session | user_id | 1:N 一对多 | 租户与成员 → Agent 交互 |
project | agent_session | project_id | 1:N 一对多 | 画布 · 时间轴(项目文档) → Agent 交互 |
skill | agent_session | skill_id | 1:N 一对多 | Agent 交互 → Agent 交互 |
workspace | agent_session | workspace_id | 1:N 一对多 | 租户与成员 → Agent 交互 |
workspace | api_key | workspace_id | 1:N 一对多 | 租户与成员 → 租户与成员 |
member | approval_policy | member_id | 0..1:N 一对多(父可选) | 租户与成员 → 积分账本 · 订阅 · 额度 |
workspace | approval_policy | workspace_id | 1:N 一对多 | 租户与成员 → 积分账本 · 订阅 · 额度 |
generation_task | asset | origin_task_id | 0..1:N 一对多(父可选) | 生成 · 报价批准 · 模型 → 素材 |
workspace | asset | workspace_id | 1:N 一对多 | 租户与成员 → 素材 |
asset | asset_embedding | asset_id | 1:N 一对多 | 素材 → 素材 |
workspace | audit_log | workspace_id | 0..1:N 一对多(父可选) | 租户与成员 → 平台 |
node | edge | dst_node_id | 1:N 一对多 | 画布 · 时间轴(项目文档) → 画布 · 时间轴(项目文档) |
node | edge | src_node_id | 1:N 一对多 | 画布 · 时间轴(项目文档) → 画布 · 时间轴(项目文档) |
project | edge | project_id | 1:N 一对多 | 画布 · 时间轴(项目文档) → 画布 · 时间轴(项目文档) |
asset | export_job | output_asset_id | 0..1:N 一对多(父可选) | 素材 → 画布 · 时间轴(项目文档) |
hold | export_job | hold_id | 0..1:1 一对一(父可选) | 积分账本 · 订阅 · 额度 → 画布 · 时间轴(项目文档) |
timeline | export_job | timeline_id | 1:N 一对多 | 画布 · 时间轴(项目文档) → 画布 · 时间轴(项目文档) |
workspace | export_job | workspace_id | 1:N 一对多 | 租户与成员 → 画布 · 时间轴(项目文档) |
generation_quote | generation_approval | quote_id | 1:N 一对多 | 生成 · 报价批准 · 模型 → 生成 · 报价批准 · 模型 |
generation_task | generation_approval | task_id | 0..1:N 一对多(父可选) | 生成 · 报价批准 · 模型 → 生成 · 报价批准 · 模型 |
agent_run | generation_quote | source_run_id | 0..1:N 一对多(父可选) | Agent 交互 → 生成 · 报价批准 · 模型 |
model_version | generation_quote | model_version_id | 1:N 一对多 | 生成 · 报价批准 · 模型 → 生成 · 报价批准 · 模型 |
workspace | generation_quote | workspace_id | 1:N 一对多 | 租户与成员 → 生成 · 报价批准 · 模型 |
agent_run | generation_task | run_id | 0..1:N 一对多(父可选) | Agent 交互 → 生成 · 报价批准 · 模型 |
api_key | generation_task | api_key_id | 0..1:N 一对多(父可选) | 租户与成员 → 生成 · 报价批准 · 模型 |
hold | generation_task | hold_id | 0..1:1 一对一(父可选) | 积分账本 · 订阅 · 额度 → 生成 · 报价批准 · 模型 |
model_catalog | generation_task | model_id | 0..1:N 一对多(父可选) | 生成 · 报价批准 · 模型 → 生成 · 报价批准 · 模型 |
node | generation_task | node_id | 0..1:N 一对多(父可选) | 画布 · 时间轴(项目文档) → 生成 · 报价批准 · 模型 |
project | generation_task | project_id | 0..1:N 一对多(父可选) | 画布 · 时间轴(项目文档) → 生成 · 报价批准 · 模型 |
workspace | generation_task | workspace_id | 1:N 一对多 | 租户与成员 → 生成 · 报价批准 · 模型 |
workspace | hold | workspace_id | 1:N 一对多 | 租户与成员 → 积分账本 · 订阅 · 额度 |
project | intent | project_id | 1:N 一对多 | 画布 · 时间轴(项目文档) → 画布 · 时间轴(项目文档) |
skill | intent | skill_id | 0..1:N 一对多(父可选) | Agent 交互 → 画布 · 时间轴(项目文档) |
workspace | intent | workspace_id | 1:N 一对多 | 租户与成员 → 画布 · 时间轴(项目文档) |
agent_run | interaction | run_id | 1:N 一对多 | Agent 交互 → Agent 交互 |
workspace | ledger_account | workspace_id | 0..1:N 一对多(父可选) | 租户与成员 → 积分账本 · 订阅 · 额度 |
ledger_account | ledger_entry | account_id | 1:N 一对多 | 积分账本 · 订阅 · 额度 → 积分账本 · 订阅 · 额度 |
point_lot | ledger_entry | lot_id | 0..1:N 一对多(父可选) | 积分账本 · 订阅 · 额度 → 积分账本 · 订阅 · 额度 |
app_user | member | user_id | 1:N 一对多 | 租户与成员 → 租户与成员 |
workspace | member | workspace_id | 1:N 一对多 | 租户与成员 → 租户与成员 |
model_catalog | model_version | model_id | 1:N 一对多 | 生成 · 报价批准 · 模型 → 生成 · 报价批准 · 模型 |
node | node | parent_id | 0..1:N 一对多(父可选) | 画布 · 时间轴(项目文档) → 画布 · 时间轴(项目文档) |
project | node | project_id | 1:N 一对多 | 画布 · 时间轴(项目文档) → 画布 · 时间轴(项目文档) |
workspace | node | workspace_id | 1:N 一对多 | 租户与成员 → 画布 · 时间轴(项目文档) |
asset | node_version | output_asset_id | 0..1:N 一对多(父可选) | 素材 → 画布 · 时间轴(项目文档) |
generation_task | node_version | task_id | 0..1:N 一对多(父可选) | 生成 · 报价批准 · 模型 → 画布 · 时间轴(项目文档) |
node | node_version | node_id | 1:N 一对多 | 画布 · 时间轴(项目文档) → 画布 · 时间轴(项目文档) |
workspace | point_lot | workspace_id | 1:N 一对多 | 租户与成员 → 积分账本 · 订阅 · 额度 |
model_catalog | price_rule | model_id | 1:N 一对多 | 生成 · 报价批准 · 模型 → 生成 · 报价批准 · 模型 |
app_user | project | owner_id | 1:N 一对多 | 租户与成员 → 画布 · 时间轴(项目文档) |
asset | project | cover_asset_id | 0..1:N 一对多(父可选) | 素材 → 画布 · 时间轴(项目文档) |
workspace | project | workspace_id | 1:N 一对多 | 租户与成员 → 画布 · 时间轴(项目文档) |
asset | project_asset_ref | asset_id | 1:N 一对多 | 素材 → 画布 · 时间轴(项目文档) |
project | project_asset_ref | project_id | 1:N 一对多 | 画布 · 时间轴(项目文档) → 画布 · 时间轴(项目文档) |
workspace | purchase_order | workspace_id | 1:N 一对多 | 租户与成员 → 积分账本 · 订阅 · 额度 |
workspace | quota_window | workspace_id | 1:N 一对多 | 租户与成员 → 积分账本 · 订阅 · 额度 |
asset | retrieval_seen | asset_id | 1:N 一对多 | 素材 → 素材 |
agent_run | run_action | run_id | 1:N 一对多 | Agent 交互 → Agent 交互 |
agent_run | run_event | run_id | 1:N 一对多 | Agent 交互 → Agent 交互 |
app_user | session_token | user_id | 1:N 一对多 | 租户与成员 → 租户与成员 |
workspace | skill | owner_workspace_id | 0..1:N 一对多(父可选) | 租户与成员 → Agent 交互 |
skill | skill_version | skill_id | 1:N 一对多 | Agent 交互 → Agent 交互 |
plan | subscription | plan_code | 1:N 一对多 | 租户与成员 → 积分账本 · 订阅 · 额度 |
workspace | subscription | workspace_id | 1:N 一对多 | 租户与成员 → 积分账本 · 订阅 · 额度 |
generation_task | task_attempt | task_id | 1:N 一对多 | 生成 · 报价批准 · 模型 → 生成 · 报价批准 · 模型 |
model_catalog | task_attempt | model_id | 1:N 一对多 | 生成 · 报价批准 · 模型 → 生成 · 报价批准 · 模型 |
project | timeline | project_id | 1:N 一对多 | 画布 · 时间轴(项目文档) → 画布 · 时间轴(项目文档) |
workspace | timeline | workspace_id | 1:N 一对多 | 租户与成员 → 画布 · 时间轴(项目文档) |
timeline | timeline_version | timeline_id | 1:N 一对多 | 画布 · 时间轴(项目文档) → 画布 · 时间轴(项目文档) |
workspace | webhook_endpoint | workspace_id | 1:N 一对多 | 租户与成员 → 平台 |
org | workspace | org_id | 1:N 一对多 | 租户与成员 → 租户与成员 |
plan | workspace | plan_code | 1:N 一对多 | 租户与成员 → 租户与成员 |
完整 ER:46 个实体的全部列,带主键 / 外键与基数符号(鸦脚)
erDiagram
agent_message {
CHAR id PK
CHAR session_id FK
CHAR run_id FK
TEXT role
TEXT delivery
TEXT content
JSONB attachments
TEXT status
INT content_seq
JSONB suggestions
TEXT client_action_id
TIMESTAMPTZ created_at
TIMESTAMPTZ completed_at
}
agent_run {
CHAR id PK
CHAR session_id FK
CHAR workspace_id FK
TEXT status
TEXT workflow_id
TEXT skill_version
BIGINT budget_centi
BIGINT spent_centi
JSONB input
TEXT error_code
TEXT error_message
TIMESTAMPTZ started_at
TIMESTAMPTZ finished_at
TIMESTAMPTZ created_at
}
agent_session {
CHAR id PK
CHAR project_id FK
CHAR workspace_id FK
CHAR user_id FK
TEXT skill_id FK
TEXT skill_version
TEXT title
TIMESTAMPTZ last_message_at
TIMESTAMPTZ created_at
}
api_key {
CHAR id PK
CHAR workspace_id FK
TEXT name
TEXT key_prefix
BYTEA key_hash
TEXT_ARR scopes
TEXT status
TIMESTAMPTZ expires_at
TIMESTAMPTZ last_used_at
TIMESTAMPTZ created_at
}
app_user {
CHAR id PK
TEXT email
TEXT display_name
TEXT password_hash
TEXT status
TIMESTAMPTZ created_at
TIMESTAMPTZ last_login_at
}
approval_policy {
CHAR id PK
CHAR workspace_id FK
BIGINT member_id FK
TEXT mode
BIGINT per_task_limit_centi
BIGINT daily_limit_centi
}
asset {
CHAR id PK
CHAR workspace_id FK
TEXT kind
TEXT source
TEXT storage_key
TEXT mime
BIGINT bytes
INT duration_ms
INT width
INT height
REAL fps
BYTEA sha256
CHAR origin_task_id FK
TEXT origin_url
TEXT moderation
TEXT_ARR tags
JSONB meta
TIMESTAMPTZ deleted_at
TIMESTAMPTZ created_at
}
asset_embedding {
CHAR asset_id PK
INT segment_no PK
INT start_ms
INT end_ms
TEXT caption
FLOAT4__ embedding
}
audit_log {
BIGINT id PK
CHAR workspace_id FK
TEXT actor
TEXT action
TEXT target_type
TEXT target_id
JSONB diff
INET ip
TIMESTAMPTZ created_at
}
edge {
CHAR id PK
CHAR project_id FK
CHAR src_node_id FK
CHAR dst_node_id FK
TEXT kind
}
export_job {
CHAR id PK
CHAR workspace_id FK
CHAR timeline_id FK
BIGINT timeline_ver
TEXT preset
TEXT status
TEXT workflow_id
CHAR output_asset_id FK
CHAR hold_id FK
TEXT error_code
TEXT error_message
TIMESTAMPTZ created_at
TIMESTAMPTZ finished_at
}
generation_approval {
CHAR id PK
CHAR quote_id FK
TEXT client_approval_id
CHAR request_sha256
CHAR quote_sha256
CHAR task_id FK
TIMESTAMPTZ created_at
}
generation_quote {
CHAR id PK
CHAR workspace_id FK
TEXT client_request_id
CHAR request_sha256
CHAR quote_sha256
CHAR model_version_id FK
BIGINT quoted_centi
TIMESTAMPTZ expires_at
CHAR source_run_id FK
CHAR source_sha256
TEXT status
}
generation_task {
CHAR id PK
CHAR workspace_id FK
CHAR project_id FK
CHAR node_id FK
CHAR run_id FK
CHAR api_key_id FK
TEXT capability
CHAR model_id FK
JSONB request
BYTEA request_hash
TEXT idem_key
TEXT status
CHAR hold_id FK
BIGINT quoted_centi
BIGINT charged_centi
JSONB outputs
TEXT error_code
TEXT error_message
TEXT workflow_id
INT attempt_count
TIMESTAMPTZ created_at
TIMESTAMPTZ finished_at
}
hold {
CHAR id PK
CHAR workspace_id FK
TEXT ref_type
TEXT ref_id
BIGINT amount_centi
TEXT status
JSONB lot_allocation
TIMESTAMPTZ expires_at
TIMESTAMPTZ created_at
}
intent {
CHAR id PK
CHAR workspace_id FK
CHAR project_id FK
TEXT adapter
JSONB source_ref
TEXT skill_id FK
TEXT skill_version
TEXT status
TIMESTAMPTZ created_at
}
interaction {
CHAR id PK
CHAR run_id FK
TEXT kind
JSONB request
JSONB response
CHAR card_sha256
JSONB schema
TEXT client_action_id
TEXT status
TIMESTAMPTZ expires_at
TIMESTAMPTZ created_at
TIMESTAMPTZ resolved_at
}
ledger_account {
CHAR id PK
CHAR workspace_id FK
TEXT kind
BIGINT balance_centi
BIGINT version
}
ledger_entry {
BIGINT id PK
CHAR txn_id
CHAR account_id FK
SMALLINT direction
BIGINT amount_centi
TEXT ref_type
TEXT ref_id
CHAR lot_id FK
TEXT memo
TIMESTAMPTZ created_at PK
}
member {
BIGINT id PK
CHAR workspace_id FK
CHAR user_id FK
TEXT role
BOOL seat
TIMESTAMPTZ created_at
}
model_catalog {
CHAR id PK
TEXT capability
TEXT provider_key
TEXT model_name
TEXT display_name
JSONB input_schema
JSONB limits
JSONB default_params
INT max_concurrency
INT timeout_s
TEXT status
TEXT adapter_key
}
model_version {
CHAR id PK
CHAR model_id FK
TEXT version_key
JSONB config
CHAR config_sha256
TIMESTAMPTZ published_at
}
node {
CHAR id PK
CHAR project_id FK
CHAR workspace_id FK
TEXT type
CHAR parent_id FK
TEXT title
REAL pos_x
REAL pos_y
JSONB data
INT current_ver
CHAR lock_owner
TIMESTAMPTZ lock_until
TEXT status
TEXT created_by
TIMESTAMPTZ deleted_at
TIMESTAMPTZ created_at
TIMESTAMPTZ updated_at
}
node_version {
CHAR node_id PK
INT version PK
JSONB data
CHAR output_asset_id FK
CHAR task_id FK
TEXT created_by
TIMESTAMPTZ created_at
}
org {
CHAR id PK
TEXT name
TEXT status
TIMESTAMPTZ created_at
}
outbox {
BIGINT id PK
TEXT topic
TEXT key
JSONB payload
TEXT status
INT attempts
TIMESTAMPTZ next_at
TIMESTAMPTZ created_at
}
payment_event {
BIGINT id PK
TEXT provider
TEXT event_id
TEXT type
JSONB payload
TIMESTAMPTZ processed_at
TIMESTAMPTZ received_at
}
plan {
TEXT code PK
TEXT name
TEXT interval
INT price_cents
TEXT currency
BIGINT monthly_points_centi
INT seats
JSONB features
}
point_lot {
CHAR id PK
CHAR workspace_id FK
TEXT source
BIGINT granted_centi
BIGINT remaining_centi
TIMESTAMPTZ expires_at
SMALLINT priority
TIMESTAMPTZ created_at
}
price_rule {
CHAR id PK
CHAR model_id FK
TEXT unit
BIGINT cost_micro
BIGINT charge_centi
JSONB modifiers
TIMESTAMPTZ effective_from
TIMESTAMPTZ effective_to
}
project {
CHAR id PK
CHAR workspace_id FK
CHAR owner_id FK
TEXT title
TEXT kind
TEXT aspect_ratio
TEXT language
CHAR cover_asset_id FK
TEXT status
BIGINT doc_version
TIMESTAMPTZ deleted_at
TIMESTAMPTZ created_at
TIMESTAMPTZ updated_at
}
project_asset_ref {
CHAR project_id PK
CHAR asset_id PK
TEXT purpose
TIMESTAMPTZ created_at
}
purchase_order {
CHAR id PK
CHAR workspace_id FK
TEXT kind
TEXT sku_code
INT amount_cents
TEXT currency
TEXT status
TIMESTAMPTZ created_at
}
quota_window {
CHAR workspace_id PK
DATE window_start PK
TEXT kind PK
BIGINT limit_units
BIGINT used_units
BOOL overage_enabled
}
retrieval_seen {
TEXT context_key PK
CHAR asset_id PK
}
run_action {
CHAR id PK
CHAR run_id FK
TEXT kind
TEXT client_action_id
CHAR request_sha256
TEXT status
INT attempt
JSONB result
TIMESTAMPTZ created_at
}
run_event {
BIGINT id PK
CHAR run_id FK
INT seq
TEXT type
JSONB payload
TIMESTAMPTZ created_at PK
}
session_token {
CHAR id PK
CHAR user_id FK
BYTEA token_hash
TIMESTAMPTZ expires_at
TIMESTAMPTZ revoked_at
TIMESTAMPTZ created_at
}
skill {
TEXT id PK
TEXT display_name
CHAR owner_workspace_id FK
TEXT status
TIMESTAMPTZ created_at
}
skill_version {
TEXT skill_id PK
TEXT version PK
JSONB manifest
CHAR sha256
TEXT status
TIMESTAMPTZ published_at
}
subscription {
CHAR id PK
CHAR workspace_id FK
TEXT plan_code FK
TEXT status
TEXT provider
TEXT provider_sub_id
TIMESTAMPTZ current_period_start
TIMESTAMPTZ current_period_end
BOOL cancel_at_period_end
}
task_attempt {
CHAR id PK
CHAR task_id FK
SMALLINT seq
CHAR model_id FK
TEXT provider_task_id
TEXT provider_request_id
TEXT status
BIGINT cost_micro
JSONB usage
TEXT error_code
TEXT error_message
TIMESTAMPTZ submitted_at
TIMESTAMPTZ finished_at
}
timeline {
CHAR id PK
CHAR project_id FK
CHAR workspace_id FK
SMALLINT fps
INT width
INT height
INT duration_ms
JSONB doc
BIGINT version
TIMESTAMPTZ updated_at
}
timeline_version {
CHAR timeline_id PK
BIGINT version PK
JSONB doc
BIGINT restored_from
TEXT created_by
TIMESTAMPTZ created_at
}
webhook_endpoint {
CHAR id PK
CHAR workspace_id FK
TEXT url
BYTEA secret_hash
TEXT_ARR events
TEXT status
TIMESTAMPTZ created_at
}
workspace {
CHAR id PK
CHAR org_id FK
TEXT name
TEXT region
TEXT plan_code FK
TEXT status
TIMESTAMPTZ created_at
TIMESTAMPTZ updated_at
}
plan ||--o{ workspace : "plan_code"
workspace ||--o{ member : "workspace_id"
workspace ||--o{ api_key : "workspace_id"
workspace ||--o{ project : "workspace_id"
asset |o--o{ project : "cover_asset_id"
project ||--o{ node : "project_id"
workspace ||--o{ node : "workspace_id"
node |o--o{ node : "parent_id"
node ||--o{ node_version : "node_id"
asset |o--o{ node_version : "output_asset_id"
generation_task |o--o{ node_version : "task_id"
project ||--o{ edge : "project_id"
node ||--o{ edge : "src_node_id"
node ||--o{ edge : "dst_node_id"
project ||--o{ timeline : "project_id"
workspace ||--o{ timeline : "workspace_id"
workspace ||--o{ export_job : "workspace_id"
timeline ||--o{ export_job : "timeline_id"
asset |o--o{ export_job : "output_asset_id"
hold |o--o| export_job : "hold_id"
project ||--o{ agent_session : "project_id"
workspace ||--o{ agent_session : "workspace_id"
agent_session ||--o{ agent_run : "session_id"
workspace ||--o{ agent_run : "workspace_id"
agent_run ||--o{ run_event : "run_id"
agent_run ||--o{ interaction : "run_id"
model_catalog ||--o{ price_rule : "model_id"
workspace ||--o{ generation_task : "workspace_id"
project |o--o{ generation_task : "project_id"
node |o--o{ generation_task : "node_id"
agent_run |o--o{ generation_task : "run_id"
api_key |o--o{ generation_task : "api_key_id"
model_catalog |o--o{ generation_task : "model_id"
hold |o--o| generation_task : "hold_id"
generation_task ||--o{ task_attempt : "task_id"
model_catalog ||--o{ task_attempt : "model_id"
workspace ||--o{ asset : "workspace_id"
generation_task |o--o{ asset : "origin_task_id"
asset ||--o{ asset_embedding : "asset_id"
asset ||--o{ retrieval_seen : "asset_id"
workspace |o--o{ ledger_account : "workspace_id"
ledger_account ||--o{ ledger_entry : "account_id"
point_lot |o--o{ ledger_entry : "lot_id"
workspace ||--o{ point_lot : "workspace_id"
workspace ||--o{ hold : "workspace_id"
workspace ||--o{ subscription : "workspace_id"
plan ||--o{ subscription : "plan_code"
workspace ||--o{ purchase_order : "workspace_id"
workspace |o--o{ audit_log : "workspace_id"
generation_quote ||--o{ generation_approval : "quote_id"
generation_task |o--o{ generation_approval : "task_id"
model_version ||--o{ generation_quote : "model_version_id"
model_catalog ||--o{ model_version : "model_id"
workspace ||--o{ quota_window : "workspace_id"
workspace ||--o{ approval_policy : "workspace_id"
project ||--o{ intent : "project_id"
agent_run ||--o{ run_action : "run_id"
org ||--o{ workspace : "org_id"
app_user ||--o{ member : "user_id"
app_user ||--o{ agent_session : "user_id"
app_user ||--o{ project : "owner_id"
app_user ||--o{ session_token : "user_id"
skill ||--o{ skill_version : "skill_id"
skill ||--o{ agent_session : "skill_id"
skill |o--o{ intent : "skill_id"
workspace |o--o{ skill : "owner_workspace_id"
workspace ||--o{ webhook_endpoint : "workspace_id"
workspace ||--o{ generation_quote : "workspace_id"
workspace ||--o{ intent : "workspace_id"
agent_run |o--o{ generation_quote : "source_run_id"
member |o--o{ approval_policy : "member_id"
project ||--o{ project_asset_ref : "project_id"
agent_session ||--o{ agent_message : "session_id"
agent_run |o--o{ agent_message : "run_id"
asset ||--o{ project_asset_ref : "asset_id"
timeline ||--o{ timeline_version : "timeline_id"实测验证 最终 DDL 在真实 PostgreSQL 16 上整体执行通过,展开看核对项
实测验证(真实 PostgreSQL 16)
把本页的核心 DDL 与增量 DDL 在一个临时的 PostgreSQL 16 实例里真正执行,再把实际建出的表、列、主键、类型,逐项与本页的 ER 图对照;增量里的唯一键、检查约束用真实插入去触发。20 / 20 项通过。
查看全部核对项
| 核对项 | 结果 |
|---|---|
| 核心 DDL 在真实 PostgreSQL 16 上全部建成(pgvector 的类型与 HNSW 索引除外,本机没有该扩展) | 通过 |
| ER 实体 = 文档声明的 30 张表 | 通过 |
| 除 30 张表外只多出 2 个默认分区(run_event_default、ledger_entry_default) | 通过 |
| ER 中列出的每一列都在实际表里存在 | 通过 |
| ER 中标 PK 的列确实是主键 | 通过 |
| 实际主键列在 ER 中都标了 PK | 通过 |
| ER 的每条关系:两端表存在,子表里确有该外键列 | 通过 |
| 外键列类型与父表主键类型一致 | 通过 |
| 所有「<表名>_id」列都画成了关系(没有漏画) | 通过 |
| 核心 DDL 与设计声明一致:不建数据库外键 | 通过 |
| ER 关系数 49,没有重复 | 通过 |
| 增量 DDL 在核心 DDL 之上执行成功,新增 7 张表 | 通过 |
| 增量 ER 里的每个实体与列都在建出的表里 | 通过 |
| 增量 ER 的每条关系:两端表存在,子表里确有该外键列 | 通过 |
| 增量关系:外键列类型与父表主键类型一致 | 通过 |
| 增量 DDL 同样不建数据库外键(沿用 Lumen 约定),关系靠应用层与唯一键 | 通过 |
| 重放批准(同一报价、同一 client_approval_id)被唯一键拒绝 | 通过 |
| 报价状态只能取 4 个值(检查约束) | 通过 |
| 同一个 run 内同一个 client_action_id 只能有一条动作(唯一键,重复写入被拒绝) | 通过 |
| 每个工作区只能有一条默认审批策略(表达式唯一索引,NULL 成员也受约束) | 通过 |
- 核心 DDL 的订单表原来叫
"order"(保留字),而 ER 图里画的是purchase_order,两处对不上;已统一为purchase_order。 - 增量 DDL 里审批策略表用了表达式做主键,PostgreSQL 不允许;已改成独立主键加表达式唯一索引。
vector(1024) 列与 HNSW 索引(本机没有该扩展,验证时换成数组类型);分区表在大数据量下的表现;与应用代码的集成。最终设计 · 表结构
- 每个域一张总览表(存什么、主要列),完整列定义在表下方展开。★ 新增、◆ 补全;最该细看的是“生成 · 报价批准”和“积分账本”两组。
- 账本只追加、金额用整数最小单位,状态迁移用条件更新,影响 0 行即冲突。完整 DDL 可直接执行。
最终产物:46 张表 · 405 列 · 76 条关系(另有 2 个默认分区表)。下面按域列出每张表的列;完整 DDL 是同一份、可直接执行的脚本。★ = 吸收竞品后新增;◆ = 补全(原设计提到或被引用,没给 DDL)。
租户与成员
| 表 | 存什么 | 列数 | 主要列 |
|---|---|---|---|
org ◆ | 组织 | 4 | name, status … |
app_user ◆ | 用户 | 7 | email, display_name, password_hash, status, last_login_at … |
session_token ◆ | 登录会话 | 6 | user_id, token_hash, expires_at, revoked_at … |
plan | 套餐 | 8 | name, interval, price_cents, currency, monthly_points_centi, seats … |
workspace | 工作区 | 8 | org_id, name, region, plan_code, status … |
member | 成员 | 6 | workspace_id, user_id, role, seat … |
api_key | API Key | 10 | workspace_id, name, key_prefix, key_hash, scopes, status … |
租户与成员:每张表的全部列、类型、默认值
org
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
name | text | 非空 | |
status | text | 非空 | 'active'::text |
created_at | timestamptz | 非空 | now() |
app_user
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
email | text | 非空 | |
display_name | text | 可空 | |
password_hash | text | 可空 | |
status | text | 非空 | 'active'::text |
created_at | timestamptz | 非空 | now() |
last_login_at | timestamptz | 可空 | |
session_token
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
user_id | char | 非空 | |
token_hash | bytea | 非空 | |
expires_at | timestamptz | 非空 | |
revoked_at | timestamptz | 可空 | |
created_at | timestamptz | 非空 | now() |
plan
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
code PK | text | 非空 | |
name | text | 非空 | |
interval | text | 非空 | |
price_cents | integer | 非空 | |
currency | text | 非空 | |
monthly_points_centi | bigint | 非空 | |
seats | integer | 非空 | |
features | jsonb | 非空 | |
workspace
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
org_id | char | 非空 | |
name | text | 非空 | |
region | text | 非空 | |
plan_code | text | 非空 | 'free'::text |
status | text | 非空 | 'active'::text |
created_at | timestamptz | 非空 | now() |
updated_at | timestamptz | 非空 | now() |
member
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | bigint | 非空 | |
workspace_id | char | 非空 | |
user_id | char | 非空 | |
role | text | 非空 | |
seat | boolean | 非空 | true |
created_at | timestamptz | 非空 | now() |
api_key
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
workspace_id | char | 非空 | |
name | text | 非空 | |
key_prefix | text | 非空 | |
key_hash | bytea | 非空 | |
scopes | text[] | 非空 | |
status | text | 非空 | 'active'::text |
expires_at | timestamptz | 可空 | |
last_used_at | timestamptz | 可空 | |
created_at | timestamptz | 非空 | now() |
画布 · 时间轴(项目文档)
| 表 | 存什么 | 列数 | 主要列 |
|---|---|---|---|
project | 项目 | 13 | workspace_id, owner_id, title, kind, aspect_ratio, language … |
project_asset_ref ◆ | 项目引用的素材 | 4 | purpose … |
node | 节点 | 17 | project_id, workspace_id, type, parent_id, title, pos_x … |
node_version | 节点版本 | 7 | data, output_asset_id, task_id, created_by … |
edge | 连线 | 5 | project_id, src_node_id, dst_node_id, kind |
timeline | 时间轴 | 10 | project_id, workspace_id, fps, width, height, duration_ms … |
timeline_version ◆ | 时间轴版本 | 6 | doc, restored_from, created_by … |
export_job | 导出任务 | 13 | workspace_id, timeline_id, timeline_ver, preset, status, workflow_id … |
intent ★ | 创作意图 | 9 | workspace_id, project_id, adapter, source_ref, skill_id, skill_version … |
画布 · 时间轴(项目文档):每张表的全部列、类型、默认值
project
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
workspace_id | char | 非空 | |
owner_id | char | 非空 | |
title | text | 非空 | |
kind | text | 非空 | |
aspect_ratio | text | 非空 | '9:16'::text |
language | text | 非空 | 'en'::text |
cover_asset_id | char | 可空 | |
status | text | 非空 | 'draft'::text |
doc_version | bigint | 非空 | 0 |
deleted_at | timestamptz | 可空 | |
created_at | timestamptz | 非空 | now() |
updated_at | timestamptz | 非空 | now() |
project_asset_ref
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
project_id PK | char | 非空 | |
asset_id PK | char | 非空 | |
purpose | text | 非空 | 'reference'::text |
created_at | timestamptz | 非空 | now() |
node
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
project_id | char | 非空 | |
workspace_id | char | 非空 | |
type | text | 非空 | |
parent_id | char | 可空 | |
title | text | 可空 | |
pos_x | real | 非空 | 0 |
pos_y | real | 非空 | 0 |
data | jsonb | 非空 | '{}'::jsonb |
current_ver | integer | 非空 | 1 |
lock_owner | char | 可空 | |
lock_until | timestamptz | 可空 | |
status | text | 非空 | 'idle'::text |
created_by | text | 非空 | |
deleted_at | timestamptz | 可空 | |
created_at | timestamptz | 非空 | now() |
updated_at | timestamptz | 非空 | now() |
node_version
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
node_id PK | char | 非空 | |
version PK | integer | 非空 | |
data | jsonb | 非空 | |
output_asset_id | char | 可空 | |
task_id | char | 可空 | |
created_by | text | 非空 | |
created_at | timestamptz | 非空 | now() |
edge
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
project_id | char | 非空 | |
src_node_id | char | 非空 | |
dst_node_id | char | 非空 | |
kind | text | 非空 | |
timeline
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
project_id | char | 非空 | |
workspace_id | char | 非空 | |
fps | smallint | 非空 | 30 |
width | integer | 非空 | |
height | integer | 非空 | |
duration_ms | integer | 非空 | 0 |
doc | jsonb | 非空 | |
version | bigint | 非空 | 1 |
updated_at | timestamptz | 非空 | now() |
timeline_version
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
timeline_id PK | char | 非空 | |
version PK | bigint | 非空 | |
doc | jsonb | 非空 | |
restored_from | bigint | 可空 | |
created_by | text | 非空 | |
created_at | timestamptz | 非空 | now() |
export_job
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
workspace_id | char | 非空 | |
timeline_id | char | 非空 | |
timeline_ver | bigint | 非空 | |
preset | text | 非空 | |
status | text | 非空 | 'queued'::text |
workflow_id | text | 可空 | |
output_asset_id | char | 可空 | |
hold_id | char | 可空 | |
error_code | text | 可空 | |
error_message | text | 可空 | |
created_at | timestamptz | 非空 | now() |
finished_at | timestamptz | 可空 | |
intent
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
workspace_id | char | 非空 | |
project_id | char | 非空 | |
adapter | text | 非空 | |
source_ref | jsonb | 非空 | |
skill_id | text | 可空 | |
skill_version | text | 可空 | |
status | text | 非空 | 'open'::text |
created_at | timestamptz | 非空 | now() |
⭕ Agent 交互
| 表 | 存什么 | 列数 | 主要列 |
|---|---|---|---|
agent_session | 会话 | 9 | project_id, workspace_id, user_id, skill_id, skill_version, title … |
agent_message ◆ | 13 | session_id, run_id, role, delivery, content, attachments … | |
agent_run | 一次回复 | 14 | session_id, workspace_id, status, workflow_id, skill_version, budget_centi … |
run_event | 事件流 | 6 | run_id, seq, type, payload … |
interaction | 澄清卡 | 12 | run_id, kind, request, response, card_sha256, schema … |
run_action ★ | 动作回执 | 9 | run_id, kind, client_action_id, request_sha256, status, attempt … |
skill ◆ | 技能 | 5 | display_name, owner_workspace_id, status … |
skill_version ◆ | 技能版本 | 6 | manifest, sha256, status, published_at … |
Agent 交互:每张表的全部列、类型、默认值
agent_session
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
project_id | char | 非空 | |
workspace_id | char | 非空 | |
user_id | char | 非空 | |
skill_id | text | 非空 | |
skill_version | text | 非空 | |
title | text | 可空 | |
last_message_at | timestamptz | 可空 | |
created_at | timestamptz | 非空 | now() |
agent_message
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
session_id | char | 非空 | |
run_id | char | 可空 | |
role | text | 非空 | |
delivery | text | 可空 | |
content | text | 非空 | ''::text |
attachments | jsonb | 非空 | '[]'::jsonb |
status | text | 非空 | 'complete'::text |
content_seq | integer | 非空 | 0 |
suggestions | jsonb | 非空 | '[]'::jsonb |
client_action_id | text | 可空 | |
created_at | timestamptz | 非空 | now() |
completed_at | timestamptz | 可空 | |
agent_run
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
session_id | char | 非空 | |
workspace_id | char | 非空 | |
status | text | 非空 | |
workflow_id | text | 非空 | |
skill_version | text | 非空 | |
budget_centi | bigint | 非空 | |
spent_centi | bigint | 非空 | 0 |
input | jsonb | 非空 | |
error_code | text | 可空 | |
error_message | text | 可空 | |
started_at | timestamptz | 可空 | |
finished_at | timestamptz | 可空 | |
created_at | timestamptz | 非空 | now() |
run_event
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | bigint | 非空 | |
run_id | char | 非空 | |
seq | integer | 非空 | |
type | text | 非空 | |
payload | jsonb | 非空 | |
created_at PK | timestamptz | 非空 | now() |
interaction
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
run_id | char | 非空 | |
kind | text | 非空 | |
request | jsonb | 非空 | |
response | jsonb | 可空 | |
card_sha256 | char | 可空 | |
schema | jsonb | 可空 | |
client_action_id | text | 可空 | |
status | text | 非空 | 'pending'::text |
expires_at | timestamptz | 可空 | |
created_at | timestamptz | 非空 | now() |
resolved_at | timestamptz | 可空 | |
run_action
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
run_id | char | 非空 | |
kind | text | 非空 | |
client_action_id | text | 非空 | |
request_sha256 | char | 非空 | |
status | text | 非空 | |
attempt | integer | 非空 | 1 |
result | jsonb | 可空 | |
created_at | timestamptz | 非空 | now() |
skill
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | text | 非空 | |
display_name | text | 非空 | |
owner_workspace_id | char | 可空 | |
status | text | 非空 | 'active'::text |
created_at | timestamptz | 非空 | now() |
skill_version
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
skill_id PK | text | 非空 | |
version PK | text | 非空 | |
manifest | jsonb | 非空 | |
sha256 | char | 非空 | |
status | text | 非空 | 'published'::text |
published_at | timestamptz | 可空 | |
生成 · 报价批准 · 模型
| 表 | 存什么 | 列数 | 主要列 |
|---|---|---|---|
model_catalog | 模型 | 12 | capability, provider_key, model_name, display_name, input_schema, limits … |
model_version ★ | 模型版本 | 6 | model_id, version_key, config, config_sha256, published_at |
price_rule | 价格规则 | 8 | model_id, unit, cost_micro, charge_centi, modifiers, effective_from … |
generation_quote ★ | 报价 | 11 | workspace_id, client_request_id, request_sha256, quote_sha256, model_version_id, quoted_centi … |
generation_approval ★ | 批准 | 7 | quote_id, client_approval_id, request_sha256, quote_sha256, task_id … |
generation_task | 生成任务 | 22 | workspace_id, project_id, node_id, run_id, api_key_id, capability … |
task_attempt | 提交尝试 | 13 | task_id, seq, model_id, provider_task_id, provider_request_id, status … |
生成 · 报价批准 · 模型:每张表的全部列、类型、默认值
model_catalog
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
capability | text | 非空 | |
provider_key | text | 非空 | |
model_name | text | 非空 | |
display_name | text | 非空 | |
input_schema | jsonb | 非空 | |
limits | jsonb | 非空 | |
default_params | jsonb | 非空 | '{}'::jsonb |
max_concurrency | integer | 非空 | 10 |
timeout_s | integer | 非空 | 900 |
status | text | 非空 | 'active'::text |
adapter_key | text | 非空 | 'default'::text |
model_version
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
model_id | char | 非空 | |
version_key | text | 非空 | |
config | jsonb | 非空 | |
config_sha256 | char | 非空 | |
published_at | timestamptz | 可空 | |
price_rule
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
model_id | char | 非空 | |
unit | text | 非空 | |
cost_micro | bigint | 非空 | |
charge_centi | bigint | 非空 | |
modifiers | jsonb | 非空 | '{}'::jsonb |
effective_from | timestamptz | 非空 | |
effective_to | timestamptz | 可空 | |
generation_quote
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
workspace_id | char | 非空 | |
client_request_id | text | 非空 | |
request_sha256 | char | 非空 | |
quote_sha256 | char | 非空 | |
model_version_id | char | 非空 | |
quoted_centi | bigint | 非空 | |
expires_at | timestamptz | 非空 | |
source_run_id | char | 可空 | |
source_sha256 | char | 可空 | |
status | text | 非空 | 'quoted'::text |
generation_approval
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
quote_id | char | 非空 | |
client_approval_id | text | 非空 | |
request_sha256 | char | 非空 | |
quote_sha256 | char | 非空 | |
task_id | char | 可空 | |
created_at | timestamptz | 非空 | now() |
generation_task
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
workspace_id | char | 非空 | |
project_id | char | 可空 | |
node_id | char | 可空 | |
run_id | char | 可空 | |
api_key_id | char | 可空 | |
capability | text | 非空 | |
model_id | char | 可空 | |
request | jsonb | 非空 | |
request_hash | bytea | 非空 | |
idem_key | text | 可空 | |
status | text | 非空 | |
hold_id | char | 可空 | |
quoted_centi | bigint | 非空 | |
charged_centi | bigint | 可空 | |
outputs | jsonb | 可空 | |
error_code | text | 可空 | |
error_message | text | 可空 | |
workflow_id | text | 可空 | |
attempt_count | integer | 非空 | 0 |
created_at | timestamptz | 非空 | now() |
finished_at | timestamptz | 可空 | |
task_attempt
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
task_id | char | 非空 | |
seq | smallint | 非空 | |
model_id | char | 非空 | |
provider_task_id | text | 可空 | |
provider_request_id | text | 可空 | |
status | text | 非空 | |
cost_micro | bigint | 可空 | |
usage | jsonb | 可空 | |
error_code | text | 可空 | |
error_message | text | 可空 | |
submitted_at | timestamptz | 可空 | |
finished_at | timestamptz | 可空 | |
素材
| 表 | 存什么 | 列数 | 主要列 |
|---|---|---|---|
asset | 素材 | 19 | workspace_id, kind, source, storage_key, mime, bytes … |
asset_embedding | 素材向量 | 6 | start_ms, end_ms, caption, embedding … |
retrieval_seen | 检索去重 | 2 | … |
素材:每张表的全部列、类型、默认值
asset
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
workspace_id | char | 非空 | |
kind | text | 非空 | |
source | text | 非空 | |
storage_key | text | 非空 | |
mime | text | 非空 | |
bytes | bigint | 非空 | |
duration_ms | integer | 可空 | |
width | integer | 可空 | |
height | integer | 可空 | |
fps | real | 可空 | |
sha256 | bytea | 非空 | |
origin_task_id | char | 可空 | |
origin_url | text | 可空 | |
moderation | text | 非空 | 'pending'::text |
tags | text[] | 非空 | '{}'::text[] |
meta | jsonb | 非空 | '{}'::jsonb |
deleted_at | timestamptz | 可空 | |
created_at | timestamptz | 非空 | now() |
asset_embedding
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
asset_id PK | char | 非空 | |
segment_no PK | integer | 非空 | 0 |
start_ms | integer | 可空 | |
end_ms | integer | 可空 | |
caption | text | 可空 | |
embedding | float4[] | 非空 | |
retrieval_seen
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
context_key PK | text | 非空 | |
asset_id PK | char | 非空 | |
积分账本 · 订阅 · 额度
| 表 | 存什么 | 列数 | 主要列 |
|---|---|---|---|
ledger_account | 账户 | 5 | workspace_id, kind, balance_centi, version |
ledger_entry | 账本分录 | 10 | txn_id, account_id, direction, amount_centi, ref_type, ref_id … |
point_lot | 积分批次 | 8 | workspace_id, source, granted_centi, remaining_centi, expires_at, priority … |
hold | 冻结 | 9 | workspace_id, ref_type, ref_id, amount_centi, status, lot_allocation … |
quota_window ★ | 额度窗口 | 6 | limit_units, used_units, overage_enabled … |
approval_policy ★ | 审批策略 | 6 | workspace_id, member_id, mode, per_task_limit_centi, daily_limit_centi |
subscription | 订阅 | 9 | workspace_id, plan_code, status, provider, provider_sub_id, current_period_start … |
purchase_order | 订单 | 8 | workspace_id, kind, sku_code, amount_cents, currency, status … |
payment_event | 支付事件 | 7 | provider, event_id, type, payload, processed_at, received_at |
积分账本 · 订阅 · 额度:每张表的全部列、类型、默认值
ledger_account
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
workspace_id | char | 可空 | |
kind | text | 非空 | |
balance_centi | bigint | 非空 | 0 |
version | bigint | 非空 | 0 |
ledger_entry
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | bigint | 非空 | |
txn_id | char | 非空 | |
account_id | char | 非空 | |
direction | smallint | 非空 | |
amount_centi | bigint | 非空 | |
ref_type | text | 非空 | |
ref_id | text | 非空 | |
lot_id | char | 可空 | |
memo | text | 可空 | |
created_at PK | timestamptz | 非空 | now() |
point_lot
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
workspace_id | char | 非空 | |
source | text | 非空 | |
granted_centi | bigint | 非空 | |
remaining_centi | bigint | 非空 | |
expires_at | timestamptz | 可空 | |
priority | smallint | 非空 | |
created_at | timestamptz | 非空 | now() |
hold
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
workspace_id | char | 非空 | |
ref_type | text | 非空 | |
ref_id | text | 非空 | |
amount_centi | bigint | 非空 | |
status | text | 非空 | |
lot_allocation | jsonb | 非空 | |
expires_at | timestamptz | 非空 | |
created_at | timestamptz | 非空 | now() |
quota_window
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
workspace_id PK | char | 非空 | |
window_start PK | date | 非空 | |
kind PK | text | 非空 | |
limit_units | bigint | 非空 | |
used_units | bigint | 非空 | 0 |
overage_enabled | boolean | 非空 | false |
approval_policy
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
workspace_id | char | 非空 | |
member_id | bigint | 可空 | |
mode | text | 非空 | |
per_task_limit_centi | bigint | 可空 | |
daily_limit_centi | bigint | 可空 | |
subscription
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
workspace_id | char | 非空 | |
plan_code | text | 非空 | |
status | text | 非空 | |
provider | text | 非空 | |
provider_sub_id | text | 非空 | |
current_period_start | timestamptz | 可空 | |
current_period_end | timestamptz | 可空 | |
cancel_at_period_end | boolean | 非空 | false |
purchase_order
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
workspace_id | char | 非空 | |
kind | text | 非空 | |
sku_code | text | 可空 | |
amount_cents | integer | 非空 | |
currency | text | 非空 | |
status | text | 非空 | |
created_at | timestamptz | 非空 | now() |
payment_event
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | bigint | 非空 | |
provider | text | 非空 | |
event_id | text | 非空 | |
type | text | 非空 | |
payload | jsonb | 非空 | |
processed_at | timestamptz | 可空 | |
received_at | timestamptz | 非空 | now() |
平台
| 表 | 存什么 | 列数 | 主要列 |
|---|---|---|---|
outbox | 事件外发 | 8 | topic, key, payload, status, attempts, next_at … |
webhook_endpoint ◆ | Webhook 地址 | 7 | workspace_id, url, secret_hash, events, status … |
audit_log | 审计 | 9 | workspace_id, actor, action, target_type, target_id, diff … |
平台:每张表的全部列、类型、默认值
outbox
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | bigint | 非空 | |
topic | text | 非空 | |
key | text | 非空 | |
payload | jsonb | 非空 | |
status | text | 非空 | 'pending'::text |
attempts | integer | 非空 | 0 |
next_at | timestamptz | 非空 | now() |
created_at | timestamptz | 非空 | now() |
webhook_endpoint
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | char | 非空 | |
workspace_id | char | 非空 | |
url | text | 非空 | |
secret_hash | bytea | 非空 | |
events | text[] | 非空 | |
status | text | 非空 | 'active'::text |
created_at | timestamptz | 非空 | now() |
audit_log
| 列 | 类型 | 空 | 默认 |
|---|---|---|---|
id PK | bigint | 非空 | |
workspace_id | char | 可空 | |
actor | text | 非空 | |
action | text | 非空 | |
target_type | text | 可空 | |
target_id | text | 可空 | |
diff | jsonb | 可空 | |
ip | inet | 可空 | |
created_at | timestamptz | 非空 | now() |
原设计提到、最终版没有单独建表的表,去哪了
原设计的“表域总览”列了约 60 个名字,但只给了 30 张的 DDL。最终版把每个名字都交代清楚:要么建了,要么说明由谁代替,要么明确没做。
| 原设计提到的表 | 最终版去向 |
|---|---|
user | 建为 app_user(“user”是 PostgreSQL 保留字) |
identity_provider_binding | 未建。app_user.password_hash 为空表示走 SSO;第三方登录绑定表放到做 SSO 时再设计 |
canvas | 不单建:画布 = project + node + edge |
timeline_track / timeline_clip | 不单建:轨道和片段在 timeline.doc(JSONB)里;历史在 timeline_version |
checkpoint | 不建业务表:由 Agent 运行时(LangGraph)的检查点存储管理,可与业务库同一个 PostgreSQL 实例、独立 schema |
task_event | 不单建:任务状态变化走 outbox 投递,运行过程事件在 run_event |
model_route | 不单建:路由规则放配置,价格与约束在 model_version / price_rule |
quota | 建为 quota_window |
asset_variant / asset_tag / character / character_voice / collection_job | 不单建:放在 asset.kind(如 character_ref)和 asset 的 JSONB 元数据里 |
order / payment | 建为 purchase_order / payment_event |
sku / redeem_code | 未建:套餐与积分包由 plan 表达;兑换码以后需要时再加 |
moderation_record / banned_term / risk_rule / config_item | 未建:违禁词与规则放配置中心;输入审核拒绝记为任务的 content_rejected,供应商审核结果记在 task_attempt,素材审核结果在 asset.moderation;F11 的 L5 人工复核队列依赖这些表,属于后续 |
usage_record | 不单建:用量从 ledger_entry 与 generation_task 聚合进 ClickHouse,GET /billing/usage 读聚合 |
完整 DDL(PostgreSQL 16)
展开完整脚本
CREATE TABLE workspace (
id CHAR(26) PRIMARY KEY,
org_id CHAR(26) NOT NULL,
name TEXT NOT NULL,
region TEXT NOT NULL CHECK (region IN ('cn','global')),
plan_code TEXT NOT NULL DEFAULT 'free',
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active','suspended','closed')),
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE member (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
workspace_id CHAR(26) NOT NULL,
user_id CHAR(26) NOT NULL,
role TEXT NOT NULL CHECK (role IN ('owner','admin','editor','viewer')),
seat BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (workspace_id, user_id)
);
CREATE TABLE api_key (
id CHAR(26) PRIMARY KEY,
workspace_id CHAR(26) NOT NULL,
name TEXT NOT NULL,
key_prefix TEXT NOT NULL, -- 展示用前 8 位
key_hash BYTEA NOT NULL UNIQUE, -- SHA-256,明文不入库
scopes TEXT[] NOT NULL, -- e.g. {'generate:write','project:read'}
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active','revoked','expired')),
expires_at TIMESTAMPTZ,
last_used_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE project (
id CHAR(26) PRIMARY KEY,
workspace_id CHAR(26) NOT NULL,
owner_id CHAR(26) NOT NULL,
title TEXT NOT NULL,
kind TEXT NOT NULL CHECK (kind IN ('freeform','url_ad','viral_clone','drama','batch')),
aspect_ratio TEXT NOT NULL DEFAULT '9:16',
language TEXT NOT NULL DEFAULT 'en',
cover_asset_id CHAR(26),
status TEXT NOT NULL DEFAULT 'draft' CHECK (status IN ('draft','generating','ready','archived')),
doc_version BIGINT NOT NULL DEFAULT 0, -- 画布整体版本,节点变更自增
deleted_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX project_ws_updated ON project (workspace_id, updated_at DESC) WHERE deleted_at IS NULL;
CREATE TABLE node (
id CHAR(26) PRIMARY KEY,
project_id CHAR(26) NOT NULL,
workspace_id CHAR(26) NOT NULL,
type TEXT NOT NULL CHECK (type IN
('text','script','image','video','audio','character','storyboard','scene','shot','ref_video','product','plan','final_video')),
parent_id CHAR(26), -- scene → shot 层级
title TEXT,
pos_x REAL NOT NULL DEFAULT 0,
pos_y REAL NOT NULL DEFAULT 0,
data JSONB NOT NULL DEFAULT '{}', -- 按 type 的 schema,见 4.5
current_ver INT NOT NULL DEFAULT 1,
lock_owner CHAR(26), -- 节点级编辑提示锁(软锁,30s 租期)
lock_until TIMESTAMPTZ,
status TEXT NOT NULL DEFAULT 'idle' CHECK (status IN ('idle','pending','running','done','failed','stale')),
created_by TEXT NOT NULL, -- 'user:<id>' | 'agent:<run_id>'
deleted_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX node_project ON node (project_id) WHERE deleted_at IS NULL;
CREATE TABLE node_version (
node_id CHAR(26) NOT NULL,
version INT NOT NULL,
data JSONB NOT NULL,
output_asset_id CHAR(26), -- 该版本产物
task_id CHAR(26), -- 来源生成任务(溯源)
created_by TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (node_id, version)
);
CREATE TABLE edge (
id CHAR(26) PRIMARY KEY,
project_id CHAR(26) NOT NULL,
src_node_id CHAR(26) NOT NULL,
dst_node_id CHAR(26) NOT NULL,
kind TEXT NOT NULL CHECK (kind IN ('data','ref','sequence')),
UNIQUE (src_node_id, dst_node_id, kind)
);
CREATE TABLE timeline (
id CHAR(26) PRIMARY KEY,
project_id CHAR(26) NOT NULL,
workspace_id CHAR(26) NOT NULL,
fps SMALLINT NOT NULL DEFAULT 30,
width INT NOT NULL, height INT NOT NULL,
duration_ms INT NOT NULL DEFAULT 0,
doc JSONB NOT NULL, -- 轨道/片段/转场/字幕样式,见 4.5
version BIGINT NOT NULL DEFAULT 1,
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE export_job (
id CHAR(26) PRIMARY KEY,
workspace_id CHAR(26) NOT NULL,
timeline_id CHAR(26) NOT NULL,
timeline_ver BIGINT NOT NULL,
preset TEXT NOT NULL, -- '1080p_h264' | '720p_h264' | '4k_h265'
status TEXT NOT NULL DEFAULT 'queued'
CHECK (status IN ('queued','rendering','succeeded','failed','cancelled')),
workflow_id TEXT,
output_asset_id CHAR(26),
hold_id CHAR(26) UNIQUE, -- 一个导出只对应一笔冻结(与 hold.UNIQUE(ref_type, ref_id) 一致)
error_code TEXT, error_message TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
finished_at TIMESTAMPTZ
);
CREATE TABLE agent_session (
id CHAR(26) PRIMARY KEY,
project_id CHAR(26) NOT NULL,
workspace_id CHAR(26) NOT NULL,
user_id CHAR(26) NOT NULL,
skill_id TEXT NOT NULL, -- 'url_to_ad' | 'viral_clone' | 'freeform'
skill_version TEXT NOT NULL, -- 会话创建时固定的技能版本(决策 D9)
title TEXT,
last_message_at TIMESTAMPTZ, -- 历史列表排序;每写入一条消息时更新
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE agent_run (
id CHAR(26) PRIMARY KEY,
session_id CHAR(26) NOT NULL,
workspace_id CHAR(26) NOT NULL,
status TEXT NOT NULL CHECK (status IN
('queued','running','waiting_user','succeeded','failed','cancelled')),
workflow_id TEXT NOT NULL,
skill_version TEXT NOT NULL,
budget_centi BIGINT NOT NULL, -- 本 run 预算
spent_centi BIGINT NOT NULL DEFAULT 0,
input JSONB NOT NULL,
error_code TEXT, error_message TEXT,
started_at TIMESTAMPTZ, finished_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- 同一会话同一时刻只允许一个"活跃 run"
CREATE UNIQUE INDEX one_active_run_per_session
ON agent_run (session_id) WHERE status IN ('queued','running','waiting_user');
CREATE TABLE run_event (
id BIGINT GENERATED ALWAYS AS IDENTITY,
run_id CHAR(26) NOT NULL,
seq INT NOT NULL, -- run 内单调递增,SSE 断线续传依据
type TEXT NOT NULL, -- 见 5.6 事件表
payload JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (created_at, id)
) PARTITION BY RANGE (created_at);
CREATE UNIQUE INDEX run_event_run_seq ON run_event (run_id, seq, created_at);
CREATE TABLE interaction (
id CHAR(26) PRIMARY KEY,
run_id CHAR(26) NOT NULL,
kind TEXT NOT NULL, -- 'collect_info'|'confirm_plan'|'pick_option'|'confirm_cost'|'review_script'|'payment_required'
request JSONB NOT NULL,
response JSONB,
card_sha256 CHAR(64), -- 卡片内容哈希:答案按原卡校验
schema JSONB, -- 字段 key / kind / required / options
client_action_id TEXT, -- 幂等键
status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending','resolved','expired','cancelled')),
expires_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
resolved_at TIMESTAMPTZ
);
CREATE UNIQUE INDEX interaction_idem ON interaction (id, client_action_id) WHERE client_action_id IS NOT NULL;
CREATE TABLE model_catalog (
id CHAR(26) PRIMARY KEY,
capability TEXT NOT NULL, -- 't2v' 'i2v' 'flf2v' 'r2v' 't2i' 'tts' 'lipsync' ...
provider_key TEXT NOT NULL, -- 'ark' 'dashscope' 'tencent_vod' ...
model_name TEXT NOT NULL,
display_name TEXT NOT NULL,
input_schema JSONB NOT NULL, -- JSON Schema:可传参数
limits JSONB NOT NULL, -- 最长时长、分辨率、参考图数量
default_params JSONB NOT NULL DEFAULT '{}',
max_concurrency INT NOT NULL DEFAULT 10,
timeout_s INT NOT NULL DEFAULT 900,
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active','disabled','beta')),
adapter_key TEXT NOT NULL DEFAULT 'default', -- 适配器注册键:新增模型只加数据 + 一个适配器
UNIQUE (provider_key, model_name, capability)
);
CREATE TABLE price_rule (
id CHAR(26) PRIMARY KEY,
model_id CHAR(26) NOT NULL,
unit TEXT NOT NULL CHECK (unit IN ('second','image','token','call','char')),
cost_micro BIGINT NOT NULL, -- 我方成本,1e-6 USD
charge_centi BIGINT NOT NULL, -- 向用户收取积分(1/100 点)/单位
modifiers JSONB NOT NULL DEFAULT '{}',-- {"resolution":{"1080p":1.5},"audio":1.3}
effective_from TIMESTAMPTZ NOT NULL,
effective_to TIMESTAMPTZ
);
CREATE TABLE generation_task (
id CHAR(26) PRIMARY KEY,
workspace_id CHAR(26) NOT NULL,
project_id CHAR(26),
node_id CHAR(26),
run_id CHAR(26),
api_key_id CHAR(26),
capability TEXT NOT NULL,
model_id CHAR(26), -- 路由决定后写入
request JSONB NOT NULL,
request_hash BYTEA NOT NULL,
idem_key TEXT,
status TEXT NOT NULL CHECK (status IN
('created','held','queued','submitting','submit_uncertain','running',
'succeeded','failed','cancelling','cancelled','expired')),
hold_id CHAR(26) UNIQUE, -- 一个任务只对应一笔冻结(与 hold.UNIQUE(ref_type, ref_id) 一致)
quoted_centi BIGINT NOT NULL,
charged_centi BIGINT,
outputs JSONB,
error_code TEXT, error_message TEXT,
workflow_id TEXT,
attempt_count INT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
finished_at TIMESTAMPTZ
);
CREATE UNIQUE INDEX task_idem ON generation_task (workspace_id, idem_key) WHERE idem_key IS NOT NULL;
CREATE INDEX task_ws_created ON generation_task (workspace_id, created_at DESC);
CREATE INDEX task_active ON generation_task (status) WHERE status IN ('queued','submitting','submit_uncertain','running','cancelling');
CREATE TABLE task_attempt (
id CHAR(26) PRIMARY KEY,
task_id CHAR(26) NOT NULL,
seq SMALLINT NOT NULL,
model_id CHAR(26) NOT NULL,
provider_task_id TEXT,
provider_request_id TEXT,
status TEXT NOT NULL, -- submitted/succeeded/failed/uncertain
cost_micro BIGINT,
usage JSONB,
error_code TEXT, error_message TEXT,
submitted_at TIMESTAMPTZ, finished_at TIMESTAMPTZ,
UNIQUE (task_id, seq)
);
CREATE INDEX attempt_provider ON task_attempt (model_id, provider_task_id);
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE asset (
id CHAR(26) PRIMARY KEY,
workspace_id CHAR(26) NOT NULL,
kind TEXT NOT NULL CHECK (kind IN ('image','video','audio','font','doc','character_ref')),
source TEXT NOT NULL CHECK (source IN ('upload','generated','collected','library')),
storage_key TEXT NOT NULL, -- COS/S3 key
mime TEXT NOT NULL, bytes BIGINT NOT NULL,
duration_ms INT, width INT, height INT, fps REAL,
sha256 BYTEA NOT NULL,
origin_task_id CHAR(26), -- 生成溯源
origin_url TEXT, -- 采集来源
moderation TEXT NOT NULL DEFAULT 'pending' CHECK (moderation IN ('pending','pass','review','reject')),
tags TEXT[] NOT NULL DEFAULT '{}',
meta JSONB NOT NULL DEFAULT '{}',
deleted_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX asset_ws_kind ON asset (workspace_id, kind, created_at DESC) WHERE deleted_at IS NULL;
CREATE INDEX asset_hash ON asset (workspace_id, sha256);
CREATE TABLE asset_embedding (
asset_id CHAR(26) NOT NULL,
segment_no INT NOT NULL DEFAULT 0, -- 视频按镜头切分
start_ms INT, end_ms INT,
caption TEXT,
embedding vector(1024) NOT NULL,
PRIMARY KEY (asset_id, segment_no)
);
CREATE INDEX asset_emb_hnsw ON asset_embedding USING hnsw (embedding vector_cosine_ops) WITH (m=16, ef_construction=128);
CREATE TABLE retrieval_seen ( -- 继承旧 knowhub 的 context_key 去重语义
context_key TEXT NOT NULL,
asset_id CHAR(26) NOT NULL,
PRIMARY KEY (context_key, asset_id)
);
CREATE TABLE ledger_account (
id CHAR(26) PRIMARY KEY,
workspace_id CHAR(26), -- 系统账户为 NULL
kind TEXT NOT NULL CHECK (kind IN
('wallet_paid','wallet_bonus','wallet_subscription','held','revenue','cost_of_goods','expired','refund_pool')),
balance_centi BIGINT NOT NULL DEFAULT 0, -- 缓存余额,可由 entry 重算
version BIGINT NOT NULL DEFAULT 0,
UNIQUE (workspace_id, kind)
);
CREATE TABLE ledger_entry (
id BIGINT GENERATED ALWAYS AS IDENTITY,
txn_id CHAR(26) NOT NULL, -- 同一笔业务的所有分录
account_id CHAR(26) NOT NULL,
direction SMALLINT NOT NULL CHECK (direction IN (1,-1)), -- +入 / -出
amount_centi BIGINT NOT NULL CHECK (amount_centi > 0),
ref_type TEXT NOT NULL, -- 'hold'|'task'|'run'|'order'|'subscription'|'adjust'|'expire'(run = 对话推理用量,task = 媒体生成,决策 D4)
ref_id TEXT NOT NULL,
lot_id CHAR(26), -- 积分批次(有过期时间、扣减顺序)
memo TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (created_at, id)
) PARTITION BY RANGE (created_at);
CREATE INDEX entry_txn ON ledger_entry (txn_id);
CREATE INDEX entry_ref ON ledger_entry (ref_type, ref_id);
CREATE TABLE point_lot ( -- 积分批次:过期时间 + 扣减优先级
id CHAR(26) PRIMARY KEY,
workspace_id CHAR(26) NOT NULL,
source TEXT NOT NULL CHECK (source IN ('purchase','subscription','bonus','promo','compensation')),
granted_centi BIGINT NOT NULL,
remaining_centi BIGINT NOT NULL,
expires_at TIMESTAMPTZ,
priority SMALLINT NOT NULL, -- 小者先扣:promo < subscription < bonus < purchase
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX lot_spend ON point_lot (workspace_id, priority, expires_at NULLS LAST) WHERE remaining_centi > 0;
CREATE TABLE hold (
id CHAR(26) PRIMARY KEY,
workspace_id CHAR(26) NOT NULL,
ref_type TEXT NOT NULL, ref_id TEXT NOT NULL,
amount_centi BIGINT NOT NULL,
status TEXT NOT NULL CHECK (status IN ('active','settled','released','expired')),
lot_allocation JSONB NOT NULL, -- [{lot_id, centi}],释放/结算时按此回写
expires_at TIMESTAMPTZ NOT NULL, -- 兜底:超时自动 release
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (ref_type, ref_id) -- 同一业务只能一个冻结 → 幂等
);
CREATE TABLE plan (
code TEXT PRIMARY KEY, name TEXT NOT NULL, interval TEXT NOT NULL CHECK (interval IN ('month','year')),
price_cents INT NOT NULL, currency TEXT NOT NULL,
monthly_points_centi BIGINT NOT NULL, seats INT NOT NULL, features JSONB NOT NULL
);
CREATE TABLE subscription (
id CHAR(26) PRIMARY KEY, workspace_id CHAR(26) NOT NULL, plan_code TEXT NOT NULL,
status TEXT NOT NULL CHECK (status IN ('trialing','active','past_due','cancelled','expired')),
provider TEXT NOT NULL, provider_sub_id TEXT NOT NULL,
current_period_start TIMESTAMPTZ, current_period_end TIMESTAMPTZ,
cancel_at_period_end BOOLEAN NOT NULL DEFAULT false,
UNIQUE (provider, provider_sub_id)
);
CREATE TABLE purchase_order (
id CHAR(26) PRIMARY KEY, workspace_id CHAR(26) NOT NULL,
kind TEXT NOT NULL CHECK (kind IN ('subscription','topup','seat','storage')),
sku_code TEXT, amount_cents INT NOT NULL, currency TEXT NOT NULL,
status TEXT NOT NULL CHECK (status IN ('created','paid','failed','refunded','partially_refunded')),
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE payment_event ( -- Webhook 原始事件,幂等入账依据
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
provider TEXT NOT NULL, event_id TEXT NOT NULL, type TEXT NOT NULL,
payload JSONB NOT NULL, processed_at TIMESTAMPTZ,
received_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (provider, event_id)
);
CREATE TABLE outbox (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
topic TEXT NOT NULL, key TEXT NOT NULL, payload JSONB NOT NULL,
status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending','sent','dead')),
attempts INT NOT NULL DEFAULT 0, next_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX outbox_pending ON outbox (next_at) WHERE status='pending';
CREATE TABLE audit_log (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
workspace_id CHAR(26), actor TEXT NOT NULL, action TEXT NOT NULL,
target_type TEXT, target_id TEXT, diff JSONB, ip INET, created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- 分区父表必须有分区才能写入。DEFAULT 分区兜底;生产用 pg_partman 按月预建并滚动归档。
CREATE TABLE run_event_default PARTITION OF run_event DEFAULT;
CREATE TABLE ledger_entry_default PARTITION OF ledger_entry DEFAULT;
-- ===== 吸收竞品后新增的 7 张表 =====
-- 1) 报价与批准:批准必须带两个哈希,并有有效期(来自复刻里跑通的流程;LibTV 预算只提醒的做法被否决)
CREATE TABLE generation_quote (
id CHAR(26) PRIMARY KEY,
workspace_id CHAR(26) NOT NULL,
client_request_id TEXT NOT NULL,
request_sha256 CHAR(64) NOT NULL, -- 提示词、参数、模型版本的规范化摘要
quote_sha256 CHAR(64) NOT NULL, -- 价格与有效期的摘要
model_version_id CHAR(26) NOT NULL,
quoted_centi BIGINT NOT NULL CHECK (quoted_centi >= 0),
expires_at TIMESTAMPTZ NOT NULL,
source_run_id CHAR(26), -- 来自 Agent 回复时记录来源
source_sha256 CHAR(64),
status TEXT NOT NULL DEFAULT 'quoted' CHECK (status IN ('quoted','approved','expired','rejected')),
UNIQUE (workspace_id, client_request_id)
);
CREATE TABLE generation_approval (
id CHAR(26) PRIMARY KEY,
quote_id CHAR(26) NOT NULL, -- → generation_quote.id(沿用 Lumen 约定:不建数据库外键,靠应用层与唯一键)
client_approval_id TEXT NOT NULL,
request_sha256 CHAR(64) NOT NULL,
quote_sha256 CHAR(64) NOT NULL,
task_id CHAR(26),
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (quote_id, client_approval_id) -- 重放只返回同一个任务
);
-- 2) 审批策略:Ask First / Always Allow(来自 TopView),带额度上限
CREATE TABLE approval_policy (
id CHAR(26) PRIMARY KEY,
workspace_id CHAR(26) NOT NULL,
member_id BIGINT, -- NULL = 工作区默认策略
mode TEXT NOT NULL CHECK (mode IN ('ask_first','always_allow_within_limit')),
per_task_limit_centi BIGINT,
daily_limit_centi BIGINT
);
CREATE UNIQUE INDEX approval_policy_scope ON approval_policy (workspace_id, COALESCE(member_id, 0));
-- 3) 额度窗口:日额度与「额外用量」开关(来自 CreaTok);与积分分开
CREATE TABLE quota_window (
workspace_id CHAR(26) NOT NULL,
window_start DATE NOT NULL,
kind TEXT NOT NULL CHECK (kind IN ('agent_daily','plan_monthly')),
limit_units BIGINT NOT NULL,
used_units BIGINT NOT NULL DEFAULT 0,
overage_enabled BOOLEAN NOT NULL DEFAULT FALSE,
PRIMARY KEY (workspace_id, window_start, kind)
);
-- 4) 创作意图:URL / 商品 / 脚本 / 参考视频等入口统一成 intent(来自 Creatify、Pollo、TopView)
CREATE TABLE intent (
id CHAR(26) PRIMARY KEY,
workspace_id CHAR(26) NOT NULL,
project_id CHAR(26) NOT NULL,
adapter TEXT NOT NULL, -- 'url' | 'product' | 'script' | 'ref_video' | 'freeform'
source_ref JSONB NOT NULL,
skill_id TEXT,
skill_version TEXT,
status TEXT NOT NULL DEFAULT 'open' CHECK (status IN ('open','planned','running','done','cancelled')),
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- 5) 模型注册:版本、价格表、适配器键(我们在复刻里遇到的最大扩展障碍)
CREATE TABLE model_version (
id CHAR(26) PRIMARY KEY,
model_id CHAR(26) NOT NULL, -- → model_catalog.id
version_key TEXT NOT NULL,
config JSONB NOT NULL, -- 时长/画幅/分辨率约束、价格表、是否可取消
config_sha256 CHAR(64) NOT NULL,
published_at TIMESTAMPTZ,
UNIQUE (model_id, version_key)
);
-- 6) 动作回执:消息、停止、切换模型、澄清卡回答都是幂等动作
CREATE TABLE run_action (
id CHAR(26) PRIMARY KEY,
run_id CHAR(26) NOT NULL,
kind TEXT NOT NULL CHECK (kind IN ('message','stop','model_change','interaction_response')),
client_action_id TEXT NOT NULL,
request_sha256 CHAR(64) NOT NULL,
status TEXT NOT NULL, -- accepted | terminal_observed | rejected | unknown
attempt INT NOT NULL DEFAULT 1,
result JSONB,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (run_id, kind, client_action_id) -- 同一个动作 ID 内容不同则冲突(409)
);
-- 7) 澄清卡:带内容哈希,答案按原卡校验
-- 补全:最终设计里被其他表、接口、决策引用,但原设计没有给 DDL 的表。
-- 沿用 Lumen 的约定:不建数据库外键,关系由应用层与唯一键保证。
CREATE TABLE org (
id CHAR(26) PRIMARY KEY,
name TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active','suspended','closed')),
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE app_user ( -- “user” 是 PostgreSQL 保留字,所以叫 app_user
id CHAR(26) PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
display_name TEXT,
password_hash TEXT, -- 为空表示走 SSO
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active','locked','deleted')),
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
last_login_at TIMESTAMPTZ
);
CREATE TABLE session_token ( -- 刷新令牌(只存哈希),登出与轮换都落在这里
id CHAR(26) PRIMARY KEY,
user_id CHAR(26) NOT NULL,
token_hash BYTEA NOT NULL UNIQUE,
expires_at TIMESTAMPTZ NOT NULL,
revoked_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE skill (
id TEXT PRIMARY KEY, -- 'url_to_ad' | 'viral_clone' | 'freeform' | 开发者发布的 id
display_name TEXT NOT NULL,
owner_workspace_id CHAR(26), -- 为空表示官方
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active','retired')),
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE skill_version ( -- 会话创建时固定一个版本,发布新版不影响进行中的会话
skill_id TEXT NOT NULL,
version TEXT NOT NULL,
manifest JSONB NOT NULL,
sha256 CHAR(64) NOT NULL,
status TEXT NOT NULL DEFAULT 'published' CHECK (status IN ('draft','published','retired')),
published_at TIMESTAMPTZ,
PRIMARY KEY (skill_id, version)
);
CREATE TABLE webhook_endpoint ( -- 开放平台回调地址;投递走 outbox
id CHAR(26) PRIMARY KEY,
workspace_id CHAR(26) NOT NULL,
url TEXT NOT NULL,
secret_hash BYTEA NOT NULL,
events TEXT[] NOT NULL,
status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active','disabled')),
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE project_asset_ref ( -- 素材归工作区,项目只记引用和用途(项目 ⇄ 素材 多对多)
project_id CHAR(26) NOT NULL,
asset_id CHAR(26) NOT NULL,
purpose TEXT NOT NULL DEFAULT 'reference',
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (project_id, asset_id)
);
CREATE TABLE timeline_version ( -- 时间线每次保存一条历史;恢复 = 以旧内容新建一个版本
timeline_id CHAR(26) NOT NULL,
version BIGINT NOT NULL,
doc JSONB NOT NULL,
restored_from BIGINT,
created_by TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (timeline_id, version)
);
-- 账本只追加:分录写入后不能改、不能删(决策 D3)。归档用分区的 DETACH,不经过这个触发器。
CREATE FUNCTION ledger_entry_append_only() RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
RAISE EXCEPTION 'ledger_entry is append-only';
END $$;
CREATE TRIGGER ledger_entry_no_change BEFORE UPDATE OR DELETE ON ledger_entry
FOR EACH ROW EXECUTE FUNCTION ledger_entry_append_only();
CREATE TABLE agent_message ( -- 对话消息:历史、刷新恢复、下一轮上下文都读这里;run_event 只记执行过程
id CHAR(26) PRIMARY KEY,
session_id CHAR(26) NOT NULL,
run_id CHAR(26), -- 用户消息:它启动或补充的 run;助手消息:产生它的 run
role TEXT NOT NULL CHECK (role IN ('user','assistant')),
delivery TEXT CHECK (delivery IN ('new_run','guidance','resume')), -- 仅用户消息:新任务 / 补充到运行中的任务 / 回答卡片
content TEXT NOT NULL DEFAULT '', -- Markdown;助手消息流式期间按 content_seq 定期落库
attachments JSONB NOT NULL DEFAULT '[]', -- [{asset_id, purpose}]
status TEXT NOT NULL DEFAULT 'complete' CHECK (status IN ('streaming','complete','stopped','failed')),
content_seq INT NOT NULL DEFAULT 0, -- content 已包含到哪个事件 seq;刷新后从这里续接
suggestions JSONB NOT NULL DEFAULT '[]', -- 助手消息结束时给出的后续建议,最多 3 条
client_action_id TEXT, -- 用户消息的幂等键,与 run_action.client_action_id 相同
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
completed_at TIMESTAMPTZ
);
CREATE UNIQUE INDEX agent_message_idem ON agent_message (session_id, client_action_id) WHERE client_action_id IS NOT NULL;
CREATE INDEX agent_message_page ON agent_message (session_id, created_at DESC, id DESC);
CREATE UNIQUE INDEX one_streaming_message_per_run ON agent_message (run_id) WHERE status = 'streaming';
- 约束写进数据库:应用会有 bug,约束不会。报价哈希、幂等唯一键、状态枚举都是数据库层面的保证。
- 账本只追加:每一分都有来源和去向,失败任务释放冻结。
- PostgreSQL + JSONB:节点、模型约束、Skill 参数变化很快,用 JSONB 承载可变部分。
状态机、JSONB 约定、索引与分区(保留)
4.1 数据设计总则
- PostgreSQL 16,不建数据库外键(沿用旧网关经验),一致性由应用事务、唯一索引、对账任务保证。
- 主键:对外资源用
ULID(CHAR(26),带前缀如prj_、tsk_仅在 API 层加);内部流水用BIGINT IDENTITY。 - 租户内的业务表带
workspace_id(分库键);子表经父表确定工作区(例如node_version经node);全局表(用户、组织、模型目录、技能、套餐)不带。时间用timestamptz;需要软删除的表用deleted_at。 - 金额与积分:
BIGINT存最小单位(积分 = 1/100 点,即 "centi-point";货币 = 分/美分),禁止浮点。 - 大表按月分区:
run_event、ledger_entry。原设计还列了task_event、usage_record,最终版没有建这两张表(任务事件走 outbox,用量从账本与任务聚合进 ClickHouse)。 - 状态字段用
TEXT + CHECK,状态迁移通过UPDATE ... WHERE status = :from乐观实现,不满足影响行数为 0 即视为冲突。
4.4 状态机
生成任务 generation_task
stateDiagram-v2 [*] --> created: 批准报价(与冻结同一事务) created --> held: 冻结积分成功(同一事务内) held --> queued: outbox 启动工作流 queued --> cancelled: 排队中取消 queued --> submitting: Worker 领取 submitting --> running: 供应商受理(拿到 provider_task_id) submitting --> submit_uncertain: 超时/连接断开,是否受理未知 submit_uncertain --> running: 查询确认已受理 submit_uncertain --> queued: 查询确认未受理,重投(可换供应商) running --> succeeded: 产物落库+审核通过 running --> failed: 供应商失败/审核拒绝 running --> cancelling: 用户取消 cancelling --> cancelled: 供应商确认/超时强制 running --> expired: 超过 timeout succeeded --> [*] failed --> [*] cancelled --> [*] expired --> [*]
结算规则:succeeded → settle(实扣 = 报价,可含供应商返回的实际 usage 修正);failed/cancelled/expired → release 全额;submit_uncertain 保持冻结,直到确认;供应商返回失败但没有原因、无法确认是否已计费时同样保持冻结,界面显示“费用待核对”,人工处理。余额不足、报价过期、哈希不符在批准时被拒(402 / 409),输入审核在报价时被拒(403),这些情况都不建任务、不扣费;路由也在报价时完成。对外只暴露 6 态:queued / running / succeeded / failed / cancelled / expired。
Agent Run
stateDiagram-v2 [*] --> queued queued --> running: Workflow 启动 running --> waiting_user: 发出 interaction waiting_user --> running: interaction_response(Signal) waiting_user --> cancelled: 取消 / 卡片过期 running --> succeeded running --> failed running --> cancelled
积分冻结 hold
stateDiagram-v2 [*] --> active: reserve active --> settled: settle(实扣 ≤ 冻结,差额返还) active --> released: release(失败/取消) active --> expired: 到期兜底释放(跳过状态不明、待人工核对的任务)
节点 node
stateDiagram-v2 direction LR [*] --> idle idle --> pending: 触发生成 pending --> running running --> done running --> failed failed --> pending: 重试 done --> stale: 上游变更 stale --> pending: 重生成 done --> pending: 重新生成
导出 export_job
stateDiagram-v2 [*] --> queued queued --> rendering: Worker 领取 rendering --> succeeded: 产出入库 rendering --> failed queued --> cancelled: 取消 rendering --> cancelled: 取消
4.5 JSONB 结构约定(节选)
// node.data type=shot
{
"prompt": "Close-up of the bottle, water droplets, soft light",
"negative": "",
"duration_s": 5,
"aspect_ratio": "9:16",
"capability": "i2v",
"model": {"mode":"auto","quality":"standard"}, // auto → 报价时由路由决定,批准后固定为报价里的版本
"refs": [{"role":"first_frame","asset_id":"01J..."},{"role":"character","node_id":"01J..."}],
"camera": {"move":"push_in","speed":0.4},
"audio": {"mode":"native|tts|none","tts_text":"..."},
"seed": 123456
}
// timeline.doc
{
"tracks":[
{"id":"v1","type":"video","clips":[
{"id":"c1","asset_id":"01J..","in_ms":0,"out_ms":5000,"start_ms":0,"transform":{"scale":1,"x":0,"y":0},
"transition_in":{"type":"fade","ms":300},"source_node":"01J.."}]},
{"id":"a1","type":"audio","clips":[{"asset_id":"01J..","start_ms":0,"gain_db":-6}]},
{"id":"s1","type":"subtitle","clips":[{"text":"...","start_ms":200,"end_ms":2400,"style_id":"sty_01"}]}
]
}
4.6 索引与分区策略
| 表 | 分区 | 保留 | 说明 |
|---|---|---|---|
| run_event | 按月 | 热 3 月 → 归档 Parquet 至 COS 2 年 | SSE 续传只读热区 |
| ledger_entry | 按月 | 永久(法务 7 年) | 冷分区压缩 |
| generation_task / ledger_entry 的用量聚合 | — | — | 不建 task_event / usage_record 表,聚合结果进 ClickHouse,GET /billing/usage 读聚合 |
| asset_embedding | 不分区 | — | HNSW,超 5000 万行迁向量库 |
最终设计 · 接口清单
- 55 条接口按 7 个领域分组,每组标出它读写的表;点组名可收起。
- 变化集中在两处:报价与批准拆成两个接口;所有写操作带幂等键,重放返回原回执。
最终产物:55 条接口,按业务领域分成 7 组,和 ER 图里的表域一一对应(每组标出它主要读写的表)。原有 40,调整 6,新增 9;「状态」列只标明它相对原设计是否变化。
用户领域 11 项目与会话领域 7 Agent 交互领域 9 画布与时间轴领域 11 生成与报价批准领域 7 素材领域 6 开放平台与能力 4
用户领域 · 11 条 谁在用、怎么付费:登录与成员、API Key、支付、订阅、积分、用量
谁在用、怎么付费:登录与成员、API Key、支付、订阅、积分、用量。读写的表:org、app_user、session_token、plan、workspace、member、api_key、generation_task、ledger_account、ledger_entry、point_lot、hold、quota_window、approval_policy、subscription、purchase_order、payment_event
| 方法 路径 | 说明 | 鉴权 scope | 状态 |
|---|---|---|---|
| 身份与成员 | |||
POST /auth/login · /auth/refresh · /auth/logout | 登录、刷新、登出 | — | 原有 |
GET /me | 用户 + 当前工作区 + 权益 | user | 原有 |
GET/POST /workspaces/{id}/members | 成员管理 | admin | 原有 |
GET/POST/DELETE /api-keys | API Key 管理 | admin | 原有 |
| 支付 · 订阅 · 积分 | |||
GET /billing/balance | 余额、冻结、即将过期 | billing:read | 原有 |
GET /workspaces/{id}/admission | 发送前准入:额度/积分是否够用、原因、下一步(购买/升级/打开额外用量) | billing:read | 新增 |
GET /billing/ledger | 明细(可导出 CSV) | billing:read | 原有 |
POST /billing/checkout | 创建支付会话(订阅/积分包) | billing:write | 原有 |
POST /billing/portal | 订阅管理入口 | billing:write | 原有 |
POST /webhooks/stripe · /webhooks/wechatpay | 支付回调(验签) | — | 原有 |
GET /billing/usage?group_by=model|member|project | 用量报表 | billing:read | 原有 |
项目与会话领域 · 7 条 项目是一份文档;会话挂在项目下;创作意图从不同入口汇入
项目是一份文档;会话挂在项目下;创作意图从不同入口汇入。读写的表:workspace、project、node、edge、intent、agent_session、agent_run、interaction、skill、skill_version
| 方法 路径 | 说明 | 鉴权 scope | 状态 |
|---|---|---|---|
| 项目 | |||
POST /projects | 新建项目(可带 kind、输入) | project:write | 原有 |
POST /intents | 创建创作意图:adapter + source_ref(URL、商品、脚本、参考视频) | project:write | 新增 |
GET /projects?cursor= | 列表 | project:read | 原有 |
GET /projects/{id} | 详情 + 画布快照(节点、边) | project:read | 原有 |
PATCH /projects/{id} | 改标题/比例/语言 | project:write | 原有 |
| 会话 | |||
POST /projects/{id}/sessions | 创建会话(选 skill) | agent:write | 原有 |
GET /projects/{id}/sessions | 会话列表(历史):按 last_message_at 倒序,q 搜索标题;每项带 active_run {id, status} 与 needs_action(等用户回答卡片或充值时为 true) | agent:read | 新增 |
⭕ Agent 交互领域 · 9 条 发消息、事件流、停止、澄清卡片、技能
发消息、事件流、停止、澄清卡片、技能。读写的表:agent_session、agent_message、agent_run、run_event、interaction、run_action、skill、skill_version
| 方法 路径 | 说明 | 鉴权 scope | 状态 |
|---|---|---|---|
| 运行与交互 | |||
GET /sessions/{id} | 打开或刷新会话:返回会话、最近 50 条消息、进行中的 run(状态、last_seq、计划、未关闭的卡片);前端先按它渲染,再从 last_seq 接事件流 | agent:read | 新增 |
GET /sessions/{id}/messages | 向上翻历史:before=<message_id>&limit≤50,按时间倒序 | agent:read | 新增 |
POST /sessions/{id}/messages | 请求头 / body 带 client_action_id;返回 202 + run_id;同 ID 不同内容 409 | agent:write | 调整 |
GET /sessions/{id}/events (SSE) | 事件流,支持 Last-Event-ID | agent:read | 原有 |
GET /runs/{id} | run 状态 | agent:read | 原有 |
POST /runs/{id}:stop | 幂等停止;回执 status=terminal_observed | unknown;已输出的文字保存为一条 status=stopped 的助手消息;不承诺供应商侧已取消计费 | agent:write | 调整 |
POST /interactions/{id}:respond | 带 card_sha256;答案按卡片 schema 校验;已恢复过的卡再提交返回原回执 | agent:write | 调整 |
| 技能 | |||
GET /skills · GET /skills/{id} | 可用 Skill | agent:read | 原有 |
POST /skills (发布,开发者) | 上传 Skill 包 | skill:publish | 原有 |
画布与时间轴领域 · 11 条 节点与边、批量变更、版本、时间线、导出
节点与边、批量变更、版本、时间线、导出。读写的表:project、node、node_version、edge、timeline、timeline_version、export_job、asset、hold
| 方法 路径 | 说明 | 鉴权 scope | 状态 |
|---|---|---|---|
| 节点、边与版本 | |||
POST /projects/{id}/nodes | 创建节点 | project:write | 原有 |
PATCH /nodes/{id} | 更新节点(If-Match) | project:write | 原有 |
POST /projects/{id}/graph:patch | 批量变更节点/边(画布拖拽、Agent 写入) | project:write | 原有 |
GET /nodes/{id}/versions | 版本历史 | project:read | 原有 |
POST /nodes/{id}/versions/{v}:restore | 回滚 | project:write | 原有 |
| 时间轴与导出 | |||
GET/PUT /projects/{id}/timeline | 读写(If-Match) | project:write | 原有 |
GET /timelines/{id}/versions | 时间线版本历史(每次保存一条) | project:read | 新增 |
POST /timelines/{id}/versions/{v}:restore | 恢复到某个版本:以旧内容新建一个版本,不覆盖历史 | project:write | 新增 |
POST /timelines/{id}/exports | 导出 | export:write | 原有 |
GET /exports/{id} | 导出状态 | export:read | 原有 |
POST /timelines/{id}/preview-proxy | 生成低码率预览代理 | export:write | 原有 |
生成与报价批准领域 · 7 条 先报价再批准、生成任务、模型目录与价格
先报价再批准、生成任务、模型目录与价格。读写的表:model_catalog、model_version、price_rule、generation_quote、generation_approval、generation_task、task_attempt、ledger_entry、point_lot、hold、quota_window、approval_policy
| 方法 路径 | 说明 | 鉴权 scope | 状态 |
|---|---|---|---|
POST /generations | 批准并创建任务:body 带 quote_id、client_approval_id、两个哈希;重放返回同一任务;报价过期返回 409 quote_expired | generate:write | 调整 |
POST /generations:quote | 报价,不扣费;返回 quote_id、request_sha256、quote_sha256、expires_at | generate:read | 调整 |
GET /generations/{id} | 查询任务 | generate:read | 原有 |
POST /generations/{id}:cancel | 取消 | generate:write | 原有 |
GET /generations?project_id=&status= | 列表 | generate:read | 原有 |
PUT /workspaces/{id}/approval-policy | Ask First / Always Allow(带单次与每日上限) | generate:write | 新增 |
GET /models?capability= | 模型清单:版本、约束、价格表(来自 model_version) | generate:read | 调整 |
素材领域 · 6 条 上传、检索、采集、角色
上传、检索、采集、角色。读写的表:project_asset_ref、asset、asset_embedding、retrieval_seen
| 方法 路径 | 说明 | 鉴权 scope | 状态 |
|---|---|---|---|
POST /assets:init-upload | 获取预签名直传 URL | asset:write | 原有 |
POST /assets/{id}:complete | 确认上传完成,触发解析 | asset:write | 原有 |
GET /assets · /assets/{id} | 查询 | asset:read | 原有 |
POST /assets:search | 语义/混合检索(含 context_key 去重) | asset:read | 原有 |
POST /collections:from-url | 链接采集(商品/视频) | asset:write | 原有 |
POST /characters | 创建角色(形象 + 声音) | asset:write | 原有 |
开放平台与能力 · 4 条 Webhook 注册、MCP、OpenAPI、能力注册表
Webhook 注册、MCP、OpenAPI、能力注册表。读写的表:api_key、skill、model_catalog、outbox、webhook_endpoint
| 方法 路径 | 说明 | 鉴权 scope | 状态 |
|---|---|---|---|
POST /webhook-endpoints | 注册回调 | admin | 原有 |
MCP: https://mcp.lumen.example/ | MCP Server(Streamable HTTP) | OAuth2 / API Key | 原有 |
GET /openapi.json | OpenAPI 3.1 | — | 原有 |
GET /capabilities | 能力注册表:每项能力状态(可用/灰度/未接入),界面只渲染可用项 | user | 新增 |
- 先报价后批准是两个接口:用户看到的价格就是被批准的价格。
- 每个写动作都有幂等键:前端可以放心重试,后端不会产生第二次副作用。
- 内外同一套工具面:界面能做的,外部 Agent 通过 MCP 也能做,鉴权、审批、计费完全一致。
- 按领域分组:每组对应一组表和一支小团队,接口与表同进同出,新增能力时知道往哪里放。
本页涉及的决策
D2 先报价,再批准,批准带哈希 · D5 缺信息时用结构化澄清卡 · D8 事件流带游标,可停止、可恢复 · D13 修订可恢复 · D14 能力对内外一致:Agent、API、MCP 用同一套工具面 · D15 不展示做不到的功能 (借鉴来源与原因见“设计取舍与原因”)
通用约定、错误模型与核心接口详解(已按最终规则改写,与上表一致)
5.1 通用约定
| 项 | 约定 |
|---|---|
| Base URL | https://api.lumen.example/v1(国内 api.cn.lumen.example) |
| 鉴权 | Web:Authorization: Bearer <JWT>(15 分钟)+ Refresh Cookie;开放 API:Authorization: Bearer lm_sk_...(API Key,scope 限定) |
| 幂等 | 所有写动作都带客户端生成的幂等标识:发消息和 Run 动作用 client_action_id,批准用 client_approval_id,报价用 client_request_id;其余创建类 POST 用 Idempotency-Key(24h)。同标识同内容返回首次结果,同标识不同内容返回 409 idempotency_conflict |
| ID | 库里存 26 位 ULID,接口层加资源前缀:prj_ nod_ tsk_ run_ ast_ ord_ ses_ itx_ qte_ exp_ mdl_ req_ |
| 时间/金额 | RFC 3339 UTC;积分字段 *_centi 整数;API 同时给 points 展示值(字符串,2 位小数) |
| 分页 | 游标:?limit=50&cursor=... → {items, next_cursor} |
| 并发控制 | 单个资源的更新(PATCH /nodes、PUT /projects/{id}/timeline)用 If-Match: <version>,不匹配返回 412 version_mismatch;批量图变更用请求体里的 base_version(就是 project.doc_version)和每个节点的 if_ver,冲突返回 409 state_conflict 并列出冲突节点 |
| 限流 | 响应头 X-RateLimit-Limit/Remaining/Reset;超限 429 + Retry-After |
| Webhook | X-Lumen-Signature: t=...,v1=HMAC_SHA256(secret, t.body),失败指数退避 8 次(最长 24h) |
错误模型
HTTP 4xx/5xx
{
"error": {
"code": "insufficient_points", // 稳定的机器可读码,调用方只判断 code
"message": "Insufficient points.", // 人读,按 Accept-Language 本地化
"details": {"required_centi": 12000, "available_centi": 3000},
"request_id": "req_01J..."
}
}
| HTTP | code | 含义 / 客户端动作 |
|---|---|---|
| 400 | invalid_argument | 参数校验失败,details 含字段 |
| 401 | unauthenticated / token_expired | 刷新 token 或重新登录 |
| 402 | insufficient_points | 引导充值 |
| 403 | forbidden / content_rejected / region_blocked | 无权限 / 审核拒绝 |
| 404 | not_found | — |
| 409 | idempotency_conflict / run_busy / state_conflict / quote_expired | run_busy:会话已有活跃 run;quote_expired:报价过期,不建任务、不扣费,重新报价;state_conflict:乐观锁冲突、卡片或报价与当前不一致 |
| 412 | version_mismatch | 重新拉取再合并 |
| 422 | unsupported_combination | 模型不支持该参数组合,details 给出可选项 |
| 429 | rate_limited / quota_exceeded | 退避重试 |
| 503 | provider_unavailable / overloaded | 可重试(幂等安全) |
5.3 核心接口详解
5.3.1 POST /generations:quote 与 POST /generations — 先报价,再批准
POST /v1/generations:quote
{
"client_request_id": "c-52ad",
"capability": "i2v",
"project_id": "prj_01J...", // 可选,挂到项目/节点
"node_id": "nod_01J...",
"input": { "prompt": "A bottle on a marble table, slow push-in", "duration_s": 5, "aspect_ratio": "9:16", "resolution": "1080p" },
"model": {"mode": "auto", "quality": "standard"}, // 或 {"mode":"fixed","id":"mdl_..."}
"source": {"run_id": "run_01J..."} // 可选:来自 Agent 回复时带上
}
200 { "quote_id": "qte_01J...", "request_sha256": "…", "quote_sha256": "…",
"model": {"id": "mdl_01J...", "version": "v1"}, "quoted_centi": 15000, "points": "150.00",
"expires_at": "2026-10-19T10:05:00Z" } // 不扣费;输入审核和模型路由在这一步完成
POST /v1/generations
{ "quote_id": "qte_01J...", "client_approval_id": "c-9a10", "request_sha256": "…", "quote_sha256": "…" }
201 Created
{ "id": "tsk_01J...", "status": "queued", "quoted_centi": 15000, "links": {"self": "/v1/generations/tsk_01J...", "events": "/v1/generations/tsk_01J.../events"} }
同一个 (quote_id, client_approval_id) 重放 → 返回同一个任务,不会重复扣费
409 quote_expired 报价过期:不建任务、不扣费,重新报价
409 state_conflict 请求或价格与报价不一致(哈希不符)
402 insufficient_points {"required_centi":15000,"available_centi":3000}
403 content_rejected {"category":"violence","field":"input.prompt"}
422 unsupported_combination {"field":"input.duration_s","allowed":[5,8,10]}
语义:批准时在一个本地事务内完成 ① 校验报价未过期、两个哈希一致 ② 冻结积分 ③ 写 generation_approval、generation_task 与 outbox ④ 通过 outbox 异步启动 Temporal 工作流(保证不丢)。用户看到的价格和提示词,就是被批准、被执行的那一份。
5.3.2 GET /generations/{id} — 查询
200
{
"id":"tsk_01J...", "status":"succeeded",
"outputs":[{"asset_id":"ast_01J...","type":"video","url":"https://cdn.../a.mp4?sig=..","duration_s":5,"width":1080,"height":1920}],
"charged_centi":15000,
"created_at":"2026-10-11T08:00:00Z","finished_at":"2026-10-11T08:01:34Z",
"error":null,
"attempts":[{"seq":1,"model":"Seedance 2.5","status":"succeeded"}],
"quote_id":"qte_01J..." // 这个任务是由哪份报价批准出来的
}
5.3.3 POST /sessions/{id}/messages — 向 Agent 发消息
POST /v1/sessions/ses_01J.../messages
{
"client_action_id": "c-31ab",
"content": [
{"type":"text","text":"用这个商品做 3 条 15 秒的 TikTok 广告,风格偏 ASMR"},
{"type":"url","url":"https://shop.example.com/p/123"},
{"type":"asset","asset_id":"ast_01J..."}
]
}
202 Accepted
{"run_id":"run_01J...","mode":"new_run"} // new_run | guidance;消息永远不会恢复一个等待中的 run
状态规则(沿用旧网关的规则;本方案没有重新验证):
- 会话空闲 → 新建 run
- run 运行中 → 作为 guidance 追加给当前 run(mode=guidance)
- run 等待交互且收到普通消息 → 取消旧 run,新建 run
- 只有 interactions/{id}:respond 才恢复同一个 run
409 run_busy:guidance 通道被关闭(run 正在收尾)时返回,客户端稍后重试
同一个 client_action_id 内容不同 → 409。消息不能附带“自动批准”:花积分只能走“报价 → 批准”。要免确认,只能由用户在工作区里开启审批策略(approval_policy,Always Allow,限额度内,仍写账本)。
5.3.4 GET /sessions/{id}/events — SSE
GET /v1/sessions/ses_01J.../events?from_seq=120
Accept: text/event-stream
Last-Event-ID: run_01J...:120
id: run_01J...:121
event: assistant.delta
data: {"run_id":"run_01J...","seq":121,"text":"我先分析商品页面…"}
id: run_01J...:130
event: node.created
data: {"seq":130,"node":{"id":"nod_01J...","type":"script","data":{...}},"graph_version":42}
id: run_01J...:135
event: interaction.requested
data: {"seq":135,"interaction":{"id":"itx_01J...","kind":"collect_info","card_sha256":"…",
"title":"需要补充商品信息","schema":{"fields":[{"key":"product_name","kind":"input","label":"商品名称","required":true}]},
"expires_at":"2026-10-11T09:00:00Z"}} // 答案用 :respond 提交,必须带这个 card_sha256
: heartbeat (每 15s)
断线续传:服务端按 (run_id, seq) 从 PG 热分区补读;Redis Stream 仅作低延迟提示。事件顺序以 seq 为准,客户端去重。
5.3.5 POST /interactions/{id}:respond
POST /v1/interactions/itx_01J...:respond
{ "client_action_id": "c-9f3e", "card_sha256": "…", "action": "submit", "values": {"product_name": "不锈钢保温杯"} }
200 {"status":"resolved","run_id":"run_01J..."}
同 client_action_id 重放 → 200 返回同样结果;同 id 不同内容 → 409 state_conflict
卡片哈希与当前卡不一致(卡已更新)→ 409 state_conflict,不提交旧答案
action="cancel" → 取消这一轮
答案按卡片 schema 校验(必填、选项取值);已经恢复过的卡再提交,返回原回执,不会恢复两次。只有这个接口能恢复同一个 run。
5.3.6 POST /projects/{id}/graph:patch — 批量图变更
{
"base_version": 41,
"ops": [
{"op":"add_node","temp_id":"t1","type":"shot","parent_id":"nod_scene1","data":{"prompt":"..."},"pos":{"x":120,"y":80}},
{"op":"update_node","id":"nod_02","if_ver":3,"data":{"prompt":"new"}},
{"op":"add_edge","src":"nod_01","dst":"t1","kind":"data"},
{"op":"delete_node","id":"nod_09"}
]
}
200 {"graph_version":42,"id_map":{"t1":"nod_01J..."},"stale_nodes":["nod_05"]}
409 state_conflict {"conflicts":[{"id":"nod_02","server_ver":4}]} // 乐观锁失败,客户端 rebase
base_version 与响应里的 graph_version 都是 project.doc_version;if_ver 对应 node.current_ver。
5.3.7 POST /assets:search
{
"query": "close-up of hands applying serum, soft light",
"kinds": ["video"],
"filters": {"duration_s": {"lte": 8}, "tags_any": ["beauty"]},
"scope": ["workspace","library"],
"context_key": "prj_01J...:scene3", // 同 key 下已返回过的素材不再返回
"top_k": 8
}
200 {"items":[{"asset_id":"ast_..","score":0.82,"segment":{"start_ms":1200,"end_ms":4200},"url":"..."}]}
5.4 内部接口(core ↔ model-gateway,gRPC)
service ModelGateway {
rpc Route(RouteRequest) returns (RouteDecision); // 能力 → 模型 + 版本 + 价格(报价写入 generation_quote)
rpc Submit(SubmitRequest) returns (SubmitResponse); // 幂等键 = task_id + attempt_seq
rpc Query(QueryRequest) returns (QueryResponse); // 按 provider_task_id 或 idempotency
rpc Cancel(CancelRequest) returns (CancelResponse);
rpc ListModels(ListModelsRequest) returns (ListModelsResponse);
}
message SubmitRequest {
string task_id = 1; int32 attempt_seq = 2; string model_id = 3; string model_version_id = 8; // 必须是报价时的版本
google.protobuf.Struct input = 4; repeated AssetRef refs = 5; // 网关负责把 asset 转成供应商可访问 URL
string callback_url = 6; int64 deadline_unix = 7;
}
enum SubmitOutcome { ACCEPTED = 0; REJECTED = 1; UNCERTAIN = 2; } // UNCERTAIN: 超时/断连,无法确认供应商是否受理
5.5 Webhook 事件
| type | 触发 | data 关键字段 |
|---|---|---|
| generation.succeeded / failed / cancelled | 任务终态 | task、outputs、charged_centi、error |
| export.succeeded / failed / cancelled | 导出终态 | export、asset |
| run.waiting_user | Agent 需要用户 | interaction |
| billing.low_balance | 余额低于阈值 | available_centi、threshold |
| subscription.renewed / past_due | 订阅事件 | subscription |
5.6 Agent 事件类型
| type | 说明 | 持久化 |
|---|---|---|
| run.started / run.succeeded / run.failed / run.cancelled | 生命周期,状态变更与事件同事务 | 是 |
| assistant.delta / assistant.message | 对话流式文本 | delta 否 / message 是 |
| plan.updated | Todo/计划变化 | 是 |
| tool.started / tool.completed / tool.failed | 工具调用生命周期 | 是 |
| node.created / node.updated / node.deleted | 画布变更(带 graph_version) | 是 |
| task.progress / task.completed / task.failed | 生成任务进度与终态(来自 generation 事件) | 是 |
| interaction.requested / interaction.resolved / interaction.expired | HITL | 是 |
| budget.warning | 预算接近上限 | 是 |
5.7 MCP 工具面(对内外一致)
| 工具 | 入参要点 | 说明 |
|---|---|---|
| lumen_create_project | kind, title, inputs | — |
| lumen_generate_video | prompt, refs, duration, model | 默认只报价(返回 quote_id 与两个哈希);带 quote_id 与 client_approval_id 才创建任务 |
| lumen_get_task | task_id | — |
| lumen_search_assets | query, context_key | — |
| lumen_collect_url | url | 采集商品/视频 |
| lumen_edit_timeline | ops[] | 结构化修改时间线 |
| lumen_export | timeline_id, preset | — |
| lumen_get_balance | — | — |
| lumen_get_admission | workspace_id | 发送前准入:额度、积分是否够用 |
| lumen_send_message | session_id, content, client_action_id | 发消息,返回 run_id |
| lumen_stop_run | run_id, client_action_id | 幂等停止 |
| lumen_respond_interaction | interaction_id, card_sha256, values | 回答澄清卡,恢复同一个 run |
client_*_id 或 idempotency_key);成本类工具遵循"先报价后批准",批准要带 quote_id,防止外部 Agent 无意识烧积分。最终设计 · 设计取舍与原因
- 17 条决策里标 核心 的 4 条是地基,落地时不能妥协:D1 共用文档、D2 报价批准、D3 复式账本、D17 共享内核。
- 其余决策可以按“落地指南”的阶段逐步做。
每一条都回答三个问题:借鉴了谁、我们怎么做、为什么这样更好。借鉴来源来自我们对七个竞品的调研和复刻时亲手跑过的结果,不是想象。
| # | 决策 | 为什么好(一句话) |
|---|---|---|
| D1 | 一个项目、三种视图共用一份文档 核心 | 竞品里「对话产物」和「可编辑对象」常常是两套数据,用户改了画布,Agent 不知道;改了对话,画布不变。 |
| D2 | 先报价,再批准,批准带哈希 核心 | LibTV 的预算只在达到阈值时提醒,不阻止下一笔扣费,用户仍可能超支;我们把批准做成硬门槛。 |
| D3 | 积分用复式账本,先冻结再结算 核心 | 竞品只暴露余额数字,对账和退款难以解释。 |
| D4 | 文字推理成本和媒体成本分开显示 | 用户最怕的是不知道哪一步在花钱。 |
| D5 | 缺信息时用结构化澄清卡 | 把一串问题写进聊天段落,无法做必填校验,也没法在断线后恢复。 |
| D6 | 方案是结构化实体,不是一大段文字 | 整段文字改一处就要整体重写,容易误伤已满意的镜头。 |
| D7 | 发送前就说明准入条件 | 失败在发送之后才出现,用户会反复重试。 |
| D8 | 事件流带游标,可停止、可恢复 | 长回复和长任务一定会遇到断线、刷新、重复点击。 |
| D9 | Skill 与模板有版本,会话固定绑定版本 | 没有版本,同一个 Skill 今天和明天表现不同,问题无法复现;固定版本后可复现、可回滚,社区发布也有了安全边界。 |
| D10 | 模型靠注册表和适配器接入 | 新增一个模型要改核心代码、重新编译、重启服务,是复刻里最大的扩展障碍。 |
| D11 | 不同入口汇成同一个「创作意图」 | 入口多是竞品的增长手段,但内核不应该重复实现。 |
| D12 | 素材归用户,项目只引用 | 素材被项目复制会产生所有权和删除纠纷;只引用则复用方便、权限清楚,删除素材前可以查到还有哪些项目在用。 |
| D13 | 修订可恢复 | 创作工具里最痛的是改坏了回不去。 |
| D14 | 能力对内外一致:Agent、API、MCP 用同一套工具面 | 多套接口会出现「界面能做、API 不能做」或相反,还要分别做计费和审计。 |
| D15 | 不展示做不到的功能 | 假按钮会消耗用户信任,也会把「没做」误当成「做了但坏了」。 |
| D16 | 登录与会话状态要有可见入口 | 用户遇到的第一个问题往往是「怎么登录」和「为什么突然不能用了」。 |
| D17 | 一个共享内核加品牌配置,而不是七套代码 核心 | 我们的实测是:七个产品的后端结构几乎一致,区别在入口、模板和视觉。 |
展开完整版:借鉴来源、我们的做法、完整原因
| # | 决策 | 借鉴来源 | 我们的做法 | 为什么好 | 对应章节 |
|---|---|---|---|---|---|
| D1 | 一个项目、三种视图共用一份文档 | TopView 同一项目双编辑模式;LibTV 画布+故事板+Agent;Flova 画布/分镜/时间轴;invideo Agent 到编辑器 | 对话、画布、时间线都读写同一份项目文档(project.doc_version 乐观锁,node/edge/timeline 为其结构化投影)。Agent 的产出落成节点,而不是留在聊天记录里。 | 竞品里「对话产物」和「可编辑对象」常常是两套数据,用户改了画布,Agent 不知道;改了对话,画布不变。共用一份文档后,Agent 可以只改第 2 个镜头,撤销、版本、协作都只实现一次。 | 总览与架构 · ER 图 |
| D2 | 先报价,再批准,批准带哈希 | 我们复刻中跑通的流程;TopView 的 Ask First / Always Allow;LibTV 的预算阈值只提醒 | 生成前先给报价(含有效期),批准时必须带请求哈希和报价哈希;服务端重放同一个批准只返回同一个任务。「始终允许」只能在额度内由用户明确打开,并且仍写账本。 | LibTV 的预算只在达到阈值时提醒,不阻止下一笔扣费,用户仍可能超支;我们把批准做成硬门槛。哈希绑定让「用户看到的价格和提示词」与「实际执行的」不可能不一致,也防重复点击重复扣费。真实测试里报价过期后批准被拒,没有建任务也没有扣费。 | Agent 交互 · 接口清单 |
| D3 | 积分用复式账本,先冻结再结算 | 各家都有积分/额度;CreaTok 有每日额度和额外用量;Pollo 显示余额 | 充值、赠送、冻结、结算、释放都是账本分录,只追加,用触发器禁止修改;任务明确失败时释放冻结,状态无法确认时保持冻结并告警(原设计的 GN-05)。额度(日额度、套餐额度)与积分分开建模。 | 竞品只暴露余额数字,对账和退款难以解释。复式账本让每一分都有来源和去向,失败任务不会吞积分;额度与积分分开,才能表达「额度用完后按用量扣积分」。 | 表结构 · ER 图 |
| D4 | 文字推理成本和媒体成本分开显示 | LibTV TV Director:推理实时耗积分,素材生成另计 | 界面和账本都区分「对话/推理用量」与「媒体生成」(账本分录 ref_type=run 记推理,ref_type=task 记生成),对话前显示当前模型倍率,不把文字对话标成免费。 | 用户最怕的是不知道哪一步在花钱。分开显示让「聊一聊」和「真的生成」边界清楚,也方便给文字对话单独设上限。 | Agent 交互 |
| D5 | 缺信息时用结构化澄清卡 | CreaTok:4 题表单、一题一页、可回退,回答后继续原任务(已真实跑通两轮) | 运行进入 waiting_user(Agent Run 的等待状态),下发带 ID 的卡片(必填/可选、单选/文本);用户提交时带卡片哈希;服务端验证状态后恢复同一个 Run;重复提交不会恢复两次。 | 把一串问题写进聊天段落,无法做必填校验,也没法在断线后恢复。卡片是一个有状态的对象:刷新后仍在、过期有明确状态、答案可校验。 | Agent 交互 · ER 图 |
| D6 | 方案是结构化实体,不是一大段文字 | CreaTok:3 镜头表格,自然语言只改第 2 镜头,其他镜头保持 | 方案落成节点:storyboard → scene → shot(node 表,type=shot),每个镜头有稳定的 node id、时长、画面、对白、字幕、转场;修改只产生新的 node_version,旧版本保留可对比。 | 整段文字改一处就要整体重写,容易误伤已满意的镜头。有稳定键才能做局部重生成、对比和只对改动的镜头重新计费。 | Agent 交互 · 表结构 |
| D7 | 发送前就说明准入条件 | Flova:积分不足时发送前就提示并给购买入口 | 输入框旁实时显示额度/积分是否够用、原因和下一步;不够用时不让用户白白等待一轮再失败。 | 失败在发送之后才出现,用户会反复重试。提前说明一次,既少一次无效请求,也少一次无效体验。 | Agent 交互 |
| D8 | 事件流带游标,可停止、可恢复 | Pollo 的流式事件;我们复刻里的游标轮询、停止回执、刷新后恢复 | 每个 Run 的事件有递增序号;客户端断线后用序号续读;停止是幂等动作,回执只声明「已观测到终态」,不承诺供应商已取消计费;停止后对话里保留「已停止」标记。 | 长回复和长任务一定会遇到断线、刷新、重复点击。序号让续读不丢不重;幂等停止让重复点击安全;诚实的回执避免把「已停止」说成「不收费」。我们在复刻里还修了一个停止按钮从不发请求的缺陷,说明这条路径必须有端到端测试。 | Agent 交互 · 接口清单 |
| D9 | Skill 与模板有版本,会话固定绑定版本 | LibTV 的 Skill 社区与固定版本绑定会话;Pollo 的 63 个技能和模板库 | skill 与 skill_version 分开;会话创建时记录所用版本;发布新版本不影响进行中的会话。 | 没有版本,同一个 Skill 今天和明天表现不同,问题无法复现;固定版本后可复现、可回滚,社区发布也有了安全边界。 | 总览与架构 · 表结构 |
| D10 | 模型靠注册表和适配器接入 | Pollo/LibTV/TopView 的多模型矩阵;我们在复刻里发现后端把单个模型写死在代码和 worker 配置里,并已按这个方向改成:模型登记为数据、白名单由环境变量扩展、每个模型一个独立 worker;四个模型真实出片 | model_catalog + model_version(含价格表、时长/画幅/分辨率约束、adapter_key)放在数据里;适配器按 adapter_key 注册;每个模型有自己的路由与限流。 | 新增一个模型要改核心代码、重新编译、重启服务,是复刻里最大的扩展障碍。把模型变成数据加适配器,新增模型只是加一行配置加一个适配器,核心不动,也能按模型灰度和下线。 | 总览与架构 · 表结构 |
| D11 | 不同入口汇成同一个「创作意图」 | Creatify 的 URL→视频;Pollo 的营销批量;TopView 的商品链接广告;爆款复刻 | 入口适配器(URL、商品、脚本、参考视频)把输入统一成 intent,后面的计划、报价、生成、导出走同一条链。 | 入口多是竞品的增长手段,但内核不应该重复实现。统一成 intent 后,新增一个入口只写适配器,计费、审批、恢复全部复用。 | 总览与架构 · Agent 交互 |
| D12 | 素材归用户,项目只引用 | Pollo / LibTV 的个人素材库、团队复制 | asset 属于工作区(个人空间也是一个工作区);项目通过 project_asset_ref 只记引用和用途,所以项目与素材是多对多;不复制素材。 | 素材被项目复制会产生所有权和删除纠纷;只引用则复用方便、权限清楚,删除素材前可以查到还有哪些项目在用。 | 表结构 · ER 图 |
| D13 | 修订可恢复 | Flova 文档版本;invideo 历史审阅 | 节点每次修改写一条 node_version,时间线每次保存写一条 timeline_version;恢复是以旧内容新建一个版本,不覆盖历史;导出记录所用的时间线版本(export_job.timeline_ver)。 | 创作工具里最痛的是改坏了回不去。恢复成新修订让历史不被改写,导出绑定修订则保证「导出的就是看到的」。 | 表结构 · 接口清单 |
| D14 | 能力对内外一致:Agent、API、MCP 用同一套工具面 | TopView / Pollo 的 MCP 与 CLI;Flova、CreaTok 的 CLI | 平台内部 Agent 调用的工具,就是对外 MCP/API 暴露的工具;同样的鉴权、同样的审批和计费。 | 多套接口会出现「界面能做、API 不能做」或相反,还要分别做计费和审计。一套工具面让外部 Agent 接入几乎零成本,也只需测试一次。 | 接口清单 |
| D15 | 不展示做不到的功能 | 我们复刻中的做法:Tools 页没有后端的工具标注「未接入」,不提供可点击的创建 | 能力注册表(GET /capabilities,由 model_catalog.status、skill.status 和配置里登记的“未接入”能力合成)里每项能力有状态(可用/灰度/未接入);界面只渲染可用能力,其余明确标注。 | 假按钮会消耗用户信任,也会把「没做」误当成「做了但坏了」。诚实标注让缺口可见,排期也有依据。 | 总览与架构 |
| D16 | 登录与会话状态要有可见入口 | 我们在复刻里发现:未登录页面没有登录入口,会话过期也无提示 | 页面始终有登录/账号入口;会话过期时顶部提示并保留当前上下文,重新登录后恢复。 | 用户遇到的第一个问题往往是「怎么登录」和「为什么突然不能用了」。把状态说出来,比让用户从失败的发送里猜要好得多。 | Agent 交互 |
| D17 | 一个共享内核加品牌配置,而不是七套代码 | 七个复刻共用同一套 24 张表、55 个接口,只在前端令牌和少量入口上不同 | 数据库按 workspace 隔离;品牌差异放在配置与前端令牌里(颜色、入口、模板、模型清单)。 | 我们的实测是:七个产品的后端结构几乎一致,区别在入口、模板和视觉。把差异收敛到配置,维护成本是一份,而不是七份。 | 总览与架构 · 表结构 |
我们明确没有照搬的
- 只提醒的预算阈值(LibTV):达到阈值提醒不等于阻止下一笔扣费。我们要的是硬上限。
- 文字对话标成免费:竞品的官方说明里推理实时消耗积分。我们把对话与媒体成本分开展示,不承诺免费。
- 没有后端的工具也放一个创建按钮:我们在复刻里把这类工具标成「未接入」,不提供可点击的创建。
- 每个品牌一套代码:七个复刻共用一套后端,品牌差异只放在配置与前端令牌里。
最终设计的边界
- 逐条核对见“一页读懂 → 技术方案自审”:17 条里 7 条已在测试部署上验证,5 条部分验证。D5(澄清卡)在 Pollo 测试部署上走通,目前只支持“商品名称”一种卡。
- D10:模型登记已改成数据加环境变量,新增模型不改代码;Seedance 2.0、2.0 Fast、2.0 Mini、2.5 真实出片;Seedance 1.5 Pro 在当前密钥下被供应商拒绝,原因不明。
- 最终 DDL(46 张表)已在真实 PostgreSQL 16 上整体执行成功,并读回结构生成 ER 图与表结构;向量列在本机验证时用数组类型代替,分区表在大数据量下的表现没有测。复刻后端用的是 MySQL,和最终设计的表结构不是同一套。
- 失败后自动释放冻结是设计目标;复刻里供应商已受理后失败的任务保持冻结、标“费用待核对”,释放分录还没有真实出现过。
- 最终接口清单是设计稿,没有实现成服务;只有与复刻重合的接口在复刻里测过。
最终设计 · 落地指南
- 第一版只做一条主线:一句话需求 → Agent 出镜头方案 → 报价 → 批准 → 生成 → 交付;每一步能停止、能恢复、不重复扣费。
- 产品先拍板 6 件事(定价与免费额度等),上线后再改代价很大,见下表。
- 技术按 P0 地基开始:身份、项目文档、积分账本、素材归属;每个阶段都有可写成测试的验收标准。
给马上要开发的同事:产品看“做什么、先拍板什么、怎么验收”,技术看“按什么顺序做、复用什么、哪里踩过坑”。结论来自七个竞品的复刻和实测;没有实测过的地方,在验收表和最后一节单独标出。
产品:第一版只做这条主线
一句话需求 → Agent 出镜头方案 → 报价 → 用户批准 → 生成 → 交付与下载。这条线上每一步都要能停止、能恢复、不重复扣费。其余先不做:
| 第一版做 | 第二版再做 | 明确不做 |
|---|---|---|
| 一个入口(Agent 对话);一个官方技能并固定版本;镜头表可局部修改;先报价再批准;积分账本;3 个模型;停止与刷新恢复 | 多入口(URL / 商品链接 / 参考视频);澄清卡;开发者发布技能与模板;图片附件;团队与素材库 | 把文字对话标成免费;只提醒不拦截的预算;每个品牌一套代码;没有后端的工具放可点按钮 |
产品要先拍板的 6 件事
| 决策 | 为什么要早定 | 我们的建议 |
|---|---|---|
| 积分定价与免费额度 | 决定账本里“额度”和“积分”怎么分;上线后改很贵 | 日额度和积分分开;首版只给新用户一次性赠送 |
| 是否提供“始终允许” | 影响批准流程与风控 | 首版只开放“每次先问”;approval_policy 表和接口保留,以后开“始终允许”时只能在额度内、用户显式打开、仍写账本 |
| 首发模型清单与价格 | 每个模型要有独立价格表、时长/画幅限制和灰度开关 | 3 个:快/标准/高质;价格放数据,不写代码 |
| 内容审核与版权口径 | 生成前后都要有拦截点;影响提示词与产出的存储 | 提交前过审核;产出保留审核结果;明确素材归属 |
| 入口优先级 | 每个入口只是一个适配器,但要排期 | 先 URL→视频(最短路径),再商品、参考视频 |
| 失败后积分策略 | 供应商失败后是否自动退还,要产品给口径 | 先冻结后结算;失败默认释放;供应商状态不明时标“待核对”,人工处理 |
验收标准(每条都能写成测试)
| 场景 | 期望结果 | 在复刻里验证过吗 |
|---|---|---|
| 同一个批准点两次 | 只创建一个任务,只扣一次 | 已验证(批准带请求哈希与报价哈希) |
| 报价过期后批准 | 被拒绝;不建任务,不扣费;界面说明“报价已过期” | 已验证 |
| 生成失败 | 设计目标:供应商明确返回失败时释放冻结;状态无法确认(提交结果未知,或失败但没有原因)时保持冻结,显示“费用待核对”,人工处理 | “待核对”分支已验证(Seedance 1.5 Pro 两次失败且无原因,冻结保留);自动释放分支在复刻里没出现过,未验证 |
| 回复中点停止 | 回复停止,对话里留“已停止”;重复点击安全 | 已验证;修过“停止按钮从不发请求”的缺陷 |
| 刷新或断线 | 对话与任务状态恢复;事件按序号续读 | 已验证 |
| 新增一个模型 | 只加数据与一个 worker,不改核心代码、不重启主服务 | 已验证(Seedance 2.0 真实出片) |
| 澄清卡 | 缺商品信息时发卡;用户回答后同一个 Run 恢复;只发商品名称这一种卡 | 已在 Pollo 测试部署上验证 |
| 图片附件 | 发送图片后助手能描述它;超限或类型不对被拒 | 已在 Pollo 测试部署上验证 |
| 生成图片 | 图片模型与视频走同一套报价→批准→结算;图片只能是图片任务的产出 | 已验证(5 个测试站,Qwen-Image 2.1) |
技术:按这个顺序做
| 阶段 | 交付 | 依赖 | 怎么验证 |
|---|---|---|---|
| P0 地基 | 身份、项目文档(版本号+乐观锁)、积分账本(只追加+触发器)、素材归属 | 无 | 账本分录对账;并发改同一文档只有一个成功 |
| P1 Agent 运行 | 对话 Run(会话固定一个官方技能版本)、事件流(递增序号)、停止、恢复 | P0 | 断线续读不丢不重;重复停止幂等 |
| P2 报价到生成 | 报价、批准(双哈希)、冻结→提交→结算/释放、模型适配器与独立 worker | P0、P1 | 重复批准、过期、失败三类用例;加模型不改核心 |
| P3 扩展 | 澄清卡、开发者发布技能、入口适配器、图片附件、团队与素材库 | P1、P2 | 每项各自的验收表;附件只在单独实例开 |
可以直接复用的:本站每个竞品页下载包里的前端、Go 后端(报价/批准/账本/模型适配器)、七个品牌库和身份库的 DDL、接口目录。Lumen 的最终 DDL(全部表)已在 PostgreSQL 16 上整体执行通过。
- 下载 lumen-handoff.zip,交给 Codex 等编码 Agent,告诉它“按 AGENTS.md 实现 Lumen”。
- 包里有:完整接口规格(OpenAPI 3.1,61 个操作)、可执行的建表脚本、哈希与事件等契约、状态机、可写成测试的验收用例、待拍板事项与默认值、未覆盖范围。
我们踩过的坑(别再踩)
| 坑 | 后果 | 做法 |
|---|---|---|
| 模型写死在代码和 worker 配置里 | 加一个模型要改代码、重编译、重启 | 模型与版本放数据;适配器按 key 注册;白名单可由环境变量扩展 |
| 共享的 Agent 会话状态被“隔离环境”改动 | 克隆库里改了模型,生产会话读绑定返回 503 | 隔离测试必须连 Agent 一起隔离;绑定与会话模型版本要有一致性校验 |
| 附件与统一品牌实例互斥 | 开附件会让七品牌实例启动失败 | 附件放单独实例;或先解开这条互斥 |
| 启动器只认固定库名与固定地址 | 拷贝库、新端口被安全检查拒绝 | 起独立实例时同时准备同名库的拷贝,并显式放行新地址 |
| 页面自带点击守卫吞掉不认识的按钮 | 新加的按钮点了没反应 | 新功能在更早的捕获阶段处理,并加端到端点击测试 |
| 前端模型切换层在澄清卡打开时拒绝一切操作 | 用户永远答不了卡(卡片路径从没跑过,所以没发现) | 回答卡片要放行;任何“冻结的功能”都要有端到端用例 |
| 业务后端只认单字段商品名称卡,且要求卡的指纹是哈希 | Agent 发出别的卡会被静默丢弃,页面停在“待核对” | 后端与 Agent 对卡的格式要共用一份契约,并在 Agent 侧限制可发的卡 |
| 批准后供应商立刻失败且无原因 | 积分冻结后需要人工判断 | 账本保留冻结;界面写“费用待核对”;提供人工释放入口 |
还没验证的(立项前要知道)
- 澄清卡:Pollo 测试部署上已走通,但只支持“商品名称”一种单字段卡;多字段卡要同时扩展业务后端的卡片校验与前端渲染。
- 七个复刻都不是完美复刻:7 个测试站都跑通了登录、项目会话、对话、停止和视频生成,5 个站能生成图片;其余大部分入口点了只提示“此功能正在接入”;见“一页读懂”里的审计结论和各品牌“代码与下载”页。
- Seedance 1.5 Pro 在当前密钥下被供应商拒绝,原因不明;上线前确认模型权限。