--- reviewStatus: pending reviewedAt: null replacedBy: null --- # 第一阶段工程基线数据库设计 ## 1. 设计边界 本文档定义第一阶段用户资料和 Agent 运行审计数据的逻辑结构、约束、索引、迁移与回滚策略。开发和自动化测试使用 SQLite,集成与生产使用 PostgreSQL。 项目尚未确认 PostgreSQL 精确版本,因此本文档不采用版本专属字段、索引方法、表达式索引或方言 SQL。实现以 Django 6.0.8 ORM 和迁移能力表达;版本专属优化须在 PostgreSQL 版本确认后另行评审。 关联设计: - [后端落地设计](backend-design.md) - [前端落地设计](frontend-design.md) - [接口与页面契约设计](interface-design.md) ## 2. 设计原则 - 用户私有数据必须具有明确的用户归属。 - 状态转换由服务层执行,数据库约束负责守住唯一性和基础合法性。 - 运行事件采用追加模式,保留审计轨迹。 - JSON 字段只保存经过脱敏和大小限制的摘要。 - 时间统一存储为支持时区的 Django 时间值,显示时转换到用户时区。 - 金额、token 和耗时使用确定类型,避免浮点误差。 - 表名、约束名和索引名在迁移中显式稳定,避免不同数据库自动命名差异影响排查。 ## 3. 实体关系 ```mermaid erDiagram AUTH_USER ||--o| USER_PROFILE : has AUTH_USER ||--o{ AGENT_RUN : owns AGENT_RUN ||--o{ AGENT_RUN_EVENT : contains AGENT_RUN ||--o{ TOOL_CALL : contains AGENT_RUN ||--o{ HUMAN_APPROVAL : requests AUTH_USER ||--o{ HUMAN_APPROVAL : resolves ``` ## 4. 表结构草案 ### 4.1 `accounts_user_profile` | 字段 | Django 类型建议 | 空值 | 约束与说明 | | --- | --- | --- | --- | | `id` | `BigAutoField` | 否 | 主键 | | `user_id` | `OneToOneField` | 否 | 唯一,关联 Django 用户 | | `display_name` | `CharField` | 是 | 空字符串表示未设置,长度上限实现时确认 | | `timezone` | `CharField` | 否 | 默认 `Asia/Shanghai`,必须来自受控候选 | | `created_at` | `DateTimeField` | 否 | 创建时写入 | | `updated_at` | `DateTimeField` | 否 | 修改时更新 | 删除策略:用户尚无审计数据时资料可随用户删除;用户存在 Agent Run 时由运行记录的保护关系阻止用户物理删除。 ### 4.2 `agent_runtime_agent_run` | 字段组 | 字段 | 类型建议 | 说明 | | --- | --- | --- | --- | | 标识 | `id` | `UUIDField` | 主键,避免在页面暴露连续编号 | | 归属 | `owner_id` | `ForeignKey(PROTECT)` | 用户私有归属 | | 展示 | `title` | `CharField` | 简短标题 | | 状态 | `status` | `CharField` | 使用代码枚举和数据库检查约束 | | 并发 | `lock_version` | `PositiveBigIntegerField` | 每次状态写入递增 | | 摘要 | `input_summary` | `JSONField` | 脱敏、限长输入摘要 | | 摘要 | `output_summary` | `JSONField` | 可空,脱敏输出摘要 | | 版本 | `agent_name` | `CharField` | Agent 稳定标识 | | 版本 | `agent_version` | `CharField` | 可空 | | 版本 | `instruction_version` | `CharField` | 可空 | | 版本 | `toolset_version` | `CharField` | 可空 | | 模型 | `model_name` | `CharField` | 第一阶段允许为空 | | 追踪 | `trace_id` | `CharField` | 可空,非秘密标识 | | 时间 | `started_at` | `DateTimeField` | 可空 | | 时间 | `finished_at` | `DateTimeField` | 可空 | | 耗时 | `duration_ms` | `PositiveBigIntegerField` | 可空 | | 用量 | `input_tokens` | `PositiveBigIntegerField` | 可空 | | 用量 | `output_tokens` | `PositiveBigIntegerField` | 可空 | | 费用 | `estimated_cost` | `DecimalField` | 可空,精度实现前确认 | | 失败 | `error_code` | `CharField` | 可空、稳定机器码 | | 失败 | `error_summary` | `TextField` | 可空、脱敏且限长 | | 审计 | `created_at` | `DateTimeField` | 否 | | 审计 | `updated_at` | `DateTimeField` | 否 | 检查约束至少保证: - `status` 属于已定义枚举。 - `lock_version >= 0`。 - token、耗时和费用非负。 跨字段状态不变量仍由服务层验证,因为 SQLite 与 PostgreSQL 对复杂检查约束和时间语义的行为需要保持一致。 ### 4.3 `agent_runtime_agent_run_event` | 字段 | 类型建议 | 说明 | | --- | --- | --- | | `id` | `BigAutoField` | 主键 | | `run_id` | `ForeignKey(PROTECT)` | 关联 Run,审计事件不可级联丢失 | | `sequence` | `PositiveBigIntegerField` | Run 内递增序号 | | `event_type` | `CharField` | 事件枚举 | | `summary` | `CharField` | 短摘要 | | `payload_summary` | `JSONField` | 脱敏事件数据 | | `occurred_at` | `DateTimeField` | 业务发生时间 | | `created_at` | `DateTimeField` | 数据库记录时间 | 唯一约束:`(run_id, sequence)`。 索引:`(run_id, sequence)` 唯一索引已覆盖详情页时间线读取,无需重复创建同前缀普通索引。 ### 4.4 `agent_runtime_tool_call` | 字段组 | 字段 | 类型建议 | 说明 | | --- | --- | --- | --- | | 标识 | `id` | `BigAutoField` | 主键 | | 归属 | `run_id` | `ForeignKey(PROTECT)` | 关联 Run | | 调用 | `call_id` | `CharField` | Run 内调用标识 | | 工具 | `tool_name` | `CharField` | 工具稳定名称 | | 工具 | `tool_version` | `CharField` | 可空 | | 幂等 | `idempotency_key` | `CharField` | 可空,作用域见约束 | | 状态 | `status` | `CharField` | `started/succeeded/failed` | | 摘要 | `arguments_summary` | `JSONField` | 脱敏、限长 | | 摘要 | `result_summary` | `JSONField` | 可空、脱敏、限长 | | 失败 | `error_code` | `CharField` | 可空 | | 失败 | `error_summary` | `TextField` | 可空、限长 | | 时间 | `started_at` | `DateTimeField` | 否 | | 时间 | `finished_at` | `DateTimeField` | 可空 | | 耗时 | `duration_ms` | `PositiveBigIntegerField` | 可空 | | 审计 | `created_at`、`updated_at` | `DateTimeField` | 否 | 唯一约束: - `(run_id, call_id)` 唯一。 - 非空幂等键的作用域在真实工具模型确定前采用 `(run_id, idempotency_key)`,后续如需跨 Run 幂等必须重新设计业务作用域。 ### 4.5 `agent_runtime_human_approval` | 字段 | 类型建议 | 说明 | | --- | --- | --- | | `id` | `UUIDField` | 主键 | | `run_id` | `ForeignKey(PROTECT)` | 关联 Run | | `request_key` | `CharField` | Run 内稳定请求键 | | `approval_type` | `CharField` | 确认类型枚举 | | `status` | `CharField` | 确认状态枚举 | | `request_summary` | `JSONField` | 脱敏请求摘要 | | `decision_summary` | `JSONField` | 可空、脱敏处理摘要 | | `requested_at` | `DateTimeField` | 请求时间 | | `resolved_at` | `DateTimeField` | 可空 | | `resolved_by_id` | `ForeignKey(PROTECT)` | 可空,处理人 | | `created_at`、`updated_at` | `DateTimeField` | 审计时间 | 唯一约束:`(run_id, request_key)`。 索引:`(status, requested_at)`,支持 Admin 查询待处理确认。 ## 5. 主要访问模式与索引 | 访问模式 | 过滤与排序 | 索引建议 | | --- | --- | --- | | 当前用户 Run 列表 | `owner_id`,`created_at DESC` | `(owner_id, created_at)` | | 当前用户按状态查询 | `owner_id`、`status`、`created_at DESC` | 第一阶段无筛选需求,暂不新增 | | Run 事件时间线 | `run_id`、`sequence ASC` | 唯一索引 `(run_id, sequence)` | | Run 工具调用列表 | `run_id`、`started_at ASC` | `(run_id, started_at)` | | 待处理人工确认 | `status`、`requested_at ASC` | `(status, requested_at)` | | trace 定位运行 | `trace_id` | 有真实查询需求后再决定唯一性和索引 | 索引以第一阶段真实页面和 Admin 查询为依据,不为未来假设查询提前增加索引。 ## 6. 事务与并发 - Run 状态变更、状态事件和关联确认记录在同一事务内完成。 - 更新 Run 前锁定目标记录,并校验 `lock_version`。 - 事件序号在锁定 Run 后读取最大值并递增。 - 唯一约束捕获遗漏的并发冲突,并转换为领域冲突错误。 - 工具外部调用不持有数据库事务;开始和结束分别使用短事务。 - SQLite 不提供等价的行锁验证,PostgreSQL 集成测试必须覆盖双并发更新。 ## 7. 数据生命周期 - 用户资料可修改,保留最新值即可。 - Agent Run、事件、工具调用和人工确认属于审计数据,第一阶段不提供删除入口。 - 用户存在运行记录时不得物理删除,改为停用账户。 - 第一阶段不自动清理日志或审计记录。 - 后续建立保留周期时必须区分运行摘要、完整原始证据和应用日志,不能使用同一删除策略。 ## 8. 迁移顺序 1. 创建 `common` 基础抽象代码,不生成抽象表。 2. 创建 `accounts` 与 `UserProfile` 迁移。 3. 创建 `agent_runtime` 核心表和基础约束。 4. 单独迁移补充经验证的组合索引和检查约束。 5. 在空 SQLite 数据库执行完整迁移。 6. 确认 PostgreSQL 精确版本和隔离环境。 7. 在空 PostgreSQL 数据库执行完整迁移和核心约束测试。 迁移发布后不得直接修改历史迁移;修正通过新迁移完成。 ## 9. 回滚策略 - 第一阶段没有存量业务数据转换,回滚以撤销未发布迁移为主。 - 已发布环境回滚前必须确认表内是否已产生审计数据。 - 存在数据时禁止直接反向删除表,应先停止写入、导出验证数据并制定显式迁移。 - 应用代码回滚必须与数据库迁移兼容,不能先删除旧代码仍会读取的字段。 ## 10. 验证清单 - Django 迁移无遗漏。 - 空 SQLite 数据库全量迁移和反向迁移测试。 - 空 PostgreSQL 数据库全量迁移。 - 用户一对一资料唯一约束。 - Run 状态、非负数值和用户保护约束。 - 事件序号唯一约束。 - 工具调用编号和幂等键冲突。 - 人工确认请求键唯一约束。 - 两个并发状态更新只有一个成功。 - 主要列表查询使用预期索引;数据量不足时不声称完成性能验收。 ## 11. 待确认项 - PostgreSQL 精确版本、部署方式和连接池策略。 - 摘要字段的最大序列化字节数。 - 字符字段长度、费用精度和稳定约束名称。 - trace 标识是否需要全局唯一。 - PostgreSQL 版本确认后是否需要部分索引或其他专属优化。