vdi-cloud/docs/cloud-platform-development.md

10 KiB
Raw Blame History

云端服务与控制台开发说明

更新:2026-11-09。当前交付是第一阶段本地可运行版本。Vue 控制台通过真实 HTTP 调用 Go API,账号、授权、设备、任务和审计保存在 PostgreSQL;演示 VM 的电源操作由明确标记的演示计算适配执行。本文件主要描述演示开发环境;随后已接通独立真实环境,控制台端口 5182、设备 HTTPS 8443。

启动

Windows 本机开发

需要 Node.js 22.12+、Go 1.25+、Docker Desktop。仓库根目录执行:

.\tools\start-cloud-dev.ps1

已安装前端依赖时可加 -SkipInstall。脚本启动专用 PostgreSQL 容器,编译并启动本机 API,再启动 Vite。默认控制台地址 http://127.0.0.1:5180,API 地址 http://127.0.0.1:8088,数据库仅映射本机 55438。可用 -ApiPort 和 -ConsolePort 改开发端口。不会停止其他占用端口的程序。

演示账号 admin、operator、viewer,统一演示密码 Demo@2026。对应超级管理员、运维、只读角色,仅 VDI_MODE=demo 会创建这些账号。首次数据库初始化后,重新启动保留业务数据。

进程 PID 和日志在忽略提交的 .local/ 中。关闭本机开发进程时根据 .local/cloud-dev.json 确认 PID 和命令路径,只停止本次启动的 API 与 Vite。数据库可通过 docker compose -f deploy/compose.dev.yml stop postgres 停止;不删除卷即可保留数据。

全容器开发

与本机模式二选一,避免占用同一端口:

docker compose -f deploy/compose.dev.yml up --build -d

控制台仍是 http://127.0.0.1:5180。Nginx 代理同源 /api 到 Go 服务,PostgreSQL 使用命名卷。该 compose 是开发演示配置,不是客户生产部署包。

端口被其他开发进程占用时,可先设置 $env:VDI_CONSOLE_PORT='5181'、$env:VDI_API_PORT='8089' 再执行 compose。当前本机验收使用该端口组合,预览地址为 http://127.0.0.1:5181。

仅前端模拟

cd console
npm ci
$env:VITE_API_MODE='mock'
npm run dev

MSW 在浏览器层模拟 HTTP,只有开发构建允许启用,不需要 Go 或数据库。模拟操作不控制真实资源,刷新页面会重置模拟业务数据。正常的 api 模式不注册模拟 Worker。

当前可用范围

模块 当前实现
登录 bcrypt 密码校验、JWT、服务端会话记录、退出撤销、刷新页面恢复、三角色服务端授权
总览 终端在线、VM 电源、实际画面就绪连接、异常任务;连接预约单独记录
计算资源 节点列表;配置 PVE 后每 30 秒同步节点/已纳管 VM,显示同步时间与过期标记
桌面 演示桌面;发现 PVE VM、纳管、查看详情、开机/正常关机/重启;PVE UPID 跟踪
终端 管理员登记、一次性激活、设备独立令牌、心跳、桌面授权列表、命令领取与回执
授权 创建最终使用者、每设备关联一位使用者、每使用者多个桌面、停用和撤销后阻止新连接
任务 持久化排队/执行/成功/失败/结果未确认、请求去重、同对象任务互斥、最终回执审计
连接契约 短期单次票据、终端隔离、消费时重新校验授权、同桌面活动占用检查

当前连接票据仅授权并返回 Moonlight 端点与参数;终端仍需既有 Sunshine 配对。消费票据登记连接预约,不证明串流已建立;现场 Qt 已上报实际画面就绪与进程结束事件,详情见真实接入说明。不要把 credentialMode=existing-pairing 当作免配对认证。

本轮将 API 入口与基础业务模块放在一个可运行的 Go 网关进程中,数据库和 Proxmox client 独立封装。原方案的七个服务职责继续作为后续拆分边界;当前尚未交付七个独立部署的服务。MQTT 总线、Rust Agent、VictoriaMetrics 指标接入、模板发放、桌面池、GPU 绑定、OTA、AD/LDAP 尚未完成;Qt 适配现已实际部署。控制台仅显示已接通的第一阶段功能。

真实 Proxmox 接入

使用新的独立数据库,按 platform/.env.example 注入配置。正式模式要求至少 32 字符的 JWT 密钥、管理员账号和至少 12 字符的初始密码。管理员环境变量仅在账号首次创建时生效,不会在每次启动时覆盖已有密码。数据库记录初始化模式,拒绝直接混用演示与正式数据库。

VDI_MODE=production
DATABASE_URL=postgres://.../vdi?sslmode=require
VDI_JWT_SECRET=...
VDI_ADMIN_USERNAME=...
VDI_ADMIN_PASSWORD=...
PVE_URL=https://pve.example.internal:8006
PVE_TOKEN_ID=vdi@pve!console
PVE_TOKEN_SECRET=...
PVE_CA_FILE=/run/secrets/pve-ca.pem

PVE 凭据由后端持有,前端和终端不会接收;证书校验始终开启。PVE_URL 只填 HTTPS origin,不附 /api2/json。由运维给 API Token 配置实际需要的节点/VM/存储查询和 VM 电源操作权限。本轮不自动修改 PVE 账号、ACL、VM 或主机配置。

启动后到“计算资源”手动同步;再到“桌面管理”选择“纳管已有 VM”。纳管仅登记已存在的 VM,不改 VM 配置。连接地址可在纳管表单填写。首次真实接入应使用专门测试 VM 核验 API 版本、证书、任务结果和关机行为,再对业务 VM 开放操作。

正式环境的 HTTPS 入口、运维凭据轮换、账号维护、登录限流、独立数据库迁移流程与备份恢复仍属于部署产品化工作;当前 compose 不作生产就绪声明。

设备接口联调

接口契约在 docs/openapi/platform.v1.json,API 根路径 /api/v1。控制台通过生成的类型和统一请求适配调用接口,页面不拼接 API 地址。

  1. 管理员在终端页登记 SN,取得仅显示一次的 activationSecret。
  2. 终端 POST /terminal/register 提交 SN、activationSecret、agentVersion,取得设备令牌;激活密钥随即作废。
  3. 设备以独立 Authorization: Bearer <device-token> 发送心跳、拉配置和获取授权桌面。
  4. 管理员创建用户并关联终端、勾选多个桌面;设备再次请求 /terminal/desktops 即获得更新列表。
  5. 设备轮询 GET /terminal/commands 领取命令,执行后 POST /terminal/commands/{id}/ack 报告 success/failed。没有回执的命令约两分钟后显示结果未确认;不会自动重放。
  6. 申请 /terminal/connect-ticket,再用 /terminal/connect-ticket/consume 单次消费;消费时再次检查授权与桌面占用。之后仍使用已有 Moonlight/Sunshine 配对。

tools/platform-terminal-simulator.py --sn <SN> 可在本机演示平台注册、发心跳和读取授权桌面。激活密钥通过交互输入或 VDI_DEVICE_ACTIVATION_SECRET 传入;模拟器对所有设备操作回失败,避免假装执行了重启或日志收集。它不是可部署的 Rust Agent。

当前 HTTPS 轮询是 MQTT 接入前的可验证通道;没有声称已提供消息总线。终端令牌的撤销/重新激活、配置热更新将继续扩展契约;Qt 串流事件、固定命令执行和诊断日志上传已在真实环境接通。

检查命令

cd console
npm run lint
npm run typecheck
npm run test
npm run build
npm run test:e2e
npm run api:generate

E2E 使用已经启动的本机平台,只允许对 /healthz 返回 demo 模式的服务运行;Windows 默认使用已安装的 Edge。其他环境使用 npx playwright install chromium 准备测试浏览器。VDI_E2E_URL 可覆盖测试地址。测试会创建演示用户和待激活终端、切换演示 VM 电源,不会操作真实 PVE。

cd platform
go test ./...
go vet ./...

数据库集成测试需要 VDI_TEST_DATABASE_URL 指向专用可清空测试数据库。测试会清空该数据库内平台表,不要指向开发业务库或生产库。

docker exec vdi-cloud-dev-postgres-1 psql -U vdi -d postgres -c 'CREATE DATABASE vdi_test'
$env:VDI_TEST_DATABASE_URL='postgres://vdi:vdi-local-demo@127.0.0.1:55438/vdi_test?sslmode=disable'
go test ./...

后端测试覆盖服务端 RBAC、JWT 退出失效、幂等任务、授权变更事务回滚、设备隔离、一次性票据、回执和超时;PVE client 使用本地测试服务器验证 TLS 和 UPID,不向现场 PVE 发送请求。

本轮验收记录(2026-11-09)

  • Go 单元测试、专用 PostgreSQL 集成测试和 go vet 通过;包含模式隔离、重启后撤权保留、PVE 明确失败与提交结果未确认的区分。
  • 前端 ESLint、TypeScript、3 项登录状态单元测试和生产构建通过。
  • 容器版 http://127.0.0.1:5181 的 7 项 Playwright 用例全部通过:登录失败/恢复/退出、桌面命令最终结果、用户多桌面授权持久化、终端激活信息、两种权限角色、空列表/异常/401。
  • 单独启动 MSW 模式,验证模拟登录和授权页导航;检查 1440px 桌面及 390px 窄屏。
  • 页面截图:总览、桌面管理、窄屏。页面主题集中在 console/src/styles/tokens.css,可交给 UI 同事继续调整。
  • Node 依赖完整审计为 0 项已知漏洞。Vitest 已更新;TypeScript ESLint 的 minimatch 子依赖定向覆盖至 11.0.1+,静态检查通过。
  • Docker API/控制台镜像构建并启动,数据库保留卷内已有业务数据。未向现场 PVE 或盒子发送操作。

数据与执行边界

  • 在线按最近 90 秒心跳计算;FPS/RTT 缺失为 null,不填 0。PVE 电源状态与 VM 内连接服务状态分开。
  • 任务成功必须有计算适配结果或设备回执。提交后发生通信异常时保留“结果未确认”,由管理员核对实际状态,不自动重试。
  • 桌面“重启”只用 PVE reboot;未将硬重启 reset 冒充“还原镜像”。
  • 当前任务和审计列表展示最近 1000 条,完整记录仍存 PostgreSQL;长期检索和归档后续扩展。
  • 凭据不写入审计;设备上报的自由文本不直接放入公开任务结果。