> ## Documentation Index
> Fetch the complete documentation index at: https://aicoding.cscitech.top/llms.txt
> Use this file to discover all available pages before exploring further.

# 01-需求分析与项目规则

> 以一个可运行的 TODO API 为案例，把需求澄清、非目标、验收标准、AGENTS.md、风险登记和任务拆分落成可交接的项目规则。

## 本页要交付什么

这一页不是讲如何泛泛地“写清需求”，而是把一个小型项目的需求从模糊想法推进到可开发、可测试、可审查的工作包。案例是一个本地运行的 TODO API：客户端用 HTTP 请求创建、查询、完成和删除待办事项，服务端用 SQLite 持久化数据。

本页结束时，你应该已经得到以下六项具体产物：

1. 一份经过澄清的产品范围，包含目标、非目标和明确的取舍。
2. 一份可直接执行的 API 契约，写明请求、响应、状态码和错误格式。
3. 一组可以逐条打勾的验收标准，而不是“接口能用”这种模糊结论。
4. 一份项目根目录的 `AGENTS.md`，告诉 Codex 如何运行、测试和修改项目。
5. 一份风险登记表，说明风险、触发条件、缓解办法和责任边界。
6. 一份按依赖关系拆开的任务清单，交接到下一页的计划与开发阶段。

后续页面会继续处理计划、实现、测试和 Git 收口。因此，本页的终点不是写完代码，而是让下一位执行者拿到足够信息后不必重新猜需求。

> 本页示例使用 Python 3.11、FastAPI、Uvicorn、SQLite 和 pytest。命令、版本参数以及 Codex 的界面行为可能随环境变化，请以项目实际配置和本机 `codex --help` 为准。

## 01 先定义问题，不急着选实现

### 业务背景

一个只有命令行入口的个人 TODO 工具，已经可以保存待办，但无法被浏览器、脚本或其他本地工具调用。现在需要增加一个 HTTP API，让一个简单客户端可以完成以下工作：

* 查看当前待办列表；
* 新建一个待办；
* 将待办标记为已完成；
* 删除一个待办；
* 在请求错误时得到稳定、可判断的 JSON 响应。

这是一个学习型、单用户、本地优先的项目。我们刻意把范围控制在一个人半天到一天能够完成并验证的大小。它足以练习需求澄清和代理协作，又不会把认证、部署、多人并发等问题混成一团。

### 原始需求

产品同学最初只说了一句话：

```text theme={null}
把 TODO 工具改成 API，支持增删改查，能给前端用。
```

这句话不能直接交给 Codex 开发，原因很具体：

| 未知项    | 可能的不同解释                             |
| ------ | ----------------------------------- |
| “API”  | REST、GraphQL、命令行包装器，或一个临时 JSON 文件接口 |
| “增删改查” | 是否包含完成状态、标题编辑、批量操作、分页和搜索            |
| “给前端用” | 本机浏览器、局域网客户端，还是公网产品                 |
| 数据保存   | 内存、SQLite、PostgreSQL，是否要求重启后保留      |
| 错误处理   | 返回纯文本、框架默认错误，还是统一 JSON              |
| 身份     | 单用户，还是需要登录和用户隔离                     |
| 完成标准   | 代码能启动，还是必须有测试和示例请求                  |

需求分析的第一步，就是把这些可能性变成选择，而不是让代理替我们决定。模型可以提出选项，但产品边界要由人确认。

## 02 需求澄清记录

下面是一轮足够短、但能消除主要歧义的澄清记录。实际工作中可以把它放在 Issue、任务描述或会话开头；重要的是答案要进入项目产物，而不是只留在聊天记录里。

### 问题一：谁使用 API

**问题：** 这版 API 是给谁用的？需要登录、多个用户或权限控制吗？

**确认结果：** 第一版只服务于本机上的单个用户。不做登录，不做用户表，不做跨用户隔离。接口监听本机地址，默认端口为 `8000`。

**为什么这样定：** 登录会引入密码、会话、密钥和权限模型。它们属于独立需求，不能因为“给前端用”就默认加入。

### 问题二：待办包含哪些字段

**问题：** 一条待办最少需要哪些字段？标题是否允许为空？是否需要截止日期、标签和优先级？

**确认结果：** 第一版只包含：

* `id`：服务端生成的正整数；
* `title`：必填字符串，去除首尾空白后长度为 1 到 200；
* `completed`：布尔值，创建时默认为 `false`；
* `created_at`：服务端生成的 UTC 时间字符串；
* `updated_at`：服务端生成的 UTC 时间字符串。

不加入截止日期、标签、描述、排序字段和附件。

### 问题三：状态变化如何表达

**问题：** “修改”是允许任意字段更新，还是只做完成/未完成切换？

**确认结果：** 第一版采用专门的完成接口：`PATCH /todos/{todo_id}/complete`。它把 `completed` 设为 `true`，重复调用仍然成功并返回当前资源。第一版不提供通用 `PUT`，也不支持把已完成改回未完成。

**为什么这样定：** 一个明确动作比任意更新更容易理解和测试。撤销完成可以作为后续需求，不在本次范围里偷偷扩展。

### 问题四：数据是否需要持久化

**问题：** 服务重启后，之前创建的待办还要存在吗？

**确认结果：** 要。使用项目根目录下的 `data/todos.db` SQLite 文件。数据库文件是运行时产物，不提交到 Git；仓库提交 schema 或初始化代码。

### 问题五：客户端如何知道请求失败

**问题：** 前端需要稳定的错误结构吗？

**确认结果：** 所有预期的客户端错误都返回 JSON：

```json theme={null}
{
  "error": {
    "code": "TODO_TITLE_REQUIRED",
    "message": "title 不能为空"
  }
}
```

客户端可以依赖 `error.code` 做分支，`message` 用于展示。不会把 SQLite traceback 或内部路径返回给客户端。

### 问题六：列表是否需要分页和筛选

**问题：** 列表会不会很大？是否需要分页、搜索和按状态筛选？

**确认结果：** 第一版最多返回 100 条，按 `id` 升序排列。不做分页、不做搜索、不做状态筛选。如果未来超过 100 条，接口返回前 100 条并在响应中给出 `count`；是否增加分页留到下一次需求评审。

### 问题七：是否要兼容已有命令行工具

**问题：** API 是否必须复用或保持原有 CLI 的行为？

**确认结果：** 本次项目从一个独立 API 目录开始，不修改旧 CLI。可以复用数据模型思想，但不得为了“顺手”重写旧入口。

## 03 形成需求基线

### 目标

在本地启动一个单用户 TODO API，并提供以下可验证能力：

1. `GET /health` 返回服务健康状态。
2. `POST /todos` 创建一条合法待办并持久化。
3. `GET /todos` 返回按 `id` 升序排列的待办列表。
4. `PATCH /todos/{id}/complete` 将指定待办标记为完成。
5. `DELETE /todos/{id}` 删除指定待办。
6. 对空标题、过长标题、非法 JSON、不存在的 ID 返回稳定错误。
7. 服务重启后，已创建且未删除的数据仍然存在。
8. 自动化测试覆盖成功路径、边界条件和状态码。

### 非目标

非目标不是“以后也不会做”，而是“本次任务不能因为看起来合理就做”。以下内容明确排除：

* 不做用户注册、登录、JWT、Cookie 或权限系统。
* 不做 CORS 配置，不把服务声明为公网可用。
* 不做 PostgreSQL、Redis、消息队列或云端存储。
* 不做全文搜索、标签、截止日期、优先级和提醒。
* 不做批量创建、批量删除和批量完成。
* 不做撤销完成；本版只有完成动作。
* 不做分页、复杂排序和导出功能。
* 不修改旧 CLI、前端页面或其他目录中的无关代码。
* 不提交真实数据库文件、日志、`.env` 或任何密钥。
* 不自动部署、不推送 Git、不创建 Pull Request。
* 不为了“顺便整理”升级依赖或重构整个项目。

### 成功与失败的判定

“服务能启动”只是开发开始，不是交付完成。只有当需求基线、验收标准和自动化验证同时满足，才能把实现交给下一阶段审查。

| 结果             | 是否算完成 | 证据            |
| -------------- | ----- | ------------- |
| 浏览器打开 `/docs`  | 否     | 只能证明框架启动      |
| `POST` 后立即返回对象 | 不足    | 还需证明数据保存和错误处理 |
| 所有测试通过         | 必须    | 需要看到测试命令和退出码  |
| 重启后数据仍在        | 必须    | 测试或手工步骤给出证据   |
| 修改了旧 CLI       | 否     | 超出范围，需回退      |
| 引入未批准依赖        | 否     | 即使功能正常也不合格    |

## 04 API 契约：让输入和输出可检查

以下契约是本页最重要的开发输入。实现可以在内部采用不同模块，但对外行为必须与此一致。

### 通用约定

* 基础地址：`http://127.0.0.1:8000`。
* 请求和成功响应使用 `application/json`。
* 时间使用 UTC ISO 8601 字符串，例如 `2026-09-05T10:30:00Z`。
* ID 是正整数。
* 未找到资源返回 `404`，不返回 `200` 加空对象。
* 创建成功返回 `201`，删除成功返回 `204` 且没有响应体。
* 错误响应统一使用 `{"error": {"code": ..., "message": ...}}`。

### 健康检查

请求：

```http theme={null}
GET /health
```

成功响应：`200 OK`

```json theme={null}
{
  "status": "ok"
}
```

健康检查不访问外部服务，不检查数据库中的业务数据。数据库连接错误属于服务启动或内部错误，需要在后续测试阶段单独处理。

### 创建待办

请求：

```http theme={null}
POST /todos
Content-Type: application/json

{
  "title": "整理 API 验收清单"
}
```

成功响应：`201 Created`

```json theme={null}
{
  "id": 1,
  "title": "整理 API 验收清单",
  "completed": false,
  "created_at": "2026-09-05T10:30:00Z",
  "updated_at": "2026-09-05T10:30:00Z"
}
```

输入规则：

* `title` 缺失或不是字符串，返回 `422` 和 `TODO_TITLE_REQUIRED`；
* `title` 去除首尾空白后为空，返回 `422` 和 `TODO_TITLE_REQUIRED`；
* 去除首尾空白后超过 200 个字符，返回 `422` 和 `TODO_TITLE_TOO_LONG`；
* 请求体是非法 JSON，返回 `400` 和 `INVALID_JSON`；
* 客户端不能传入 `id`、`completed`、`created_at` 或 `updated_at` 伪造服务端字段。

### 列出待办

请求：

```http theme={null}
GET /todos
```

成功响应：`200 OK`

```json theme={null}
{
  "items": [
    {
      "id": 1,
      "title": "整理 API 验收清单",
      "completed": false,
      "created_at": "2026-09-05T10:30:00Z",
      "updated_at": "2026-09-05T10:30:00Z"
    }
  ],
  "count": 1
}
```

空列表响应：

```json theme={null}
{
  "items": [],
  "count": 0
}
```

列表最多返回 100 条，按 `id` 升序。当前不接受 `page`、`limit`、`q` 或 `completed` 查询参数；是否忽略未知参数需要在实现前确认，默认要求返回 `400` 和 `UNSUPPORTED_QUERY`，避免客户端误以为筛选已经生效。

### 完成待办

请求：

```http theme={null}
PATCH /todos/1/complete
Content-Type: application/json

{}
```

成功响应：`200 OK`

```json theme={null}
{
  "id": 1,
  "title": "整理 API 验收清单",
  "completed": true,
  "created_at": "2026-09-05T10:30:00Z",
  "updated_at": "2026-09-05T10:35:00Z"
}
```

边界行为：

* ID 不存在：`404`，错误码 `TODO_NOT_FOUND`；
* ID 不是正整数：`422`，错误码 `INVALID_TODO_ID`；
* 重复调用：仍返回 `200`，结果保持 `completed: true`；
* 请求体包含不支持字段：返回 `400`，错误码 `UNSUPPORTED_FIELDS`。

### 删除待办

请求：

```http theme={null}
DELETE /todos/1
```

成功响应：`204 No Content`，响应体必须为空。

边界行为：

* ID 不存在：`404`，错误码 `TODO_NOT_FOUND`；
* 删除成功后再次查询列表，不应出现该项；
* 删除成功后再次删除同一个 ID，仍返回 `404`，不能返回成功假装幂等；
* 删除不影响其他待办的 ID 和内容。

## 05 数据规则和错误规则

### 数据库最小结构

实现可以使用 ORM，也可以使用 `sqlite3`，但第一版倾向于直接使用已批准依赖和简单 SQL。逻辑结构如下：

```sql theme={null}
CREATE TABLE todos (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  title TEXT NOT NULL,
  completed INTEGER NOT NULL DEFAULT 0,
  created_at TEXT NOT NULL,
  updated_at TEXT NOT NULL
);
```

`completed` 在 SQLite 中使用 `0` 和 `1` 保存，在 API 层必须转换为 JSON 布尔值。时间统一由服务端生成，更新完成状态时更新 `updated_at`。

### 错误响应示例

缺少标题：

```http theme={null}
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json

{
  "error": {
    "code": "TODO_TITLE_REQUIRED",
    "message": "title 不能为空"
  }
}
```

资源不存在：

```http theme={null}
HTTP/1.1 404 Not Found
Content-Type: application/json

{
  "error": {
    "code": "TODO_NOT_FOUND",
    "message": "待办 99 不存在"
  }
}
```

服务器内部错误不能把 SQL、绝对路径、环境变量或堆栈返回给客户端。日志可以保留诊断信息，但日志不得写入版本库。

## 06 验收标准：每一条都要有证据

将下面清单复制到任务或验收记录中。实现者不能只回复“已完成”，需要给出命令、测试名称或实际响应作为证据。

### 功能验收

* [ ] 运行启动命令后，服务监听 `127.0.0.1:8000`。
* [ ] `GET /health` 返回 `200` 和 `{"status":"ok"}`。
* [ ] 合法 `POST /todos` 返回 `201`，标题、ID、状态和时间字段齐全。
* [ ] 创建后 `GET /todos` 能查到刚创建的数据。
* [ ] 标题首尾空白会被去除后保存。
* [ ] 缺少标题返回 `422/TODO_TITLE_REQUIRED`。
* [ ] 空标题返回 `422/TODO_TITLE_REQUIRED`。
* [ ] 超过 200 个字符返回 `422/TODO_TITLE_TOO_LONG`。
* [ ] 非法 JSON 返回 `400/INVALID_JSON`。
* [ ] `PATCH /todos/{id}/complete` 将状态设为 `true`。
* [ ] 重复完成同一条待办不会生成第二条记录。
* [ ] 不存在的 ID 完成时返回 `404/TODO_NOT_FOUND`。
* [ ] `DELETE /todos/{id}` 返回 `204` 且没有响应体。
* [ ] 删除后列表不再包含该待办。
* [ ] 删除不存在的 ID 返回 `404/TODO_NOT_FOUND`。
* [ ] 服务重启后未删除的数据仍可查询。
* [ ] 列表按 ID 升序，最多返回 100 条。
* [ ] 所有预期错误都符合统一 JSON 结构。

### 工程验收

* [ ] 新增代码有对应测试，不依赖手工点 Swagger 才能证明正确。
* [ ] 测试使用临时数据库，不污染 `data/todos.db`。
* [ ] 项目根目录有准确、短小的 `AGENTS.md`。
* [ ] `README` 或现有项目入口中的启动和测试命令与实际一致。
* [ ] 没有提交 SQLite 数据库、日志、缓存、`.env` 或密钥。
* [ ] 没有修改旧 CLI 或需求未授权的目录。
* [ ] `pytest` 通过，进程退出码为 `0`。
* [ ] `git diff --check` 通过。
* [ ] 实现者报告了未验证项，而不是用“测试通过”掩盖环境限制。

## 07 项目规则：写一份可执行的 AGENTS.md

`AGENTS.md` 不是公司介绍，也不是把 README 复制一遍。它应该记录 Codex 每次进入这个项目都需要知道的事实：用什么命令、哪些目录能改、哪些行为不能擅自增加、完成后必须如何验证。

在项目根目录创建以下文件。若仓库已有 `AGENTS.md`，先合并规则，不要直接覆盖已有团队约定。

```markdown theme={null}
# TODO API

## 项目

本地单用户 TODO HTTP API。Python 3.11、FastAPI、Uvicorn、SQLite、pytest。
服务只监听 127.0.0.1:8000，不是公网服务。

## 常用命令

- 安装依赖：`python -m pip install -r requirements.txt`
- 启动服务：`python -m uvicorn app.main:app --host 127.0.0.1 --port 8000`
- 运行测试：`python -m pytest -q`
- 检查语法：`python -m compileall app tests`

## 目录约定

- `app/`：应用代码
- `tests/`：自动化测试
- `data/`：本地运行数据，不提交数据库文件
- `requirements.txt`：已批准的运行和测试依赖

## API 规则

- 所有错误使用 `error.code` 和 `error.message` 的 JSON 结构。
- 标题去除首尾空白后必须为 1 到 200 个字符。
- 删除成功返回 204 且无响应体。
- 完成接口可以重复调用，但不支持撤销完成。
- 时间使用 UTC ISO 8601 字符串，ID 由数据库生成。

## 修改边界

- 不修改旧 CLI、生产配置、部署文件或数据库文件，除非任务明确授权。
- 不新增依赖；确需新增时先说明理由并等待确认。
- 不访问外部服务，不提交、不推送、不发布，除非任务明确授权。
- 不把密钥、个人数据、`.env`、日志或 `data/*.db` 加入 Git。

## 完成前必须做

1. 先读取相关代码和测试，再提出计划。
2. 修改后运行 `python -m pytest -q`。
3. 再运行 `python -m compileall app tests`。
4. 检查 `git diff --check` 和 `git status --short`。
5. 汇报变更文件、测试输出、未验证假设和回滚方式。
```

这份规则有三个设计点：

* 命令是可复制的，不写“运行测试”这种无法执行的描述；
* 非目标写成禁止动作，防止代理顺手扩展认证、部署或依赖；
* 验收要求输出证据，避免代理只报告结论。

根据参考资料，项目级规则会和更上层的 `AGENTS.md` 合并，当前目录更近的规则在冲突时更具体。若使用 `AGENTS.override.md`，它只替代同目录候选文件，不会自动清除上层规则。因此不要把本项目的安全边界寄托在“代理应该记得上一轮聊天”上。

## 08 风险登记

需求分析必须同时记录“做什么”和“可能怎么出事”。下表是本项目的最小风险登记，可随实现进展更新。

| 编号  | 风险         | 触发条件                   | 影响           | 缓解措施                           | 责任边界                |
| --- | ---------- | ---------------------- | ------------ | ------------------------------ | ------------------- |
| R1  | 服务被误认为公网可用 | 绑定 `0.0.0.0` 或开放防火墙    | 未授权访问本地数据    | 固定绑定 `127.0.0.1`，文档明确本地范围      | 实现者负责监听地址，使用者负责网络环境 |
| R2  | 测试污染真实数据   | 测试直接使用 `data/todos.db` | 删除或修改手工数据    | 测试使用临时目录和独立连接                  | 测试代码负责隔离            |
| R3  | 错误泄露内部信息   | 直接返回异常字符串或 traceback   | 路径、SQL 和配置泄露 | 统一错误映射，日志和响应分离                 | API 层负责脱敏           |
| R4  | 标题输入失控     | 未限制长度或未校验类型            | 数据污染、异常或资源消耗 | 1 到 200 字符校验并覆盖测试              | API 层负责输入边界         |
| R5  | 并发写入异常     | 两个请求同时修改 SQLite        | 锁错误或丢失更新     | 先限定单用户本地场景，统一连接和事务             | 本版不承诺高并发            |
| R6  | 依赖漂移       | 未锁定或擅自升级依赖             | 本机能跑、他人不能跑   | 使用现有依赖文件，变更前确认                 | 依赖变更需单独审批           |
| R7  | 需求扩张       | 顺手加入认证、分页或前端           | diff 过大、无法审查 | 维护非目标清单，超出范围先提问                | 产品负责人决定是否扩展         |
| R8  | 数据库文件被提交   | 未配置忽略规则                | 个人数据进入仓库     | 检查 `.gitignore` 和 `git status` | 提交前审查者负责拦截          |
| R9  | 时间比较不一致    | 混用本地时间和 UTC            | 排序和客户端展示错误   | 所有服务端时间统一 UTC                  | 数据层负责生成格式           |
| R10 | 删除不可恢复     | 用户误删待办                 | 数据丢失         | 明确本版无回收站，后续需单独设计备份和恢复          | 使用者确认删除语义           |

高风险动作的处理原则是先停下来确认，不让代理从上下文自行推断授权。包括安装新包、访问网络、修改工作区外文件、改生产配置、删除数据、提交和推送。

## 09 把需求交给 Codex：先澄清再动手

进入仓库后，不要直接说“实现 TODO API”。第一条消息应该要求 Codex 读取现状、指出冲突、列出问题，并且明确禁止修改。

```text theme={null}
请先只读检查当前仓库，不要修改文件、安装依赖、访问网络、提交或推送。

背景：我们要做一个本地单用户 TODO HTTP API，使用 Python 3.11、FastAPI、Uvicorn、SQLite 和 pytest。

请先读取：
- 现有 README、依赖文件和目录结构；
- 现有 CLI 或 TODO 相关代码；
- 现有测试和 Git 状态；
- 当前生效的 AGENTS.md。

请输出四部分：
1. 仓库现状和可复用代码；
2. 与下面需求基线冲突的地方；
3. 需要我确认的问题；
4. 你建议的最小文件变更和验证命令。

本次需求基线：
- GET /health 返回 {"status":"ok"}；
- POST /todos 创建 title，去首尾空白后长度 1 到 200；
- GET /todos 按 id 升序，最多 100 条；
- PATCH /todos/{id}/complete 将 completed 设为 true，重复调用成功；
- DELETE /todos/{id} 成功返回 204 且无响应体；
- 数据保存到 data/todos.db，测试必须使用临时数据库；
- 错误统一为 {"error":{"code":"...","message":"..."}}。

非目标：认证、用户隔离、CORS、公网部署、搜索、标签、截止日期、分页、撤销完成、修改旧 CLI。

在我确认计划前，不要编辑任何文件。
```

这条提示把“背景、输入材料、目标、非目标、输出格式和禁止动作”放在一起。它不是为了让代理显得更听话，而是为了给后续审查留下可比较的基线。

### 澄清阶段的预期输出

一个合格的只读回复至少应该指出类似问题：

```text theme={null}
发现：仓库已有 todo.py CLI，但没有 app/、tests/ 或 requirements.txt。
冲突：现有 CLI 使用内存列表，无法满足 API 重启后持久化；本次应新增 API 目录而不改 CLI。
待确认：当前仓库是否已有 FastAPI 依赖和统一错误处理约定？
建议变更：新增 app/main.py、app/db.py、app/models.py、tests/test_todos.py、requirements.txt 或复用现有依赖文件。
建议验证：python -m pytest -q；python -m compileall app tests。
```

如果它直接创建文件、升级依赖或声称“已经实现”，说明提示中的边界没有被遵守。先停止，检查审批和工作区，再重新发送“只读检查”的要求。

## 10 任务拆分：每一步都有输入、输出和停点

下一页会进入计划与开发。为了让交接可执行，把大目标拆成以下六个任务。每个任务都应该产生一个可以审查的结果，完成后再进入下一个有依赖的任务。

### T1：确认仓库和依赖

**输入：** 当前仓库、现有 `README`、依赖文件、测试命令和 `AGENTS.md`。

**动作：** 识别现有框架，确认 FastAPI、Uvicorn、pytest 是否已存在；如果不存在，只记录差异，不自动安装。

**输出：** 一份现状报告，列出可复用文件、缺失依赖和不应修改的目录。

**通过条件：** 能解释为什么新增或复用每个依赖；没有工作区改动。

**停点：** 产品或仓库负责人确认依赖方案后，才进入 T2。

### T2：建立数据访问边界

**输入：** 已确认的 SQLite 表结构和 `data/todos.db` 路径规则。

**动作：** 设计数据库初始化、连接、事务和测试数据库注入方式。

**输出：** 数据层接口草图和一个可重复创建临时数据库的测试方案。

**通过条件：** 生产数据库与测试数据库路径不会混用；不需要真实数据才能运行测试。

**停点：** 先审数据生命周期，再实现 API 路由。

### T3：实现读取和健康检查

**输入：** 数据层接口、`GET /health` 和 `GET /todos` 契约。

**动作：** 实现健康检查、列表查询、排序、上限和资源序列化。

**输出：** 可运行的读取接口和对应测试。

**通过条件：** 空列表、单条、多条和超过 100 条的行为都有测试。

### T4：实现创建和输入校验

**输入：** `POST /todos` 请求规则和错误码清单。

**动作：** 实现标题清洗、长度校验、服务端字段保护、持久化和 `201` 响应。

**输出：** 创建接口、错误响应和成功/失败测试。

**通过条件：** 缺失、空白、过长、非字符串和合法标题都能得到契约规定的结果。

### T5：实现完成和删除

**输入：** 已通过审查的读取和创建接口。

**动作：** 实现完成状态更新、重复完成、删除、找不到资源和空响应体。

**输出：** 两个接口及其测试。

**通过条件：** 状态改变可被列表读到，删除后数据消失，其他数据不受影响。

### T6：集成验证和交接

**输入：** T1 到 T5 的代码和测试。

**动作：** 运行完整测试、编译检查、启动服务做最小 HTTP 烟测，检查 diff 和敏感文件。

**输出：** 测试结果、实际请求响应、变更文件清单、未验证风险和下一步建议。

**通过条件：** 满足本页验收清单，且未发生提交、推送或发布。

### 任务依赖图

```text theme={null}
T1 仓库/依赖确认
  |
  v
T2 数据访问边界
  |
  +--> T3 读取与健康检查
  |       |
  +------>+--> T4 创建与校验
                  |
                  v
            T5 完成与删除
                  |
                  v
            T6 集成验证与交接
```

这里没有把所有任务并行化。T3、T4 和 T5 共享数据模型，过早并行会让接口字段和测试夹具互相漂移。下一页可以在同一会话中顺序执行，也可以让子代理只做只读调查；是否使用子代理要根据真实仓库规模决定，不是为了形式上显得复杂。

## 11 下一页交接包

交接到 [02-计划开发与协作](/09-综合实战/02-计划开发与协作) 时，应该把下面的内容原样带过去。不要只说“需求已经分析完了”。

```text theme={null}
项目：本地单用户 TODO API

已确认目标：
- GET /health -> 200 {"status":"ok"}
- POST /todos -> 201，title 去首尾空白后 1-200 字符
- GET /todos -> 200，items 按 id 升序，最多 100 条
- PATCH /todos/{id}/complete -> 200，completed=true，重复调用成功
- DELETE /todos/{id} -> 204，无响应体
- 数据持久化到 data/todos.db，测试使用临时数据库
- 错误统一为 error.code + error.message JSON

明确非目标：
- 认证、用户隔离、CORS、公网部署
- PostgreSQL、Redis、搜索、标签、截止日期、分页
- 撤销完成、批量操作、前端页面
- 修改旧 CLI、安装未确认依赖、提交、推送、发布

必须遵守的项目规则：
- 先读代码并给计划，再编辑
- 不把数据库、日志、.env、密钥加入 Git
- 修改后运行 python -m pytest -q
- 再运行 python -m compileall app tests
- 最后检查 git diff --check 和 git status --short

待执行任务：T1 -> T2 -> T3 -> T4 -> T5 -> T6。
当前停点：先完成 T1 的仓库、依赖和现有测试调查，不要直接编码。

下一页需要产出：
- 按文件和验证命令展开的执行计划；
- 每个任务的完成条件和回滚点；
- Codex 会话中可直接使用的开发提示词。
```

这份交接包同时是对本页的自测。如果其中任何一项仍然使用“尽量”“支持一下”“体验良好”之类无法判断的描述，就不要进入实现阶段，回到需求澄清。

## 小结

本页完成的是项目的“边界工程”：先把原始一句话拆成使用者、数据、状态、错误和持久化问题；再用目标与非目标限制范围；用 API 契约固定输入输出；用验收标准规定什么证据才算完成；用 `AGENTS.md` 固化运行和修改规则；最后用风险表和 T1-T6 任务清单把工作交给下一页。

记住本案例中最容易被忽略的三件事：

1. “增删改查”不等于所有可能的功能，完成动作、撤销动作和通用更新必须分别确认。
2. “能启动”不等于“可交付”，持久化、错误结构、测试隔离和不提交敏感产物同样是验收项。
3. 非目标要写出来，`AGENTS.md` 要写可执行命令，任务要写停点。它们共同减少代理的猜测空间。

下一页 [02-计划开发与协作](/09-综合实战/02-计划开发与协作) 将使用本页的交接包，把 T1-T6 变成具体计划，决定每一步让 Codex 读取什么、修改什么、运行什么验证，以及何时暂停给人审查。

参考资料：`参考/codex/34-capstone.md`、`参考/codex/13-prompting.md`、`参考/codex/11-agents-md.md`。
