- 21~26 Flutter 社区接入五单 + 字典 v3 白名单(flutter 286→502、api 325→334) - 27 收口总表:社区 demo 三页消亡、M3 四条验收标准逐条取证、 乐观更新与媒体链路端到端、实现期修正记录 - device-verification.md 的 M3 四项真机步骤已由各单收口补全 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,303 @@
|
||||
# 26 M3 第三波:发布页替换(T3-17)
|
||||
|
||||
**执行日期**:2026-09-10
|
||||
**工单**:T3-17 发布页替换——第三波收尾单,组装 T3-13 的 MediaUploader,接通发布漏斗埋点
|
||||
**依赖**:21 号(T3-12 数据层)、23 号(T3-13 MediaUploader 与孤儿防护)、15 号(后端帖子生命周期语义)、05 号 §2.3/§3.2/§3.3(P3 规范)、22 号(事件白名单 v3 实际收录名)、25 号(T3-15/16 埋点封装与页面惯例)
|
||||
**提交**:patbond-flutter dev `9892b65`(基线 `f873acf`),已推送 origin/dev
|
||||
|
||||
---
|
||||
|
||||
## 0. 概要
|
||||
|
||||
社区发布链路整条真实化:新建 `PostComposePage`(05 号 P3 规范,push 全屏页、
|
||||
路由名 `post_form`),组装 `MediaUploader` + `UploadProgressOverlay` 成编辑态
|
||||
九宫格;发布按「**createPost(draft) → PATCH status=published**」两步走,
|
||||
三条失败语义(40905 / 42203 / 网络)各有明确 UI 与埋点;发布漏斗五事件 +
|
||||
媒体上传三段全部挂接。create 页只余 AI 生成模拟(M4 原样保留),
|
||||
`AppState.posts` / `publishPost` / `updatePost` 及其 shared_preferences
|
||||
持久化整体退役。**未动 patbond-api。**
|
||||
|
||||
| 文件 | 性质 | 职责 |
|
||||
|------|------|------|
|
||||
| `lib/features/community/post_compose_page.dart` | 新增 | 发布页本体(结构、gating、两路径、失败语义、草稿恢复) |
|
||||
| `lib/features/community/post_analytics.dart` | 新增 | post 域埋点封装(发布漏斗 5 + 媒体三段 3,枚举编译期锁死) |
|
||||
| `lib/core/widgets/post_media_grid.dart` | 扩展 | 新增 `PostMediaEditGrid` 编辑态(+格/删除角标/进度层/重试) |
|
||||
| `lib/features/community/media_uploader.dart` | 扩展 | 媒体三段埋点挂接(attemptSeq / durationMs / cancelled) |
|
||||
| `lib/features/community/community_repository.dart` | 扩展 | `createPost` 支持调用方持键(同键重放) |
|
||||
| `lib/features/community/community_display.dart` | 扩展 | 发布/草稿失败话术映射(服务端 message 不上屏) |
|
||||
| `lib/analytics/analytics_page_name.dart` | 扩展 | 页名枚举补 `post_form`(字典 v3 页面族) |
|
||||
| `lib/features/main/main_shell_page.dart` | 扩展 | `openCompose(entryPoint)` push + 发布成功回 Feed 刷新 |
|
||||
| `lib/features/create/create_page.dart` | 改造 | demo 发布流退役 + 顶部「发布动态」真入口;AI 模拟零改动 |
|
||||
| `lib/features/home/home_page.dart` | 改造 | story「发布」与空态 CTA 改为 push 发布页(entryPoint=feed) |
|
||||
| `lib/state/app_state.dart` / `profile_page.dart` | 改造 | demo 帖子列表与持久化退役;「我的作品」改直读 demo 家具 |
|
||||
| `integration_test/publish_live_test.dart` | 新增 | 桌面真链路实测(env 门控,默认跳过) |
|
||||
|
||||
**质量门禁**:`flutter test` 502/502 全绿(基线 458,+44;另 2 个 env 门控
|
||||
compose 冒烟默认跳过)、`flutter analyze` 0 问题、
|
||||
`dart format --set-exit-if-changed` 无 diff、compose 六容器真链路实测通过(§5)。
|
||||
|
||||
## 1. 页面结构(05 号 §2.3 逐条对照)
|
||||
|
||||
自上而下:`已恢复上次草稿`提示条 → 发布失败横幅(+「草稿已保存」附注)→
|
||||
`已保存草稿 ✓` → **媒体编辑区**(3 列九宫格 + 「+」格)→ 页级上传汇总条 →
|
||||
正文(`minLines 6` 自增、`maxLength 1000` 计数器)→ 分类(`日常分享` /
|
||||
`求助` 二选)→ 位置 ListTile(占位);AppBar:左「取消」、标题「发布动态」、
|
||||
右「存草稿」+「发布」(高 40 / 水平 padding 20,禁用与转圈锁定)。
|
||||
|
||||
`PostMediaEditGrid`(05 §3.2 编辑态)实现要点:1:1 `cover`、格间距 4、圆角
|
||||
`sm`(12);缩略图直接 `Image.memory(previewBytes)`(选图原始字节,不落磁盘、
|
||||
不走网络,解码失败回落 `surfaceTint` + pets 图标);每格叠
|
||||
`UploadProgressOverlay` 六态→四视觉态;删除角标 22 圆 `ink` 80% + 白 close
|
||||
14(padding 撑到 32 触控热区);「+」格 1.5px **虚线**(Flutter 无内置虚线
|
||||
边框,按规范自绘 `_DashedBorderPainter`)、满 9 张隐藏。页级汇总条为
|
||||
「正在上传 n/N」+ `LinearProgressIndicator`(值条 `primaryStrong`、轨道
|
||||
`surfaceTint`)。
|
||||
|
||||
**与 05 号的偏差(4 项,均记录理由)**:
|
||||
|
||||
| # | 规范 | 本单实现 | 理由 |
|
||||
|---|------|---------|------|
|
||||
| 1 | 可发布条件「正文非空**或**媒体 ≥1」 | 正文非空 **且** 在场媒体全 ready | 后端 `content` 全程必填 1~10000(15 号 §2.4),「只发图不写字」在服务端不可能成功,不给按不亮的钮 |
|
||||
| 2 | 展示态与编辑态「一个组件」 | 同文件两个类(`PostMediaGrid` / `PostMediaEditGrid`) | 展示态以「≥1 张图 + URL 列表」为构造前提(既有断言),编辑态常态是「0 张图 + 一个+格」;共用签名会让两边都别扭 |
|
||||
| 3 | 内容变更后**静默自动保存**(防抖 2s) | 不做自动保存,只有「存草稿」与「取消 → 保留」两个显式动作 | 一次 `createPost` 只能建一份草稿(幂等键一次一用),自动保存要么反复建草稿要么每次 PATCH,收益不抵复杂度;且 06 §1.4 明确「自动保存不埋点」,无观测价值。列入遗留(§7) |
|
||||
| 4 | 「已保存草稿 ✓」置底部安全区上方 | 置提示条区(AppBar 之下) | 提交钮在 AppBar(顶部),反馈跟随触点;置底会出现「点了顶部按钮、底部看不见的反馈」 |
|
||||
| 5 | 话题行(TopicChip + 话题选择 shet) | 不渲染 | 契约无话题端点(21 号 §5),`topicCount` 埋点恒 0;随话题域落地补 |
|
||||
|
||||
拖拽排序(05 §6 D9 可选项)未做:**删格即整组重排**——position 由
|
||||
`buildAttachRequests` 按当前列表序 0..n-1 重发号(widget 测试实证「3 图删中间
|
||||
→ position 0,1、assetId 为 a-1/a-3」)。
|
||||
|
||||
## 2. 两条提交路径与草稿最小实现
|
||||
|
||||
```
|
||||
直接发布:createPost(status=draft, media=全ready挂接) ──► PATCH {version, status=published}
|
||||
↑ 幂等键由页面持有(同键重放) ↑ 失败时草稿已在服务端
|
||||
存草稿退出:createPost(status=draft) 或 PATCH(已有草稿:内容/类目/media 增量)──► 离页
|
||||
```
|
||||
|
||||
**为什么发布也先建草稿**:这样「发布失败但草稿已保存」是事实而非话术——
|
||||
迁移那一步失败时草稿已落库,UI 才敢显示「草稿已保存,可稍后继续发布」,
|
||||
重试也只补 PATCH 不重建帖(widget 测试断言 `created` 仍为 1 条)。
|
||||
|
||||
**幂等纪律**:建草稿的 `Idempotency-Key` 由**页面**持有(仓库层新增
|
||||
`createPost(request, {idempotencyKey})`,缺省仍是每次换新键,既有调用方
|
||||
不受影响):网络失败重试沿用同键 → 服务端命中首帖不重复建帖;**表单一经
|
||||
改动即弃用旧键**(下次提交换新键),使 40905 不会常态化。
|
||||
|
||||
**media 三态用法**(15 号 §2.6):以「上次同步到服务端的 ready assetId 签名」
|
||||
与当前签名比对——一致则 PATCH **缺席不动**(刚建的草稿不重复整组替换,也
|
||||
保住恢复草稿的既有图),不一致则整组替换,本地清空则传 `[]`。
|
||||
|
||||
**草稿管理最小实现**:进页 `listMyPosts(status=draft, limit=1)` 恢复最新一条
|
||||
(提示条「已恢复上次草稿」+「清空」;正文/类目预填;既有图以「草稿已含 N
|
||||
张图片(发布时保留;重新选图将整组替换)」呈现——`MediaUploader` 只持本地
|
||||
选图字节,服务端 asset 不回灌编辑器)。恢复失败静默降级为新建,不打扰。
|
||||
「取消 → 不保留」且服务端已有草稿 → `deletePost` 软删(`post_deleted` 的
|
||||
M3 唯一触点)。**完整草稿列表页(`draft_list`)留待**(§7)。
|
||||
|
||||
## 3. gating 与失败语义
|
||||
|
||||
**gating**:`正文非空 && (无媒体 || 全部 ready) && 无在途提交`——「全部
|
||||
ready」直接用 `MediaUploader.allReady`,与 `buildAttachRequests` 的
|
||||
`StateError` 孤儿防护形成双保险(gating 拦在前,类型层兜在后)。
|
||||
|
||||
| 失败 | UI 呈现(横幅,页内停留) | 客户端动作 | 埋点 failureReason |
|
||||
|------|--------------------------|-----------|-------------------|
|
||||
| **40905** 同键异 hash | 「提交内容与上次重试不一致,已重置提交标识,请再点一次「发布」」 | 弃用旧幂等键(下次换新键即成功) | `validation_error`(+errorCode 40905 / httpStatus 409) |
|
||||
| **42203** asset 未 ready | 「有图片还没上传完成,请等图片就绪后再发布」 | 保留内容,等图 ready 后重试 | `media_upload_incomplete` |
|
||||
| **网络失败** | 「网络异常,请检查网络后重试」(+ 草稿已落则附「草稿已保存,可稍后继续发布」) | 同键重放;已建草稿只补 PATCH | `network_error`(无 errorCode) |
|
||||
| 40000 参数 | 「内容不符合发布要求,请修改后重试」 | 保留内容 | `validation_error` |
|
||||
| 40403 草稿已被别处删 | 「草稿已不存在(可能已在别处删除),请重新发布」 | 解除草稿关联,重试走全新建草稿 | `not_found`(沿 06 §1.4 失败枚举基底的 not_found 复用条) |
|
||||
| 40902 乐观锁 | (不上屏)自动 `getPost` 取新 version 重提一次 | 再失败才落横幅 | `server_error` 兜底 |
|
||||
| 会话失效 | 应用自动回登录页 | — | **不上报**(feed / 互动域同款口径) |
|
||||
|
||||
发布成功:`MediaUploader.reset()` → `pop(true)` → 主壳切首页 Tab +
|
||||
`controller.refresh()` 整体替换 → 新帖按 `(published_at DESC, id DESC)`
|
||||
落首位 + SnackBar「已发布,去首页看看吧 🐾」(主壳级 widget 测试逐条断言)。
|
||||
|
||||
## 4. 埋点挂接清单(8 事件,按 22 号实际收录名)
|
||||
|
||||
| # | 事件 | 触发点 | props | 挂接位置 |
|
||||
|---|------|--------|-------|---------|
|
||||
| 1 | `post_create_started` | 进页后**首次输入**(首个字符或首次选媒体),每次进入一次 | entryPoint(create_tab / feed) | 发布页输入与 uploader 监听 |
|
||||
| 2 | `post_draft_saved` | 草稿保存**成功响应后** | trigger(manual / on_exit)、mediaCount | 「存草稿」与「取消 → 保留」 |
|
||||
| 3 | `post_publish_succeeded` | 迁移发布成功响应后 | durationMs、mediaCount、topicCount、textLengthBucket、fromDraft | 发布回调 |
|
||||
| 4 | `post_publish_failed` | 发布任一步失败 | failureReason、errorCode、httpStatus、attemptSeq | 发布回调(§3 映射表) |
|
||||
| 5 | `post_deleted` | 「不保留草稿」软删成功后 | (空集) | 离页确认弹窗 |
|
||||
| 6 | `post_media_upload_started` | 单文件一次尝试开始(含压缩段) | mediaType、sizeBucket | `MediaUploader._run` |
|
||||
| 7 | `post_media_upload_succeeded` | confirm 返回 ready 后 | mediaType、sizeBucket、durationMs | `MediaUploader._uploadAndConfirm` |
|
||||
| 8 | `post_media_upload_failed` | 单文件失败 / 在途被删格(cancelled) | mediaType、sizeBucket、failureReason、errorCode、httpStatus、attemptSeq | `MediaUploader._fail` / `_reportCancelled` |
|
||||
|
||||
口径说明(单测/widget 测试逐字段断言):
|
||||
|
||||
- **`entryPoint` 收敛为两值**:`create_tab`(创作 Tab 顶部「发布动态」)与
|
||||
`feed`(首页 story 环「发布」+ Feed 空态 CTA);topic_detail / pet_detail
|
||||
随对应页面启用。
|
||||
- **`fromDraft` 口径**:指「本次发布基于**先前保存/恢复的草稿**」;发布内部
|
||||
的建草稿→迁移两步**不算**(否则该字段恒真、失去分析意义)。
|
||||
- **`durationMs`**:`post_create_started` → 发布成功;媒体段为单次尝试
|
||||
started → ready。
|
||||
- **`sizeBucket` 取原图字节数**(压缩前),保证同一次尝试三段事件桶值一致;
|
||||
精确字节数、文件名、路径、URL 一律不出端(红线 4)。
|
||||
- **`attemptSeq`**:发布为本页发布尝试序号;媒体为单图尝试序号(retry 递增,
|
||||
重试的 started 与 failed 同序号)。
|
||||
- **`textLengthBucket`** 复用 `community_interaction_analytics.dart` 的
|
||||
`textLengthBucketOf`(不重复实现),精确字数不出端(红线 1)。
|
||||
- **`topicCount` 恒 0**(无话题端点);postId / assetId 等内容 ID 一律不进
|
||||
props(红线 2)。
|
||||
- **自动保存不埋**(06 §1.4)——本单索性不做自动保存(§1 偏差 3)。
|
||||
- **锁死事件不发**:`post_impression` / `post_viewed` / `comment_create_started`
|
||||
/ 单点互动失败等 7 项(22 号 §1 末段)本单未提供任何封装。
|
||||
- **page_viewed 页名核对**:发布页是 push 路由,`RouteSettings(name:
|
||||
'post_form')` 由既有 `AnalyticsRouteObserver` 自动上报;`post_form` 已在
|
||||
22 号 §2 的 v3 页面族内(字典侧仅 javadoc 登记,**后端零改动**)。客户端
|
||||
枚举补 `postForm`。创作 Tab 仍报 `create`(AI 创作面,语义未变)。
|
||||
- **未接触点**:`post_deleted` 除草稿丢弃外的「删已发布帖」触点无 UI(M3
|
||||
无删帖入口),随删帖 UI 启用;`experiment_exposed` 仍属 M4。
|
||||
|
||||
## 5. compose 实测
|
||||
|
||||
后端 patbond-api dev@`8089c06`(零改动)六容器 `docker compose up -d --build`
|
||||
全部 Up、postgres/minio healthy;测毕 `docker compose down` 干净退出。
|
||||
|
||||
```bash
|
||||
cd <你的工作区>/patbond-api
|
||||
./deploy/init-secrets.sh
|
||||
JAVA_HOME=<你的 JDK17 路径> ./mvnw -DskipTests package # BUILD SUCCESS
|
||||
docker compose up -d --build
|
||||
|
||||
cd <你的工作区>/patbond-flutter
|
||||
PATBOND_PUBLISH_LIVE=1 flutter test integration_test/publish_live_test.dart -d linux
|
||||
# 00:06 +1: All tests passed!
|
||||
|
||||
cd <你的工作区>/patbond-api && docker compose down
|
||||
```
|
||||
|
||||
### (a)Linux 桌面真链路 + 跨客户端可见性取证
|
||||
|
||||
`integration_test/publish_live_test.dart`(env 门控 `PATBOND_PUBLISH_LIVE=1`,
|
||||
默认跳过)驱动**真实 App**(桌面渲染管线 + 生产 ApiClient / Repository /
|
||||
CommunityController / MediaUploader / 直传客户端)走完整一轮:
|
||||
|
||||
注册两个一次性账号 → **A 登录** → 创作 Tab「发布动态」→ 输入正文 → 选图
|
||||
(真 `createUpload`@user:8082 → 真预签名 PUT@MinIO:9000 → 真 `confirm`)→
|
||||
发布钮由禁用转可点(gating 实证)→ 发布(建草稿 → PATCH 迁移)→
|
||||
**回首页 Feed,新帖置顶且 mediaCount=1** → **另起一个全新 App 实例**
|
||||
(换 key 强制重建:新 SessionManager / 新 Controller / 新 HTTP 客户端,
|
||||
等价于另一台客户端首次登录)**以 B 账号登录 → B 的 Feed 首位就是该帖**
|
||||
——M3 验收「发布后可在另一客户端看到」取证。**一次通过。**
|
||||
|
||||
桌面替身仅两处:**选图与压缩**——`image_picker` 与
|
||||
`flutter_image_compress` 均无 Linux 平台实现(桌面选图这一步在 Linux 上物理
|
||||
不可达),实测注入 1x1 真 PNG 字节与透传压缩,其余全为生产实现。原生选图/
|
||||
压缩行为仍属真机项(device-verification M3 第 1 项 (e))。
|
||||
|
||||
落库核对(psql):
|
||||
|
||||
```text
|
||||
community.posts: status=published, category=general, version=1, published_at≠null, media=1
|
||||
media.assets: status=ready, mime_type=image/png, byte_size=70
|
||||
```
|
||||
|
||||
### (b)后端语义三点复核(curl,与客户端实现对齐)
|
||||
|
||||
| 复核 | 结果 |
|
||||
|------|------|
|
||||
| 建草稿 → 迁移发布的 version 走线 | `createPost(draft)` 返回 **version 0** → `PATCH {version:0, status:published}` → **published / version 1 / publishedAt 非空**(客户端用响应 version,不硬编码) |
|
||||
| 同键异 payload | 同 `Idempotency-Key` 改正文 → **40905「幂等键已用于不同请求」** |
|
||||
| 引用未 ready asset | `createUpload` 后不上传直接发帖 → **42203「媒体尚未就绪」** |
|
||||
|
||||
三条与 §3 的 UI 语义一一对应,映射无偏差。
|
||||
|
||||
### (c)发布/媒体 8 事件白名单验真(curl,客户端真实 payload 形状)
|
||||
|
||||
`POST /api/v1/events`(user :8082)一批 8 条(platform=android,props 逐键
|
||||
按 §4 客户端实际形状)→ **202 accepted 8 / duplicated 0 / rejected 0**;
|
||||
`platform.product_events` 落库 props 完整无剥离:
|
||||
|
||||
```text
|
||||
post_create_started {"entryPoint": "create_tab"}
|
||||
post_draft_saved {"trigger": "on_exit", "mediaCount": 2}
|
||||
post_publish_succeeded {"fromDraft": true, "durationMs": 18200, "mediaCount": 2, "topicCount": 0, "textLengthBucket": "short"}
|
||||
post_publish_failed {"errorCode": 42203, "attemptSeq": 1, "httpStatus": 422, "failureReason": "media_upload_incomplete"}
|
||||
post_deleted {}
|
||||
post_media_upload_started {"mediaType": "image", "sizeBucket": "lt_1mb"}
|
||||
post_media_upload_succeeded {"mediaType": "image", "durationMs": 640, "sizeBucket": "lt_1mb"}
|
||||
post_media_upload_failed {"mediaType": "image", "attemptSeq": 2, "sizeBucket": "mb_1_5", "failureReason": "cancelled"}
|
||||
```
|
||||
|
||||
### (d)实测附带发现:桌面端埋点整批被拒(非回归,属既有预期)
|
||||
|
||||
桌面真链路运行时日志出现 `Analytics batch permanently rejected (400)`——
|
||||
原因是桌面 `platform` 值为 `linux`,而契约校验为
|
||||
`@Pattern(^(android|ios)$)`,**bean 校验整批 400**(不是逐条 rejected)。
|
||||
`analytics_service.dart` 的注释已声明桌面属「开发调试形态、上报被拒属预期」,
|
||||
但措辞是「逐条 rejected」,与实况(整批 400)有出入——**不改行为**,已在
|
||||
device-verification M3 第 4 项写明「v3 事件落库只能在 Android 上验证」,
|
||||
措辞修正留给埋点侧工单顺带处理(§7)。
|
||||
|
||||
## 6. 测试数变化
|
||||
|
||||
| 项 | 基线 | 本单后 |
|
||||
|----|------|--------|
|
||||
| flutter test | 458(+2 门控冒烟跳过) | **502(+44,门控冒烟跳过 2)** |
|
||||
| flutter analyze | 0 | 0 |
|
||||
| dart format | 无 diff | 无 diff |
|
||||
|
||||
新增分布:
|
||||
|
||||
- **发布页 widget 22**(`post_compose_page_test.dart`):gating 2(空正文禁用
|
||||
/ 在途禁用与全 ready 放行 + 汇总条)、直接发布 3(纯文字帖请求形状与漏斗
|
||||
事件、求助类目两图 position/封面/mediaCount、**删格重排** position 重发号)、
|
||||
失败三语义 4(网络**同键重放**实证两次同键、迁移失败「草稿已保存」且重试只
|
||||
补 PATCH、40905 换新键、42203 提示与埋点)、存草稿 5(manual / on_exit /
|
||||
「不保留」软删 + post_deleted / 「继续编辑」不动服务端 / 空表单直接离页)、
|
||||
草稿恢复 6(提示条与预填、恢复后只 PATCH 且 fromDraft=true、重新选图整组
|
||||
替换、40902 自动重提、「清空」、恢复失败静默降级)、结构 2。
|
||||
- **post 域埋点单测 11**(键集与白名单逐一对齐、分桶四档边界、异常 →
|
||||
failureReason 映射、隐私红线断言「无 postId / 无精确字数 / 无字节数」)。
|
||||
- **媒体三段埋点 7**(`media_uploader_test.dart` 扩展):成功一对且 sizeBucket
|
||||
同值 + durationMs、压缩终态 media_too_large、断连 → retry 的 attemptSeq
|
||||
递增、createUpload 40000 → unsupported_format 带 errorCode/httpStatus、
|
||||
在途删格 cancelled 与 ready 后删格不报、会话失效不上报。
|
||||
- **编辑态九宫格 widget 4**(空列表只出+格 / 满 9 隐藏+格 / 删除角标回传
|
||||
localId / 上传中与失败态覆盖层与整格重试,终态无重试通栏)。
|
||||
- **主壳发布闭环 1**(`main_shell_publish_test.dart`):创作 Tab 入口 → 发布 →
|
||||
回首页 + **两次 getFeed(整体刷新)** + 新帖置顶 + SnackBar。
|
||||
- 首页测试 1 处随回调改名更新(`onOpenCreate` → `onOpenCompose`),helpers 扩
|
||||
createPost/updatePost/deletePost/listMyPosts 钩子与幂等键记录、真 PNG 字节。
|
||||
|
||||
验证命令(patbond-flutter 仓库根执行):
|
||||
|
||||
```bash
|
||||
flutter analyze
|
||||
flutter test
|
||||
dart format --set-exit-if-changed --output=none .
|
||||
```
|
||||
|
||||
## 7. 遗留与交接
|
||||
|
||||
- **草稿自动保存与草稿列表页**:本单只做「显式两路径 + 进页恢复最新一条」。
|
||||
完整草稿管理(`draft_list` 页名已在 v3 页面族预留、我的帖子按 status 过滤
|
||||
的接口已就位)与 05 §2.3 的自动保存(防抖 2s)留待——自动保存需先定「一份
|
||||
草稿反复 PATCH」的语义与 `post_draft_saved` 不埋自动保存的口径衔接。
|
||||
- **话题域**:TopicChip / 话题选择 sheet / `topic_followed` 事件均待契约端点,
|
||||
`topicCount` 现恒 0。
|
||||
- **位置**:ListTile 为占位(无契约字段),点按 SnackBar 提示。
|
||||
- **AI 作品发布**:create 页 AI 结果是生成图(无本地文件、无 media asset),
|
||||
走不了两步上传,其「发布到社区」现为占位提示,随 M4 AI 能力一并接。
|
||||
- **拖拽排序**(05 §6 D9 可选)未做;删格重排已保证 position 正确。
|
||||
- **真机项**:device-verification.md「M3 预登记」第 4 项(社区事件落库)
|
||||
**本单已补全细则**——含发布漏斗成链、媒体三段逐文件成对与 attemptSeq、
|
||||
隐私红线核对、Feed 与互动事件、`page_viewed(post_form)` 页名归一化、
|
||||
rejected=0 六条通过标准,并写明「桌面 platform=linux 整批 400,落库只能在
|
||||
Android 验证」的前置事实。第 1 项(媒体弱网)与本项建议同一轮执行。
|
||||
- **埋点侧措辞修正**(非阻塞):`analytics_service.dart` 关于桌面上报被拒的
|
||||
注释应由「逐条 rejected」改为「整批 400」(§5d),留给埋点侧工单顺带处理。
|
||||
- `MediaUploaderFactory` 是**测试与桌面实测专用**注入口(生产恒缺省):
|
||||
Linux 桌面既无 image_picker 也无 flutter_image_compress 原生实现,真链路
|
||||
实测只替换选图与压缩两层。
|
||||
|
||||
---
|
||||
**Frontend Developer(Flutter)**
|
||||
**日期**:2026-09-10
|
||||
Reference in New Issue
Block a user