Files
patbond-doc/docs/development/iterations/iteration-3.5/06-wave2-closure.md
T
lixi 38d9e97174
CI / docs-build (push) Successful in 2m58s
docs: M3.5 收口报告 + 暴露面清单补全(文档站/处置记录/凭证纪律)
- 06 M3.5 收口:6 项用户反馈处置结果、迁移预估被审计推翻的教训、
  关键语义定型(/me 不回退、PATCH 三态、头像权限按字段定档、昵称按码点计)、
  实现期 4 项发现、契约 v1.4.0 纯增量承诺、遗留 5 项
- server-exposure.md 补:patbond-doc 文档站(漏记)、2026-09-11 处置记录、
  纪律 6「凭证不进任何可留存介质」与纪律 7「配置备份不留配置目录」

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-11 18:05:12 +08:00

7.3 KiB
Raw Blame History

06 M3.5 收口:体验补齐

执行日期2026-09-10 ~ 2026-09-11 交付形态:客户端体验修复 + 用户资料与头像全链路 + 契约冻结 v1.4.0;另含一次安全事件的处置与固化


0. 概要

M3.5 由用户在 v0.3.0 发布后的桌面实测反馈驱动(6 项问题),分两批交付。

批次 工单 提交 测试
第一批(纯客户端) M3.5-01 中文本地化 / -02 日期录入收口 / -03 花费卡月份 flutter 60389017d5c84d 502→526
第一波(后端) T3.5-04 用户资料读写 / -05 宠物头像 / -06 获赞聚合 api a5634c5d98a400 334→379
闸门 T3.5-07 契约冻结 v1.4.0 + 四模块快照同步 + 矩阵扩展 doc 5f02909 / api 3cd8005 矩阵 173→181
第二波(前端) T3.5-08 资料页+编辑页 / -09 宠物头像接线 / -10 首页问候语 flutter a4a97c06945436 526→597

波末状态patbond-api 379 测试、patbond-flutter 597 测试全绿;契约 v1.4.032 路径/45 操作/75 schema);零 Flyway 迁移ADR-022)。

1. 用户 6 项反馈的处置结果

反馈 处置
① 日历英文 flutter_localizations + zh-CN 三件套(此前从未配置,Flutter 静默回退英文);datePickerTheme 上品牌色,只复用已审计色对
② 月份只能 < > pickAppDate 收口 7 处裸调用;保留手输铅笔 + 表单行「今天」快捷(原生 showDatePicker 无法注入弹窗内动作,放表单行反而一键落值、绕开月份导航)
③ 宠物无头像 铅笔角标接 MediaUploaderpurpose=pet_avatar),列表/详情展示预签名头像
④ 资料页无法改昵称/头像、显示 demo 176 行硬编码 demo 退役;新增编辑页(昵称 + 头像 + 各自显式清除入口)
⑤ 本月花费 ¥0 非 bug——记录在 2026-04-09、当天 09-10,9 月确为 0;根因是 ②。改为显示实际月份(「9 月花费」)+ 四张数据卡补可点提示(原本都可点却无提示)
⑥ 资料页统计是假数据 关注/我关注/获赞/作品四个数字全部真实(/me + /me/community-stats + follow-stats
(未提)首页 demo 仅问候语真实化(ADR-022);天气/位置/圈子/促销卡刻意保留并在代码标注去向,另有 widget 用例反向钉住「保留项仍在」

2. 开工审计推翻了迁移预估(本迭代最大的省事项)

原估「需 Flyway V6 加列、规模 L」。逐一核实原始 SQL 后确认所需列全部早已存在

  • identity.users.nicknameV1 第 63 行,含 btrim + 1~32 CHECK)、avatar_asset_id(V1 第 67 行,含 FK + 索引)
  • pet_health.pets.avatar_asset_id(V3 第 64 行,含索引)——但 pet 模块代码此前零处读写
  • community.posts.like_count 等冗余列(V5)——获赞总数 SUM 即可
  • media.assets.purpose 无 CHECK 约束,白名单在配置项 MediaProperties.allowedPurposes → 加 user_avatar/pet_avatar 只改配置

教训:转述不可采信。「identity.users 无 nickname」来自 M3 T3-05 报告的一句表述,实际那句说的是「契约未暴露 nickname」。核实原始 SQL 只花几分钟,却把工作量预估降了一档。

3. 关键语义定型

  • /me 不做 username 回退(返回 DB 原值):回退是展示约定,若放进本人编辑态,编辑页会预填 llx,一保存就把它固化成真昵称,/internal 的回退链从此永不触发。回退只在客户端展示层做一层nickname ?? username)。
  • PATCH 三态(键缺省=不改 / 显式 null=清空 / 给值=设置):客户端以 PatchField<T> 类型承载,序列化单一路径。若把未改字段也发成 null,用户只改昵称就会连头像一起被清掉。纯空白昵称为 400 而非隐式清空;空 patch 前置短路。
  • 宠物头像权限按「本次碰了哪些字段」定档:仅头像=WRITEowner+caregiver),碰任一资料字段=MANAGE(仅 owner),混合取更严——堵住 caregiver 把改名夹带进头像请求。客户端纯头像 PATCH 只带 version + avatarAssetId(测试断言 keys.length == 2)。
  • avatarAssetId 只写不读:响应不外露,「有头像」等价 avatarUrl != null
  • 昵称长度按码点计runes.length):32 个 emoji 的合法昵称 UTF-16 长度为 64,按 String.length 会误拒数据库存得下的昵称。

4. 实现期发现与修正

  1. /api/v1/me 错线(先于本迭代存在):该端点由 user 服务(:8082) 提供,但 ApiAuthRepository 只挂了 auth(:8081),实测 404。此前无人消费 me() 故一直未暴露;已加 userApi 线路。
  2. Feed 作者名 ≤60s 滞后是服务端设计AuthorProfileGateway 有 60s TTL 进程内缓存;/me 无缓存立即生效,故存在一分钟「资料页已变、Feed 还是旧名」的窗口。未改服务端,已写入注释与真机清单。
  3. 1×1 极小 PNG 能上传能下载但 Flutter 解码器拒绝Codec failed to produce an image),会被误判成「头像没传上」;夹具改 16×16。
  4. 中文「9月10日周四」在日期弹窗头部 26px 起折行 → headerHeadlineStyle 32→22(只有真跑起来才看得见)。

5. 契约冻结 v1.4.0

  • 规模:路径 31→32、操作 43→45、schema 72→75(多出的 CommunityStatsEnvelope 为保持「每个 200 响应都 $ref 一个 Envelope」的一致性)
  • 对 v1.3.0 纯增量:无字段删改、无类型变更、无必填收紧,已写入 info.description 作为对既有集成方的承诺
  • 零新增错误码;四模块快照 md5 与正典一致;11 格「未声明字段即漂移」的红全部转绿;mutation 三处定向注毒自证有效

6. 安全事件(并行处置,已闭环)

本迭代期间 CI 全面失效,根因为 Gitea 被注入 gitconfig 的 packObjectsHook。完整复盘见 07 号,处置与纪律固化见新建的 服务器暴露面清单。要点:攻击未达成代码执行、三仓代码经核对未被篡改、无系统层入侵;服务器侧新增「决策与环境同步」等 7 条纪律。

7. 遗留

  1. 「我的收藏与草稿」列表页未做(工单许可的裁剪):后端与仓库层均已就位,缺两个页面 + 导航,建议独立小工单(S~M,可照抄既有 CursorPage 四态列表骨架)
  2. 月份网格选择器未做(年份网格 + 手输 + 「今天」已覆盖实测痛点)
  3. SegmentedButton 选中态仍是 fromSeed 派生粉底(M2 遗留主题债),建议并入后续主题收敛单
  4. widthPx/heightPx 恒 null(M3 观察项,单图帖回落 4:3)、eventVersion 口径未定型——两项均未在本迭代处理
  5. 真机验证:device-verification.md 新增 M3.5 节(头像上传弱网、头像缓存等 4 项 + 1 备注)

8. 待发布

v0.4.0 尚未发布。main 已受分支保护,须走 PR 流程(见 发布记录「发布后生效的纪律」):三仓 CI 绿 + E2E 双份回归 → Gitea 建 PRdev→main)→ CI 状态检查转绿 → 合并 → 打 tag → 登记发布记录。