Initial commit: 浼佷笟寰俊 AI 鏈哄櫒浜哄姪鐞?MVP
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
151
docs/cloudflared-quickstart.md
Normal file
151
docs/cloudflared-quickstart.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# Cloudflare Tunnel 快速开始指南
|
||||
|
||||
## 一键安装(Windows)
|
||||
|
||||
### 方法 1:使用 MSI 安装包(最简单)
|
||||
|
||||
1. **下载安装包**:
|
||||
- 直接下载:https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-windows-amd64.msi
|
||||
- 或访问:https://github.com/cloudflare/cloudflared/releases 选择最新版本的 MSI 文件
|
||||
|
||||
2. **安装**:
|
||||
- 双击 `cloudflared-windows-amd64.msi`
|
||||
- 按照安装向导完成安装
|
||||
- 安装完成后会自动添加到系统 PATH
|
||||
|
||||
3. **验证安装**:
|
||||
```powershell
|
||||
cloudflared --version
|
||||
```
|
||||
|
||||
### 方法 2:使用 Scoop(推荐开发者)
|
||||
|
||||
```powershell
|
||||
# 安装 Scoop(如果还没有)
|
||||
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
|
||||
irm get.scoop.sh | iex
|
||||
|
||||
# 安装 cloudflared
|
||||
scoop install cloudflared
|
||||
|
||||
# 验证
|
||||
cloudflared --version
|
||||
```
|
||||
|
||||
### 方法 3:直接下载 EXE(无需安装)
|
||||
|
||||
1. **下载**:https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-windows-amd64.exe
|
||||
2. **重命名**:将文件重命名为 `cloudflared.exe`
|
||||
3. **使用**:在项目目录中直接运行 `.\cloudflared.exe tunnel --url http://localhost:8000`
|
||||
|
||||
---
|
||||
|
||||
## 快速启动 Tunnel
|
||||
|
||||
### 步骤 1:确保后端服务运行
|
||||
|
||||
```powershell
|
||||
# 检查服务状态
|
||||
docker compose ps
|
||||
|
||||
# 如果未运行,启动服务
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### 步骤 2:启动 Cloudflare Tunnel
|
||||
|
||||
```powershell
|
||||
# 在项目根目录运行
|
||||
cloudflared tunnel --url http://localhost:8000
|
||||
```
|
||||
|
||||
**输出示例**:
|
||||
```
|
||||
2025-02-05T10:00:00Z INF +--------------------------------------------------------------------------------------------+
|
||||
2025-02-05T10:00:00Z INF | Your quick Tunnel has been created! Visit it at: |
|
||||
2025-02-05T10:00:00Z INF | https://abc123-def456-ghi789.trycloudflare.com |
|
||||
2025-02-05T10:00:00Z INF +--------------------------------------------------------------------------------------------+
|
||||
```
|
||||
|
||||
### 步骤 3:复制公网 URL
|
||||
|
||||
从输出中复制 `https://xxx.trycloudflare.com`,例如:
|
||||
```
|
||||
https://abc123-def456-ghi789.trycloudflare.com
|
||||
```
|
||||
|
||||
### 步骤 4:配置企业微信回调
|
||||
|
||||
1. 登录企业微信管理后台:https://work.weixin.qq.com
|
||||
2. 进入:应用管理 → 自建应用 → 你的应用 → 接收消息 → 设置 API 接收
|
||||
3. 填写回调 URL:`https://abc123-def456-ghi789.trycloudflare.com/api/wecom/callback`
|
||||
4. 填写 Token 和 EncodingAESKey(与 `.env` 文件一致)
|
||||
5. 点击保存
|
||||
|
||||
### 步骤 5:验证配置
|
||||
|
||||
```powershell
|
||||
# 在另一个终端查看后端日志
|
||||
docker compose logs backend -f
|
||||
```
|
||||
|
||||
应该看到:
|
||||
```
|
||||
INFO: wecom verify success {"trace_id": "...", "echostr_length": 43}
|
||||
```
|
||||
|
||||
企微后台应显示 **保存成功** ✅
|
||||
|
||||
---
|
||||
|
||||
## 测试消息回调
|
||||
|
||||
1. **在企业微信中发送消息**:`你好,测试一下`
|
||||
2. **查看后端日志**:
|
||||
```powershell
|
||||
docker compose logs backend -f
|
||||
```
|
||||
应该看到:
|
||||
- `wecom message received`(收到消息)
|
||||
- `wecom reply sent`(发送回复)
|
||||
3. **在企业微信中验证**:应收到回复 `已收到:你好,测试一下`
|
||||
|
||||
---
|
||||
|
||||
## 重要提示
|
||||
|
||||
1. **保持 cloudflared 运行**:不要关闭运行 cloudflared 的终端窗口
|
||||
2. **URL 有效期**:本次运行期间 URL 固定,关闭 cloudflared 后 URL 失效
|
||||
3. **如需固定域名**:登录 Cloudflare 创建命名 tunnel(参见 `docs/cloudflared-setup.md`)
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q: cloudflared 命令找不到?
|
||||
|
||||
**A**:
|
||||
- 如果使用 MSI 安装,重启终端或重新打开 PowerShell
|
||||
- 如果手动下载,确保文件在 PATH 中或使用完整路径
|
||||
|
||||
### Q: 连接失败?
|
||||
|
||||
**A**:
|
||||
- 检查本地服务是否运行:`docker compose ps`
|
||||
- 检查端口是否正确:`netstat -an | findstr 8000`
|
||||
- 检查防火墙设置
|
||||
|
||||
### Q: 企微回调失败?
|
||||
|
||||
**A**:
|
||||
- 确保 cloudflared URL 可访问:在浏览器打开 `https://你的域名.trycloudflare.com/api/health`
|
||||
- 检查 Token 和 EncodingAESKey 是否与 `.env` 一致
|
||||
- 查看后端日志:`docker compose logs backend | grep wecom`
|
||||
|
||||
---
|
||||
|
||||
## 更多信息
|
||||
|
||||
- **详细设置指南**:`docs/cloudflared-setup.md`
|
||||
- **完整测试流程**:`docs/wecom-test-guide.md`
|
||||
- **官方文档**:https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/
|
||||
312
docs/cloudflared-setup.md
Normal file
312
docs/cloudflared-setup.md
Normal file
@@ -0,0 +1,312 @@
|
||||
# 使用 Cloudflare Tunnel 设置公网域名
|
||||
|
||||
Cloudflare Tunnel (cloudflared) 是 Cloudflare 提供的免费内网穿透服务,相比 ngrok 的优势:
|
||||
- ✅ 提供固定的免费域名(不会每次重启都变化)
|
||||
- ✅ 免费且稳定
|
||||
- ✅ 支持 HTTPS(自动配置 SSL 证书)
|
||||
|
||||
---
|
||||
|
||||
## 一、安装 cloudflared
|
||||
|
||||
### Windows 安装方法
|
||||
|
||||
#### 方法 1:使用 Scoop(推荐)
|
||||
|
||||
```powershell
|
||||
# 安装 Scoop(如果还没有)
|
||||
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
|
||||
irm get.scoop.sh | iex
|
||||
|
||||
# 安装 cloudflared
|
||||
scoop install cloudflared
|
||||
```
|
||||
|
||||
#### 方法 2:使用 Chocolatey
|
||||
|
||||
```powershell
|
||||
# 安装 Chocolatey(如果还没有)
|
||||
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
|
||||
|
||||
# 安装 cloudflared
|
||||
choco install cloudflared
|
||||
```
|
||||
|
||||
#### 方法 3:手动下载(推荐用于快速测试)
|
||||
|
||||
1. **访问发布页面**:https://github.com/cloudflare/cloudflared/releases
|
||||
2. **下载最新版本**:
|
||||
- 找到最新的发布版本(例如:`2026.1.2`)
|
||||
- 下载 Windows 64位版本:`cloudflared-windows-amd64.exe`
|
||||
- 或下载 MSI 安装包:`cloudflared-windows-amd64.msi`(自动安装到系统)
|
||||
3. **使用方式**:
|
||||
- **方式 A(直接使用)**:将 `cloudflared-windows-amd64.exe` 重命名为 `cloudflared.exe`,放到项目目录或任意目录
|
||||
- **方式 B(添加到 PATH)**:将文件放到 PATH 环境变量中的目录(如 `C:\Windows\System32`),这样可以在任何地方使用 `cloudflared` 命令
|
||||
- **方式 C(MSI 安装)**:双击 `cloudflared-windows-amd64.msi` 安装,会自动添加到系统 PATH
|
||||
|
||||
**最新版本下载链接**(直接下载):
|
||||
- Windows 64位 EXE:https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-windows-amd64.exe
|
||||
- Windows 64位 MSI:https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-windows-amd64.msi
|
||||
|
||||
---
|
||||
|
||||
## 二、快速启动(无需登录,临时使用)
|
||||
|
||||
### 2.1 启动 Tunnel
|
||||
|
||||
```powershell
|
||||
# 在项目根目录运行
|
||||
cloudflared tunnel --url http://localhost:8000
|
||||
```
|
||||
|
||||
**输出示例**:
|
||||
```
|
||||
2025-02-05T10:00:00Z INF +--------------------------------------------------------------------------------------------+
|
||||
2025-02-05T10:00:00Z INF | Your quick Tunnel has been created! Visit it at: |
|
||||
2025-02-05T10:00:00Z INF | https://abc123-def456-ghi789.trycloudflare.com |
|
||||
2025-02-05T10:00:00Z INF +--------------------------------------------------------------------------------------------+
|
||||
```
|
||||
|
||||
### 2.2 复制公网 URL
|
||||
|
||||
从输出中复制 `https://xxx.trycloudflare.com`,这就是你的公网域名。
|
||||
|
||||
**注意**:
|
||||
- 这个 URL 在本次运行期间是固定的
|
||||
- 关闭 cloudflared 后,URL 会失效
|
||||
- 每次重新启动会生成新的 URL
|
||||
|
||||
### 2.3 配置企业微信回调
|
||||
|
||||
在企微后台配置回调 URL:
|
||||
```
|
||||
https://你的cloudflared域名.trycloudflare.com/api/wecom/callback
|
||||
```
|
||||
|
||||
例如:`https://abc123-def456-ghi789.trycloudflare.com/api/wecom/callback`
|
||||
|
||||
---
|
||||
|
||||
## 三、使用固定域名(推荐,需要 Cloudflare 账号)
|
||||
|
||||
### 3.1 登录 Cloudflare
|
||||
|
||||
```powershell
|
||||
cloudflared tunnel login
|
||||
```
|
||||
|
||||
这会打开浏览器,选择你的域名(如果没有域名,可以跳过,使用免费域名)。
|
||||
|
||||
### 3.2 创建命名 Tunnel
|
||||
|
||||
```powershell
|
||||
# 创建名为 wecom-callback 的 tunnel
|
||||
cloudflared tunnel create wecom-callback
|
||||
```
|
||||
|
||||
### 3.3 配置 Tunnel
|
||||
|
||||
创建配置文件 `~/.cloudflared/config.yml`(Windows 路径:`C:\Users\你的用户名\.cloudflared\config.yml`):
|
||||
|
||||
```yaml
|
||||
tunnel: wecom-callback
|
||||
credentials-file: C:\Users\你的用户名\.cloudflared\<tunnel-id>.json
|
||||
|
||||
ingress:
|
||||
- hostname: wecom-callback.your-domain.com # 你的域名(如果有)
|
||||
service: http://localhost:8000
|
||||
- service: http_status:404
|
||||
```
|
||||
|
||||
**如果没有域名,使用免费域名**:
|
||||
|
||||
```yaml
|
||||
tunnel: wecom-callback
|
||||
credentials-file: C:\Users\你的用户名\.cloudflared\<tunnel-id>.json
|
||||
|
||||
ingress:
|
||||
- service: http://localhost:8000
|
||||
```
|
||||
|
||||
### 3.4 启动 Tunnel
|
||||
|
||||
```powershell
|
||||
cloudflared tunnel run wecom-callback
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、后台运行(Windows)
|
||||
|
||||
### 方法 1:使用 PowerShell 后台任务
|
||||
|
||||
```powershell
|
||||
# 启动后台任务
|
||||
Start-Process -NoNewWindow cloudflared -ArgumentList "tunnel --url http://localhost:8000"
|
||||
|
||||
# 查看进程
|
||||
Get-Process cloudflared
|
||||
|
||||
# 停止进程
|
||||
Stop-Process -Name cloudflared
|
||||
```
|
||||
|
||||
### 方法 2:创建 Windows 服务(固定域名方式)
|
||||
|
||||
```powershell
|
||||
# 安装为 Windows 服务
|
||||
cloudflared service install
|
||||
|
||||
# 启动服务
|
||||
net start cloudflared
|
||||
|
||||
# 停止服务
|
||||
net stop cloudflared
|
||||
|
||||
# 卸载服务
|
||||
cloudflared service uninstall
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、验证 Tunnel 是否工作
|
||||
|
||||
### 5.1 测试本地端点
|
||||
|
||||
```powershell
|
||||
# 测试本地服务
|
||||
curl http://localhost:8000/api/health
|
||||
|
||||
# 应该返回:{"status":"up","service":"backend"}
|
||||
```
|
||||
|
||||
### 5.2 测试公网端点
|
||||
|
||||
```powershell
|
||||
# 测试公网 URL(替换为你的 cloudflared URL)
|
||||
curl https://你的域名.trycloudflare.com/api/health
|
||||
|
||||
# 应该返回:{"status":"up","service":"backend"}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、完整测试流程
|
||||
|
||||
### 6.1 启动服务
|
||||
|
||||
```powershell
|
||||
# 终端 1:启动 Docker 服务
|
||||
docker compose up -d
|
||||
|
||||
# 终端 2:启动 cloudflared
|
||||
cloudflared tunnel --url http://localhost:8000
|
||||
```
|
||||
|
||||
### 6.2 配置企微回调
|
||||
|
||||
1. 复制 cloudflared 提供的 URL(例如:`https://abc123-def456-ghi789.trycloudflare.com`)
|
||||
2. 在企微后台配置回调 URL:`https://abc123-def456-ghi789.trycloudflare.com/api/wecom/callback`
|
||||
3. 填写 Token 和 EncodingAESKey(与 `.env` 一致)
|
||||
4. 点击保存
|
||||
|
||||
### 6.3 验证 GET 校验
|
||||
|
||||
```powershell
|
||||
# 查看后端日志
|
||||
docker compose logs backend -f
|
||||
|
||||
# 应该看到:
|
||||
# INFO: wecom verify success {"trace_id": "...", "echostr_length": 43}
|
||||
```
|
||||
|
||||
### 6.4 测试消息回调
|
||||
|
||||
1. 在企业微信中发送消息
|
||||
2. 查看后端日志确认收到消息和发送回复
|
||||
3. 在企业微信中验证收到回复
|
||||
|
||||
---
|
||||
|
||||
## 七、常见问题
|
||||
|
||||
### 问题 1:cloudflared 连接失败
|
||||
|
||||
**解决方案**:
|
||||
- 检查本地服务是否运行:`docker compose ps`
|
||||
- 检查端口是否正确:`netstat -an | findstr 8000`
|
||||
- 检查防火墙是否阻止了 cloudflared
|
||||
|
||||
### 问题 2:企微回调失败
|
||||
|
||||
**解决方案**:
|
||||
- 确保 cloudflared URL 可访问:在浏览器中打开 `https://你的域名.trycloudflare.com/api/health`
|
||||
- 检查 Token 和 EncodingAESKey 是否一致
|
||||
- 查看后端日志:`docker compose logs backend | grep wecom`
|
||||
|
||||
### 问题 3:cloudflared 进程意外退出
|
||||
|
||||
**解决方案**:
|
||||
- 使用后台运行方式(见上方)
|
||||
- 或使用 Windows 服务方式
|
||||
- 检查 cloudflared 日志
|
||||
|
||||
---
|
||||
|
||||
## 八、与 ngrok 对比
|
||||
|
||||
| 特性 | cloudflared | ngrok |
|
||||
|------|-------------|-------|
|
||||
| 免费域名 | ✅ 固定(登录后) | ❌ 每次变化(免费版) |
|
||||
| 安装 | 简单 | 简单 |
|
||||
| 稳定性 | 高 | 中等 |
|
||||
| 速度 | 快 | 中等 |
|
||||
| 推荐 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
|
||||
|
||||
---
|
||||
|
||||
## 九、快速命令参考
|
||||
|
||||
```powershell
|
||||
# 启动临时 tunnel
|
||||
cloudflared tunnel --url http://localhost:8000
|
||||
|
||||
# 登录 Cloudflare
|
||||
cloudflared tunnel login
|
||||
|
||||
# 创建命名 tunnel
|
||||
cloudflared tunnel create wecom-callback
|
||||
|
||||
# 运行命名 tunnel
|
||||
cloudflared tunnel run wecom-callback
|
||||
|
||||
# 列出所有 tunnel
|
||||
cloudflared tunnel list
|
||||
|
||||
# 删除 tunnel
|
||||
cloudflared tunnel delete wecom-callback
|
||||
|
||||
# 查看 tunnel 信息
|
||||
cloudflared tunnel info wecom-callback
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十、推荐配置(生产环境)
|
||||
|
||||
对于生产环境,建议:
|
||||
|
||||
1. **使用固定域名**:登录 Cloudflare,创建命名 tunnel
|
||||
2. **配置为 Windows 服务**:确保自动启动
|
||||
3. **监控 tunnel 状态**:设置日志和告警
|
||||
|
||||
```powershell
|
||||
# 创建配置文件后,安装为服务
|
||||
cloudflared service install
|
||||
|
||||
# 启动服务
|
||||
net start cloudflared
|
||||
|
||||
# 查看服务状态
|
||||
sc query cloudflared
|
||||
```
|
||||
415
docs/deploy-cloud-minimal.md
Normal file
415
docs/deploy-cloud-minimal.md
Normal file
@@ -0,0 +1,415 @@
|
||||
# 云端最小回调壳部署方案
|
||||
|
||||
## 一、目标
|
||||
|
||||
**阶段目标**:在备案域名上部署最小可用回调壳,使企业微信能完成 URL 校验与回调联调。
|
||||
|
||||
**最小功能范围**:
|
||||
- ✅ `/api/wecom/callback` GET 校验(兼容 `signature`/`msg_signature`)
|
||||
- ✅ `/api/wecom/callback` POST 密文消息回调(验签、解密、echo 回复)
|
||||
- ✅ 结构化日志 + trace_id
|
||||
- ✅ Nginx 反代 + HTTPS(Let's Encrypt)
|
||||
- ⏸️ 数据库(可先不启用,但接口与配置要预留)
|
||||
- ⏸️ Admin 后台(可先占位)
|
||||
|
||||
---
|
||||
|
||||
## 二、架构
|
||||
|
||||
```
|
||||
企业微信 → HTTPS (443) → Nginx → Backend (8000)
|
||||
↓
|
||||
PostgreSQL (可选)
|
||||
```
|
||||
|
||||
**服务清单**:
|
||||
- `backend`: Python 3.12 + FastAPI + Uvicorn(最小回调壳)
|
||||
- `nginx`: 反代 + HTTPS(Let's Encrypt)
|
||||
- `db`: PostgreSQL 16(可选,先不启用)
|
||||
|
||||
---
|
||||
|
||||
## 三、环境变量配置
|
||||
|
||||
### 3.1 必需变量(`.env`)
|
||||
|
||||
```bash
|
||||
# ============ Backend ============
|
||||
API_HOST=0.0.0.0
|
||||
API_PORT=8000
|
||||
|
||||
# Database(可选,先不启用)
|
||||
DATABASE_URL=postgresql+asyncpg://wecom:wecom_secret@db:5432/wecom_ai
|
||||
DATABASE_URL_SYNC=postgresql://wecom:wecom_secret@db:5432/wecom_ai
|
||||
|
||||
# JWT(admin 登录,可选)
|
||||
JWT_SECRET=your-jwt-secret-change-in-production
|
||||
JWT_ALGORITHM=HS256
|
||||
JWT_EXPIRE_MINUTES=60
|
||||
|
||||
# WeCom Callback(必须,从企业微信管理后台获取)
|
||||
WECOM_CORP_ID=你的企业ID
|
||||
WECOM_AGENT_ID=你的应用AgentId
|
||||
WECOM_SECRET=你的应用Secret(可选,用于主动发送消息)
|
||||
WECOM_TOKEN=你的Token(必须与企微后台一致)
|
||||
WECOM_ENCODING_AES_KEY=你的43位密钥(必须与企微后台一致)
|
||||
|
||||
# WeCom API
|
||||
WECOM_API_BASE=https://qyapi.weixin.qq.com
|
||||
WECOM_API_TIMEOUT=10
|
||||
WECOM_API_RETRIES=2
|
||||
|
||||
# Log
|
||||
LOG_LEVEL=INFO
|
||||
LOG_JSON=true
|
||||
|
||||
# ============ Nginx ============
|
||||
# 域名(必须,备案域名)
|
||||
DOMAIN=your-domain.com
|
||||
|
||||
# SSL(Let's Encrypt)
|
||||
SSL_EMAIL=your-email@example.com
|
||||
```
|
||||
|
||||
### 3.2 关键变量说明
|
||||
|
||||
| 变量 | 说明 | 来源 |
|
||||
|------|------|------|
|
||||
| `WECOM_TOKEN` | 企业微信回调 Token | 企微后台 → 应用 → 接收消息 → Token |
|
||||
| `WECOM_ENCODING_AES_KEY` | 43 位 Base64 编码密钥 | 企微后台 → 应用 → 接收消息 → EncodingAESKey |
|
||||
| `WECOM_CORP_ID` | 企业 ID | 企微后台 → 我的企业 → 企业信息 |
|
||||
| `WECOM_AGENT_ID` | 应用 AgentId | 企微后台 → 应用管理 → 自建应用 → 应用详情 |
|
||||
| `DOMAIN` | 备案域名 | 你的域名服务商 |
|
||||
|
||||
---
|
||||
|
||||
## 四、部署步骤
|
||||
|
||||
### 4.1 前置条件
|
||||
|
||||
1. **备案域名**:已备案且主体关联的域名(例如:`api.yourdomain.com`)
|
||||
2. **服务器**:Linux(Ubuntu 20.04+ / CentOS 7+),公网 IP,开放 80/443 端口
|
||||
3. **Docker**:已安装 Docker 和 docker-compose
|
||||
4. **GitHub**:代码已推送到 GitHub(用于 CI/CD)
|
||||
|
||||
### 4.2 服务器初始化
|
||||
|
||||
```bash
|
||||
# 1. 安装 Docker 和 docker-compose
|
||||
curl -fsSL https://get.docker.com | sh
|
||||
sudo usermod -aG docker $USER
|
||||
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
sudo chmod +x /usr/local/bin/docker-compose
|
||||
|
||||
# 2. 克隆项目(或通过 CI/CD 部署)
|
||||
git clone https://github.com/your-org/wecom-ai-assistant.git
|
||||
cd wecom-ai-assistant
|
||||
|
||||
# 3. 创建 .env 文件
|
||||
cp .env.example .env
|
||||
# 编辑 .env,填入上述必需变量
|
||||
```
|
||||
|
||||
### 4.3 配置 Nginx + HTTPS
|
||||
|
||||
#### 方案 A:使用 Certbot(Let's Encrypt)
|
||||
|
||||
```bash
|
||||
# 1. 安装 Certbot
|
||||
sudo apt-get update
|
||||
sudo apt-get install certbot python3-certbot-nginx
|
||||
|
||||
# 2. 先启动 HTTP 服务(用于验证)
|
||||
docker-compose up -d backend
|
||||
|
||||
# 3. 配置 Nginx(临时 HTTP 配置)
|
||||
# 编辑 deploy/nginx.conf,添加 server_name
|
||||
# 然后运行:docker-compose up -d nginx
|
||||
|
||||
# 4. 获取 SSL 证书
|
||||
sudo certbot --nginx -d your-domain.com -d www.your-domain.com --email your-email@example.com --agree-tos --non-interactive
|
||||
|
||||
# 5. 更新 nginx.conf,使用 Certbot 生成的配置
|
||||
# Certbot 会自动修改 /etc/nginx/sites-available/default
|
||||
# 将配置复制到 deploy/nginx.conf,或使用 volume 挂载
|
||||
```
|
||||
|
||||
#### 方案 B:手动配置 Nginx + Let's Encrypt
|
||||
|
||||
创建 `deploy/nginx-ssl.conf`:
|
||||
|
||||
```nginx
|
||||
events { worker_connections 1024; }
|
||||
|
||||
http {
|
||||
upstream backend {
|
||||
server backend:8000;
|
||||
}
|
||||
|
||||
# HTTP → HTTPS 重定向
|
||||
server {
|
||||
listen 80;
|
||||
server_name your-domain.com www.your-domain.com;
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
# HTTPS
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name your-domain.com www.your-domain.com;
|
||||
|
||||
# SSL 证书(Let's Encrypt)
|
||||
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
|
||||
# /api -> backend
|
||||
location /api/ {
|
||||
proxy_pass http://backend;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_read_timeout 30s;
|
||||
}
|
||||
|
||||
# 健康检查
|
||||
location /health {
|
||||
proxy_pass http://backend/health;
|
||||
access_log off;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
更新 `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./deploy/nginx-ssl.conf:/etc/nginx/nginx.conf:ro
|
||||
- /etc/letsencrypt:/etc/letsencrypt:ro # SSL 证书
|
||||
depends_on:
|
||||
- backend
|
||||
```
|
||||
|
||||
### 4.4 启动服务
|
||||
|
||||
```bash
|
||||
# 1. 构建镜像
|
||||
docker-compose build backend
|
||||
|
||||
# 2. 启动服务(最小回调壳:只启动 backend + nginx)
|
||||
docker-compose up -d backend nginx
|
||||
|
||||
# 3. 检查日志
|
||||
docker-compose logs -f backend
|
||||
```
|
||||
|
||||
### 4.5 验证服务
|
||||
|
||||
```bash
|
||||
# 1. 检查服务状态
|
||||
docker-compose ps
|
||||
|
||||
# 2. 检查健康检查
|
||||
curl https://your-domain.com/health
|
||||
|
||||
# 3. 检查回调接口(应返回 400,因为缺少参数)
|
||||
curl https://your-domain.com/api/wecom/callback
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、本地验证
|
||||
|
||||
### 5.1 本地启动最小回调壳
|
||||
|
||||
```bash
|
||||
# 1. 启动后端(不启动 db/admin)
|
||||
docker-compose up -d backend
|
||||
|
||||
# 2. 检查日志
|
||||
docker-compose logs backend
|
||||
|
||||
# 3. 测试 GET 校验(模拟企业微信)
|
||||
# 注意:需要正确的 signature/timestamp/nonce/echostr
|
||||
curl "http://localhost:8000/api/wecom/callback?signature=xxx×tamp=123&nonce=abc&echostr=xxx"
|
||||
```
|
||||
|
||||
### 5.2 本地测试 POST 回调
|
||||
|
||||
```bash
|
||||
# 使用企业微信官方测试工具生成测试请求
|
||||
# 或使用 curl 模拟(需要正确的签名和加密)
|
||||
curl -X POST "http://localhost:8000/api/wecom/callback?msg_signature=xxx×tamp=123&nonce=abc" \
|
||||
-H "Content-Type: application/xml" \
|
||||
-d '<xml><Encrypt><![CDATA[加密内容]]></Encrypt></xml>'
|
||||
```
|
||||
|
||||
### 5.3 验证日志格式
|
||||
|
||||
检查日志输出是否符合结构化日志格式:
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "2025-02-05T10:00:00Z",
|
||||
"level": "INFO",
|
||||
"message": "wecom verify success",
|
||||
"trace_id": "abc123",
|
||||
"echostr_length": 43
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、线上验证
|
||||
|
||||
### 6.1 企业微信后台配置
|
||||
|
||||
1. **登录企业微信管理后台**:https://work.weixin.qq.com
|
||||
2. **进入应用设置**:应用管理 → 自建应用 → 选择你的应用
|
||||
3. **配置回调 URL**:
|
||||
- 接收消息服务器 URL:`https://your-domain.com/api/wecom/callback`
|
||||
- Token:与 `.env` 中的 `WECOM_TOKEN` **完全一致**
|
||||
- EncodingAESKey:与 `.env` 中的 `WECOM_ENCODING_AES_KEY` **完全一致**
|
||||
- 消息加解密方式:**安全模式**
|
||||
4. **点击保存**
|
||||
|
||||
### 6.2 验证 GET 校验
|
||||
|
||||
保存后,企业微信会立即发送 GET 请求验证。观察后端日志:
|
||||
|
||||
```bash
|
||||
docker-compose logs -f backend
|
||||
```
|
||||
|
||||
**成功日志**:
|
||||
```
|
||||
INFO: wecom verify success {"trace_id": "...", "echostr_length": 43}
|
||||
```
|
||||
|
||||
**失败日志**:
|
||||
```
|
||||
WARNING: wecom verify failed {"trace_id": "...", "timestamp": "...", "nonce": "..."}
|
||||
```
|
||||
|
||||
如果验证失败,检查:
|
||||
- Token 是否一致
|
||||
- EncodingAESKey 是否一致
|
||||
- 域名是否可访问(`curl https://your-domain.com/api/wecom/callback`)
|
||||
|
||||
### 6.3 验证 POST 回调
|
||||
|
||||
1. **在企业微信中发送测试消息**:
|
||||
- 打开企业微信客户端
|
||||
- 找到你配置的应用
|
||||
- 发送文本消息:`你好,测试一下`
|
||||
|
||||
2. **观察后端日志**:
|
||||
```bash
|
||||
docker-compose logs -f backend
|
||||
```
|
||||
|
||||
**成功日志**:
|
||||
```json
|
||||
{
|
||||
"timestamp": "2025-02-05T10:00:00Z",
|
||||
"level": "INFO",
|
||||
"message": "wecom message received",
|
||||
"trace_id": "abc123",
|
||||
"external_userid": "external_userid_xxx",
|
||||
"msgid": "123456",
|
||||
"msg_type": "text",
|
||||
"content_summary": "你好,测试一下"
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "2025-02-05T10:00:01Z",
|
||||
"level": "INFO",
|
||||
"message": "wecom reply sent",
|
||||
"trace_id": "abc123",
|
||||
"external_userid": "external_userid_xxx",
|
||||
"msgid": "123456",
|
||||
"reply_summary": "已收到:你好,测试一下"
|
||||
}
|
||||
```
|
||||
|
||||
3. **检查企业微信客户端**:应收到回复:`已收到:你好,测试一下`
|
||||
|
||||
---
|
||||
|
||||
## 七、常见问题
|
||||
|
||||
### 7.1 GET 校验失败
|
||||
|
||||
**原因**:
|
||||
- Token 不一致
|
||||
- EncodingAESKey 不一致
|
||||
- 签名算法错误
|
||||
|
||||
**解决**:
|
||||
1. 检查 `.env` 中的 `WECOM_TOKEN` 和 `WECOM_ENCODING_AES_KEY`
|
||||
2. 确保与企微后台配置**完全一致**(包括大小写、空格)
|
||||
3. 重启后端:`docker-compose restart backend`
|
||||
|
||||
### 7.2 POST 回调失败
|
||||
|
||||
**原因**:
|
||||
- 签名验证失败
|
||||
- 解密失败
|
||||
- XML 解析失败
|
||||
|
||||
**解决**:
|
||||
1. 检查日志中的错误信息
|
||||
2. 确认 EncodingAESKey 正确
|
||||
3. 确认消息加解密方式为**安全模式**
|
||||
|
||||
### 7.3 HTTPS 证书问题
|
||||
|
||||
**原因**:
|
||||
- Let's Encrypt 证书未正确配置
|
||||
- 证书过期
|
||||
|
||||
**解决**:
|
||||
1. 检查证书:`sudo certbot certificates`
|
||||
2. 续期证书:`sudo certbot renew`
|
||||
3. 重启 Nginx:`docker-compose restart nginx`
|
||||
|
||||
### 7.4 域名无法访问
|
||||
|
||||
**原因**:
|
||||
- DNS 未解析
|
||||
- 防火墙未开放 80/443 端口
|
||||
- Nginx 配置错误
|
||||
|
||||
**解决**:
|
||||
1. 检查 DNS:`nslookup your-domain.com`
|
||||
2. 检查端口:`netstat -tlnp | grep -E '80|443'`
|
||||
3. 检查 Nginx 日志:`docker-compose logs nginx`
|
||||
|
||||
---
|
||||
|
||||
## 八、下一步
|
||||
|
||||
完成最小回调壳部署后,按以下顺序逐步接入:
|
||||
|
||||
1. ✅ **最小回调壳**(当前阶段)
|
||||
2. ⏭️ **数据库接入**(会话与消息入库)
|
||||
3. ⏭️ **Admin 后台**(会话列表、工单、知识库)
|
||||
4. ⏭️ **FAQ/RAG**(智能回复)
|
||||
|
||||
---
|
||||
|
||||
## 九、参考文档
|
||||
|
||||
- [企业微信回调配置](./wecom.md)
|
||||
- [企业微信测试指南](./wecom-test-guide.md)
|
||||
- [GitHub Actions CI/CD](../deploy/ci/github-actions.yml)
|
||||
106
docs/deploy-quick-reference.md
Normal file
106
docs/deploy-quick-reference.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# 生产部署快速参考
|
||||
|
||||
## 一、首次部署(5 分钟)
|
||||
|
||||
```bash
|
||||
# 1. 克隆项目
|
||||
git clone https://github.com/your-org/wecom-ai-assistant.git
|
||||
cd wecom-ai-assistant
|
||||
|
||||
# 2. 配置环境变量
|
||||
cp .env.prod.example .env.prod
|
||||
nano .env.prod # 填写必需变量
|
||||
|
||||
# 3. 启动服务
|
||||
chmod +x deploy/scripts/*.sh
|
||||
./deploy/scripts/start.sh
|
||||
|
||||
# 4. 配置 HTTPS(Let's Encrypt)
|
||||
export DOMAIN=your-domain.com
|
||||
export EMAIL=your-email@example.com
|
||||
sudo certbot certonly --nginx -d $DOMAIN --email $EMAIL --agree-tos --non-interactive
|
||||
|
||||
# 5. 更新 Nginx 配置(使用实际域名替换 nginx.conf 中的 _)
|
||||
# 然后重启: docker-compose -f docker-compose.prod.yml restart nginx
|
||||
```
|
||||
|
||||
## 二、常用命令
|
||||
|
||||
```bash
|
||||
# 启动服务
|
||||
./deploy/scripts/start.sh
|
||||
|
||||
# 停止服务
|
||||
./deploy/scripts/stop.sh
|
||||
|
||||
# 更新服务
|
||||
./deploy/scripts/update.sh latest
|
||||
|
||||
# 查看日志
|
||||
docker-compose -f docker-compose.prod.yml logs -f backend
|
||||
|
||||
# 查看服务状态
|
||||
docker-compose -f docker-compose.prod.yml ps
|
||||
|
||||
# 健康检查
|
||||
curl https://your-domain.com/api/health
|
||||
```
|
||||
|
||||
## 三、GitHub Actions 自动部署
|
||||
|
||||
### 配置 Secrets
|
||||
|
||||
在 GitHub 仓库设置中添加:
|
||||
- `PROD_HOST`: 服务器 IP
|
||||
- `PROD_USER`: SSH 用户名
|
||||
- `PROD_SSH_KEY`: SSH 私钥
|
||||
- `PROD_DOMAIN`: 生产域名
|
||||
- `PROD_APP_PATH`: 应用路径(可选)
|
||||
|
||||
### 部署流程
|
||||
|
||||
1. 推送代码到 `main` 分支
|
||||
2. GitHub Actions 自动构建并部署
|
||||
3. 查看部署日志:`https://github.com/your-org/wecom-ai-assistant/actions`
|
||||
|
||||
## 四、关键文件
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `.env.prod` | 生产环境变量(不提交到 Git) |
|
||||
| `docker-compose.prod.yml` | 生产环境 Docker Compose 配置 |
|
||||
| `deploy/docker/backend.Dockerfile` | Backend 生产镜像构建文件 |
|
||||
| `deploy/docker/nginx.conf` | Nginx 生产配置 |
|
||||
| `deploy/scripts/start.sh` | 启动脚本 |
|
||||
| `deploy/scripts/update.sh` | 更新脚本 |
|
||||
| `.github/workflows/deploy.yml` | GitHub Actions 部署 workflow |
|
||||
|
||||
## 五、故障排查
|
||||
|
||||
```bash
|
||||
# 查看服务日志
|
||||
docker-compose -f docker-compose.prod.yml logs backend
|
||||
|
||||
# 检查服务状态
|
||||
docker-compose -f docker-compose.prod.yml ps
|
||||
|
||||
# 检查环境变量
|
||||
docker-compose -f docker-compose.prod.yml config
|
||||
|
||||
# 检查 SSL 证书
|
||||
sudo certbot certificates
|
||||
|
||||
# 测试健康检查
|
||||
curl -v https://your-domain.com/api/health
|
||||
```
|
||||
|
||||
## 六、回滚
|
||||
|
||||
```bash
|
||||
# 回滚到指定版本
|
||||
export IMAGE_TAG=v0.9.0
|
||||
docker-compose -f docker-compose.prod.yml --env-file .env.prod pull
|
||||
docker-compose -f docker-compose.prod.yml --env-file .env.prod up -d
|
||||
```
|
||||
|
||||
**详细文档**:参见 `docs/deploy.md`
|
||||
130
docs/deploy-quickstart.md
Normal file
130
docs/deploy-quickstart.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# 云端最小回调壳快速部署指南
|
||||
|
||||
## 一、前置条件检查清单
|
||||
|
||||
- [ ] 备案域名(例如:`api.yourdomain.com`)
|
||||
- [ ] Linux 服务器(Ubuntu 20.04+ / CentOS 7+)
|
||||
- [ ] 公网 IP,开放 80/443 端口
|
||||
- [ ] Docker 和 docker-compose 已安装
|
||||
- [ ] 企业微信管理后台访问权限
|
||||
|
||||
## 二、5 分钟快速部署
|
||||
|
||||
### 步骤 1:克隆项目
|
||||
|
||||
```bash
|
||||
git clone https://github.com/your-org/wecom-ai-assistant.git
|
||||
cd wecom-ai-assistant
|
||||
```
|
||||
|
||||
### 步骤 2:配置环境变量
|
||||
|
||||
```bash
|
||||
# 复制模板
|
||||
cp .env.example .env
|
||||
|
||||
# 编辑 .env,填写以下必需变量:
|
||||
# - WECOM_TOKEN(从企微后台获取)
|
||||
# - WECOM_ENCODING_AES_KEY(从企微后台获取,43位)
|
||||
# - WECOM_CORP_ID(从企微后台获取)
|
||||
# - WECOM_AGENT_ID(从企微后台获取)
|
||||
```
|
||||
|
||||
### 步骤 3:部署最小回调壳
|
||||
|
||||
```bash
|
||||
# 方式 A:使用 docker-compose
|
||||
docker-compose -f docker-compose.minimal.yml up -d
|
||||
|
||||
# 方式 B:使用部署脚本
|
||||
chmod +x deploy/scripts/deploy-minimal.sh
|
||||
export DOMAIN=your-domain.com
|
||||
bash deploy/scripts/deploy-minimal.sh
|
||||
```
|
||||
|
||||
### 步骤 4:配置 HTTPS(Let's Encrypt)
|
||||
|
||||
```bash
|
||||
export DOMAIN=your-domain.com
|
||||
export SSL_EMAIL=your-email@example.com
|
||||
chmod +x deploy/scripts/setup-ssl.sh
|
||||
bash deploy/scripts/setup-ssl.sh
|
||||
```
|
||||
|
||||
### 步骤 5:配置企业微信回调
|
||||
|
||||
1. 登录企业微信管理后台:https://work.weixin.qq.com
|
||||
2. 进入:应用管理 → 自建应用 → 选择你的应用
|
||||
3. 配置回调:
|
||||
- **接收消息服务器 URL**:`https://your-domain.com/api/wecom/callback`
|
||||
- **Token**:与 `.env` 中的 `WECOM_TOKEN` **完全一致**
|
||||
- **EncodingAESKey**:与 `.env` 中的 `WECOM_ENCODING_AES_KEY` **完全一致**
|
||||
- **消息加解密方式**:**安全模式**
|
||||
4. 点击 **保存**
|
||||
|
||||
### 步骤 6:验证
|
||||
|
||||
```bash
|
||||
# 查看日志
|
||||
docker-compose logs -f backend
|
||||
|
||||
# 应该看到:
|
||||
# INFO: wecom verify success {"trace_id": "...", "echostr_length": 43}
|
||||
```
|
||||
|
||||
## 三、关键环境变量
|
||||
|
||||
| 变量 | 说明 | 来源 |
|
||||
|------|------|------|
|
||||
| `WECOM_TOKEN` | 企业微信回调 Token | 企微后台 → 应用 → 接收消息 → Token |
|
||||
| `WECOM_ENCODING_AES_KEY` | 43 位 Base64 编码密钥 | 企微后台 → 应用 → 接收消息 → EncodingAESKey |
|
||||
| `WECOM_CORP_ID` | 企业 ID | 企微后台 → 我的企业 → 企业信息 |
|
||||
| `WECOM_AGENT_ID` | 应用 AgentId | 企微后台 → 应用管理 → 自建应用 → 应用详情 |
|
||||
|
||||
## 四、验证清单
|
||||
|
||||
- [ ] 服务启动:`docker-compose ps` 显示 backend 和 nginx 运行中
|
||||
- [ ] 健康检查:`curl http://localhost:8000/health` 返回 200
|
||||
- [ ] HTTPS 访问:`curl https://your-domain.com/api/health` 返回 200
|
||||
- [ ] 企业微信 GET 校验:保存回调配置后,日志显示 `wecom verify success`
|
||||
- [ ] 企业微信 POST 回调:发送测试消息后,日志显示 `wecom message received` 和 `wecom reply sent`
|
||||
|
||||
## 五、常见问题
|
||||
|
||||
### 5.1 GET 校验失败
|
||||
|
||||
**症状**:企微后台保存失败,日志显示 `wecom verify failed`
|
||||
|
||||
**解决**:
|
||||
1. 检查 `.env` 中的 `WECOM_TOKEN` 和 `WECOM_ENCODING_AES_KEY`
|
||||
2. 确保与企微后台配置**完全一致**(包括大小写、空格)
|
||||
3. 重启后端:`docker-compose restart backend`
|
||||
|
||||
### 5.2 HTTPS 证书问题
|
||||
|
||||
**症状**:浏览器显示"不安全连接"
|
||||
|
||||
**解决**:
|
||||
1. 检查证书:`sudo certbot certificates`
|
||||
2. 更新 Nginx 配置,使用正确的证书路径
|
||||
3. 重启 Nginx:`docker-compose restart nginx`
|
||||
|
||||
### 5.3 域名无法访问
|
||||
|
||||
**症状**:`curl https://your-domain.com/api/health` 超时
|
||||
|
||||
**解决**:
|
||||
1. 检查 DNS:`nslookup your-domain.com`
|
||||
2. 检查防火墙:`sudo ufw status`(Ubuntu)或 `sudo firewall-cmd --list-all`(CentOS)
|
||||
3. 检查端口:`netstat -tlnp | grep -E '80|443'`
|
||||
|
||||
## 六、下一步
|
||||
|
||||
完成最小回调壳部署后:
|
||||
|
||||
1. ✅ **最小回调壳**(当前阶段)
|
||||
2. ⏭️ **数据库接入**(会话与消息入库)
|
||||
3. ⏭️ **Admin 后台**(会话列表、工单、知识库)
|
||||
4. ⏭️ **FAQ/RAG**(智能回复)
|
||||
|
||||
**详细文档**:参见 `docs/deploy-cloud-minimal.md`
|
||||
655
docs/deploy.md
Normal file
655
docs/deploy.md
Normal file
@@ -0,0 +1,655 @@
|
||||
# 生产环境部署指南
|
||||
|
||||
## 一、概述
|
||||
|
||||
本文档描述如何在云端服务器上部署企业微信 AI 助手的最小回调壳,支持企业微信回调 URL 校验和消息回调。
|
||||
|
||||
**部署架构**:
|
||||
```
|
||||
企业微信 → HTTPS (443) → Nginx → Backend (8000)
|
||||
↓
|
||||
PostgreSQL (可选)
|
||||
```
|
||||
|
||||
**服务清单**:
|
||||
- `backend`: Python 3.12 + FastAPI + Uvicorn(最小回调壳)
|
||||
- `nginx`: 反向代理 + HTTPS(Let's Encrypt)
|
||||
- `db`: PostgreSQL 16(可选,最小回调壳可以先不启用)
|
||||
- `admin`: Next.js 管理后台(可选,最小回调壳可以先不启用)
|
||||
|
||||
---
|
||||
|
||||
## 二、云服务器准备
|
||||
|
||||
### 2.1 服务器要求
|
||||
|
||||
- **操作系统**:Ubuntu 20.04+ / CentOS 7+ / Debian 11+
|
||||
- **CPU**:1 核以上
|
||||
- **内存**:1GB 以上(推荐 2GB)
|
||||
- **磁盘**:20GB 以上
|
||||
- **网络**:公网 IP,开放 80/443 端口
|
||||
|
||||
### 2.2 安装 Docker 和 Docker Compose
|
||||
|
||||
#### Ubuntu/Debian
|
||||
|
||||
```bash
|
||||
# 更新系统
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ca-certificates curl gnupg lsb-release
|
||||
|
||||
# 添加 Docker 官方 GPG 密钥
|
||||
sudo mkdir -p /etc/apt/keyrings
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||
|
||||
# 添加 Docker 仓库
|
||||
echo \
|
||||
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
|
||||
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
|
||||
# 安装 Docker
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||
|
||||
# 将当前用户添加到 docker 组(可选,避免每次使用 sudo)
|
||||
sudo usermod -aG docker $USER
|
||||
newgrp docker
|
||||
|
||||
# 验证安装
|
||||
docker --version
|
||||
docker compose version
|
||||
```
|
||||
|
||||
#### CentOS/RHEL
|
||||
|
||||
```bash
|
||||
# 安装依赖
|
||||
sudo yum install -y yum-utils
|
||||
|
||||
# 添加 Docker 仓库
|
||||
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
|
||||
|
||||
# 安装 Docker
|
||||
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||
|
||||
# 启动 Docker
|
||||
sudo systemctl start docker
|
||||
sudo systemctl enable docker
|
||||
|
||||
# 将当前用户添加到 docker 组
|
||||
sudo usermod -aG docker $USER
|
||||
newgrp docker
|
||||
|
||||
# 验证安装
|
||||
docker --version
|
||||
docker compose version
|
||||
```
|
||||
|
||||
### 2.3 配置防火墙
|
||||
|
||||
#### Ubuntu (UFW)
|
||||
|
||||
```bash
|
||||
# 允许 SSH(避免锁定)
|
||||
sudo ufw allow 22/tcp
|
||||
|
||||
# 允许 HTTP/HTTPS
|
||||
sudo ufw allow 80/tcp
|
||||
sudo ufw allow 443/tcp
|
||||
|
||||
# 启用防火墙
|
||||
sudo ufw enable
|
||||
|
||||
# 检查状态
|
||||
sudo ufw status
|
||||
```
|
||||
|
||||
#### CentOS/RHEL (firewalld)
|
||||
|
||||
```bash
|
||||
# 允许 HTTP/HTTPS
|
||||
sudo firewall-cmd --permanent --add-service=http
|
||||
sudo firewall-cmd --permanent --add-service=https
|
||||
sudo firewall-cmd --reload
|
||||
|
||||
# 检查状态
|
||||
sudo firewall-cmd --list-all
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、域名 DNS 配置
|
||||
|
||||
### 3.1 添加 A 记录
|
||||
|
||||
在域名服务商(如阿里云、腾讯云、Cloudflare)添加 A 记录:
|
||||
|
||||
```
|
||||
类型: A
|
||||
主机记录: @ 或 api(例如:api.yourdomain.com)
|
||||
记录值: 你的服务器公网 IP
|
||||
TTL: 600(或默认)
|
||||
```
|
||||
|
||||
### 3.2 验证 DNS 解析
|
||||
|
||||
```bash
|
||||
# 检查 DNS 解析
|
||||
nslookup your-domain.com
|
||||
# 或
|
||||
dig your-domain.com
|
||||
|
||||
# 应该返回你的服务器 IP
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、项目部署
|
||||
|
||||
### 4.1 克隆项目
|
||||
|
||||
```bash
|
||||
# 创建项目目录
|
||||
sudo mkdir -p /opt/wecom-ai-assistant
|
||||
sudo chown $USER:$USER /opt/wecom-ai-assistant
|
||||
cd /opt/wecom-ai-assistant
|
||||
|
||||
# 克隆项目(或通过 CI/CD 部署)
|
||||
git clone https://github.com/your-org/wecom-ai-assistant.git .
|
||||
```
|
||||
|
||||
### 4.2 配置环境变量
|
||||
|
||||
```bash
|
||||
# 复制环境变量模板
|
||||
cp .env.example .env.prod
|
||||
|
||||
# 编辑 .env.prod,填写必需变量
|
||||
nano .env.prod
|
||||
```
|
||||
|
||||
**必需变量**:
|
||||
|
||||
```bash
|
||||
# ============ Backend ============
|
||||
API_HOST=0.0.0.0
|
||||
API_PORT=8000
|
||||
|
||||
# Database(可选,最小回调壳可以先不启用)
|
||||
# DATABASE_URL=postgresql+asyncpg://wecom:wecom_secret@db:5432/wecom_ai
|
||||
# DATABASE_URL_SYNC=postgresql://wecom:wecom_secret@db:5432/wecom_ai
|
||||
|
||||
# JWT(admin 登录,可选)
|
||||
JWT_SECRET=your-jwt-secret-change-in-production
|
||||
JWT_ALGORITHM=HS256
|
||||
JWT_EXPIRE_MINUTES=60
|
||||
|
||||
# WeCom Callback(必须,从企业微信管理后台获取)
|
||||
WECOM_CORP_ID=你的企业ID
|
||||
WECOM_AGENT_ID=你的应用AgentId
|
||||
WECOM_SECRET=你的应用Secret(可选)
|
||||
WECOM_TOKEN=你的Token(必须与企微后台一致)
|
||||
WECOM_ENCODING_AES_KEY=你的43位密钥(必须与企微后台一致)
|
||||
|
||||
# WeCom API
|
||||
WECOM_API_BASE=https://qyapi.weixin.qq.com
|
||||
WECOM_API_TIMEOUT=10
|
||||
WECOM_API_RETRIES=2
|
||||
|
||||
# Log
|
||||
LOG_LEVEL=INFO
|
||||
LOG_JSON=true
|
||||
```
|
||||
|
||||
**重要**:
|
||||
- `WECOM_TOKEN` 和 `WECOM_ENCODING_AES_KEY` 必须与企微后台配置**完全一致**
|
||||
- `.env.prod` 文件包含敏感信息,**不要提交到 Git 仓库**
|
||||
|
||||
### 4.3 首次部署
|
||||
|
||||
#### 方式 A:使用部署脚本(推荐)
|
||||
|
||||
```bash
|
||||
# 赋予执行权限
|
||||
chmod +x deploy/scripts/*.sh
|
||||
|
||||
# 启动服务
|
||||
./deploy/scripts/start.sh
|
||||
```
|
||||
|
||||
#### 方式 B:手动部署
|
||||
|
||||
```bash
|
||||
# 设置镜像标签(默认 latest)
|
||||
export IMAGE_TAG=latest
|
||||
export GITHUB_REPOSITORY_OWNER=your-org
|
||||
|
||||
# 启动服务
|
||||
docker-compose -f docker-compose.prod.yml --env-file .env.prod up -d
|
||||
|
||||
# 查看日志
|
||||
docker-compose -f docker-compose.prod.yml logs -f backend
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、HTTPS 配置(Let's Encrypt)
|
||||
|
||||
### 5.1 安装 Certbot
|
||||
|
||||
#### Ubuntu/Debian
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y certbot python3-certbot-nginx
|
||||
```
|
||||
|
||||
#### CentOS/RHEL
|
||||
|
||||
```bash
|
||||
sudo yum install -y certbot python3-certbot-nginx
|
||||
```
|
||||
|
||||
### 5.2 配置 Nginx 占位路径
|
||||
|
||||
在获取证书之前,需要先配置 Nginx 的 HTTP 服务,以便 Certbot 验证域名所有权。
|
||||
|
||||
**临时修改 `deploy/docker/nginx.conf`**:
|
||||
|
||||
```nginx
|
||||
# HTTP 服务器(临时配置,用于证书申请)
|
||||
server {
|
||||
listen 80;
|
||||
server_name your-domain.com;
|
||||
|
||||
# Let's Encrypt 验证路径
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
# /api -> backend
|
||||
location /api/ {
|
||||
proxy_pass http://backend;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# 健康检查
|
||||
location /health {
|
||||
proxy_pass http://backend/api/health;
|
||||
access_log off;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**创建验证目录**:
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /var/www/certbot
|
||||
sudo chown -R $USER:$USER /var/www/certbot
|
||||
```
|
||||
|
||||
**更新 `docker-compose.prod.yml`**,添加验证目录挂载:
|
||||
|
||||
```yaml
|
||||
nginx:
|
||||
volumes:
|
||||
- ./deploy/docker/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- /var/www/certbot:/var/www/certbot:ro # 添加此行
|
||||
```
|
||||
|
||||
**重启 Nginx**:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.prod.yml restart nginx
|
||||
```
|
||||
|
||||
### 5.3 申请 SSL 证书
|
||||
|
||||
```bash
|
||||
# 设置域名和邮箱
|
||||
export DOMAIN=your-domain.com
|
||||
export EMAIL=your-email@example.com
|
||||
|
||||
# 申请证书(使用 Nginx 插件)
|
||||
sudo certbot certonly --nginx \
|
||||
-d $DOMAIN \
|
||||
-d www.$DOMAIN \
|
||||
--email $EMAIL \
|
||||
--agree-tos \
|
||||
--non-interactive \
|
||||
--preferred-challenges http
|
||||
|
||||
# 或使用 standalone 模式(如果 Nginx 未运行)
|
||||
sudo certbot certonly --standalone \
|
||||
-d $DOMAIN \
|
||||
-d www.$DOMAIN \
|
||||
--email $EMAIL \
|
||||
--agree-tos \
|
||||
--non-interactive
|
||||
```
|
||||
|
||||
### 5.4 更新 Nginx 配置
|
||||
|
||||
证书申请成功后,更新 `deploy/docker/nginx.conf`:
|
||||
|
||||
```nginx
|
||||
# HTTPS 服务器
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name your-domain.com;
|
||||
|
||||
# SSL 证书(使用实际域名替换 _)
|
||||
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
|
||||
|
||||
# ... 其他配置
|
||||
}
|
||||
```
|
||||
|
||||
**更新 `docker-compose.prod.yml`**,确保证书目录已挂载:
|
||||
|
||||
```yaml
|
||||
nginx:
|
||||
volumes:
|
||||
- ./deploy/docker/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- /etc/letsencrypt:/etc/letsencrypt:ro # SSL 证书
|
||||
- /var/www/certbot:/var/www/certbot:ro # 验证文件
|
||||
```
|
||||
|
||||
**重启 Nginx**:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.prod.yml restart nginx
|
||||
```
|
||||
|
||||
### 5.5 配置证书自动续期
|
||||
|
||||
Let's Encrypt 证书有效期为 90 天,需要定期续期。
|
||||
|
||||
```bash
|
||||
# 测试续期
|
||||
sudo certbot renew --dry-run
|
||||
|
||||
# 添加定时任务(每天检查一次)
|
||||
sudo crontab -e
|
||||
|
||||
# 添加以下行:
|
||||
0 0 * * * certbot renew --quiet --deploy-hook "docker-compose -f /opt/wecom-ai-assistant/docker-compose.prod.yml restart nginx"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、部署命令
|
||||
|
||||
### 6.1 首次部署
|
||||
|
||||
```bash
|
||||
# 使用部署脚本
|
||||
./deploy/scripts/start.sh
|
||||
|
||||
# 或手动部署
|
||||
docker-compose -f docker-compose.prod.yml --env-file .env.prod up -d
|
||||
```
|
||||
|
||||
### 6.2 更新部署
|
||||
|
||||
#### 方式 A:使用部署脚本
|
||||
|
||||
```bash
|
||||
# 更新到最新版本
|
||||
./deploy/scripts/update.sh latest
|
||||
|
||||
# 更新到指定版本
|
||||
./deploy/scripts/update.sh v1.0.0
|
||||
```
|
||||
|
||||
#### 方式 B:手动更新
|
||||
|
||||
```bash
|
||||
# 设置镜像标签
|
||||
export IMAGE_TAG=latest # 或指定版本,如 v1.0.0
|
||||
|
||||
# 登录到容器镜像仓库
|
||||
docker login ghcr.io -u your-username -p your-token
|
||||
|
||||
# 拉取最新镜像
|
||||
docker-compose -f docker-compose.prod.yml --env-file .env.prod pull
|
||||
|
||||
# 重启服务
|
||||
docker-compose -f docker-compose.prod.yml --env-file .env.prod up -d
|
||||
```
|
||||
|
||||
### 6.3 回滚部署
|
||||
|
||||
```bash
|
||||
# 回滚到指定版本(需要知道之前的镜像标签)
|
||||
export IMAGE_TAG=v0.9.0 # 替换为要回滚的版本
|
||||
|
||||
# 拉取指定版本镜像
|
||||
docker-compose -f docker-compose.prod.yml --env-file .env.prod pull
|
||||
|
||||
# 重启服务
|
||||
docker-compose -f docker-compose.prod.yml --env-file .env.prod up -d
|
||||
```
|
||||
|
||||
**查看历史版本**:
|
||||
|
||||
```bash
|
||||
# 查看 GitHub Container Registry 中的镜像标签
|
||||
# 访问: https://github.com/your-org/wecom-ai-assistant/pkgs/container/wecom-ai-backend
|
||||
```
|
||||
|
||||
### 6.4 停止服务
|
||||
|
||||
```bash
|
||||
# 使用部署脚本
|
||||
./deploy/scripts/stop.sh
|
||||
|
||||
# 或手动停止
|
||||
docker-compose -f docker-compose.prod.yml --env-file .env.prod down
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、验证部署
|
||||
|
||||
### 7.1 检查服务状态
|
||||
|
||||
```bash
|
||||
# 查看服务状态
|
||||
docker-compose -f docker-compose.prod.yml ps
|
||||
|
||||
# 查看日志
|
||||
docker-compose -f docker-compose.prod.yml logs -f backend
|
||||
```
|
||||
|
||||
### 7.2 健康检查
|
||||
|
||||
```bash
|
||||
# HTTP 健康检查(如果 HTTPS 未配置)
|
||||
curl http://your-domain.com/api/health
|
||||
|
||||
# HTTPS 健康检查(推荐)
|
||||
curl https://your-domain.com/api/health
|
||||
|
||||
# 应该返回:
|
||||
# {"status":"ok"}
|
||||
```
|
||||
|
||||
### 7.3 企业微信回调验证
|
||||
|
||||
1. **配置企业微信回调 URL**:
|
||||
- 登录企业微信管理后台:https://work.weixin.qq.com
|
||||
- 进入:应用管理 → 自建应用 → 选择你的应用
|
||||
- 配置回调:
|
||||
- **接收消息服务器 URL**:`https://your-domain.com/api/wecom/callback`
|
||||
- **Token**:与 `.env.prod` 中的 `WECOM_TOKEN` **完全一致**
|
||||
- **EncodingAESKey**:与 `.env.prod` 中的 `WECOM_ENCODING_AES_KEY` **完全一致**
|
||||
- **消息加解密方式**:**安全模式**
|
||||
- 点击 **保存**
|
||||
|
||||
2. **验证 GET 校验**:
|
||||
- 保存后,企业微信会立即发送 GET 请求验证
|
||||
- 观察后端日志:
|
||||
```bash
|
||||
docker-compose -f docker-compose.prod.yml logs -f backend
|
||||
```
|
||||
- 应该看到:
|
||||
```
|
||||
INFO: wecom verify success {"trace_id": "...", "echostr_length": 43}
|
||||
```
|
||||
|
||||
3. **验证 POST 回调**:
|
||||
- 在企业微信中发送测试消息
|
||||
- 观察后端日志,应该看到:
|
||||
```
|
||||
INFO: wecom message received {"trace_id": "...", "external_userid": "...", "msgid": "...", "content_summary": "..."}
|
||||
INFO: wecom reply sent {"trace_id": "...", "reply_summary": "..."}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、GitHub Actions 自动部署
|
||||
|
||||
### 8.1 配置 GitHub Secrets
|
||||
|
||||
在 GitHub 仓库设置中添加以下 Secrets:
|
||||
|
||||
| Secret 名称 | 说明 | 示例 |
|
||||
|------------|------|------|
|
||||
| `PROD_HOST` | 生产服务器 IP 或域名 | `123.45.67.89` |
|
||||
| `PROD_USER` | SSH 用户名 | `ubuntu` |
|
||||
| `PROD_SSH_KEY` | SSH 私钥 | `-----BEGIN OPENSSH PRIVATE KEY-----...` |
|
||||
| `PROD_SSH_PORT` | SSH 端口(可选,默认 22) | `22` |
|
||||
| `PROD_DOMAIN` | 生产域名 | `api.yourdomain.com` |
|
||||
| `PROD_APP_PATH` | 应用部署路径(可选) | `/opt/wecom-ai-assistant` |
|
||||
|
||||
### 8.2 生成 SSH 密钥对
|
||||
|
||||
```bash
|
||||
# 在本地生成 SSH 密钥对
|
||||
ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/github-actions-deploy
|
||||
|
||||
# 将公钥添加到服务器
|
||||
ssh-copy-id -i ~/.ssh/github-actions-deploy.pub user@your-server
|
||||
|
||||
# 将私钥内容复制到 GitHub Secrets
|
||||
cat ~/.ssh/github-actions-deploy
|
||||
```
|
||||
|
||||
### 8.3 自动部署流程
|
||||
|
||||
1. **推送代码到 main 分支**:
|
||||
```bash
|
||||
git push origin main
|
||||
```
|
||||
|
||||
2. **GitHub Actions 自动执行**:
|
||||
- 构建 backend 镜像
|
||||
- 推送到 GHCR
|
||||
- SSH 到生产服务器
|
||||
- 拉取最新镜像
|
||||
- 重启服务
|
||||
- 健康检查
|
||||
|
||||
3. **查看部署日志**:
|
||||
- 访问 GitHub Actions:`https://github.com/your-org/wecom-ai-assistant/actions`
|
||||
|
||||
---
|
||||
|
||||
## 九、常见问题
|
||||
|
||||
### 9.1 服务启动失败
|
||||
|
||||
**症状**:`docker-compose ps` 显示服务状态为 `Restarting` 或 `Exited`
|
||||
|
||||
**排查**:
|
||||
```bash
|
||||
# 查看详细日志
|
||||
docker-compose -f docker-compose.prod.yml logs backend
|
||||
|
||||
# 检查环境变量
|
||||
docker-compose -f docker-compose.prod.yml config
|
||||
```
|
||||
|
||||
**常见原因**:
|
||||
- 环境变量未正确配置
|
||||
- 端口被占用
|
||||
- 镜像拉取失败
|
||||
|
||||
### 9.2 HTTPS 证书问题
|
||||
|
||||
**症状**:浏览器显示"不安全连接"或证书错误
|
||||
|
||||
**排查**:
|
||||
```bash
|
||||
# 检查证书
|
||||
sudo certbot certificates
|
||||
|
||||
# 检查证书有效期
|
||||
sudo openssl x509 -in /etc/letsencrypt/live/your-domain.com/cert.pem -noout -dates
|
||||
|
||||
# 测试续期
|
||||
sudo certbot renew --dry-run
|
||||
```
|
||||
|
||||
### 9.3 企业微信回调失败
|
||||
|
||||
**症状**:企微后台保存失败,日志显示 `wecom verify failed`
|
||||
|
||||
**排查**:
|
||||
1. 检查 `.env.prod` 中的 `WECOM_TOKEN` 和 `WECOM_ENCODING_AES_KEY`
|
||||
2. 确保与企微后台配置**完全一致**(包括大小写、空格)
|
||||
3. 检查域名是否可访问:`curl https://your-domain.com/api/wecom/callback`
|
||||
4. 查看后端日志:`docker-compose -f docker-compose.prod.yml logs backend`
|
||||
|
||||
### 9.4 镜像拉取失败
|
||||
|
||||
**症状**:`docker pull` 失败,提示认证错误
|
||||
|
||||
**解决**:
|
||||
```bash
|
||||
# 登录到 GHCR
|
||||
docker login ghcr.io -u your-username -p your-token
|
||||
|
||||
# 或使用 GitHub Personal Access Token
|
||||
echo $GITHUB_TOKEN | docker login ghcr.io -u your-username --password-stdin
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十、安全最佳实践
|
||||
|
||||
1. **环境变量**:
|
||||
- 使用 `.env.prod` 存储敏感信息
|
||||
- **不要提交 `.env.prod` 到 Git 仓库**
|
||||
- 定期轮换密钥和 Token
|
||||
|
||||
2. **SSH 安全**:
|
||||
- 使用密钥认证,禁用密码登录
|
||||
- 限制 SSH 访问 IP(可选)
|
||||
- 定期更新 SSH 密钥
|
||||
|
||||
3. **防火墙**:
|
||||
- 只开放必要的端口(80, 443, 22)
|
||||
- 使用 fail2ban 防止暴力破解(可选)
|
||||
|
||||
4. **日志**:
|
||||
- 定期清理日志文件
|
||||
- 监控异常日志
|
||||
|
||||
5. **更新**:
|
||||
- 定期更新系统和 Docker
|
||||
- 及时应用安全补丁
|
||||
|
||||
---
|
||||
|
||||
## 十一、参考文档
|
||||
|
||||
- [本地部署指南](./deploy-cloud-minimal.md)
|
||||
- [企业微信回调配置](./wecom.md)
|
||||
- [企业微信测试指南](./wecom-test-guide.md)
|
||||
- [GitHub Actions 部署 Workflow](../.github/workflows/deploy.yml)
|
||||
62
docs/docker-mirror.md
Normal file
62
docs/docker-mirror.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Docker 拉取失败:配置镜像加速
|
||||
|
||||
构建时若出现 `failed to fetch oauth token`、`dial tcp ... connectex` 等无法连接 `auth.docker.io` 的错误,多半是网络无法访问 Docker Hub。
|
||||
|
||||
## 本仓库已做的默认处理
|
||||
|
||||
- **admin** 与 **backend** 的 Dockerfile 已默认使用国内镜像源拉取基础镜像:`docker.mirrors.ustc.edu.cn/library/node:20-alpine`、`docker.mirrors.ustc.edu.cn/library/python:3.12-slim`。多数情况下可直接执行 `docker-compose up -d` 构建。
|
||||
- 若你环境能直连 Docker Hub、希望用官方镜像,可执行:
|
||||
```bash
|
||||
docker-compose build --build-arg NODE_IMAGE=node:20-alpine --build-arg PYTHON_IMAGE=python:3.12-slim
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
若仍报错(例如 USTC 镜像在你网络不可用),可再按下面方式配置 Docker daemon 的镜像加速。
|
||||
|
||||
## 方式一:Docker Desktop(推荐)
|
||||
|
||||
1. 打开 **Docker Desktop** → **Settings**(设置)→ **Docker Engine**。
|
||||
2. 在 JSON 里为 `"registry-mirrors"` 增加一个镜像地址,例如:
|
||||
```json
|
||||
{
|
||||
"registry-mirrors": [
|
||||
"https://docker.mirrors.ustc.edu.cn",
|
||||
"https://hub-mirror.c.163.com"
|
||||
]
|
||||
}
|
||||
```
|
||||
3. 点击 **Apply & Restart**,等待重启完成。
|
||||
4. 回到项目根目录重新执行:`docker-compose up -d`。
|
||||
|
||||
## 方式二:Linux 直接改 daemon 配置
|
||||
|
||||
编辑 `/etc/docker/daemon.json`(没有则新建),加入:
|
||||
|
||||
```json
|
||||
{
|
||||
"registry-mirrors": [
|
||||
"https://docker.mirrors.ustc.edu.cn",
|
||||
"https://hub-mirror.c.163.com"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
然后执行:
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl restart docker
|
||||
```
|
||||
|
||||
## 镜像源说明
|
||||
|
||||
- 上面为常见公共镜像,可用性以当前网络为准。
|
||||
- 若使用阿里云 ECS,可在容器镜像服务里申请**专属加速地址**,替换到 `registry-mirrors` 中,通常更稳定。
|
||||
|
||||
配置完成后再次运行:
|
||||
|
||||
```powershell
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
若仍失败,可尝试开代理或换网络环境后再试。
|
||||
168
docs/github-config-guide.md
Normal file
168
docs/github-config-guide.md
Normal file
@@ -0,0 +1,168 @@
|
||||
# GitHub 配置文件使用指南
|
||||
|
||||
## 概述
|
||||
|
||||
项目已包含 GitHub 配置文件(`.github-config`),用于自动化 GitHub 操作。配置文件包含你的 GitHub 用户名、token 和仓库信息。
|
||||
|
||||
## 配置文件说明
|
||||
|
||||
### 文件位置
|
||||
|
||||
- **`.github-config`**:实际配置文件(包含敏感信息,**不提交到 Git**)
|
||||
- **`.github-config.example`**:配置模板(可提交到 Git)
|
||||
|
||||
### 配置项说明
|
||||
|
||||
```bash
|
||||
# GitHub 用户名/组织
|
||||
GITHUB_USERNAME=bujie9527
|
||||
|
||||
# GitHub Personal Access Token
|
||||
# ⚠️ 警告:此 token 具有仓库访问权限,请妥善保管!
|
||||
GITHUB_TOKEN=your_token_here
|
||||
|
||||
# GitHub 仓库名称
|
||||
GITHUB_REPO_NAME=wecom-ai-assistant
|
||||
|
||||
# GitHub 仓库完整 URL
|
||||
GITHUB_REPO_URL=https://github.com/bujie9527/wecom-ai-assistant.git
|
||||
|
||||
# 默认分支
|
||||
GITHUB_DEFAULT_BRANCH=main
|
||||
|
||||
# Container Registry 配置
|
||||
GHCR_REGISTRY=ghcr.io
|
||||
GHCR_IMAGE_PREFIX=bujie9527
|
||||
|
||||
# 镜像名称
|
||||
BACKEND_IMAGE_NAME=wecom-ai-backend
|
||||
ADMIN_IMAGE_NAME=wecom-ai-admin
|
||||
```
|
||||
|
||||
## 快速使用
|
||||
|
||||
### 1. 初始化 GitHub 仓库
|
||||
|
||||
```powershell
|
||||
# 使用配置文件自动设置 Git 远程仓库
|
||||
.\scripts\setup-github-from-config.ps1
|
||||
```
|
||||
|
||||
此脚本会:
|
||||
- 检查并初始化 Git 仓库
|
||||
- 配置 Git 用户信息(如果需要)
|
||||
- 设置远程仓库地址
|
||||
- 配置 Git 凭据(使用 token)
|
||||
- 创建初始提交(如果还没有)
|
||||
|
||||
### 2. 推送代码到 GitHub
|
||||
|
||||
```powershell
|
||||
# 快速推送(使用默认提交信息)
|
||||
.\scripts\push-to-github.ps1
|
||||
|
||||
# 自定义提交信息
|
||||
.\scripts\push-to-github.ps1 -CommitMessage "Fix: 修复登录问题"
|
||||
|
||||
# 强制推送(危险操作)
|
||||
.\scripts\push-to-github.ps1 -Force
|
||||
```
|
||||
|
||||
### 3. 手动操作
|
||||
|
||||
如果不想使用脚本,也可以手动操作:
|
||||
|
||||
```powershell
|
||||
# 添加远程仓库
|
||||
git remote add origin https://github.com/bujie9527/wecom-ai-assistant.git
|
||||
|
||||
# 使用 token 推送(将 token 嵌入 URL)
|
||||
git remote set-url origin https://bujie9527:YOUR_TOKEN@github.com/bujie9527/wecom-ai-assistant.git
|
||||
|
||||
# 推送代码
|
||||
git push -u origin main
|
||||
```
|
||||
|
||||
## 安全注意事项
|
||||
|
||||
### ⚠️ 重要安全提示
|
||||
|
||||
1. **`.github-config` 文件已添加到 `.gitignore`**,不会被提交到 Git
|
||||
2. **Token 安全**:
|
||||
- 不要将 token 分享给他人
|
||||
- 不要在公开场合展示 token
|
||||
- 如果 token 泄露,立即在 GitHub 上撤销并重新生成
|
||||
3. **Token 权限**:
|
||||
- 当前 token 需要以下权限:
|
||||
- `repo`:访问和修改仓库
|
||||
- `write:packages`:推送 Docker 镜像到 GHCR
|
||||
- `read:packages`:从 GHCR 拉取镜像
|
||||
|
||||
### 撤销和重新生成 Token
|
||||
|
||||
如果 token 泄露或需要更新:
|
||||
|
||||
1. 访问:https://github.com/settings/tokens
|
||||
2. 找到对应的 token,点击 **Revoke**(撤销)
|
||||
3. 点击 **Generate new token**(生成新 token)
|
||||
4. 选择权限:`repo`, `write:packages`, `read:packages`
|
||||
5. 复制新 token 并更新 `.github-config` 文件
|
||||
|
||||
## 配置文件的使用场景
|
||||
|
||||
### 1. 本地开发
|
||||
|
||||
配置文件主要用于:
|
||||
- 自动配置 Git 远程仓库
|
||||
- 快速推送代码
|
||||
- 本地脚本自动化操作
|
||||
|
||||
### 2. GitHub Actions
|
||||
|
||||
GitHub Actions workflow 使用 GitHub Secrets,而不是配置文件:
|
||||
- 配置文件中的 token 用于**本地推送**
|
||||
- GitHub Actions 使用 `GITHUB_TOKEN`(自动提供)或 `GHCR_TOKEN`(在 Secrets 中配置)
|
||||
|
||||
### 3. 生产部署
|
||||
|
||||
生产服务器上:
|
||||
- 使用 SSH 密钥(不是 token)进行部署
|
||||
- 通过 GitHub Actions 自动部署
|
||||
- 不需要在生产服务器上配置 token
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q: 配置文件在哪里?
|
||||
|
||||
**A**: 配置文件位于项目根目录:
|
||||
- `.github-config`:实际配置文件(本地使用,不提交)
|
||||
- `.github-config.example`:模板文件(可提交)
|
||||
|
||||
### Q: 如何更新配置?
|
||||
|
||||
**A**: 直接编辑 `.github-config` 文件,修改对应的值即可。
|
||||
|
||||
### Q: Token 在哪里获取?
|
||||
|
||||
**A**:
|
||||
1. 访问:https://github.com/settings/tokens
|
||||
2. 点击 **Generate new token (classic)**
|
||||
3. 选择权限:`repo`, `write:packages`, `read:packages`
|
||||
4. 复制 token 并更新配置文件
|
||||
|
||||
### Q: 推送时提示认证失败?
|
||||
|
||||
**A**:
|
||||
1. 检查 token 是否正确
|
||||
2. 确认 token 权限包含 `repo`
|
||||
3. 尝试重新运行 `.\scripts\setup-github-from-config.ps1`
|
||||
|
||||
### Q: 配置文件可以提交到 Git 吗?
|
||||
|
||||
**A**: **不可以**。`.github-config` 包含敏感 token,已添加到 `.gitignore`。只有 `.github-config.example`(模板)可以提交。
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [GitHub 快速开始指南](./github-quickstart.md)
|
||||
- [GitHub 完整设置指南](./github-setup-guide.md)
|
||||
- [生产部署文档](./deploy.md)
|
||||
235
docs/github-quickstart.md
Normal file
235
docs/github-quickstart.md
Normal file
@@ -0,0 +1,235 @@
|
||||
# GitHub Actions 快速开始指南
|
||||
|
||||
## 5 分钟快速部署
|
||||
|
||||
### 步骤 1:创建 GitHub 仓库(2 分钟)
|
||||
|
||||
1. 访问 https://github.com/new
|
||||
2. 填写仓库名称:`wecom-ai-assistant`
|
||||
3. 选择 **Private**(推荐)
|
||||
4. 点击 **Create repository**
|
||||
|
||||
### 步骤 2:推送代码到 GitHub(1 分钟)
|
||||
|
||||
在项目根目录执行:
|
||||
|
||||
```powershell
|
||||
# 初始化 Git(如果还没有)
|
||||
git init
|
||||
|
||||
# 添加所有文件
|
||||
git add .
|
||||
|
||||
# 提交
|
||||
git commit -m "Initial commit: 企业微信 AI 助手"
|
||||
|
||||
# 添加远程仓库(替换 YOUR_USERNAME)
|
||||
git remote add origin https://github.com/YOUR_USERNAME/wecom-ai-assistant.git
|
||||
|
||||
# 推送到 GitHub
|
||||
git branch -M main
|
||||
git push -u origin main
|
||||
```
|
||||
|
||||
**如果遇到认证问题**:
|
||||
- 访问 https://github.com/settings/tokens
|
||||
- 生成新 token(权限:`repo`, `write:packages`)
|
||||
- 使用 token 作为密码推送
|
||||
|
||||
### 步骤 3:配置 GitHub Secrets(2 分钟)
|
||||
|
||||
1. 进入仓库 → **Settings** → **Secrets and variables** → **Actions**
|
||||
2. 点击 **New repository secret**,依次添加:
|
||||
|
||||
#### 必需 Secrets
|
||||
|
||||
| Secret 名称 | 说明 | 如何获取 |
|
||||
|------------|------|---------|
|
||||
| `PROD_HOST` | 服务器 IP | 你的云服务器公网 IP |
|
||||
| `PROD_USER` | SSH 用户名 | 通常是 `root` 或 `ubuntu` |
|
||||
| `PROD_SSH_KEY` | SSH 私钥 | 见下方"生成 SSH 密钥" |
|
||||
| `PROD_DOMAIN` | 生产域名 | 例如:`api.yourdomain.com` |
|
||||
|
||||
#### 可选 Secrets
|
||||
|
||||
| Secret 名称 | 说明 | 默认值 |
|
||||
|------------|------|--------|
|
||||
| `PROD_SSH_PORT` | SSH 端口 | `22` |
|
||||
| `PROD_APP_PATH` | 应用路径 | `/opt/wecom-ai-assistant` |
|
||||
| `GHCR_TOKEN` | GitHub Packages Token | 使用默认 `GITHUB_TOKEN` |
|
||||
|
||||
#### 生成 SSH 密钥
|
||||
|
||||
```powershell
|
||||
# 在本地生成 SSH 密钥对
|
||||
ssh-keygen -t ed25519 -C "github-actions" -f $env:USERPROFILE\.ssh\github-actions
|
||||
|
||||
# 查看私钥(复制到 GitHub Secrets 的 PROD_SSH_KEY)
|
||||
cat $env:USERPROFILE\.ssh\github-actions
|
||||
|
||||
# 查看公钥(需要添加到服务器)
|
||||
cat $env:USERPROFILE\.ssh\github-actions.pub
|
||||
```
|
||||
|
||||
**将公钥添加到服务器**:
|
||||
|
||||
```bash
|
||||
# SSH 登录服务器
|
||||
ssh user@your-server
|
||||
|
||||
# 添加公钥到 authorized_keys
|
||||
mkdir -p ~/.ssh
|
||||
echo "你的公钥内容" >> ~/.ssh/authorized_keys
|
||||
chmod 600 ~/.ssh/authorized_keys
|
||||
chmod 700 ~/.ssh
|
||||
```
|
||||
|
||||
### 步骤 4:配置仓库权限(30 秒)
|
||||
|
||||
1. 进入仓库 → **Settings** → **Actions** → **General**
|
||||
2. 找到 **Workflow permissions**
|
||||
3. 选择 **Read and write permissions**
|
||||
4. 点击 **Save**
|
||||
|
||||
### 步骤 5:在生产服务器上准备(5 分钟)
|
||||
|
||||
```bash
|
||||
# 1. SSH 登录服务器
|
||||
ssh user@your-server
|
||||
|
||||
# 2. 安装 Docker(Ubuntu/Debian)
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y docker.io docker-compose-plugin
|
||||
sudo systemctl start docker
|
||||
sudo systemctl enable docker
|
||||
sudo usermod -aG docker $USER
|
||||
newgrp docker
|
||||
|
||||
# 3. 创建项目目录
|
||||
sudo mkdir -p /opt/wecom-ai-assistant
|
||||
sudo chown $USER:$USER /opt/wecom-ai-assistant
|
||||
cd /opt/wecom-ai-assistant
|
||||
|
||||
# 4. 克隆项目
|
||||
git clone https://github.com/YOUR_USERNAME/wecom-ai-assistant.git .
|
||||
|
||||
# 5. 创建生产环境变量文件
|
||||
cp .env.prod.example .env.prod
|
||||
nano .env.prod # 填写实际配置
|
||||
```
|
||||
|
||||
**必需的环境变量**(`.env.prod`):
|
||||
|
||||
```bash
|
||||
# WeCom 回调配置(必须)
|
||||
WECOM_CORP_ID=你的企业ID
|
||||
WECOM_AGENT_ID=你的应用AgentId
|
||||
WECOM_TOKEN=你的Token(43位随机字符串)
|
||||
WECOM_ENCODING_AES_KEY=你的43位密钥
|
||||
|
||||
# 其他配置...
|
||||
```
|
||||
|
||||
### 步骤 6:触发首次部署(1 分钟)
|
||||
|
||||
#### 方式 A:推送代码自动触发
|
||||
|
||||
```powershell
|
||||
# 在本地执行
|
||||
git add .
|
||||
git commit -m "Trigger deployment"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
#### 方式 B:手动触发
|
||||
|
||||
1. 进入 GitHub 仓库 → **Actions**
|
||||
2. 选择 **Deploy to Production** workflow
|
||||
3. 点击 **Run workflow**
|
||||
4. 选择分支 `main`,点击 **Run workflow**
|
||||
|
||||
### 步骤 7:验证部署(1 分钟)
|
||||
|
||||
1. **查看 GitHub Actions 日志**:
|
||||
- 进入 **Actions** → 点击最新的 workflow run
|
||||
- 查看各步骤执行情况
|
||||
|
||||
2. **验证服务状态**:
|
||||
```bash
|
||||
# SSH 到服务器
|
||||
ssh user@your-server
|
||||
cd /opt/wecom-ai-assistant
|
||||
|
||||
# 查看服务状态
|
||||
docker compose -f docker-compose.prod.yml ps
|
||||
|
||||
# 查看日志
|
||||
docker compose -f docker-compose.prod.yml logs -f backend
|
||||
```
|
||||
|
||||
3. **健康检查**:
|
||||
```bash
|
||||
curl https://your-domain.com/api/health
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 后续更新部署
|
||||
|
||||
### 自动部署(推送到 main)
|
||||
|
||||
```powershell
|
||||
git add .
|
||||
git commit -m "Update: 描述你的更改"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
推送后,GitHub Actions 会自动:
|
||||
1. 构建 backend 镜像
|
||||
2. 推送到 GHCR
|
||||
3. SSH 到服务器部署
|
||||
4. 执行健康检查
|
||||
|
||||
### 手动触发部署
|
||||
|
||||
1. 进入 **Actions** → **Deploy to Production**
|
||||
2. 点击 **Run workflow**
|
||||
3. 可选择指定镜像标签(用于回滚)
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q: SSH 连接失败?
|
||||
|
||||
**A**: 检查以下项:
|
||||
- `PROD_HOST`、`PROD_USER`、`PROD_SSH_KEY` 是否正确
|
||||
- 服务器防火墙是否开放 SSH 端口
|
||||
- SSH 公钥是否已添加到服务器的 `~/.ssh/authorized_keys`
|
||||
|
||||
### Q: 镜像推送失败?
|
||||
|
||||
**A**:
|
||||
- 确认仓库权限已设置为 "Read and write"
|
||||
- 检查 GitHub Packages 是否启用
|
||||
|
||||
### Q: 部署后服务无法访问?
|
||||
|
||||
**A**:
|
||||
- 检查 `.env.prod` 配置是否正确
|
||||
- 查看服务日志:`docker compose -f docker-compose.prod.yml logs backend`
|
||||
- 确认域名 DNS 已正确解析到服务器 IP
|
||||
|
||||
### Q: 如何回滚到之前的版本?
|
||||
|
||||
**A**:
|
||||
1. 在 GitHub Actions 中手动触发
|
||||
2. 指定镜像标签(例如:`main-abc1234`,commit SHA 的前缀)
|
||||
|
||||
---
|
||||
|
||||
## 下一步
|
||||
|
||||
- 配置 HTTPS:参见 `docs/deploy.md` 中的 Let's Encrypt 部分
|
||||
- 配置企业微信回调:参见 `docs/wecom.md`
|
||||
- 详细部署文档:参见 `docs/github-setup-guide.md`
|
||||
350
docs/github-setup-guide.md
Normal file
350
docs/github-setup-guide.md
Normal file
@@ -0,0 +1,350 @@
|
||||
# GitHub 项目设置与部署 Workflow 配置指南
|
||||
|
||||
## 一、创建 GitHub 仓库
|
||||
|
||||
### 1.1 在 GitHub 上创建新仓库
|
||||
|
||||
1. 登录 GitHub:https://github.com
|
||||
2. 点击右上角 **+** → **New repository**
|
||||
3. 填写仓库信息:
|
||||
- **Repository name**: `wecom-ai-assistant`(或你喜欢的名称)
|
||||
- **Description**: 企业微信 AI 机器人助理
|
||||
- **Visibility**: Private(推荐)或 Public
|
||||
- **不要**勾选 "Initialize this repository with a README"
|
||||
4. 点击 **Create repository**
|
||||
|
||||
### 1.2 推送本地代码到 GitHub
|
||||
|
||||
```powershell
|
||||
# 在项目根目录执行
|
||||
cd D:\企微AI助手
|
||||
|
||||
# 初始化 Git(如果还没有)
|
||||
git init
|
||||
|
||||
# 添加所有文件
|
||||
git add .
|
||||
|
||||
# 提交
|
||||
git commit -m "Initial commit: 企业微信 AI 助手 MVP"
|
||||
|
||||
# 添加远程仓库(替换 YOUR_USERNAME 为你的 GitHub 用户名)
|
||||
git remote add origin https://github.com/YOUR_USERNAME/wecom-ai-assistant.git
|
||||
|
||||
# 推送到 GitHub
|
||||
git branch -M main
|
||||
git push -u origin main
|
||||
```
|
||||
|
||||
**注意**:如果遇到认证问题,可能需要配置 GitHub Personal Access Token:
|
||||
- 访问:https://github.com/settings/tokens
|
||||
- 生成新 token(权限:`repo`, `write:packages`, `read:packages`)
|
||||
- 使用 token 作为密码推送
|
||||
|
||||
---
|
||||
|
||||
## 二、配置 GitHub Secrets
|
||||
|
||||
### 2.1 进入仓库设置
|
||||
|
||||
1. 在 GitHub 仓库页面,点击 **Settings**
|
||||
2. 左侧菜单选择 **Secrets and variables** → **Actions**
|
||||
3. 点击 **New repository secret**
|
||||
|
||||
### 2.2 添加必需的 Secrets
|
||||
|
||||
依次添加以下 Secrets:
|
||||
|
||||
| Secret 名称 | 说明 | 示例值 |
|
||||
|------------|------|--------|
|
||||
| `PROD_HOST` | 生产服务器 IP 或域名 | `123.45.67.89` |
|
||||
| `PROD_USER` | SSH 用户名 | `ubuntu` 或 `root` |
|
||||
| `PROD_SSH_KEY` | SSH 私钥(完整内容) | `-----BEGIN OPENSSH PRIVATE KEY-----...` |
|
||||
| `PROD_SSH_PORT` | SSH 端口(可选,默认 22) | `22` |
|
||||
| `PROD_DOMAIN` | 生产域名(用于健康检查) | `api.yourdomain.com` |
|
||||
| `PROD_APP_PATH` | 应用部署路径(可选) | `/opt/wecom-ai-assistant` |
|
||||
|
||||
### 2.3 生成 SSH 密钥对
|
||||
|
||||
在本地生成 SSH 密钥对(如果还没有):
|
||||
|
||||
```powershell
|
||||
# 生成 SSH 密钥对
|
||||
ssh-keygen -t ed25519 -C "github-actions-deploy" -f $env:USERPROFILE\.ssh\github-actions-deploy
|
||||
|
||||
# 查看公钥(需要添加到服务器)
|
||||
cat $env:USERPROFILE\.ssh\github-actions-deploy.pub
|
||||
|
||||
# 查看私钥(需要添加到 GitHub Secrets)
|
||||
cat $env:USERPROFILE\.ssh\github-actions-deploy
|
||||
```
|
||||
|
||||
**重要**:
|
||||
- **公钥**(`.pub` 文件)需要添加到生产服务器的 `~/.ssh/authorized_keys`
|
||||
- **私钥**(无 `.pub` 后缀)需要添加到 GitHub Secrets 的 `PROD_SSH_KEY`
|
||||
|
||||
### 2.4 将公钥添加到生产服务器
|
||||
|
||||
```bash
|
||||
# 在本地执行(将公钥复制到服务器)
|
||||
type $env:USERPROFILE\.ssh\github-actions-deploy.pub | ssh user@your-server "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
|
||||
|
||||
# 或在服务器上手动添加
|
||||
# 1. SSH 登录服务器
|
||||
# 2. 编辑 ~/.ssh/authorized_keys
|
||||
# 3. 粘贴公钥内容
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、配置 GitHub Packages 权限
|
||||
|
||||
### 3.1 启用 GitHub Packages
|
||||
|
||||
GitHub Actions 默认使用 `GITHUB_TOKEN` 推送镜像到 GHCR,但需要确保仓库有写入权限:
|
||||
|
||||
1. 进入仓库 **Settings** → **Actions** → **General**
|
||||
2. 找到 **Workflow permissions**
|
||||
3. 选择 **Read and write permissions**
|
||||
4. 勾选 **Allow GitHub Actions to create and approve pull requests**(可选)
|
||||
5. 点击 **Save**
|
||||
|
||||
### 3.2 验证镜像推送权限
|
||||
|
||||
首次推送后,检查镜像是否成功推送到 GHCR:
|
||||
- 访问:`https://github.com/YOUR_USERNAME/wecom-ai-assistant/pkgs/container/wecom-ai-backend`
|
||||
|
||||
---
|
||||
|
||||
## 四、首次部署流程
|
||||
|
||||
### 4.1 在生产服务器上准备
|
||||
|
||||
```bash
|
||||
# 1. SSH 登录生产服务器
|
||||
ssh user@your-server
|
||||
|
||||
# 2. 安装 Docker 和 Docker Compose(如果还没有)
|
||||
# Ubuntu/Debian:
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y docker.io docker-compose-plugin
|
||||
|
||||
# CentOS/RHEL:
|
||||
sudo yum install -y docker docker-compose-plugin
|
||||
|
||||
# 3. 启动 Docker
|
||||
sudo systemctl start docker
|
||||
sudo systemctl enable docker
|
||||
|
||||
# 4. 将当前用户添加到 docker 组(避免每次使用 sudo)
|
||||
sudo usermod -aG docker $USER
|
||||
newgrp docker
|
||||
|
||||
# 5. 创建项目目录
|
||||
sudo mkdir -p /opt/wecom-ai-assistant
|
||||
sudo chown $USER:$USER /opt/wecom-ai-assistant
|
||||
cd /opt/wecom-ai-assistant
|
||||
|
||||
# 6. 克隆项目
|
||||
git clone https://github.com/YOUR_USERNAME/wecom-ai-assistant.git .
|
||||
|
||||
# 7. 创建生产环境变量文件
|
||||
cp .env.prod.example .env.prod
|
||||
nano .env.prod # 填写实际的生产环境变量
|
||||
```
|
||||
|
||||
### 4.2 配置生产环境变量
|
||||
|
||||
编辑 `.env.prod`,填写以下必需变量:
|
||||
|
||||
```bash
|
||||
# WeCom Callback(必须)
|
||||
WECOM_CORP_ID=你的企业ID
|
||||
WECOM_AGENT_ID=你的应用AgentId
|
||||
WECOM_TOKEN=你的Token(必须与企微后台一致)
|
||||
WECOM_ENCODING_AES_KEY=你的43位密钥(必须与企微后台一致)
|
||||
|
||||
# 其他配置...
|
||||
```
|
||||
|
||||
### 4.3 配置 HTTPS(Let's Encrypt)
|
||||
|
||||
```bash
|
||||
# 1. 安装 Certbot
|
||||
sudo apt-get install -y certbot python3-certbot-nginx
|
||||
|
||||
# 2. 先启动 HTTP 服务(用于验证)
|
||||
export IMAGE_TAG=latest
|
||||
export GITHUB_REPOSITORY_OWNER=YOUR_USERNAME
|
||||
docker-compose -f docker-compose.prod.yml --env-file .env.prod up -d backend nginx
|
||||
|
||||
# 3. 申请 SSL 证书
|
||||
export DOMAIN=your-domain.com
|
||||
export EMAIL=your-email@example.com
|
||||
sudo certbot certonly --nginx -d $DOMAIN --email $EMAIL --agree-tos --non-interactive
|
||||
|
||||
# 4. 更新 Nginx 配置(使用实际域名替换 nginx.conf 中的 _)
|
||||
# 编辑 deploy/docker/nginx.conf,将 server_name _ 改为 server_name your-domain.com
|
||||
# 将 SSL 证书路径改为实际路径
|
||||
|
||||
# 5. 重启 Nginx
|
||||
docker-compose -f docker-compose.prod.yml restart nginx
|
||||
```
|
||||
|
||||
### 4.4 触发首次部署
|
||||
|
||||
有两种方式:
|
||||
|
||||
#### 方式 A:通过 GitHub Actions(推荐)
|
||||
|
||||
1. 在 GitHub 仓库页面,点击 **Actions** 标签
|
||||
2. 选择 **Deploy to Production** workflow
|
||||
3. 点击 **Run workflow**
|
||||
4. 选择分支(`main`)和镜像标签(默认 `latest`)
|
||||
5. 点击 **Run workflow**
|
||||
|
||||
#### 方式 B:手动推送代码
|
||||
|
||||
```powershell
|
||||
# 在本地执行
|
||||
git add .
|
||||
git commit -m "Trigger deployment"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
推送后,GitHub Actions 会自动:
|
||||
1. 构建 backend 镜像
|
||||
2. 推送到 GHCR
|
||||
3. SSH 到生产服务器
|
||||
4. 拉取镜像并部署
|
||||
5. 执行健康检查
|
||||
|
||||
---
|
||||
|
||||
## 五、验证部署
|
||||
|
||||
### 5.1 查看 GitHub Actions 日志
|
||||
|
||||
1. 进入 GitHub 仓库 → **Actions**
|
||||
2. 点击最新的 workflow run
|
||||
3. 查看各步骤的执行日志
|
||||
|
||||
### 5.2 验证服务状态
|
||||
|
||||
```bash
|
||||
# SSH 到生产服务器
|
||||
ssh user@your-server
|
||||
cd /opt/wecom-ai-assistant
|
||||
|
||||
# 查看服务状态
|
||||
docker-compose -f docker-compose.prod.yml ps
|
||||
|
||||
# 查看日志
|
||||
docker-compose -f docker-compose.prod.yml logs -f backend
|
||||
|
||||
# 健康检查
|
||||
curl https://your-domain.com/api/health
|
||||
```
|
||||
|
||||
### 5.3 配置企业微信回调
|
||||
|
||||
1. 登录企业微信管理后台:https://work.weixin.qq.com
|
||||
2. 进入:应用管理 → 自建应用 → 选择你的应用
|
||||
3. 配置回调:
|
||||
- **接收消息服务器 URL**:`https://your-domain.com/api/wecom/callback`
|
||||
- **Token**:与 `.env.prod` 中的 `WECOM_TOKEN` **完全一致**
|
||||
- **EncodingAESKey**:与 `.env.prod` 中的 `WECOM_ENCODING_AES_KEY` **完全一致**
|
||||
- **消息加解密方式**:**安全模式**
|
||||
4. 点击 **保存**
|
||||
|
||||
---
|
||||
|
||||
## 六、后续更新部署
|
||||
|
||||
### 6.1 自动部署(推送到 main)
|
||||
|
||||
```powershell
|
||||
# 本地修改代码后
|
||||
git add .
|
||||
git commit -m "Update: 描述你的更改"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
推送后,GitHub Actions 会自动触发部署。
|
||||
|
||||
### 6.2 手动触发部署
|
||||
|
||||
1. 进入 GitHub 仓库 → **Actions**
|
||||
2. 选择 **Deploy to Production** workflow
|
||||
3. 点击 **Run workflow**
|
||||
4. 可选择指定镜像标签(用于回滚)
|
||||
|
||||
### 6.3 回滚到指定版本
|
||||
|
||||
```bash
|
||||
# 在 GitHub Actions 中手动触发,指定镜像标签
|
||||
# 例如:main-abc1234(commit SHA 的前缀)
|
||||
|
||||
# 或在服务器上手动回滚
|
||||
cd /opt/wecom-ai-assistant
|
||||
export IMAGE_TAG=main-abc1234
|
||||
docker-compose -f docker-compose.prod.yml --env-file .env.prod pull
|
||||
docker-compose -f docker-compose.prod.yml --env-file .env.prod up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、故障排查
|
||||
|
||||
### 7.1 GitHub Actions 失败
|
||||
|
||||
**常见问题**:
|
||||
|
||||
1. **SSH 连接失败**:
|
||||
- 检查 `PROD_HOST`、`PROD_USER`、`PROD_SSH_KEY` 是否正确
|
||||
- 确认服务器防火墙允许 SSH 端口
|
||||
- 测试 SSH 连接:`ssh -i ~/.ssh/github-actions-deploy user@your-server`
|
||||
|
||||
2. **镜像推送失败**:
|
||||
- 检查 GitHub Packages 权限
|
||||
- 确认 `GITHUB_TOKEN` 有写入权限
|
||||
|
||||
3. **部署失败**:
|
||||
- 查看 GitHub Actions 日志中的错误信息
|
||||
- 检查服务器上的 Docker 和 docker-compose 是否正常
|
||||
|
||||
### 7.2 健康检查失败
|
||||
|
||||
```bash
|
||||
# 检查服务是否运行
|
||||
docker-compose -f docker-compose.prod.yml ps
|
||||
|
||||
# 检查后端日志
|
||||
docker-compose -f docker-compose.prod.yml logs backend
|
||||
|
||||
# 检查 Nginx 日志
|
||||
docker-compose -f docker-compose.prod.yml logs nginx
|
||||
|
||||
# 手动测试健康检查
|
||||
curl -v https://your-domain.com/api/health
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、安全检查清单
|
||||
|
||||
- [ ] GitHub 仓库设置为 Private(如果包含敏感信息)
|
||||
- [ ] 所有敏感信息存储在 `.env.prod`(不提交到 Git)
|
||||
- [ ] SSH 密钥使用强加密(ed25519)
|
||||
- [ ] 生产服务器防火墙配置正确(只开放必要端口)
|
||||
- [ ] SSL 证书配置正确(HTTPS)
|
||||
- [ ] 定期更新 Docker 镜像和依赖
|
||||
|
||||
---
|
||||
|
||||
## 九、参考文档
|
||||
|
||||
- [GitHub Actions 文档](https://docs.github.com/en/actions)
|
||||
- [GitHub Container Registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry)
|
||||
- [生产部署文档](./deploy.md)
|
||||
- [企业微信回调配置](./wecom.md)
|
||||
51
docs/phase1.md
Normal file
51
docs/phase1.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Phase 1:初始化仓库与脚手架 + 本地跑通
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
backend/ # FastAPI,routers/services/models,config 来自 env
|
||||
admin/ # Next.js + TypeScript + Ant Design
|
||||
deploy/ # nginx.conf
|
||||
docs/ # wecom.md, phase*.md
|
||||
docker-compose.yml
|
||||
.env.example
|
||||
```
|
||||
|
||||
## 本地启动
|
||||
|
||||
1. 复制环境变量:
|
||||
- **Bash:** `cp .env.example .env`
|
||||
- **PowerShell:** `Copy-Item .env.example .env`
|
||||
2. 一键启动(需本机已装 Docker + docker-compose):
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
3. 等待 db 健康后,backend 与 admin 会启动;nginx 监听 80。
|
||||
|
||||
## 验证
|
||||
|
||||
- **健康检查**:`curl http://localhost:8000/api/health` 或经 nginx `curl http://localhost/api/health`
|
||||
- 期望:`{"code":0,"message":"ok","data":{"status":"up"},"trace_id":"..."}`
|
||||
- **管理后台**:浏览器打开 `http://localhost:3000` 或 `http://localhost`(经 nginx)
|
||||
- 登录页,用户名/密码填 `admin`/`admin`,点击登录应提示「登录成功」(当前为占位校验)
|
||||
- **后端测试**:在 `backend/` 下执行 `pytest tests/test_health.py -v`
|
||||
|
||||
## 关键配置项(.env)
|
||||
|
||||
- `DATABASE_URL` / `DATABASE_URL_SYNC`:Phase 2 迁移会用。
|
||||
- `NEXT_PUBLIC_API_BASE`:前端请求 API 的地址;本地直连后端可设为 `http://localhost:8000`,经 nginx 可留空或 `http://localhost`。
|
||||
|
||||
## 仅本地跑后端(不 Docker)
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
python -m venv .venv
|
||||
.venv\Scripts\activate # Windows
|
||||
pip install -r requirements.txt
|
||||
# 先启动 PostgreSQL 并建库 wecom_ai、用户 wecom
|
||||
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
|
||||
```
|
||||
|
||||
前端单独起:
|
||||
- **Bash:** `cd admin && npm install && npm run dev`,且设置 `NEXT_PUBLIC_API_BASE=http://localhost:8000`(可在 `admin/.env.local` 写一行)。
|
||||
- **PowerShell:** 先 `cd admin`,再 `npm install`,再 `$env:NEXT_PUBLIC_API_BASE="http://localhost:8000"; npm run dev`(或把 `NEXT_PUBLIC_API_BASE=http://localhost:8000` 写入 `admin/.env.local` 后直接 `npm run dev`)。
|
||||
50
docs/phase2.md
Normal file
50
docs/phase2.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Phase 2:后端基础 API + 数据库迁移
|
||||
|
||||
## 新增内容
|
||||
|
||||
- **ORM**:`app/models/`(User, ChatSession, Message, Ticket),SQLAlchemy 2.x
|
||||
- **数据库**:`app/database.py` 异步会话,`get_db` 依赖
|
||||
- **迁移**:Alembic,`alembic/versions/001_init_tables.py`、`002_seed_admin.py`
|
||||
- **认证**:`app/services/auth_service.py`(bcrypt + JWT),`app/deps.py`(get_current_user_id)
|
||||
- **登录**:`POST /api/auth/login` 查 User 表并校验密码,返回 JWT
|
||||
|
||||
## 本地启动与迁移
|
||||
|
||||
1. 启动 DB(或整栈):
|
||||
```bash
|
||||
docker-compose up -d db
|
||||
```
|
||||
2. 在 `backend/` 下执行迁移(需已配置 `DATABASE_URL_SYNC`,如从项目根 `.env` 加载):
|
||||
```bash
|
||||
cd backend
|
||||
# 若 .env 在项目根,可:export $(grep -v '^#' ../.env | xargs) 或复制 .env 到 backend/
|
||||
alembic upgrade head
|
||||
```
|
||||
3. 启动后端:
|
||||
```bash
|
||||
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
|
||||
```
|
||||
|
||||
## 验证
|
||||
|
||||
- **健康检查**:`curl http://localhost:8000/api/health` → `code: 0, data.status: "up"`
|
||||
- **登录**:`curl -X POST http://localhost:8000/api/auth/login -H "Content-Type: application/json" -d "{\"username\":\"admin\",\"password\":\"admin\"}"`
|
||||
- 迁移并 seed 后应返回 `code: 0` 且 `data.access_token` 为 JWT
|
||||
- **测试**:`pytest tests/test_health.py tests/test_auth.py -v`
|
||||
|
||||
## 关键配置项
|
||||
|
||||
- `DATABASE_URL`:异步连接串,供 FastAPI 使用(如 `postgresql+asyncpg://...`)
|
||||
- `DATABASE_URL_SYNC`:同步连接串,供 Alembic 使用(如 `postgresql://...`)
|
||||
- `JWT_SECRET`:生产环境必须修改
|
||||
- `JWT_EXPIRE_MINUTES`:token 有效期(分钟)
|
||||
|
||||
## Docker 内迁移
|
||||
|
||||
若后端在 Docker 内启动,可在首次启动时自动迁移(可选)。例如在 `backend/Dockerfile` 或启动脚本中:
|
||||
|
||||
```bash
|
||||
alembic upgrade head && uvicorn app.main:app --host 0.0.0.0 --port 8000
|
||||
```
|
||||
|
||||
需保证容器内能访问 `DATABASE_URL_SYNC` 且指向 `db:5432`。
|
||||
35
docs/phase3.md
Normal file
35
docs/phase3.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Phase 3:管理后台基础页面 + API 联通
|
||||
|
||||
## 新增内容
|
||||
|
||||
- **前端**:Next.js App Router,路由组 `(main)` 下会话/知识库/设置共用布局
|
||||
- **登录**:`/login` → 存 token 到 localStorage → 跳转 `/sessions`
|
||||
- **会话列表**:`/sessions`,调用 `GET /api/sessions`,表格 + 查看消息链接
|
||||
- **会话详情**:`/sessions/[id]`,消息列表 + 手动回复输入 + 「转人工/创建工单」按钮
|
||||
- **知识库**:`/knowledge`,拖拽上传,调用 `POST /api/knowledge/upload`(占位)
|
||||
- **设置**:`/settings`,调用 `GET /api/settings`(占位)
|
||||
- **API 封装**:`lib/api.ts`,统一带 `Authorization: Bearer <token>`
|
||||
|
||||
## 本地启动
|
||||
|
||||
1. 后端与 DB 已起(Phase 2):`docker-compose up -d db backend` 或全栈 `docker-compose up -d`
|
||||
2. 前端(从项目根):
|
||||
- **Bash:** `cd admin` → `npm install` → `npm run dev`
|
||||
- **PowerShell:** `cd admin` → `npm install` → 设置 API 再启动:
|
||||
```powershell
|
||||
$env:NEXT_PUBLIC_API_BASE="http://localhost:8000"; npm run dev
|
||||
```
|
||||
或新建 `admin/.env.local` 内容 `NEXT_PUBLIC_API_BASE=http://localhost:8000`,然后 `npm run dev`
|
||||
3. 浏览器打开 `http://localhost:3000`,根路径会重定向到 `/login` 或 `/sessions`
|
||||
|
||||
## 验证
|
||||
|
||||
- 使用 `admin` / `admin` 登录(需已执行迁移并 seed)
|
||||
- 会话列表可为空(Phase 5 入库后会有数据)
|
||||
- 会话详情页可点「转人工/创建工单」、输入内容点「发送」(后端占位返回成功)
|
||||
- 知识库页拖拽上传任意文件,应提示上传成功(占位)
|
||||
- 设置页展示空对象 `{}`
|
||||
|
||||
## 关键配置
|
||||
|
||||
- `NEXT_PUBLIC_API_BASE`:前端请求的后端地址。本地直连填 `http://localhost:8000`;经 nginx 填 `http://localhost` 或留空(同域)
|
||||
18
docs/phase4.md
Normal file
18
docs/phase4.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Phase 4:企业微信回调打通(GET 验签 + POST echo)
|
||||
|
||||
## 新增内容
|
||||
|
||||
- **GET /api/wecom/callback**:使用 `WECOM_TOKEN`、`WECOM_ENCODING_AES_KEY` 验签并解密 `echostr`,将解密结果原样返回。
|
||||
- **POST /api/wecom/callback**:解析加密 XML,验签、解密、解析消息,文本消息 echo 回复,回复加密后以 XML 返回。
|
||||
- **加解密**:`app/services/wecom_crypto.py`(SHA1 验签、AES-256-CBC 加解密,与企微文档一致)。
|
||||
|
||||
## 验证
|
||||
|
||||
1. 在企微管理后台配置回调 URL:`https://你的域名/api/wecom/callback`,填 Token、EncodingAESKey。
|
||||
2. 保存后企微会发 GET 校验,服务端应返回解密后的 echostr,后台显示「保存成功」。
|
||||
3. 给应用发一条文本消息,应收到 echo 回复。
|
||||
|
||||
## 关键配置
|
||||
|
||||
- `WECOM_TOKEN`、`WECOM_ENCODING_AES_KEY` 必须与企微后台一致。
|
||||
- `WECOM_CORP_ID` 用于回复加密尾部;POST 回复时需正确。
|
||||
18
docs/phase5.md
Normal file
18
docs/phase5.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Phase 5:会话入库 + 后台可看
|
||||
|
||||
## 新增内容
|
||||
|
||||
- **回调入库**:WeCom POST 回调解析到客户消息后,`get_or_create_session` + `add_message`(user/assistant)写入 DB。
|
||||
- **会话列表**:`GET /api/sessions` 从 `chat_sessions` 表读取,需 Bearer token。
|
||||
- **消息列表**:`GET /api/sessions/{session_id}/messages` 从 `messages` 表读取,需 Bearer token。
|
||||
|
||||
## 验证
|
||||
|
||||
1. 配置好 WeCom 回调 URL、Token、EncodingAESKey,并确保回调可访问(公网或 ngrok)。
|
||||
2. 在企微侧给应用发一条文本消息,触发 POST 回调。
|
||||
3. 管理后台登录后打开「会话列表」,应出现一条会话;点「查看消息」应看到用户消息与机器人 echo 回复。
|
||||
|
||||
## 关键点
|
||||
|
||||
- 外部客户仅使用 public 知识;回调中只存消息内容与 external_user_id,不落内部配置。
|
||||
- 会话以 `external_user_id`(企微 FromUserName)唯一,同一客户多条消息归同一会话。
|
||||
17
docs/phase6.md
Normal file
17
docs/phase6.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Phase 6:转人工工单 + 手动回复(企业微信发消息)
|
||||
|
||||
## 新增内容
|
||||
|
||||
- **创建工单**:`POST /api/tickets`,body `session_id`、`reason`;插入 `tickets` 表并将对应会话 `status` 置为 `transferred`。
|
||||
- **手动回复**:`POST /api/tickets/reply`,body `session_id`、`content`;根据会话查 `external_user_id`,调用企业微信「发送消息给外部联系人」API 下发文本。
|
||||
- **WeCom API 封装**:`app/services/wecom_api.py`,`get_access_token`、`send_text_to_external`,带超时与重试。
|
||||
|
||||
## 验证
|
||||
|
||||
1. 在管理后台进入某会话详情,点击「转人工/创建工单」→ 应提示工单已创建。
|
||||
2. 在输入框输入内容点「发送」→ 客户端(企微侧)应收到该条消息(需配置好 `WECOM_CORP_ID`、`WECOM_SECRET`、`WECOM_AGENT_ID`)。
|
||||
|
||||
## 配置与接口说明
|
||||
|
||||
- 发消息接口以当前实现为准(如 `externalcontact/message/send` 或 `externalcontact/send_message_to_user`);若企微返回 4xx/5xx,请对照官方文档调整 URL 与参数。
|
||||
- `sender` 当前使用 `WECOM_AGENT_ID`;若需指定客服成员,可后续增加 `WECOM_SENDER_USERID` 配置。
|
||||
35
docs/phase7.md
Normal file
35
docs/phase7.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Phase 7:云端 CI/CD + 线上回调稳定 + 最小闭环验收
|
||||
|
||||
## CI/CD(GitHub Actions)
|
||||
|
||||
- **位置**:`.github/workflows/build-deploy.yml`(副本说明见 `deploy/ci/`)
|
||||
- **触发**:推送到 `main` 分支
|
||||
- **流程**:
|
||||
1. **test-backend**:启动 PostgreSQL 16,执行迁移,运行 `pytest tests/`
|
||||
2. **build-backend**:构建 backend 镜像并推送到 GitHub Container Registry(`ghcr.io/<owner>/wecom-ai-backend:latest`)
|
||||
3. **build-admin**:构建 admin 镜像并推送(`ghcr.io/<owner>/wecom-ai-admin:latest`)
|
||||
|
||||
## 云端部署(方案 A)
|
||||
|
||||
1. 服务器安装 Docker + docker-compose。
|
||||
2. 从 GHCR 拉取镜像(或从仓库 build):
|
||||
- 使用 `docker-compose.yml` 时,可改为使用 `image: ghcr.io/<owner>/wecom-ai-backend:latest` 等,不再本地 build。
|
||||
3. 配置 `.env`(含 `WECOM_*`、`DATABASE_URL`、`JWT_SECRET` 等)。
|
||||
4. 执行:`docker-compose up -d`。
|
||||
5. 配置 Nginx 反代或直接暴露端口;HTTPS 证书后补。
|
||||
|
||||
## 无 GitHub 时(GitLab CI 替代)
|
||||
|
||||
在仓库根目录创建 `.gitlab-ci.yml`,阶段与上述对应:
|
||||
`test`(postgres service + migrate + pytest)、`build`(docker build + push 到 GitLab Registry)。变量使用 `CI_REGISTRY`、`CI_REGISTRY_USER`、`CI_REGISTRY_PASSWORD`。
|
||||
|
||||
## 最小闭环验收脚本
|
||||
|
||||
- **路径**:`deploy/scripts/acceptance.sh`
|
||||
- **用法**:`BASE_URL=http://localhost ./acceptance.sh` 或 `BASE_URL=https://你的域名 ./acceptance.sh`
|
||||
- **步骤**:
|
||||
1. `GET /api/health` 期望 200
|
||||
2. `POST /api/auth/login`(admin/admin)期望 `code: 0`
|
||||
3. `GET /api/wecom/callback?...` 期望 200 或 400(验签失败为 400)
|
||||
|
||||
全部通过即打印 "All checks passed"。
|
||||
240
docs/setup-steps.md
Normal file
240
docs/setup-steps.md
Normal file
@@ -0,0 +1,240 @@
|
||||
# 企业微信回调配置完整步骤
|
||||
|
||||
## 当前状态检查
|
||||
|
||||
✅ Docker 服务运行正常
|
||||
✅ 后端服务正常(http://localhost:8000)
|
||||
✅ .env 文件已配置企业微信参数
|
||||
|
||||
---
|
||||
|
||||
## 步骤 1:安装 cloudflared
|
||||
|
||||
### 方法 A:使用 MSI 安装包(推荐,最简单)
|
||||
|
||||
1. **下载安装包**:
|
||||
- 直接下载:https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-windows-amd64.msi
|
||||
- 或访问:https://github.com/cloudflare/cloudflared/releases 选择最新版本
|
||||
|
||||
2. **安装**:
|
||||
- 双击下载的 `cloudflared-windows-amd64.msi` 文件
|
||||
- 按照安装向导完成安装
|
||||
- 安装完成后会自动添加到系统 PATH
|
||||
|
||||
3. **验证安装**:
|
||||
```powershell
|
||||
cloudflared --version
|
||||
```
|
||||
应该显示版本号,例如:`cloudflared 2026.1.2`
|
||||
|
||||
### 方法 B:使用 Scoop(如果已安装)
|
||||
|
||||
```powershell
|
||||
scoop install cloudflared
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 步骤 2:启动 Cloudflare Tunnel
|
||||
|
||||
### 2.1 启动 tunnel
|
||||
|
||||
在 PowerShell 中运行:
|
||||
|
||||
```powershell
|
||||
cloudflared tunnel --url http://localhost:8000
|
||||
```
|
||||
|
||||
### 2.2 复制公网 URL
|
||||
|
||||
启动后会显示类似这样的输出:
|
||||
|
||||
```
|
||||
+--------------------------------------------------------------------------------------------+
|
||||
| Your quick Tunnel has been created! Visit it at: |
|
||||
| https://abc123-def456-ghi789.trycloudflare.com |
|
||||
+--------------------------------------------------------------------------------------------+
|
||||
```
|
||||
|
||||
**重要**:复制这个 URL(例如:`https://abc123-def456-ghi789.trycloudflare.com`)
|
||||
|
||||
### 2.3 保持窗口运行
|
||||
|
||||
**重要**:不要关闭这个 PowerShell 窗口,保持 cloudflared 运行。
|
||||
|
||||
---
|
||||
|
||||
## 步骤 3:配置企业微信后台
|
||||
|
||||
### 3.1 登录企业微信管理后台
|
||||
|
||||
访问:https://work.weixin.qq.com
|
||||
|
||||
### 3.2 进入应用设置
|
||||
|
||||
1. 点击 **应用管理**
|
||||
2. 选择 **自建应用**
|
||||
3. 选择你的应用(AgentId: 1000003)
|
||||
4. 找到 **接收消息** 或 **API接收**
|
||||
5. 点击 **设置 API 接收** 或 **配置回调URL**
|
||||
|
||||
### 3.3 填写回调配置
|
||||
|
||||
根据你的 `.env` 文件,填写以下信息:
|
||||
|
||||
| 配置项 | 值 | 说明 |
|
||||
|--------|-----|------|
|
||||
| **接收消息服务器 URL** | `https://你的cloudflared域名.trycloudflare.com/api/wecom/callback` | 将 `你的cloudflared域名` 替换为步骤 2.2 中复制的域名 |
|
||||
| **Token** | `tuqA13S8A9L2` | 与 `.env` 中的 `WECOM_TOKEN` 一致 |
|
||||
| **EncodingAESKey** | `VjrVc9NuGr1pikvwKLjr2OpB6gh1wDlBaUMKeUHAlKw` | 与 `.env` 中的 `WECOM_ENCODING_AES_KEY` 一致 |
|
||||
| **消息加解密方式** | **安全模式** | 推荐选择安全模式 |
|
||||
|
||||
**示例**:
|
||||
- 如果 cloudflared URL 是:`https://abc123-def456-ghi789.trycloudflare.com`
|
||||
- 那么回调 URL 应该是:`https://abc123-def456-ghi789.trycloudflare.com/api/wecom/callback`
|
||||
|
||||
### 3.4 保存配置
|
||||
|
||||
点击 **保存** 按钮。
|
||||
|
||||
---
|
||||
|
||||
## 步骤 4:验证配置
|
||||
|
||||
### 4.1 查看后端日志
|
||||
|
||||
在另一个 PowerShell 窗口中运行:
|
||||
|
||||
```powershell
|
||||
docker compose logs backend -f
|
||||
```
|
||||
|
||||
### 4.2 检查验证结果
|
||||
|
||||
保存配置后,企业微信会立即发送 GET 请求进行校验。
|
||||
|
||||
**成功标志**:
|
||||
- 后端日志中应该看到:
|
||||
```
|
||||
INFO: wecom verify success {"trace_id": "...", "echostr_length": 43}
|
||||
```
|
||||
- 企业微信后台应显示 **保存成功** ✅
|
||||
|
||||
**失败标志**:
|
||||
- 后端日志显示 `wecom verify failed`
|
||||
- 企业微信后台显示"URL校验失败"
|
||||
|
||||
**如果失败,检查**:
|
||||
1. Token 是否与 `.env` 中的 `WECOM_TOKEN` 完全一致
|
||||
2. EncodingAESKey 是否与 `.env` 中的 `WECOM_ENCODING_AES_KEY` 完全一致(43位,不含等号)
|
||||
3. 回调 URL 是否正确(包含 `/api/wecom/callback`)
|
||||
4. cloudflared 是否仍在运行
|
||||
|
||||
---
|
||||
|
||||
## 步骤 5:测试消息回调
|
||||
|
||||
### 5.1 发送测试消息
|
||||
|
||||
1. 打开企业微信客户端
|
||||
2. 找到你配置的应用
|
||||
3. 发送一条文本消息,例如:`你好,测试一下`
|
||||
|
||||
### 5.2 查看后端日志
|
||||
|
||||
在后端日志中应该看到:
|
||||
|
||||
**收到消息**:
|
||||
```json
|
||||
{
|
||||
"level": "INFO",
|
||||
"message": "wecom message received",
|
||||
"trace_id": "...",
|
||||
"external_userid": "wmxxxxx",
|
||||
"msgid": "1234567890",
|
||||
"msg_type": "text",
|
||||
"content_summary": "你好,测试一下"
|
||||
}
|
||||
```
|
||||
|
||||
**发送回复**:
|
||||
```json
|
||||
{
|
||||
"level": "INFO",
|
||||
"message": "wecom reply sent",
|
||||
"trace_id": "...",
|
||||
"external_userid": "wmxxxxx",
|
||||
"msgid": "1234567890",
|
||||
"reply_summary": "已收到:你好,测试一下"
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 验证回复
|
||||
|
||||
在企业微信客户端中,应该收到回复:**`已收到:你好,测试一下`**
|
||||
|
||||
### 5.4 检查数据库
|
||||
|
||||
```powershell
|
||||
# 查看会话
|
||||
docker compose exec db psql -U wecom -d wecom_ai -c "SELECT id, external_user_id, status, created_at FROM chat_sessions ORDER BY created_at DESC LIMIT 5;"
|
||||
|
||||
# 查看消息
|
||||
docker compose exec db psql -U wecom -d wecom_ai -c "SELECT id, session_id, role, content, created_at FROM messages ORDER BY created_at DESC LIMIT 10;"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1: cloudflared 命令找不到?
|
||||
|
||||
**解决**:
|
||||
- 如果使用 MSI 安装,重启 PowerShell 窗口
|
||||
- 或使用完整路径运行:`C:\Program Files\Cloudflare\cloudflared.exe tunnel --url http://localhost:8000`
|
||||
|
||||
### Q2: GET 校验失败?
|
||||
|
||||
**检查清单**:
|
||||
- [ ] Token 是否与 `.env` 中的 `WECOM_TOKEN` 完全一致(包括大小写、空格)
|
||||
- [ ] EncodingAESKey 是否与 `.env` 中的 `WECOM_ENCODING_AES_KEY` 完全一致(43位)
|
||||
- [ ] 回调 URL 是否正确(格式:`https://域名.trycloudflare.com/api/wecom/callback`)
|
||||
- [ ] cloudflared 是否仍在运行
|
||||
- [ ] 后端服务是否正常运行
|
||||
|
||||
### Q3: 收到消息但没有回复?
|
||||
|
||||
**检查**:
|
||||
- 查看后端日志是否有错误
|
||||
- 检查数据库连接是否正常
|
||||
- 确认消息类型是否为文本消息
|
||||
|
||||
---
|
||||
|
||||
## 快速命令参考
|
||||
|
||||
```powershell
|
||||
# 检查服务状态
|
||||
docker compose ps
|
||||
|
||||
# 查看后端日志
|
||||
docker compose logs backend -f
|
||||
|
||||
# 测试本地服务
|
||||
curl http://localhost:8000/api/health
|
||||
|
||||
# 启动 cloudflared
|
||||
cloudflared tunnel --url http://localhost:8000
|
||||
|
||||
# 检查数据库
|
||||
docker compose exec db psql -U wecom -d wecom_ai -c "SELECT * FROM chat_sessions;"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 下一步
|
||||
|
||||
完成配置后,可以:
|
||||
1. 测试不同类型的消息(文本、图片等)
|
||||
2. 查看管理后台的会话列表和消息记录
|
||||
3. 继续开发阶段 5:FAQ 匹配功能
|
||||
34
docs/stage1.md
Normal file
34
docs/stage1.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# 阶段 1:Monorepo 骨架 + Docker Compose 本地可启动
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
backend/ # FastAPI,/api/health、/api/ready
|
||||
admin/ # Next.js + TS,/login、/dashboard 占位
|
||||
deploy/ # nginx.conf
|
||||
docs/ # 本文件等
|
||||
docker-compose.yml
|
||||
.env.example
|
||||
README.md
|
||||
```
|
||||
|
||||
## 本地启动
|
||||
|
||||
1. 复制环境变量:`cp .env.example .env`(PowerShell: `Copy-Item .env.example .env`)
|
||||
2. 启动:`docker compose up -d`
|
||||
3. 访问:http://localhost(nginx)、http://localhost:3000(admin 直连)、http://localhost:8000(backend 直连)
|
||||
|
||||
## 验证
|
||||
|
||||
- `GET http://localhost/api/health` → `{"status":"up","service":"backend"}`
|
||||
- `GET http://localhost/api/ready` → `{"ready":true,"service":"backend"}`
|
||||
- 打开 http://localhost → 重定向到 /login,可点「去 Dashboard」到 /dashboard
|
||||
|
||||
## 端口
|
||||
|
||||
| 服务 | 端口 |
|
||||
|--------|------|
|
||||
| nginx | 80 |
|
||||
| admin | 3000 |
|
||||
| backend| 8000 |
|
||||
| db | 5432 |
|
||||
160
docs/stage2.md
Normal file
160
docs/stage2.md
Normal file
@@ -0,0 +1,160 @@
|
||||
# 阶段 2:SQLAlchemy + Alembic + 用户登录体系
|
||||
|
||||
## 1. 数据库与迁移
|
||||
|
||||
- **连接**:backend 通过环境变量 `DATABASE_URL`(异步 `postgresql+asyncpg://...`)连接 PostgreSQL;Alembic 使用 `DATABASE_URL_SYNC`(同步 `postgresql://...`)。
|
||||
- **表结构**:
|
||||
- **users**:id (uuid)、username、password_hash、role、is_active、created_at
|
||||
- **audit_logs**:id (uuid)、actor_user_id (FK users)、action、meta_json (JSONB)、created_at
|
||||
|
||||
### 迁移流程说明
|
||||
|
||||
Alembic 会按版本顺序执行 `alembic/versions/` 下的迁移脚本,在数据库中创建或修改表,并在库中记录当前版本(表 `alembic_version`)。
|
||||
执行时:
|
||||
|
||||
1. 读取 `backend/alembic.ini` 和 `backend/alembic/env.py`。
|
||||
2. `env.py` 从 `app.config.settings` 读取 `database_url_sync`(即环境变量 `DATABASE_URL_SYNC`),用该同步连接串连接 PostgreSQL。
|
||||
3. 对比数据库中的 `alembic_version` 与本地迁移文件,将尚未执行的迁移按顺序执行(例如 `001_users_and_audit_logs.py` 会创建 `users`、`audit_logs` 表)。
|
||||
|
||||
---
|
||||
|
||||
### 方式 A:Docker 启动时自动迁移
|
||||
|
||||
**步骤:**
|
||||
|
||||
1. 在项目根目录执行:
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
2. Compose 会先启动 `db`,等待健康检查通过后再启动 `backend`。
|
||||
3. **backend 容器**的启动命令为:
|
||||
```text
|
||||
sh -c "alembic upgrade head && uvicorn app.main:app --host 0.0.0.0 --port 8000"
|
||||
```
|
||||
4. **迁移阶段**:
|
||||
- 容器内当前目录为 `/app`(即 backend 代码根目录),`PYTHONPATH=/app`。
|
||||
- 执行 `alembic upgrade head` 时,Alembic 在 `/app` 下找到 `alembic.ini`、`alembic/env.py` 和 `alembic/versions/`。
|
||||
- 环境变量由 `docker-compose` 注入(含 `DATABASE_URL_SYNC=postgresql://wecom:wecom_secret@db:5432/wecom_ai`,注意主机名为 `db`)。
|
||||
- `env.py` 通过 `app.config.settings` 读到该连接串,用**同步**驱动连接 PostgreSQL,执行所有未执行的迁移(如创建 `users`、`audit_logs`)。
|
||||
5. **应用启动**:迁移成功后执行 `uvicorn ...`,FastAPI 启动。
|
||||
|
||||
**注意**:若迁移失败(例如数据库未就绪、连接串错误),整条 CMD 会失败,容器退出,backend 不会起来。可查看日志:`docker compose logs backend`。
|
||||
|
||||
**一键迁移脚本(Docker)**:在项目根目录执行其一即可完成「起 db → 等就绪 → 执行 alembic upgrade head」:
|
||||
|
||||
- **Windows PowerShell**:`.\deploy\scripts\migrate.ps1`
|
||||
- **Linux / macOS**:`bash deploy/scripts/migrate.sh`
|
||||
- **任意平台(Python)**:`python deploy/scripts/migrate.py`(默认 Docker);本机迁移用 `python deploy/scripts/migrate.py --local`
|
||||
|
||||
---
|
||||
|
||||
### 方式 B:本机执行迁移
|
||||
|
||||
适用于在本机用 Python 直接跑迁移、数据库可在本机访问(本地 PostgreSQL 或已映射端口的 Docker 数据库)的情况。
|
||||
|
||||
**前提**:
|
||||
|
||||
- 本机已安装 Python 3.12、PostgreSQL 客户端库(`psycopg2-binary`)。
|
||||
- 数据库已存在(例如 Docker 只起 db:`docker compose up -d db`),且已知连接信息。
|
||||
|
||||
**步骤:**
|
||||
|
||||
1. **进入 backend 目录**(迁移必须在 backend 根目录执行,以便找到 `alembic.ini` 和 `alembic/`):
|
||||
```bash
|
||||
cd backend
|
||||
```
|
||||
|
||||
2. **准备环境变量**(二选一):
|
||||
- 在项目根目录已有 `.env` 时,可在 backend 下复制一份,让 `app.config` 自动读取:
|
||||
```bash
|
||||
cp ../.env .env
|
||||
```
|
||||
- 或直接设置连接串(PowerShell 示例):
|
||||
```powershell
|
||||
$env:DATABASE_URL_SYNC = "postgresql://wecom:wecom_secret@localhost:5432/wecom_ai"
|
||||
```
|
||||
Linux/macOS:
|
||||
```bash
|
||||
export DATABASE_URL_SYNC=postgresql://wecom:wecom_secret@localhost:5432/wecom_ai
|
||||
```
|
||||
若数据库在 Docker 且未改端口,主机填 `localhost`、端口 `5432` 即可。
|
||||
|
||||
3. **安装依赖**(若未装过):
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
4. **执行迁移**:
|
||||
```bash
|
||||
alembic upgrade head
|
||||
```
|
||||
- Alembic 会读取当前目录下的 `alembic.ini` 和 `alembic/env.py`。
|
||||
- `env.py` 里会 `from app.config import settings`、`from app.models import Base`,因此当前目录必须在 backend(或设置 `PYTHONPATH` 指向 backend),这样 `app` 才能正确解析。
|
||||
- 执行后,数据库中会创建/更新表,并写入 `alembic_version`。
|
||||
|
||||
5. **验证**:连接数据库查看是否有 `users`、`audit_logs` 及 `alembic_version` 表。
|
||||
|
||||
**本机常见问题**:
|
||||
|
||||
- 报错 `No module named 'app'`:未在 `backend` 目录执行,或未设置 `PYTHONPATH`。解决:`cd backend` 再执行,或 `PYTHONPATH=backend alembic -c backend/alembic.ini upgrade head`(在项目根目录时)。
|
||||
- 连接被拒绝:检查 `DATABASE_URL_SYNC` 的主机、端口、用户名、密码、数据库名是否与真实 PostgreSQL 一致(Docker 时主机为 `localhost`,端口一般为 `5432`)。
|
||||
|
||||
## 2. 如何创建管理员
|
||||
|
||||
使用 seed 脚本(从 **项目根目录** 执行,依赖已安装的 Python 和 .env):
|
||||
|
||||
```bash
|
||||
# 确保 .env 存在,且 DATABASE_URL_SYNC 指向数据库(Docker 时用 localhost:5432)
|
||||
pip install python-dotenv bcrypt psycopg2-binary sqlalchemy
|
||||
|
||||
python deploy/scripts/seed.py
|
||||
```
|
||||
|
||||
可选环境变量(在 .env 或导出):
|
||||
|
||||
- `ADMIN_USERNAME`:默认 `admin`
|
||||
- `ADMIN_PASSWORD`:默认 `admin`
|
||||
- `DATABASE_URL_SYNC`:同步连接串,Docker 时一般为 `postgresql://wecom:wecom_secret@localhost:5432/wecom_ai`
|
||||
|
||||
脚本会检查 `users` 表是否存在;若不存在会提示先执行迁移。若用户名已存在则跳过创建。
|
||||
|
||||
## 3. Auth API
|
||||
|
||||
- **POST /api/auth/login**
|
||||
- Body: `{"username":"admin","password":"admin"}`
|
||||
- 成功:200,`{"access_token":"...","token_type":"bearer"}`
|
||||
- 失败:401/403
|
||||
|
||||
- **GET /api/auth/me**
|
||||
- Header: `Authorization: Bearer <access_token>`
|
||||
- 成功:200,当前用户信息(id、username、role、is_active、created_at)
|
||||
- 失败:401/403
|
||||
|
||||
## 4. 管理后台
|
||||
|
||||
- **Token 存储**:使用 **localStorage**,key 为 `"token"`。实现见 `admin/lib/api.ts` 注释。生产环境可改为 httpOnly Cookie 由后端 Set-Cookie。
|
||||
- **登录页 /login**:表单提交后调用 `POST /api/auth/login`,成功则写入 localStorage 并跳转 `/dashboard`。
|
||||
- **Dashboard /dashboard**:需登录;进入时请求 `GET /api/auth/me`,失败则清除 token 并跳转 `/login`;成功则展示当前用户信息与退出按钮。
|
||||
- **根路径 /**:有 token 则跳转 `/dashboard`,否则跳转 `/login`。
|
||||
|
||||
## 5. 安全
|
||||
|
||||
- **密码**:bcrypt(passlib + bcrypt 4.1.2)。
|
||||
- **JWT**:有过期时间,由 `JWT_EXPIRE_MINUTES` 控制(默认 60 分钟);密钥 `JWT_SECRET` 需在生产环境修改。
|
||||
|
||||
## 6. 如何登录验证
|
||||
|
||||
1. 启动:`docker compose up -d`(自动执行迁移)。
|
||||
2. 创建管理员:`python deploy/scripts/seed.py`(见上文)。
|
||||
3. 打开 http://localhost 或 http://localhost:3000,应跳转登录页。
|
||||
4. 输入 admin / admin(或你在 .env 里设置的 `ADMIN_USERNAME` / `ADMIN_PASSWORD`),提交后应跳转 Dashboard 并显示当前用户信息。
|
||||
5. 点击退出后应回到登录页;再次访问 /dashboard 应被重定向到 /login。
|
||||
|
||||
直连 API 验证:
|
||||
|
||||
```bash
|
||||
# 登录取 token
|
||||
TOKEN=$(curl -s -X POST http://localhost:8000/api/auth/login -H "Content-Type: application/json" -d '{"username":"admin","password":"admin"}' | jq -r .access_token)
|
||||
# 当前用户
|
||||
curl -s -H "Authorization: Bearer $TOKEN" http://localhost:8000/api/auth/me
|
||||
```
|
||||
38
docs/stage3.md
Normal file
38
docs/stage3.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# 阶段 3:管理后台闭环页面结构 + 后端占位 API
|
||||
|
||||
## 页面结构(Next.js 路由)
|
||||
|
||||
- **/dashboard**:总览占位(统计卡片:会话总数、工单总数、当前用户)
|
||||
- **/sessions**:会话列表(表格:ID、外部用户ID、昵称、状态、创建时间、操作)
|
||||
- **/sessions/[id]**:会话详情(消息列表 + 创建工单按钮 + 回复输入框占位)
|
||||
- **/tickets**:工单列表(表格:ID、会话、原因、状态、创建时间、操作)
|
||||
- **/kb**:知识库(上传拖拽区 + 文档列表表格)
|
||||
- **/settings**:模型/策略设置(表单:模型名称、FAQ 优先、启用 RAG)
|
||||
- **/users**:用户管理(仅管理员可见,表格 + 新建/删除)
|
||||
|
||||
## 后端 API(统一 code/data/message/trace_id,需 JWT)
|
||||
|
||||
- **GET /api/admin/sessions**:会话列表
|
||||
- **GET /api/admin/sessions/{id}**:会话详情(含消息列表)
|
||||
- **GET /api/admin/tickets**:工单列表
|
||||
- **POST /api/admin/tickets**:创建工单(body: session_id, reason)
|
||||
- **PATCH /api/admin/tickets/{id}**:更新工单(body: status, reason)
|
||||
- **GET /api/admin/kb/docs**:知识库文档列表
|
||||
- **POST /api/admin/kb/docs/upload**:上传文档(multipart/form-data)
|
||||
- **GET /api/admin/settings**:获取设置
|
||||
- **PATCH /api/admin/settings**:更新设置(body: model_name, strategy)
|
||||
- **GET /api/admin/users**:用户列表(仅管理员)
|
||||
- **POST /api/admin/users**:创建用户(仅管理员)
|
||||
- **PATCH /api/admin/users/{id}**:更新用户(仅管理员)
|
||||
- **DELETE /api/admin/users/{id}**:删除用户(仅管理员)
|
||||
|
||||
## 前端 API Client
|
||||
|
||||
- **admin/lib/api.ts**:统一封装 `adminApi<T>()`,自动带 Bearer token,返回 `ApiRes<T>`(code/data/message/trace_id)
|
||||
- 所有函数返回 `Promise<ApiRes<T>>`,401 时自动清除 token
|
||||
|
||||
## 验证
|
||||
|
||||
1. 登录后应看到顶部导航:总览 | 会话列表 | 工单列表 | 知识库 | 设置 | 用户管理
|
||||
2. 各页面应能正常加载并显示占位数据(表格、卡片、表单等)
|
||||
3. 用户管理页面:非管理员访问应提示「仅管理员可访问」;管理员可看到用户列表并可新建/删除
|
||||
544
docs/wecom-test-guide.md
Normal file
544
docs/wecom-test-guide.md
Normal file
@@ -0,0 +1,544 @@
|
||||
# 企业微信回调功能测试详细流程
|
||||
|
||||
## 一、前置准备
|
||||
|
||||
### 1.1 检查服务状态
|
||||
|
||||
```bash
|
||||
# 检查所有服务是否运行
|
||||
docker compose ps
|
||||
|
||||
# 应该看到:
|
||||
# - ai-db-1 (Running)
|
||||
# - ai-backend-1 (Running)
|
||||
# - ai-admin-1 (Running,可选)
|
||||
```
|
||||
|
||||
### 1.2 检查后端日志
|
||||
|
||||
```bash
|
||||
# 查看后端最新日志,确认无错误
|
||||
docker compose logs backend --tail 50
|
||||
|
||||
# 应该看到:
|
||||
# INFO: Uvicorn running on http://0.0.0.0:8000
|
||||
# INFO: Application startup complete.
|
||||
```
|
||||
|
||||
### 1.3 配置环境变量
|
||||
|
||||
编辑 `.env` 文件,确保以下企业微信相关配置已填写:
|
||||
|
||||
```bash
|
||||
# 企业微信配置(必须)
|
||||
WECOM_CORP_ID=你的企业ID # 从"我的企业 → 企业信息"获取
|
||||
WECOM_AGENT_ID=你的应用AgentId # 从"自建应用 → 应用详情"获取
|
||||
WECOM_SECRET=你的应用Secret # 从"自建应用 → 应用详情"获取(可选,用于主动发送消息)
|
||||
WECOM_TOKEN=你的Token # 自定义字符串,需与企微后台一致
|
||||
WECOM_ENCODING_AES_KEY=你的43位密钥 # 从企微后台获取,43位Base64编码
|
||||
WECOM_API_BASE=https://qyapi.weixin.qq.com
|
||||
WECOM_API_TIMEOUT=10
|
||||
WECOM_API_RETRIES=2
|
||||
```
|
||||
|
||||
**重要提示**:
|
||||
- `WECOM_TOKEN` 和 `WECOM_ENCODING_AES_KEY` 必须与企微后台配置**完全一致**
|
||||
- `WECOM_ENCODING_AES_KEY` 是 43 位 Base64 编码字符串(不含等号)
|
||||
|
||||
### 1.4 重启后端服务(如果修改了 .env)
|
||||
|
||||
```bash
|
||||
# 重启后端以加载新的环境变量
|
||||
docker compose restart backend
|
||||
|
||||
# 等待几秒后检查日志
|
||||
docker compose logs backend --tail 20
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、企业微信后台配置
|
||||
|
||||
### 2.1 获取必要参数
|
||||
|
||||
1. **登录企业微信管理后台**:https://work.weixin.qq.com
|
||||
|
||||
2. **获取企业 ID (CorpId)**:
|
||||
- 进入 **我的企业** → **企业信息**
|
||||
- 复制 **企业 ID**,填入 `.env` 的 `WECOM_CORP_ID`
|
||||
|
||||
3. **获取应用信息**:
|
||||
- 进入 **应用管理** → **自建应用** → 选择你的应用
|
||||
- 在 **应用详情** 中获取:
|
||||
- **AgentId**:填入 `.env` 的 `WECOM_AGENT_ID`
|
||||
- **Secret**:填入 `.env` 的 `WECOM_SECRET`(可选)
|
||||
|
||||
### 2.2 配置回调 URL(关键步骤)
|
||||
|
||||
1. **进入接收消息设置**:
|
||||
- 在应用详情页面,找到 **接收消息** 或 **API接收**
|
||||
- 点击 **设置 API 接收** 或 **配置回调URL**
|
||||
|
||||
2. **填写回调配置**:
|
||||
- **接收消息服务器 URL**:`https://你的公网域名/api/wecom/callback`
|
||||
- 本地测试:使用 ngrok 等工具暴露本地服务(见下方)
|
||||
- 生产环境:使用你的实际域名
|
||||
- **Token**:填写一个自定义字符串(例如:`my_wecom_token_2025`)
|
||||
- **重要**:这个 Token 必须与 `.env` 中的 `WECOM_TOKEN` **完全一致**
|
||||
- **EncodingAESKey**:
|
||||
- 点击 **随机获取** 或手动输入 43 位 Base64 编码字符串
|
||||
- **重要**:这个密钥必须与 `.env` 中的 `WECOM_ENCODING_AES_KEY` **完全一致**
|
||||
- **消息加解密方式**:选择 **安全模式**(推荐)或 **明文模式**(仅测试)
|
||||
|
||||
3. **保存配置**:
|
||||
- 点击 **保存** 按钮
|
||||
- 企业微信会立即发送 GET 请求到你的回调 URL 进行校验
|
||||
- 如果配置正确,会显示 **保存成功** ✅
|
||||
|
||||
---
|
||||
|
||||
## 三、本地测试方法
|
||||
|
||||
### 方法 1:使用 Cloudflare Tunnel(推荐 ⭐⭐⭐⭐⭐)
|
||||
|
||||
Cloudflare Tunnel (cloudflared) 提供免费的固定域名,比 ngrok 更稳定。
|
||||
|
||||
#### 3.1 安装 cloudflared
|
||||
|
||||
**Windows(使用 Scoop)**:
|
||||
```powershell
|
||||
# 安装 Scoop(如果还没有)
|
||||
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
|
||||
irm get.scoop.sh | iex
|
||||
|
||||
# 安装 cloudflared
|
||||
scoop install cloudflared
|
||||
```
|
||||
|
||||
**或使用 Chocolatey**:
|
||||
```powershell
|
||||
choco install cloudflared
|
||||
```
|
||||
|
||||
**或手动下载**:
|
||||
- 访问:https://github.com/cloudflare/cloudflared/releases
|
||||
- 下载 `cloudflared-windows-amd64.exe`,重命名为 `cloudflared.exe`
|
||||
|
||||
#### 3.2 启动 cloudflared
|
||||
|
||||
```powershell
|
||||
# 在项目根目录运行(暴露本地 8000 端口)
|
||||
cloudflared tunnel --url http://localhost:8000
|
||||
```
|
||||
|
||||
**输出示例**:
|
||||
```
|
||||
2025-02-05T10:00:00Z INF +--------------------------------------------------------------------------------------------+
|
||||
2025-02-05T10:00:00Z INF | Your quick Tunnel has been created! Visit it at: |
|
||||
2025-02-05T10:00:00Z INF | https://abc123-def456-ghi789.trycloudflare.com |
|
||||
2025-02-05T10:00:00Z INF +--------------------------------------------------------------------------------------------+
|
||||
```
|
||||
|
||||
#### 3.3 获取公网 URL
|
||||
|
||||
从输出中复制 `https://xxx.trycloudflare.com`,这就是你的公网 URL。
|
||||
|
||||
**注意**:
|
||||
- 这个 URL 在本次运行期间是固定的
|
||||
- 关闭 cloudflared 后,URL 会失效
|
||||
- 如需固定域名,请登录 Cloudflare 创建命名 tunnel(见 `docs/cloudflared-setup.md`)
|
||||
|
||||
#### 3.4 配置企微后台
|
||||
|
||||
在企微后台的回调 URL 中填写:`https://你的cloudflared域名.trycloudflare.com/api/wecom/callback`
|
||||
|
||||
例如:`https://abc123-def456-ghi789.trycloudflare.com/api/wecom/callback`
|
||||
|
||||
#### 3.5 保存并验证
|
||||
|
||||
1. 点击 **保存**
|
||||
2. 观察后端日志:
|
||||
```bash
|
||||
docker compose logs backend -f
|
||||
```
|
||||
3. 应该看到:
|
||||
```
|
||||
INFO: wecom verify success {"trace_id": "...", "echostr_length": 43}
|
||||
```
|
||||
4. 企微后台应显示 **保存成功**
|
||||
|
||||
**详细文档**:参见 `docs/cloudflared-setup.md`
|
||||
|
||||
---
|
||||
|
||||
### 方法 2:使用 ngrok 暴露本地服务
|
||||
|
||||
#### 2.1 安装 ngrok
|
||||
|
||||
- **Windows**:下载 https://ngrok.com/download,解压到任意目录
|
||||
- **或使用包管理器**:`choco install ngrok` 或 `scoop install ngrok`
|
||||
|
||||
#### 2.2 启动 ngrok
|
||||
|
||||
```bash
|
||||
# 在终端中运行(暴露本地 8000 端口)
|
||||
ngrok http 8000
|
||||
|
||||
# 输出示例:
|
||||
# Forwarding https://abc123.ngrok.io -> http://localhost:8000
|
||||
```
|
||||
|
||||
#### 2.3 获取公网 URL
|
||||
|
||||
从 ngrok 输出中复制 `https://xxx.ngrok.io`,这就是你的公网 URL。
|
||||
|
||||
**注意**:免费版 ngrok 每次重启 URL 都会变化,需要重新配置企微后台。
|
||||
|
||||
#### 2.4 配置企微后台
|
||||
|
||||
在企微后台的回调 URL 中填写:`https://你的ngrok域名.ngrok.io/api/wecom/callback`
|
||||
|
||||
例如:`https://abc123.ngrok.io/api/wecom/callback`
|
||||
|
||||
#### 2.5 保存并验证
|
||||
|
||||
1. 点击 **保存**
|
||||
2. 观察后端日志:
|
||||
```bash
|
||||
docker compose logs backend -f
|
||||
```
|
||||
3. 应该看到:
|
||||
```
|
||||
INFO: wecom verify success {"trace_id": "...", "echostr_length": 43}
|
||||
```
|
||||
4. 企微后台应显示 **保存成功**
|
||||
|
||||
---
|
||||
|
||||
### 方法 2:使用企业微信官方测试工具
|
||||
|
||||
1. 在企业微信管理后台,进入 **自建应用** → **接收消息** → **调试工具**
|
||||
2. 输入测试参数,生成测试请求
|
||||
3. 使用 curl 或 Postman 发送请求到本地服务
|
||||
|
||||
---
|
||||
|
||||
## 四、测试消息回调
|
||||
|
||||
### 4.1 发送测试消息
|
||||
|
||||
1. **在企业微信中**:
|
||||
- 打开企业微信客户端
|
||||
- 找到你配置的应用
|
||||
- 发送一条文本消息,例如:`你好,测试一下`
|
||||
|
||||
### 4.2 查看后端日志
|
||||
|
||||
```bash
|
||||
# 实时查看日志
|
||||
docker compose logs backend -f
|
||||
|
||||
# 应该看到以下日志:
|
||||
```
|
||||
|
||||
**收到消息日志**:
|
||||
```json
|
||||
{
|
||||
"timestamp": "2025-02-05T10:00:00Z",
|
||||
"level": "INFO",
|
||||
"message": "wecom message received",
|
||||
"trace_id": "abc123-def456",
|
||||
"external_userid": "wmxxxxx",
|
||||
"msgid": "1234567890",
|
||||
"msg_type": "text",
|
||||
"content_summary": "你好,测试一下"
|
||||
}
|
||||
```
|
||||
|
||||
**发送回复日志**:
|
||||
```json
|
||||
{
|
||||
"timestamp": "2025-02-05T10:00:01Z",
|
||||
"level": "INFO",
|
||||
"message": "wecom reply sent",
|
||||
"trace_id": "abc123-def456",
|
||||
"external_userid": "wmxxxxx",
|
||||
"msgid": "1234567890",
|
||||
"reply_summary": "已收到:你好,测试一下"
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 验证回复消息
|
||||
|
||||
在企业微信客户端中,应该收到回复:**`已收到:你好,测试一下`**
|
||||
|
||||
### 4.4 检查数据库
|
||||
|
||||
```bash
|
||||
# 进入数据库容器
|
||||
docker compose exec db psql -U wecom -d wecom_ai
|
||||
|
||||
# 查询会话
|
||||
SELECT id, external_user_id, external_name, status, created_at
|
||||
FROM chat_sessions
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 5;
|
||||
|
||||
# 查询消息
|
||||
SELECT id, session_id, role, content, created_at
|
||||
FROM messages
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 10;
|
||||
|
||||
# 应该看到:
|
||||
# - 一条会话记录(external_user_id 为你的企微用户ID)
|
||||
# - 两条消息记录(一条 user,一条 assistant)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、完整测试检查清单
|
||||
|
||||
### 5.1 配置检查
|
||||
|
||||
- [ ] `.env` 文件中所有企业微信配置已填写
|
||||
- [ ] `WECOM_TOKEN` 与企微后台一致
|
||||
- [ ] `WECOM_ENCODING_AES_KEY` 与企微后台一致(43位)
|
||||
- [ ] `WECOM_CORP_ID` 已填写
|
||||
- [ ] 后端服务正常运行
|
||||
|
||||
### 5.2 GET 校验测试
|
||||
|
||||
- [ ] 在企微后台点击保存配置
|
||||
- [ ] 后端日志显示 `wecom verify success`
|
||||
- [ ] 企微后台显示 **保存成功**
|
||||
|
||||
### 5.3 POST 回调测试
|
||||
|
||||
- [ ] 在企业微信中发送文本消息
|
||||
- [ ] 后端日志显示 `wecom message received`
|
||||
- [ ] 后端日志显示 `wecom reply sent`
|
||||
- [ ] 企业微信中收到回复消息
|
||||
- [ ] 数据库中创建了会话记录
|
||||
- [ ] 数据库中创建了消息记录(user + assistant)
|
||||
|
||||
---
|
||||
|
||||
## 六、常见问题排查
|
||||
|
||||
### 问题 1:GET 校验失败
|
||||
|
||||
**症状**:企微后台显示"保存失败"或"URL校验失败"
|
||||
|
||||
**排查步骤**:
|
||||
|
||||
1. **检查 Token**:
|
||||
```bash
|
||||
# 查看 .env 中的 WECOM_TOKEN
|
||||
cat .env | grep WECOM_TOKEN
|
||||
|
||||
# 确保与企微后台完全一致(包括大小写、空格等)
|
||||
```
|
||||
|
||||
2. **检查 EncodingAESKey**:
|
||||
```bash
|
||||
# 查看 .env 中的 WECOM_ENCODING_AES_KEY
|
||||
cat .env | grep WECOM_ENCODING_AES_KEY
|
||||
|
||||
# 确保是 43 位 Base64 编码(不含等号)
|
||||
# 确保与企微后台完全一致
|
||||
```
|
||||
|
||||
3. **检查后端日志**:
|
||||
```bash
|
||||
docker compose logs backend | grep "wecom verify"
|
||||
|
||||
# 如果看到 "wecom verify failed",检查签名或解密错误
|
||||
```
|
||||
|
||||
4. **检查回调 URL**:
|
||||
- 确保 URL 可公网访问(使用 ngrok 等工具)
|
||||
- 确保 URL 格式正确:`https://域名/api/wecom/callback`
|
||||
- 确保后端服务正常运行
|
||||
|
||||
**解决方案**:
|
||||
- 重新检查并同步 Token 和 EncodingAESKey
|
||||
- 确保回调 URL 可访问
|
||||
- 重启后端服务:`docker compose restart backend`
|
||||
|
||||
---
|
||||
|
||||
### 问题 2:POST 回调失败
|
||||
|
||||
**症状**:发送消息后没有收到回复,或后端日志显示错误
|
||||
|
||||
**排查步骤**:
|
||||
|
||||
1. **检查后端日志**:
|
||||
```bash
|
||||
docker compose logs backend | grep -E "wecom|error|Error"
|
||||
```
|
||||
|
||||
2. **检查解密错误**:
|
||||
- 如果看到 `wecom decrypt error`,检查 `WECOM_ENCODING_AES_KEY` 是否正确
|
||||
- 如果看到 `wecom xml parse failed`,检查 XML 格式
|
||||
|
||||
3. **检查企业 ID**:
|
||||
```bash
|
||||
# 确保 WECOM_CORP_ID 正确
|
||||
cat .env | grep WECOM_CORP_ID
|
||||
```
|
||||
|
||||
4. **检查数据库连接**:
|
||||
```bash
|
||||
# 确保数据库服务正常运行
|
||||
docker compose ps db
|
||||
|
||||
# 检查数据库连接
|
||||
docker compose exec backend python -c "from app.database import engine; print('DB OK')"
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
- 检查并修复配置错误
|
||||
- 重启后端服务
|
||||
- 检查数据库连接
|
||||
|
||||
---
|
||||
|
||||
### 问题 3:收到消息但没有回复
|
||||
|
||||
**症状**:后端日志显示收到消息,但企业微信中没有收到回复
|
||||
|
||||
**排查步骤**:
|
||||
|
||||
1. **检查回复日志**:
|
||||
```bash
|
||||
docker compose logs backend | grep "wecom reply sent"
|
||||
|
||||
# 如果没有这条日志,说明回复构造或加密失败
|
||||
```
|
||||
|
||||
2. **检查回复 XML 格式**:
|
||||
- 查看后端代码中的 `build_reply_xml` 函数
|
||||
- 确保 XML 格式符合企业微信规范
|
||||
|
||||
3. **检查加密**:
|
||||
- 确保 `WECOM_ENCODING_AES_KEY` 正确
|
||||
- 确保 `WECOM_CORP_ID` 正确(用于加密验证)
|
||||
|
||||
**解决方案**:
|
||||
- 检查回复 XML 构造逻辑
|
||||
- 检查加密函数
|
||||
- 查看完整错误日志
|
||||
|
||||
---
|
||||
|
||||
### 问题 4:URL 变化问题
|
||||
|
||||
**症状**:每次重启内网穿透工具,URL 都会变化
|
||||
|
||||
**解决方案**:
|
||||
- **使用 Cloudflare Tunnel**:登录后可以创建固定域名的 tunnel(推荐)
|
||||
- **使用 ngrok**:每次重启后需要重新在企微后台更新回调 URL
|
||||
- **使用 ngrok 付费版**:可以设置固定域名
|
||||
- **其他工具**:frp、localtunnel 等(参见 `docs/cloudflared-setup.md`)
|
||||
|
||||
---
|
||||
|
||||
## 七、高级测试
|
||||
|
||||
### 7.1 测试不同类型的消息
|
||||
|
||||
- **文本消息**:发送普通文本
|
||||
- **图片消息**:发送图片(当前实现可能只回复"收到")
|
||||
- **事件消息**:测试关注/取消关注等事件
|
||||
|
||||
### 7.2 测试并发消息
|
||||
|
||||
- 同时发送多条消息
|
||||
- 检查数据库是否正确记录所有消息
|
||||
- 检查回复是否正确
|
||||
|
||||
### 7.3 测试错误处理
|
||||
|
||||
- 发送格式错误的消息
|
||||
- 检查错误日志
|
||||
- 确保服务不会崩溃
|
||||
|
||||
---
|
||||
|
||||
## 八、测试完成后
|
||||
|
||||
### 8.1 验证数据完整性
|
||||
|
||||
```bash
|
||||
# 检查会话和消息数据
|
||||
docker compose exec db psql -U wecom -d wecom_ai -c "
|
||||
SELECT
|
||||
cs.id as session_id,
|
||||
cs.external_user_id,
|
||||
cs.external_name,
|
||||
COUNT(m.id) as message_count,
|
||||
MAX(m.created_at) as last_message_time
|
||||
FROM chat_sessions cs
|
||||
LEFT JOIN messages m ON cs.id = m.session_id
|
||||
GROUP BY cs.id
|
||||
ORDER BY cs.created_at DESC;
|
||||
"
|
||||
```
|
||||
|
||||
### 8.2 清理测试数据(可选)
|
||||
|
||||
```bash
|
||||
# 删除测试数据
|
||||
docker compose exec db psql -U wecom -d wecom_ai -c "
|
||||
DELETE FROM messages;
|
||||
DELETE FROM chat_sessions;
|
||||
"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、下一步
|
||||
|
||||
完成阶段 4 测试后,可以继续:
|
||||
|
||||
- **阶段 5**:接入 FAQ 匹配
|
||||
- **阶段 6**:接入 RAG 检索
|
||||
- **阶段 7**:实现工单转人工流程
|
||||
|
||||
---
|
||||
|
||||
## 十、快速测试命令汇总
|
||||
|
||||
```bash
|
||||
# 1. 检查服务状态
|
||||
docker compose ps
|
||||
|
||||
# 2. 查看后端日志
|
||||
docker compose logs backend -f
|
||||
|
||||
# 3. 检查环境变量
|
||||
docker compose exec backend env | grep WECOM
|
||||
|
||||
# 4. 启动 Cloudflare Tunnel(推荐)
|
||||
cloudflared tunnel --url http://localhost:8000
|
||||
|
||||
# 5. 测试本地健康检查
|
||||
curl http://localhost:8000/api/health
|
||||
|
||||
# 6. 测试公网健康检查(替换为你的 cloudflared URL)
|
||||
curl https://你的域名.trycloudflare.com/api/health
|
||||
|
||||
# 7. 检查数据库
|
||||
docker compose exec db psql -U wecom -d wecom_ai -c "SELECT * FROM chat_sessions;"
|
||||
|
||||
# 8. 重启服务
|
||||
docker compose restart backend
|
||||
```
|
||||
|
||||
**详细 Cloudflare Tunnel 配置**:参见 `docs/cloudflared-setup.md`
|
||||
|
||||
---
|
||||
|
||||
**提示**:如果遇到问题,请先查看后端日志,大多数问题都会在日志中显示错误信息。
|
||||
193
docs/wecom-test.md
Normal file
193
docs/wecom-test.md
Normal file
@@ -0,0 +1,193 @@
|
||||
# 企业微信回调本地测试指南
|
||||
|
||||
## 前置条件
|
||||
|
||||
1. 已配置企业微信后台(Token、EncodingAESKey、回调 URL)
|
||||
2. 已配置 `.env` 文件中的企业微信相关参数
|
||||
3. 后端服务已启动:`docker compose up -d backend`
|
||||
|
||||
## 测试方法
|
||||
|
||||
### 方法 1:使用企业微信官方测试工具(推荐)
|
||||
|
||||
企业微信提供了在线测试工具,可以模拟回调请求:
|
||||
|
||||
1. 访问企业微信管理后台
|
||||
2. 进入 **自建应用** → **接收消息** → **调试工具**
|
||||
3. 输入测试参数,生成测试请求
|
||||
4. 使用 curl 或 Postman 发送请求到本地服务
|
||||
|
||||
### 方法 2:使用 ngrok 暴露本地服务
|
||||
|
||||
1. **安装 ngrok**:https://ngrok.com/
|
||||
|
||||
2. **启动 ngrok**:
|
||||
```bash
|
||||
ngrok http 8000
|
||||
```
|
||||
|
||||
3. **获取公网 URL**:例如 `https://abc123.ngrok.io`
|
||||
|
||||
4. **配置企微后台**:
|
||||
- 回调 URL:`https://abc123.ngrok.io/api/wecom/callback`
|
||||
- Token 和 EncodingAESKey 与 `.env` 一致
|
||||
|
||||
5. **保存配置**:企微会自动发送 GET 请求校验
|
||||
|
||||
6. **发送测试消息**:在企业微信中向应用发送消息
|
||||
|
||||
### 方法 3:手动构造测试请求(高级)
|
||||
|
||||
**注意**:需要真实的签名和加密数据,通常从企微后台的实际请求中获取。
|
||||
|
||||
#### GET 请求测试
|
||||
|
||||
```bash
|
||||
curl -X GET "http://localhost:8000/api/wecom/callback?msg_signature=xxx×tamp=xxx&nonce=xxx&echostr=xxx"
|
||||
```
|
||||
|
||||
**预期响应**:返回解密后的 `echostr` 明文
|
||||
|
||||
#### POST 请求测试
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8000/api/wecom/callback?msg_signature=xxx×tamp=xxx&nonce=xxx" \
|
||||
-H "Content-Type: application/xml" \
|
||||
-d '<xml><Encrypt><![CDATA[加密后的消息XML]]></Encrypt></xml>'
|
||||
```
|
||||
|
||||
**预期响应**:返回加密后的回复 XML
|
||||
|
||||
## 验证步骤
|
||||
|
||||
### 1. 检查 GET 校验日志
|
||||
|
||||
```bash
|
||||
docker compose logs backend | grep "wecom verify"
|
||||
```
|
||||
|
||||
**成功日志示例**:
|
||||
```json
|
||||
{
|
||||
"level": "INFO",
|
||||
"message": "wecom verify success",
|
||||
"trace_id": "abc123",
|
||||
"echostr_length": 43
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 检查 POST 回调日志
|
||||
|
||||
```bash
|
||||
docker compose logs backend | grep "wecom message"
|
||||
```
|
||||
|
||||
**成功日志示例**:
|
||||
```json
|
||||
{
|
||||
"level": "INFO",
|
||||
"message": "wecom message received",
|
||||
"trace_id": "abc123",
|
||||
"external_userid": "wmxxxxx",
|
||||
"msgid": "1234567890",
|
||||
"msg_type": "text",
|
||||
"content_summary": "你好,我想咨询一下..."
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"level": "INFO",
|
||||
"message": "wecom reply sent",
|
||||
"trace_id": "abc123",
|
||||
"external_userid": "wmxxxxx",
|
||||
"msgid": "1234567890",
|
||||
"reply_summary": "已收到:你好,我想咨询一下..."
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 检查数据库
|
||||
|
||||
```bash
|
||||
# 进入数据库容器
|
||||
docker compose exec db psql -U wecom -d wecom_ai
|
||||
|
||||
# 查询会话
|
||||
SELECT id, external_user_id, status, created_at FROM chat_sessions;
|
||||
|
||||
# 查询消息
|
||||
SELECT id, session_id, role, content, created_at FROM messages ORDER BY created_at DESC LIMIT 10;
|
||||
```
|
||||
|
||||
### 4. 在企业微信中验证
|
||||
|
||||
- 发送消息后,应收到回复:`已收到:{你发送的消息}`
|
||||
- 如果未收到回复,检查后端日志中的错误信息
|
||||
|
||||
## 常见错误排查
|
||||
|
||||
### 错误 1:GET 校验失败
|
||||
|
||||
**日志**:`wecom verify failed`
|
||||
|
||||
**可能原因**:
|
||||
- Token 不匹配
|
||||
- EncodingAESKey 不匹配
|
||||
- 签名计算错误
|
||||
|
||||
**解决方法**:
|
||||
1. 检查 `.env` 中的 `WECOM_TOKEN` 是否与企微后台一致
|
||||
2. 检查 `.env` 中的 `WECOM_ENCODING_AES_KEY` 是否与企微后台一致(43 位,不含等号)
|
||||
3. 确认回调 URL 可公网访问
|
||||
|
||||
### 错误 2:POST 解密失败
|
||||
|
||||
**日志**:`wecom decrypt error`
|
||||
|
||||
**可能原因**:
|
||||
- EncodingAESKey 错误
|
||||
- 加密数据格式错误
|
||||
- 企业 ID 不匹配
|
||||
|
||||
**解决方法**:
|
||||
1. 检查 `WECOM_ENCODING_AES_KEY` 是否正确
|
||||
2. 检查 `WECOM_CORP_ID` 是否正确(用于验证解密后的企业 ID)
|
||||
|
||||
### 错误 3:XML 解析失败
|
||||
|
||||
**日志**:`wecom xml parse failed`
|
||||
|
||||
**可能原因**:
|
||||
- XML 格式错误
|
||||
- 字符编码问题
|
||||
|
||||
**解决方法**:
|
||||
1. 检查解密后的 XML 格式是否正确
|
||||
2. 确认 XML 使用 UTF-8 编码
|
||||
|
||||
### 错误 4:回复未收到
|
||||
|
||||
**可能原因**:
|
||||
- 回复 XML 格式错误
|
||||
- 回复加密错误
|
||||
- 网络问题
|
||||
|
||||
**解决方法**:
|
||||
1. 检查日志中是否有 `wecom reply sent` 记录
|
||||
2. 检查回复 XML 格式是否正确
|
||||
3. 检查加密后的回复是否正确
|
||||
|
||||
## 测试检查清单
|
||||
|
||||
- [ ] GET 校验成功(企微后台显示"保存成功")
|
||||
- [ ] POST 回调日志正常(收到消息和发送回复都有日志)
|
||||
- [ ] 数据库中有会话和消息记录
|
||||
- [ ] 企业微信中能收到回复消息
|
||||
- [ ] 日志中包含 trace_id、external_userid、msgid、content_summary
|
||||
|
||||
## 下一步
|
||||
|
||||
完成阶段 4 测试后,可以继续:
|
||||
- 阶段 5:接入 FAQ 匹配
|
||||
- 阶段 6:接入 RAG 检索
|
||||
- 阶段 7:实现工单转人工流程
|
||||
243
docs/wecom.md
Normal file
243
docs/wecom.md
Normal file
@@ -0,0 +1,243 @@
|
||||
# 企业微信回调配置与联调说明
|
||||
|
||||
## 一、企业微信后台配置
|
||||
|
||||
### 1. 获取必要参数
|
||||
|
||||
在企业微信管理后台(https://work.weixin.qq.com)获取以下参数:
|
||||
|
||||
| 参数 | 获取位置 | 说明 |
|
||||
|------|---------|------|
|
||||
| **企业 ID (CorpId)** | 我的企业 → 企业信息 | 企业唯一标识 |
|
||||
| **Token** | 自建应用 → 接收消息 → 设置 | 自定义字符串,用于签名校验 |
|
||||
| **EncodingAESKey** | 自建应用 → 接收消息 → 设置 | 43 位 Base64 编码的 AES 密钥(自动生成或手动输入) |
|
||||
| **AgentId** | 自建应用 → 应用详情 | 应用 ID |
|
||||
| **Secret** | 自建应用 → 应用详情 | 应用密钥(用于主动发送消息,当前阶段可选) |
|
||||
|
||||
### 2. 配置回调 URL
|
||||
|
||||
1. 进入 **自建应用** → 选择你的应用 → **接收消息**
|
||||
2. 点击 **设置 API 接收**
|
||||
3. 填写以下信息:
|
||||
- **接收消息服务器 URL**:`https://你的域名/api/wecom/callback`
|
||||
- **Token**:填写你自定义的 Token(需与 `.env` 中的 `WECOM_TOKEN` 一致)
|
||||
- **EncodingAESKey**:填写 43 位密钥(需与 `.env` 中的 `WECOM_ENCODING_AES_KEY` 一致)
|
||||
- **消息加解密方式**:选择 **安全模式**(推荐)或 **明文模式**(仅用于测试)
|
||||
|
||||
### 3. 保存配置
|
||||
|
||||
点击 **保存** 后,企业微信会立即发送 GET 请求到你的回调 URL 进行校验。如果配置正确,会显示 **保存成功**。
|
||||
|
||||
---
|
||||
|
||||
## 二、本地环境变量配置
|
||||
|
||||
在 `.env` 文件中配置以下变量:
|
||||
|
||||
```bash
|
||||
# 企业微信配置
|
||||
WECOM_CORP_ID=你的企业ID
|
||||
WECOM_AGENT_ID=你的应用AgentId
|
||||
WECOM_SECRET=你的应用Secret(可选,当前阶段用于主动发送消息)
|
||||
WECOM_TOKEN=你的Token(需与企微后台一致)
|
||||
WECOM_ENCODING_AES_KEY=你的43位EncodingAESKey(需与企微后台一致)
|
||||
WECOM_API_BASE=https://qyapi.weixin.qq.com
|
||||
WECOM_API_TIMEOUT=10
|
||||
WECOM_API_RETRIES=2
|
||||
```
|
||||
|
||||
**重要**:
|
||||
- `WECOM_TOKEN` 和 `WECOM_ENCODING_AES_KEY` 必须与企微后台配置完全一致
|
||||
- `WECOM_CORP_ID` 用于加密回复时验证企业身份
|
||||
|
||||
---
|
||||
|
||||
## 三、回调机制说明
|
||||
|
||||
### GET 请求(URL 校验)
|
||||
|
||||
企业微信在保存配置时会发送 GET 请求:
|
||||
|
||||
```
|
||||
GET /api/wecom/callback?msg_signature=xxx×tamp=xxx&nonce=xxx&echostr=xxx
|
||||
```
|
||||
|
||||
**处理流程**:
|
||||
1. 使用 `msg_signature`、`timestamp`、`nonce`、`echostr` 验签
|
||||
2. 解密 `echostr` 得到明文
|
||||
3. 将明文原样返回
|
||||
|
||||
**成功响应**:返回解密后的 `echostr` 明文(纯文本)
|
||||
|
||||
### POST 请求(消息回调)
|
||||
|
||||
客户发送消息时,企业微信会发送 POST 请求:
|
||||
|
||||
```
|
||||
POST /api/wecom/callback?msg_signature=xxx×tamp=xxx&nonce=xxx
|
||||
Content-Type: application/xml
|
||||
|
||||
<xml>
|
||||
<Encrypt><![CDATA[加密后的消息]]></Encrypt>
|
||||
</xml>
|
||||
```
|
||||
|
||||
**处理流程**:
|
||||
1. 解析 XML,提取 `Encrypt` 节点
|
||||
2. 使用 `msg_signature`、`timestamp`、`nonce`、`Encrypt` 验签
|
||||
3. 解密 `Encrypt` 得到消息 XML
|
||||
4. 解析消息(`MsgType`、`Content`、`FromUserName`、`MsgId` 等)
|
||||
5. 记录日志(trace_id + external_userid + msgid + 内容摘要)
|
||||
6. 创建/更新会话,保存消息到数据库
|
||||
7. 构造回复 XML(当前为 echo:`已收到:{用户消息}`)
|
||||
8. 加密回复 XML
|
||||
9. 返回加密后的 XML 响应
|
||||
|
||||
**成功响应**:返回加密后的 XML(被动回复)
|
||||
|
||||
```xml
|
||||
<xml>
|
||||
<Encrypt><![CDATA[加密后的回复]]></Encrypt>
|
||||
<MsgSignature><![CDATA[签名]]></MsgSignature>
|
||||
<TimeStamp>时间戳</TimeStamp>
|
||||
<Nonce><![CDATA[随机字符串]]></Nonce>
|
||||
</xml>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、加解密说明
|
||||
|
||||
### 安全模式(推荐)
|
||||
|
||||
- **加密算法**:AES-256-CBC
|
||||
- **填充方式**:PKCS7
|
||||
- **签名算法**:SHA1
|
||||
|
||||
**加密格式**:
|
||||
```
|
||||
[16字节随机数][4字节消息长度][消息内容][企业ID][PKCS7填充]
|
||||
```
|
||||
|
||||
**解密流程**:
|
||||
1. Base64 解码
|
||||
2. AES-CBC 解密
|
||||
3. 提取消息长度(第 16-20 字节)
|
||||
4. 按长度提取消息内容
|
||||
5. 验证尾部企业 ID
|
||||
|
||||
### 明文模式(仅测试)
|
||||
|
||||
如果选择明文模式,企业微信会直接发送未加密的 XML,但**不推荐用于生产环境**。
|
||||
|
||||
**切换到明文模式**:
|
||||
1. 在企微后台将 **消息加解密方式** 改为 **明文模式**
|
||||
2. 代码中需要修改 `wecom.py`,跳过解密步骤,直接解析 XML(当前实现仅支持安全模式)
|
||||
|
||||
---
|
||||
|
||||
## 五、本地联调测试
|
||||
|
||||
### 1. 启动服务
|
||||
|
||||
```bash
|
||||
# 确保后端服务运行
|
||||
docker compose up -d backend
|
||||
|
||||
# 查看日志
|
||||
docker compose logs backend -f
|
||||
```
|
||||
|
||||
### 2. 使用 curl 测试 GET 校验(模拟企微)
|
||||
|
||||
**注意**:实际测试需要真实的签名和加密数据。以下为示例格式:
|
||||
|
||||
```bash
|
||||
# 需要先获取真实的签名和 echostr(从企微后台保存配置时的请求中获取)
|
||||
curl -X GET "http://localhost:8000/api/wecom/callback?msg_signature=xxx×tamp=xxx&nonce=xxx&echostr=xxx"
|
||||
```
|
||||
|
||||
**预期响应**:返回解密后的 `echostr` 明文
|
||||
|
||||
### 3. 使用 curl 测试 POST 回调(模拟企微)
|
||||
|
||||
**注意**:需要真实的加密 XML。可以从企微后台的实际回调请求中获取,或使用企业微信官方测试工具。
|
||||
|
||||
```bash
|
||||
# 示例格式(需要替换为真实的加密 XML)
|
||||
curl -X POST "http://localhost:8000/api/wecom/callback?msg_signature=xxx×tamp=xxx&nonce=xxx" \
|
||||
-H "Content-Type: application/xml" \
|
||||
-d '<xml><Encrypt><![CDATA[加密后的消息XML]]></Encrypt></xml>'
|
||||
```
|
||||
|
||||
**预期响应**:返回加密后的回复 XML
|
||||
|
||||
### 4. 真实环境测试
|
||||
|
||||
1. **配置回调 URL**:将你的公网域名配置到企微后台(如使用 ngrok 等工具暴露本地服务)
|
||||
2. **保存配置**:在企微后台点击保存,观察 GET 请求是否成功
|
||||
3. **发送测试消息**:在企业微信中向应用发送一条文本消息
|
||||
4. **查看日志**:检查后端日志,应看到:
|
||||
```
|
||||
INFO: wecom message received {"trace_id": "...", "external_userid": "...", "msgid": "...", "content_summary": "..."}
|
||||
INFO: wecom reply sent {"trace_id": "...", "external_userid": "...", "msgid": "...", "reply_summary": "..."}
|
||||
```
|
||||
5. **验证回复**:在企业微信中应收到回复消息:`已收到:{你发送的消息}`
|
||||
|
||||
---
|
||||
|
||||
## 六、日志格式
|
||||
|
||||
所有回调请求都会记录结构化日志,包含以下字段:
|
||||
|
||||
- **trace_id**:请求追踪 ID
|
||||
- **external_userid**:外部用户 ID(客户 ID)
|
||||
- **msgid**:消息 ID
|
||||
- **msg_type**:消息类型(text/image/event 等)
|
||||
- **content_summary**:消息内容摘要(前 50 字符)
|
||||
- **reply_summary**:回复内容摘要(前 50 字符)
|
||||
|
||||
**示例日志**:
|
||||
```json
|
||||
{
|
||||
"timestamp": "2025-02-05T10:00:00Z",
|
||||
"level": "INFO",
|
||||
"message": "wecom message received",
|
||||
"trace_id": "abc123",
|
||||
"external_userid": "wmxxxxx",
|
||||
"msgid": "1234567890",
|
||||
"msg_type": "text",
|
||||
"content_summary": "你好,我想咨询一下产品信息..."
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、常见问题
|
||||
|
||||
### 1. GET 校验失败
|
||||
|
||||
- **检查 Token**:确保 `.env` 中的 `WECOM_TOKEN` 与企微后台一致
|
||||
- **检查 EncodingAESKey**:确保 `.env` 中的 `WECOM_ENCODING_AES_KEY` 与企微后台一致(43 位,不含等号)
|
||||
- **检查 URL**:确保回调 URL 可公网访问
|
||||
|
||||
### 2. POST 回调失败
|
||||
|
||||
- **检查签名**:确保 `msg_signature` 校验通过
|
||||
- **检查解密**:确保 `WECOM_ENCODING_AES_KEY` 正确
|
||||
- **检查企业 ID**:确保 `WECOM_CORP_ID` 正确(用于验证解密后的企业 ID)
|
||||
|
||||
### 3. 回复未收到
|
||||
|
||||
- **检查日志**:查看是否有错误日志
|
||||
- **检查数据库**:确认消息是否已入库
|
||||
- **检查 XML 格式**:确保回复 XML 格式正确
|
||||
- **检查加密**:确保回复加密正确
|
||||
|
||||
---
|
||||
|
||||
## 八、下一步(阶段 5+)
|
||||
|
||||
- 接入企业微信主动发送消息 API(需要 `WECOM_SECRET` 获取 access_token)
|
||||
- 实现 FAQ 匹配和 RAG 检索
|
||||
- 实现工单转人工流程
|
||||
Reference in New Issue
Block a user