Files
patbond-doc/docs/architecture/backend-modules.md
T
lixi 296d454d30
CI / docs-build (push) Successful in 41s
docs: backend-modules 补 creation 与 patbond-ai + 新建本仓 README
- backend-modules.md:速览图补 patbond-creation(:8085) 与独立的 patbond-ai
  仓;新增两节职责说明(含 V6 两处偏离目标模型的原因、队列不引入 broker
  的依据、服务身份 JWT 用独立密钥对的事实依据、以及骨架阶段刻意未实现项);
  关键纪律第 2 条补「谁拥有 schema」与「迁移文件放哪」是分开的(pet/
  community/creation 代码各在自己模块,迁移全在 patbond-user),第 3 条补
  两套内部鉴权并存的原因。并注明 patbond-creation 尚未入 compose 及其原因。
- 新建本仓 README(此前四仓中唯一没有的):权威文档索引、本地构建与门禁、
  以及三条写作纪律——常设文档不写死本机路径、迭代报告是时点存档不回改
  (结论失效时追加带日期注记)、不要引用别的报告的转述结论(附本项目
  已因此把规模预估高估一整档的实例)。

验证:secret-scan exit 0;mkdocs build --strict exit 0。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 17:37:35 +08:00

99 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 后端模块结构与职责
> 本页是后端结构的**唯一权威速览**:模块怎么划分、各自负责什么、端口与依赖关系。
> 结构性变更(新增/拆分模块)须经 ADR 决策并同步更新本页。
> 最后更新:2026-09-08(M3 第一波收口:六容器 + media 闭环)。
## 一图速览
```
patbond-api(Maven 多模块,Spring Boot 3.5 + JDK 17)
├── patbond-common 公共库(无端口,被其余模块依赖)
├── patbond-auth 认证服务 :8081
├── patbond-user 用户服务 + 埋点 :8082 ← Flyway 迁移链唯一持有者
├── patbond-pet 宠物健康档案服务 :8083 ← M2 新增(ADR-009)
├── patbond-community 社区服务 :8084 ← M3 新增(ADR-017)
└── patbond-creation AI 生成编排服务 :8085 ← M4 新增(ADR-023)
patbond-ai(独立仓库,Python) ← M4 新增(ADR-023),只调 AI 服务商 API
```
部署形态:docker compose 六容器(postgres:18 + **MinIO 对象存储**(ADR-016,自托管、私有桶)+ auth + user + pet + community),应用容器无状态(ADR-007)。**`patbond-creation` 尚未入 compose**——其 Worker 依赖 `patbond-ai` 与对象存储方案,两者均未落地。
## 模块职责
### patbond-common(公共库)
- 统一错误信封与业务错误码体系(`code`/`message`/`data` 结构,稳定错误码契约)
- 共享异常类型与基础组件
- **不含业务逻辑、不起服务**;其余四个服务模块都依赖它
### patbond-auth(认证域,:8081)
- 注册 / 登录 / 退出:`/api/v1/auth/**`
- JWT RS256 签发;access 15 分钟 / refresh 30 天轮换 / 多设备并行(ADR-003)
- 登录失败锁定(5 次错误 → 423 临时锁定)
- 首版仅账号 + 密码(ADR-004),凭证模型预留扩展
- 会话真值在数据库(auth_sessions,token_family 轮换检测)
### patbond-user(用户域 + 平台能力,:8082)
- 用户资料:`/api/v1/me`
- **埋点接收**:`/api/v1/events`(批量 ≤50、202 逐条结果、唯一允许匿名的写端点、eventId 幂等),落 `platform.product_events`
- **media 上传流程**(ADR-017):`POST /api/v1/media/uploads` 两步上传(预签名 PUT 直传 MinIO → confirm ready)+ 预签名 GET 读取,存储经 ObjectStorage 适配层隔离供应商
- **Flyway 迁移链唯一持有者**:全部数据库迁移(V1 身份/媒体基线、V2 埋点表、V3 宠物健康域、V4 字典种子……)集中在本模块 `src/main/resources/db/migration/` 统一执行,**其他模块不得携带 Flyway**——避免多模块并发迁移竞争,pet 域建表也在这里
### patbond-pet(宠物健康档案域,:8083,M2 新增)
- 宠物 CRUD 与品种目录:`/api/v1/pets`、breeds
- 成员权限模型:pet_owners 三角色(owner / caregiver 可写,viewer 只读;ADR-015),创建宠物者自动成为 primary owner
- 健康记录:体重(weights)、疫苗(vaccinations + vaccine catalog,状态机)、健康事件(health-events,六类)、照护提醒(care-reminders,四类,仅数据接口不做推送)
- 档案聚合摘要:summary(最新体重 / 疫苗进度 / 下次接种 / 当月花费,事实表实时聚合不持久化展示值)
- 照片/附件 M2 未做(ADR-010);media 基础能力 M3 已落地(ADR-016/017),宠物头像/疫苗证书接线另排
- **当前状态**:M2 已收官全量交付(18 操作 + 契约 v1.2.0 冻结)
### patbond-community(社区域,:8084,M3 新增)
- 社区 Feed / 帖子 / 单层评论 / 点赞收藏 / 关注(ADR-018 的 M3 MVP 范围;话题表已建但功能首版剪出)
- 只读写 `community` schema(数据表由 V5 建);作者公开资料按 D3-9 方案 B 经 patbond-user 的 /internal 批量接口取数(后续波次落地)
- `/api/v1/**` 自骨架起即接 RS256 资源侧校验(与 user/pet 同一公钥约定);`/health` 探活在 /api/v1 之外
- media 上传流程不在本模块(ADR-017:实现在 patbond-user,社区侧只做 asset 只读校验)
- **当前状态**:第一波骨架(T3-02)已落地;业务端点随 M3 后续波次按契约实现
### patbond-creation(AI 生成编排域,:8085,M4 新增)
- **编排生成任务,不调用 AI 服务商**:上游调用在独立的 `patbond-ai`(Python)仓库,经 REST 到达(ADR-023 §2)
- 只读写 `creation` schema(数据表由 V6 建,含两处刻意偏离目标模型:`input_asset_id` 改可空以支持文生图、新增 `first_attempt_at` 使排队时长与执行耗时可分离)
- `/api/v1/creation/**` 客户端端点 + **数据库租约队列 Worker**(`FOR UPDATE SKIP LOCKED` + 租约列,**不引入 Redis/MQ**,ADR-023 §3)
- **不直连对象存储**:产物上传凭证来自 patbond-user 的内部媒体接口(预签名 PUT),由生成方直传——ADR-017 的边界不动,且 `patbond-ai` 也因此零对象存储凭证
- **调用 patbond-ai 用服务身份 JWT,独立密钥对**(不转发用户 token)。选独立密钥对的依据:现有 `JwtVerifier` 只验签名、不校验 `aud`/`iss`,而用户 token 无 `aud` claim,复用密钥对会让四个模块把服务票当合法用户 token 接受(ADR-023 §5)
- **当前状态**:骨架已落地(端点、队列仓储、Worker 三通道、租约回收器、provider 适配层接口)。**刻意未实现且会响亮失败**:provider 两个实现位(待服务商文档确认五项)、预签名上传目标获取与产物入 `media.assets`(取决于**挂起中的对象存储决策**,ADR-023 §7)
### patbond-ai(AI 生成服务,独立仓库,Python,M4 新增)
- 不属于 `patbond-api` 多模块,是**第四个仓库**,已纳入发布语义(ADR-023 §12)
- 只负责调用 AI 服务商 API(视频 Seedance / 图片 gpt-image-2);**不访问数据库**,任务状态的唯一事实来源是 Java 侧的 `creation.generation_jobs`
- **对上游同步或异步一律对外呈现为异步**:`submit` 立即返回任务 id,同步型服务商在其内部以后台任务承载长连接。这样 Java 侧无长连接占线程,且 `provider_request_id` 立即可得——超时不再产生「是否已扣费」的歧义
- 内部契约为该仓内独立的 `openapi-internal.yaml`,**不进四模块快照锁**,也不写入对外 `openapi.yaml`
- **是四仓中唯一持有 AI 服务商凭证的仓库**,故 `check-secrets.sh` 已补 `sk-ant-` / `sk-` / `api_key` 等形态
## 关键纪律
1. **契约先行**:所有对外端点以 `patbond-doc/docs/api/openapi.yaml` 为唯一事实源,新接口先冻结契约再实现(M2 起)。
2. **单迁移链**:数据库迁移只进 patbond-user,新表按域用 schema 前缀区分(identity / platform / pet_health / community / creation)。注意「谁拥有 schema」与「迁移文件放哪」是分开的——pet/community/creation 的业务代码各在自己模块,迁移文件全在 patbond-user,`flyway_schema_history` 只有一份。
3. **服务间调用**:MVP 阶段 Feign 静态 URL 直连、无注册中心(ADR-002,Nacos 已移除);微服务化阶段再引入。Java↔Java 用 `InternalAuthFilter` 的共享 token,Java↔Python 用服务身份 JWT——两套并存是有意选择,见 ADR-023 §5。
4. **配置**:敏感配置走 `.env` / `application.yml`(gitignore)+ `.sample` 模式,环境变量注入(`PATBOND_DB_URL` 等)。
5. **测试**:集成测试一律 Testcontainers(postgres:18,ADR-006/008),每模块交付 `./mvnw clean test` 必绿。
## 演进方向
- **微服务化**(ADR-002 预留):模块边界即服务边界,pet 域可整模块独立部署;届时引入配套版本 Spring Cloud Alibaba。
- **M5 marketplace 域**:V3 已裁剪的 4 条跨 schema 外键(vaccinations/health_events → providers/bookings)由 M5 迁移补回。
- **media 域扩展**:基础上传链路已随 M3 落地(自托管 MinIO,ADR-016);带宽/预算触发时迁云对象存储(适配层保证仅换配置);宠物头像、疫苗证书、健康事件附件接线另排。
## 相关文档
- 技术决策记录:[decisions.md](decisions.md)(ADR-001 起持续编号)
- API 契约:`docs/api/openapi.yaml`
- 各迭代过程报告:开发文档 → 第一/第二迭代