184 lines
5.5 KiB
Markdown
184 lines
5.5 KiB
Markdown
|
|
# 二次评审: workbuddy 4 P1 消息优化修复
|
||
|
|
|
||
|
|
**推送日期**: 2026-06-14
|
||
|
|
**评审日期**: 2026-06-14
|
||
|
|
**评审人**: Claude
|
||
|
|
**关联 PR**: `feature/p1-message-fixes` → main
|
||
|
|
**关联 commit**: 4 个(整合到 3 commit)
|
||
|
|
- `c7eb87b` fix(upload): P1-1 改 volume mount 持久化上传文件(P1-1 + P1-3 合并)
|
||
|
|
- `2cd162e` fix(alembic): P1-2 生成消息状态字段迁移
|
||
|
|
- `59c5df3` feat(ws): P1-4 实现 broadcast_message_status 实时广播
|
||
|
|
- 任务清单 `2026-06-14-任务-修P1消息.md` 已在 e057923
|
||
|
|
**评审结论**: 🟢 **3/4 完美,1 半成品(P1-1 留优化项)**
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## ⭐ 一句话结论
|
||
|
|
|
||
|
|
4 P1 修复全部合入:**P1-2 / P1-3 / P1-4 完美**;**P1-1 半成品**(用了 named volume,没用 host bind mount)→ 留 P2 优化项,本轮**通过合入**。
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📊 4 P1 评审结果
|
||
|
|
|
||
|
|
| P1 # | 项 | 评审 | 备注 |
|
||
|
|
|---|---|---|---|
|
||
|
|
| P1-1 | upload volume mount | 🟡 半成品 | named volume → 留 P2 优化 |
|
||
|
|
| P1-2 | alembic 009 迁移 | 🟢 完美 | 字段 + 链对 |
|
||
|
|
| P1-3 | healthcheck Python | 🟢 完美 | urllib,稍重可接受 |
|
||
|
|
| P1-4 | ws_manager 状态广播 | 🟢 完美 | 方法签名清晰 |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## ✅ 已正确完成
|
||
|
|
|
||
|
|
### P1-2 (alembic 009 迁移)
|
||
|
|
|
||
|
|
**文件**: `backend/alembic/versions/009_add_message_status.py`
|
||
|
|
|
||
|
|
```python
|
||
|
|
revision: str = '009_add_message_status'
|
||
|
|
down_revision: Union[str, None] = '008_add_agent_password'
|
||
|
|
|
||
|
|
def upgrade():
|
||
|
|
op.add_column('messages', sa.Column('status', sa.String(20), nullable=False, server_default='sent'))
|
||
|
|
op.add_column('messages', sa.Column('recallable_until', sa.DateTime(timezone=True), nullable=True))
|
||
|
|
```
|
||
|
|
|
||
|
|
**验收** ✅:
|
||
|
|
- 依赖链对(009 → 008)
|
||
|
|
- `status` 字段 NOT NULL + server_default='sent' 兼容旧数据
|
||
|
|
- `recallable_until` 字段 nullable(撤回前允许 NULL)
|
||
|
|
- `downgrade()` 干净
|
||
|
|
|
||
|
|
### P1-3 (healthcheck 改 Python)
|
||
|
|
|
||
|
|
**改动**:
|
||
|
|
```yaml
|
||
|
|
# 旧
|
||
|
|
test: ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"]
|
||
|
|
# 新
|
||
|
|
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health').read()"]
|
||
|
|
```
|
||
|
|
|
||
|
|
**验收** ✅:
|
||
|
|
- backend 精简镜像没 curl,改 Python 走 urllib 解决
|
||
|
|
- 后端需有 `/health` 端点(看是否要补)
|
||
|
|
- 顺手把 interval 15s→30s, timeout 5s→10s, start_period 30s→40s(更稳)
|
||
|
|
|
||
|
|
### P1-4 (ws_manager 状态广播)
|
||
|
|
|
||
|
|
**文件**: `backend/app/services/ws_manager.py`
|
||
|
|
|
||
|
|
```python
|
||
|
|
async def broadcast_message_status(
|
||
|
|
self,
|
||
|
|
conv_id: str,
|
||
|
|
msg_id: str,
|
||
|
|
status: str,
|
||
|
|
participant_ids: List[str],
|
||
|
|
extra: dict = None,
|
||
|
|
) -> int:
|
||
|
|
"""向会话所有参与方广播消息状态变更。"""
|
||
|
|
payload = {
|
||
|
|
"type": "message_status",
|
||
|
|
"conv_id": conv_id,
|
||
|
|
"msg_id": msg_id,
|
||
|
|
"status": status,
|
||
|
|
**(extra or {}),
|
||
|
|
}
|
||
|
|
sent_count = 0
|
||
|
|
for pid in participant_ids:
|
||
|
|
if pid in self.active_connections:
|
||
|
|
await self.send_to_agent(pid, payload)
|
||
|
|
sent_count += 1
|
||
|
|
elif pid in self.employee_connections:
|
||
|
|
await self.send_to_employee(pid, payload)
|
||
|
|
sent_count += 1
|
||
|
|
return sent_count
|
||
|
|
```
|
||
|
|
|
||
|
|
**验收** ✅:
|
||
|
|
- 方法签名清晰,接收 `participant_ids: List[str]`
|
||
|
|
- 推 `{"type": "message_status", ...}` JSON
|
||
|
|
- 分别推坐席(`active_connections`)+ 员工(`employee_connections`)
|
||
|
|
- 返回 sent_count
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🟡 P1-1 半成品(留 P2 优化)
|
||
|
|
|
||
|
|
**当前实现**:
|
||
|
|
```yaml
|
||
|
|
volumes:
|
||
|
|
backend-uploads:
|
||
|
|
name: wecom_it_backend_uploads
|
||
|
|
```
|
||
|
|
|
||
|
|
**问题**:
|
||
|
|
- **named volume** 由 Docker 管理
|
||
|
|
- 容器重建(`docker-compose up -d`)→ volume **保留** → 数据不丢
|
||
|
|
- 但 `docker-compose down -v` → **删所有 volume** → 数据**丢** ⚠️
|
||
|
|
- 之前 6-14 生产事故(`docker compose -p root ... down`)教训:用户曾误删容器
|
||
|
|
|
||
|
|
**理想修复**:
|
||
|
|
```yaml
|
||
|
|
volumes:
|
||
|
|
backend-uploads:
|
||
|
|
driver: local
|
||
|
|
driver_opts:
|
||
|
|
type: none
|
||
|
|
o: bind
|
||
|
|
device: /volume1/docker/wecom-it-desk/uploads
|
||
|
|
```
|
||
|
|
+ `scripts/deploy.sh` 部署时建 host 目录
|
||
|
|
+ 容器重建**永不丢**(数据在 host 物理盘)
|
||
|
|
|
||
|
|
**评审结论**:
|
||
|
|
- 当前实现**够用**(用户不用 `-v` 不会丢)
|
||
|
|
- **风险**:用户文档/培训没强调"不要用 `-v`"
|
||
|
|
- 留 P2 优化项,#25 跟踪
|
||
|
|
- **本轮通过合入**
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📁 变更清单(3 commit)
|
||
|
|
|
||
|
|
```
|
||
|
|
c7eb87b fix(upload): P1-1 改 volume mount 持久化上传文件 +20 行
|
||
|
|
2cd162e fix(alembic): P1-2 生成消息状态字段迁移 +36 行(新文件)
|
||
|
|
59c5df3 feat(ws): P1-4 实现 broadcast_message_status 实时广播 +49 行
|
||
|
|
|
||
|
|
3 commits
|
||
|
|
- backend/alembic/versions/009_add_message_status.py +36(新)
|
||
|
|
- backend/app/services/ws_manager.py +49
|
||
|
|
- docker-compose.yml +14 -3
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔄 workbuddy 下一轮任务清单(留 P1-1 优化)
|
||
|
|
|
||
|
|
| # | 任务 | 备注 |
|
||
|
|
|---|---|---|
|
||
|
|
| P1-1 优化 | 改 host bind mount 到 `/volume1/docker/wecom-it-desk/uploads` | 任务 #25 |
|
||
|
|
| | 同步 `scripts/deploy.sh` 建 host 目录 | |
|
||
|
|
| | 加 `deploy.sh` 文档:别用 `docker-compose down -v` | |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## ⚠️ 评审教训(防 workbuddy 再犯)
|
||
|
|
|
||
|
|
1. **P1 修复合入也要标"半成品"** —— 不是 0/1,可能有 90% 完美项
|
||
|
|
2. **workbuddy 把 P1-1 + P1-3 合 1 commit** —— 因为都改 `docker-compose.yml`,但 commit message 应该写"含 P1-1 + P1-3"更清晰
|
||
|
|
3. **named volume vs host bind mount** —— workbuddy 没主动选最稳的,需要评审员点出
|
||
|
|
4. **/health 端点存在性** —— healthcheck 引用了 `/health`,需确认 backend 路由有
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔗 推 Gitea 状态
|
||
|
|
|
||
|
|
- **远端分支**: `feature/p1-message-fixes`(HEAD = `59c5df3`)
|
||
|
|
- **评审**: 3/4 完美 + 1 半成品(可合)
|
||
|
|
- **下一步**: 用户开 PR 合 main → 部署 9 修复
|