chore(repo): reinitialize repository

This commit is contained in:
2026-03-18 11:29:54 +08:00
commit 24871e213a
288 changed files with 44369 additions and 0 deletions
+790
View File
@@ -0,0 +1,790 @@
# 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