38d9e97174
CI / docs-build (push) Successful in 2m58s
- 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>
7.3 KiB
7.3 KiB
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 6038901→7d5c84d |
502→526 |
| 第一波(后端) | T3.5-04 用户资料读写 / -05 宠物头像 / -06 获赞聚合 | api a5634c5→d98a400 |
334→379 |
| 闸门 | T3.5-07 契约冻结 v1.4.0 + 四模块快照同步 + 矩阵扩展 | doc 5f02909 / api 3cd8005 |
矩阵 173→181 格 |
| 第二波(前端) | T3.5-08 资料页+编辑页 / -09 宠物头像接线 / -10 首页问候语 | flutter a4a97c0→6945436 |
526→597 |
波末状态:patbond-api 379 测试、patbond-flutter 597 测试全绿;契约 v1.4.0(32 路径/45 操作/75 schema);零 Flyway 迁移(ADR-022)。
1. 用户 6 项反馈的处置结果
| 反馈 | 处置 |
|---|---|
| ① 日历英文 | ✅ 补 flutter_localizations + zh-CN 三件套(此前从未配置,Flutter 静默回退英文);datePickerTheme 上品牌色,只复用已审计色对 |
② 月份只能 < > 切 |
✅ 抽 pickAppDate 收口 7 处裸调用;保留手输铅笔 + 表单行「今天」快捷(原生 showDatePicker 无法注入弹窗内动作,放表单行反而一键落值、绕开月份导航) |
| ③ 宠物无头像 | ✅ 铅笔角标接 MediaUploader(purpose=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.nickname(V1 第 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 前置短路。 - 宠物头像权限按「本次碰了哪些字段」定档:仅头像=WRITE(owner+caregiver),碰任一资料字段=MANAGE(仅 owner),混合取更严——堵住 caregiver 把改名夹带进头像请求。客户端纯头像 PATCH 只带
version+avatarAssetId(测试断言keys.length == 2)。 avatarAssetId只写不读:响应不外露,「有头像」等价avatarUrl != null。- 昵称长度按码点计(
runes.length):32 个 emoji 的合法昵称 UTF-16 长度为 64,按String.length会误拒数据库存得下的昵称。
4. 实现期发现与修正
/api/v1/me错线(先于本迭代存在):该端点由 user 服务(:8082) 提供,但ApiAuthRepository只挂了 auth(:8081),实测 404。此前无人消费me()故一直未暴露;已加userApi线路。- Feed 作者名 ≤60s 滞后是服务端设计:
AuthorProfileGateway有 60s TTL 进程内缓存;/me无缓存立即生效,故存在一分钟「资料页已变、Feed 还是旧名」的窗口。未改服务端,已写入注释与真机清单。 - 1×1 极小 PNG 能上传能下载但 Flutter 解码器拒绝(
Codec failed to produce an image),会被误判成「头像没传上」;夹具改 16×16。 - 中文「9月10日周四」在日期弹窗头部 26px 起折行 →
headerHeadlineStyle32→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. 遗留
- 「我的收藏与草稿」列表页未做(工单许可的裁剪):后端与仓库层均已就位,缺两个页面 + 导航,建议独立小工单(S~M,可照抄既有
CursorPage四态列表骨架) - 月份网格选择器未做(年份网格 + 手输 + 「今天」已覆盖实测痛点)
SegmentedButton选中态仍是fromSeed派生粉底(M2 遗留主题债),建议并入后续主题收敛单widthPx/heightPx恒 null(M3 观察项,单图帖回落 4:3)、eventVersion口径未定型——两项均未在本迭代处理- 真机验证:
device-verification.md新增 M3.5 节(头像上传弱网、头像缓存等 4 项 + 1 备注)
8. 待发布
v0.4.0 尚未发布。main 已受分支保护,须走 PR 流程(见 发布记录「发布后生效的纪律」):三仓 CI 绿 + E2E 双份回归 → Gitea 建 PR(dev→main)→ CI 状态检查转绿 → 合并 → 打 tag → 登记发布记录。