# API 契约交叉审计(view/app ⇄ KenApi) 本轮目标:找出与 `8dfc4c1b` 同类的接口契约错配——即「前端发的东西后端不认,或后端返回的东西前端按错的形状用」。 每个域一份报告:`audit/.md`,只读源码,不改业务代码。 ## 判定基线 前端的唯一入口是 `view/app/src/services/api`: - `Apis..({ 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 | ## 每条的取证要求 1. 前端:`view/app/src/...:line` 原始调用片段。 2. 后端:`lib/.../*.rs` 的 query/body 结构体或 `utoipa::path` 声明(路径 + 行号)。 3. 生成类型:`packages/apiclient//.schemas.ts` 的字段清单。 4. 能实证就给 curl:`http://localhost:7051/api/v1/...`(公开仓库 `demo/demorepos` 可匿名读; 需要登录的端点记「未实证」并说明原因)。400 的响应体会直接点名字段,最有力。 ## 报告格式(严格) ```md # ## 结论 - 检查调用点 N 个 / 操作 M 个 - 确认问题 X 条(Q a / B b / P c / R d / G e),可疑 Y 条,未实证 Z 条 ## 确认问题 | # | 类 | 位置 | 操作 | 现象 | 后端依据 | 建议修法 | |---|---|---|---|---|---|---| ## 可疑(需人工确认) | # | 位置 | 操作 | 疑点 | 已排除的可能 | |---|---|---|---|---| ## 已核对无问题 | 操作 | 依据 | |---|---| ``` ## 禁止 - 不改 `view/app/src`、`packages/apiclient`、`lib/**`(本轮只出结论)。 - 不把「风格问题」「性能问题」「a11y」写进报告——只写契约错配。 - 不臆测:没找到后端结构体就标「未实证」。