# 企微智能 IT 支持服务台 — 项目全量知识库

> **项目代号**:`wecom_it_smart_desk`
> **状态**:v0.5.0-beta 内测(2026-06-15),v0.4.x 仍为生产稳定版
> **目标用户**:公司 6000 员工(企微 IM)
> **核心痛点**:员工绕过 AI 直接找人工 / AI 转人工需另开窗口 / 无法跨主体共享
> **核心方案**:自研 IT 服务坐席系统,基于企微自建应用消息 API
> **演进路径**:M1 消息接管 → M2 AI 接入 → M3 知识库闭环
> **本文档用途**:Claude 全面接管项目后的"项目大脑" — 完整功能/架构/集成/部署/安全/历史决策清单
> **最后更新**:2026-06-15(项目从 WB 移交到 Claude 接管)

---

## 0. 项目移交状态(2026-06-15)

| 项目 | 状态 |
|---|---|
| 项目控制方 | **Claude 全面接管**(原由 Workbuddy CN 推进,2026-06-15 起停用) |
| WB 项目目录 | `D:\资料\03-项目开发\wecom_it_smart_desk`(待用户授权后归档封存) |
| Claude 工作目录 | `D:\资料\03-项目开发\wecom_it_smart_desk-claude`(唯一 active 副本) |
| 代码托管 | Gitea(自托管 NAS 8418 端口),推送前需重新获 token |
| 移交决策原因 | WB 1009 上下文冲突 + token 误吊销 + 大量功能信息丢失 |
| 关联 memory | `project-handover-to-claude` / `gitea-push-permission-revoked-2026-06-15` |

---

## 1. 业务背景

### 1.1 公司规模与用户
- 6000 员工,全国分子机构
- 内部 IM:企业微信(企微)
- 现有痛点:
  - 员工绕过 AI 直接找人工,AI 筛选率极低
  - AI 转人工需另开窗口,体验割裂
  - 企微"员工服务"不支持跨企业应用共享

### 1.2 核心设计理念
- **并行协作**(非传统串行排队):AI 全程在线 + 人工随时介入 + 员工同一窗口无缝切换
- **统一入口**(v0.5):企微工作台 → 唯一 OAuth2 认证点 → 角色检测 → 路由到用户端/坐席端/管理端
- **AI Wingman**(v0.6+):AI 不仅是服务员工的,更是解放坐席的

### 1.3 三步演进路径

| 里程碑 | 周期 | 核心交付 | 状态 |
|---|---|---|---|
| **M1** 消息接管 + 极简坐席 | 6-8 周 | 企微 API 链路 · 三栏工作台 · H5 双栏 · 邀请功能 | ✅ 代码完成,部署中 |
| **M2** AI 机器人接入 | M1 后 4-6 周 | 千问/Dify/RAGFlow · AI 前置筛选 · 排队系统 | 📋 计划中 |
| **M3** 知识库闭环 | M2 后 4-6 周 | 坐席标注系统 · 千问自动分析 · 知识库自优化 | 📋 计划中 |

---

## 2. 系统架构

### 2.1 部署架构(Docker Compose 单机版)

```
浏览器 ──→ https://itsupport.servyou.com.cn:443
                │
                ▼
         ┌─── nginx (Docker 容器) ────────────────┐
         │  /itdesk/  → H5 员工端 SPA              │
         │  /itagent/ → 坐席工作台 SPA              │
         │  /itadmin/ → 管理后台 SPA(内网/VPN)     │
         │  /itportal/ → 统一入口 SPA              │
         │  /api/*     → backend:8000 (FastAPI)   │
         │  /ws/*      → backend:8000 (WebSocket)  │
         └──────────────┬──────────────────────────┘
                        │ Docker 网络
          ┌─────────────┼─────────────┐
          ▼             ▼             ▼
    ┌──────────┐ ┌──────────┐ ┌──────────┐
    │ backend  │ │ postgres │ │  redis   │
    │ :8000    │ │ :5432    │ │ :6379    │
    └──────────┘ └──────────┘ └──────────┘
```

| 对比项 | 预生产(当前) | 正式环境(未来) |
|---|---|---|
| 部署方式 | Docker Compose 单主机 | K8s 集群高可用 |
| 域名 | `itsupport.servyou.com.cn` | 公司高可用架构 |
| 服务器 | **10.90.5.110**(2026-06-15 起替代 10.80.0.136) | 待迁移 |

### 2.2 技术栈

| 层级 | 技术选型 | 说明 |
|---|---|---|
| 反向代理 | **Nginx**(Docker 容器) | HTTPS 终止 + 路径路由 + WS 代理 + 静态文件 |
| 后端框架 | **FastAPI**(Python 3.12) | 异步 + 自动 OpenAPI + 类型安全 |
| 数据库 | **PostgreSQL 16** | 16 张表(2026-06 最新盘点) |
| 缓存 | **Redis 7** | access_token(TTL 7200s) + JWT 会话 + 模板缓存 |
| ORM | **SQLAlchemy 2.0(async)** | 声明式模型 |
| 数据库迁移 | **Alembic** | 10 个迁移版本(002-009 + initial) |
| 加解密 | **cryptography** | AES-CBC-256 企微消息加解密 |
| 坐席前端 | **Vue3 + ElementPlus + Pinia** | 三栏工作台(会话/对话/AI 助手) |
| 员工 H5 | **Vue3 + Vant4 + Pinia** | 双栏 + 摇人按钮 + 呼叫坐席 |
| 统一入口 | **Vue3**(独立 frontend-portal) | 角色路由选择页 |
| 管理后台 | **Vue3 + ElementPlus** | 13+ 视图(仪表盘/坐席/集成等) |
| 容器化 | Docker + Docker Compose | 4-5 容器一键启停 |

### 2.3 URL 路径规划(已实现)

| 端 | 路径 | 说明 |
|---|---|---|
| 统一入口 | `/itportal/` | 角色路由选择页(v0.5 新增) |
| 用户端 | `/itdesk/` | 员工 H5(原员工端) |
| 坐席端 | `/itagent/` | IT 坐席工作台 |
| 管理端 | `/itadmin/` | 系统配置 + 数据分析(内网白名单) |
| API | `/api/` | 后端接口(企微回调/会话/消息/坐席/...) |
| WebSocket | `/ws/{agent_id}` | 坐席实时推送 |
| 统一入口跳转 | `/` | 302 → `/itportal/` |

---

## 3. 数据库设计(16 张表)

### 3.1 核心业务表(9 张)

| 表名 | 用途 | 关键字段 |
|---|---|---|
| `conversations` | 会话主表 | employee_id, status(queued/serving/resolved), urgency_score(1-5), tags(JSON), is_vip, participants(JSON) |
| `messages` | 消息记录 | sender_type(employee/agent/ai/system), content, msg_type(text/image/file/voice) |
| `agents` | 坐席信息 | user_id, status(online/offline/busy), current_load, max_load, **password_hash**(v0.5 加) |
| `quick_reply_templates` | 快速回复模板 | category, title, content({变量}), variables(JSON) |
| `system_configs` | 系统配置 | config_key, config_value(关键词/阈值/话术) |
| `funny_phrases` | 趣味话术 | scene(6 种), content, tone, is_active |
| `approval_links` | 审批流程链接 | category(IT/HR/行政/财务), title, url |
| `software_downloads` | 软件下载入口 | category, name, version, platform, download_url |
| `agent_notes` | 坐席备注 | conversation_id, agent_id, content |

### 3.2 阶段一新增表(7 张)

| 表名 | 用途 | 关键字段 |
|---|---|---|
| `employees` | 员工档案 | user_id, name, department, mobile, email, is_vip |
| `todos` | 待办事项 | agent_id, conversation_id, content, due_at, status |
| `troubleshooting_templates` | 排障模板 | category, title, steps(JSON) |
| `roles` | RBAC 角色 | name(user/agent/admin), display_name, permissions(JSON) |
| `user_roles` | 用户角色关联 | employee_id, role_id, source(auto/tag/ehr/manual) |
| `role_mapping_rules` | 角色映射规则 | role_id, source_type(wecom_tag/ehr_position/manual), source_value, priority |
| `config_change_logs` | 配置变更审计 | config_key, old_value, new_value, changed_by, changed_at |

> **alembic 迁移链**:6d5520491644(initial) → 002 → 003 → 004 → 005 → 006 → 007 → 008 → 009
> **v0.5 修过的 007 链路断裂** = `007_role_system.py` 中 docstring + `revision` 都写成 `007_role_sys`,v0.5.1 需统一 filename 与 revision(任务 #41)

---

## 4. 业务功能清单(已实现,分阶段)

### 4.1 阶段 0(2025-12, v0.1) — 基础框架
- FastAPI + SQLAlchemy 2.0 + Alembic
- 4 前端工程(坐席/H5/Portal/Admin)
- 企微回调基础
- Docker Compose 编排

### 4.2 阶段 0.2(2026-01, v0.2) — 核心业务
- 16 张数据表(初始 9 张)
- 40+ API 端点
- OAuth2 企微登录
- 消息收发(文本/图片/文件/语音)
- 会话分配 / 抢单 / 转接
- 协作坐席(摇人按钮)
- 邀请功能(P0-09~11)

### 4.3 阶段 0.3(2026-03, v0.3) — AI 辅助与标记
- AI 草稿回复(坐席采纳模式)
- AI 实质性回复计数
- 紧急度评分(1-5)
- 标签系统(举手/情绪/需介入)
- 影响范围评估
- 阻断性标记

### 4.4 阶段 0.4(2026-04, v0.4) — RBAC + 配置
- RBAC 角色管理(user/agent/admin)
- 角色自动映射(企微标签 + eHR 字段)
- 配置变更日志(审计)
- 趣味话术(摇人/等待/接入 6 场景)
- 审批流程链接
- 软件下载入口
- 紧急度算法优化 + VIP 自动匹配
- 部门权限粒度

### 4.5 阶段 0.5(2026-05~06, v0.5.0-beta) — 阶段一收尾
**4 前端 + 47 项功能盘点 66% 完成**

- **H5 员工端**(11 组件):
  - 双栏布局(对话/助手 + 摇人按钮)
  - 摇人(转人工)
  - 呼叫坐席
  - 会话进度查看
  - 审批链接 / 软件下载入口
  - 表情/截图/文件/图片 4 类消息
  - OAuth2 + 降级登录(密码)
- **坐席工作台**(23 组件,三栏):
  - 会话列表(紧急度排序 + VIP/举手/需介入/情绪 标记)
  - 对话区(WebSocket 实时推送 + 30s 心跳 + 指数退避重连 + 3s 轮询降级)
  - AI 助手侧栏(草稿回复/摘要/标签/知识推荐)
  - 接单/抢单/转接
  - 多人协作(摇人 + 邀请功能)
  - 待办事项
  - 排障模板
  - 快速回复(模板缓存到 Redis)
  - 坐席备注
- **管理后台**(13+ 视图):
  - 仪表盘(会话统计/坐席负载/紧急度分布)
  - 坐席管理(CRUD + 状态监控)
  - 角色管理 + 角色映射规则
  - 系统配置(关键词/阈值/话术 CRUD)
  - 配置变更审计
  - 快速回复模板管理
  - 排障模板管理
  - 趣味话术管理
  - 审批链接 / 软件下载管理
  - 终端安全(联软/火绒 集成视图)
  - 集成配置(4 外部系统)
- **统一入口 Portal**:
  - 唯一 OAuth2 认证点
  - 角色检测 + 卡片选择页
  - 角色切换 API
  - 消除公网直访登录页(安全)
- **管理端 API**:
  - 仅内网/VPN 访问(IP 白名单 + 路径 `/api/admin/*`)
- **4 个外部系统集成**:
  - 火绒企业版(17 API 端点,认证成功)
  - 联软 LV7000(68 API 端口,员工映射核心)
  - aTrust 零信任(官方文档修正版)
  - 北森 eHR(待对接,OAuth2)
- **ExternalSystemAdapter 抽象层**(统一接口规范):
  - MockAdapter(开发期) → 真实 API 无缝切换
  - 缓存透明(5 种 TTL)+ 降级安全
  - 上层业务只依赖 ExternalSystemService 统一门面

### 4.6 阶段二规划(v0.6+,启动中)
- H5 全流程(邀请功能已闭环)
- WebSocket 推送(H5 WS 端点已上线)
- OAuth2 认证(已上线)
- 排队机制(未开始,P1)
- 满意度评价(未开始,P1)

### 4.7 阶段三规划
- AI Wingman(三层渐进式:效率 → 认知 → 情感)
  - 效率层:AI 草稿回复 + 自动摘要 + 自动标签(Phase 1)
  - 认知层:知识推荐 + SOP 导航 + 相似工单(Phase 2)
  - 情感层:情绪识别 + 安抚话术 + 语气润色(Phase 3)
- 排查流程图
- 标注体系

### 4.8 阶段四规划
- 知识库迭代闭环
- 数据看板
- 知识库管理

### 4.9 阶段五规划
- 自动/辅助审核
- 自动开单/结单

---

## 5. API 接口分组(20 个 router,7890 行)

| 路径前缀 | 文件 | 端点数 | 说明 |
|---|---|---|---|
| `/api/wecom/callback` | wecom_callback.py | 2 | GET 验证 URL + POST 接收消息 |
| `/api/conversations` | conversations.py | ~15 | 列表/详情/状态/置顶/接单/邀请/退出/移除参与者 |
| `/api/conversations/{id}/messages` | messages.py | ~10 | 消息列表/发送/撤回 |
| `/api/agents` | agents.py | ~12 | 列表/登录(企微+降级+OAuth)/状态切换/密码/OTP |
| `/api/h5/*` | h5.py | ~25 | H5 完整功能(会话/摇人/审批/软件/OAuth) |
| `/api/portal/*` | portal.py | ~5 | 统一入口(角色列表/切换/入口 URL) |
| `/api/admin/*` | admin.py + admin_roles.py | ~25 | 管理后台(仪表盘/坐席/角色/配置) |
| `/api/quick-replies` | quick_replies.py | ~5 | CRUD |
| `/api/todos` | todo_items.py | ~8 | 待办事项 |
| `/api/troubleshooting-templates` | troubleshooting_templates.py | ~6 | 排障模板 |
| `/api/upload` | upload.py | ~4 | 文件/图片/表情上传 |
| `/api/employees` | employees.py | ~5 | 员工档案 |
| `/api/notes` | agent_notes.py | ~4 | 坐席备注 |
| `/api/approvals` | approval.py | ~4 | 审批链接 |
| `/api/wingman` | wingman.py | ~5 | AI Wingman 草稿/摘要 |
| `/api/system` | system.py | ~3 | 健康检查 + 系统信息 |
| `/api/ws/{agent_id}` | ws.py | 1 | WebSocket 实时推送 |
| router.py | — | — | 路由汇总 |

**统一响应格式**:`{ "code": 0, "data": {}, "message": "success" }`
**错误码体系**:0=成功,1000+=通用(10/11/12/13/14/15/16),2000+=企微 API 错误,3000+=业务逻辑错误

### 5.1 v0.5 安全相关错误码(新增)
- E1010 = OAuth2 token 过期
- E1011 = 未授权
- E1012 = **已废弃拆码**(原"首次登录请设置密码"和"改密请输旧密码"语义冲突)
  - **E1015** = AUTH_OLD_PASSWORD_REQUIRED(改密时未输旧密码)
  - **E1016** = AUTH_OLD_PASSWORD_WRONG(改密时旧密码错)
  - E1012 仍保留给"首次登录请设置密码"单一场景
- E1013 = 密码格式不符
- E1014 = 旧密码新密码相同

---

## 6. 后端服务层(15 个 service,7117 行)

| 服务 | 行数 | 职责 |
|---|---|---|
| `wecom_service.py` | 573 | 企微 API 封装(access_token 缓存 + 发消息 + 通讯录 + 上传素材 + OAuth2) |
| `ai_service.py` | 271 | Dify API 封装(流式 + 非流式) |
| `ai_handler.py` | 289 | AI 路由逻辑(打招呼检测 + 呼叫人工拦截) — **v0.5 替换原 ai_service 直接调用** |
| `message_router.py` | 671 | 消息路由大脑(接收 → 路由 → VIP → 标记 → 评分 → 入库 → AI/坐席) |
| `scoring_service.py` | 406 | 紧急度评分(基础分 + 情绪 + VIP + 重复追问 = 1-5) + 标记检测(举手/需介入/情绪) |
| `session_service.py` | 1234 | 会话全生命周期(创建/分配/接单/转接/邀请/退出/移除) |
| `ws_manager.py` | 327 | WebSocket 连接管理(坐席 + H5 注册/推送/广播/清理) |
| `role_mapping_service.py` | 350 | 角色自动映射(企微标签 + eHR 岗位 + 手动) |
| `wingman_service.py` | 445 | 坐席端 AI 助手(草稿/摘要/标签/知识推荐) |
| `token_service.py` | 263 | JWT + Redis 会话管理 |
| `cache_service.py` | 232 | Redis 缓存装饰器 + 策略 |
| `funny_phrase_service.py` | 157 | 6 场景趣味话术(摇人/等待/接入 等) |
| `admin_service.py` | 1728 | 管理后台综合服务 |
| `security_comparison.py` | 149 | 前后端安全对照 |
| `external/`(空目录) | — | 原计划,实际放到 `integrations/` 下 |

---

## 7. 4 个外部系统集成(2,850 行)

### 7.1 通用抽象层(`ExternalSystemAdapter`)

```python
class ExternalSystemAdapter(ABC):
    system_name: str
    is_available: bool
    
    async def health_check() -> bool
    async def get_terminal_by_user(username) -> Optional[TerminalInfo]  # 联软主源
    async def get_terminal_by_computer(name) -> Optional[TerminalInfo]
    async def get_terminal_detail(terminal_id) -> Optional[TerminalInfo]
    async def get_security_status(terminal_id) -> Optional[SecurityStatus]  # 火绒
    async def isolate_terminal(terminal_id, reason) -> bool  # 仅火绒
    async def unisolate_terminal(terminal_id) -> bool
    async def get_vpn_sessions(username) -> List[VpnSession]  # 仅 aTrust
    async def get_online_status(username) -> bool
```

**统一 DTO**:
- `TerminalInfo`(source_system / computer_name / ip_addresses / mac_addresses / os_version / is_online / logged_in_user / department / hardware_summary / last_seen)
- `SecurityStatus`(source_system / virus_events / vulnerabilities / is_isolated)
- `VpnSession`(username / display_name / remote_ip / vpn_ip / is_trusted)

**统一门面服务** `ExternalSystemService.find_user_terminal(username)`:
- 优先级:联软(strusername 精确) → aTrust(bindUserList) → eHR(无,返回 None)
- 火绒隔离操作:重试 1 次 → 失败则记录待执行队列 → 告警坐席

**缓存策略**:
| 数据 | TTL | 刷新 |
|---|---|---|
| 终端映射 | 30 分钟 | 定时 + 访问检查 |
| 终端详情 | 60 分钟 | 懒加载 |
| 安全状态 | 5 分钟 | 短 TTL + 事件驱动 |
| VPN 在线 | 1 分钟 | 短 TTL |
| eHR 员工 | 24 小时 | 每日凌晨全量 |

**降级策略**:
- 单系统不可用:跳过该系统尝试下一优先级
- 全部不可用:返回缓存(标注"可能过时")
- 缓存+系统全挂:返回空 + 告警坐席
- 火绒隔离失败:重试 + 待执行队列 + 告警

### 7.2 火绒企业版集成(`integrations/huorong/`,1184 行)

| 维度 | 内容 |
|---|---|
| 角色 | **安全源(P0)** — 终端列表/漏洞/病毒/隔离 |
| 认证 | HMAC-SHA1 AccessKey |
| 凭证状态 | **现在可拿** |
| API 端点 | 17 个 |
| 核心方法 | `_list`(终端列表) + `_isolation`(隔离) + `_leak`(漏洞) + `_virus`(病毒) |
| 生产 URL | `http://huorong.oa.servyou-it.com:8080` |
| 关键功能 | 一键隔离/解除 + 漏洞事件 + 病毒事件 |
| 文档 | `docs/火绒终端安全系统集成分析.md`(560 行) |

### 7.3 联软 LV7000 集成(`integrations/lianruan/`,956 行)

| 维度 | 内容 |
|---|---|
| 角色 | **主映射源(P0)** — 员工 → 终端精确匹配 |
| 认证 | IP 白名单 + 账号密码 + Token |
| 凭证状态 | 明天可拿(2026-06-11 评估) |
| API 端口 | 68 个 |
| **核心字段** | `strusername`(员工账号,新系统通过此字段关联) |
| 核心方法 | `queryDevByParams(strusername=xxx)` |
| 核心价值 | 员工映射 + 硬件详情 + 在线状态 + VPN IP 关联 |
| 文档 | `docs/联软终端安全系统集成分析.md`(797 行) |

### 7.4 aTrust 零信任集成(`integrations/atrust/`,无)

| 维度 | 内容 |
|---|---|
| 角色 | **VPN 源(P1)** |
| 认证 | HMAC-SHA256 签名 |
| 凭证状态 | **约一周可拿** |
| 核心方法 | `queryAll(bindUserList)` 终端绑定用户 |
| 核心价值 | VPN 在线用户 + VPN IP + 踢出用户 |
| 待对接 | 信息安全团队 |
| 文档 | `docs/aTrust零信任系统集成分析.md`(879 行) |

### 7.5 北森 eHR 集成(规划中)

| 维度 | 内容 |
|---|---|
| 角色 | **辅助静态数据(P2)** |
| 认证 | OAuth2.0 |
| 凭证状态 | 待对接 HR 数字化团队 |
| 用途 | 员工基础信息 + 任职信息(辅助角色映射 ehr_position 字段) |

### 7.6 RAGFlow 知识库集成(`integrations/ragflow/`,690 行)

| 维度 | 内容 |
|---|---|
| 角色 | **AI 知识库(P1)** |
| 用途 | M3 知识库迭代 + M2 语义检索 |
| 凭证 | 现有 10.80.0.85:8080 |
| 文档 | `integrations/ragflow/`, API 模型在 `models.py` |

---

## 8. 消息收发全链路

```
员工发消息(企微) → 企微回调解密 → 消息路由 → 评分标记 → 入库
                                                       │
                                       ┌───────────────┴───────────────┐
                                       ▼                               ▼
                                  坐席 WS 推送                    AI 处理(v0.5 路由层已就位)
                                       │                               │
                                       ▼                               ▼
                                  坐席回复                          AI 回复
                                       │                               │
                                       └──────────────┬────────────────┘
                                                      ▼
                                          企微主动推送(message/send)
                                                      │
                                                      ▼
                                          员工同一窗口收到(无跳转)
```

### 8.1 9 步详细链路
1. **接收**:员工在企微应用内发消息
2. **回调**:企微 POST 加密 XML 到 `/api/wecom/callback`
3. **解密**:`wecom_crypto.decrypt_message()`(AES-CBC-256)
4. **路由**:`MessageRouter.route_message()` — 创建会话 → VIP 检测 → 标记检测 → 评分 → 入库
5. **评分**:`ScoringService` — 5 步(基础分 + 情绪 + VIP + 重复追问 + clamp 1-5)
6. **入库**:`conversations` + `messages` 原子写入
7. **坐席 WS 推送**:`ws_manager.broadcast()`(坐席新消息)
8. **坐席回复**:POST → 后端调企微 `message/send`
9. **员工收到**:企微推送到员工(同一窗口)

### 8.2 紧急度评分公式
```
紧急度 = 基础分(关键词) + 情绪加成 + VIP加成 + 重复追问加成
范围:1-5(clamp)
映射:1=低, 2=中, 3=高, 4=紧急, 5=最高
所有关键词和阈值存 system_configs,支持动态修改无需重启
```

### 8.3 会话排序规则
```
紧急 → 举手 → 需介入 → 活跃 → AI处理中 → 已结单
(同级按 last_message_at 倒序)
```

### 8.4 标记系统
| 标记 | 图标 | 触发条件 |
|---|---|---|
| VIP | 红色 | 企微通讯录规则匹配 |
| 举手 | 黄色 | 员工说关键词或点击摇人按钮 |
| 需介入 | 橙红 | 同一问题追问 > 3 轮 |
| 情绪 | 红色 | 关键词匹配(急/崩溃/投诉等) |

---

## 9. 现有系统复用资源(7 + 8 + 10 项)

### 9.1 🔴 核心复用(P0,直接影响架构)
| # | 资源 | 现有位置 | 新系统对应 |
|---|---|---|---|
| 1 | Dify Workflow | `yw-dify.dc.servyou-it.com/apps` | 坐席助手 AI 面板 + 自动回复(M2) |
| 2 | dify2openai 桥接 | `yw-dify.dc/dify2openai/v1/chat/completions` | 后端调 AI 入口 |
| 3 | RAGFlow 知识库 | `10.80.0.85:8080` | 知识库管理 + 标注闭环(M3) |
| 4 | Qwen3-30B 大模型 | `10.80.0.49:5000/api/llm/servyou/v1` | AI 对话底层 |
| 5 | bge-m3 向量模型 | RAGFlow 内置 | 知识库检索向量化 |
| 6 | Dify DB(只读) | `10.80.128.40:5432` DB=dify User=difyro | 历史数据迁移 |
| 7 | 企微自建应用 | 已创建(CorpID/AgentID/Secret) | 消息收发的企微入口 |

### 9.2 🟡 业务逻辑复用(需适配)
- 现有 system_users → 新 Agent(改 password 明文 → bcrypt)
- 现有会话定义(15 分钟无交互=一个会话)→ 新状态机(queued/serving/resolved)
- 现有自助解决判定 → 新统计口径
- 现有知识库命中判定 → 加 AI 置信度
- 现有 ManualIntervention → 新 tags 体系
- 现有 ManualEntry → 直接复用
- 现有 MonthlyReportQueryView → 新运营报表
- 现有登录认证(Session+Redis+12h) → 新 JWT+Redis

### 9.3 🟢 基础设施复用(直接复用或微调)
- 服务器 `10.80.0.86`(原 Django+PG+Redis,新 FastAPI 同机部署)
- 域名 `it-dataquery.dc.servyou-it.com`(新系统用子域名)
- SSL 证书(`ssl/` 目录)
- Nginx(`nginx/nginx.conf`,改反代配置)
- Docker Compose 部署模式
- Redis(可复用,db=0 旧 / db=1 新)
- SearXNG 搜索 `10.90.5.8:8080`(M2 AI 联网)
- LangBot `10.90.5.8:30030`(多模型接入)
- Docker 网络 `dbquery_net`(新 `itdesk_net`)

### 9.4 关键对接参数
```
dify2openai API:    http://yw-dify.dc.servyou-it.com/dify2openai/v1/chat/completions
RAGFlow:            http://10.80.0.85:8080
Qwen3-30B:          http://10.80.0.49:5000/api/llm/servyou/v1/chat/completions
Dify DB(生产只读):  10.80.128.40:5432 DB=dify User=difyro
Dify DB(测试):      10.199.16.9:5432 DB=dify User=dify_ro
Redis:              10.90.5.8:6379
数据平台:           http://it-dataquery.dc.servyou-it.com (10.80.0.86)
B 端智能体:         https://agent.dc.servyou-it.com
SearXNG:            http://10.90.5.8:8080
Dify App ID:        a57543f3-de66-47cc-ad89-d0540c08159f
```

---

## 10. WebSocket 实时通信

### 10.1 设计要点
- **路径**:`/ws/{agent_id}` + `/ws/h5/{employee_id}`(H5 端点)
- **认证**:**P0 修复后** token 走 `Sec-WebSocket-Protocol` subprotocol(不是 URL query,不是 header)
- **nginx 配置**:
  - `proxy_http_version 1.1`
  - `Upgrade` + `Connection "upgrade"`
  - `proxy_read_timeout 86400s`
  - **`access_log off`**(避免 token 泄露,P0-#4)
- **限流**:无原生限流,依赖 token 鉴权

### 10.2 心跳 + 重连 + 降级
- 心跳:前端 30s ping,后端 pong
- 重连:指数退避(1s → 2s → 4s → ... → 30s 上限)
- 降级:WS 断连 → 自动切 3s 轮询 → 重连后停轮询

### 10.3 ws_manager 单例
- 模块级单例,全局共享
- broadcast 遇发送失败自动断开该连接(避免僵尸)
- 失败只记 warning 不抛异常(不阻塞调用方)

---

## 11. 前端 4 端总览

| 端 | 路径 | 技术栈 | 组件数 | 路由 |
|---|---|---|---|---|
| frontend-h5 | `/itdesk/` | Vue3 + Vant4 + Pinia + TS | 11 | vue-router |
| frontend-agent | `/itagent/` | Vue3 + ElementPlus + Pinia + TS | 23 | vue-router |
| frontend-portal | `/itportal/` | Vue3 + Vant4 + Pinia + TS | 3 | 角色卡片选择 |
| frontend-admin | `/itadmin/` | Vue3 + ElementPlus + Pinia + TS | 13+ | vue-router |

### 11.1 关键 UI 决策
- **统一企微浅色扁平风格**(accent=#07C160 微信绿)
- **术语统一**:"举手" → "招手","铃铛" → "传菜铃"
- **响应式**:H5 端适配企微 WebView

### 11.2 4 前端审计 + 16 项统一优化路线
详见 `docs/前端审计报告.md`

---

## 12. 部署方案

### 12.1 生产服务器(当前 v0.5.0-beta)
| 资源 | 值 |
|---|---|
| 服务器 | **10.90.5.110**(公司内网,2026-06-15 起替代 10.80.0.136) |
| 域名 | `itsupport.servyou.com.cn`(通配符 `*.servyou.com.cn`) |
| HTTPS | 443(SSL 证书已部署,2026-06-15) |
| 80 端口 | 301 跳 443 |
| 数据库 | PostgreSQL 16(Docker) |
| 缓存 | Redis 7(Docker) |
| 部署目录 | `/opt/wecom-it-desk/` |
| 上传临时目录 | `/tmp/`(堡垒机限制) |
| Docker 网络 | bridge(Docker Compose 自定义) |
| 健康检查 | nginx `curl -kf https://localhost:443/itdesk/health` |

### 12.2 NAS 测试环境
| 资源 | 值 |
|---|---|
| 服务器 | NAS(Synology 套件) |
| 域名 | `itdesk.amanzac.com` |
| 用途 | Gitea 自托管(8418 端口) + 内部测试 |

### 12.3 部署包结构(`package.py` 生成)
```
it-smart-desk-server-deploy.zip
├── docker-compose.yml
├── .env.example
├── deploy.sh
├── README.md
├── nginx/nginx.conf
├── frontend-h5/dist/       # H5 静态文件
├── frontend-agent/dist/    # 坐席端静态
├── frontend-portal/dist/   # 统一入口静态
├── frontend-admin/dist/    # 管理后台静态
└── backend/                # FastAPI 源码(排除 uploads/ 隐私)
```

### 12.4 ⚠️ package.py P0 修复(v0.5)
- 补:INCLUDE_MAP 缺 `frontend-portal/dist` 和 `frontend-admin/dist`
- 补:should_exclude 排除 `uploads/`(隐私不打包)
- 补:build_frontends 加 portal + admin 端构建

---

## 13. 运维操作

### 13.1 一键部署
```bash
# 打包
cd 项目根目录
python deploy-server/package.py
# → it-smart-desk-server-deploy.zip

# 上传
scp it-smart-desk-server-deploy.zip user@server:/tmp/
# (堡垒机禁 ProxyJump,需用其他方式:Web 上传 / 内部文件平台)

# 部署
ssh user@server
sudo cp /tmp/it-smart-desk-server-deploy.zip /opt/
cd /opt
unzip it-smart-desk-server-deploy.zip
mv it-smart-desk-server-deploy wecom-it-desk
cd wecom-it-desk
cp .env.example .env
vi .env                  # 编辑配置
chmod +x deploy.sh
./deploy.sh
```

### 13.2 日常运维
```bash
# 查看服务状态
docker compose ps

# 查看后端日志
docker compose logs -f backend

# 数据库迁移
docker compose exec backend alembic upgrade head

# 备份
./scripts/backup-gitea.sh

# 健康度仪表盘
./scripts/dashboard.py
# → docs/dashboard.html(浏览器打开)
```

### 13.3 应急响应
详见 `docs/SOPs/SOP-004-应急响应.md`

---

## 14. 安全设计

### 14.1 已修复 P0(2026-06-14~15)
1. **WS token 泄露** — token 改走 `Sec-WebSocket-Protocol` subprotocol(非 URL/header)
2. **坐席登录缺密码** — `agents.py` L222-232 加 bcrypt 验证(3 测试覆盖)
3. **nginx access_log 记录 WS token** — `/ws/` 路径 `access_log off`
4. **5 鉴权漏洞** — 5 端点鉴权已修
5. **企微凭据硬编码** — 旧 `Bs7ucT*` 已轮换,新值走 `WECOM_CORP_SECRET` env

### 14.2 待修 P0(2026-06-15 报告)
- 5 鉴权漏洞全部修完(已 100% 闭环,见 [[review-p0-security-2026-06-14]])
- 浏览器 WS API 不支持 subprotocol → 需找替代方案
- nginx access_log 全局配置未关(只关了 /ws/)
- 类型 bug / 降级放行 / 缺依赖 5 项遗留(详见评审报告)

### 14.3 安全 Header(nginx)
- `X-Content-Type-Options: nosniff`
- `X-Frame-Options: SAMEORIGIN`
- `X-XSS-Protection: 1; mode=block`
- `Strict-Transport-Security: max-age=31536000; includeSubDomains`
- `Referrer-Policy: strict-origin-when-cross-origin`
- **CSP**:`default-src 'self'; script-src 'self' 'unsafe-eval' https://res.wx.qq.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https: http:; connect-src 'self' https://qyapi.weixin.qq.com wss://*; font-src 'self' data:;`
- `Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()`
- `Cross-Origin-Opener-Policy: same-origin`
- `Cross-Origin-Embedder-Policy: require-corp`
- `Cross-Origin-Resource-Policy: same-origin`
- `server_tokens off`

### 14.4 IP 白名单(nginx)
- `/itadmin/`:10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 10.212.0.0/16(VPN)
- `/api/admin/`:同 itadmin

### 14.5 密码策略
- 坐席密码:**bcrypt**(已迁移明文 → hash)
- DB 用户:PostgreSQL `wecom`(trust on unix socket / MD5 on TCP)
- 旧凭据:已轮换

---

## 15. 决策锁(已锁定,不可随意变更)

| 决策 | 内容 | 锁定日期 | 依据 |
|---|---|---|---|
| **域名** | `itsupport.servyou.com.cn`(通配符 `*.servyou.com.cn`) | 2026-06 | 已有 SSL 证书 |
| **UI 风格** | 企微浅色扁平风,accent=#07C160 | 2026-06-13 | 坐席+H5 统一 |
| **术语** | "举手" → "招手","铃铛" → "传菜铃" | 2026-06-13 | 25+ 处代码修改 |
| **双企微应用** | 正式 + 测试(子域名申请困难) | 2026-06-13 | 决策记录在状态报告 |
| **架构** | 单体 Docker Compose → 未来 K8s 集群 | 2026-06-03 | 演进路径 M3 后再迁 |
| **数据库** | PostgreSQL 16(单库,合并原 Dify + intervention) | 2026-06 | 升级策略 |
| **缓存** | Redis 7(单实例,db 0 旧/db 1 新) | 2026-06 | 复用现有 |
| **认证** | JWT + Redis(替换 Django Session) | 2026-06 | 重写认证层 |
| **AI 模型** | Qwen3-30B 主, Dify Workflow 编排 | 2026-06 | 复用现有 |
| **项目名** | `wecom_it_smart_desk`(claude 工作副本 `-claude` 后缀) | 2026-06-15 | 移交后命名 |
| **Git 托管** | Gitea 自托管(NAS 8418) | 2026-06-14 | ADR-001 |
| **IP 白名单(临时)** | set_real_ip_from 用 10/172.16/192.168/10.212 4 段(内网最大化)**临时方案** | 2026-06-15 | 修 403 异常 |
| **IP 白名单(正式)** | **正式发布前必改**:审计公司实际前置代理 IP,精确单 IP 列表(防 X-Forwarded-For 伪造) | v1.0 必做 | 见 [[ip-whitelist-trust-proxies-todo]] |

### 15.1 配色体系(UI 重要性标识)
- 🔴 紧急/高风险
- 🟡 重要/需关注
- 🟢 常规/OK
- ⚪ 信息/记录

### 15.2 选择项中英对照(用户偏好)
所有选择项英文内容必须包含中文翻译

---

## 16. 工具链(8 个脚本 + 5 份配置)

| # | 路径 | 用途 |
|---|---|---|
| 1 | `scripts/dashboard.py` | 生成健康度 HTML(`docs/dashboard.html`) |
| 2 | `scripts/oneclick-deploy.sh` | 一键部署(灰度) |
| 3 | `scripts/pre-commit-check.sh` | 提交前 4 件套预检(鉴权+依赖+alembic+配置) |
| 4 | `scripts/backup-gitea.sh` | Gitea 备份 + 恢复(cron 3 点) |
| 5 | `scripts/security-audit.sh` | 5 工具集成审计 |
| 6 | `scripts/generate-api-docs.sh` | OpenAPI + Swagger UI + ReDoc |
| 7 | `scripts/build.sh` | 统一构建 |
| 8 | `scripts/deploy.sh` | 通用部署 |

| # | 路径 | 用途 |
|---|---|---|
| 1 | `.dockerignore` | Docker 优化 |
| 2 | `.gitea/dependabot.yml` | 依赖自动更新 |
| 3 | `.gitea/ISSUE_TEMPLATE/bug.md` | Bug 报告模板 |
| 4 | `.gitea/ISSUE_TEMPLATE/feature.md` | Feature 申请模板 |
| 5 | `.gitea/PULL_REQUEST_TEMPLATE.md` | PR 模板 |

---

## 17. 文档体系(50+ 份)

### 17.1 设计文档(7)
- `docs/01-项目总览与部署手册.md`(v2.1, 34K)
- `docs/ARCHITECTURE.md`(完整架构,2,880 行,129K)
- `docs/ARCHITECTURE-admin.md`(管理后台,1,274 行)
- `docs/团队沟通文档-架构消息知识库.md`(655 行)
- `docs/统一入口技术设计文档.md`(909 行)
- `docs/Wingman设计.md`(776 行)
- `docs/外部系统集成`:火绒 560 行 + 联软 797 行 + aTrust 879 行

### 17.2 PRD(2)
- `docs/PRD.md`(完整需求,2,077 行,127K)
- `docs/PRD-admin.md`(管理后台,27K)
- `docs/PRD-增量-人工按钮与术语统一.md`(14K)

### 17.3 技术方案(5)
- `docs/ExternalSystemAdapter设计文档.md`(v1.0)
- `docs/消息功能详细方案.md`(534 行)
- `docs/摇人-多坐席协作-技术方案.md`(389 行)
- `docs/邀请功能-技术方案.md`(407 行)
- `docs/OTP二次验证实现.md`(88 行)

### 17.4 ADR(架构决策记录,4 份)
- `docs/ADRs/ADR-001-Gitea自托管-Funnel暴露.md`
- `docs/ADRs/ADR-002-WS-Token-Subprotocol鉴权.md`
- `docs/ADRs/ADR-003-nginx-access_log关闭.md`
- `docs/ADRs/ADR-004-Token不入文件-走wincred.md`

### 17.5 SOP(标准操作流程,4 份)
- `docs/SOPs/SOP-001-Gitea部署.md`
- `docs/SOPs/SOP-002-Gitea备份恢复.md`
- `docs/SOPs/SOP-003-推送评审.md`
- `docs/SOPs/SOP-004-应急响应.md`

### 17.6 审计报告(4)
- `docs/审计报告/CORS-CSP-安全Header全套.md`
- `docs/审计报告/Dockerfile优化与镜像审计.md`
- `docs/审计报告/依赖漏洞扫描与Lockfile审计.md`(识别 5 CVE)
- `docs/审计报告/健康检查+错误码+日志结构化.md`(40+ 错误码 + JSON 日志)

### 17.7 惊喜报告(2)
- `docs/惊喜报告/🎁惊喜1-项目健康度仪表盘.md`
- `docs/惊喜报告/🎁惊喜2-README徽章+CHANGELOG+模板.md`

### 17.8 评审报告(6)
- `docs/评审报告/workbuddy-2026-06-14-Gitea重建.md`
- `docs/评审报告/workbuddy-2026-06-14-P0安全.md`
- `docs/评审报告/workbuddy-2026-06-14-消息优化-P1二次评审.md`
- `docs/评审报告/workbuddy-2026-06-14-消息优化.md`
- `docs/评审报告/workbuddy-2026-06-14-预检验证.md`
- `docs/评审报告/workbuddy-2026-06-15-T组A组.md`

### 17.9 部署/迁移(6)
- `docs/DEPLOY_NAS.md`
- `docs/NAS部署指南.md`
- `docs/Gitea部署指南.md`
- `docs/正式环境独立部署架构方案.md`
- `docs/智能IT支持服务台-项目迁移文档.md`
- `docs/资源申请清单.md`

### 17.10 状态/报告(5)
- `docs/RELEASE_NOTES_v0.5.0-beta.md`
- `docs/项目任务状态报告_2026-06-13.md`(152 任务 99.3% 完成)
- `docs/IT服务台部署修复记录-2026-06-13.md`
- `docs/调试验证指南_2026-06-13.md`
- `docs/风险跟踪表.md`(907 行)

### 17.11 数据库(1)
- `docs/数据库ER图与环境变量清点.md`(16 表 ER + 17 env)

### 17.12 前端审计(1)
- `docs/前端审计报告.md`(10K)

### 17.13 原型/prototypes(目录)
- `docs/prototypes/`
- `docs/IT智能服务台_项目汇报.html`(34K,可视化)
- `docs/dashboard.html`(健康度仪表盘)

### 17.14 域名/邮件(1)
- `docs/域名申请邮件-itsupport-servyou-com-cn.md`

### 17.15 现有系统交接(1)
- `docs/现有系统交接文档内容.txt`(137 行,原 Django 系统)

### 17.16 紧急预案(1)
- `docs/需求-发布预演页面.md`(应急降级页 v4)

---

## 18. 测试

### 18.1 后端测试
- 116 条 pytest(已写,部分已通过)
- v0.5 新增 3 条(降级登录密码验证)
- 路径:`backend/tests/test_agents.py`

### 18.2 端到端验证
- 任务 #149 — In Progress
- 范围:H5 登录(3 种)/ 坐席接单 / 消息收发 / 邀请功能 / 管理后台
- 环境:`https://itsupport.servyou.com.cn` + `https://itdesk.amanzac.com`

---

## 19. 待办清单(从项目任务状态报告 + 评审报告 + 风险表)

### 19.1 立即执行(P0)
1. ~~端到端验证 #149~~(等待中)
2. ~~HTTPS 配置(SSL 证书)~~ ✅ 已完成(2026-06-15)
3. 修 006 filename 与 revision 不一致(v0.5.1)— 任务 #41
4. ~~alembic chain 修复(007 typo)~~ ✅ 已完成
5. ~~浏览器验证 4 域名~~ ✅ 已完成

### 19.2 近期安排(P1)
1. **创建测试企微应用**(双企微方案)
2. **阶段二启动**:排队机制 + 满意度评价
3. **aTrust 对接**:找信息安全团队
4. **北森 eHR 对接**:找 HR 数字化团队
5. **集成验证**:4 外部系统端到端

### 19.3 技术债务(P2)
1. Redis 密码加固
2. PostgreSQL 强密码
3. CORS 配置收紧
4. CSP 策略实施(已部分实施)
5. 应急降级页(BC/DR)代码
6. 演练 SOP-005

### 19.4 风险登记
| 风险 | 级别 | 缓解 |
|---|---|---|
| 企微凭据集中化 | 中 | NAS Vault(待做) |
| 5 外部系统任一不可用 | 中 | ExternalSystemAdapter 自动降级 |
| 现有系统密码明文 | 高 | bcrypt 迁移已完成 |
| Dify DB 只读 | 中 | 新系统自建库,只从 Dify 同步 |
| 5 CVE(依赖漏洞) | 中 | dependabot 自动更新 |
| WB 上下文冲突 | 高 | **已退出,Claude 接管** |

---

## 20. 关键文件路径速查

### 20.1 后端核心
```
backend/
├── alembic/versions/         # 10 个迁移
├── app/
│   ├── main.py              # FastAPI 入口(608 行)
│   ├── config.py            # 配置(154 行)
│   ├── database.py          # DB 连接(146 行)
│   ├── api/                 # 20 个 router
│   ├── services/            # 15 个 service
│   ├── models/              # 16 个 model
│   ├── schemas/             # Pydantic 5 套
│   ├── integrations/        # 4 个外部系统
│   └── utils/               # error_codes/token/crypto
├── tests/                   # 116 条 pytest
├── Dockerfile
└── requirements.txt
```

### 20.2 前端核心
```
frontend-h5/         # H5 员工端(11 组件)
frontend-agent/      # 坐席工作台(23 组件)
frontend-portal/     # 统一入口(3 组件)
frontend-admin/      # 管理后台(13+ 视图)
```

### 20.3 部署核心
```
deploy-server/
├── package.py       # 打包脚本
├── docker-compose.yml
├── nginx/nginx.conf
├── .env.example
└── deploy.sh
```

### 20.4 配置/规范
```
.dockerignore
.gitea/             # dependabot + issue_template + pr_template
.pre-commit-config.yaml
docs/ADRs/          # 4 份架构决策
docs/SOPs/          # 4 份标准操作
```

---

## 21. 关联 memory 索引(已沉淀)

- [[project-handover-to-claude]] — 项目从 WB 全面移交到 Claude(2026-06-15)
- [[locked-decisions]] — 锁定的设计决策
- [[phase1-progress]] — 痛点清单 + 五阶段演进规划
- [[tech-architecture]] — 技术架构细节(超时/字段映射/Redis 协议)
- [[wechat-environment]] — 企微环境限制(UA/OAuth2/统一入口)
- [[deployment]] — 部署经验(NAS/Docker/堡垒机)
- [[external-integrations]] — 外部系统集成(火绒/联软/aTrust/eHR)
- [[workbuddy-tool]] — WB 推进工具(已停用)
- [[ip-whitelist-trust-proxies-todo]] — IP 白名单正式发布前必收窄(P0 安全收尾)
- [[code-version-chaos]] — 代码版本管理混乱(治理中)
- [[gitea-deployed-2026-06-14]] — Gitea 部署
- [[gitea-push-permission-revoked-2026-06-15]] — push 权限吊销
- [[review-messages-2026-06-14]] — WB 消息评审
- [[review-p0-security-2026-06-14]] — WB P0 安全评审
- [[overnight-batch-2026-06-15]] — 满载跑批产出
- [[server-upload-path]] — 服务器上传路径
- [[production-architecture-pitfall]] — 生产架构误判教训
- [[backend-healthcheck-curl-pitfall]] — backend healthcheck curl 坑
- [[user-language-preference]] — 选择项中英对照
- [[choice-importance-colors]] — 选项配色体系
- [[feedback-execute-without-asking]] — 直接执行不请示

---

## 22. 后续行动(Claude 接管后)

### 22.1 立即
- [ ] 修复 006 filename 与 revision 不一致(v0.5.1,任务 #41)
- [ ] commit 当前所有 hotfixes + push 到 Gitea(等用户重授权)
- [ ] 重打部署包并验证
- [ ] 浏览器验证 /itdesk/ 500 错误根因

### 22.2 短期(1 周)
- [ ] 阶段二排队机制设计
- [ ] 满意度评价 PRD
- [ ] 应急降级页 v4 实现
- [ ] 演练 SOP-005
- [ ] 单元测试全量跑通

### 22.3 中期(1 月)
- [ ] 阶段二 AI 接入(Dify + RAGFlow)
- [ ] aTrust API 对接
- [ ] 北森 eHR OAuth2 对接
- [ ] 知识库迭代闭环(M3 起步)
- [ ] 应急降级页演练

### 22.4 长期
- [ ] v0.6.0 正式发布(2026-06-20)
- [ ] v1.0.0 正式版目标(2026-12,阶段 5 完成)
- [ ] K8s 集群迁移
- [ ] 跨主体共享支持

---

## 23. 今日踩坑(2026-06-15~16 经验沉淀)

> **作用**:把过去两天踩过的 7 个坑写成"事后诸葛亮",让以后部署/排错时少走弯路。每条都给了"症状 → 根因 → 修法 → 教训"四段式。

### 23.1 alembic_version 表脏数据导致 backend 启动 overlaps

- **症状**:backend 容器启动后 alembic 报错 `Multiple head revisions are present for alembic_version`,数据库迁移失败。
- **根因**:之前手动执行 `alembic stamp 009` 后没清旧数据,表里残留两行版本号(008 和 009),alembic 检测到"两个 head"就抛错。
- **修法**:SQL 直连 PostgreSQL → `DELETE FROM alembic_version WHERE version_num != '009';` 只保留最新一行。
- **教训**:**永远用 alembic 命令升级**(alembic upgrade head),不要手工 stamp;如果非要 stamp,先清表再写。

### 23.2 REDIS_URL 密码含 @ # 必须 URL-encode

- **症状**:backend 容器一直 `Redis TimeoutError`,redis-cli 连不上。
- **根因**:生产 Redis 密码 `R3d!s@2026#Secure` 含 `@` 和 `#` 两个 URL 保留字符。redis-py 用 urlparse 解析 `redis://:R3d!s@2026#Secure@redis:6379/0`,第一个 `@` 被当 host 分割,密码被截成 `R3d!s`。
- **修法**:docker-compose.yml 的 REDIS_URL 用 `${REDIS_PASSWORD:-R3d%21s%402026%23Secure}`,shell 展开后是 URL-encoded → redis-py 会自动 decode 回明文 → 与 Redis 实际密码一致。
- **教训**:**密码含 URL 保留字符必须 URL-encode**(`@`→`%40`、`#`→`%23`、`!`→`%21`)。参考 [[redis-url-special-chars-pitfall]] 和 [[redis-py-url-decode-trap]]。

### 23.3 nginx IP 白名单"两处都改"才生效

- **症状**:`/itadmin/` 一直返 403 Forbidden,即使加了 `allow 115.236.188.3;`。
- **根因**:nginx 配置有**嵌套 location**,`/itadmin/` 块(返回 HTML)和 `/api/admin/` 块(代理 API)各有一套独立的 `allow/deny`。只改一处白名单不生效。
- **修法**:两个块都要加 `allow 115.236.188.3;`,然后 `docker exec wecom_it_nginx nginx -s reload`。
- **教训**:**nginx 嵌套 location 都要单独检查**。看 conf 时区分 outer block(12-space indent)和 inner block(16-space indent)。参考 [[nginx-allow-list-pitfall]]。

### 23.4 企微 WebView 真实 IP 不是公司公网 IP

- **症状**:加 `allow 115.236.188.3;` 后用户用 企微 Android Edge 访问 `/itadmin/` 还是 403。
- **根因**:`115.236.188.3` 是公司**公网出口 IP**(WAF 后面的),用户手机走的是移动运营商网络,客户端真实 IP 是运营商 IP,不会经过 115.236.188.3。
- **修法**:临时改成 `allow 0.0.0.0/0;`(全开),靠 backend 的 admin token 鉴权保护。
- **教训**:**WAF/公司公网出口 IP ≠ 用户真实客户端 IP**。要拿用户真实 IP,得看 WAF/CDN 透传的 X-Forwarded-For 字段。**v1.0 前必须收窄**(任务 #48)。

### 23.5 SPA 路由守卫是异步,组件 mount 早就触发了

- **症状**:企微点坐席应用 → `/itagent/` 弹"未授权,请重新登录"2 次。
- **根因**:router 守卫虽然会跳到 `/itportal/`,但 Vue 组件的 `import` + `onMounted` 在 router 守卫**之前**就触发了,axios 拦截器已经发了 `/api/agents/me` 请求 → 后端 401 → 弹"未授权"。
- **修法**:`Workspace.vue` 的 `onMounted` 第一行先检查 `localStorage.getItem('agent_token')`,没 token 立刻 `window.location.href = '/itportal/'` 并 `return`。
- **教训**:**router 守卫不可靠**,任何需要鉴权的页面都要在 `onMounted` 第一行手动检查 token。参考 [[workspace-vue-pre-mount-check]]。

### 23.6 Workspace.vue 没输入框不是 bug,是没选会话

- **症状**:用户报"坐席端没有消息输入框"。
- **根因**:`Workspace.vue` 中间区域是**动态切换**的(`v-if/v-else-if/v-else`),没 `currentConversation` 时显示 `<el-empty description="请从左侧选择..." />` 占位,根本没有 ChatArea/InputBox。
- **诊断**:让用户看中间显示什么。
  - 显示"请选择..." → 不是 bug,引导用户点左侧会话
  - 显示对话气泡但无输入框 → ChatArea 组件 bug
  - 完全空白 → 组件渲染失败
- **教训**:**SPA 视图切换**不要只看"UI 元素缺失",要先看父组件的 `v-if` 条件。参考 [[agent-input-box-no-bug]]。

### 23.7 SQLAlchemy UUID 列在 DB 里是 VARCHAR → 偶发 500

- **症状**:`/h5/conversations/current/messages/poll` 接口偶发 500,日志 `operator does not exist: character varying = uuid`。
- **根因**:数据库 `messages.id` 列是 VARCHAR(早期 migration 用 String 定义),但 SQLAlchemy 模型把 `id` 定义成 UUID,查询时自动 cast `WHERE id = $1::UUID` → 类型不匹配 → 500。
- **修法**:加 alembic migration `ALTER TABLE messages ALTER COLUMN id TYPE UUID USING id::UUID` 把列类型统一成 UUID。
- **教训**:**schema 演进必须改 DB schema**,只改 Python 模型不够。看到 `operator does not exist` 错误,八成是列类型不匹配。参考 [[sql-messages-id-varchar-vs-uuid]]。

### 23.8 backend 精简镜像没 curl,healthcheck 永远 unhealthy 但业务正常

- **症状**:`docker ps` 显示 backend `unhealthy`,但 API 接口全部正常返回 200。
- **根因**:backend 用的是 `python:3.11-slim` 精简镜像,**没有 curl**。docker healthcheck 跑 `curl -f http://localhost:8000/health` 直接 `command not found`,每次都 unhealthy。
- **修法**:改用 `wget --spider` 或直接 `python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"`。
- **教训**:**精简镜像做 healthcheck 要选已装的工具**,或者 build 时加 `apt-get install -y curl`。参考 [[backend-healthcheck-curl-pitfall]]。

### 23.9 frontend 不是独立容器,是 nginx 静态文件挂载

- **症状**:以为 frontend 是 docker 容器,改前端要重新 build image + push。
- **根因**:看 docker-compose.yml 后才发现 frontend 4 个端都是**构建产物直接挂载**到 nginx 容器的 `/itagent/` `/itadmin/` 等目录,前端代码完全在宿主机 `/opt/wecom-it-desk/frontend-*/dist/`。
- **修法**:改前端 → 本地 build → tar 上传 → 解压到 `/opt/wecom-it-desk/frontend-*/dist/` → `docker exec wecom_it_nginx nginx -s reload`。
- **教训**:**先 `cat docker-compose.yml` 再下架构结论**。参考 [[production-architecture-pitfall]]。

---

> **本文档维护者**:Claude(claude 工作目录)
> **更新频率**:每次重大变更后更新
> **下次审计**:v0.6.0 发布前
