zijunchiang 75498db1c0 feat(web): 部署方式由 Docker 改为 Linux 原生站点(nginx + systemd)
需求变更:Web 服务端不再使用 Docker,改为直接运行在 Linux 上的网站。

- 移除 deploy/docker-compose.yml、web-server/Dockerfile、
  web-server/admin/Dockerfile、web-server/.dockerignore
- 新增 deploy/install.sh:建服务用户与目录 → 装运行期依赖 → 迁移
  → 注册 systemd 服务 → 配置 nginx 站点 → 健康检查,一键完成
- 新增 deploy/systemd/opendance-api.service:ProtectSystem=strict 等
  安全加固,ReadWritePaths 限定为上传目录
- 新增 deploy/nginx/opendance.conf:同站点托管管理端静态资源 +
  反代 /api /health /static,client_max_body_size 512m,SPA 回退
- 新增 deploy/uninstall.sh:默认保留数据,--purge 才删除
- 新增配置项 HOST(AppConfig.bindHost):原生部署下 Node 只监听
  127.0.0.1,不直接对外暴露,实测外部 IP 不可达
- 同步更新 contracts/rest-api.yaml、DSH.md、project.yaml、README.txt、
  tasks/008、tasks/010 与发布打包脚本
2026-09-14 22:42:56 +08:00

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
================================================================
OpenDance Studio —— Web 管理服务端 v0.1.0  使用说明
================================================================

本服务端是 OpenDance Studio 三端中的第一端,负责管理歌曲、VRM 模型与
动作来源,是 Windows 客户端与 Android 辅助 App 的唯一数据源与契约权威。

重要:本服务端 **不部署、不管理 MySQL**。数据库为部署方提供的现有实例,
连接信息通过 .env 注入。

----------------------------------------------------------------
一、部署到 Linux 服务器(原生站点,不使用 Docker)
----------------------------------------------------------------

部署形态:一个 nginx 站点同时提供管理端页面与 API。
Node 进程由 systemd 托管,只监听 127.0.0.1,外部只能经 nginx 访问。

前置要求
  - Linux 服务器(Debian/Ubuntu 或 RHEL 系均可),有 root 权限
  - Node.js 22 或更高版本
  - nginx(未安装时脚本会跳过站点配置并给出提示)
  - 一个可连通的现有 MySQL / MariaDB 实例,并已创建数据库与账号:

      CREATE DATABASE IF NOT EXISTS dpendance
        CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
      CREATE USER IF NOT EXISTS 'dpendance'@'%' IDENTIFIED BY '<密码>';
      GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX, DROP, REFERENCES
        ON dpendance.* TO 'dpendance'@'%';
      FLUSH PRIVILEGES;

  (本项目不会创建数据库本身,也不需要 GRANT OPTION / FILE / SUPER 等管理权限)

部署步骤
  tar -xzf opendance-web-v0.1.0.tar.gz
  cd opendance-web-v0.1.0
  cp deploy/.env.example deploy/.env
  vi deploy/.env          # 填写 DB_HOST / DB_PORT / DB_USER / DB_PASS / DB_NAME
  sudo bash deploy/install.sh

脚本会依次:
  校验环境与 .env → 创建服务用户与目录 → 安装运行期依赖 →
  执行 TypeORM 迁移 → 注册并启动 systemd 服务 → 等待健康检查 →
  配置 nginx 站点并重载

部署完成后(<host> 为服务器 IP)
  管理端首页: http://<host>/
  API 前缀:   http://<host>/api
  健康检查:   http://<host>/health
  契约快照:   http://<host>/contracts/

可覆盖的安装参数
  APP_DIR=/opt/opendance                 程序目录
  SERVICE_USER=opendance                 运行服务的系统用户
  STORAGE_DIR=/var/lib/opendance/storage 上传文件目录
  SERVER_NAME=example.com                nginx server_name
  SKIP_NGINX=1                           只装 API 服务,不配置 nginx

  例:sudo SERVER_NAME=dance.example.com bash deploy/install.sh

升级
  解压新版本后重新执行 sudo bash deploy/install.sh 即可(会覆盖程序文件,
  保留 deploy/.env 与上传数据)。

卸载
  sudo bash deploy/uninstall.sh           # 停服务、禁用站点,保留数据
  sudo bash deploy/uninstall.sh --purge   # 一并删除程序目录与上传文件

  数据库始终由部署方自行管理,卸载脚本不做任何改动。

常用命令
  systemctl status opendance-api      # 服务状态
  journalctl -u opendance-api -f      # 实时日志
  systemctl restart opendance-api     # 重启
  nginx -t && systemctl reload nginx  # 校验并重载 nginx

----------------------------------------------------------------
二、本地开发
----------------------------------------------------------------

后端
  cd web-server
  cp .env.example .env    # 填写 DB_*
  npm install
  npm run migration:run   # 首次需要
  npm run start:dev       # http://localhost:3000

管理前端
  cd web-server/admin
  npm install
  npm run dev             # http://localhost:5173(/api 与 /health 代理到 3000)

----------------------------------------------------------------
三、验证
----------------------------------------------------------------

  cd web-server
  npm run contracts:check   # 契约版本一致性
  npm run typecheck         # TypeScript 严格检查
  npm run test              # 31 项单元测试
  npm run build             # 生产构建
  npm run start:prod &      # 启动
  npm run test:smoke        # 57 项端到端冒烟(需要数据库可连通)

  cd ../admin && npm run build   # 管理端构建

----------------------------------------------------------------
四、环境变量
----------------------------------------------------------------

  DB_HOST / DB_PORT / DB_USER / DB_PASS / DB_NAME
      现有 MySQL 实例连接信息(必填)

  DB_SYNCHRONIZE
      必须为 false。生产环境启动时若检测到 true 会直接中止启动。
      所有表结构变更通过 TypeORM migration 执行。

  DB_LOGGING            是否打印 SQL(默认 false)
  PORT                  API 监听端口(默认 3000)
  HOST                  API 监听地址(原生部署用 127.0.0.1,仅由 nginx 反代访问)
  STORAGE_DIR           上传文件存储目录(原生部署默认 /var/lib/opendance/storage)
  UPLOAD_MAX_BYTES      单文件上限,默认 536870912(512 MiB)
  ASSIMP_BIN            可选:Assimp 可执行文件,FBX/glTF 动作预处理需要
  CONTRACTS_DIR         可选:契约目录,设置后 /health 反映实时契约版本
                        (原生部署默认指向 /opt/opendance/contracts)

----------------------------------------------------------------
五、主要 API
----------------------------------------------------------------

  GET    /health                              健康检查(含数据库连通性)
  GET    /api/songs                           曲目列表(分页 / 检索)
  POST   /api/songs                           新建曲目
  GET    /api/songs/:id                       曲目详情
  PATCH  /api/songs/:id                       更新曲目
  DELETE /api/songs/:id                       删除曲目(软删除)
  POST   /api/songs/:id/audio                 上传音频
  GET    /api/motions                         动作列表
  POST   /api/motions                         上传动作 + 来源信息
  POST   /api/motions/:id/preprocess          BVH/FBX → MediaPipe33 关键点
  GET    /api/motions/:id/keypoints           下载关键点序列(NDJSON)
  GET    /api/models                          模型列表
  POST   /api/models                          上传模型 + 来源信息(VRM 优先)
  POST   /api/models/:id/primary              设为全局默认模型
  GET    /api/reviews                         审核流水 / 待审列表
  POST   /api/reviews/:type/:id/approve       审核通过
  POST   /api/reviews/:type/:id/reject        审核驳回(必须填意见)
  GET    /api/catalog/export                  客户端一次性拉取已发布目录
  GET    /api/catalog/version                 契约版本 + 目录指纹

完整契约(OpenAPI 3.0)见 contracts/rest-api.yaml。

上传文件通过 /static/<kind>/<yyyy>/<mm>/<sha256>.ext 访问,
相同内容只落盘一次(sha256 去重)。

----------------------------------------------------------------
六、目录结构
----------------------------------------------------------------

  project.yaml            任务清单与状态
  DSH.md                  本项目 DSH 执行约束
  tasks/                  单任务说明书(T-WEB-001 ~ 010)
  contracts/              跨端契约(权威,改接口先改这里)
  web-server/             NestJS 服务端源码
  web-server/admin/       React 管理端
  deploy/                 Linux 原生站点部署(nginx + systemd,不含 MySQL)
  THIRD_PARTY.md          第三方开源项目声明

----------------------------------------------------------------
七、安全提示
----------------------------------------------------------------

1. .env 已被 .gitignore 忽略,禁止提交;仓库中只保留 .env.example。
2. 数据库账号使用最小权限,不授予 GRANT OPTION / FILE / SUPER。
3. 本版本未内置管理端登录认证,请部署在内网,或在 nginx 层加 Basic Auth / SSO。
4. 上传的模型与动作必须填写来源五元组并通过审核后才对客户端可见。
5. 未使用 SMPL 拓扑,统一 MediaPipe 33 点,规避非商用许可限制。

----------------------------------------------------------------
八、第三方开源声明
----------------------------------------------------------------

见 THIRD_PARTY.md,或访问站点 http://<host>/ 的「关于」页面。
S
Description
OpenDance Studio - opendance-web
Readme
1.5 MiB
2026-09-18 03:03:50 +08:00
Languages
TypeScript 80.3%
Shell 9.3%
JavaScript 7.4%
CSS 2.3%
Python 0.6%