feat: 宠物头像读写——PATCH 支持 avatarAssetId、详情与列表补 avatarUrl(T3.5-05,ADR-022)

- PATCH /api/v1/pets/{petId} 支持 avatarAssetId 三态:缺省不改、显式 null
  清空、给值设置。这是 pets 域唯一的三态字段——M2 惯例「null 与缺省同义」
  无法表达「删掉头像」,而 name/species/sex 本就不允许为空,故差异刻意限定
  在本字段
- 权限按「本次请求碰了哪些字段」定档:仅改头像为 WRITE(owner+caregiver,
  ADR-022:头像属日常照护信息,与体重/疫苗同档),碰到任一资料字段仍是
  MANAGE(仅 owner),混合请求按更严的一半判;viewer 一律 403/40300
- 头像与资料共用同一把乐观锁:仅改头像也吃 version,旧版本必答 409/40902
- asset 校验复用 T3-03 引用侧协议 + purpose='pet_avatar':不存在/非本人/
  已删/用途不符答 404/40405,本人未就绪答 422/42203(user_avatar 资源也不能
  当宠物头像)
- 详情与列表响应补 avatarUrl(本地 SigV4 现签预签名 GET,沿用 community 读侧
  先例):仅当 asset 为 ready 才签,指针在而资源退出 ready 时降级为 null,
  不签一个下载必 404 的地址,也不隐式清理指针
- PetRepository 读改为返回 PetRow(含头像存储坐标),签名上移到 PetService,
  与 community 的 PostRow → PostResponse 装配同构——过期 URL 不下沉到仓储层
- pet 模块加入 aws-sdk s3(仅本地签名,不直连对象存储)与读侧 patbond.media
  配置;compose 补同一组 PATBOND_MINIO_* 环境变量
- 测试 +11(成功/清空/缺省保留/降级/caregiver 与 viewer 权限/防枚举 404/
  asset 五态/畸形入参/乐观锁与重放),pet 模块 89 → 100

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-11 10:02:50 +08:00
parent a5634c5f85
commit 15c2e66519
13 changed files with 782 additions and 18 deletions
@@ -19,3 +19,12 @@ patbond:
# 值可以是 PEM 文件路径,也可以是内联 PEM 内容(以 -----BEGIN 开头)。
# 私钥只给 patbond-auth,绝不入库。
public-key: ${PATBOND_JWT_PUBLIC_KEY:}
media:
# 媒体读取侧(ADR-016 定型:私有桶 + 预签名 GET)。本服务只做本地 SigV4
# 签名计算生成宠物头像访问 URL,从不直连对象存储;写入流程在 patbond-user。
# 环境变量与 patbond-user/patbond-community 共用同一组(一套部署一套旋钮)。
# public-endpoint 为空时服务照常启动,宠物响应中 avatarUrl 为 null。
public-endpoint: ${PATBOND_MINIO_PUBLIC_ENDPOINT:}
access-key: ${PATBOND_MINIO_ACCESS_KEY:}
secret-key: ${PATBOND_MINIO_SECRET_KEY:}
download-ttl: ${PATBOND_MEDIA_DOWNLOAD_TTL:1h}