Files
gochat/docs/qa/2026-07-17-cdp-full-user-function-test-plan.md
T
2026-07-27 15:50:18 +08:00

1091 lines
53 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 2026-07-17 GoChat CDP 用户功能全量测试计划
> 创建:2026-07-17
> 最后更新:2026-07-19
> 目标:基于已手动启动的 `backend + frontend + fake channel`,通过 CDP 按真实用户点击路径完成 GoChat 各页面功能验收,并明确补齐哪些数据与 `fake:ai` 能力后,才能做“全量实际功能测试”。
## 1. 本轮输入前提
你已经手动启动:
```bash
pnpm dev:backend
pnpm dev:frontend
GOCHAT_WEBHOOK_URL=http://127.0.0.1:3000/webhooks/fake/fake_01 FAKE_AUTO_REPLY=true pnpm fake:start
```
本轮计划默认使用:
- frontend: `http://127.0.0.1:3036`
- backend: `http://127.0.0.1:3000`
- fake channel: `http://127.0.0.1:9100`
- Chrome CDP: 优先复用现有 `127.0.0.1:9222`
关联资产:
- 既有计划:[docs/qa/2026-07-15-cdp-user-function-test-plan.md](/home/rogee/Projects/gochat/docs/qa/2026-07-15-cdp-user-function-test-plan.md)
- 既有执行报告:[docs/qa/reports/2026-07-15-cdp-user-function-report.md](/home/rogee/Projects/gochat/docs/qa/reports/2026-07-15-cdp-user-function-report.md)
这份文档的角色不是重复旧计划,而是把“页面级功能点覆盖”和“全量测试所缺数据/AI 桩能力”整理成可直接执行的版本。
### 1.1 本轮文档直接产出
| 产出 | 文件/位置 | 用途 |
|---|---|---|
| CDP 全量测试执行计划 | 当前文档 | 作为后续 click-only 页面验收的唯一执行基线 |
| 页面级执行报告 | `docs/qa/reports/2026-07-15-cdp-user-function-report.md` | 持续追加 pass/fail/blocked 证据 |
| 全量测试缺口清单 | 第 8 节、第 12.4 节 | 明确哪些数据/能力不补就不能宣称“全量实际功能测试完成” |
| AI 测试支撑方案 | 第 10 节、第 11 节 | 约束 `fake:ai` 的最小落地面和接入方式 |
### 1.2 全量测试 blocker 速览
先把最影响实际执行的缺口压缩成一页,避免后续翻全文:
| 优先级 | 缺口 | 最低要求 | 不补会卡住什么 |
|---|---|---|---|
| P0 | 第二个可登录 agent | 1 个 | 分配、协作、mentions、参与者、在线状态 |
| P0 | `fake_01` inbox 建档 + webhook 回流 | 1 套 | fake 入站、客服回复、auto reply 主链路 |
| P0 | 多状态会话池 | 至少 6 条,不同 status | 会话列表、过滤、报表、回归验证 |
| P0 | CRM 非空数据 | contacts 8+、companies 3+ | 联系人/公司列表、搜索、分页、联动 |
| P0 | 标签与团队数据 | labels 5+、teams 2+ | 标签过滤、team assign、报表 |
| P0 | 本地 AI 假服务 | `fake:ai` 可用 | Captain / Copilot 只能停留在 render-only |
| P1 | 回复提效对象 | canned responses 3、macros 3、automation 3 | 回复框、宏执行、自动化页面 |
| P1 | 自定义属性 | 三类对象各 2 个 | 详情表单、筛选、自动化条件 |
| P1 | 通知 / 审计 / CSAT / SLA | notifications 5、audit logs 5、csat 5、applied sla 3 | 通知中心、审计、报表 drilldown |
| P2 | API / Email / Campaign / Help Center 丰富数据 | 各 1 套以上 | 集成配置页、campaign、locale、多语言公共页 |
### 1.3 `fake:ai` 最小落地结论
结合当前仓库的 `openai_compatible` provider 能力,这轮不需要先改 GoChat 的 provider 抽象,直接补一个本地 OpenAI-compatible 假服务即可:
| 项 | 结论 |
|---|---|
| 放置位置 | 建议新建 `channels/fake-ai`,与 `channels/fake` 维持同构 |
| 接入方式 | Captain / Copilot 配置为 `openai_compatible` + 本地 `base_url` |
| 当前代码必需接口 | `POST /v1/chat/completions`、`POST /v1/embeddings` |
| 可选补充接口 | `GET /v1/models`(便于后续扩展,但不是当前 GoChat 接入链路的必需项) |
| 最小控制面 | `GET /health`、`POST /api/scenario`、`GET /api/requests` |
| 最少模式 | `ok`、`error`、`slow`、`rate_limit` |
| 最少证据 | 记录最近请求摘要,但必须脱敏 `Authorization` / `api_key` |
### 1.4 当前代码核对结论(2026-07-18)
这部分是为了确保计划文档和当前仓库实现保持一致,不靠假设推进:
| 核对项 | 当前状态 | 对计划的影响 |
|---|---|---|
| 根 `package.json` | 只有 `fake:start` / `fake:dev` / `fake:test` | 说明 message fake 已经可跑,`fake:ai` 还没有统一启动入口 |
| `pnpm-workspace.yaml` | 只包含 `frontend` 与 `channels/fake` | 说明 `channels/fake-ai` 目前尚未纳入 workspace |
| `channels/fake-ai/` 目录 | 当前不存在 | 说明 `fake:ai` 是待新增测试支撑,而不是已有能力 |
| `backend/internal/llm/openai_provider.go` | 请求路径是 `{baseURL}/chat/completions` 与 `{baseURL}/embeddings` | 说明如果本地 `fake:ai` 监听 `9110`,GoChat 配置里的 `base_url` 应填写为 `http://127.0.0.1:9110/v1` |
| `backend/internal/llm/provider_manager.go` | 已支持 `openai_compatible` chat + embedding | 说明不需要先改 provider 抽象,优先补本地 OpenAI-compatible 假服务即可 |
### 1.5 本轮服务矩阵与待补支撑(2026-07-19)
基于本轮手工启动情况,当前可直接进入 CDP 点击测试的服务矩阵如下:
| 服务 | 当前状态 | 启动方式 | 用途 |
|---|---|---|---|
| backend | 已启动 | `pnpm dev:backend` | API、webhook、WebSocket、Captain/Copilot 后端逻辑 |
| frontend | 已启动 | `pnpm dev:frontend` | dashboard / widget / public 页面点击验收 |
| fake channel | 已启动 | `GOCHAT_WEBHOOK_URL=http://127.0.0.1:3000/webhooks/fake/fake_01 FAKE_AUTO_REPLY=true pnpm fake:start` | 外部客户消息模拟、客服出站回收、auto reply 回流 |
| fake:ai | 未启动(当前仓库也尚未提供) | 待新增 `pnpm fake:ai` | Captain / Copilot / Playground / Embedding 的可重复 AI 测试支撑 |
因此本轮测试边界应明确分成两层:
1. 非 AI 页面与消息主链路:可以立刻开始做 click-only CDP 实测。
2. AI 相关页面与任务链路:先按本计划补齐 `fake:ai`,再进入“全量实际功能测试”。
这也意味着:
- 当前三服务已足够支持会话、联系人、公司、settings、widget、public、help center 等非 AI 主链路验收。
- Captain / Copilot 在没有 `fake:ai` 前,只能做页面渲染、路由、表单、空态、错误态层面的验证,不能把结果记为 AI 功能完整通过。
## 2. 测试原则
### 2.1 导航原则
- dashboard 内部页面只允许通过真实点击进入。
- 不允许把 `/app/accounts/:id/...` deep-link 当作“通过证据”。
- 仅允许直接打开:
- 登录页 `/app/login`
- widget/public 根入口
- fake / fake:ai 观测接口
### 2.2 每个页面的统一断言
每个页面至少验证这 6 类内容:
1. 可达:能通过真实入口点击进入。
2. 可见:主区域、左导航、顶部操作区能正常渲染,不是空白壳。
3. 可载:关键 API 返回 2xx,首屏数据成功加载。
4. 可用:页面 1~3 个核心操作可以实际执行。
5. 可回:刷新或回到列表后状态保持一致。
6. 可观测:console / network / runtime exception 有据可查。
额外加一条壳层门槛:
7. 如果顶部或左侧导航点击后 URL 已变化,但主区域仍只显示 `离线的`、空白壳、Vue update error 或没有新的首屏 API,请先把它记成“壳层/挂载失败”,并暂停把后续子页算作通过。
### 2.3 缺陷分级
| 级别 | 定义 |
|---|---|
| P0 | 登录失败、主工作台不可用、消息链路断、权限越界、数据保存丢失 |
| P1 | 页面主 CRUD 不可用、关键列表/详情不加载、核心操作失败 |
| P2 | 子功能失败、边界态错误、局部入口断、错误提示缺失 |
| P3 | 文案/i18n/样式/非阻断 warning |
## 3. 执行顺序
建议按“先打通主壳,再铺页面,再补 AI”的顺序执行:
1. 环境与 CDP 连接基线
2. 登录与 dashboard 主壳
3. 会话主链路与 fake channel E2E
4. CRM 与检索
5. Settings 全量页面
6. Campaign / Help Center / Widget / Public
7. Captain / Copilot / AI 任务
8. 权限、刷新、异常态、回归重走
原因很直接:如果主壳更新、侧栏路由、主区挂载本身有问题,后面的页面覆盖会出现大片假失败。
## 4. 预检查清单
| 检查项 | 动作 | 通过标准 |
|---|---|---|
| backend health | `GET /health` | 200 |
| frontend login | 打开 `/app/login` | 登录页可见 |
| fake channel | `GET http://127.0.0.1:9100/health` | `status=ok` |
| fake 配置 | `POST /api/config` | webhook 指向 `fake_01`,auto reply 生效 |
| CDP | `GET http://127.0.0.1:9222/json/version` | 可拿到 `webSocketDebuggerUrl` |
| 管理员账号 | 实际登录 | 成功进入 account dashboard |
| websocket | 登录后观察 `/cable` | 不持续 401/403/重连风暴 |
| report sink | 确认报告文件 | 本轮证据统一追加到同一份 QA 报告 |
### 4.1 建议的 CDP 最小命令集
为了把“计划”直接衔接到后续点击执行,这里固定一套最小命令集。默认复用当前已经在本机验证过的 CDP CLI:
```bash
CDP=/home/rogee/.npm/_npx/15c61037b1978c83/node_modules/chrome-devtools-mcp/build/src/bin/chrome-devtools.js
```
建议按下面顺序做基线连接:
```bash
curl http://127.0.0.1:9222/json/version
node "$CDP" list_pages
node "$CDP" select_page 5
node "$CDP" take_snapshot
node "$CDP" evaluate_script '() => ({ url: location.href, title: document.title, body: document.body.innerText.slice(0,1200) })'
node "$CDP" list_console_messages --pageSize 20
node "$CDP" list_network_requests --pageSize 20
```
后续进入逐页点击测试时,统一使用这 4 类动作:
| 动作 | 示例 | 用途 |
|---|---|---|
| 页面快照 | `node "$CDP" take_snapshot` | 记录当前导航树、主区、按钮文案 |
| 可见文本核对 | `node "$CDP" evaluate_script '() => document.body.innerText.slice(0,1200)'` | 判断是否是空壳、离线态、错误页 |
| 点击 | `node "$CDP" click <uid> --includeSnapshot` | 严格按真实点击进入下一页 |
| 证据回收 | `node "$CDP" list_console_messages --pageSize 20` / `node "$CDP" list_network_requests --pageSize 20` | 回收 console、API、websocket 证据 |
执行约束:
- 只把 `click` 触发的内部导航视为页面覆盖证据。
- 如果 URL 变了但主区域仍然只是 `离线的`、空白壳或 runtime error,记为失败,不算通过。
- 每切一个页面组,都至少补一次 snapshot、一次 console、一次 network。
建议额外固定一个 Gate-0:
- 从登录后的干净 dashboard 壳,至少点击 `会话 / 联系人 / 公司 / 报告 / Captain / 帮助中心 / 设置` 各 1 次。
- 只有当这些一级入口里,大多数页面都满足“主区真正换页且有对应 API 请求”时,才继续做更细颗粒的页面深测。
- 如果一级入口已经普遍出现“只变 URL、不换主区”,后续工作以定位 shell/router/store 挂载问题为先。
## 5. 页面覆盖矩阵
下面按“真实用户会走到的页面组”来拆。
### 5.1 登录与主工作台壳
| 页面组 | 入口 | 关键功能点 |
|---|---|---|
| 登录页 | `/app/login` | 登录、错误密码、输入校验、回车提交、loading 态 |
| dashboard 主壳 | 登录后默认页 | 左导航渲染、顶部搜索、当前用户、账号切换/状态、路由切换后主区更新 |
| 刷新恢复 | 任一已进入页面 | 刷新后仍在当前页,用户态不丢失 |
### 5.2 会话工作台
来源:`conversation.routes.js` 与 M03 对话/消息需求。
| 页面组 | 关键路径 | 关键功能点 |
|---|---|---|
| Dashboard 会话总览 | 会话 → 默认列表 | open/pending/resolved/snoozed 列表、分页、筛选、计数 |
| 单会话详情 | 从列表点进会话 | 消息时间线、联系人侧栏、公司侧栏、标签、优先级、分配 |
| Inbox 维度会话 | 会话 → inbox 过滤 | inbox 切换、列表过滤、单会话打开 |
| Label / Team / Mention / Unattended / Participating 视图 | 左侧子导航 | 各维度列表、计数、切换后详情 |
| 会话操作 | 详情页操作区 | 回复、private note、resolve/reopen、snooze、assign agent、assign team、add/remove label、priority |
| 消息能力 | 编辑区/附件区 | 发送文本、表情、附件、canned response、macro、reply suggestion/rewrite(后续接 fake:ai) |
| 实时性 | fake channel + dashboard | 新消息推送、已读状态、typing、auto reply 回流、无刷新更新 |
### 5.3 Inbox View / 视图切换
| 页面组 | 入口 | 关键功能点 |
|---|---|---|
| Inbox View | `inbox-view` | 按 inbox 聚合视图、切换后列表与详情同步 |
| 视图切换稳定性 | 左侧不同会话入口之间来回切换 | 子导航清理、面包屑/主区同步、无残留导航状态 |
### 5.4 联系人与公司
来源:`contacts/routes.js`、`companies/routes.js`、M04 CRM 需求。
| 页面组 | 关键功能点 |
|---|---|
| 联系人列表 | 列表加载、搜索、分页、segment/label/active 过滤 |
| 联系人详情 | 基础资料、公司关联、标签、自定义属性、最近会话 |
| 联系人操作 | 新建、编辑、合并、添加电话/邮箱、打标签 |
| 公司列表 | 列表、搜索、分页 |
| 公司详情 | 公司信息、关联联系人、关联会话 |
| CRM 联动 | 从会话侧栏跳到联系人/公司,再回会话 |
### 5.5 全局搜索与通知
| 页面组 | 关键功能点 |
|---|---|
| 全局搜索 | conversations / messages / contacts / articles 结果切换、关键词高亮、空态 |
| 通知中心 | 列表加载、已读/未读、点击跳转回目标会话或页面 |
### 5.6 Settings 全量页面
来源:`settings.routes.js`。
#### A. 账户与个人设置
| 页面组 | 关键功能点 |
|---|---|
| General / Account | 账户名、语言、时区、自动设置、保存与刷新回显 |
| Profile | 个人资料、显示名、签名、通知偏好 |
| Security / MFA / SSO | 可见性、表单渲染、保存校验、受限能力的降级提示 |
#### B. 人员与权限
| 页面组 | 关键功能点 |
|---|---|
| Agents | 列表、邀请/创建、编辑、重置密码、激活状态 |
| Teams | 列表、新建、编辑、成员绑定 |
| Custom Roles | 列表、权限矩阵、创建/编辑、角色绑定 |
#### C. Inbox 与渠道
| 页面组 | 关键功能点 |
|---|---|
| Inbox 列表 | 类型徽标、入口可点、列表完整 |
| Website inbox | 基础配置、欢迎语、营业时间、CSAT、预聊天表单、锁单会话 |
| Email inbox | 配置表单、校验提示、降级态 |
| API inbox | 创建、token/endpoint 展示 |
| Voice/Twilio 类 inbox | voice 页面、降级配置、保存校验 |
| Inbox members / collaborators | agent 绑定、移除、回显 |
#### D. 标签、属性、提效工具
| 页面组 | 关键功能点 |
|---|---|
| Labels | 列表、创建、编辑、删除 |
| Custom Attributes | contact / conversation / company 三类定义 CRUD |
| Canned Responses | 列表、创建、编辑、插入消息编辑器 |
| Macros | 列表、创建、编辑、执行宏后会话变化 |
#### E. 规则与编排
| 页面组 | 关键功能点 |
|---|---|
| Automation | event/condition/action 表单、create/edit/clone/delete、校验 |
| Conversation Workflow | 自动流程与配置项渲染、保存回显 |
| Assignment Policy | assignment/capacity 两类策略的列表、创建、编辑、绑定 inbox / agent |
| SLA | 策略列表、创建、编辑、删除、会话命中展示 |
#### F. 集成与审计
| 页面组 | 关键功能点 |
|---|---|
| Integrations | Slack / Webhook / Dashboard Apps / 其他集成卡片渲染 |
| Webhook hooks | 列表、创建、编辑、删除、测试 |
| Dashboard Apps | iframe app 列表、创建、删除 |
| Audit Logs | 列表、筛选、关键操作写入可见 |
| Billing | 页面加载、enterprise feature 与配额信息展示 |
#### G. Reports
来源:`reports.routes.js` 与 M07 报表需求。
| 页面组 | 关键功能点 |
|---|---|
| Overview | 指标卡、筛选器、日期切换 |
| Conversations / Agents / Teams / Labels / Inbox | 各页数据加载、筛选、切换 |
| CSAT | 列表、metrics、空态与有数据态 |
| SLA | 列表、metrics、下载 |
| Bot / Live reports | 页面可见、筛选器工作 |
### 5.7 Campaigns
来源:`campaigns.routes.js`。
| 页面组 | 关键功能点 |
|---|---|
| Live chat campaigns | 列表、创建、编辑、启停、依赖 website inbox |
| SMS campaigns | 列表、创建、编辑 |
| WhatsApp campaigns | feature flag 下渲染、创建页校验 |
### 5.8 Help Center 后台
来源:`helpcenter.routes.js`。
| 页面组 | 关键功能点 |
|---|---|
| Portal 列表 | portal 列表、入口跳转 |
| Articles | 列表、筛选、创建、编辑、发布状态 |
| Categories | 列表、创建、排序、关联文章 |
| Locales | locale 列表、切换、多语言文章入口 |
| Portal settings | 基础设置、logo/domain/config |
| Article preview | preview 跳转与渲染 |
### 5.9 Widget / Public Surface
这部分允许从根入口直接打开,但内部仍应按真实点击验证。
| 页面组 | 关键功能点 |
|---|---|
| Widget config/init | `website_token` 可用、首屏渲染、launcher 打开 |
| Pre-chat form | 字段展示、必填校验、提交建会话 |
| Widget messaging | 客户发首条消息、客服回复、fake 回流 |
| Public CSAT | 评分页可打开、提交后报表可见 |
| Public Help Center | portal 首页、分类页、文章页、搜索 |
### 5.10 Captain / Copilot / AI Surface
来源:`dashboard/captain/*.routes.js`、`settings/copilot`、`captain/tasks.js`。
| 页面组 | 关键功能点 |
|---|---|
| Captain Settings / Copilot Config | provider 配置、feature toggle、model 选择、test config、embedding reindex |
| Assistants | 列表、创建、编辑、删除 |
| Assistant Settings | 基础信息、guardrails、guidelines、behavior 保存 |
| Assistant Inboxes | 绑定/解绑 inbox |
| Documents | URL/PDF 创建、sync 状态、失败态、删除 |
| Responses / FAQs | 列表、pending 审核、approve/reject、搜索 |
| Scenarios | 列表、创建、编辑、启用禁用 |
| Custom Tools | 列表、创建、测试、启用禁用 |
| Playground | 发送 prompt、得到稳定回复、错误态可见 |
| Conversation 内 AI 任务 | summarize / rewrite / reply suggestion / label suggestion / follow_up |
| Copilot threads | 创建 thread、发消息、接收回复、刷新恢复历史 |
### 5.11 页面组与数据依赖矩阵
这张表的目的不是重复功能点,而是提前说明“为什么某些页面现在只能看渲染,不能算完整通过”。
| 页面组 | 最低依赖数据/能力 | 不足时的结果 |
|---|---|---|
| 登录 / dashboard 主壳 | 1 个管理员、1 个有效 account | 直接 P0 |
| 会话列表 / 详情 | `fake_01` inbox、6+ 会话、3+ 消息类型 | 只能看空态或单条 smoke 会话 |
| 分配 / 团队 / mentions | 第 2 个 agent、2 个 team | 无法验证协作与在线状态 |
| 联系人 / 公司 | 8+ contacts、3+ companies | 搜索、分页、合并、关联验证失真 |
| Labels / Attributes / Filters | 5+ labels、三类 attributes 定义 | 过滤器与详情侧栏大面积空态 |
| Canned / Macros / Automation | 各 3 条以上配置对象 | 只能验页面挂载,不能验执行链路 |
| Reports / CSAT / SLA | applied SLA、CSAT、通知、审计日志 | 只能验空态,不能验指标和 drilldown |
| Campaign / Widget / Public | website inbox、portal、campaign 样本 | 无法完成触发和回流验证 |
| Captain / Copilot | fake:ai、assistant/documents/responses/scenarios/tools | 只能验路由与表单渲染,不能算 AI 功能通过 |
### 5.12 每个页面组的执行粒度
为了避免“页面打开了就算测过”,每个页面组默认至少拆成下面 4 类用例:
1. 首屏加载:入口点击、首屏渲染、关键 API、空态/有数据态。
2. 核心操作:创建 / 编辑 / 删除 / 应用 / 发送 / 跳转中的 1~3 个主操作。
3. 状态回写:保存后列表回显、刷新恢复、再次进入详情一致。
4. 异常分支:缺字段、接口失败、无权限、空返回、超时或 loading 收敛。
如果某页当前只有空态数据,也仍要记录:
- 该页是否能稳定挂载;
- 空态是否符合预期;
- 哪个具体数据缺口阻止了继续深测;
- 它属于 `blocked` 还是 `partial pass`。
### 5.13 按前端路由拆分的执行清单
这部分专门回答“每个页面的特性功能点都要详细测试”这个要求。它不是要求首轮一次性全部跑完,而是把后续 CDP 点击清单拆成不会漏页的颗粒度。
| 路由族 | 页面/子页 | 至少覆盖的动作 |
|---|---|---|
| 会话工作台 | `home`、`inbox_dashboard`、`inbox_conversation`、`label_conversations`、`team_conversations`、`conversation_mentions`、`conversation_unattended`、`conversation_participating` | 列表切换、打开会话、发送消息、切换 assignee/team/label、刷新恢复 |
| Inbox View | `inbox_view`、`inbox_view_conversation` | inbox 聚合视图切换、从列表进入详情、回到列表、子导航清理 |
| 联系人 | `contacts_dashboard_index`、segments、labels、active、`contacts_edit` | 搜索、分页、筛选、进入详情、编辑、标签/属性回显 |
| 公司 | `companies_dashboard_index`、`companies_dashboard_show` | 列表加载、搜索、进入公司详情、回联系人/会话联动 |
| 搜索 | `search` | 不同 tab 切换、关键词搜索、结果跳转回原页面 |
| Campaigns | ongoing、one_off、live_chat、sms、whatsapp | 列表渲染、创建/编辑入口、启停、依赖 inbox 校验 |
| Help Center | portals index/new、articles index/new/edit/preview、categories、locales、settings | portal 创建、文章 CRUD、分类排序、多语言切换、preview/public 联动 |
| Settings-General/Profile | general、profile settings、mfa | 保存回显、校验、受限功能降级、刷新后仍一致 |
| Settings-Agents/Teams/Roles | agents、teams list/new/edit/finish/members、custom roles | 人员创建/编辑、团队成员绑定、角色矩阵保存、权限边界 |
| Settings-Inbox | inbox list、新建 channel、website/api/email/voice/fake channel 设置、collaborators、CSAT、business hours | 列表、创建、配置保存、成员绑定、公开侧联动 |
| Settings-效率工具 | labels、custom attributes、canned responses、macros、agent bots | CRUD、会话内实际使用、保存回显 |
| Settings-规则编排 | automation、conversation workflow、assignment policy、agent capacity、SLA | create/edit/delete、条件动作校验、绑定 inbox/agent、命中回显 |
| Settings-Integrations | integrations root、dashboard apps、webhook、slack、linear、notion、shopify | 卡片可见、hook CRUD、dashboard app 装载、第三方配置错误态 |
| Settings-Audit/Billing | audit logs、billing | 列表、筛选、配额/套餐信息、enterprise 降级态 |
| Reports | overview、agents、inboxes、labels、teams、csat、sla、bot/live reports | 日期筛选、指标卡、钻取、下载、空态与有数据态 |
| Captain/Copilot 设置 | copilot settings、provider test、embedding reindex、feature/model 保存 | 保存、测试连接、错误提示、配置持久化 |
| Captain 资源页 | assistants、assistant settings、assistant inboxes、documents、responses、scenarios、custom tools | CRUD、绑定、sync/test、审核、启停、状态回写 |
| AI 交互页 | playground、copilot threads、会话内 summarize/rewrite/reply suggestion/label suggestion/follow_up | 请求发出、稳定响应、stream、错误态、刷新恢复 |
| Widget/Public | widget init、pre-chat、public csat、public help center | 公开入口可打开、提交/搜索/评分成功、后台有回流证据 |
建议执行时,把上表每一行视为一个“页面族批次”,每个批次至少产出:
1. 入口点击链路;
2. 1 个加载用例;
3. 1~3 个核心操作用例;
4. 1 个刷新/返回一致性用例;
5. 1 个异常或空态用例。
### 5.13.1 路由来源文件对照
为了避免后续执行时只盯着左侧菜单、却漏掉某些子页,这里把当前前端实际路由来源文件也固定下来。后续如果某个页面组出现“菜单存在但主区没挂载”或“子页残留/串页”,可以直接回到对应 routes 文件做对照。
| 页面族 | 主要路由来源文件 |
|---|---|
| dashboard 主壳 / 一级容器 | `frontend/app/javascript/dashboard/routes/dashboard/dashboard.routes.js` |
| 会话工作台 | `frontend/app/javascript/dashboard/routes/dashboard/conversation/conversation.routes.js` |
| Inbox View | `frontend/app/javascript/dashboard/routes/dashboard/inbox/routes.js` |
| 联系人 | `frontend/app/javascript/dashboard/routes/dashboard/contacts/routes.js` |
| 公司 | `frontend/app/javascript/dashboard/routes/dashboard/companies/routes.js` |
| 全局搜索 | `frontend/app/javascript/dashboard/modules/search/search.routes.js` |
| 通知 | `frontend/app/javascript/dashboard/routes/dashboard/notifications/routes.js` |
| Campaigns | `frontend/app/javascript/dashboard/routes/dashboard/campaigns/campaigns.routes.js` |
| Help Center | `frontend/app/javascript/dashboard/routes/dashboard/helpcenter/helpcenter.routes.js` |
| Captain 主区 | `frontend/app/javascript/dashboard/routes/dashboard/captain/captain.routes.js` |
| Settings 根路由 | `frontend/app/javascript/dashboard/routes/dashboard/settings/settings.routes.js` |
| Settings / Account | `frontend/app/javascript/dashboard/routes/dashboard/settings/account/account.routes.js` |
| Settings / Profile | `frontend/app/javascript/dashboard/routes/dashboard/settings/profile/profile.routes.js` |
| Settings / Security | `frontend/app/javascript/dashboard/routes/dashboard/settings/security/security.routes.js` |
| Settings / Agents | `frontend/app/javascript/dashboard/routes/dashboard/settings/agents/agent.routes.js` |
| Settings / Teams | `frontend/app/javascript/dashboard/routes/dashboard/settings/teams/teams.routes.js` |
| Settings / Custom Roles | `frontend/app/javascript/dashboard/routes/dashboard/settings/customRoles/customRole.routes.js` |
| Settings / Inboxes | `frontend/app/javascript/dashboard/routes/dashboard/settings/inbox/inbox.routes.js` |
| Settings / Labels | `frontend/app/javascript/dashboard/routes/dashboard/settings/labels/labels.routes.js` |
| Settings / Attributes | `frontend/app/javascript/dashboard/routes/dashboard/settings/attributes/attributes.routes.js` |
| Settings / Canned Responses | `frontend/app/javascript/dashboard/routes/dashboard/settings/canned/canned.routes.js` |
| Settings / Macros | `frontend/app/javascript/dashboard/routes/dashboard/settings/macros/macros.routes.js` |
| Settings / Agent Bots | `frontend/app/javascript/dashboard/routes/dashboard/settings/agentBots/agentBot.routes.js` |
| Settings / Automation | `frontend/app/javascript/dashboard/routes/dashboard/settings/automation/automation.routes.js` |
| Settings / Conversation Workflow | `frontend/app/javascript/dashboard/routes/dashboard/settings/conversationWorkflow/conversationWorkflow.routes.js` |
| Settings / Assignment Policy | `frontend/app/javascript/dashboard/routes/dashboard/settings/assignmentPolicy/assignmentPolicy.routes.js` |
| Settings / SLA | `frontend/app/javascript/dashboard/routes/dashboard/settings/sla/sla.routes.js` |
| Settings / Integrations | `frontend/app/javascript/dashboard/routes/dashboard/settings/integrations/integrations.routes.js` |
| Settings / Audit Logs | `frontend/app/javascript/dashboard/routes/dashboard/settings/auditlogs/audit.routes.js` |
| Settings / Billing | `frontend/app/javascript/dashboard/routes/dashboard/settings/billing/billing.routes.js` |
| Reports | `frontend/app/javascript/dashboard/routes/dashboard/settings/reports/reports.routes.js` |
| Settings / Captain 配置页 | `frontend/app/javascript/dashboard/routes/dashboard/settings/captain/captain.routes.js` |
### 5.14 页面级测试用例模板
为了避免后续执行时每页都重新想“要点什么、验什么”,这里固定一个页面级模板。后面每个页面族至少套一次。
| 用例类型 | 最低动作 | 最低断言 |
|---|---|---|
| 首屏加载 | 从上一级页面真实点击进入 | URL 变化、主区有业务内容、首屏 API 2xx、console 无阻断异常 |
| 列表操作 | 搜索 / 筛选 / tab 切换 / 分页 / 排序 至少 1 项 | 列表内容变化、计数变化或空态正确、network 有对应请求 |
| 详情操作 | 从列表进入详情,再返回列表 | 详情数据完整,返回后列表状态未丢失 |
| 表单操作 | create / edit / save 至少 1 项 | 校验提示正确、保存后 toast/列表/详情回显一致 |
| 破坏性操作 | delete / disable / remove / close 至少 1 项 | 二次确认、结果可见、刷新后仍生效 |
| 联动操作 | 从 A 页跳 B 页再回 A 页 | breadcrumb/side nav/main area 同步更新,无旧页面残留 |
| 权限/异常 | 缺字段 / 失败响应 / 无数据态 至少 1 项 | 错误提示明确,不出现空白壳或静默失败 |
| 刷新恢复 | F5 或重新进入当前页 | 当前位置、列表筛选、详情对象或最近状态能恢复 |
建议把每个页面族都落成下面这种最小结构:
```text
页面族:Settings > Labels
- load: 从 设置 -> 标签 进入,列表成功加载
- core action 1: 新建标签
- core action 2: 编辑标签
- destructive: 删除标签
- refresh: 刷新后标签仍存在/已删除
- exception: 提交空名称时出现校验
```
如果一个页面当前只能跑到空态,也要按同样结构记录:
```text
页面族:Reports > CSAT
- load: 页面可挂载
- blocked: 缺少 5 条以上 CSAT response
- exception: 空态文案正确
```
## 6. 证据采集规范
每条页面用例至少记录:
- 起始入口与点击路径
- 结束 URL
- 关键可见文案
- 发出的关键 API
- console / runtime exception
- 是否需要刷新后复核
- 结果:pass / fail / blocked
建议输出继续统一沉淀到:
- [docs/qa/reports/2026-07-15-cdp-user-function-report.md](/home/rogee/Projects/gochat/docs/qa/reports/2026-07-15-cdp-user-function-report.md)
如果要单开新报告,可使用:
- `docs/qa/reports/2026-07-17-cdp-user-function-report.md`
## 7. 当前仓库已具备的数据基线
从 `backend/cmd/gochat seed` 与 `backend/scripts/parity_frontend_smoke.sh` 看,当前 smoke seed 已能提供:
| 类别 | 当前基线 |
|---|---|
| 管理员 | 1 个 `admin@gochat.local / changeme` |
| Account | 1 个 smoke account |
| Website inbox | 1 个 `web_widget` inbox,带 `website_token` |
| Voice-like inbox | 1 个 `twilio_sms` 型 smoke inbox |
| Contact / Company | 各 1 条 |
| Conversation | 1 条 open conversation |
| Messages | 3 条左右基础消息 |
| Help Center | 1 portal + 1 category + 1 article |
| SLA | 1 条 smoke policy |
| Custom Role | 1 条 |
| Capacity Policy | 1 条 |
| Captain | 1 个 assistant + 少量 smoke fixture |
这足够跑 smoke,但不够支撑“每个页面的特性功能点都详细测试”。
## 8. 还需要补充的、会影响全量实际测试的数据
### 8.1 P0:不补就会大面积 blocked
| 缺口 | 最低要求 | 直接影响 |
|---|---|---|
| 第二个可登录 agent | 1 个 | 分配、协作、在线状态、mentions、跨坐席实时 |
| `fake_01` inbox 真正建档 | 1 个 | 当前 fake webhook 主链路、消息回流 |
| 多状态会话 | 至少 8 条 | open / pending / resolved / snoozed / unattended / assigned 视图 |
| 更丰富消息类型 | 至少覆盖 text/private note/attachment/template | 会话详情、时间线、编辑器、下载 |
| website inbox 真实配置 | 1 套完整配置 | widget / pre-chat / live chat campaign |
### 8.2 P1:不补就只能看空态或半成品态
| 缺口 | 最低要求 | 直接影响 |
|---|---|---|
| Contacts | 8~12 条 | CRM 列表、搜索、分页、合并 |
| Companies | 3~5 条 | 公司列表、详情、关联联系人 |
| Labels | 5 条以上 | 过滤、标签设置、报表 |
| Teams | 2 条以上 | 团队分配、团队报表 |
| Custom attributes | contact/conversation/company 各 2 条定义 | 表单、筛选、详情侧栏 |
| Canned responses | 3 条 | 编辑器插入、列表 CRUD |
| Macros | 3 条 | 会话执行宏 |
| Automation rules | 3 条 | 列表、编辑、条件动作校验 |
| Notifications | 5 条以上 | 通知列表与跳转 |
| Audit logs | 5 条以上 | 审计页是否有真实内容 |
### 8.3 P2:不补就无法完成高级页验证
| 缺口 | 最低要求 | 直接影响 |
|---|---|---|
| Email inbox | 1 个 | email channel 配置页与表单 |
| API inbox | 1 个 | API channel 页面与 token 展示 |
| Campaign 样本 | live chat / sms / whatsapp 各 1 条 | campaign 列表、编辑、启停 |
| 多 locale help center | 至少 2 个 locale | locales / article 多语言验证 |
| CSAT responses | 5 条以上 | CSAT 列表、metrics、public submit 回流 |
| Applied SLA data | 3 条以上 | SLA metrics / download |
| Dashboard app | 1 个 | iframe app 页面 |
### 8.4 建议一次性补齐的数据包
如果目标是“尽快进入全量点击测试”,最省事的方式不是边点边发现缺数据,而是先凑齐一包能覆盖主链路的数据。
推荐一次性补到这个下限:
| 数据包 | 推荐下限 | 覆盖的页面/动作 |
|---|---:|---|
| 管理员 | 1 | 登录、settings、reports、captain |
| 普通 agent | 2 | 会话分配、协作、在线状态、team、mentions |
| custom role 用户 | 1 | 权限边界、受限菜单、禁用按钮 |
| fake inbox | 1 (`fake_01`) | fake 入站、客服回复、auto reply 回流 |
| website inbox | 1 | widget、pre-chat、campaign、公开面 |
| api inbox | 1 | inbox 配置页、token 展示 |
| email inbox | 1 | email provider / SMTP / IMAP 页 |
| voice/twilio inbox | 1 | voice 页面与降级态 |
| open 会话 | 4 | 会话主列表、详情、分配、标签 |
| pending 会话 | 2 | pending tab、bot handoff、assign |
| resolved 会话 | 2 | resolved tab、reopen、报表 |
| snoozed 会话 | 2 | snooze 视图、恢复 |
| unattended / participating / mention 命中会话 | 各 1 | 左侧特殊视图 |
| 附件消息 | 2 | 下载、预览、时间线渲染 |
| private note | 2 | 私有备注时间线、过滤 |
| labels | 5 | 标签页、过滤、报表、自动化 |
| teams | 2 | 团队页、team assign、team report |
| contacts | 10 | CRM 列表、搜索、分页、合并 |
| companies | 4 | 公司列表、详情、联系人关联 |
| canned responses | 3 | 回复框插入、settings CRUD |
| macros | 3 | 执行宏、状态回写 |
| automation rules | 3 | 自动化页 create/edit/delete |
| custom attributes | 三类各 2 | 详情表单、筛选、自动化条件 |
| notifications | 5 | 通知中心列表、跳转 |
| audit logs | 5 | 审计页内容与筛选 |
| csat responses | 5 | CSAT 页面、public csat 回流 |
| applied sla | 3 | SLA 指标、drilldown、download |
| help center portal | 1 | public/help center 后台 |
| categories | 2 | article 分类、排序 |
| published articles | 3 | article 列表、搜索、public article |
| campaigns | live chat / sms / whatsapp 各 1 | campaign 列表、编辑、启停 |
| captain assistant | 1 | AI 页面根对象 |
| captain documents | 3 | syncing/synced/failed |
| captain responses | 5 | FAQ / pending / 审核 |
| captain scenarios | 2 | 场景列表、启停 |
| captain custom tools | 1 | tool test / tool call |
执行策略建议:
1. `seed` 只负责兜底,不负责把列表型页面喂饱。
2. fake channel 负责会话、消息、实时链路造数。
3. settings/UI 首轮执行中,顺手创建 labels / teams / canned / macros / attributes。
4. 报表、通知、审计、SLA 这类“结果数据”,要么走定向 seed,要么走真实操作回灌。
### 8.5 按当前三服务拆分的可测范围
基于你现在已经手工启动的三项服务:
```bash
pnpm dev:backend
pnpm dev:frontend
GOCHAT_WEBHOOK_URL=http://127.0.0.1:3000/webhooks/fake/fake_01 FAKE_AUTO_REPLY=true pnpm fake:start
```
后续执行时建议明确分成两层,不要把“已经能做的页面验收”和“仍缺本地 AI 支撑的页面”混在一起。
| 范围 | 当前能否直接进入 CDP 实测 | 说明 |
|---|---|---|
| 登录 / dashboard 主壳 | 可以 | 只依赖 backend + frontend |
| 会话列表 / 会话详情 / fake 入站出站 / auto reply | 可以 | 但前提是 GoChat 里已有 `fake_01` 对应 inbox |
| 联系人 / 公司 / 搜索 / 通知 | 可以 | 深测仍取决于 contacts / companies / notifications 数据量 |
| Settings 非 AI 页面 | 可以 | 适合一边点击一边补 labels / teams / macros / attributes 等对象 |
| Campaigns / Widget / Public / Help Center | 可以 | 依赖 website inbox、portal、campaign 样本是否已补齐 |
| Reports / Audit / CSAT / SLA | 可以 | 页面能测,但“有数据态”仍取决于结果型数据是否已回灌 |
| Captain / Copilot 的路由、表单、开关、空态、错误态 | 可以 | 在没有 `fake:ai` 前,只能算 render/config/error-path 验证 |
| Captain Playground / Documents / Responses / Copilot threads / 会话内 AI 任务成功链路 | 暂不建议宣称完整通过 | 需要 `fake:ai` 才能把 success / stream / timeout / 429 / embedding 等路径测全 |
因此推荐执行顺序不要反过来:
1. 先用当前三服务完成非 AI 页面与消息主链路的 click-only 全量覆盖。
2. 把数据缺口补到足以支撑有数据态验证。
3. 再补 `fake:ai`,最后收 Captain / Copilot 的成功链路与失败链路。
## 9. 数据补齐建议
### 9.1 先用 seed 打底
先执行一次:
```bash
cd backend
go run ./cmd/gochat seed
```
### 9.2 再补 fake channel 所需真实 inbox
最少需要把 `fake_01` 这个 webhook 标识对应到 GoChat 内的 fake inbox 配置,确保:
- fake 发出的入站消息能建会话
- dashboard 发出的出站消息能回到 `/receive`
- auto reply 回来的消息能附着到同一会话
### 9.3 把“列表型数据”与“功能型数据”分开准备
建议分三类造数:
| 类别 | 数据 | 建议方式 |
|---|---|---|
| 主链路数据 | admin / 2 agents / fake inbox / website inbox / 基础 conversations | 执行前一次性准备 |
| CRUD 数据 | labels / teams / macros / canned / custom attributes | 直接在 CDP 首轮过程中边测边创建 |
| 报表数据 | csat / applied_sla / notifications / audit logs | 定向 seed 或通过 API/fake 回灌 |
### 9.4 建议的数据准备责任矩阵
这张表的目的,是把“哪些数据要先准备好、哪些可以在点测时顺手造出来”定死,避免后面执行过程中频繁停下来补环境。
| 数据/能力 | 推荐准备方式 | 最好何时完成 | 主要服务谁 |
|---|---|---|---|
| 管理员账号 | `go run ./cmd/gochat seed` 打底 | 执行前 | 登录、settings、reports、captain |
| 第二个 agent | 后台创建或补定向 seed | 执行前 | 分配、协作、在线状态、mentions |
| custom role 用户 | 后台创建 | 执行前或批次 B 开始前 | 权限边界、受限入口 |
| `fake_01` inbox | 后台建 fake inbox,并把 webhook 标识对到 `fake_01` | 执行前 | fake 入站、出站、auto reply 主链路 |
| website inbox | seed 打底后在 settings 补齐配置 | 执行前 | widget、pre-chat、campaign、public 面 |
| API inbox / Email inbox / Voice inbox | settings 页面内创建或补 seed | 批次 B 前 | inbox 类型页、provider 配置页 |
| open/pending/resolved/snoozed 会话池 | `channels/fake` 批量造数 | 执行前 | 会话列表、筛选、报表、刷新恢复 |
| private note / attachment / template 消息 | UI 操作 + fake 回灌混合 | 批次 A 过程中 | 会话时间线、附件预览、编辑器能力 |
| contacts / companies | UI 创建为主,必要时补 seed | 批次 A 前半段 | CRM 列表、搜索、分页、关联 |
| labels / teams | UI 创建 | 批次 B 过程中 | 标签过滤、team assign、team report |
| canned responses / macros / automation | UI 创建 | 批次 B 过程中 | 回复提效、宏执行、自动化规则 |
| custom attributes | UI 创建 | 批次 B 过程中 | 详情表单、筛选、自动化条件 |
| notifications / audit logs / csat / applied sla | 真实操作回灌优先,不足再补定向 seed | 批次 B 或 C 前 | 通知、审计、CSAT/SLA 报表 |
| help center portal / categories / articles | seed 打底后在 UI 补多语言/多分类 | 批次 B 或 C 前 | help center 后台与 public |
| campaigns 样本 | UI 创建 | 批次 C 前 | live chat / sms / whatsapp campaigns |
| `fake:ai` 服务 | 新增 `channels/fake-ai` 并接到 `openai_compatible` | 批次 D 前 | Captain / Copilot / Playground / Embedding |
| captain assistant / docs / responses / scenarios / tools | settings / captain 页面内创建,必要时配合定向 seed | 批次 D 前半段 | AI 子页 CRUD、状态流转、工具调用 |
建议执行节奏:
1. 先把执行前必需项一次性补到位,再开始点击主链路。
2. 把适合“边测边造”的对象留在对应页面里创建,顺便验证页面 CRUD。
3. 结果型数据尽量通过真实操作自然回灌,这样后面的报表和审计验证会更可信。
## 10. AI 测试为什么需要单独补 `fake:ai`
当前仓库的 AI 运行时是通过 `llm.Provider` 抽象接入的,最关键的 3 个能力是:
- `ChatCompletion`
- `CreateEmbedding`
- `ChatCompletionStream`
同时,平台配置页和 AI 功能页都围绕这些能力工作:
- `/platform/api/v1/copilot/config`
- `/platform/api/v1/copilot/config/test`
- `/platform/api/v1/copilot/embeddings/reindex`
- `/api/v1/accounts/:id/captain/tasks/*`
- `/api/v1/accounts/:id/captain/assistants/:assistant_id/playground`
- `/api/v1/accounts/:id/captain/copilot_threads/*`
并且当前后端已经支持 `openai_compatible` provider:
- `ProviderManager` 接受 `openai_compatible`
- chat 侧请求会打到 `/chat/completions`
- embedding 侧请求会打到 `/embeddings`
这意味着 `fake:ai` 不需要先改 GoChat provider 矩阵,优先做成一个本地 OpenAI-compatible 假服务即可。
如果没有本地 deterministic AI provider,Captain/Copilot 相关测试会卡在:
- 依赖真实第三方 key
- 响应不可复现
- 无法稳定覆盖超时/429/stream 中断/工具调用失败
所以这部分不应继续复用 message fake,而应该新增一条独立的 `fake:ai` 测试通道。
## 11. `fake:ai` 的建议形态
### 11.1 最小落地方向
推荐直接新增成 `channels/fake-ai`,尽量与现有 `channels/fake` 保持同构:
- 同样走独立目录
- 同样通过根 `package.json` 暴露启动脚本
- 同样提供健康检查、控制接口、历史请求观测
并让 GoChat Copilot/Captain 用 `openai_compatible` 模式直连它。
这样不需要改动 `ProviderManager` 的支持矩阵,只需要在平台配置里填本地地址。
如果希望复用现有 fake channel 的使用习惯,建议 `fake:ai` 也采用同样的“观测 + 场景切换 + 历史查询”风格:
- `GET /health`
- `POST /api/config`
- `POST /api/reset`
- `GET /api/status`
- `GET /api/requests`
这样 CDP 脚本切换消息 fake 与 AI fake 时,控制面会非常一致。
### 11.1.1 当前仓库已确认的实现缺口
基于当前仓库实际检查,`fake:ai` 现在还不是“已有能力”,而是明确待补的测试支撑项:
| 项 | 当前状态 | 结论 |
|---|---|---|
| 根脚本 `fake:start / fake:dev / fake:test` | 已存在 | `channels/fake` 现成可用 |
| 根脚本 `fake:ai / fake:ai:dev / fake:ai:test` | 不存在 | 需要新增 |
| workspace 包 `channels/fake` | 已纳入 `pnpm-workspace.yaml` | 现有 fake message 平台可直接运行 |
| workspace 包 `channels/fake-ai` | 不存在 | 需要新增目录并纳入 workspace |
| OpenAI-compatible provider 支持 | 已存在 | 可直接复用当前 `openai_compatible` 配置链路 |
因此这轮计划里提到的 `fake:ai`,应理解为:
1. 新增 `channels/fake-ai`
2. 根 `package.json` 增加 `fake:ai*` 脚本
3. `pnpm-workspace.yaml` 纳入 `channels/fake-ai`
4. 暴露最小 OpenAI-compatible 接口与控制/观测接口
### 11.1.2 建议直接补齐的工程脚手架
为了让 `fake:ai` 能像当前 `fake:start` 一样被稳定复用,建议第一步先补齐下面这些工程入口:
| 文件 | 建议新增项 | 目的 |
|---|---|---|
| 根 `package.json` | `fake:ai`、`fake:ai:dev`、`fake:ai:test` | 与现有 `fake:start` 使用习惯保持一致,方便人工与 CDP 脚本统一调用 |
| `pnpm-workspace.yaml` | `channels/fake-ai` | 让依赖安装、脚本执行、后续 CI 接入保持一致 |
| `channels/fake-ai/package.json` | `dev/start/test` 脚本 | 独立维护 fake:ai 的本地服务与测试 |
| `channels/fake-ai/README.md` | 启动方式、接口、scenario 用法 | 给后续 QA/CDP 执行者直接复用 |
| `channels/fake-ai/src/*` | `health`、OpenAI-compatible 路由、控制接口、请求观测 | 支撑 AI 页面联调与失败场景编排 |
建议默认启动命令直接约定成这种风格:
```bash
pnpm fake:ai
pnpm fake:ai:dev
pnpm fake:ai:test
```
这样后续本地全量测试的服务矩阵就会比较稳定:
```bash
pnpm dev:backend
pnpm dev:frontend
pnpm fake:start
pnpm fake:ai
```
### 11.2 最小接口
`fake:ai` 最少实现:
| 方法 | 路径 | 用途 |
|---|---|---|
| `GET` | `/health` | 健康检查 |
| `POST` | `/v1/chat/completions` | 普通对话 / playground / copilot / tasks |
| `POST` | `/v1/embeddings` | 文档 embedding / reindex |
如果要完整覆盖流式任务,再加:
| 方法 | 路径 | 用途 |
|---|---|---|
| `POST` | `/v1/chat/completions?stream=true` 或同一路由 SSE 输出 | summarize/rewrite/coproilot stream |
### 11.3 建议的测试场景开关
`fake:ai` 不应只返回固定 “OK”,而应支持 scenario 切换:
| 场景 | 用途 |
|---|---|
| success_text | 正常文本回复 |
| success_stream | 正常流式输出 |
| tool_call | 返回 function call,验证 custom tool / search_documentation |
| empty | 空回复,验证 UI 降级 |
| malformed | 非法结构,验证错误提示 |
| timeout | 超时,验证 loading / cancel / retry |
| rate_limit | 429,验证限流提示 |
| unauthorized | 401/403,验证 provider 配置错误提示 |
| embedding_success | 正常 embedding |
| embedding_fail | embedding 失败,验证 reindex / document 状态 |
### 11.4 推荐的控制接口
为了让 CDP 用例可编排,建议再加:
| 方法 | 路径 | 用途 |
|---|---|---|
| `POST` | `/api/scenario` | 切换当前场景 |
| `POST` | `/api/reset` | 清空调用历史 |
| `GET` | `/api/requests` | 查看收到的 prompts / embeddings 请求 |
| `GET` | `/api/status` | 当前模式、计数、最近错误 |
| `POST` | `/api/config` | 统一配置默认模型、延迟、stream 开关、默认 scenario |
建议 `GET /api/requests` 至少记录这些字段,方便我们之后做断言与排错:
- timestamp
- route (`/v1/chat/completions` or `/v1/embeddings`)
- scenario
- model
- messages / input 摘要
- response status
- latency
- tool calls / stream chunk 数
- 最近一次 error
### 11.5 这样能覆盖哪些 AI 页面
接上 `fake:ai` 后,以下页面就能稳定做真功能测试,而不只是“页面能打开”:
- Copilot Config 页面:test config / provider health / embedding reindex
- Captain Settings:feature toggle / model 选择 / 保存回显
- Assistant Playground:发 prompt 得到确定性回复
- Documents:创建后进入 syncing / synced / failed 三种状态
- Responses / FAQs:生成、审核、过滤
- Custom Tools:tool_call 成功与失败
- 会话里的 summarize / rewrite / reply suggestion / label suggestion / follow_up
- Copilot threads:多轮上下文与刷新恢复
### 11.6 推荐先覆盖的 fake:ai 场景集
第一版不需要追求“大而全”,但至少要覆盖下面这 8 种:
| 场景 | 主要验证页 |
|---|---|
| success_text | playground、copilot 普通回复、assistant response 生成 |
| success_stream | reply suggestion、rewrite、copilot thread streaming |
| tool_call | custom tools、documentation/search 类能力 |
| timeout | provider test、rewrite、copilot panel loading/timeout |
| rate_limit | provider test、inline AI task 错误提示 |
| unauthorized | copilot config test、provider save 后再试用 |
| embedding_success | document sync / reindex / faq embedding |
| embedding_fail | documents failed 状态、reindex 失败回显 |
### 11.7 `fake:ai` 与当前 fake channel 的职责边界
这两者建议保持分工明确,避免后面观测混乱:
| 组件 | 负责什么 | 不负责什么 |
|---|---|---|
| `channels/fake` | 模拟外部客户消息、回收 GoChat 出站消息、auto reply | 不模拟 LLM、embedding、tool calling |
| `fake:ai` | 模拟 chat completion、stream、embedding、tool call、AI 失败场景 | 不模拟客户消息、不承载会话 webhook |
建议最终执行时把两条链路串起来看:
1. `channels/fake` 负责造出真实会话和客服回复链路。
2. `fake:ai` 负责让同一会话内的 Copilot/Captain 操作可重复、可观测、可断言。
### 11.8 推荐的接入方式与配置模板
为了减少对 GoChat 现有 ProviderManager 的侵入,`fake:ai` 最好直接伪装成一个本地 OpenAI-compatible 服务。
推荐接法:
1. 启动 `fake:ai`,例如监听 `http://127.0.0.1:9110`
2. 在 Copilot Config 页面把 chat provider 与 embedding provider 都设为 `openai_compatible`
3. chat base URL 指向 `http://127.0.0.1:9110/v1`
4. embedding base URL 指向 `http://127.0.0.1:9110/v1`
5. API key 可填固定占位值,如 `fake-ai-key`
建议在文档或实现里直接约定这组默认值:
```text
FAKE_AI_PORT=9110
FAKE_AI_BASE_URL=http://127.0.0.1:9110/v1
FAKE_AI_API_KEY=fake-ai-key
FAKE_AI_DEFAULT_MODEL=fake-gpt-4o-mini
FAKE_AI_DEFAULT_EMBED_MODEL=fake-text-embedding-3-small
```
这样后续 CDP 用例可以固定验证:
- config test 成功
- save 后再次进入 settings 仍回显本地 fake 配置
- playground / tasks / copilot threads 的请求都能在 `fake:ai` 侧被观测到
### 11.9 推荐的最小响应契约
为了让前端和后端都能稳定消费,`fake:ai` 第一版至少要保证返回结构长得像 OpenAI。
普通 completion 最小返回可约定为:
```json
{
"id": "chatcmpl_fake_001",
"object": "chat.completion",
"created": 1784332800,
"model": "fake-gpt-4o-mini",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "这是 fake:ai 的确定性回复"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 12,
"completion_tokens": 8,
"total_tokens": 20
}
}
```
embedding 最小返回可约定为:
```json
{
"object": "list",
"data": [
{
"object": "embedding",
"index": 0,
"embedding": [0.01, 0.02, 0.03, 0.04]
}
],
"model": "fake-text-embedding-3-small",
"usage": {
"prompt_tokens": 4,
"total_tokens": 4
}
}
```
流式返回建议直接走 SSE,每个 chunk 保持 OpenAI 风格:
```text
data: {"id":"chatcmpl_fake_stream_001","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"你好"},"finish_reason":null}]}
data: {"id":"chatcmpl_fake_stream_001","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":",这里是"},"finish_reason":null}]}
data: {"id":"chatcmpl_fake_stream_001","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":" fake:ai"},"finish_reason":null}]}
data: {"id":"chatcmpl_fake_stream_001","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: [DONE]
```
如果要支持 tool call,可在 `choices[0].message.tool_calls` 或 stream delta 里返回固定结构;第一版不需要复杂执行器,只要能让 GoChat 和前端正确进入“收到了 tool call”分支即可。
## 12. 推荐执行批次
### 批次 A:主壳与消息链路
- 登录
- dashboard
- 会话列表/详情
- fake 入站/出站/auto reply
- contacts / companies / search / notifications
### 批次 B:settings 与后台页面
- agents / teams / custom roles
- inbox / labels / attributes / canned / macros
- automations / assignment policy / sla / reports
- integrations / audit / billing / help center
### 批次 C:widget / public
- widget config
- pre-chat
- public csat
- public help center
- campaign 触达验证
### 批次 D:AI
- 先接 `fake:ai`
- 再跑 captain settings / assistants / documents / responses / scenarios / tools / playground / copilot / task actions
## 13. 本轮建议结论
这轮如果要真正做到“每个页面特性功能点详细测试”,我建议按下面的定义推进:
1. 先把已有 CDP 计划升级为“页面矩阵 + 数据缺口 + AI 桩方案”。
2. 先以 `seed + fake channel` 打通非 AI 的主流程。
3. 把缺失的真实数据补到能覆盖列表、详情、筛选、报表,而不是只停留在 smoke 空态。
4. 单独补一个 `fake:ai`,通过 `openai_compatible` 接到当前 Copilot/Captain 运行时。
5. AI 不接 fake 之前,只能做“页面渲染级”验证,不能算“全量实际功能测试完成”。
## 14. 建议下一步
按性价比最高的顺序,下一步建议是:
1. 先补 `fake_01 inbox + 第二个 agent + 多状态 conversations`
2. 再开始批次 A 的 CDP 实测
3. 同时排一个小实现项:落地 `fake:ai`