Files
lixi f17e6f1215
CI / docs-build (push) Successful in 34s
docs: M3 第一波收口——报告 09~14 与契约草案入档挂导航
- 09 V5+community 骨架(191→206)、10 埋点队列三项(272→286)、
  11 契约草案(13 路径/19 操作)、12 防泄漏三仓落地、
  13 media MinIO 闭环 + auth 契约测试(→226,抓修 1 漂移)、14 收口总表
- backend-modules.md 更新五模块/六容器口径
- 媒体凭据形态已定型(契约冻结输入),剩余待定型点在 T3-04/05

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-08 17:13:49 +08:00

10 KiB
Raw Permalink Blame History

M3 第一波社区地基施工报告(数据与骨架线:V5 迁移 + patbond-community 骨架)

作者:Senior Developer(后端) 日期:2026-09-08 工单:T3-01Flyway V5 community schema 迁移)、T3-02patbond-community 模块骨架与鉴权接入) 代码基线:patbond-api 64c9b72191 测试全绿)→ 交付 3c671fc206 测试全绿) 结论先行:V5 建 community 全部 8 表,2 条跨 schema 外键(generation_job_id→creation、region_id→platform.regions)按拍板剥离;patbond-community:8084)挂入构建链、自骨架起 /api/v1/ 即接 RS256 校验并纳入 compose 第五容器;干净 postgres:18 上 V1→V5 全量迁移一次成功,全套 206 测试全绿。**


1. 提交清单

按工单各一逻辑提交,全部已推送 origin/dev

提交 内容
a97814a feat: Flyway V5 community schema 基线 + 迁移验证集成测试(T3-01)
3c671fc feat: 新建 patbond-community 模块骨架(ADR-017T3-02

2. Flyway V5:表清单与裁剪对照(T3-01)

2.1 V5 结构基线(patbond-user/src/main/resources/db/migration/V5__community_baseline.sql

从目标模型 patbond-doc/docs/database/patbond_postgresql.sql718~875 行)提取,共建 8 张表

# 处置 与目标模型的差异
1 community.posts 剥离 2 条跨 schema FK(见 2.2);列全保留,其余约束/索引无差异
2 community.post_media 无差异(asset_id → media.assets RESTRICT 保留,media 表 V1 已建;封面部分唯一索引 uq_post_media_cover 照建)
3 community.comments 无差异(刻意单层平铺,reply_to_user_id 支持 @ 回复;幂等列 client_request_id + request_hash 照建)
4 community.post_likes 无差异(PK (post_id, user_id) 天然幂等)
5 community.post_bookmarks 无差异(同上)
6 community.user_follows 无差异(含禁自关注 CHECK
7 community.topics 无差异(name citext UNIQUE)。表建功能剪ADR-018 话题剪出 M3 MVP,但结构按目标模型建;无种子数据进生产链(测试断言 topics 为空)
8 community.post_topics 无差异

其余保留项:全部 CHECK 约束(ck_posts_publish_stateck_posts_idempotencyck_comments_deleted 等)、Feed 部分索引 ix_posts_feed (published_at DESC, id DESC) WHERE status='published' AND visibility='public'uq_posts_author_idempotency、2 个 updated_at 触发器(posts/comments,复用 V1 的 platform.set_updated_at())。到 identity.userspet_health.petsmedia.assets 的跨 schema FK 全部保留(三个 schema V1/V3 已存在,共库阶段先例)。

2.2 强制裁剪:2 条跨 schema 外键(逐条对照)

按拍板(工单 T3-01,照 V3 剪 4 条 marketplace FK 的先例格式),对应字段保留为裸可空 uuid 列,索引照建,迁移文件头注释逐条标明补回时点:

# 原定义 V5 处置 补回时点
1 posts.generation_job_id → creation.generation_jobs(id) ON DELETE SET NULL 剥离;裸列保留,ix_posts_generation_job 索引保留 M4 建 creation schema 的迁移补回
2 posts.region_id → platform.regions(id) ON DELETE SET NULL 剥离;裸列保留,ix_posts_regionix_posts_region_feed 索引保留 M5 地区体系迁移补回(ADR-018 将 region 剪出 M3

说明:platform.regions 表 V1 已存在(02 号评估 1.4 节原判「保留」),但 PM 拆解按 ADR-018 范围裁剪把 region 体系整体划入 M5,本工单按拍板剪 FK——列与索引保留,M5 补回约束零成本。

2.3 扩展启用

  • pg_trgm:02 号评估发现 V1 只建了 pgcrypto 与 citext,而 ix_posts_content_trgmgin, gin_trgm_ops)需要 pg_trgm——V5 文件头 CREATE EXTENSION IF NOT EXISTS pg_trgm 补齐;postgres:18 官方镜像含 contribTestcontainers 与 compose 均实测无障碍。trgm 索引按 02 号建议照建(M3 无搜索需求,但成本极低、剪了偏离目标模型)。
  • citextV1 已建;V5 以 IF NOT EXISTS 幂等重申(迁移日志出现一条「already exists, skipping」提示,无害)。

2.4 主键 DEFAULT 的取舍

02 号评估表格建议 V5「去掉主键 DEFAULT gen_random_uuid()」,但核对既有链:V1(users)与 V3pets均保留了该 DEFAULT,应用侧显式写入 UUIDv7、DB DEFAULT 仅作兜底。V5 与 V1/V3 同规保留 DEFAULT(工单要求「照 V3 先例写法」优先于评估建议;两者对运行时行为无差异,应用永远显式供 id)。

3. patbond-community 模块骨架(T3-02ADR-017

patbond-community/
├── Dockerfile                      # 同 user/auth/pet 模式(temurin-17-jreuid 10001,无状态,EXPOSE 8084
├── pom.xml                         # 挂入父 pom;依赖对齐 petcommon/web/validation/jdbc/jjwt + 测试侧 user jar + Flyway + Testcontainers
└── src/
    ├── main/java/com/patbond/patbond/community/
    │   ├── CommunityApplication.java            # Spring Boot 入口
    │   ├── config/CommunitySecurityProperties.java  # patbond.jwt.public-key
    │   ├── config/SecurityConfig.java           # BearerAuthFilter 注册到 /api/v1/*order 20
    │   ├── config/JacksonConfig.java            # 整数字段拒绝小数(与其余服务同规)
    │   ├── security/{BearerAuthFilter,JwtVerifier,RsaPublicKeyLoader}.java  # RS256 资源侧校验(user/pet 同款第三份复制)
    │   ├── web/GlobalExceptionHandler.java      # {code,message,data} 信封契约
    │   └── controller/HealthController.java     # GET /health 探活(含 SELECT 1 连通检查,在 /api/v1 之外)
    ├── main/resources/application.yml.sample    # .sample 模式,默认端口 8084,DB/公钥经环境变量注入
    └── test/java/com/patbond/patbond/community/
        ├── TestcontainersConfiguration.java     # postgres:18 @ServiceConnection;测试 classpath 挂 user jar + Flyway 跑全链 V1..V5
        ├── CommunityApplicationTests.java       # 上下文冒烟
        ├── controller/HealthControllerTest.java # /health 200 + db=up
        ├── security/BearerAuthIntegrationTest.java  # 无 token/畸形/错签/过期 → 401+40101;有效 token 过滤器放行(未实现路由 404+40400
        └── support/TestJwtKeys.java             # 运行时生成 RSA 对,无密钥材料入库

关键取舍:

  • 鉴权自骨架起接入(与 pet 骨架期不同):T3-02 验收要求无 token/过期 token 返回 401 + 40100 系,故 BearerAuthFilter/JwtVerifier/RsaPublicKeyLoader 随骨架落地(user/pet 同款第三份复制)。02 号评估 P9 建议的「纯 Java 件下沉 common」未进 ADR-016~021 拍板,本单不做,留待后续决策——届时三处复制件切换为共享件、测试全绿即证等价。
  • Flyway 归属不拆community 生产 classpath 无 Flyway;单迁移链(V1..V5)由 patbond-user 启动统一执行。模块只经 JdbcClient 读写 community schema。
  • compose 第五容器:照 pet 服务块模式(build + .sample 挂载 + 环境变量注入 + 公钥只读挂载);depends_on postgres 健康 + user 先起(保证 V5 已执行、community schema 就绪)。
  • 作者资料取数:按 ADR-017/D3-9 方案 Buser 增 /internal 批量公开资料接口),本单只搭骨架不实现。

4. compose 五容器验证

./mvnw -DskipTests package + docker compose up -d --build 实测(既有 pgdata volume,数据库处于 V4):

  • 五容器全部 Uppostgreshealthy+ auth + user + pet + community。
  • 增量迁移零影响user 启动日志 Migrating schema "public" to version "5 - community baseline"Successfully applied 1 migration ... now at version v5——在带 M2 数据的既有库上 V5 增量应用成功(纯增量 schema,对 V1~V4 数据零影响的实证)。
  • community 探活GET :8084/health{"code":0,...,"data":{"status":"ok","db":"up"}}pet :8083 同绿)。
  • 鉴权实证GET :8084/api/v1/posts 无 token → HTTP 401 + {"code":40101,"message":"token 无效或过期"},与验收标准一致。
  • 验证后 docker compose down(保留 pgdata volume),恢复环境原状。

5. 测试数变化:191 → 206(+15,0 回归)

模块 基线 交付 新增内容
patbond-common 3 3
patbond-user 68 76 CommunityMigrationIntegrationTest 8 例(schema 存在、8 表齐、pg_trgm 扩展与 trgm 索引、2 条裁剪 FK 确不存在且裸列在、保留 FK 抽查、结构抽查、触发器 2 个、topics 无种子)
patbond-auth 31 31
patbond-pet 89 89
patbond-community 7 上下文冒烟 1 + /health 探活 1 + 鉴权集成 5(无 token/畸形/错签/过期 → 401+40101、有效 token 放行)+ 迁移链随上下文启动隐式验证
合计 191 206 JAVA_HOME=/usr/lib/jvm/java-17-openjdk ./mvnw clean test 一次通过,BUILD SUCCESS

V1→V2→V3→V4→V5 全量迁移经 Testcontainers 在全新 postgres:18 容器上自动验证通过(user 与 community 两模块的每个 @SpringBootTest 上下文启动即执行全链迁移)。

6. 遗留与下一波衔接

  • 2 条裁剪 FK 补回generation_job_id 随 M4 creation schema 迁移、region_id 随 M5 地区体系迁移(V5 文件头注释已标明)。
  • P9 共享设施下沉:JWT 校验件已是第三份复制,待拍板后统一下沉 common。
  • 作者公开资料 /internal 批量接口D3-9 方案 B):随 Feed/评论纵切(T3-05 等)在 patbond-user 侧落地。
  • media 上传流程T3-03):归 patbond-user,本模块只做 asset 只读校验,随帖子纵切接入。
  • CI:多模块 reactor 自动含 patbond-community.gitea/workflows/ci.yml 零改动。
  • backend-modules.md:已同步加 patbond-community 行与五容器口径(doc 仓工作区修改,随波末收口提交)。