企微智能 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 单机版)
| 对比项 |
预生产(当前) |
正式环境(未来) |
| 部署方式 |
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)
统一 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. 消息收发全链路
8.1 9 步详细链路
- 接收:员工在企微应用内发消息
- 回调:企微 POST 加密 XML 到
/api/wecom/callback
- 解密:
wecom_crypto.decrypt_message()(AES-CBC-256)
- 路由:
MessageRouter.route_message() — 创建会话 → VIP 检测 → 标记检测 → 评分 → 入库
- 评分:
ScoringService — 5 步(基础分 + 情绪 + VIP + 重复追问 + clamp 1-5)
- 入库:
conversations + messages 原子写入
- 坐席 WS 推送:
ws_manager.broadcast()(坐席新消息)
- 坐席回复:POST → 后端调企微
message/send
- 员工收到:企微推送到员工(同一窗口)
8.2 紧急度评分公式
8.3 会话排序规则
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 关键对接参数
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 生成)
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 一键部署
13.2 日常运维
13.3 应急响应
详见 docs/SOPs/SOP-004-应急响应.md
14. 安全设计
14.1 已修复 P0(2026-06-14~15)
- WS token 泄露 — token 改走
Sec-WebSocket-Protocol subprotocol(非 URL/header)
- 坐席登录缺密码 —
agents.py L222-232 加 bcrypt 验证(3 测试覆盖)
- nginx access_log 记录 WS token —
/ws/ 路径 access_log off
- 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 项遗留(详见评审报告)
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)
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)
端到端验证 #149(等待中)
HTTPS 配置(SSL 证书) ✅ 已完成(2026-06-15)
- 修 006 filename 与 revision 不一致(v0.5.1)— 任务 #41
alembic chain 修复(007 typo) ✅ 已完成
浏览器验证 4 域名 ✅ 已完成
19.2 近期安排(P1)
- 创建测试企微应用(双企微方案)
- 阶段二启动:排队机制 + 满意度评价
- aTrust 对接:找信息安全团队
- 北森 eHR 对接:找 HR 数字化团队
- 集成验证:4 外部系统端到端
19.3 技术债务(P2)
- Redis 密码加固
- PostgreSQL 强密码
- CORS 配置收紧
- CSP 策略实施(已部分实施)
- 应急降级页(BC/DR)代码
- 演练 SOP-005
19.4 风险登记
| 风险 |
级别 |
缓解 |
| 企微凭据集中化 |
中 |
NAS Vault(待做) |
| 5 外部系统任一不可用 |
中 |
ExternalSystemAdapter 自动降级 |
| 现有系统密码明文 |
高 |
bcrypt 迁移已完成 |
| Dify DB 只读 |
中 |
新系统自建库,只从 Dify 同步 |
| 5 CVE(依赖漏洞) |
中 |
dependabot 自动更新 |
| WB 上下文冲突 |
高 |
已退出,Claude 接管 |
20. 关键文件路径速查
20.1 后端核心
20.2 前端核心
20.3 部署核心
20.4 配置/规范
21. 关联 memory 索引(已沉淀)
22. 后续行动(Claude 接管后)
22.1 立即
22.2 短期(1 周)
22.3 中期(1 月)
22.4 长期
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 发布前