# 企微智能 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` 时显示 `` 占位,根本没有 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 发布前