# 发送路由端到端验证实施计划

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** 通过 admin-web UI 走通「内部群 → WECOM_BOT → 发送 → 查询状态」链路，验证自动路由可用，并修复沿途问题。

**Architecture:** 基于现有后台能力（已有异步发送、任务状态查询、会话管理和账号管理 API），通过 Chrome DevTools MCP 操作浏览器完成端到端验证；发现问题时现场修复前后端代码并重新验证。

**Tech Stack:** Spring Boot 4.1.0 (backend), Vue 3 + Element Plus (admin-web), RabbitMQ (async send), MySQL, Chrome DevTools MCP.

## Global Constraints

- 项目工作目录：`/f/sino-mci`
- JDK 21 路径：`/f/tools/jdk-21.0.4+7`
- 后端构建命令：`cd /f/sino-mci/backend && mvn clean install -DskipTests`
- 后端单元测试：`cd /f/sino-mci/backend && mvn test -pl mci-server,mci-channel-wecom`
- admin-web 运行命令：`cd /f/sino-mci/admin-web && npm run dev`
- 登录账号：`superadmin` / `admin123`
- 当前代码分支：`main`，远端为 `origin/main`
- 不要删除或覆盖工作区中未提交的无关文件

---

## 文件结构

本次验证主要读取/操作以下文件：

- `admin-web/src/views/ChannelAccount.vue` — 创建 WECOM_BOT 账号
- `admin-web/src/views/Conversation.vue` — 创建内部群、绑定账号
- `admin-web/src/views/MessageTest.vue` — 发送测试消息
- `admin-web/src/views/SendRecord.vue` — 查询发送记录
- `backend/mci-server/src/main/java/com/sino/mci/send/service/SendService.java` — 发送路由与状态
- `backend/mci-server/src/main/java/com/sino/mci/channel/service/ConversationService.java` — 会话绑定校验
- `backend/mci-server/src/main/java/com/sino/mci/channel/service/AccountSelector.java` — 账号选择
- `logs/mci-server.log` — 后端错误排查
- `admin-web/screenshots/` — 保存验证截图

---

### Task 1: 环境检查

**Files:**
- Read: `logs/admin-web.log`, `logs/mci-server.log`, `logs/channel-service.log`
- Use: Chrome DevTools MCP

**Interfaces:**
- Consumes: 后台服务进程状态
- Produces: 环境就绪确认

- [ ] **Step 1: 检查后台服务是否运行**

Run: `cd /f/sino-mci && docker compose -p sino-mci --profile infra ps` (Windows 环境可能无 Docker CLI，此时通过后端日志/网络连接确认基础设施可达)
Expected: MySQL / Redis / RabbitMQ 容器正常（或本地已启动等价服务/远程可达）。

Run: `ps aux | grep -E "mci-server|admin-web|channel-service" | grep -v grep`
Expected: 三个服务进程都在运行。

- [ ] **Step 2: 检查 admin-web 可访问**

Use Chrome DevTools MCP navigate to `http://localhost:5177/login`.
Expected: 页面加载到登录页，无 404/502。注意：开发环境下 `/msg-platform` 会被 Vite proxy 转发到后端。

- [ ] **Step 3: 若服务未启动则启动**

Run: `cd /f/sino-mci && ./scripts/run-local.sh backend` (若未运行)
Run: `cd /f/sino-mci && ./scripts/run-local.sh frontend` (若未运行)
Run: `cd /f/sino-mci && ./scripts/run-local.sh channel` (若未运行)

- [ ] **Step 4: 提交状态**

If all services are healthy, mark Task 1 complete. No code commit needed.

---

### Task 2: 登录并创建 WECOM_BOT 账号

**Files:**
- Modify if needed: `admin-web/src/views/ChannelAccount.vue`
- Test via UI: `http://localhost:5177/channel/account`

**Interfaces:**
- Consumes: `POST /api/v1/channel-account`
- Produces: 一个 accountType=6 的 WECOM_BOT 账号记录

- [ ] **Step 1: 登录 admin-web**

Use Chrome DevTools MCP:
- Navigate to `http://localhost:5177/login`
- Fill username `superadmin`, password `admin123`
- Click login
- Expected: 跳转至首页。

- [ ] **Step 2: 进入渠道账号页面**

Navigate to `http://localhost:5177/channel/account`.
Take screenshot: `admin-web/screenshots/02-bot-created.png`

- [ ] **Step 3: 打开创建账号弹窗**

Click "新增账号".
Expected: 弹窗显示表单，账号类型下拉包含「企微群机器人」。

- [ ] **Step 4: 填写 WECOM_BOT 账号信息**

Select:
- 账号类型：企微群机器人
- 渠道：`wecom`
- 账号 ID：填写企业微信群机器人 key（如真实 key 或 `test-bot-001`）
- 名称：`测试内部群机器人`
- Webhook URL：若使用占位 key，填写一个可访问的 mock URL（如 `https://httpbin.org/post` 或本地 mock 服务）

- [ ] **Step 5: 提交并确认**

Click "保存".
Expected: 弹窗关闭，列表出现新账号，类型显示为「企微群机器人」。
Take screenshot: `admin-web/screenshots/02-bot-created.png`

- [ ] **Step 6: 数据库确认（可选）**

Run: `docker exec -it mci-mysql mysql -uroot -proot sino_mci -e "SELECT id, account_name, account_type, channel_type FROM mci_channel_account WHERE account_type=6;"`
Expected: 看到新创建的 WECOM_BOT 记录。

- [ ] **Step 7: 提交修复（如有 UI 问题）**

If any bug found, fix in `admin-web/src/views/ChannelAccount.vue` and commit.

---

### Task 3: 手动创建内部群

**Files:**
- Modify if needed: `admin-web/src/views/Conversation.vue`
- Test via UI: `http://localhost:5177/customer/group`

**Interfaces:**
- Consumes: `POST /api/v1/conversation`
- Produces: conversationType=2, conversationScene=1 的会话记录

- [ ] **Step 1: 进入会话管理页面**

Navigate to `http://localhost:5177/customer/group`.
Take screenshot: `admin-web/screenshots/04-internal-group-created.png`

- [ ] **Step 2: 打开新增会话弹窗**

Click "新增会话".
Expected: 弹窗包含「会话类型」「渠道」「场景」「渠道会话ID」「名称」「负责人」。

- [ ] **Step 3: 填写内部群信息**

Select:
- 会话类型：群聊
- 渠道：`wecom`
- 场景：内部群
- 渠道会话 ID：`roomid_manual_internal_001`
- 名称：`测试内部群`
- 负责人：留空或选择任意账号

- [ ] **Step 4: 提交并确认**

Click "保存".
Expected: 弹窗关闭，列表出现新群聊，场景列显示「内部群」。
Take screenshot: `admin-web/screenshots/04-internal-group-created.png`

- [ ] **Step 5: 数据库确认（可选）**

Run: `docker exec -it mci-mysql mysql -uroot -proot sino_mci -e "SELECT id, conversation_name, conversation_type, conversation_scene FROM mci_conversation WHERE channel_conversation_id='roomid_manual_internal_001';"`
Expected: conversation_scene=1。

---

### Task 4: 绑定 WECOM_BOT 到内部群

**Files:**
- Modify if needed: `admin-web/src/views/Conversation.vue`, `backend/mci-server/src/main/java/com/sino/mci/channel/service/ConversationService.java`
- Test via UI: 会话详情抽屉

**Interfaces:**
- Consumes: `POST /api/v1/conversation/{id}/bind-account`
- Produces: ChannelAccountConversation 主发送绑定记录

- [ ] **Step 1: 打开会话详情**

In Conversation list, click the row of the newly created internal group.
Expected: 右侧抽屉打开，显示会话详情和「绑定账号」「绑定标签」按钮。

- [ ] **Step 2: 打开绑定账号弹窗**

Click "绑定账号".
Expected: 弹窗显示可选账号列表，应能过滤或显示 WECOM_BOT 账号。

- [ ] **Step 3: 选择 WECOM_BOT 账号**

Select the WECOM_BOT account created in Task 2.
Binding type: 主发送账号（若 UI 有选项，选 1）。

- [ ] **Step 4: 提交并确认**

Click "保存" / "绑定".
Expected: 绑定成功提示，会话详情中负责人变为该 WECOM_BOT 账号。
Take screenshot: `admin-web/screenshots/05-bot-bound.png`

- [ ] **Step 5: 数据库确认（可选）**

Run: `docker exec -it mci-mysql mysql -uroot -proot sino_mci -e "SELECT account_id, binding_type FROM mci_channel_account_conversation WHERE conversation_id=(SELECT id FROM mci_conversation WHERE channel_conversation_id='roomid_manual_internal_001');"`
Expected: 存在 binding_type=1 的记录。

- [ ] **Step 6: 提交修复（如有绑定校验问题）**

If binding fails with "账号渠道类型与会话不一致" or similar, check `ConversationService.isAccountCompatibleWithConversation` and fix.

---

### Task 5: 发送测试消息

**Files:**
- Modify if needed: `admin-web/src/views/MessageTest.vue`, `backend/mci-server/src/main/java/com/sino/mci/send/service/SendService.java`
- Test via UI: `http://localhost:5177/message/test`

**Interfaces:**
- Consumes: `POST /api/v1/send/test` 或 `POST /api/v1/send`
- Produces: SendResponse(taskId, totalCount, status)

- [ ] **Step 1: 进入消息测试页面**

Navigate to `http://localhost:5177/message/test`.
Take screenshot: `admin-web/screenshots/06-message-test.jpeg`

- [ ] **Step 2: 选择内部群目标**

Select target type = 群聊，选择刚才创建的「测试内部群」。

- [ ] **Step 3: 填写消息内容**

Content type: text
Content: `测试消息 from e2e verification`

- [ ] **Step 4: 发送并记录 taskId**

Click "发送".
Expected: 页面显示发送成功，返回 taskId 和 status（如 `accepted`）。
Copy the taskId.
Take screenshot: `admin-web/screenshots/07-message-sent.png`

- [ ] **Step 5: 后端日志检查**

Tail `logs/mci-server.log` for routing decision.
Expected log: 路由到 WECOM_BOT 账号，调用 webhook URL。

- [ ] **Step 6: 提交修复（如有路由错误）**

If routing goes to WECHAT_PERSONAL or WECOM_AGENT instead of WECOM_BOT, fix `SendService.resolveConversationTarget`.

---

### Task 6: 查询任务状态

**Files:**
- Modify if needed: `admin-web/src/views/SendRecord.vue`, `backend/mci-server/src/main/java/com/sino/mci/send/service/SendService.java`
- Test via UI/API: `GET /api/v1/send/{taskId}/status`, `GET /api/v1/send/records`
- UI page: `http://localhost:5177/message/send-record`

**Interfaces:**
- Consumes: taskId from Task 5
- Produces: 聚合状态计数和明细记录

- [ ] **Step 1: 等待 MQ 消费**

Wait 5-10 seconds for send task to be processed.

- [ ] **Step 2: 查询任务状态**

Option A (UI): Navigate to SendRecord page, filter by taskId.
Option B (API): `curl -H "X-Tenant-Code: <tenant>" http://localhost:8080/msg-platform/api/v1/send/{taskId}/status`

Expected: total=1, success=1 或 failed=1（取决于 webhook URL 是否有效）。
Take screenshot: `admin-web/screenshots/08-task-status.png`

- [ ] **Step 3: 查询明细记录**

Run: `docker exec -it mci-mysql mysql -uroot -proot sino_mci -e "SELECT task_id, channel_type, send_status, channel_result FROM mci_send_record WHERE task_id='{taskId}';"`
Expected: send_status in (2,3)，channel_type related to wecom_bot/wecom。

- [ ] **Step 4: 提交修复（如有状态不准）**

If status counts are wrong or records missing, fix `SendService.getTaskStatus` or `SendMessageConsumer`.

---

### Task 7: 汇总验证报告

**Files:**
- Create: `docs/testing/2026-07-15-send-routing-e2e-report.md`

**Interfaces:**
- Consumes: 前面所有任务的截图、日志、数据库结果
- Produces: 验证报告文档

- [ ] **Step 1: 整理发现的问题和修复**

List all bugs found and their commits.

- [ ] **Step 2: 编写报告**

Write report with sections:
- 环境
- 执行步骤
- 通过项
- 未验证项（如需真实企业微信环境）
- 剩余风险
- 截图索引

- [ ] **Step 3: 提交报告和截图**

```bash
git add admin-web/screenshots/ docs/testing/2026-07-15-send-routing-e2e-report.md
git commit -m "docs(testing): e2e verification report for send routing"
```

- [ ] **Step 4: Push 到 origin/main**

```bash
git push origin main
```

---

## Self-Review Checklist

- [ ] Spec coverage: 设计文档中的 7 步流程、检查点、问题处理、交付物均有对应任务。
- [ ] Placeholder scan: 无 TBD/TODO，所有步骤均有明确命令或操作。
- [ ] Type consistency: 使用的设计字段名（conversationScene, accountType, channelType, taskId）与代码一致。
- [ ] File paths: 所有路径均使用绝对路径或相对于 `/f/sino-mci` 的路径。
