feat: 宠物 CRUD 与 pet_owners 三角色权限框架(T2-03)
CI / backend-test (push) Successful in 7m22s

- GET/POST /api/v1/pets、GET/PATCH /api/v1/pets/{petId}、GET /api/v1/breeds
  (species 过滤);创建者自动写入 pet_owners primary owner(同事务)
- PetAccessService 统一权限闸口(READ/WRITE/MANAGE 三档 × owner/caregiver/
  viewer 三角色,ADR-015):无关系一律 404/40401 防枚举,可见越权 403/40300;
  每请求实时查库无缓存,撤销关系即时生效;T2-04~07 复用同一入口
- PATCH version 乐观锁(40902);部分更新语义;status 白名单排除 deleted,
  软删除不可经 PATCH 绕过 ck_pets_deleted
- ck_pets_breed 互斥 + 字典品种存在/物种匹配应用层先行校验(40000);
  芯片号唯一冲突新错误码 40903 MICROCHIP_EXISTS
- pet 模块接入 RS256 bearer 鉴权(与 user 同一公钥约定),compose 挂载公钥
- 测试基建:test classpath 引入 patbond-user + Flyway,Testcontainers 上跑
  完整 V1..V4 迁移链;三角色以测试数据直写 pet_owners 构造(T2-10)
- 集成测试覆盖六类路径 23 例;全套 118 测试全绿(基线 95)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-07 17:27:44 +08:00
parent 58576f8ebc
commit 8fbf44472d
28 changed files with 1893 additions and 14 deletions
+44 -5
View File
@@ -17,11 +17,9 @@
<name>patbond-pet</name>
<description>Pet profile and health record service for Patbond (ADR-009)</description>
<!-- M2 first-wave skeleton: web + datasource wiring and a liveness endpoint.
Flyway is intentionally absent — the single migration chain (V1..V4,
including the pet_health schema) is owned and applied by patbond-user,
the shared database's startup path. This module only reads/writes the
pet_health schema once business endpoints land (M2 second wave). -->
<!-- M2 second-wave: business endpoints with RS256 bearer auth (same JWT
verification stack as patbond-user), pet_health schema CRUD. Flyway
remains absent — the migration chain is owned by patbond-user. -->
<dependencies>
<dependency>
<groupId>com.patbond.patbond</groupId>
@@ -45,11 +43,52 @@
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Access token verification (RS256, public key only): jjwt is not in
the Boot BOM, version pinned in step with patbond-user/auth. -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.12.6</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.12.6</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.12.6</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Tests need the pet_health schema. The migration chain (V1..V4) is
owned by patbond-user (single flyway_schema_history); pulling its
plain jar plus Flyway into the TEST classpath lets Boot's Flyway
auto-config apply the same chain to the disposable container.
Production wiring is unchanged: this module still ships without
Flyway and the chain runs in patbond-user's startup path. -->
<dependency>
<groupId>com.patbond.patbond</groupId>
<artifactId>patbond-user</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-database-postgresql</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-testcontainers</artifactId>