Document vconsole visibility rules (SYS_TESTER label / SYS_CAN_SUDO tag), existing debug data injection patterns, and the norm for inserting new debug data in frontend (console.warn + localStorage), backend (tracing), and database fixtures. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
8.3 KiB
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/
E2E 测试流程(新功能开发标准流程)
为节约 CI 资源、加快迭代速度,新功能开发采用 先本地验证,再推送 CI 的流程:
- 本地开发 & 编译 —
cargo check确保无编译错误 - 部署测试服 (moicen) —
git push→ SSH 登录 moicen →git pull→cargo build --release - 本地发起 e2e 测试 — 在本地运行 e2e 测试套件,请求指向 moicen 测试服
- 验证通过后推送 CI —
git push origin master→ GitHub Actions 自动运行cargo check+ 全量 e2e - 部署正式服 (alchemy) — SSH 登录 alchemy →
git pull→cargo build --release→ 重启服务 - 正式服 CI smoke test — 部署后立即触发 GitHub Actions 的 prod smoke test workflow,验证正式服 API 响应正常。若 smoke test 失败,立即回滚并排查
Why: 大部分问题在步骤 2-3 就能发现,避免反复触发 CI 浪费排队时间和 GitHub Actions 配额。
E2E 调试原则
排查不了的 E2E 问题时,可以往前后端插入 debug 数据辅助排查。
vConsole(小程序前端调试面板)
- 打开条件:用户有
SYS_CAN_SUDOtag(root 标签)或角色上有SYS_TESTERlabel → 自动显示 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 中新增步骤运行即可。
部署原则
禁止使用 scp/rsync 部署代码。 所有部署必须走 GitHub push → 服务器 git pull 的流程。
# 本地
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 工作流确保二进制与代码一致、依赖已解析、构建可重复。
前端部署提醒:必须上传静态资源到又拍云 CDN
cp_dist_huiwing.sh / cp_dist_moicen.sh 已自动包含又拍云上传步骤。
严禁只手动 sudo cp 而不上传 CDN。HTML 中的 JS/CSS 链接指向 static.* CDN 域名(又拍云),而非 nginx 本地目录。若只拷贝到 nginx,JS 会返回 404,页面为空白白屏。
# 正确:执行完整部署脚本
sh cp_dist_huiwing.sh
# 错误(从仓库复制到 nginx 但跳过 CDN,会导致白屏)
sudo cp -r dist/* /usr/local/openresty/nginx/html/music-room/
手动修复白屏:
cd /mnt/huiwing/huike-front/cdn
sh upload_assets.sh .huiwing_upyun_pass 1
htyproc (Task Processor)
启动流程
cd /path/to/huike-back/htyproc
bash start.sh
启动后 proc server 默认处于 PENDING 状态,不会处理任务。需要调用 API 切换为 RUNNING:
# 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,可手动重置重新处理:
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。
# 错误
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 隧道命令
# 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 可用性
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}