# Inbox V2 数据库设计 本文档是 `inbox v2` 的数据库开发基线。 它服务于三件事: 1. 明确 `v2` 到底使用哪些数据库。 2. 明确每张表的字段、主键、外键和作用。 3. 明确各张表之间的关系,作为后续 `store / app / http` 实现依据。 ## 1. 物理数据库 `v2` 先只使用 **1 个物理数据库**: | 数据库 | 引擎 | 是否采用 | 用途 | | --- | --- | --- | --- | | `inbox.db` | SQLite | 是 | 所有运行时业务数据、在线可编辑配置、配置审计 | | Redis | - | 否 | 当前不需要单独缓存或队列 | | PostgreSQL | - | 否 | 当前先不引入额外运维复杂度 | | 独立日志库 | - | 否 | 执行日志先跟主库放一起 | | 向量库 | - | 否 | 当前主流程不依赖向量检索 | 一句话: - `V2` 先只有一个库:`inbox.db` ## 2. 关键决策 ### 2.1 配置入库 因为 `roles / prompts / skills / config` 需要满足: - 前端可编辑 - 保存后立即生效 - 不需要改文件后再发版 所以第二版里,这些内容的**运行时真源就是数据库**。 文件只保留这些作用: - 默认模板 - 初始化导入源 - 内置技能的原始资产 ### 2.2 立即生效的定义 这里的“立即生效”定义为: - 配置保存成功后 - **下一次新的 agent run / 新的消息处理 / 新的 HTTP 请求** 立即读取最新配置 不包含: - 已经运行中的 agent 进程半路热切换配置 ### 2.3 配置覆盖规则 在线配置支持两层作用域: 1. `global` 2. `workspace override` 解析优先级固定为: `workspace row > global row` 也就是说: - 如果某个 workspace 有自己的 prompt/config/binding,就优先使用它 - 否则回退到全局默认 ### 2.4 统一建模原则 1. 所有业务主键统一使用 `TEXT` 2. 所有时间统一使用 UTC RFC3339 3. 核心业务关系用结构化表,不用 JSON blob 代替 4. JSON 只用于快照和弱结构扩展字段 5. `topic` 是业务主实体 6. `product` 接管需求整理文档 7. `clarifier_state / clarifier_artifacts / topic_records` 在 `v2` 中不再保留 ## 3. 数据域划分 | 数据域 | 表 | | --- | --- | | 系统 | `schema_migrations` | | 项目与工作区 | `projects`, `workspaces` | | 在线角色配置 | `roles`, `role_prompts`, `role_configs`, `skills`, `role_skill_bindings` | | Topic 与文档 | `topics`, `topic_documents` | | 消息协作 | `messages`, `message_deliveries` | | Requirement / Discovery / Workflow / Merge | `requirements`, `discovery_rounds`, `discovery_candidates`, `discovery_votes`, `workflow_runs`, `workflow_run_logs`, `merge_requests` | ## 4. 表清单总览 | 表名 | 数据域 | 说明 | | --- | --- | --- | | `schema_migrations` | 系统 | 迁移历史 | | `projects` | 项目 | 项目主表 | | `workspaces` | 工作区 | 工作区主表 | | `roles` | 在线角色配置 | 角色定义 | | `role_prompts` | 在线角色配置 | 角色提示词 | | `role_configs` | 在线角色配置 | 角色模型和运行配置 | | `skills` | 在线角色配置 | 技能定义 | | `role_skill_bindings` | 在线角色配置 | 角色与技能绑定 | | `topics` | Topic | 统一 topic 主实体 | | `topic_documents` | Topic | `PRD`、`Decision Log`、Discovery 文档 | | `messages` | 消息协作 | 消息信封与正文 | | `message_deliveries` | 消息协作 | 消息收件与归档状态 | | `requirements` | Requirement | pool 队列项 | | `discovery_rounds` | Discovery | discovery 轮次 | | `discovery_candidates` | Discovery | discovery 候选项 | | `discovery_votes` | Discovery | discovery 投票 | | `workflow_runs` | Workflow | 角色执行记录 | | `workflow_run_logs` | Workflow | 执行日志流 | | `merge_requests` | Merge | merge 请求记录 | ## 5. 表字段定义 ### 5.1 `schema_migrations` | 字段 | 类型 | 约束 | 说明 | | --- | --- | --- | --- | | `version` | `INTEGER` | PK | 迁移版本号 | | `name` | `TEXT` | NOT NULL | 迁移名称 | | `applied_at` | `TEXT` | NOT NULL | 执行时间 | ### 5.2 `projects` | 字段 | 类型 | 约束 | 说明 | | --- | --- | --- | --- | | `id` | `TEXT` | PK | 项目 ID | | `slug` | `TEXT` | NOT NULL, UNIQUE | 项目标识 | | `name` | `TEXT` | NOT NULL | 展示名称 | | `root_path` | `TEXT` | NOT NULL, UNIQUE | 项目根目录 | | `default_branch` | `TEXT` | NOT NULL | 默认分支 | | `status` | `TEXT` | NOT NULL | `active / archived` | | `created_at` | `TEXT` | NOT NULL | 创建时间 | | `updated_at` | `TEXT` | NOT NULL | 更新时间 | 关系: - `projects 1 -> N workspaces` ### 5.3 `workspaces` | 字段 | 类型 | 约束 | 说明 | | --- | --- | --- | --- | | `id` | `TEXT` | PK | 工作区 ID | | `project_id` | `TEXT` | FK -> `projects.id` | 所属项目 | | `slug` | `TEXT` | NOT NULL, UNIQUE | 工作区标识 | | `name` | `TEXT` | NOT NULL | 展示名称 | | `root_path` | `TEXT` | NOT NULL, UNIQUE | 工作区路径 | | `base_branch` | `TEXT` | NOT NULL | 基线分支 | | `worktree_branch` | `TEXT` | NOT NULL, UNIQUE | 工作分支 | | `runtime_backend` | `TEXT` | NOT NULL | `local / container / remote` | | `status` | `TEXT` | NOT NULL | `active / paused / archived` | | `created_at` | `TEXT` | NOT NULL | 创建时间 | | `updated_at` | `TEXT` | NOT NULL | 更新时间 | 关系: - `workspaces N -> 1 projects` - `workspaces 1 -> N topics` - `workspaces 1 -> N messages` - `workspaces 1 -> N requirements` - `workspaces 1 -> N discovery_rounds` - `workspaces 1 -> N workflow_runs` - `workspaces 1 -> N merge_requests` ### 5.4 `roles` | 字段 | 类型 | 约束 | 说明 | | --- | --- | --- | --- | | `name` | `TEXT` | PK | 角色名,例如 `product` | | `title` | `TEXT` | NOT NULL | 展示名称 | | `category` | `TEXT` | NOT NULL | `product / delivery / review / discovery` | | `description` | `TEXT` | NOT NULL DEFAULT `''` | 角色说明 | | `is_enabled` | `INTEGER` | NOT NULL | 1 启用,0 禁用 | | `is_builtin` | `INTEGER` | NOT NULL | 1 内置,0 自定义 | | `sort_order` | `INTEGER` | NOT NULL DEFAULT `0` | 排序 | | `created_at` | `TEXT` | NOT NULL | 创建时间 | | `updated_at` | `TEXT` | NOT NULL | 更新时间 | 关系: - `roles 1 -> N role_prompts` - `roles 1 -> N role_configs` - `roles 1 -> N role_skill_bindings` - `roles 1 -> N messages` - `roles 1 -> N message_deliveries` - `roles 1 -> N requirements` - `roles 1 -> N discovery_candidates` - `roles 1 -> N discovery_votes` - `roles 1 -> N workflow_runs` ### 5.5 `role_prompts` 当前生效的提示词表。 | 字段 | 类型 | 约束 | 说明 | | --- | --- | --- | --- | | `id` | `TEXT` | PK | 提示词记录 ID | | `role_name` | `TEXT` | FK -> `roles.name` | 所属角色 | | `workspace_id` | `TEXT` | FK -> `workspaces.id`, NULLABLE | 为空表示全局默认;非空表示 workspace override | | `prompt_kind` | `TEXT` | NOT NULL | `system / clarification / plan / review / freeze / execution / verification / discovery` | | `content_markdown` | `TEXT` | NOT NULL | 提示词正文 | | `version` | `INTEGER` | NOT NULL | 当前版本号 | | `updated_by` | `TEXT` | NOT NULL DEFAULT `''` | 修改人或修改来源 | | `created_at` | `TEXT` | NOT NULL | 创建时间 | | `updated_at` | `TEXT` | NOT NULL | 更新时间 | 唯一约束: - 全局:每个 `(role_name, prompt_kind)` 只能有 1 条全局默认记录 - 工作区:每个 `(role_name, workspace_id, prompt_kind)` 只能有 1 条 override 记录 关系: - `role_prompts N -> 1 roles` - `role_prompts N -> 1 workspaces`(可空) ### 5.6 `role_configs` 当前生效的角色运行配置表。 | 字段 | 类型 | 约束 | 说明 | | --- | --- | --- | --- | | `id` | `TEXT` | PK | 配置记录 ID | | `role_name` | `TEXT` | FK -> `roles.name` | 所属角色 | | `workspace_id` | `TEXT` | FK -> `workspaces.id`, NULLABLE | 为空表示全局默认;非空表示 workspace override | | `model` | `TEXT` | NOT NULL DEFAULT `''` | 默认模型 | | `model_provider` | `TEXT` | NOT NULL DEFAULT `''` | 模型提供方 | | `provider_name` | `TEXT` | NOT NULL DEFAULT `''` | Provider 名称 | | `provider_base_url` | `TEXT` | NOT NULL DEFAULT `''` | Provider Base URL | | `provider_wire_api` | `TEXT` | NOT NULL DEFAULT `''` | Provider Wire API | | `reasoning_effort` | `TEXT` | NOT NULL DEFAULT `''` | 默认 reasoning 等级 | | `plan_model` | `TEXT` | NOT NULL DEFAULT `''` | 规划阶段专用模型 | | `plan_reasoning_effort` | `TEXT` | NOT NULL DEFAULT `''` | 规划阶段 reasoning | | `disable_response_storage` | `INTEGER` | NOT NULL DEFAULT `0` | 是否关闭响应持久化 | | `shell_env_inherit` | `TEXT` | NOT NULL DEFAULT `core` | 继承环境变量策略 | | `shell_env_overrides_json` | `TEXT` | NOT NULL DEFAULT `{}` | 环境变量覆盖项 | | `extra_config_json` | `TEXT` | NOT NULL DEFAULT `{}` | 其他扩展配置 | | `version` | `INTEGER` | NOT NULL | 当前版本号 | | `updated_by` | `TEXT` | NOT NULL DEFAULT `''` | 修改人或修改来源 | | `created_at` | `TEXT` | NOT NULL | 创建时间 | | `updated_at` | `TEXT` | NOT NULL | 更新时间 | 唯一约束: - 全局:每个 `role_name` 只能有 1 条全局默认配置 - 工作区:每个 `(role_name, workspace_id)` 只能有 1 条 override 配置 关系: - `role_configs N -> 1 roles` - `role_configs N -> 1 workspaces`(可空) ### 5.7 `skills` 技能定义表。运行时真正使用数据库中的技能内容。 | 字段 | 类型 | 约束 | 说明 | | --- | --- | --- | --- | | `id` | `TEXT` | PK | 技能 ID | | `skill_key` | `TEXT` | NOT NULL, UNIQUE | 稳定标识 | | `name` | `TEXT` | NOT NULL | 展示名称 | | `description` | `TEXT` | NOT NULL DEFAULT `''` | 技能说明 | | `source_type` | `TEXT` | NOT NULL | `builtin / imported / custom` | | `content_markdown` | `TEXT` | NOT NULL DEFAULT `''` | 技能正文内容 | | `status` | `TEXT` | NOT NULL | `active / disabled / archived` | | `version` | `INTEGER` | NOT NULL | 当前版本号 | | `created_at` | `TEXT` | NOT NULL | 创建时间 | | `updated_at` | `TEXT` | NOT NULL | 更新时间 | 关系: - `skills 1 -> N role_skill_bindings` ### 5.8 `role_skill_bindings` 角色与技能的绑定表。 | 字段 | 类型 | 约束 | 说明 | | --- | --- | --- | --- | | `id` | `TEXT` | PK | 绑定记录 ID | | `role_name` | `TEXT` | FK -> `roles.name` | 角色 | | `workspace_id` | `TEXT` | FK -> `workspaces.id`, NULLABLE | 为空表示全局默认;非空表示 workspace override | | `skill_id` | `TEXT` | FK -> `skills.id` | 技能 | | `is_enabled` | `INTEGER` | NOT NULL | 1 启用,0 禁用 | | `sort_order` | `INTEGER` | NOT NULL DEFAULT `0` | 排序 | | `config_json` | `TEXT` | NOT NULL DEFAULT `{}` | 绑定级配置 | | `version` | `INTEGER` | NOT NULL | 当前版本号 | | `updated_by` | `TEXT` | NOT NULL DEFAULT `''` | 修改人或修改来源 | | `created_at` | `TEXT` | NOT NULL | 创建时间 | | `updated_at` | `TEXT` | NOT NULL | 更新时间 | 唯一约束: - 全局:每个 `(role_name, skill_id)` 只能有 1 条全局默认绑定 - 工作区:每个 `(role_name, workspace_id, skill_id)` 只能有 1 条 override 绑定 关系: - `role_skill_bindings N -> 1 roles` - `role_skill_bindings N -> 1 skills` - `role_skill_bindings N -> 1 workspaces`(可空) ### 5.10 `topics` 这是第二版的主实体表。 | 字段 | 类型 | 约束 | 说明 | | --- | --- | --- | --- | | `id` | `TEXT` | PK | topic ID | | `workspace_id` | `TEXT` | FK -> `workspaces.id` | 所属工作区 | | `slug` | `TEXT` | NOT NULL | 稳定标识 | | `title` | `TEXT` | NOT NULL | 标题 | | `space` | `TEXT` | NOT NULL | `discovery / clarify / pool / workflow` | | `status` | `TEXT` | NOT NULL | 当前状态 | | `source_topic_id` | `TEXT` | FK -> `topics.id`, NULLABLE | 来源 topic | | `owner_role_name` | `TEXT` | FK -> `roles.name`, NULLABLE | 当前主责角色 | | `summary` | `TEXT` | NOT NULL DEFAULT `''` | 摘要 | | `meta_json` | `TEXT` | NOT NULL DEFAULT `{}` | 扩展元数据 | | `created_at` | `TEXT` | NOT NULL | 创建时间 | | `updated_at` | `TEXT` | NOT NULL | 更新时间 | | `closed_at` | `TEXT` | NULLABLE | 关闭时间 | 唯一约束: - 每个 workspace 下 `slug` 唯一 关系: - `topics N -> 1 workspaces` - `topics N -> 1 topics`(`source_topic_id`) - `topics N -> 1 roles`(`owner_role_name`) - `topics 1 -> N topic_documents` - `topics 1 -> N messages` - `topics 1 -> N requirements` - `topics 1 -> N discovery_rounds` - `topics 1 -> N workflow_runs` - `topics 1 -> N merge_requests` ### 5.11 `topic_documents` topic 持有的正式文档。 | 字段 | 类型 | 约束 | 说明 | | --- | --- | --- | --- | | `id` | `TEXT` | PK | 文档 ID | | `topic_id` | `TEXT` | FK -> `topics.id` | 所属 topic | | `kind` | `TEXT` | NOT NULL | `prd / decision_log / discovery_request / discovery_result` | | `content_markdown` | `TEXT` | NOT NULL | Markdown 正文 | | `version` | `INTEGER` | NOT NULL | 版本号 | | `updated_by_role_name` | `TEXT` | FK -> `roles.name`, NULLABLE | 最后更新角色 | | `created_at` | `TEXT` | NOT NULL | 创建时间 | | `updated_at` | `TEXT` | NOT NULL | 更新时间 | 唯一约束: - 每个 topic 下每种 `kind` 只能有 1 条当前文档 说明: - `PRD` 与 `Decision Log` 在 `v2` 中归 `product` 所有 ### 5.12 `messages` 消息主表。 | 字段 | 类型 | 约束 | 说明 | | --- | --- | --- | --- | | `id` | `TEXT` | PK | 消息 ID | | `workspace_id` | `TEXT` | FK -> `workspaces.id` | 所属工作区 | | `topic_id` | `TEXT` | FK -> `topics.id` | 所属 topic | | `from_role_name` | `TEXT` | FK -> `roles.name` | 发送角色 | | `to_expr` | `TEXT` | NOT NULL | 原始收件表达式,例如 `backend`、`all` | | `type` | `TEXT` | NOT NULL | `chat / proposal / question / decision / summary` | | `stage` | `TEXT` | NOT NULL | `clarification / plan / review / freeze / execution / verification / discovery` | | `round` | `INTEGER` | NULLABLE | 回合号 | | `reply_to_message_id` | `TEXT` | FK -> `messages.id`, NULLABLE | 回复目标消息 | | `body_markdown` | `TEXT` | NOT NULL | 消息正文 | | `created_at` | `TEXT` | NOT NULL | 创建时间 | 关系: - `messages N -> 1 workspaces` - `messages N -> 1 topics` - `messages N -> 1 roles` - `messages N -> 1 messages`(`reply_to_message_id`) - `messages 1 -> N message_deliveries` ### 5.13 `message_deliveries` 每个实际收件人的投递状态。 | 字段 | 类型 | 约束 | 说明 | | --- | --- | --- | --- | | `message_id` | `TEXT` | FK -> `messages.id` | 对应消息 | | `recipient_role_name` | `TEXT` | FK -> `roles.name` | 实际收件角色 | | `state` | `TEXT` | NOT NULL | `pending / received / read / archived` | | `delivered_at` | `TEXT` | NOT NULL | 投递时间 | | `read_at` | `TEXT` | NULLABLE | 已读时间 | | `archived_at` | `TEXT` | NULLABLE | 归档时间 | | `updated_at` | `TEXT` | NOT NULL | 更新时间 | 主键: - `PRIMARY KEY (message_id, recipient_role_name)` 说明: - `to: all` 会在这里展开成多条记录 - 它只表达“线程绑定” - 不表达“这次执行的历史” ### 5.15 `requirements` pool 阶段的结构化队列项。 | 字段 | 类型 | 约束 | 说明 | | --- | --- | --- | --- | | `id` | `TEXT` | PK | requirement ID | | `workspace_id` | `TEXT` | FK -> `workspaces.id` | 所属工作区 | | `topic_id` | `TEXT` | FK -> `topics.id` | 来源 topic | | `title` | `TEXT` | NOT NULL | 标题 | | `body_markdown` | `TEXT` | NOT NULL | 详细说明 | | `status` | `TEXT` | NOT NULL | `pending / dispatched / completed / archived` | | `priority` | `INTEGER` | NOT NULL | 优先级 | | `created_by_role_name` | `TEXT` | FK -> `roles.name` | 创建角色,通常是 `product` | | `created_at` | `TEXT` | NOT NULL | 创建时间 | | `updated_at` | `TEXT` | NOT NULL | 更新时间 | | `completed_at` | `TEXT` | NULLABLE | 完成时间 | 说明: - `requirements` 以 `workspace + topic` 为来源 - 不再把 `project_id` 当成 requirement 的主归属 ### 5.16 `discovery_rounds` discovery 轮次主表。 | 字段 | 类型 | 约束 | 说明 | | --- | --- | --- | --- | | `id` | `TEXT` | PK | round ID | | `workspace_id` | `TEXT` | FK -> `workspaces.id` | 所属工作区 | | `topic_id` | `TEXT` | FK -> `topics.id` | 关联 topic | | `phase` | `TEXT` | NOT NULL | `collecting / voting / completed / cancelled` | | `request_document_id` | `TEXT` | FK -> `topic_documents.id`, NULLABLE | discovery request 文档 | | `result_document_id` | `TEXT` | FK -> `topic_documents.id`, NULLABLE | discovery result 文档 | | `started_at` | `TEXT` | NOT NULL | 开始时间 | | `completed_at` | `TEXT` | NULLABLE | 完成时间 | | `updated_at` | `TEXT` | NOT NULL | 更新时间 | 关系: - `discovery_rounds N -> 1 workspaces` - `discovery_rounds N -> 1 topics` - `discovery_rounds 1 -> N discovery_candidates` ### 5.17 `discovery_candidates` discovery 候选项结构化表。 | 字段 | 类型 | 约束 | 说明 | | --- | --- | --- | --- | | `id` | `TEXT` | PK | candidate ID | | `round_id` | `TEXT` | FK -> `discovery_rounds.id` | 所属 round | | `proposer_role_name` | `TEXT` | FK -> `roles.name` | 提出角色 | | `status` | `TEXT` | NOT NULL | `draft / ready / accepted / rejected / archived` | | `title` | `TEXT` | NOT NULL | 候选标题 | | `problem` | `TEXT` | NOT NULL DEFAULT `''` | 问题描述 | | `evidence` | `TEXT` | NOT NULL DEFAULT `''` | 证据 | | `proposal` | `TEXT` | NOT NULL DEFAULT `''` | 提案内容 | | `expected_impact` | `TEXT` | NOT NULL DEFAULT `''` | 预期收益 | | `risk` | `TEXT` | NOT NULL DEFAULT `''` | 风险 | | `how_to_verify` | `TEXT` | NOT NULL DEFAULT `''` | 验证方式 | | `created_at` | `TEXT` | NOT NULL | 创建时间 | | `updated_at` | `TEXT` | NOT NULL | 更新时间 | 关系: - `discovery_candidates N -> 1 discovery_rounds` - `discovery_candidates N -> 1 roles` - `discovery_candidates 1 -> N discovery_votes` ### 5.18 `discovery_votes` discovery 候选项投票表。 | 字段 | 类型 | 约束 | 说明 | | --- | --- | --- | --- | | `id` | `TEXT` | PK | vote ID | | `round_id` | `TEXT` | FK -> `discovery_rounds.id` | 所属 round | | `candidate_id` | `TEXT` | FK -> `discovery_candidates.id` | 所投候选项 | | `voter_role_name` | `TEXT` | FK -> `roles.name` | 投票角色 | | `vote` | `TEXT` | NOT NULL | `agree / reject / unclear` | | `reason` | `TEXT` | NOT NULL DEFAULT `''` | 原因 | | `created_at` | `TEXT` | NOT NULL | 创建时间 | 唯一约束: - 每个角色对每个候选项最多投 1 票 ### 5.19 `workflow_runs` 执行阶段主表。 | 字段 | 类型 | 约束 | 说明 | | --- | --- | --- | --- | | `id` | `TEXT` | PK | run ID | | `workspace_id` | `TEXT` | FK -> `workspaces.id` | 所属工作区 | | `topic_id` | `TEXT` | FK -> `topics.id` | 所属 topic | | `role_name` | `TEXT` | FK -> `roles.name` | 执行角色 | | `stage` | `TEXT` | NOT NULL | `plan / review / execution / verification` | | `mode` | `TEXT` | NOT NULL DEFAULT `''` | 运行模式 | | `status` | `TEXT` | NOT NULL | `running / succeeded / failed / cancelled` | | `request_message_id` | `TEXT` | FK -> `messages.id`, NULLABLE | 触发消息 | | `config_snapshot_json` | `TEXT` | NOT NULL DEFAULT `{}` | 启动时解析出的 prompt/config/skills 快照 | | `command_json` | `TEXT` | NOT NULL DEFAULT `[]` | 执行命令快照 | | `reply_message_id` | `TEXT` | FK -> `messages.id`, NULLABLE | 执行完成后的回复消息 | | `exit_code` | `INTEGER` | NOT NULL DEFAULT `0` | 退出码 | | `started_at` | `TEXT` | NOT NULL | 开始时间 | | `completed_at` | `TEXT` | NULLABLE | 完成时间 | | `error_message` | `TEXT` | NOT NULL DEFAULT `''` | 错误信息 | 说明: - 新的 run 启动时必须把解析后的角色配置快照写入 `config_snapshot_json` - 这样后续即使 prompt/config 被改动,历史 run 仍然可追溯 ### 5.20 `workflow_run_logs` 执行日志流。 | 字段 | 类型 | 约束 | 说明 | | --- | --- | --- | --- | | `run_id` | `TEXT` | FK -> `workflow_runs.id` | 所属 run | | `seq` | `INTEGER` | NOT NULL | 行序号 | | `stream` | `TEXT` | NOT NULL | `stdout / stderr / system` | | `content` | `TEXT` | NOT NULL | 日志内容 | | `created_at` | `TEXT` | NOT NULL | 创建时间 | 主键: - `PRIMARY KEY (run_id, seq)` 关系: - `workflow_run_logs N -> 1 workflow_runs` ### 5.21 `merge_requests` merge 请求记录。 | 字段 | 类型 | 约束 | 说明 | | --- | --- | --- | --- | | `id` | `TEXT` | PK | merge request ID | | `workspace_id` | `TEXT` | FK -> `workspaces.id` | 所属工作区 | | `topic_id` | `TEXT` | FK -> `topics.id` | 所属 topic | | `workflow_run_id` | `TEXT` | FK -> `workflow_runs.id`, NULLABLE | 来源执行记录 | | `requested_by_role_name` | `TEXT` | FK -> `roles.name`, NULLABLE | 发起角色 | | `target_branch` | `TEXT` | NOT NULL | 目标分支 | | `status` | `TEXT` | NOT NULL | `pending / merged / failed / cancelled` | | `summary` | `TEXT` | NOT NULL DEFAULT `''` | 摘要 | | `files_changed` | `INTEGER` | NOT NULL DEFAULT `0` | 改动文件数 | | `insertions` | `INTEGER` | NOT NULL DEFAULT `0` | 新增行数 | | `deletions` | `INTEGER` | NOT NULL DEFAULT `0` | 删除行数 | | `changed_files_json` | `TEXT` | NOT NULL DEFAULT `[]` | 改动文件列表 | | `created_at` | `TEXT` | NOT NULL | 创建时间 | | `merged_at` | `TEXT` | NULLABLE | 合并时间 | | `error_message` | `TEXT` | NOT NULL DEFAULT `''` | 失败原因 | 关系: - `merge_requests N -> 1 workspaces` - `merge_requests N -> 1 topics` - `merge_requests N -> 1 workflow_runs` - `merge_requests N -> 1 roles` ## 6. 表关系图 ```mermaid erDiagram PROJECTS ||--o{ WORKSPACES : has WORKSPACES ||--o{ TOPICS : owns WORKSPACES ||--o{ MESSAGES : owns WORKSPACES ||--o{ REQUIREMENTS : owns WORKSPACES ||--o{ DISCOVERY_ROUNDS : owns WORKSPACES ||--o{ WORKFLOW_RUNS : owns WORKSPACES ||--o{ MERGE_REQUESTS : owns ROLES ||--o{ ROLE_PROMPTS : has ROLES ||--o{ ROLE_CONFIGS : has ROLES ||--o{ ROLE_SKILL_BINDINGS : binds SKILLS ||--o{ ROLE_SKILL_BINDINGS : used_by TOPICS ||--o{ TOPIC_DOCUMENTS : has TOPICS ||--o{ MESSAGES : contains TOPICS ||--o{ REQUIREMENTS : produces TOPICS ||--o{ DISCOVERY_ROUNDS : drives TOPICS ||--o{ WORKFLOW_RUNS : executes TOPICS ||--o{ MERGE_REQUESTS : results_in MESSAGES ||--o{ MESSAGE_DELIVERIES : fans_out MESSAGES ||--o{ MESSAGES : replies_to DISCOVERY_ROUNDS ||--o{ DISCOVERY_CANDIDATES : includes DISCOVERY_CANDIDATES ||--o{ DISCOVERY_VOTES : receives WORKFLOW_RUNS ||--o{ WORKFLOW_RUN_LOGS : emits WORKFLOW_RUNS ||--o| MERGE_REQUESTS : may_create ``` ## 7. 关系说明 ### 7.1 配置关系 | 主表 | 从表 | 关系 | 说明 | | --- | --- | --- | --- | | `roles` | `role_prompts` | 1:N | 一个角色可有多种 prompt kind,也可有 workspace override | | `roles` | `role_configs` | 1:N | 一个角色可有全局配置和多个 workspace override | | `roles` | `role_skill_bindings` | 1:N | 一个角色可绑定多个技能 | | `skills` | `role_skill_bindings` | 1:N | 一个技能可被多个角色使用 | | `workspaces` | `role_prompts / role_configs / role_skill_bindings` | 1:N | workspace 级覆盖配置 | ### 7.2 业务关系 | 主表 | 从表 | 关系 | 说明 | | --- | --- | --- | --- | | `projects` | `workspaces` | 1:N | 一个项目下有多个工作区 | | `workspaces` | `topics` | 1:N | 一个工作区下有多个 topic | | `topics` | `topic_documents` | 1:N | 一个 topic 下有多种文档 | | `topics` | `messages` | 1:N | 一个 topic 下有多条消息 | | `messages` | `message_deliveries` | 1:N | 一条消息可投递给多个角色 | | `topics` | `requirements` | 1:N | 一个 topic 可产生多个 requirement | | `topics` | `discovery_rounds` | 1:N | 一个 topic 可有多轮 discovery | | `discovery_rounds` | `discovery_candidates` | 1:N | 一轮 discovery 可有多个候选项 | | `discovery_candidates` | `discovery_votes` | 1:N | 一个候选项可收到多个角色投票 | | `topics` | `workflow_runs` | 1:N | 一个 topic 可有多次执行 | | `workflow_runs` | `workflow_run_logs` | 1:N | 一次执行有多条日志 | | `topics` | `merge_requests` | 1:N | 一个 topic 可产生多个 merge 请求 | ### 7.3 特殊关系 | 字段 | 关系 | 说明 | | --- | --- | --- | | `topics.source_topic_id` | 自关联 | topic 可从另一个 topic 派生 | | `messages.reply_to_message_id` | 自关联 | 消息可回复另一条消息 | | `discovery_rounds.request_document_id` | 指向 `topic_documents` | discovery 输入文档 | | `discovery_rounds.result_document_id` | 指向 `topic_documents` | discovery 输出文档 | | `workflow_runs.config_snapshot_json` | 快照,不是 FK | 保存运行时解析后的配置结果 | ## 8. 读取优先级 以下三张配置表都采用相同规则: - `role_prompts` - `role_configs` - `role_skill_bindings` 读取顺序固定为: 1. 先查当前 `workspace_id` 的覆盖记录 2. 如果没有,再查全局默认记录 这个规则是 `v2` 的硬约束,服务端、测试和前端都按这套理解实现。 ## 9. 写入规则 ### 9.1 配置写入 当用户在前端修改: - 角色 - 提示词 - 技能 - 角色配置 - 技能绑定 服务端必须同时做两件事: 1. 更新当前生效表 ### 9.2 新执行启动 当新的 `workflow_runs` 启动时: 1. 解析角色最终生效配置 - prompt - role config - skill binding - skill 内容 2. 将解析结果写入 `workflow_runs.config_snapshot_json` 3. 再启动实际执行 这样可以同时满足: - 配置立即生效 - 历史执行可追溯 ## 10. V2 明确不保留的旧表 | 旧表 | V2 处理 | | --- | --- | | `topic_records` | 删除,合并进 `topics` | | `clarifier_state` | 删除,状态回归 `topics` | | `clarifier_artifacts` | 删除,合并进 `topic_documents` | | `message_mailboxes` | 改为 `message_deliveries` | | `dispatches` | 改为 `workflow_runs` | | `dispatch_live_lines` | 改为 `workflow_run_logs` | | `discovery_round_proposals` | 删除,改为 `discovery_candidates` | | `discovery_round_votes` JSON blob | 删除,改为结构化 `discovery_votes` | ## 11. 对开发的直接约束 这份文档对 `v2` 开发有三条直接约束: 1. 不允许再出现“同一业务对象散落多个旧表”的设计。 2. 不允许再把在线可编辑配置只放文件、不进数据库。 3. 不允许再把 discovery 和 workflow 的核心结构塞回 JSON blob。 这份文档就是 `inbox v2` 的数据库基线,后续如果要改,应该直接更新这份文档,而不是各模块各自理解一版。 ## 当前工作流图扩展 当前运行时已经在 `chains` / `tasks` / `workflow_runs` 上扩展了 leader-managed graph 字段,作为后续 DAG planning 的基础。 ### chains 除基础标识与运行态字段外,`chains` 当前还包含: - `purpose`:这条 chain 的目标与职责摘要 ### tasks 除基础标题、正文、状态、依赖字段外,`tasks` 当前还包含: - `task_kind` - `execution` - `gate` - `verification` - `milestone` - `gate_policy` - `none` - `hard_stop` - `ask_user` - `leader_replan` - `deliverables_json` - `verification_mode` - `none` - `auto` - `human` - `batch_key` - `replan_policy` - `patch` - `clarify` - `stop` 说明: - `task_kind = milestone` 是当前 milestone 的落地方式,不单独建表。 - `gate` task 用于前置检查;存在 gate 时,其它 task 默认先不放行。 ### workflow_runs `leader` 的结构化 planning 结果当前会持久化到: - `workflow_runs.command_json` 其中包含: - `plan_version` - `plan_mode` - `replan_reason` - `supersedes` - `execution_mode` - `leader_reply` - `chains` - `tasks` - `start_nodes` 说明: - 空图首次规划使用 `plan_mode = initial` - 主题已有 graph 时,leader 必须使用 `plan_mode = patch` - 当前系统不允许 patch 模式扩图;patch 只能复用现有 graph