# 评审报告: workbuddy 2026-06-14 消息相关更新

**评审日期**: 2026-06-14
**评审人**: Claude (claude-opus-4-8)
**评审范围**: workbuddy 6-13/6-14 推送 + 版本更新说明文档 + 实际代码 diff
**状态**: P0 全部已修(本地代码);P1/P2 待 workbuddy 跟进

---

## 一、评审范围(8 个文件 + 1 文档)

| 文件 | 类型 | 评审点 |
|---|---|---|
| `backend/app/models/message.py` | 改动 | status, recallable_until 字段 |
| `backend/app/api/messages.py` | **新增 5 端点** | recall / delete / mark-read / image / file |
| `backend/app/services/ws_manager.py` | 声称改动 | "消息状态广播"(实际未实现) |
| `backend/app/dependencies.py` | 改动 | get_shared_ai_handler(AIHandler 修复) |
| `backend/app/api/h5.py` | 改动 | 邀请功能 3 端点 + participants |
| `backend/app/api/agents.py` | 改动 | OTP 双因素(otp-bind/otp-verify/otp-unbind) |
| `frontend-h5/src/api/conversation.ts` | 改动 | mapMessage 字段映射(id→message_id) |
| `docker-compose.yml` | 改动 | healthcheck 配置(backend 用 curl 已知坑) |
| `docs/智能IT支持服务台-版本更新说明-20250614.md` | 文档 | v1.1.0 发布说明 |

---

## 二、文档 vs 代码 vs 记忆 三方不一致 ⭐ 关键发现

| 项 | 版本文档 | 代码 | workbuddy 6-14 记忆 |
|---|---|---|---|
| 消息撤回/删除/状态 | ✅ 文档说已做 | ✅ 实际做了 | ❌ 记忆未提 |
| 标记已读 | ✅ | ✅ | ❌ |
| 图片/文件上传 | ✅ | ✅ (路径在容器本地) | ❌ |
| Health Check 已配置 | ✅ | ⚠️ 配了但 backend 用 curl 永远 unhealthy | ❌ |
| ws_manager 状态广播 | ✅ 文档说做了 | ❌ **代码里没有** | ❌ |
| AI Gateway 预留 | ✅ 文档说做了 | ❌ **未看到** | ❌ |
| OTP 双因素 | ✅ | ✅ | ✅ |
| 数据库 id 字段 UUID→VARCHAR(36) | ❌ 文档未提 | ✅ | ✅ |

**结论**:
- 文档描述的"本次更新"**远多于** workbuddy 实际 push 的内容
- 文档与代码有 **5 处不一致**(ws_manager 状态广播未做、AI Gateway 未做、healthcheck 配错、upload 路径不持久、SQL 迁移未走 Alembic)
- 文档 "审核状态: 待审核" → **本次评审填补了审核空缺**

---

## 三、13 项发现(按严重度)

### 🔴 P0 安全(6 项,**全部已修**)

| # | 位置 | 问题 | 修复 |
|---|---|---|---|
| **P0-1** | `h5.py:1107` | participants 端点仅校验"已登录",未校验"是否属于本会话" | 加 is_creator/is_participant 校验 |
| **P0-2** | `messages.py:293` | recall_message 无任何鉴权,任意 HTTP 客户端可改任意消息 | 加 `Depends(get_current_agent)` + sender_id 校验 |
| **P0-3** | `messages.py:336` | delete_message 同上,可删任意消息 | 同上 |
| **P0-4** | `messages.py:368` | mark_read 任意人可改任意会话已读状态 | 加 agent 鉴权 + assigned/collaborator 校验 |
| **P0-5** | `messages.py:400` | upload_image 无鉴权,可任意上传占用磁盘 | 加 `Depends(get_current_agent)` |
| **P0-6** | `messages.py:458` | upload_message_file 同上 | 同上 |

### 🟡 P1 重要(4 项,**待 workbuddy 跟进**)

| # | 位置 | 问题 |
|---|---|---|
| **P1-1** | `messages.py:434,487` | upload 保存到 `media/images/`,`media/files/`(容器本地),**容器重建即丢失** |
| **P1-2** | `alembic/versions/` | 模型有 `status`/`recallable_until`,但**未见对应迁移脚本**;文档教用户手动 ALTER(反模式) |
| **P1-3** | `docker-compose.yml:118` | backend healthcheck 用 `curl`,容器无 curl → 永远 unhealthy(关联 [[backend-healthcheck-curl-pitfall]]) |
| **P1-4** | `ws_manager.py` | 文档承诺"添加消息状态广播",**代码里没看到对应方法**(ConnectionManager 仅有 send_to_agent/broadcast/send_to_employee/broadcast_to_employees) |

### 🟢 P2 次要(3 项)

| # | 位置 | 问题 | 状态 |
|---|---|---|---|
| **P2-1** | `messages.py:388` | `where(Message.is_read == False)` 在 SQLAlchemy 里不报错但实际**未生效** | **P0-4 修复时一并修**:`is_(False)` |
| **P2-2** | `messages.py:440,494` | upload 写文件非原子,中途崩溃留半文件 | 待 workbuddy 修 |
| **P2-3** | `messages.py:501` | upload 返回原始 `original_name`,可能含中文/特殊字符 | 待 workbuddy 修 |

---

## 四、文档本身的 4 处错误(评审发现)

| # | 位置 | 错误 | 建议 |
|---|---|---|---|
| 1 | 部署步骤 6 | SQL `ALTER TABLE ... DEFAULT 'sent'` 引号未转义,shell 执行会语法错 | 改用 alembic 迁移脚本,不手动 ALTER |
| 2 | 部署步骤 5 | `docker compose -p root up -d` **正是用户 6-14 生产事故的根因** | **删除 -p root 标志**,从 `/opt/wecom-it-desk/` 跑即可 |
| 3 | 2.1 ws_manager | 声称"添加消息状态广播",**代码里没有** | 文档状态改为 "未实现,后续迭代" |
| 4 | 2.1 docker-compose | "healthcheck 已配置" 不准确 | 注明 "backend healthcheck 有 curl 坑,待修" |

---

## 五、对比之前 workbuddy 评审

| 旧 P0 (5 项) | 本次 P0 (6 项) | 备注 |
|---|---|---|
| #1 WECOM_SECRET 明文 | (不变) | 等 P0 安全止血阶段 |
| #2 SSL 私钥在 docs/ | (不变) | 阶段 8-A 前置解决 |
| #3 Mock login bypass | (已修复) | — |
| #4 WS token 在 URL/日志 | (不变) | 等 P0 安全止血 |
| #5 坐席登录无 password | (不变) | 等 P0 安全止血 |
| — | **P0-1** H5 participants 鉴权 | 本次新发现 |
| — | **P0-2**~**P0-6** messages.py 5 端点鉴权 | 本次新发现 |

**安全态势**:本次 workbuddy 推送 **反而引入了 6 个 P0 鉴权漏洞**。workbuddy 后续推送需 **强制走评审流程**(本次评审堵住了批量漏洞)。

---

## 六、修复与待办

### 已完成(2026-06-14 本地代码)

- [x] P0-1 ~ P0-6 共 6 个鉴权修复
- [x] P2-1 SQL `== False` → `is_(False)`(捎带修)

### 待 workbuddy 跟进

- [ ] P1-1 upload 路径改为 volume mount
- [ ] P1-2 补 Alembic 迁移脚本(对照 `models/message.py` 新字段)
- [ ] P1-3 docker-compose backend healthcheck 改 TCP 端口检查
- [ ] P1-4 实现 ws_manager 消息状态广播方法
- [ ] P2-2 upload 写文件改 `*.tmp` + rename 原子化
- [ ] P2-3 upload 返回文件名做 XSS 过滤 / URL encode

### 待文档/流程

- [ ] `docs/智能IT支持服务台-版本更新说明-20250614.md` 4 处错误修订
- [ ] workbuddy 推送流程:加 "PR 前 P0 强制评审" 环节

---

## 七、风险跟踪表更新

新增 6 项 P0(本次评审),3 项 P1,3 项 P2(详见 `docs/风险跟踪表.md`)。

---

**评审结论**: workbuddy 6-14 推送 **P0 比例过高(6/13 = 46%)**,强烈建议加评审环节。本次评审发现的 6 个 P0 全部已修代码,待 workbuddy 跟进 P1/P2。
