docs(engineering-baseline): 补充第一阶段落地设计
This commit is contained in:
@@ -0,0 +1,479 @@
|
|||||||
|
---
|
||||||
|
reviewStatus: pending
|
||||||
|
reviewedAt: null
|
||||||
|
replacedBy: null
|
||||||
|
---
|
||||||
|
|
||||||
|
# 第一阶段工程基线后端落地设计
|
||||||
|
|
||||||
|
## 1. 文档定位
|
||||||
|
|
||||||
|
本文档定义 JobRadar 第一阶段工程基线的后端落地边界,供后续模型设计、编码、迁移、测试和验收使用。本文档是待审核设计,不代表相关代码已经实现。
|
||||||
|
|
||||||
|
设计依据:
|
||||||
|
|
||||||
|
- [第一阶段工程基线开发计划](../../../docs/engineering-baseline/dev-plan.md)
|
||||||
|
- [架构设计](../../../docs/architecture.md)
|
||||||
|
- [Agent 契约](../../../docs/agent-contract.md)
|
||||||
|
- [AI 开发约定](../../../docs/development-guide.md)
|
||||||
|
|
||||||
|
当前技术基线为 Python 3.13、Django 6.0.8 和 OpenAI Agents SDK 0.22.0。项目没有已登记的 Django 公共 profile,实现时以当前项目规则和对应版本的官方契约为准。
|
||||||
|
|
||||||
|
## 2. 目标与范围
|
||||||
|
|
||||||
|
第一阶段将现有 Django 配置骨架扩展为一个可登录、可隔离、可审计、可记录 Agent 运行,但暂不执行真实岗位研究的模块化单体。
|
||||||
|
|
||||||
|
阶段完成后应具备:
|
||||||
|
|
||||||
|
- Django 内置用户的登录、退出及基础资料维护能力。
|
||||||
|
- 普通用户之间的数据归属隔离。
|
||||||
|
- Agent Run、运行事件、工具调用和人工确认的持久化能力。
|
||||||
|
- 合法的运行状态转换、事件顺序和幂等控制。
|
||||||
|
- OpenAI Agents SDK 的稳定适配入口及无外部费用的测试替身。
|
||||||
|
- 包含请求和运行关联标识的脱敏日志。
|
||||||
|
- SQLite 完整测试及 PostgreSQL 核心兼容验证能力。
|
||||||
|
|
||||||
|
第一阶段明确不实现:
|
||||||
|
|
||||||
|
- 招聘网站采集、企业调查、岗位标准化、筛选、评分和推荐报告。
|
||||||
|
- 真实岗位研究 Agent 循环或付费模型调用。
|
||||||
|
- Celery、Redis、定时调度和失败任务自动重试。
|
||||||
|
- 公开注册、复杂 RBAC、前后端分离、REST API 和独立前端框架。
|
||||||
|
- 自动投递简历、自动联系招聘人员或其他不可逆外部操作。
|
||||||
|
|
||||||
|
## 3. 总体调用关系
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
USER["普通用户"] --> AUTH["Django 登录与 Session"]
|
||||||
|
AUTH --> PROFILE["用户资料"]
|
||||||
|
AUTH --> RUN_VIEW["运行列表与详情"]
|
||||||
|
ADMIN["管理员"] --> ADMIN_SITE["Django Admin"]
|
||||||
|
ADMIN_SITE --> RUN_SERVICE["Agent Run 服务层"]
|
||||||
|
RUN_SERVICE --> RUN["AgentRun"]
|
||||||
|
RUN_SERVICE --> EVENT["AgentRunEvent"]
|
||||||
|
RUN_SERVICE --> TOOL["ToolCall"]
|
||||||
|
RUN_SERVICE --> APPROVAL["HumanApproval"]
|
||||||
|
SDK_ADAPTER["SDK Gateway / 测试替身"] --> RUN_SERVICE
|
||||||
|
```
|
||||||
|
|
||||||
|
所有页面、Admin 扩展和 SDK 适配器通过服务层改变运行状态,不直接拼装跨模型写入。
|
||||||
|
|
||||||
|
## 4. 模块职责
|
||||||
|
|
||||||
|
### 4.1 `common`
|
||||||
|
|
||||||
|
`common` 只提供跨业务复用的基础能力:
|
||||||
|
|
||||||
|
- 创建时间和更新时间抽象模型。
|
||||||
|
- 用户归属抽象模型及用户范围查询入口。
|
||||||
|
- 领域异常基类。
|
||||||
|
- 请求关联标识中间件。
|
||||||
|
- 日志上下文和敏感信息脱敏工具。
|
||||||
|
|
||||||
|
`common` 不包含账户、Agent 或未来岗位业务逻辑,也不依赖业务应用。
|
||||||
|
|
||||||
|
### 4.2 `accounts`
|
||||||
|
|
||||||
|
`accounts` 负责:
|
||||||
|
|
||||||
|
- Django 内置 `User` 的一对一扩展资料。
|
||||||
|
- 当前用户资料的读取和修改。
|
||||||
|
- 登录、退出及资料页面组织。
|
||||||
|
- 用户停用约定和资料管理后台。
|
||||||
|
|
||||||
|
第一阶段不自定义用户模型,不开放公开注册。用户由管理员创建,日常账户退出使用停用而非物理删除。
|
||||||
|
|
||||||
|
### 4.3 `agent_runtime`
|
||||||
|
|
||||||
|
`agent_runtime` 负责:
|
||||||
|
|
||||||
|
- Agent Run 生命周期和状态转换。
|
||||||
|
- 运行事件的有序追加。
|
||||||
|
- 工具调用、幂等键及结果摘要记录。
|
||||||
|
- 人工确认请求和处理结果。
|
||||||
|
- SDK 运行结果到本地持久化模型的适配。
|
||||||
|
- 运行列表、运行详情和管理后台。
|
||||||
|
|
||||||
|
该模块不拥有岗位、企业、筛选和评分数据。
|
||||||
|
|
||||||
|
### 4.4 依赖方向
|
||||||
|
|
||||||
|
```text
|
||||||
|
JobRadar 配置与 URL
|
||||||
|
↓
|
||||||
|
accounts ──────→ common
|
||||||
|
↓
|
||||||
|
agent_runtime ─→ common
|
||||||
|
↓
|
||||||
|
OpenAI Agents SDK 适配层
|
||||||
|
```
|
||||||
|
|
||||||
|
禁止 `common` 反向依赖业务应用,禁止 `accounts` 依赖 `agent_runtime`。
|
||||||
|
|
||||||
|
## 5. 领域对象与数据所有权
|
||||||
|
|
||||||
|
### 5.1 用户归属抽象模型
|
||||||
|
|
||||||
|
建议提供抽象模型 `UserOwnedModel`:
|
||||||
|
|
||||||
|
- `owner`:关联 Django 用户。
|
||||||
|
- `created_at`:创建时间。
|
||||||
|
- `updated_at`:更新时间。
|
||||||
|
|
||||||
|
规则:
|
||||||
|
|
||||||
|
- 所有用户私有模型必须继承该模型或提供等价的 `owner` 字段。
|
||||||
|
- 普通查询必须从 `owner=request.user` 的数据范围开始,不能先全表查询再在 Python 中校验。
|
||||||
|
- 审计数据对用户删除采用保护策略;包含历史运行记录的用户不得直接物理删除。
|
||||||
|
- 管理员跨用户查询仅允许出现在 Django Admin 或明确的管理服务中。
|
||||||
|
|
||||||
|
### 5.2 `UserProfile`
|
||||||
|
|
||||||
|
建议字段:
|
||||||
|
|
||||||
|
- `user`:与 Django `User` 一对一关联。
|
||||||
|
- `display_name`:可选显示名。
|
||||||
|
- `timezone`:默认 `Asia/Shanghai`。
|
||||||
|
- `created_at`、`updated_at`。
|
||||||
|
|
||||||
|
第一阶段不加入技能、薪资、地区和企业偏好。这些内容属于后续个人画像领域,应在需求明确后独立建模并支持版本化。
|
||||||
|
|
||||||
|
资料由账户服务显式 `get_or_create`,不依赖隐藏的 Signal 自动创建。
|
||||||
|
|
||||||
|
### 5.3 `AgentRun`
|
||||||
|
|
||||||
|
建议字段分组:
|
||||||
|
|
||||||
|
- 归属:`owner`。
|
||||||
|
- 标识与状态:主键、`title`、`status`、`lock_version`。
|
||||||
|
- 输入输出:`input_summary`、`output_summary`。
|
||||||
|
- 版本:`agent_name`、`agent_version`、`instruction_version`、`toolset_version`、`model_name`。
|
||||||
|
- 追踪:`trace_id`、`started_at`、`finished_at`、`duration_ms`。
|
||||||
|
- 用量:`input_tokens`、`output_tokens`、`estimated_cost`。
|
||||||
|
- 失败:`error_code`、`error_summary`。
|
||||||
|
- 审计:`created_at`、`updated_at`。
|
||||||
|
|
||||||
|
输入、输出和错误只保存经过脱敏、限制大小的摘要,不保存 API Key、密码、Cookie 或完整敏感工具参数。第一阶段不执行真实模型调用,因此 `model_name`、token 和费用字段允许为空。
|
||||||
|
|
||||||
|
### 5.4 `AgentRunEvent`
|
||||||
|
|
||||||
|
建议字段:
|
||||||
|
|
||||||
|
- `run`、`sequence`、`event_type`。
|
||||||
|
- `summary`、`payload_summary`。
|
||||||
|
- `occurred_at`、`created_at`。
|
||||||
|
|
||||||
|
约束:
|
||||||
|
|
||||||
|
- `(run, sequence)` 唯一。
|
||||||
|
- 默认按 Run 和序号升序读取。
|
||||||
|
- 事件作为审计记录追加,普通业务不得修改或删除。
|
||||||
|
|
||||||
|
事件类型至少包括:
|
||||||
|
|
||||||
|
- `run_created`、`run_started`、`run_paused`、`run_resumed`。
|
||||||
|
- `run_succeeded`、`run_failed`、`run_cancelled`。
|
||||||
|
- `tool_started`、`tool_completed`、`tool_failed`。
|
||||||
|
- `approval_requested`、`approval_resolved`。
|
||||||
|
|
||||||
|
### 5.5 `ToolCall`
|
||||||
|
|
||||||
|
建议字段分组:
|
||||||
|
|
||||||
|
- 归属:`run`、`call_id`。
|
||||||
|
- 工具:`tool_name`、`tool_version`、`idempotency_key`。
|
||||||
|
- 状态:`status`、`started_at`、`finished_at`、`duration_ms`。
|
||||||
|
- 摘要:`arguments_summary`、`result_summary`。
|
||||||
|
- 失败:`error_code`、`error_summary`。
|
||||||
|
- 审计:`created_at`、`updated_at`。
|
||||||
|
|
||||||
|
约束:
|
||||||
|
|
||||||
|
- `(run, call_id)` 唯一。
|
||||||
|
- 非空幂等键在明确的业务作用域内唯一。
|
||||||
|
- 已成功的相同幂等调用不得重复产生副作用。
|
||||||
|
- 第一阶段只验证记录能力,不实现真实采集工具。
|
||||||
|
|
||||||
|
### 5.6 `HumanApproval`
|
||||||
|
|
||||||
|
建议字段:
|
||||||
|
|
||||||
|
- `run`、`request_key`、`approval_type`、`status`。
|
||||||
|
- `request_summary`、`decision_summary`。
|
||||||
|
- `requested_at`、`resolved_at`、`resolved_by`。
|
||||||
|
- `created_at`、`updated_at`。
|
||||||
|
|
||||||
|
状态包括 `pending`、`approved`、`rejected`、`expired` 和 `cancelled`。
|
||||||
|
|
||||||
|
约束:
|
||||||
|
|
||||||
|
- `(run, request_key)` 唯一。
|
||||||
|
- 只有 `pending` 状态可以处理。
|
||||||
|
- `resolved_by` 必须是 Run 所属用户或具备管理权限的管理员。
|
||||||
|
- 第一阶段只在 Admin 中处理人工确认,不开发独立用户审批页面。
|
||||||
|
|
||||||
|
数据库字段类型、索引名和完整删除策略应在编码前通过数据库专项设计进一步确认。
|
||||||
|
|
||||||
|
## 6. Agent Run 状态机
|
||||||
|
|
||||||
|
运行状态:
|
||||||
|
|
||||||
|
- `pending`
|
||||||
|
- `running`
|
||||||
|
- `waiting_approval`
|
||||||
|
- `succeeded`
|
||||||
|
- `failed`
|
||||||
|
- `cancelled`
|
||||||
|
|
||||||
|
允许的转换:
|
||||||
|
|
||||||
|
| 当前状态 | 可转换状态 |
|
||||||
|
| --- | --- |
|
||||||
|
| `pending` | `running`、`cancelled` |
|
||||||
|
| `running` | `waiting_approval`、`succeeded`、`failed`、`cancelled` |
|
||||||
|
| `waiting_approval` | `running`、`failed`、`cancelled` |
|
||||||
|
| `succeeded` | 无 |
|
||||||
|
| `failed` | 无 |
|
||||||
|
| `cancelled` | 无 |
|
||||||
|
|
||||||
|
状态规则:
|
||||||
|
|
||||||
|
- 终态不可再次转换。
|
||||||
|
- 成功和失败必须记录完成时间;失败还必须记录脱敏错误摘要。
|
||||||
|
- 进入 `waiting_approval` 时必须在同一事务中创建待处理的 `HumanApproval` 和对应事件。
|
||||||
|
- 确认通过后才能恢复运行;确认拒绝默认将 Run 置为 `cancelled`。
|
||||||
|
- 状态转换和对应事件必须在同一事务中提交。
|
||||||
|
- 第一阶段不支持失败 Run 原地重试;后续重试应创建新 Run 并关联原 Run。
|
||||||
|
|
||||||
|
## 7. 服务层设计
|
||||||
|
|
||||||
|
### 7.1 账户服务
|
||||||
|
|
||||||
|
建议职责:
|
||||||
|
|
||||||
|
- 获取或显式创建当前用户资料。
|
||||||
|
- 修改当前用户自己的资料。
|
||||||
|
- 由管理员停用指定用户。
|
||||||
|
|
||||||
|
普通用户请求其他用户资料时按资源不存在处理,避免泄露目标用户是否存在。
|
||||||
|
|
||||||
|
### 7.2 Agent Run 服务
|
||||||
|
|
||||||
|
服务层应提供以下原子能力:
|
||||||
|
|
||||||
|
- 创建 Run。
|
||||||
|
- 开始、完成、失败或取消 Run。
|
||||||
|
- 追加运行事件。
|
||||||
|
- 开始、完成或失败一次工具调用。
|
||||||
|
- 创建人工确认请求。
|
||||||
|
- 处理人工确认结果。
|
||||||
|
|
||||||
|
每个状态写方法按统一顺序执行:
|
||||||
|
|
||||||
|
1. 校验操作者身份、用户归属或管理权限。
|
||||||
|
2. 锁定需要修改的记录。
|
||||||
|
3. 校验当前状态和目标状态。
|
||||||
|
4. 修改主记录。
|
||||||
|
5. 追加不可变事件或更新关联记录。
|
||||||
|
6. 提交事务后再触发任何外部操作。
|
||||||
|
|
||||||
|
## 8. 事务、并发与一致性
|
||||||
|
|
||||||
|
关键状态变更使用 `transaction.atomic()`。
|
||||||
|
|
||||||
|
同一 Run 的并发控制策略:
|
||||||
|
|
||||||
|
- PostgreSQL 使用行锁串行化状态更新。
|
||||||
|
- `lock_version` 提供乐观并发检测。
|
||||||
|
- 事件序号在锁定 Run 后生成。
|
||||||
|
- `(run, sequence)` 唯一约束作为最后一致性防线。
|
||||||
|
- SQLite 测试只验证业务约束,不能代替 PostgreSQL 行锁与并发行为验证。
|
||||||
|
|
||||||
|
外部 SDK 或工具调用不得包裹在数据库长事务中:
|
||||||
|
|
||||||
|
```text
|
||||||
|
事务 1:登记调用开始 → 提交
|
||||||
|
外部调用:不持有数据库事务
|
||||||
|
事务 2:登记成功或失败 → 更新 Run → 追加事件 → 提交
|
||||||
|
```
|
||||||
|
|
||||||
|
该边界避免网络或模型调用长期占用数据库连接和行锁。
|
||||||
|
|
||||||
|
## 9. SDK 适配边界
|
||||||
|
|
||||||
|
第一阶段只建立 SDK 适配协议和测试替身:
|
||||||
|
|
||||||
|
- `AgentExecutionRequest`:本地运行编号、用户编号、版本和预算摘要。
|
||||||
|
- `AgentExecutionResult`:状态、输出摘要、trace 标识、用量和错误摘要。
|
||||||
|
- `AgentRunnerGateway`:运行入口协议。
|
||||||
|
- `StubAgentRunnerGateway`:自动化测试替身。
|
||||||
|
- `OpenAIAgentRunnerGateway`:真实 SDK 适配位置,岗位研究逻辑留到第二阶段。
|
||||||
|
|
||||||
|
约束:
|
||||||
|
|
||||||
|
- 未配置 OpenAI API Key 时,登录、资料、Admin 和运行查询仍应正常工作。
|
||||||
|
- 只有调用真实 SDK Gateway 时才检查 API Key。
|
||||||
|
- API Key 不进入运行上下文、数据库或日志。
|
||||||
|
- 第一阶段不接入 Celery,也不在 Web 请求内执行长时间 Agent Run。
|
||||||
|
- 使用测试替身验证运行开始、事件记录、成功和失败链路。
|
||||||
|
|
||||||
|
Celery 是目标架构中的后续运行载体;第一阶段仅稳定持久化和适配边界,两者不冲突。
|
||||||
|
|
||||||
|
## 10. 页面、权限与错误语义
|
||||||
|
|
||||||
|
建议路由:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/accounts/login/
|
||||||
|
/accounts/logout/
|
||||||
|
/accounts/profile/
|
||||||
|
/runs/
|
||||||
|
/runs/<uuid>/
|
||||||
|
```
|
||||||
|
|
||||||
|
访问规则:
|
||||||
|
|
||||||
|
- 未登录用户访问资料和 Run 页面时跳转到登录页。
|
||||||
|
- 普通用户查询始终限定 `owner=request.user`。
|
||||||
|
- 跨用户访问 Run 统一返回 404,避免暴露资源存在性。
|
||||||
|
- 资料修改使用 POST 并启用 CSRF。
|
||||||
|
- Run 列表分页并按创建时间倒序。
|
||||||
|
- Run 详情按事件序号展示事件和工具调用摘要。
|
||||||
|
- 第一阶段不提供公开注册、账户自助删除或 HTTP API。
|
||||||
|
|
||||||
|
Admin 规则:
|
||||||
|
|
||||||
|
- 管理员可以维护用户资料并查看全部 Agent Run。
|
||||||
|
- 运行事件和完成后的工具调用原则上只读。
|
||||||
|
- Admin 中展示的参数和结果同样必须脱敏。
|
||||||
|
|
||||||
|
领域错误分类:
|
||||||
|
|
||||||
|
- `ResourceNotFound`:资源不存在或无权访问,页面响应为 404。
|
||||||
|
- `ValidationError`:输入不合法,显示表单错误或返回 400。
|
||||||
|
- `InvalidStateTransition`:运行状态冲突,语义为 409。
|
||||||
|
- `DuplicateOperation`:重复操作或幂等冲突,语义为 409。
|
||||||
|
- `AgentConfigurationError`:SDK 配置缺失,明确提示该功能不可用。
|
||||||
|
- `ExternalServiceError`:外部调用失败,保存脱敏错误并将 Run 置为失败。
|
||||||
|
|
||||||
|
用户响应不得包含堆栈、数据库信息、完整外部响应或敏感配置。
|
||||||
|
|
||||||
|
## 11. 日志与审计
|
||||||
|
|
||||||
|
增加请求关联标识中间件:
|
||||||
|
|
||||||
|
- 接受格式合法的入站关联标识,否则生成新标识。
|
||||||
|
- 将关联标识加入响应头和日志上下文。
|
||||||
|
- Agent 日志同时携带 `run_id`、`trace_id` 和 `tool_call_id`。
|
||||||
|
- 用户相关日志只记录内部用户编号。
|
||||||
|
|
||||||
|
必须记录:
|
||||||
|
|
||||||
|
- 登录失败和账户停用。
|
||||||
|
- Run 创建及每次状态转换。
|
||||||
|
- 工具调用开始、完成和失败。
|
||||||
|
- 人工确认请求及处理结果。
|
||||||
|
- 非法状态转换和跨用户访问尝试。
|
||||||
|
|
||||||
|
禁止记录:
|
||||||
|
|
||||||
|
- API Key、密码和 Session Cookie。
|
||||||
|
- 招聘网站完整 Cookie。
|
||||||
|
- 未脱敏的工具参数。
|
||||||
|
- 模型返回的完整敏感内容。
|
||||||
|
|
||||||
|
## 12. 实施顺序
|
||||||
|
|
||||||
|
1. 创建 `common`,实现时间戳、用户归属和领域异常。
|
||||||
|
2. 创建 `accounts`,实现 `UserProfile`、Admin、资料服务和迁移。
|
||||||
|
3. 增加登录、退出、资料页面和用户隔离测试。
|
||||||
|
4. 创建 `agent_runtime` 的枚举、模型、约束和迁移。
|
||||||
|
5. 实现 Run 状态、事件序号、工具调用和人工确认服务。
|
||||||
|
6. 增加 Agent 运行 Admin,并限制审计记录修改。
|
||||||
|
7. 实现 Run 列表、详情页面和访问控制。
|
||||||
|
8. 建立 SDK Gateway、测试替身和配置边界。
|
||||||
|
9. 增加请求关联标识、日志上下文和日志脱敏。
|
||||||
|
10. 执行 SQLite 全量验证。
|
||||||
|
11. 在 PostgreSQL 空库执行迁移及核心约束和并发验证。
|
||||||
|
12. 同步 README、路线图和第一阶段状态。
|
||||||
|
|
||||||
|
每一步都应保持可迁移、可测试,避免在单次迁移中同时承载全部模型。
|
||||||
|
|
||||||
|
## 13. 测试与验收策略
|
||||||
|
|
||||||
|
自动化测试至少覆盖:
|
||||||
|
|
||||||
|
- 用户资料首次创建和重复获取。
|
||||||
|
- 未登录访问拒绝。
|
||||||
|
- 用户只能读取和修改自己的资料。
|
||||||
|
- 用户 A 查询用户 B 的 Run 返回 404。
|
||||||
|
- 管理员能够查看全部运行记录。
|
||||||
|
- 所有合法和非法状态转换。
|
||||||
|
- 终态不可修改。
|
||||||
|
- 并发状态更新只能有一个成功。
|
||||||
|
- 事件序号连续且唯一。
|
||||||
|
- 工具调用幂等键冲突。
|
||||||
|
- 工具调用成功、失败和超时记录。
|
||||||
|
- 人工确认只能处理一次且处理人权限正确。
|
||||||
|
- 敏感字段不会写入日志和摘要。
|
||||||
|
- 未配置 API Key 时非 Agent 页面正常。
|
||||||
|
- SDK 测试替身的成功、失败和异常链路。
|
||||||
|
- SQLite 迁移和全量测试。
|
||||||
|
- PostgreSQL 空库迁移、唯一约束和并发验证。
|
||||||
|
|
||||||
|
阶段验收命令沿用开发计划:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
python manage.py check
|
||||||
|
python manage.py check --deploy --settings=JobRadar.settings.production
|
||||||
|
python manage.py makemigrations --check --dry-run
|
||||||
|
python manage.py migrate
|
||||||
|
pytest
|
||||||
|
ruff check .
|
||||||
|
```
|
||||||
|
|
||||||
|
生产配置检查需要注入非秘密的验证用配置和隔离的数据库参数,不得连接生产库执行测试。
|
||||||
|
|
||||||
|
## 14. 兼容、迁移与回滚
|
||||||
|
|
||||||
|
- 新应用按 `common`、`accounts`、`agent_runtime` 的依赖顺序生成迁移。
|
||||||
|
- 模型和约束同时兼容 SQLite 与 PostgreSQL,不使用数据库方言专属 SQL。
|
||||||
|
- 每组迁移先在空 SQLite 数据库验证,再在空 PostgreSQL 数据库验证。
|
||||||
|
- 第一阶段没有既有业务数据迁移,不提供破坏性数据转换。
|
||||||
|
- 单步实现失败时回滚对应代码和未发布迁移;不得通过修改已发布迁移掩盖问题。
|
||||||
|
- 外部 SDK 未配置或不可用时关闭真实执行入口,不影响认证、资料和运行查询。
|
||||||
|
|
||||||
|
## 15. 风险与待确认项
|
||||||
|
|
||||||
|
以下事项不阻塞第一阶段编码,但必须在对应节点前确认:
|
||||||
|
|
||||||
|
| 事项 | 当前建议 | 最迟确认时间 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| PostgreSQL 实例位置 | 本地开发继续使用 SQLite | PostgreSQL 集成验证前 |
|
||||||
|
| OpenAI 模型与预算 | 第一阶段不固定付费模型 | 第二阶段启动前 |
|
||||||
|
| API Key 注入 | 仅使用环境变量或部署平台密钥 | 真实调用前 |
|
||||||
|
| 用户物理删除 | 默认禁止,使用停用代替 | 开放账户管理能力前 |
|
||||||
|
| 摘要最大长度 | 编码前给出统一上限 | 模型详细设计时 |
|
||||||
|
| 日志和审计保留周期 | 暂不自动清理 | 公网部署前 |
|
||||||
|
| 人工确认超时 | 第一阶段仅支持手动取消 | 第二阶段运行设计时 |
|
||||||
|
|
||||||
|
## 16. 实现交接清单
|
||||||
|
|
||||||
|
编码前应进一步固化:
|
||||||
|
|
||||||
|
- 使用数据库设计明确字段类型、索引、约束名和删除策略。
|
||||||
|
- 如需 HTTP API,再使用 API 设计明确端点和响应契约;第一阶段默认只提供 Django 页面。
|
||||||
|
- 确认 `common`、`accounts`、`agent_runtime` 的应用包名和 URL 命名空间。
|
||||||
|
- 确认摘要长度、JSON 大小限制和日志脱敏词表。
|
||||||
|
- 确认 PostgreSQL 集成验证环境。
|
||||||
|
|
||||||
|
推荐实现结论:
|
||||||
|
|
||||||
|
- 使用 Django 内置用户和一对一 `UserProfile`。
|
||||||
|
- 使用 `common`、`accounts`、`agent_runtime` 三个应用。
|
||||||
|
- 由服务层统一权限检查、状态转换和审计写入。
|
||||||
|
- 运行事件采用不可变追加模式。
|
||||||
|
- 数据库事务与外部调用分离。
|
||||||
|
- SDK 使用 Gateway 和测试替身建立稳定边界。
|
||||||
|
- 第一阶段不引入 Celery、DRF、Vue 或真实模型调用。
|
||||||
@@ -0,0 +1,224 @@
|
|||||||
|
---
|
||||||
|
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 版本确认后是否需要部分索引或其他专属优化。
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
---
|
||||||
|
reviewStatus: pending
|
||||||
|
reviewedAt: null
|
||||||
|
replacedBy: null
|
||||||
|
---
|
||||||
|
|
||||||
|
# 第一阶段工程基线前端落地设计
|
||||||
|
|
||||||
|
## 1. 文档定位
|
||||||
|
|
||||||
|
本文档定义第一阶段 Django 服务端页面的页面结构、路由、交互、状态、权限与可访问性边界。当前项目没有独立前端框架或组件库,因此本阶段使用 Django Templates、Django Forms 和少量原生 CSS,不引入 Vue、React、前端状态库或前后端分离架构。
|
||||||
|
|
||||||
|
关联设计:
|
||||||
|
|
||||||
|
- [后端落地设计](backend-design.md)
|
||||||
|
- [数据库设计](database-design.md)
|
||||||
|
- [接口与页面契约设计](interface-design.md)
|
||||||
|
- [第一阶段工程基线开发计划](../../../docs/engineering-baseline/dev-plan.md)
|
||||||
|
|
||||||
|
## 2. 用户角色与核心场景
|
||||||
|
|
||||||
|
### 2.1 未登录访问者
|
||||||
|
|
||||||
|
- 可以进入登录页。
|
||||||
|
- 访问个人资料和运行页面时跳转登录页。
|
||||||
|
- 不提供公开注册入口。
|
||||||
|
|
||||||
|
### 2.2 普通用户
|
||||||
|
|
||||||
|
- 登录和退出系统。
|
||||||
|
- 查看、修改自己的基础资料。
|
||||||
|
- 查看自己的 Agent Run 列表。
|
||||||
|
- 查看自己的 Agent Run 详情、事件和工具调用摘要。
|
||||||
|
- 不能查看其他用户的数据,也不能从页面执行真实 Agent 任务。
|
||||||
|
|
||||||
|
### 2.3 管理员
|
||||||
|
|
||||||
|
- 使用 Django Admin 创建和停用用户。
|
||||||
|
- 查看全部用户资料和 Agent 运行记录。
|
||||||
|
- 创建用于验证持久化链路的最小 Run。
|
||||||
|
- 在 Admin 中处理待确认记录。
|
||||||
|
|
||||||
|
## 3. 页面与路由
|
||||||
|
|
||||||
|
| 页面 | 路由 | 访问角色 | 主要操作 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 登录 | `/accounts/login/` | 未登录用户 | 提交用户名和密码 |
|
||||||
|
| 退出 | `/accounts/logout/` | 已登录用户 | POST 确认退出 |
|
||||||
|
| 个人资料 | `/accounts/profile/` | 普通用户、管理员 | 查看和修改自己的资料 |
|
||||||
|
| 运行列表 | `/runs/` | 普通用户、管理员 | 查看当前用户的运行记录 |
|
||||||
|
| 运行详情 | `/runs/<uuid>/` | 记录所属用户、管理员 | 查看状态、事件和工具调用摘要 |
|
||||||
|
| 管理后台 | `/admin/` | 管理员 | 管理用户和审计记录 |
|
||||||
|
|
||||||
|
登录成功默认进入运行列表;退出成功返回登录页。详情页返回列表时保留原分页参数,非法或越权的运行编号统一展示 404 页面。
|
||||||
|
|
||||||
|
## 4. 页面结构
|
||||||
|
|
||||||
|
### 4.1 全局布局
|
||||||
|
|
||||||
|
建立一个全局基础模板,结构包括:
|
||||||
|
|
||||||
|
- 跳转到主要内容的无障碍链接。
|
||||||
|
- 产品名称和主导航。
|
||||||
|
- 当前用户标识。
|
||||||
|
- 运行列表、个人资料和退出入口。
|
||||||
|
- 页面级消息区域。
|
||||||
|
- 主内容区域。
|
||||||
|
|
||||||
|
退出必须使用 POST 表单,不使用可被预加载或误触发的 GET 链接。
|
||||||
|
|
||||||
|
### 4.2 登录页
|
||||||
|
|
||||||
|
页面内容:
|
||||||
|
|
||||||
|
- 用户名输入框。
|
||||||
|
- 密码输入框。
|
||||||
|
- 登录按钮。
|
||||||
|
- 表单级错误和字段级错误。
|
||||||
|
|
||||||
|
登录失败时不区分“用户不存在”和“密码错误”,避免泄露账户信息。密码字段不得回显。
|
||||||
|
|
||||||
|
### 4.3 个人资料页
|
||||||
|
|
||||||
|
字段:
|
||||||
|
|
||||||
|
- 用户名:只读。
|
||||||
|
- 显示名:可编辑。
|
||||||
|
- 时区:第一阶段使用受控选择项,默认 `Asia/Shanghai`。
|
||||||
|
|
||||||
|
提交成功后采用 POST/Redirect/GET,刷新页面不会重复提交。并发更新暂不提供复杂冲突合并,后端仍必须校验当前用户归属。
|
||||||
|
|
||||||
|
### 4.4 Agent Run 列表页
|
||||||
|
|
||||||
|
每条记录展示:
|
||||||
|
|
||||||
|
- 标题或简短运行标识。
|
||||||
|
- 当前状态。
|
||||||
|
- Agent 名称和版本摘要。
|
||||||
|
- 创建、开始和结束时间。
|
||||||
|
- 运行耗时。
|
||||||
|
- 是否存在待处理人工确认。
|
||||||
|
|
||||||
|
列表按创建时间倒序分页。第一阶段没有运行记录时展示明确空状态,不显示“创建任务”按钮,避免暗示真实 Agent 功能已开放。
|
||||||
|
|
||||||
|
### 4.5 Agent Run 详情页
|
||||||
|
|
||||||
|
页面分为:
|
||||||
|
|
||||||
|
1. 运行概览:状态、标题、版本、开始和结束时间、用量摘要。
|
||||||
|
2. 结果摘要:只展示已脱敏的结构化摘要。
|
||||||
|
3. 运行时间线:按事件序号升序展示。
|
||||||
|
4. 工具调用:名称、状态、耗时、参数摘要、结果或错误摘要。
|
||||||
|
5. 人工确认:只读展示当前状态;第一阶段由 Admin 处理。
|
||||||
|
|
||||||
|
详情页不展示 API Key、Cookie、密码、完整工具参数或原始模型敏感内容。
|
||||||
|
|
||||||
|
## 5. 模板复用边界
|
||||||
|
|
||||||
|
建议模板层级:
|
||||||
|
|
||||||
|
```text
|
||||||
|
templates/
|
||||||
|
├── base.html
|
||||||
|
├── registration/
|
||||||
|
│ └── login.html
|
||||||
|
├── accounts/
|
||||||
|
│ └── profile.html
|
||||||
|
├── agent_runtime/
|
||||||
|
│ ├── run_list.html
|
||||||
|
│ └── run_detail.html
|
||||||
|
└── errors/
|
||||||
|
├── 403.html
|
||||||
|
├── 404.html
|
||||||
|
└── 500.html
|
||||||
|
```
|
||||||
|
|
||||||
|
复用片段仅在存在稳定复用时抽取:
|
||||||
|
|
||||||
|
- 状态徽标。
|
||||||
|
- 分页导航。
|
||||||
|
- 表单错误摘要。
|
||||||
|
- 时间线事件项。
|
||||||
|
|
||||||
|
第一阶段不建立通用组件系统,也不为了文件数量提前抽象宏或模板标签库。
|
||||||
|
|
||||||
|
## 6. 状态与数据所有权
|
||||||
|
|
||||||
|
服务端拥有所有业务和权限状态,页面不保存跨请求客户端状态。
|
||||||
|
|
||||||
|
| 状态类型 | 所有者 | 页面行为 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 登录状态 | Django Session | 未登录时跳转登录 |
|
||||||
|
| 用户资料 | `accounts` 服务 | GET 回显,POST 校验和保存 |
|
||||||
|
| Run 列表与详情 | `agent_runtime` 查询服务 | 仅返回当前用户范围 |
|
||||||
|
| 分页状态 | URL 查询参数 | 可复制、可返回 |
|
||||||
|
| 表单错误 | Django Form | 同页字段级与全局提示 |
|
||||||
|
| 消息反馈 | Django Messages | 重定向后展示一次 |
|
||||||
|
|
||||||
|
页面只接收格式化后的视图模型,不在模板中执行权限判断、状态转换或复杂数据加工。
|
||||||
|
|
||||||
|
## 7. 加载、空、错误和权限状态
|
||||||
|
|
||||||
|
- 服务端页面首屏不引入异步加载骨架。
|
||||||
|
- 空列表显示原因和当前阶段说明。
|
||||||
|
- 表单校验失败保留非敏感输入并聚焦错误摘要。
|
||||||
|
- 资源不存在和跨用户访问统一显示 404。
|
||||||
|
- 服务端异常显示通用错误页,并提供返回安全页面的入口。
|
||||||
|
- SDK 配置缺失不能阻止登录、资料和历史 Run 查询。
|
||||||
|
- 页面不得把后端异常堆栈直接呈现给用户。
|
||||||
|
|
||||||
|
## 8. 响应式和可访问性
|
||||||
|
|
||||||
|
- 页面以单列内容为主,在宽屏下限制最大阅读宽度。
|
||||||
|
- Run 详情中的宽表格在窄屏改为定义列表或允许局部横向滚动。
|
||||||
|
- 所有表单字段必须具有可关联的 `label`、帮助文本和错误描述。
|
||||||
|
- 当前导航项提供可感知状态,不只依赖颜色区分。
|
||||||
|
- 状态徽标同时包含文本。
|
||||||
|
- 焦点样式不可移除,键盘可以访问所有操作。
|
||||||
|
- 标题层级连续,每页只有一个主标题。
|
||||||
|
- 时间使用语义化 `<time>` 并提供完整时间值。
|
||||||
|
|
||||||
|
## 9. 安全与隐私
|
||||||
|
|
||||||
|
- 所有写操作使用 POST 和 CSRF 防护。
|
||||||
|
- 登录后重定向参数只允许站内安全地址。
|
||||||
|
- 模板启用默认转义,不使用未经审查的 `safe` 输出。
|
||||||
|
- 页面只显示脱敏摘要。
|
||||||
|
- 不在 URL、HTML 注释或前端脚本中包含密钥和敏感参数。
|
||||||
|
- 跨用户访问由查询层限制,模板隐藏按钮不能替代后端权限校验。
|
||||||
|
|
||||||
|
## 10. 验证清单
|
||||||
|
|
||||||
|
- 登录成功、登录失败和安全重定向。
|
||||||
|
- 未登录访问受保护页面。
|
||||||
|
- 个人资料成功保存和校验失败。
|
||||||
|
- 两个普通用户之间的资料和 Run 隔离。
|
||||||
|
- 运行列表空状态、单页和多页数据。
|
||||||
|
- 运行详情事件顺序及敏感字段不展示。
|
||||||
|
- 管理员后台访问边界。
|
||||||
|
- CSRF 拒绝路径。
|
||||||
|
- 键盘导航、焦点、标签和错误关联。
|
||||||
|
- 常见桌面和窄屏宽度下的真实浏览器检查。
|
||||||
|
|
||||||
|
未执行真实浏览器和辅助技术测试前,不得宣称前端交互验收通过。
|
||||||
|
|
||||||
|
## 11. 待确认项
|
||||||
|
|
||||||
|
- 产品视觉标识、颜色和字体尚未确定;第一阶段使用简洁系统字体和高对比度基础样式。
|
||||||
|
- 是否允许普通用户处理人工确认留到第二阶段决定。
|
||||||
|
- 运行列表默认分页大小应在实现时结合样例数据确定。
|
||||||
|
- 时区候选范围需在表单实现前明确,不能接受任意未校验字符串。
|
||||||
@@ -0,0 +1,234 @@
|
|||||||
|
---
|
||||||
|
reviewStatus: pending
|
||||||
|
reviewedAt: null
|
||||||
|
replacedBy: null
|
||||||
|
---
|
||||||
|
|
||||||
|
# 第一阶段工程基线接口与页面契约设计
|
||||||
|
|
||||||
|
## 1. 设计范围
|
||||||
|
|
||||||
|
第一阶段不采用 Django REST Framework,也不提供公开 JSON API 或 OpenAPI 契约。本设计只定义浏览器访问的服务端页面 HTTP 契约,以及页面、Admin、Agent SDK 适配器调用的内部服务契约。
|
||||||
|
|
||||||
|
如果后续出现前后端分离、第三方调用或移动端需求,应重新执行正式 API 设计,不直接把本阶段内部服务暴露为外部 API。
|
||||||
|
|
||||||
|
关联设计:
|
||||||
|
|
||||||
|
- [后端落地设计](backend-design.md)
|
||||||
|
- [前端落地设计](frontend-design.md)
|
||||||
|
- [数据库设计](database-design.md)
|
||||||
|
|
||||||
|
## 2. 通用 HTTP 规则
|
||||||
|
|
||||||
|
- 用户认证使用 Django Session。
|
||||||
|
- 所有状态修改请求使用 POST 并验证 CSRF。
|
||||||
|
- GET 请求不得产生业务状态变更。
|
||||||
|
- 成功写入后使用 POST/Redirect/GET。
|
||||||
|
- 未登录访问受保护页面时跳转登录页,并携带安全的站内返回地址。
|
||||||
|
- 普通用户访问其他用户资源时返回 404,不暴露资源存在性。
|
||||||
|
- 表单输入错误返回原页面和字段错误,响应状态按 Django 页面约定实现。
|
||||||
|
- 意外异常返回通用错误页面,日志使用请求关联标识定位。
|
||||||
|
- 响应不得包含堆栈、数据库错误、密钥、Cookie 或未脱敏工具参数。
|
||||||
|
|
||||||
|
## 3. 页面端点
|
||||||
|
|
||||||
|
### 3.1 登录
|
||||||
|
|
||||||
|
`GET /accounts/login/`
|
||||||
|
|
||||||
|
- 返回登录表单。
|
||||||
|
- 已登录用户可重定向到运行列表。
|
||||||
|
|
||||||
|
`POST /accounts/login/`
|
||||||
|
|
||||||
|
- 输入:用户名、密码、可选站内 `next`。
|
||||||
|
- 成功:建立 Session,重定向到安全 `next` 或运行列表。
|
||||||
|
- 失败:返回登录页和统一认证错误,不区分用户名或密码错误。
|
||||||
|
|
||||||
|
### 3.2 退出
|
||||||
|
|
||||||
|
`POST /accounts/logout/`
|
||||||
|
|
||||||
|
- 前置条件:已登录。
|
||||||
|
- 成功:清除 Session,重定向登录页。
|
||||||
|
- 不提供 GET 退出。
|
||||||
|
|
||||||
|
### 3.3 个人资料
|
||||||
|
|
||||||
|
`GET /accounts/profile/`
|
||||||
|
|
||||||
|
- 前置条件:已登录。
|
||||||
|
- 返回当前用户的用户名、显示名和时区。
|
||||||
|
- 不接受目标用户编号参数。
|
||||||
|
|
||||||
|
`POST /accounts/profile/`
|
||||||
|
|
||||||
|
- 前置条件:已登录、CSRF 有效。
|
||||||
|
- 输入:显示名、时区。
|
||||||
|
- 成功:保存当前用户资料并重定向到资料页。
|
||||||
|
- 失败:原页显示字段错误,不保存部分数据。
|
||||||
|
|
||||||
|
### 3.4 Agent Run 列表
|
||||||
|
|
||||||
|
`GET /runs/`
|
||||||
|
|
||||||
|
- 前置条件:已登录。
|
||||||
|
- 查询参数:`page`,其他未知参数忽略或按统一规则拒绝。
|
||||||
|
- 返回当前用户拥有的 Run,按创建时间倒序分页。
|
||||||
|
- 管理员在普通站点页面仍默认只看自己的 Run;跨用户管理使用 Admin。
|
||||||
|
|
||||||
|
### 3.5 Agent Run 详情
|
||||||
|
|
||||||
|
`GET /runs/<uuid:run_id>/`
|
||||||
|
|
||||||
|
- 前置条件:已登录。
|
||||||
|
- 返回 Run 概览、有序事件、工具调用摘要和人工确认状态。
|
||||||
|
- 目标不存在或不属于当前用户时返回相同的 404。
|
||||||
|
- 页面端点不提供状态更新能力。
|
||||||
|
|
||||||
|
### 3.6 管理后台
|
||||||
|
|
||||||
|
`/admin/` 沿用 Django Admin 的认证和权限体系。
|
||||||
|
|
||||||
|
- 用户资料和 Run 主记录按配置开放管理能力。
|
||||||
|
- 事件和完成的工具调用设置为只读或限制修改。
|
||||||
|
- 人工确认处理必须调用领域服务,不能只修改单个状态字段。
|
||||||
|
|
||||||
|
## 4. 表单契约
|
||||||
|
|
||||||
|
### 4.1 登录表单
|
||||||
|
|
||||||
|
| 字段 | 必填 | 规则 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `username` | 是 | 使用 Django 认证表单规则 |
|
||||||
|
| `password` | 是 | 不回显、不写日志 |
|
||||||
|
| `next` | 否 | 只允许站内安全路径 |
|
||||||
|
|
||||||
|
### 4.2 用户资料表单
|
||||||
|
|
||||||
|
| 字段 | 必填 | 规则 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `display_name` | 否 | 去除首尾空白,长度上限由模型统一定义 |
|
||||||
|
| `timezone` | 是 | 必须来自服务端受控候选 |
|
||||||
|
|
||||||
|
模型约束、表单约束和服务校验必须保持一致,不能只依赖浏览器端校验。
|
||||||
|
|
||||||
|
## 5. 内部服务契约
|
||||||
|
|
||||||
|
内部服务只接受明确的操作者和标识,不接受未经限定的 QuerySet。
|
||||||
|
|
||||||
|
### 5.1 账户服务
|
||||||
|
|
||||||
|
| 操作 | 输入 | 输出 | 失败语义 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 获取资料 | 当前用户 | `UserProfile` | 用户无效 |
|
||||||
|
| 更新资料 | 当前用户、已校验数据 | 更新后资料 | 校验失败、并发冲突 |
|
||||||
|
| 停用用户 | 管理员、目标用户 | 停用结果 | 无权限、目标不存在 |
|
||||||
|
|
||||||
|
### 5.2 Run 查询服务
|
||||||
|
|
||||||
|
| 操作 | 输入 | 输出 | 权限规则 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 查询列表 | 当前用户、分页参数 | 分页 Run | 强制用户归属过滤 |
|
||||||
|
| 查询详情 | 当前用户、Run UUID | Run 详情视图模型 | 越权与不存在统一处理 |
|
||||||
|
|
||||||
|
### 5.3 Run 命令服务
|
||||||
|
|
||||||
|
| 操作 | 关键输入 | 关键输出 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 创建 Run | 所属用户、脱敏输入摘要、版本 | 新 Run 和创建事件 |
|
||||||
|
| 开始 Run | Run 标识、期望版本 | `running` Run 和开始事件 |
|
||||||
|
| 完成 Run | Run 标识、脱敏输出、用量 | `succeeded` Run 和完成事件 |
|
||||||
|
| 失败 Run | Run 标识、错误码、脱敏摘要 | `failed` Run 和失败事件 |
|
||||||
|
| 取消 Run | 操作者、Run 标识 | `cancelled` Run 和取消事件 |
|
||||||
|
| 请求确认 | Run、请求键、类型、摘要 | 待处理确认和暂停事件 |
|
||||||
|
| 处理确认 | 操作者、确认标识、决定 | 确认结果及 Run 状态变更 |
|
||||||
|
|
||||||
|
命令服务必须显式返回更新后的领域对象或结果对象,不依赖调用方猜测数据库状态。
|
||||||
|
|
||||||
|
## 6. SDK Gateway 契约
|
||||||
|
|
||||||
|
### 6.1 请求模型
|
||||||
|
|
||||||
|
`AgentExecutionRequest` 至少包含:
|
||||||
|
|
||||||
|
- `agent_run_id`
|
||||||
|
- `user_id`
|
||||||
|
- `agent_name`
|
||||||
|
- `agent_version`
|
||||||
|
- `instruction_version`
|
||||||
|
- `toolset_version`
|
||||||
|
- 脱敏运行输入
|
||||||
|
- 最大轮次、时间和工具调用预算
|
||||||
|
|
||||||
|
不包含 API Key、网站密码和 Cookie。
|
||||||
|
|
||||||
|
### 6.2 结果模型
|
||||||
|
|
||||||
|
`AgentExecutionResult` 至少包含:
|
||||||
|
|
||||||
|
- 结果状态。
|
||||||
|
- 脱敏结构化输出摘要。
|
||||||
|
- trace 标识。
|
||||||
|
- 输入和输出 token。
|
||||||
|
- 估算费用。
|
||||||
|
- 稳定错误码和脱敏错误摘要。
|
||||||
|
|
||||||
|
### 6.3 失败分类
|
||||||
|
|
||||||
|
- 配置缺失:调用真实 Gateway 前失败,不影响其他页面。
|
||||||
|
- 输入无效:不发起外部请求。
|
||||||
|
- 外部超时或服务失败:记录工具或 Run 失败事件。
|
||||||
|
- 输出校验失败:保留安全摘要并将 Run 标记失败。
|
||||||
|
- 取消:停止后续调用并记录取消事件。
|
||||||
|
|
||||||
|
第一阶段测试使用 Stub Gateway,禁止自动化测试发起真实付费调用。
|
||||||
|
|
||||||
|
## 7. 幂等、并发和重试
|
||||||
|
|
||||||
|
- 页面资料提交使用 POST/Redirect/GET,重复刷新不重复写入。
|
||||||
|
- Run 命令携带期望的 `lock_version` 或在服务内锁定记录。
|
||||||
|
- 工具调用使用 `(run_id, call_id)` 和幂等键防止重复记录。
|
||||||
|
- 人工确认使用 `(run_id, request_key)` 防止重复请求。
|
||||||
|
- 第一阶段不实现自动重试;失败结果保持终态。
|
||||||
|
- 外部调用开始和完成分别写入短事务,调用方可根据已有状态安全恢复记录。
|
||||||
|
|
||||||
|
## 8. 错误映射
|
||||||
|
|
||||||
|
| 领域错误 | 页面语义 | 外部 API 预留语义 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 资源不存在或无权访问 | 404 页面 | 404 |
|
||||||
|
| 输入校验失败 | 表单错误 | 400 或 422,后续 API 设计确定 |
|
||||||
|
| 状态转换冲突 | 操作失败提示 | 409 |
|
||||||
|
| 重复或幂等冲突 | 操作失败提示 | 409 |
|
||||||
|
| SDK 配置缺失 | 功能不可用提示 | 503 |
|
||||||
|
| 外部服务失败 | 通用失败提示和关联编号 | 502 或 503,后续确定 |
|
||||||
|
|
||||||
|
表中外部 API 状态只作为未来语义预留,不代表第一阶段已经提供 JSON API。
|
||||||
|
|
||||||
|
## 9. 安全测试清单
|
||||||
|
|
||||||
|
- 登录失败信息不泄露账户存在性。
|
||||||
|
- `next` 参数不能跳转到站外地址。
|
||||||
|
- GET 退出请求不能改变 Session。
|
||||||
|
- 缺失或错误 CSRF 的写请求被拒绝。
|
||||||
|
- 用户 A 无法通过修改 URL 访问用户 B 的 Run。
|
||||||
|
- UUID 格式错误和不存在资源均安全处理。
|
||||||
|
- 表单和摘要输出经过 HTML 转义。
|
||||||
|
- 密码、Cookie、API Key 和完整敏感参数不出现在响应或日志。
|
||||||
|
- Admin 人工确认操作经过领域服务和权限检查。
|
||||||
|
|
||||||
|
## 10. 兼容与演进
|
||||||
|
|
||||||
|
- 页面 URL 使用命名空间和反向解析,避免模板硬编码路径。
|
||||||
|
- 第一阶段不承诺外部 API 兼容性。
|
||||||
|
- 后续新增 JSON API 时复用领域服务,不复用 HTML 视图作为接口层。
|
||||||
|
- 引入 DRF 或 OpenAPI 前必须确认调用方、认证方式、版本策略和错误模型。
|
||||||
|
- Celery 接入后通过同一 Run 命令服务记录状态,不改变页面查询契约。
|
||||||
|
|
||||||
|
## 11. 待确认项
|
||||||
|
|
||||||
|
- 页面表单错误是否统一使用 200 还是采用更严格的 4xx 状态,实施时按项目测试约定确定。
|
||||||
|
- 是否允许管理员在普通运行页面跨用户查询;当前设计仅允许 Admin。
|
||||||
|
- 第二阶段是否向普通用户开放人工确认处理页面。
|
||||||
|
- 是否存在未来外部调用方;确认前不创建 OpenAPI 文档。
|
||||||
Reference in New Issue
Block a user