docs: add wechat message forwarding spec
This commit is contained in:
@@ -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. 审批闸口已经在接口层和账本层预留
|
||||
Reference in New Issue
Block a user