Files
patbond-doc/docs/development/iterations/iteration-2/14-pets-contract-draft.md
T
lixi 222990e587
CI / docs-build (push) Successful in 1m19s
docs: M2 第二波收口——报告 13~21 与契约草案入档挂导航
- 13~18 后端纵切六单报告(T2-03~08,测试 95→182)
- 14 + openapi-pets-draft.yaml 契约起草档案
- 19 契约冻结报告(v1.2.0,22 项草案修正对照)
- 20 契约一致性测试(快照机制 + 1 漂移修复)
- 21 第二波收口总表(定型语义汇总,第三波接入依据)
- mkdocs build --strict 通过

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-08 10:40:27 +08:00

10 KiB
Raw Blame History

T2-09 起草报告:pets 域 OpenAPI 契约草案

作者:API 契约工程师 日期:2026-09-07 状态:起草态(DRAFT)——未冻结、未并入 docs/api/openapi.yaml 草案文件:docs/development/iterations/iteration-2/openapi-pets-draft.yaml(可独立 YAML 解析:12 路径 / 18 操作 / 33 schema$ref 全部可解析) 冻结条件:T2-03 权限/错误语义定型 + T2-08 聚合字段定型,由主会话协调执行冻结合并。


1. 范围与依据

依据 用途
iteration-2/01 §1.1 端点表 + T2-03~T2-08 工单描述 端点清单、cursor 分页、乐观锁、Idempotency-Key 要求
iteration-2/02 §4 资源设计草案 + 错误码扩展段 40300/40401/40402/40902 语义、P7 防枚举裁决
patbond-api V3 迁移(V3__pet_health_baseline.sql 字段名、长度、枚举值、CHECK 约束、状态机(唯一正典
既有契约 docs/api/openapi.yaml 1.1.0 信封、错误组件、camelCase、ISO 8601、securityScheme 风格
ADR-010 certificate/provider/booking/avatar 不开放写入
ADR-015 owner/caregiver/viewer 三角色权限模型,邀请流程后置

2. 起草的端点(12 路径 / 18 操作)

# 端点 操作 对应工单
1 /api/v1/pets GET / POST T2-03
2 /api/v1/pets/{petId} GET / PATCH T2-03
3 /api/v1/breeds GET T2-03
4 /api/v1/pets/{petId}/weights GET / POST T2-04
5 /api/v1/vaccine-catalog GET T2-05
6 /api/v1/pets/{petId}/vaccinations GET / POST T2-05
7 /api/v1/vaccinations/{vaccinationId} PATCH T2-05
8 /api/v1/pets/{petId}/health-events GET / POST T2-06
9 /api/v1/health-events/{eventId} PATCH T2-06
10 /api/v1/pets/{petId}/care-reminders GET / POST T2-07
11 /api/v1/care-reminders/{reminderId} PATCH T2-07
12 /api/v1/pets/{petId}/summary GET T2-08

DELETE /api/v1/pets/{petId}(软删)未起草:02 号评估标注"是否进 M2 契约冻结时定",且 PM 决策 D2-7 建议首版仅归档。归档经 PATCH status=archived 已覆盖,软删端点留待冻结时裁决(记入 TODO-FREEZE 清单第 11 项)。

3. 设计决策(起草者裁量,冻结评审时可推翻)

  1. 子资源 PATCH 走顶层短路径/api/v1/vaccinations/{id} 而非 /api/v1/pets/{petId}/vaccinations/{id}):记录 ID 全局唯一(UUID),短路径避免冗余 petId 校验歧义(path petId 与记录归属不一致时如何报错)。与 02 号评估的 PATCH .../vaccinations/{id} 写法在语义上一致,仅路径层级不同——冻结评审时需拍板(列入 TODO-FREEZE)。
  2. 提醒资源名用 care-reminders(与表名 care_reminders 对齐),02 号评估用的是 reminders——冻结时统一。
  3. 疫苗目录路径用 /api/v1/vaccine-catalog02 号评估用 /api/v1/vaccines——冻结时统一。
  4. 新增错误码 40903(疫苗剂次重复)、42200(品种互斥)、42201(状态机违反):延续既有编号段追加,不与 40900/40901/40902 冲突。T2-05 验收标准要求"同系列同剂次重复登记返回冲突"与"状态机非法迁移被拒绝并返回稳定错误码",用 40902 一码多义会让客户端无法区分"重试可解"(版本冲突→刷新重提)与"业务性冲突"(剂次已存在→改剂次)。42200/42201 用 422 区分"参数格式合法但业务规则违反"与 40000 的"参数格式错误"。此三码为草案新提,需后端确认后进 ErrorCode 枚举
  5. cursor 分页信封形态data: { items, nextCursor, hasMore }。既有契约无分页先例,此形态为 pets 域首次定义,将成为全 API 的分页正典——按"一次定死、处处一致"原则,weights 与 health-events 完全一致。
  6. Idempotency-Key 定为可选头01 号拆解 T2-04 要求"写接口支持 Idempotency-Key",但 02 号评估指出开发计划 6.1 的强制名单不含 pets。草案折中:weights/vaccinations/health-events 三个 POST 声明可选头,语义为"带则幂等去重"care-reminders 与 pets 创建不声明(低重复风险,乐观锁与唯一约束兜底)。两份输入存在张力,冻结时需拍板
  7. 响应字段 ID 命名:资源自身 ID 用类型化名(petId/weightId/vaccinationId/eventId/reminderId),与既有契约 Me.userId 的先例一致,避免裸 id 在嵌套结构中歧义。
  8. PetDetail.myRole:详情返回调用者角色(02 号评估"详情含调用者自己的 role"),供前端决定编辑入口显隐。列表 Pet 不带 role(避免 N 次 join 语义进列表,前端列表页不需要)。
  9. 金额一律 amountCents 整数分int64、非负),日期区分 datebirthDate/plannedOn 等,数据库 date 列)与 date-timetimestamptz 列),与 V3 列类型一一对应。
  10. UpdateCareReminderRequest 无 versioncare_reminders 表没有 version 列(V3 确认),状态流转 pending→completed/dismissed 天然幂等,不做乐观锁。其余三个 PATCHpets/vaccinations/health-events)均强制 version。

4. 与 V3 约束的对照表

V3 约束 契约体现
ck_pets_species (dog/cat/other) species enum,三处字典/宠物一致
ck_pets_sex (male/female/unknown) sex enum
ck_pets_status 5 值 Pet.status enum 全 5 值;UpdatePetRequest 只开放 4 值(deleted 不开放写)
ck_pets_breed breed/custom 互斥 请求描述 + 422/42200 错误分支
ck_pets_name 164 name minLength/maxLength
ck_pet_weight >0 且 ≤500 weightKg minimum 0.01 / maximum 500numeric(6,2),最小正两位小数值)
ck_pet_weight_source 3 值 source enum (manual/clinic/device)
ck_vaccination_status 3 值 status enum (scheduled/completed/cancelled)
ck_vaccination_dates 状态-日期联动 createVaccination/updateVaccination 描述 + 422/42201
uq_pet_vaccination_dose(非 cancelled 唯一) 409/40903 错误分支
ck_vaccination_dose >0 doseNo minimum 1
ck_health_event_type 6 值 eventType enum 与 V3 逐字一致
ck_health_event_title 1160 title 长度约束
ck_health_event_amount ≥0 或 null amountCents minimum 0, nullable
ck_care_reminder_type 4 值 reminderType enum
ck_care_reminder_status 3 值 status enum (pending/completed/dismissed)
ck_care_reminder_completed 联动 UpdateCareReminderRequest 描述 + 422 分支
version 列(pets/vaccinations/health_events 三资源响应必含 versionPATCH 请求必填 version
care_reminders 无 version 列 CareReminder 响应无 versionPATCH 无乐观锁
ix_pet_weight_pet_measured (measured_at DESC, id DESC) weights 分页排序描述与索引对齐
ix_health_events_pet_time (occurred_at DESC, id DESC) health-events 分页排序与索引对齐
ADR-010 剪出列(avatar/certificate/provider/booking 全部请求体不含;Pet.avatarAssetId 只读回显、疫苗/事件的 provider/booking/certificate 字段响应中不出现(见 §5 注)

注:certificate_asset_idprovider_idprovider_name_snapshotbooking_id 在草案的响应 schema 中整体未列出(而非标 readOnly)——M2 无任何写入路径,值恒为 null,列出只会诱导客户端建模死字段;M5/媒体迭代时按"新增可选响应字段"作纯增量扩展,无破坏性。pets.deleted_at 同理不出现(软删语义未开放)。

5. 与既有契约(1.1.0)风格一致性自查

检查项 结论
统一信封 {code, message, data},成功 code 恒 0enum [0] 一致,每资源独立 XxxEnvelope,与 MeEnvelope 等先例同构
ErrorEnvelope 结构(code integer / message / data nullable 逐字段一致
ValidationError / AccessTokenInvalid 复用组件 与既有 components/responses 同名同构,合并时直接去重
camelCase、UUID 字符串(format: uuid)、ISO 8601 date-time 一致
securityScheme bearerAuthhttp/bearer/JWT 逐字一致
错误码不复用不改号,追加式扩展 40300/40401/40402/40902 取自 02 号评估;40903/42200/42201 为新提追加
中文 summary/description、错误响应带 code 注释 一致
openapi 3.0.3、tags 分组 一致
与既有契约的偏差 仅两处有意偏差:创建返回 201(既有 auth 全 200,但 02 号评估明确"返回 201",且 pets 域为资源创建语义,属域内新约定不破坏旧端点);分页信封为新增形态(既有无先例)

6. TODO-FREEZE 清单(11 项)

草案 YAML 内以 # TODO-FREEZE: 注释标注 10 处,加上本报告第 11 项:

# 位置 等待 内容
1 info.description 权限模型段 T2-03 每端点权限规则逐条定死(owner/caregiver/viewer 读写矩阵)与错误示例
2 GET /pets T2-03 列表是否分页(建议不分页)
3 GET /pets/{petId} T2-03 不可见宠物 404/40401 vs 越权 403/40300 的最终边界(P7 建议已按防枚举写入,待实现确认)
4 PATCH /pets/{petId} T2-03 caregiver 是否可改档案(建议仅 owner)
5 GET .../vaccinations T2-05 疫苗列表分页策略(量小或可不分页)
6 POST .../vaccinations ADR-010 后续 provider/booking/certificate 字段的未来开放方式(纯增量)
7 POST .../health-events ADR-010 后续 同上(provider/booking
8 GET .../care-reminders T2-07 分页与 status=pending 过滤参数形态
9 GET .../summary 端点描述 T2-08 聚合字段命名、月度边界时区口径、进度分母口径、下次接种取值优先级
10 PetSummary schema T2-08 全 schema 为占位,逐字段待定
11 本报告 §2/§3 冻结评审 DELETE 软删端点是否入 M2;子资源 PATCH 路径层级;care-reminders/vaccine-catalog 资源命名与 02 号评估用词统一;Idempotency-Key 可选 vs 强制;40903/42200/42201 三个新错误码后端确认

7. 冻结前禁止事项(自我约束声明)

  • 本草案未合入 docs/api/openapi.yaml(仍为 1.1.0 / 6 端点,未做任何修改)。
  • 未修改 mkdocs.yml、未 commit/push、未改动任何代码仓。
  • 冻结时的合并动作:去重 componentsErrorEnvelope/两个 responses/securityScheme)、版本号升 1.2.0、错误码表并入 info.description、消除全部 TODO-FREEZE——由主会话在 T2-03/T2-08 定型后协调执行。