Files
JobRadar/.craftkit/designs/engineering-baseline/database-design.md
T

11 KiB
Raw Blame History

reviewStatus, reviewedAt, replacedBy
reviewStatus reviewedAt replacedBy
pending null null

第一阶段工程基线数据库设计

1. 设计边界

本文档定义第一阶段用户资料和 Agent 运行审计数据的逻辑结构、约束、索引、迁移与回滚策略。开发和自动化测试使用 SQLite,集成与生产使用 PostgreSQL。

项目尚未确认 PostgreSQL 精确版本,因此本文档不采用版本专属字段、索引方法、表达式索引或方言 SQL。实现以 Django 6.0.8 ORM 和迁移能力表达;版本专属优化须在 PostgreSQL 版本确认后另行评审。

关联设计:

2. 设计原则

  • 用户私有数据必须具有明确的用户归属。
  • 状态转换由服务层执行,数据库约束负责守住唯一性和基础合法性。
  • 运行事件采用追加模式,保留审计轨迹。
  • JSON 字段只保存经过脱敏和大小限制的摘要。
  • 时间统一存储为支持时区的 Django 时间值,显示时转换到用户时区。
  • 金额、token 和耗时使用确定类型,避免浮点误差。
  • 表名、约束名和索引名在迁移中显式稳定,避免不同数据库自动命名差异影响排查。

3. 实体关系

erDiagram
    AUTH_USER ||--o| USER_PROFILE : has
    AUTH_USER ||--o{ AGENT_RUN : owns
    AUTH_USER ||--o{ MODEL_PROVIDER_CONFIG : 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、耗时和费用非负。

4.2.1 agent_runtime_model_provider_config

字段 类型建议 说明
owner_id ForeignKey(PROTECT) 用户私有归属
provider_code CharField 对应代码中的服务商稳定编码
encrypted_api_key TextField Fernet 密文,禁止通过页面或 Admin 展示
key_hint CharField 仅保存末四位提示
status、enabled、is_default 状态字段 连接状态和当前默认选择
default_model_id CharField 用户选择或预设推荐模型
available_models JSONField 最近一次验证取得的模型标识快照
last_verified_at、last_error_code 审计字段 验证时间和稳定错误码

唯一约束为 (owner_id, provider_code)。API Key 加密主密钥只从部署环境读取,不进入数据库;主密钥轮换必须先完成密文重加密,不能直接替换后重启。

跨字段状态不变量仍由服务层验证,因为 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 版本确认后是否需要部分索引或其他专属优化。