2026-05-01 00:36:45 +08:00
|
|
|
|
# huike-back 项目指南
|
|
|
|
|
|
|
|
|
|
|
|
## 服务器标识
|
|
|
|
|
|
|
|
|
|
|
|
| 环境 | 服务器 | SSH 用户 | 说明 |
|
|
|
|
|
|
|------|--------|----------|------|
|
|
|
|
|
|
| **正式服 (production)** | `alchemy-studio.cn` (152.136.103.69, CentOS 8) | `alchemy`(`sudo -u alchemy` 或 `sudo su - alchemy`) | 线上生产环境 |
|
|
|
|
|
|
| **测试服 (test)** | `moicen.com` (101.43.244.164, Ubuntu 24.04) | `weli` | 测试验证环境 |
|
|
|
|
|
|
|
|
|
|
|
|
**正式服 = alchemy,测试服 = moicen,不要搞混。**
|
|
|
|
|
|
|
|
|
|
|
|
### 正式服 (alchemy) 部署要点
|
|
|
|
|
|
- 所有服务以 `alchemy` 用户运行(`sudo -u alchemy -H bash`)
|
|
|
|
|
|
- 代码路径:`/mnt/huiwing/huike-back/`(新版本拆分仓库,非旧 monorepo)
|
|
|
|
|
|
- AuthCore 路径:`/mnt/huiwing/AuthCore/`
|
|
|
|
|
|
- 旧 monorepo (`/mnt/huiwing/huiwing/`) 已由拆分仓库替代,Java 服务已全部下线
|
|
|
|
|
|
|
|
|
|
|
|
### 测试服 (moicen) 部署要点
|
|
|
|
|
|
- 代码路径:`/home/weli/works/huike-back/`
|
|
|
|
|
|
- AuthCore 路径:`/home/weli/works/AuthCore/`
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-05-01 21:10:09 +08:00
|
|
|
|
## E2E 测试流程(新功能开发标准流程)
|
|
|
|
|
|
|
|
|
|
|
|
为节约 CI 资源、加快迭代速度,新功能开发采用 **先本地验证,再推送 CI** 的流程:
|
|
|
|
|
|
|
|
|
|
|
|
1. **本地开发 & 编译** — `cargo check` 确保无编译错误
|
|
|
|
|
|
2. **部署测试服 (moicen)** — `git push` → SSH 登录 moicen → `git pull` → `cargo build --release`
|
|
|
|
|
|
3. **本地发起 e2e 测试** — 在本地运行 e2e 测试套件,请求指向 moicen 测试服
|
|
|
|
|
|
4. **验证通过后推送 CI** — `git push origin master` → GitHub Actions 自动运行 `cargo check` + 全量 e2e
|
|
|
|
|
|
5. **部署正式服 (alchemy)** — SSH 登录 alchemy → `git pull` → `cargo build --release` → 重启服务
|
|
|
|
|
|
6. **正式服 CI smoke test** — 部署后立即触发 GitHub Actions 的 prod smoke test workflow,验证正式服 API 响应正常。若 smoke test 失败,立即回滚并排查
|
|
|
|
|
|
|
|
|
|
|
|
**Why:** 大部分问题在步骤 2-3 就能发现,避免反复触发 CI 浪费排队时间和 GitHub Actions 配额。
|
|
|
|
|
|
|
2026-05-02 10:38:12 +08:00
|
|
|
|
## E2E 调试原则
|
|
|
|
|
|
|
|
|
|
|
|
排查不了的 E2E 问题时,可以往前后端插入 debug 数据辅助排查。
|
|
|
|
|
|
|
|
|
|
|
|
### vConsole(小程序前端调试面板)
|
|
|
|
|
|
|
|
|
|
|
|
- **打开条件**:用户有 `SYS_CAN_SUDO` tag(root 标签)或角色上有 `SYS_TESTER` label → 自动显示 vConsole 面板
|
|
|
|
|
|
- **实现位置**:`huike-front/src/App.vue` → `watch(() => store.current)`
|
|
|
|
|
|
- **使用方式**:打开 vConsole 后,可在 Console 面板查看 `console.warn` / `console.log` 输出,Storage 面板查看 `localStorage` 数据
|
|
|
|
|
|
|
|
|
|
|
|
### 已有 debug 数据注入模式
|
|
|
|
|
|
|
|
|
|
|
|
项目中已存在以下 debug 注入模式,可直接复用:
|
|
|
|
|
|
|
|
|
|
|
|
| 模式 | 注入位置 | 查看方式 |
|
|
|
|
|
|
|------|----------|----------|
|
|
|
|
|
|
| `window.__cp_debug` | `pick.vue`、`add.vue`(课包相关) | vConsole Console 输入 `__cp_debug` |
|
|
|
|
|
|
| `localStorage.setItem("OrgSwitchDebug", ...)` | `store/org.ts` | vConsole Storage 面板 |
|
|
|
|
|
|
| `localStorage.setItem("ClazzPayloadDebug", ...)` | `store/clazz.ts` | vConsole Storage 面板 |
|
|
|
|
|
|
| `localStorage.setItem("CourseSectionPayloadDebug", ...)` | `store/qumu-section.ts` | vConsole Storage 面板 |
|
|
|
|
|
|
| `console.warn("[OrgSwitchDebug]", ...)` | `store/org.ts` | vConsole Console 面板 |
|
|
|
|
|
|
|
|
|
|
|
|
### 插入新 debug 数据的规范
|
|
|
|
|
|
|
|
|
|
|
|
**前端**:参考已有模式,用 `console.warn("[TagName]", data)` + `window.__tagName = data` 或 `localStorage.setItem("TagName", JSON.stringify(data))` 注入。vConsole 自动捕获 console 输出。
|
|
|
|
|
|
|
|
|
|
|
|
**后端(Rust)**:用 `tracing::warn!("[TagName] {:?}", data)` 或 `tracing::info!(...)` 打印关键中间数据。日志会出现在服务启动的 nohup 输出(`/tmp/htykc.log` / `/tmp/htyuc.log`)以及 CI 的收尾日志步骤中。
|
|
|
|
|
|
|
|
|
|
|
|
**数据库**:可在 `huike-unit/ci/fixtures/` 下添加 SQL fixture 文件,插入特定测试数据。在 `e2e.yml` 中新增步骤运行即可。
|
|
|
|
|
|
|
2026-05-01 00:36:45 +08:00
|
|
|
|
## 部署原则
|
|
|
|
|
|
|
|
|
|
|
|
**禁止使用 scp/rsync 部署代码。** 所有部署必须走 GitHub push → 服务器 git pull 的流程。
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 本地
|
|
|
|
|
|
git push
|
|
|
|
|
|
|
|
|
|
|
|
# 服务器
|
|
|
|
|
|
ssh <server>
|
|
|
|
|
|
cd /path/to/repo
|
|
|
|
|
|
git pull --ff-only
|
|
|
|
|
|
cargo build --release # 后端
|
|
|
|
|
|
# 或 sh cp_dist_moicen.sh / cp_dist_huiwing.sh # 前端
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
如果服务器缺少对应仓库,先在服务器上用 `git clone` 克隆,而不是从本机传文件。
|
|
|
|
|
|
|
|
|
|
|
|
**Why:** 二进制/构建产物拷贝绕过构建系统,会引入静默的架构或链接不匹配问题。git 工作流确保二进制与代码一致、依赖已解析、构建可重复。
|
|
|
|
|
|
|
2026-05-01 15:38:40 +08:00
|
|
|
|
### 前端部署提醒:必须上传静态资源到又拍云 CDN
|
|
|
|
|
|
|
|
|
|
|
|
`cp_dist_huiwing.sh` / `cp_dist_moicen.sh` 已自动包含又拍云上传步骤。
|
|
|
|
|
|
|
|
|
|
|
|
**严禁**只手动 `sudo cp` 而不上传 CDN。HTML 中的 JS/CSS 链接指向 `static.*` CDN 域名(又拍云),而非 nginx 本地目录。若只拷贝到 nginx,JS 会返回 404,页面为空白白屏。
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 正确:执行完整部署脚本
|
|
|
|
|
|
sh cp_dist_huiwing.sh
|
|
|
|
|
|
|
|
|
|
|
|
# 错误(从仓库复制到 nginx 但跳过 CDN,会导致白屏)
|
|
|
|
|
|
sudo cp -r dist/* /usr/local/openresty/nginx/html/music-room/
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
手动修复白屏:
|
|
|
|
|
|
```bash
|
|
|
|
|
|
cd /mnt/huiwing/huike-front/cdn
|
|
|
|
|
|
sh upload_assets.sh .huiwing_upyun_pass 1
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-05-01 00:36:45 +08:00
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## htyproc (Task Processor)
|
|
|
|
|
|
|
|
|
|
|
|
### 启动流程
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
cd /path/to/huike-back/htyproc
|
|
|
|
|
|
bash start.sh
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
启动后 proc server 默认处于 **PENDING** 状态,不会处理任务。需要调用 API 切换为 RUNNING:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# proc server 默认 PENDING,必须手动 start
|
|
|
|
|
|
curl -s 'http://127.0.0.1:3004/api/v1/proc/start'
|
|
|
|
|
|
|
|
|
|
|
|
# 检查状态
|
|
|
|
|
|
curl -s 'http://127.0.0.1:3004/api/v1/proc/status'
|
|
|
|
|
|
# → {"r":true,"d":"RUNNING",...}
|
|
|
|
|
|
|
|
|
|
|
|
# 停止
|
|
|
|
|
|
curl -s 'http://127.0.0.1:3004/api/v1/proc/stop'
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**注意**:`/api/v1/proc/start` 是 GET 方法(不是 POST),路由定义在 `htyproc/src/proc_api.rs`。
|
|
|
|
|
|
|
|
|
|
|
|
重启后必须手动调用 start 才能恢复任务处理。
|
|
|
|
|
|
|
|
|
|
|
|
### 重置 FAILED 任务为 PENDING
|
|
|
|
|
|
|
|
|
|
|
|
若任务因临时故障(如 AI API 不可用)标记为 FAILED,可手动重置重新处理:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
ssh moicen
|
|
|
|
|
|
sudo -u postgres psql -d htytask_moicen -c "UPDATE dbtack SET task_status='PENDING', updated_at=NOW(), updated_by='manual_reset' WHERE task_id='<task_id>';"
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
确保 proc 为 RUNNING 状态后,等待 WAIT_SEC(默认 5s)即可自动拾取。
|
|
|
|
|
|
|
|
|
|
|
|
### NGX_URL 配置陷阱
|
|
|
|
|
|
|
|
|
|
|
|
`.env` 中 `NGX_URL` 不要包含 `/api/ngx` 后缀 — 代码 `clients.rs:98` 会拼接 `/api/ngx/audio/convert`,两者叠加会变成双 `/api/ngx/api/ngx/` 路径,导致 OpenResty 返回 405。
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 错误
|
|
|
|
|
|
NGX_URL=https://admin.huiwings.cn/api/ngx
|
|
|
|
|
|
|
|
|
|
|
|
# 正确
|
|
|
|
|
|
NGX_URL=https://admin.huiwings.cn
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 日志
|
|
|
|
|
|
|
|
|
|
|
|
日志文件:`htyproc/htyproc.nohup.log`,受 logrotate 管理。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## AI API 网络架构
|
|
|
|
|
|
|
|
|
|
|
|
### 架构说明
|
|
|
|
|
|
|
|
|
|
|
|
AI API(Flask,端口 5000)部署在独立的 AI 服务器上(Mac mini 192.168.0.115),Flask 运行在 **Podman 容器** 内,通过 NPS + SSH 隧道穿透访问:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
AI Server Podman container(port 5000)
|
|
|
|
|
|
→ Podman gvproxy(port 5000)
|
|
|
|
|
|
→ Mac host(port 5000)
|
|
|
|
|
|
→ NPS client → NPS server alchemy:10001
|
|
|
|
|
|
→ alchemy(port 5000 via SSH -L)
|
|
|
|
|
|
→ moicen(port 5000 via SSH -L)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
- **穿透链路**:本机 → `ssh weli@alchemy-studio.cn` → `ssh -p 10001 weli@localhost`(经 NPS 隧道)→ Mac → `/usr/local/bin/podman exec ai-api`
|
|
|
|
|
|
- **容器信息**:`localhost/ai-api:latest`,端口映射 `5000→5000/tcp`、`5909→5901/tcp`、`2222→22/tcp`
|
|
|
|
|
|
- **便捷工具**:`plan_skills/tools/huiwing-ai-api`(一键执行容器命令,无需逐层 SSH)
|
|
|
|
|
|
- **详细文档**:见 `plan_skills/moicen/moicen-access-ai-api-container.md`
|
|
|
|
|
|
|
|
|
|
|
|
### SSH 隧道命令
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# alchemy 上的隧道(由 tmux ai-tunnel 守护,自动重连)
|
|
|
|
|
|
tmux new-session -d -s ai-tunnel 'while true; do sleep 3; ssh -L 5909:localhost:5909 -L 5000:localhost:5000 weli@localhost -p 10001; done'
|
|
|
|
|
|
|
|
|
|
|
|
# moicen 到 alchemy 转发
|
|
|
|
|
|
ssh -L 5000:localhost:5000 weli@alchemy-studio.cn
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### OpenResty 反向代理
|
|
|
|
|
|
|
|
|
|
|
|
两台服务器的 OpenResty 都配置了 `ai.conf`,将 `https://ai.<domain>/api/v1/ai/*` 代理到 `http://127.0.0.1:5000/`(注意尾部 / 会剥离 `/api/v1/ai` 前缀)。
|
|
|
|
|
|
|
|
|
|
|
|
Flask 路由实际路径(无前缀):
|
|
|
|
|
|
- `/form_image_compress_audit` — 图片压缩审计
|
|
|
|
|
|
- `/compare` — AI 评分对比
|
|
|
|
|
|
- 等
|
|
|
|
|
|
|
|
|
|
|
|
### 验证 AI API 可用性
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
curl -s 'https://ai.moicen.com/api/v1/ai/form_image_compress_audit' \
|
|
|
|
|
|
-X POST -H 'Content-Type: application/json' \
|
|
|
|
|
|
-H 'HtySudoerToken: test' -H 'HtyHost: ts.moicen.com' \
|
|
|
|
|
|
-d '{"url":"https://test.com/test.jpg"}'
|
|
|
|
|
|
# → {"d":{"acknowledged":true},"e":null,"r":true}
|
|
|
|
|
|
```
|