API 契约交叉审计(view/app ⇄ KenApi)
本轮目标:找出与 8dfc4c1b 同类的接口契约错配——即「前端发的东西后端不认,或后端返回的东西前端按错的形状用」。
每个域一份报告:audit/<domain>.md,只读源码,不改业务代码。
判定基线
前端的唯一入口是 view/app/src/services/api:
Apis.<tag>.<op>({ pathParams, params, data })走invoke(),OPS表决定path/query/body的位置。 该表由scripts/gen-api-ops.py从packages/apiclient的签名生成,已与生成客户端一致——所以本轮的 错配只可能出在「前端调用方填的字段名/形状」与「后端真契约」之间。- 响应信封:
{ code, message, data, error, error_code, request_id },code == HTTP status;data: null是成功无内容。列表统一{ items, total, limit, offset }(chat 另有has_more等)。 - 401 →
/auth/login?callback_url=…,无令牌刷新。
五类问题(每条发现必须归到其中一类)
| 类 | 名称 | 含义 |
|---|---|---|
| Q | query 名不符 | params 里的字段名不在后端 query 结构体 / 生成 *Params 类型里,会被 400 拒绝 |
| B | body 名不符 | data 里的字段名或嵌套形状与生成的 *Body/*Cmd 类型不一致(PATCH 三态:缺省=不变、null=清空、值=设置) |
| P | path 顺序/数量 | pathParams 的键序与路由段顺序不一致,或段数不足 |
| R | 响应形状误用 | 把分页对象当数组、把数组当分页、字段名过时(如 sha vs id)、data: null 未处理 |
| G | 幽灵端点 | 调用了已被删除/改名的端点,或 ALIASES/MISSING_OPS 命不中,实际返回 501/404 |
每条的取证要求
- 前端:
view/app/src/...:line原始调用片段。 - 后端:
lib/.../*.rs的 query/body 结构体或utoipa::path声明(路径 + 行号)。 - 生成类型:
packages/apiclient/<tag>/<op>.schemas.ts的字段清单。 - 能实证就给 curl:
http://localhost:7051/api/v1/...(公开仓库demo/demorepos可匿名读; 需要登录的端点记「未实证」并说明原因)。400 的响应体会直接点名字段,最有力。
报告格式(严格)
# <domain>
## 结论
- 检查调用点 N 个 / 操作 M 个
- 确认问题 X 条(Q a / B b / P c / R d / G e),可疑 Y 条,未实证 Z 条
## 确认问题
| # | 类 | 位置 | 操作 | 现象 | 后端依据 | 建议修法 |
|---|---|---|---|---|---|---|
## 可疑(需人工确认)
| # | 位置 | 操作 | 疑点 | 已排除的可能 |
|---|---|---|---|---|
## 已核对无问题
| 操作 | 依据 |
|---|---|
禁止
- 不改
view/app/src、packages/apiclient、lib/**(本轮只出结论)。 - 不把「风格问题」「性能问题」「a11y」写进报告——只写契约错配。
- 不臆测:没找到后端结构体就标「未实证」。