Files
lixi d2867826d3
CI / docs-build (push) Successful in 55s
docs: M3 开工分析 8 份报告入档 + ADR-016~021 拍板决策
- iteration-3 报告 01-08(PM 拆解/后端/Flutter/RC 首个 CERTIFIED/UI/埋点/证据基线/Git)
- ADR-016 自托管 MinIO 起步预留迁云(用户确认现无云存储)、ADR-017 patbond-community
  :8084 + media 归 user + 作者信息跨 schema 只读、ADR-018 范围裁剪(话题剪出/单层评论)、
  ADR-019 幂等按域(PUT/DELETE + request_hash)、ADR-020 聚合 feed_viewed/字典 v3/
  北极星不变/队列三项升第一波、ADR-021 Git 修订(main 更正/PR 情形触发/首发布重建 main/
  防泄漏 grep 先行)
- mkdocs 挂「第三迭代」导航,build --strict 通过

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-08 16:02:53 +08:00

342 lines
35 KiB
Markdown
Raw Permalink 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.
# Patbond 第三迭代任务分解(M3 社区)
> 作者:Senior Project Manager
> 日期:2026-09-08
> 依据:`docs/development/development-plan.md`(第 7 节 M3、第 4/6 节规范、第 9/10 节质量门禁与 DoD)、`iterations/iteration-2/29-m2-summary.md`M2 收官与遗留)、`docs/architecture/backend-modules.md`、`docs/architecture/decisions.md`ADR-001~015)、`docs/database/patbond_postgresql.sql``community` schema 7 表 + `media.assets`)、`docs/api/openapi.yaml` v1.2.018 路径,冻结中)
> 编号约定:本迭代工单以 `T3-` 前缀编号,避免与 T1/T2 冲突。
> 范围声明:严格限定为 M3 社区。AI 创作(M4)、本地服务(M5)、通知推送(M6)不在本迭代范围;`posts.generation_job_id` 等 M4 挂钩字段仅作预留,不开放写入。范围外需求一律记 backlog。
---
## 1. 范围界定与依据
### 1.1 开发计划 M3 原文(正典依据)
开发计划第 7 节 M3 定义(引用原文):
- 目标:"完成真实动态发布和互动闭环。"
- "实现 Feed、帖子详情、草稿/发布、媒体、评论、点赞、收藏、关注和话题。"
- "Feed 使用游标分页;点赞、收藏使用幂等写入。"
- "Flutter 替换本地帖子,并实现刷新、分页、失败重试和乐观更新回滚。"
- 验收标准:"发布后可在另一客户端看到;重复点赞不重复计数;分页不丢失、不重复;删除或隐藏内容不可继续出现在公共 Feed。"
四条验收标准与工单的映射:跨客户端可见 → T3-21(E2E);重复点赞不重复计数 → T3-06;分页不丢失不重复 → T3-05 + T3-11 专项测试;删除/隐藏不出公共 Feed → T3-04/T3-05 语义 + T3-21 取证。
### 1.2 开工前的关键事实(PM 逐项核实)
1. **media 域是本迭代最大前置**`media.assets` 表结构 V1 已建,但上传流程**零代码**(ADR-010 剪出 M2),且**对象存储供应商至今未拍板**(第一迭代 D4 → M2 D2-1 两度遗留)。社区帖子以图片为主要形态(demo 每帖有 `mainImage`),媒体不通则发帖闭环不成立。对象存储选型是本迭代头号拍板项(D3-1)。
2. **community 数据模型已定稿评审**7 张表(posts、post_media、comments、post_likes、post_bookmarks、user_follows、topics + post_topics 关联)。要点:
- `posts` 自带 `idempotency_key + request_hash` 唯一约束、`version` 乐观锁、`like_count/comment_count/bookmark_count` 计数列、`status`draft/published/hidden/archived)与 `visibility`public/followers/private);Feed 索引 `(published_at DESC, id DESC) WHERE status='published' AND visibility='public'` 已就绪。
- **评论刻意设计为单层平铺**(DDL 注释原文:"Comments are deliberately one flat level. reply_to_user_id supports @ replies without parent_comment_id")——"评论层级"不是开放问题,模型已裁决,仅需确认沿用(D3-5)。
- `post_likes`/`post_bookmarks` 复合主键 `(post_id, user_id)` 天然支撑幂等写入。
3. **Flutter 待替换对象明确**`lib/features/home/home_page.dart`(首页 Feed + `_PostCard`)、`lib/features/create/create_page.dart`(创作页)、`lib/features/post/post_detail_page.dart`(详情 + 评论),数据挂在 `AppState` 的本地 `PostModel`(含 mainImage、tags、hasLiked/hasBookmarked、平铺 comments)。demo **没有**关注页与话题页——关注/话题是纯增量,不是替换项,这是裁剪空间的客观依据(D3-2/D3-3)。
4. **隐藏依赖——作者公开资料**:Feed 卡片与评论需要作者昵称/头像,但现有契约只有 `GET /api/v1/me`,无任何"查看他人公开资料"的途径;`identity.users.avatar_asset_id` 又指向 media。获取方式(跨 schema 只读 vs Feign 调 user 内部接口 vs 嵌入响应)需拍板技术方案(D3-9),头像在 M3 至少要能随 media 域上传(否则占位)。
5. **跨 schema 外键**`posts.generation_job_id → creation.generation_jobs`M4)与 `posts.region_id → platform.regions`platform.regions 未随 V1/V2 迁移)在 V5 迁移时须裁剪为裸 uuid 列——与 M2 T2-01 裁剪 marketplace 外键同一先例。另 `topics.name``citext``ix_posts_content_trgm``pg_trgm`,两个扩展需随 V5 启用。
### 1.3 本迭代 MVP 范围(PM 建议口径,待 §4 拍板确认)
- **纳入**:图片媒体上传闭环(对象存储 + `POST /api/v1/media/uploads` + 状态机)、帖子草稿/编辑/发布/删除(幂等 + 乐观锁)、公共 Feed 游标分页、帖子详情、单层评论(含 @ 回复)、点赞/收藏幂等写入与计数、Flutter 三页替换真实数据 + 乐观更新回滚、M2 高优先遗留两项(auth 契约测试、埋点队列完善)。
- **待拍板裁剪项**(默认建议见 §4):关注(D3-2,建议最小数据接口入、关注流与 followers 可见性后置)、话题(D3-3,建议首版剪出)、视频(D3-4,建议图片先行视频后置 M4+)。
- **默认剪出**`region_id`/`location_text_snapshot`(依赖 platform.regions,属 M5 地区体系)、`visibility='followers'`(依赖关注体系成熟)、内容审核后台与举报流程(`hidden` 字段保留为运营位,见 D3-7)、评论区通知(M6)、全文搜索(trgm 索引建了但搜索端点不在 M3 原文)。
---
## 2. 工单列表
预估规模口径沿用前两迭代:S ≈ 半天内,M ≈ 1-2 天,L ≈ 3-5 天(含测试与文档)。
### A 组:数据与工程基础(后端)
#### T3-01 Flyway V5community schema 迁移与扩展启用
- **仓库**patbond-api(迁移进 patbond-user,单迁移链纪律),patbond-doc(迁移说明)
- **描述**:从 bootstrap SQL 提取 community 全部表结构为 V5;启用 `citext``pg_trgm` 扩展;**裁剪两条跨 schema 外键**`posts.generation_job_id``posts.region_id` 保留为裸 uuid 可空列,M4/M5 迁移时补回,写入迁移说明);topics 开发种子(若 D3-3 纳入)独立为不进生产的脚本。
- **验收标准**
- 全新 postgres:18Testcontainers)上 V1→V5 全量迁移一次成功,表结构与 bootstrap SQL 一致(裁剪项除外,差异入迁移说明)。
- `./mvnw clean test` 全绿(既有 191 测试不回归)。
- **依赖**:无(第一波首项)。
- **规模**M
#### T3-02 patbond-community 模块骨架与鉴权接入
- **仓库**patbond-apipatbond-docbackend-modules.md 更新随收口)
- **描述**:按 D3-6 拍板结果建立社区模块骨架(PM 建议:沿 ADR-009 先例新建 Maven 模块 `patbond-community`,:8084);复用 JWT 资源侧校验与当前用户解析;模块只读写 `community` schema(作者资料获取按 D3-9 方案);compose 编排纳入新容器。
- **验收标准**
- 模块编译入构建链,`./mvnw clean test` 全绿;无 token/过期 token 返回 401 + 既有 40100 系错误码。
- compose 起五容器(postgres + auth + user + pet + community)健康。
- **依赖**:D3-6 拍板(可先按建议方案搭骨架,骨架期变更成本最低)。
- **规模**M
#### T3-03 media 域最小闭环:对象存储接入与上传流程
- **仓库**patbond-api(模块归属随 D3-6),patbond-doc(上传流程说明)
- **描述**:**本迭代关键路径起点,依赖 D3-1 拍板**。实现 `POST /api/v1/media/uploads`(创建 asset 记录 + 签发上传凭据,建议预签名直传)与上传完成确认端点(uploading→ready,校验 mime/尺寸/大小;失败→failed);接入拍板的对象存储(建议 MinIO 起步);读取侧签发访问 URL(或公共读桶策略,随 D3-1 定);首版仅 `kind='image'`(D3-4),单文件上限与允许 mime 白名单写入契约。清理策略(uploading 超时未确认的 asset)首版仅记录方案不实现定时任务。
- **验收标准**
- 上传→确认→ready→URL 可访问全链路 compose 实测通过;非法 mime/超限被拒且错误码稳定。
- 集成测试覆盖状态机合法/非法迁移;CI 内以 MinIO Testcontainer(或拍板方案对应容器)验证。
- `ck_media_location`/`ck_media_ready` 等数据库约束与应用层校验一致。
- **依赖**D3-1 拍板;T3-02(或 media 独立模块骨架)。
- **规模**L
### B 组:后端社区纵切
#### T3-04 帖子生命周期:草稿/编辑/发布/删除
- **仓库**patbond-api
- **描述**`POST /api/v1/posts`(创建草稿,`Idempotency-Key` + request_hash 落 `uq_posts_author_idempotency`)、`PATCH /api/v1/posts/{postId}`(编辑,`version` 乐观锁,仅作者)、发布动作(draft→published,写 `published_at`,校验 `ck_posts_publish_state`)、删除(软删 `deleted_at`,语义随 D3-7)、`GET /api/v1/posts/{postId}` 详情、我的帖子列表(含草稿,`ix_posts_author_created` 游标)。post_media 挂接:只接受 `status='ready'` 且属于当前用户的 assetposition/is_cover 语义与 `uq_post_media_cover` 一致;发布时至少校验内容非空(图片是否必填随 D3-4 定)。category 三值白名单(general/help/ai_creationai_creation 仅预留不开放)。
- **验收标准**
- 草稿→编辑→发布→详情→删除全链路走真实 PostgreSQL;相同 Idempotency-Key 重试不产生重复帖子。
- 非作者编辑/删除被拒(403/404 语义契约定死);version 冲突返回既有 40902 语义。
- 引用非 ready/非本人 asset 被拒;六类测试路径(成功/参数错/不存在/无权限/并发冲突/幂等重试)覆盖。
- **依赖**T3-01、T3-02、T3-03media ready 校验)。
- **规模**L
#### T3-05 公共 Feed 游标分页与帖子卡片聚合
- **仓库**patbond-api
- **描述**`GET /api/v1/feed`(命名待契约定稿):`status='published' AND visibility='public'``ix_posts_feed`,复合游标 `(published_at, id)` 降序,**禁止 OFFSET**(第 6.1 节红线);软删/hidden/archived 一律不可见(M3 验收标准四)。响应含卡片所需全部字段:作者公开摘要(昵称/头像,取数方案按 D3-9)、封面图 URL、三计数、**当前用户 liked/bookmarked 状态**(批量查询避免 N+1)、话题标签(若 D3-3 纳入)。
- **验收标准**
- 分页不丢失不重复:含"翻页间隙有新发布/有删除"两个专项集成测试;游标篡改/过期返回规范错误。
- 删除与 hidden 帖子在下一次请求即不可见,有测试。
- 卡片字段口径逐项写入契约描述(liked 状态、封面选取规则、计数来源)。
- **依赖**T3-04。
- **规模**L
#### T3-06 点赞/收藏幂等写入与计数
- **仓库**patbond-api
- **描述**:点赞/收藏的施加与取消(建议 `PUT/DELETE /api/v1/posts/{postId}/like``.../bookmark`PUT/DELETE 天然幂等语义);依托复合主键防重,`like_count/bookmark_count` 与关系行**同事务**原子增减;重复施加/重复取消均返回成功且计数不变(M3 验收标准二);对不可见帖子(软删/hidden/他人 private)操作返回 404。我的收藏列表(`ix_post_bookmarks_user_created` 游标分页)。
- **验收标准**
- 重复点赞并发压测(同用户并发 N 次)后 like_count 恰为 1,有集成测试。
- 取消不存在的点赞不报错不减计数;计数列与关系表对账一致性有测试。
- **依赖**T3-04;与 T3-05/T3-07 可并行。
- **规模**M
#### T3-07 评论:单层平铺 + @ 回复
- **仓库**patbond-api
- **描述**:按 D3-5 确认的单层模型实现 `GET/POST /api/v1/posts/{postId}/comments``ix_comments_post_created` 游标分页;创建带 `client_request_id` 幂等 + `reply_to_user_id` 可选 @ 回复)与评论删除(作者可删;帖主是否可删他人评论随 D3-7 定)。`comment_count` 同事务维护(删除减计数);`ck_comments_deleted` 状态一致性;评论长度 1~2000 与数据库约束一致。响应含评论作者公开摘要(同 D3-9 方案)。
- **验收标准**
- 相同 client_request_id 重试不产生重复评论;对不可见帖子评论返回 404。
- 分页正确;删除后计数与列表一致;六类测试路径覆盖。
- **依赖**T3-04。
- **规模**M
#### T3-08 关注最小数据接口(条件单,随 D3-2)
- **仓库**patbond-api
- **描述**:若 D3-2 拍板纳入:follow/unfollowPUT/DELETE 幂等,`ck_user_follows_self` 禁自关注)、我的关注/粉丝列表(游标分页)、目标用户维度的关注状态查询(嵌入 D3-9 公开资料响应)。**关注 Feed tab 与 `visibility='followers'` 不在本单**(后置,见 D3-2 影响面)。
- **验收标准**:重复 follow 幂等;自关注被拒;列表分页正确;六类测试路径覆盖。
- **依赖**D3-2 拍板;T3-02。
- **规模**M
#### T3-09 话题目录与帖子挂接(条件单,随 D3-3)
- **仓库**patbond-api
- **描述**:若 D3-3 拍板纳入:topics 只读目录(active 过滤)、发帖挂话题(≤N 个,上限入契约)、话题维度 Feed(`ix_post_topics_topic` + 可见性过滤)。话题创建首版仅种子数据,不开放用户建话题。
- **验收标准**:挂接与话题 Feed 正确过滤不可见帖;目录/上限校验有测试。
- **依赖**D3-3 拍板;T3-04。
- **规模**M
### C 组:契约与测试
#### T3-10 OpenAPI v1.3.0 扩展与冻结
- **仓库**patbond-doc`docs/api/openapi.yaml`),patbond-api(字节级快照同步)
- **描述**:沿用 M2 验证过的**迭代式契约冻结**:第一波按 §1.1 与数据模型出草案(TODO-FREEZE 标注媒体凭据形态、Feed 卡片字段、公开资料形态三处待定型点)→ 随 T3-03/04/05 实现定型回填 → 拍板 → 冻结合入 + **api 侧字节级快照同步升版**(冻结纪律:升版须同步快照,缺一 CI 必红)。沿用既定规范:camelCase、UUID 字符串、统一信封、稳定错误码(community/media 域新错误码段定死)、cursor 分页形态、Idempotency-Key、version。
- **验收标准**:契约评审通过;契约测试锁定零漂移;`mkdocs build --strict` 通过;冻结后变更须显著上报两端同步。
- **依赖**:草案仅依赖数据模型;冻结须 T3-03 凭据形态 + T3-04 权限/错误语义 + T3-05 卡片字段定型。**冻结是第三波前端联调放行闸门。**
- **规模**M
#### T3-11 后端集成测试滚动补齐与 CI(横切单)
- **仓库**patbond-api
- **描述**:随 B 组滚动补齐 Testcontainers 集成测试与契约一致性测试(机制复用 M2 T2-20);每单交付 `./mvnw clean test` 必绿。专项:Feed 分页边界矩阵(空 Feed/单页/翻页间隙增删/游标非法)、计数对账、幂等并发。MinIO 容器纳入 CI 后记录时长,超阈值评估分层。
- **验收标准**:每个业务接口覆盖六类路径;Gitea Actions 全绿(commit status API 实查,M2 惯例);CI 时长记录在案。
- **依赖**:随 T3-03~T3-09 滚动。
- **规模**M(分摊在各单内)
### D 组:Flutter 客户端
#### T3-12 community feature 分层与 API Client
- **仓库**patbond-flutter
- **描述**:按第 4.2 节拆出 community featureController → Repository → API Client,对齐 pets feature 既有结构);依 T3-10 冻结契约实现 DTO 与 Client(帖子、Feed、评论、点赞/收藏、媒体上传,条件项随拍板);错误码解析复用既有网络层与 token 拦截。`AppState``PostModel` demo 数据链路在本组末位工单交付后移除。
- **验收标准**:DTO 映射有单元测试;错误映射类型化;UI 无关骨架可先行。
- **依赖**:T3-10 冻结(骨架部分可提前与后端并行)。
- **规模**M
#### T3-13 媒体上传客户端
- **仓库**patbond-flutter
- **描述**:选图(image_picker 或既定方案)、客户端压缩/尺寸约束(与契约上限一致)、按 T3-03 协议两步上传(取凭据→直传→确认)、上传中/失败/重试状态、多图并发上传与顺序保持(position)。
- **验收标准**:上传全链路 compose 实测;弱网失败可重试不产生孤儿引用(未确认 asset 不挂帖);单元/widget 测试覆盖状态机。
- **依赖**T3-12T3-03 联调。
- **规模**L
#### T3-14 首页 Feed 替换真实数据
- **仓库**patbond-flutter
- **描述**`home_page.dart` Feed 替换:下拉刷新、游标分页加载更多、**loading/empty/error/retry 四态**(第 9 节硬要求)、图片加载占位与失败态、卡片计数与 liked/bookmarked 状态取自服务端。demo 的 breedTag/tags 展示按契约实际字段调整(话题未纳入则该位裁剪)。
- **验收标准**:刷新与分页不丢不重(widget 测试模拟游标);四态齐备有测试;不再读 AppState demo 帖子。
- **依赖**T3-12。
- **规模**L
#### T3-15 发帖与草稿流程
- **仓库**patbond-flutter
- **描述**`create_page.dart` 替换:文字 + 多图(挂 T3-13)、本地暂存与服务端草稿(保存草稿/继续编辑/发布)、发布携带 Idempotency-Key(客户端生成并在重试间保持)、发布失败重试、成功后 Feed 可见引导。字段对齐契约(title 可选 120、content 1~10000、category)。
- **验收标准**:草稿→发布→Feed 出现全链路真实后端;断网发布重试不产生重复帖;四态与校验提示齐备有测试。
- **依赖**T3-12、T3-13。
- **规模**L
#### T3-16 帖子详情与评论接入
- **仓库**patbond-flutter
- **描述**`post_detail_page.dart` 替换:详情取数、评论游标分页、发评论(client_request_id 幂等 + @ 回复)**乐观插入**(发送即上屏置 pending 态,失败标红可重试/撤回)、删除自己的评论。已删除/隐藏帖子的详情页兜底(404 → 友好提示并从列表移除)。
- **验收标准**:评论乐观插入失败回滚有 widget 测试;分页与 @ 回复展示正确;四态齐备。
- **依赖**T3-12T3-14 后并行于 T3-15。
- **规模**M
#### T3-17 点赞/收藏乐观更新与回滚
- **仓库**patbond-flutter
- **描述**:统一乐观更新工具(立即翻转 UI 与本地计数 → 请求失败回滚 + toast;快速连点合并为末态请求,防抖;响应乱序以末次请求为准);Feed 卡片、详情页、收藏列表三处状态一致(同一帖子跨页面状态同源)。我的收藏列表页接入。
- **验收标准**:失败回滚、连点合并、跨页面一致各有 widget 测试;离线操作提示明确不假成功。
- **依赖**T3-12、T3-14。
- **规模**M
#### T3-18 关注 UI 最小版(条件单,随 D3-2)
- **仓库**patbond-flutter
- **描述**:若 D3-2 纳入:帖子作者处关注/取关按钮(乐观更新复用 T3-17 工具)、我的关注/粉丝列表页。不做关注 Feed tab。
- **验收标准**:关注状态跨页面一致;乐观回滚有测试。
- **依赖**T3-08、T3-17。
- **规模**S
### E 组:遗留、埋点与收口
#### T3-19 M2 高优先遗留清偿(第一波插入)
- **仓库**patbond-api、patbond-flutter
- **描述**:随 D3-8 拍板,PM 建议纳入两项:① auth 域契约测试补齐(机制复用 M2 契约测试框架,S);② 埋点队列完善(30s 定时冲刷、失败退避——429 依赖后端限流未做则先覆盖网络错误退避、anonymousId 持久化;方案见 iteration-2/15 §4)。与 M3 契约零耦合,第一波并行消化。
- **验收标准**:auth 全响应矩阵入契约测试;队列三项行为各有测试;不回归既有 272 前端测试。
- **依赖**D3-8 拍板。
- **规模**M
#### T3-20 社区埋点:字典 v3 与挂接
- **仓库**patbond-flutter(挂接)、patbond-api(白名单扩充)、patbond-doc(字典)
- **描述**:事件定义以 Experiment Tracker 的 M3 埋点方案为准(本单不自造字典;沿用 v1「结果编码进事件名」惯例与 ADR-013 纪律),预期覆盖发帖成功/Feed 浏览/点赞/收藏/评论等关键动作;随 D 组页面落地滚动挂接;埋点不含帖子内容明文。兼顾 ADR-012:A/B 前置 8 项目标 M3 末全绿,缺口由 Experiment Tracker 盘点。
- **验收标准**:关键动作事件端到端落库;白名单与字典同步;有测试。
- **依赖**Experiment Tracker 方案;T3-14~T3-17 滚动。
- **规模**S
#### T3-21 E2E 烟囱与验收取证
- **仓库**patbond-flutter(用例)、patbond-apicompose 环境)、patbond-doc(证据归档)
- **描述**:沿用 M2 收官战模式,烟囱场景对齐 M3 四条验收标准:账号 A 传图发帖 → 账号 B(另一客户端会话)Feed 可见并点赞/收藏/评论 → A 重复点赞并发验证计数 → 翻页期间新发布/删除验证分页 → A 删帖后 B 侧 Feed 与详情不可见 → 幂等重试发帖不重复。HTTP transcript 脱敏、数据库证据、门禁输出入档。
- **验收标准**:全场景绿;契约偏差 0;M3 四条验收标准逐条有证据。
- **依赖**T3-05、T3-06、T3-15、T3-16、T3-17。
- **规模**M
#### T3-22 文档与迭代收口
- **仓库**patbond-doc
- **描述**OpenAPI v1.3.0 归档、backend-modules.md 更新(新模块与 media 归属)、feature-checklist 增补、迭代报告归档与收官总结。**iteration-3 目录的 mkdocs.yml 导航由文档维护者收口提交统一添加(本拆解报告不改 mkdocs.yml**。
- **验收标准**`mkdocs build --strict` 通过;报告索引完整。
- **依赖**:各波交付。
- **规模**S
---
## 3. 波次划分与关键路径
沿用已验证模式:波次并行 + 迭代式契约冻结 + 同仓串行跨仓并行 + 每波 compose 实测。
### 第一波(并行开工)
| 并行线 | 工单 | 说明 |
| --- | --- | --- |
| 数据与骨架 | T3-01 → T3-02 | V5 + community 骨架,一人连续负责 |
| media 闭环 | T3-03 | **需 D3-1 开工前拍板**;未拍板时可先做 asset 元数据/状态机 + 存储接口抽象,把供应商差异隔离在适配层 |
| 契约草案 | T3-10(起草态) | TODO-FREEZE 标注三处待定型点 |
| 前端遗留 | T3-19 | 与 M3 契约零耦合 |
| UI 设计 | Feed/发帖/详情四态与空态设计稿 | 供 T3-14~16,不占关键路径 |
### 第二波(后端纵切,契约收敛)
| 并行线 | 工单 | 说明 |
| --- | --- | --- |
| 后端主线 | T3-04 → T3-05 / T3-06 / T3-0704 后三线并行);条件单 T3-08/T3-09 随拍板插入 | T3-04 帖子生命周期是全部互动单的前置 |
| 前端骨架 | T3-12 分层骨架(不依赖契约部分) | Repository/状态骨架先行 |
| 测试滚动 | T3-11 | 即测即绿即提交 |
**波末闸门:T3-10 契约冻结**(条件:T3-03 凭据形态 + T3-04 权限/错误语义 + T3-05 卡片字段定型;快照同步升版)。不冻结不放行第三波联调。
### 第三波(冻结契约下两端并行)
| 并行线 | 工单 | 说明 |
| --- | --- | --- |
| 前端主线 | T3-12(完成)→ T3-13 → T3-14 → T3-15 / T3-16 / T3-17(可两人并行);条件单 T3-18 | 媒体上传客户端先通,发帖流程才有意义 |
| 后端旁路 | 契约测试补齐、Feed 分页专项、性能核对 | 不占关键路径 |
| 埋点 | T3-20 | 随页面落地滚动挂接 |
### 第四波(收官)
T3-21 E2E 烟囱 → T3-22 文档收口 → 任务板更新与验收报告。
### 关键路径
```text
[D3-1 拍板] → T3-03(L) → T3-04(L) → T3-05(L) → [T3-10 冻结] → T3-12 → T3-13(L) → T3-15(L) → T3-21
```
五个 L 工单串在关键路径上,media 双端(T3-03/T3-13)占其二——媒体链路是周期决定因素。压缩手段:D3-1 置顶开工前拍板;T3-03 存储适配层先行;T3-10 草案与 T3-12 骨架前移;T3-06/07/16/17 走旁路。
---
## 4. 需要用户拍板的决策清单
以下决策 PM 只给建议,**不替用户拍板**。D3-1 是头号,阻塞关键路径起点;D3-1~D3-6 建议开工前裁决。
| # | 决策事项 | 影响 | PM 建议(仅供参考) |
| --- | --- | --- | --- |
| D3-1 | **对象存储选型**(第一迭代 D4 → M2 D2-1 三度上桌,本迭代无法再拖)。候选路径:**A. 自建 MinIO**S3 兼容,compose/Testcontainers 即起,后续平滑迁云 S3 兼容服务);**B. 云厂商对象存储**(阿里 OSS/腾讯 COS/AWS S3:免运维、自带 CDN,但引入账号/密钥/成本与 CI 外部依赖,且当前无生产部署环境承接);**C. 本地磁盘/DB 临时方案**(不建议:与 `storage_type='object'` 模型冲突、无预签名能力、迁移即返工) | 阻塞 T3-03/T3-13 全部媒体链路(关键路径起点);决定上传协议(预签名直传 vs 服务端中转)、URL 签发/公共读策略、compose 与 CI 编排、M4 AI 输出存储 | **方案 AMinIO)起步**:S3 SDK 编码,供应商差异收敛在配置层,生产化阶段(M6)再评估迁云;上传走预签名直传(服务端不过流量);读取侧首版公共读桶 + 稳定 URL,签名读后置 |
| D3-2 | **关注是否首版**M3 原文含"关注",但 demo 无关注 UI、四条验收标准均不涉及关注;完整关注体系 = follow 写入 + 关注 Feed + `visibility='followers'` 三层 | 全量纳入约 +1M(后端)+1M(前端)并拖长契约面;全剪则 M3 原文范围有显式缺口 | **中间态**T3-08/T3-18 最小版纳入(follow/unfollow 幂等 + 列表 + 按钮),**关注 Feed tab 与 followers 可见性后置**(首版 visibility 固定 public,字段保留);若周期紧张可整体后置,在收官总结记范围缺口 |
| D3-3 | **话题是否首版**M3 原文含"话题"demo 帖面有 tags 展示但无话题页;topics 模型已就绪 | 纳入 +1M(T3-09)+ 前端话题选择/话题页;剪出则 demo tags 位需处理 | **首版剪出**,帖子先跑通"内容+图片"主干;topics 端点 M3.5/M4 随 AI 创作分类需求一起做(ai_creation category 天然关联)。demo tags 展示位首版收起 |
| D3-4 | **媒体形态**:图片先行、视频后置?每帖图片上限?图片是否必填? | 视频涉及转码/时长/封面帧,复杂度台阶式上升;上限影响 UI 与存储 | **图片先行**`kind='image'`,视频 M4+ 随 AI 视频输出统一考虑);每帖上限 9 图(对齐主流社区惯例);图片**非必填**(纯文字帖合法,content 本就 NOT NULL |
| D3-5 | **评论层级确认**DDL 已裁决单层平铺 + `reply_to_user_id` @ 回复(注释言明不做 parent_comment_id/递归) | 若推翻需数据模型变更提案(新列 + 树查询 + UI 缩进体系,约 +1L) | **沿用单层设计**,不做二级楼中楼;@ 回复已覆盖对话场景。若产品坚持多级,另立模型变更提案排 M3.5 |
| D3-6 | **模块归属**:① 社区域——沿 ADR-009 先例新建 `patbond-community`:8084vs 并入现有模块;② **media 域归属**——独立 `patbond-media`(:8085,跨域共享:用户头像/宠物照片/帖子/M4 AI 输出都写 media.assetsvs 并入 patbond-user(平台能力先例:埋点在 uservs 并入 community(本迭代唯一消费方) | 决定 T3-02/T3-03 骨架、compose 容器数(5 或 6)、CI 时长 | 社区**新建 `patbond-community`**(ADR-009 同理:数据所有权独立、微服务化边界清晰);media **倾向独立 `patbond-media` 小模块**(M4 起至少三个域消费,塞进任何业务模块都会造成反向依赖),但六容器对双人团队运维面偏重,若求稳可先并入 patbond-user(迁移链持有者,平台能力聚合),M4 前再拆 |
| D3-7 | **删除/隐藏语义与权限**:作者删帖(软删)与 `hidden`(运营位)的开放范围;帖主是否可删他人评论 | 影响 T3-04/T3-07 权限矩阵与 M3 验收标准四的取证口径 | 作者可删自己帖子与评论(软删);`hidden`/`archived` 字段保留但**不开放任何端点**(无运营后台,M6+);帖主删他人评论首版不做(涉治理策略,随举报体系一起设计) |
| D3-8 | **M2 遗留纳入范围**:① auth 契约测试(S);② 埋点队列完善(M);③ T2-12 §8 三项交互(单宠直进/归档入口/sterilizedOn,本身即待产品拍板项);④ iteration-2/09 契约-实现出入 5 项(64KB 上限、429 限流等) | 纳入挤占 M3 周期;不纳入债务滚动 | ①② 纳入(T3-19,第一波,与 M3 零耦合);③ 待产品对三项交互本身拍板后另排,不进 M3 计划;④ 其中 429 限流若不做,T3-19 退避按网络错误实现并记录依赖;跨迭代项(token 黑名单、mTLS)继续挂技术债清单不进 M3 |
| D3-9 | **作者公开资料获取方案**:Feed/评论需他人昵称头像,现无公开资料端点。候选:**A.** community 跨 schema 只读 identity.users(破"模块只读写自己 schema"纪律,需 ADR 豁免);**B.** Feign 批量调 user 内部接口(ADR-002 静态直连先例,`/internal/**` 保护范围内);**C.** user 增开公开资料端点由前端二次请求(N+1 且泄露面大) | 决定 T3-05/T3-07 响应组装方式与性能形态;亦影响 M4/M5 同类需求的先例 | **方案 B**user 模块增 `/internal` 批量公开资料接口(仅昵称/头像 assetId),community 侧 Feign 批量取并短 TTL 进程内缓存;跨 schema 只读若被选择须补 ADR 明确豁免边界 |
---
## 5. 遗留项插入位置汇总
| 遗留项(iteration-2/29 §4 口径) | 优先级 | 插入位置 |
| --- | --- | --- |
| media 域(ADR-010 剪出项) | 最高(M3 天然落点) | **T3-03/T3-13 主线工单**;宠物头像/疫苗证书/事件附件的**接入**不在 M3(属 pet 域回填,media 通了之后 M3.5 顺手做,本迭代只交付能力) |
| auth 域契约测试 | 高 | **T3-19,第一波**(随 D3-8 |
| 埋点队列完善(30s 冲刷/退避/anonymousId | 高 | **T3-19,第一波**(随 D3-8 |
| T2-12 §8 三项交互 | 中(待产品拍板) | 不进 M3 计划,拍板后另排(D3-8③) |
| 照护人邀请流程(ADR-015 后置项) | 中 | 不进 M3(社区已满负荷),M3.5+ 候选 |
| health_record_deleted 事件 | 低 | 随 pet 域删除端点设计,不进 M3 |
| 真机补验两项(iteration-2/30) | 挂起 | 真机到位即插入,不阻塞 M3(约 0.5 天) |
| token 黑名单、/internal mTLS | 中(跨迭代) | 技术债清单,加固阶段处理;D3-9 若选 Feign 方案,mTLS 需求权重上升,记入债项说明 |
---
## 6. 风险清单
| # | 风险 | 影响 | 缓解措施 |
| --- | --- | --- | --- |
| R1 | **媒体链路全新且横跨双端**:对象存储、上传协议、状态机、CI 容器、客户端选图压缩上传全部从零;T3-03 + T3-13 占关键路径两个 L | 估算失准直接拖垮迭代周期 | D3-1 开工前拍板;存储适配层隔离供应商差异;范围钉死"图片先行 + 预签名直传 + 公共读"最小面;MinIO Testcontainer 让 CI 无外部依赖;每波 compose 实测媒体链路 |
| R2 | **D3-1 拍板拖延**:三度遗留的决策,再拖则关键路径起点空转 | 第一波 media 线停摆 | 决策清单置顶;未拍板期间 T3-03 先行做元数据/状态机/接口抽象(明确止损线:适配层以上不写供应商代码) |
| R3 | **乐观更新回滚复杂度**:点赞/收藏/评论三处乐观 UI,叠加快速连点、响应乱序、跨页面状态同源、离线场景 | 前端状态 bug 密集区,返工黑洞 | T3-17 先建统一乐观更新工具再铺页面;widget 测试矩阵(失败回滚/连点合并/乱序末态)作为 DoD 硬项;服务端幂等兜底(重复请求无害) |
| R4 | **Feed 正确性与性能**:翻页间隙增删导致丢帖/重帖;liked-by-me 逐帖查询 N+1;计数列与关系表漂移 | 直接命中 M3 验收标准二、三 | 复合游标 `(published_at, id)` 严格实现(索引已就绪);liked/bookmarked 批量 IN 查询;计数同事务更新 + 对账测试;T3-11 分页专项测试矩阵 |
| R5 | **作者资料组装成为性能与架构双坑**D3-9):Feed 每页 20 帖若逐个查作者即 N+1 跨服务调用 | Feed 延迟高、服务间耦合失控 | D3-9 开工前拍板;无论何种方案都要求**批量**接口 + 缓存;契约测试锁定卡片字段避免前端二次拼装 |
| R6 | **UGC 无审核机制上线**:帖子/评论/图片全开放,无敏感词、无举报、无运营后台 | 内容风险敞口(虽 MVP 阶段用户面小) | 模型已留 `hidden` 运营位(D3-7 保留字段不开放端点);数据库侧可手工 hidden 应急;举报/审核入 backlog 并在收官总结显式声明敞口,产品知情 |
| R7 | **契约面与冻结节奏**:media 凭据、Feed 卡片、公开资料三处形态开工时未定型,比 M2 的 TODO-FREEZE 面更宽 | 冻结延迟连锁推迟第三波 | 三处待定型点第一波即在草案中显式标注并限期收敛(第二波中期);冻结闸门纪律不放松,偏差显著上报 |
| R8 | **CI 时长与容器数增长**:五~六应用容器 + MinIO + 测试数从 191/272 继续上量 | 门禁反馈变慢被绕过 | T3-11 记录每波 CI 时长;超阈值按模块分层执行;不降低"提交前全绿"标准 |
| R9 | **未提交/未推送风险**(第一迭代 R3 教训惯例项) | 工作量全损 | 每波每单交付即提交即推送(ADR-011:只推 dev);PM 每波核对三仓 `git status` 与远端同步 |
| R10 | **demo 替换的 UI 落差**`home_page.dart`/`create_page.dart` 是 demo 中视觉最重的页面,真实数据字段与 demo 卡片(breedTag、tags、精选图)不完全对齐 | "替换后不如 demo 好看"的观感回退,或前端擅自造字段 | 第一波 UI 稿先行明确真实字段下的卡片形态(含无图帖、无头像作者的降级样式);缺失字段一律走契约提案不留本地拼凑 |
---
## 7. 质量要求(对全部工单生效)
- 遵守开发计划第 10 节 DoD:不依赖 Demo 常量;权限、校验、幂等、并发已处理;文档同步更新;干净环境可复现。
- 契约规范沿用:camelCase、UUID 字符串、ISO 8601 + timestamptz、统一信封与稳定错误码、cursor 分页(Feed 禁 OFFSET)、Idempotency-Key、version 乐观锁;**契约冻结后 api 侧字节级快照同步升版**。
- 不提交任何密码、token、对象存储密钥(`.env`/`.sample` 模式,ADR 纪律);埋点不含帖子内容明文与敏感信息。
- 集成测试一律 Testcontainers postgres:18ADR-006/008),媒体测试用 MinIO 容器(随 D3-1);每单交付 `./mvnw clean test``flutter analyze` + `flutter test` 全绿。
- 所有网络页面四态(loading/empty/error/retry)齐备;图片位另加占位/失败态。
- 本迭代不实现 AI 创作、预约、通知推送的任何接口或页面;`generation_job_id`/`region_id` 仅预留;范围外需求记 backlog。
## 8. 工单统计
- 工单总数:**22**(数据与工程基础 3 + 后端社区纵切 6 + 契约与测试 2 + Flutter 7 + 遗留与收口 4),其中 **3 个条件单**T3-08/T3-09/T3-18,随 D3-2/D3-3 拍板启停)
- 规模分布(核心 19 单):S × 2、M × 12、L × 5;条件单另计 S × 1、M × 2
- 关键路径:D3-1 拍板 → T3-03 → T3-04 → T3-05 → 契约冻结 → T3-12 → T3-13 → T3-15 → T3-21L × 5 在链上,media 双端占其二
- 待拍板决策:**9 项**D3-1~D3-9D3-1 头号且阻塞关键路径起点,D3-1~D3-6 建议开工前裁决)