diff --git a/docs/superpowers/specs/2026-03-28-wechat-message-forwarding-design.md b/docs/superpowers/specs/2026-03-28-wechat-message-forwarding-design.md new file mode 100644 index 0000000..3761055 --- /dev/null +++ b/docs/superpowers/specs/2026-03-28-wechat-message-forwarding-design.md @@ -0,0 +1,376 @@ +# Boss 原生 Android 微信式消息转发设计 + +## 1. 背景 + +当前 `Boss` 原生 Android 客户端虽然已经恢复到微信式一级结构,但“消息转发”仍停留在过渡态: + +- 原生入口还是单独的 `ProjectForwardActivity` +- 交互仍然是“选择目标项目 + 填写备注” +- 服务端接口 `POST /api/v1/projects/[projectId]/forwards` 也仍以 `targetProjectId + note` 为主 + +这条链路和用户要求的“微信最新逻辑”存在明显差距。用户已经明确要求: + +1. 既支持单条消息转发,也支持多选消息合并转发 +2. 转发流程要尽量按微信当前逻辑来 +3. 单条消息转发后在目标会话里表现为普通转发消息 +4. 多条消息转发后在目标会话里表现为聊天记录卡片 +5. 当前一次转发先只允许选择一个目标会话 +6. 转发链必须兼容现有线程会话、群聊会话和主 Agent 审批规则 + +因此,这次工作不是只换一个页面,而是要把“消息转发”升级成一条完整的微信式产品链路: + +- 原生 Android 交互回到微信式 +- 服务端账本结构能表达单条转发和聊天记录卡片 +- 目标会话选择页与当前线程会话模型一致 +- 群聊和审批规则能继续接入,而不是后续再重做 + +## 2. 目标 + +本次设计完成后,消息转发应满足以下目标: + +1. 单条消息可从消息操作菜单直接进入转发流程。 +2. 多条消息可通过多选模式进入合并转发流程。 +3. 单条和多条转发共用一个微信式目标会话选择页。 +4. 单次转发只允许选择一个目标会话。 +5. 单条消息转发到目标会话后,显示为普通消息,但保留转发来源元数据。 +6. 多条消息转发到目标会话后,显示为一张聊天记录卡片,不是多条普通消息的简单堆叠。 +7. 转发目标可以是单线程会话、群聊、`主 Agent`、`审计对话`。 +8. 非开发任务状态下,如果转发行为会引发线程之间不应直接沟通的情况,后端必须能返回“需要主 Agent / 用户审批”的结果,而不是直接放行。 +9. 这次改造不能破坏现有原生聊天页、会话信息页、群资料页和群聊创建链路。 + +## 3. 非目标 + +本次不做以下事项: + +1. 不支持一次转发到多个目标会话。 +2. 不支持转发前编辑消息内容。 +3. 不支持微信收藏、逐条再编辑、转发到外部应用等额外能力。 +4. 不在本次设计中完成“聊天记录卡片详情页”的完整浏览体验,只要求先把卡片消息结构和列表展示落下。 +5. 不改变当前原生 Android 架构、登录恢复、群聊模型或主 Agent 主链执行方式。 + +## 4. 用户体验设计 + +### 4.1 单条消息转发 + +单条消息转发按微信式链路执行: + +1. 用户在聊天页长按某条消息。 +2. 弹出轻量消息操作菜单。 +3. 菜单中点击 `转发`。 +4. 进入统一的 `选择一个会话` 页。 +5. 用户选择一个目标会话。 +6. 执行转发。 +7. 返回目标会话或给出轻量成功提示。 + +单条转发后的展示规则: + +- 在目标会话中显示为一条普通消息 +- 这条消息保留 `转发` 的轻量来源标识,但整体视觉不能变成控制台卡片 +- 账本结构中必须带上来源消息信息,便于后续扩展“查看原始消息” + +### 4.2 多选消息合并转发 + +多选消息合并转发按微信式链路执行: + +1. 用户在聊天页对消息执行 `多选` +2. 聊天页进入多选模式 +3. 用户勾选多条消息 +4. 点击底部 `转发` +5. 进入同一个 `选择一个会话` 页 +6. 用户选择一个目标会话 +7. 执行合并转发 + +多选转发后的展示规则: + +- 在目标会话中只生成一条消息 +- 该消息表现为“聊天记录卡片” +- 不能把多条消息逐条硬插入目标会话里 + +### 4.3 消息操作菜单 + +单条消息长按后的操作菜单,本次先保留以下动作: + +- `转发` +- `多选` +- `复制` +- `删除` +- `取消` + +规则: + +1. `转发` 直接进入统一转发流程 +2. `多选` 进入消息多选模式 +3. 本次不再把“填写备注”作为主流程的一部分 + +### 4.4 多选模式 + +多选模式的页面行为如下: + +顶部区域: + +- 左侧为 `取消` +- 中间显示已选消息数量 +- 不再显示普通聊天页标题和轻入口 + +消息区: + +- 每条消息左侧出现勾选控件 +- 已勾选消息有明显选中态 + +底部区域: + +- 先只保留 `转发` +- 不在本次加入更多多选操作,避免偏离微信主链 + +### 4.5 目标会话选择页 + +单条转发和多选转发共用一个目标会话选择页,规则如下: + +1. 页面标题为 `选择一个会话` +2. 页面第一屏直接显示微信式会话列表 +3. 会话 cell 沿用当前首页微信式会话样式 +4. 当前源会话本身不能作为目标被再次选中 +5. 当前一次只能选中一个目标会话 +6. 不要求用户填写备注 + +允许作为目标的会话类型: + +- 单线程会话 +- 群聊会话 +- `主 Agent` +- `审计对话` + +## 5. 数据模型设计 + +### 5.1 单条转发消息 + +单条消息转发后,在目标会话中仍表现为普通消息,但要补充“转发来源”元数据。 + +本次采用结构: + +```ts +type ForwardSource = { + sourceProjectId: string; + sourceProjectName: string; + sourceThreadId?: string; + sourceThreadTitle?: string; + sourceMessageId: string; + forwardedBy: string; + forwardedAt: string; +}; +``` + +落账本后的单条消息: + +```ts +type Message = { + id: string; + kind: "text" | ...; + body: string; + forwardSource?: ForwardSource; +}; +``` + +要求: + +1. 转发后的消息仍可作为普通消息渲染 +2. 必须保留来源项目、来源消息、来源线程的可追踪信息 +3. 不能只把原消息正文复制过去就结束 + +### 5.2 多条聊天记录卡片 + +多条消息转发后,应写成一条新的 bundle 型消息。 + +本次采用结构: + +```ts +type ForwardBundleItem = { + messageId: string; + senderLabel: string; + body: string; + kind: string; + sentAt: string; +}; + +type ForwardBundlePayload = { + sourceProjectId: string; + sourceProjectName: string; + sourceThreadId?: string; + sourceThreadTitle?: string; + itemCount: number; + startedAt: string; + endedAt: string; + items: ForwardBundleItem[]; +}; +``` + +落账本后的 bundle 消息: + +```ts +type Message = { + id: string; + kind: "forward_bundle"; + body: string; + forwardBundle?: ForwardBundlePayload; +}; +``` + +要求: + +1. 目标会话中只出现一张聊天记录卡片 +2. 卡片中要能生成合理摘要,如消息数、来源会话、时间范围 +3. bundle 的完整内容要落到账本,不能只存一个标题 + +## 6. 服务端接口设计 + +### 6.1 现有接口升级 + +当前已有: + +- `POST /api/v1/projects/[projectId]/forwards` + +这条接口应从“备注转发”升级成真正的微信式转发接口。 + +本次采用输入结构: + +```ts +type ForwardProjectMessageInput = + | { + mode: "single"; + targetProjectId: string; + sourceMessageId: string; + } + | { + mode: "bundle"; + targetProjectId: string; + sourceMessageIds: string[]; + }; +``` + +当前旧字段 `note` 不再作为主语义字段,允许兼容但不再作为核心交互入口。 + +### 6.2 返回结构 + +接口返回需要至少表达: + +```ts +{ + ok: boolean; + message?: Message; + approvalRequired?: boolean; + approvalReason?: string; +} +``` + +要求: + +1. 正常转发成功时返回目标会话中新生成的消息 +2. 需要审批时,不直接写入目标会话,而是返回 `approvalRequired=true` +3. 失败时给出明确错误 + +## 7. 审批与群聊兼容设计 + +### 7.1 正常转发 + +以下情况可直接放行: + +- 用户主动把消息转发到自己可见的单线程会话 +- 用户主动把消息转发到群聊 +- 用户主动把消息转发到 `主 Agent` +- 用户主动把消息转发到 `审计对话` + +### 7.2 需要审批的场景 + +如果这次转发在业务语义上会触发: + +- 非开发任务状态下的线程直接互相沟通 + +那么后端必须先命中治理规则: + +1. 不直接放行 +2. 返回 `approvalRequired` +3. 由主 Agent 再向用户请求批准 + +这次即使还不把完整审批 UI 全做完,也必须在接口和消息层预留这条分支。 + +### 7.3 和群聊的关系 + +转发目标页对群聊和单线程会话一视同仁,目标本质就是会话。 + +要求: + +1. 群聊和单线程会话共用同一套目标选择页 +2. 不能因为群聊存在,就做另一套“转群聊”专用流程 +3. 后端只在治理规则阶段区分是否需要审批,不在选择页阶段区分 + +## 8. Android 原生页面设计 + +### 8.1 ProjectDetailActivity + +需要补以下交互: + +1. 单条消息长按弹出操作菜单 +2. 进入多选模式 +3. 多选模式顶部与底部状态切换 +4. `转发` 入口跳转到统一会话选择页 + +### 8.2 新增原生活动页 + +本次新增: + +- `ForwardTargetActivity` + - 统一目标会话选择页 + - 同时服务单条转发和多选转发 + +`ProjectForwardActivity` 不再承担主转发链路,而是下沉为兼容入口;如果旧入口仍被触发,只负责立即跳转到新的 `ForwardTargetActivity`。 + +### 8.3 转发后的返回行为 + +要求: + +1. 转发成功后给出轻量反馈 +2. 返回链符合手机直觉 +3. 不能出现完成后回退错层、丢当前页状态、或直接退桌面 + +## 9. 测试与验收标准 + +### 9.1 单条转发验收 + +1. 长按某条消息,能看到消息菜单 +2. 点 `转发` 后进入目标会话选择页 +3. 选择一个会话后,成功写入目标会话 +4. 目标会话里显示普通转发消息 +5. 服务端账本中能看到 `forwardSource` + +### 9.2 多条转发验收 + +1. 进入多选模式并勾选多条消息 +2. 点击底部 `转发` +3. 进入同一个目标会话选择页 +4. 选择一个会话后,成功写入目标会话 +5. 目标会话中只出现一张聊天记录卡片 +6. 服务端账本中能看到 `forwardBundle` + +### 9.3 目标选择页验收 + +1. 会话项样式和首页一致 +2. 一次只能选中一个目标会话 +3. 源会话本身不能被选中 +4. 单线程、群聊、主 Agent、审计对话都能正常显示 + +### 9.4 审批兼容验收 + +1. 开发任务场景下,转发能直接通过 +2. 命中非开发任务治理规则时,接口返回 `approvalRequired` +3. 命中审批规则时不会把消息错误地直接写进目标会话 + +### 9.5 本轮实现完成标准 + +本轮可以视为完成,当且仅当: + +1. 原生 Android 已支持单条转发 +2. 原生 Android 已支持多选合并转发 +3. 目标会话选择页已经替换当前“备注转发页” +4. 服务端消息结构已经支持 `forwardSource` 和 `forwardBundle` +5. 转发接口已经支持 `single / bundle` +6. 审批闸口已经在接口层和账本层预留