Files
ctms/docs/desktop-phase-1-design.md
T
Cheng Zhou b491b6a146
Client Quality Gates / Shared client and Web (push) Has been cancelled
Client Quality Gates / macOS Desktop (push) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (push) Has been cancelled
Client Quality Gates / Shared client and Web (pull_request) Has been cancelled
Client Quality Gates / macOS Desktop (pull_request) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (pull_request) Has been cancelled
发布候选:整合桌面端界面与发布稳定化里程碑
2026-07-01 10:53:24 +08:00

12 KiB
Raw Permalink Blame History

CTMS 桌面端第一阶段详细方案

日期:2026-06-30

目标

第一阶段只交付 macOS 在线桌面客户端。桌面端使用 Tauri 承载现有 Vue/Vite 前端,连接已有 CTMS 服务端,不内嵌后端、不内嵌数据库、不做离线能力。

本阶段结束后,应能在 macOS 上启动 CTMS 桌面 App,配置 CTMS 服务端地址,完成登录,并执行现有 Web 端的常规在线业务流程。Web 端构建和现有 Docker/nginx 部署必须继续可用。

范围边界

本阶段必须做:

  • frontend/ 内加入 Tauri 工程结构。
  • 复用现有 Vue 3、Vite、Element Plus、Pinia、Vue Router、Axios 前端代码。
  • 让桌面端连接已有 CTMS 后端公开入口,推荐连接 nginx 入口而不是直接连接后端容器。
  • 提供桌面端服务端地址配置能力。
  • 抽出最小运行时适配层,避免业务页面直接依赖 Tauri API。
  • 保持认证、权限、审计和业务数据持久化由 FastAPI 后端裁决。
  • 产出 macOS 开发构建流程和后续签名、公证、DMG 发布路径。

本阶段明确不做:

  • 离线登录、离线浏览、离线草稿、离线队列、离线同步。
  • 本地 PostgreSQL、SQLite、IndexedDB 业务数据缓存或本地 API 镜像。
  • 内嵌 Python/FastAPI 后端服务。
  • 重写 CTMS 业务页面。
  • Windows 安装包交付。
  • 自动更新实现。
  • token/session 安全存储迁移;该事项进入第二阶段。

当前代码影响点

现状:

  • frontend/src/api/axios.tsfrontend/src/api/authClient.tsbaseURL 都是 /
  • API 调用路径均为 /api/v1/...
  • Web 端依赖 nginx 同域反代 /api
  • Tauri 打包后页面运行在桌面 WebView 中,不能继续假设 /api 一定代表 CTMS 服务端。
  • frontend/src/utils/auth.ts 当前使用 localStorage 保存 token。
  • frontend/src/session/sessionManager.ts 依赖 localStoragesessionStorageBroadcastChannel

第一阶段的核心改动是先解决“桌面端如何知道并访问服务端地址”,同时尽量不触碰业务页面。

目标架构

flowchart LR
  A["Tauri macOS App"] --> B["Bundled Vue/Vite Frontend"]
  B --> C["Runtime Adapters"]
  C --> D["Configured CTMS Server URL"]
  D --> E["nginx / HTTPS entry"]
  E --> F["FastAPI backend"]
  F --> G["PostgreSQL"]

桌面端只负责本地窗口、运行时配置和少量平台能力。业务数据仍走服务端 API,权限和审计仍由后端完成。

Tauri 工程方案

Tauri 目录放在现有前端工程内:

frontend/
  src-tauri/
    tauri.conf.json
    Cargo.toml
    src/
      main.rs
    capabilities/
      default.json

建议新增脚本:

{
  "scripts": {
    "tauri": "tauri",
    "desktop:dev": "tauri dev",
    "desktop:build": "tauri build",
    "desktop:bundle:dmg": "tauri build -- --bundles dmg"
  }
}

Tauri 配置方向:

  • build.beforeDevCommand: npm run dev
  • build.beforeBuildCommand: npm run build
  • build.devUrl: http://localhost:5173
  • build.frontendDist: ../dist
  • 主窗口标题:CTMS
  • 主窗口初始尺寸建议:1440x900
  • 最小窗口尺寸建议:1180x760
  • bundle identifier 待最终确认,临时建议:cn.huapont.ctms.desktop

第一阶段不加载远程 Web UI。Tauri 只加载本地打包出的前端资源,远程访问仅限 Axios 访问配置好的 CTMS 服务端。

Vite 调整方案

当前 vite.config.ts 为 Docker 开发做了固定代理:

  • dev server 端口:5173
  • HMR client port8888
  • /api 代理目标:http://backend:8000

为兼容 Web、Docker 和 Tauri,建议改成环境变量驱动:

  • VITE_DEV_API_PROXY_TARGET:默认 http://backend:8000
  • VITE_HMR_CLIENT_PORTDocker/nginx 开发时设为 8888,桌面端开发不设置。
  • TAURI_DEV_HOST:按 Tauri/Vite 推荐方式兼容 Tauri dev。

Vite 配置需要补充:

  • server.strictPort: true,避免 Tauri devUrl 与 Vite 实际端口不一致。
  • server.watch.ignored: ["**/src-tauri/**"],避免 Rust 目录变动触发不必要的前端监听。
  • clearScreen: false,避免 Rust 编译错误被 Vite 清屏隐藏。
  • build.target 按 Tauri 平台设置:Windows 使用 Chromium 目标,macOS 使用 Safari/WebKit 目标。
  • envPrefix 保留 VITE_,并允许 TAURI_ENV_*

服务端地址配置

新增运行时适配层:

frontend/src/runtime/
  platform.ts
  apiBaseUrl.ts
  desktopServerConfig.ts

职责:

  • platform.ts

    • 判断当前是否运行在 Tauri。
    • 判断目标平台是 Web、macOS 桌面端还是 Windows 桌面端。
    • 业务页面不得直接读取 Tauri 全局对象。
  • desktopServerConfig.ts

    • 保存和读取桌面端服务端地址。
    • 第一阶段可继续使用 localStorage 保存服务器地址;这不是业务数据,也不是离线能力。
    • key 建议:ctms_desktop_server_url
    • 仅接受 http://localhosthttp://127.0.0.1https://...。非本地生产服务不接受明文 HTTP。
  • apiBaseUrl.ts

    • Web 端返回 /,保持现有同域 /api 行为。
    • 桌面端返回配置的服务端 origin,例如 https://ctms.example.com/
    • 统一规范尾斜杠,避免拼接出错。

Axios 调整:

  • frontend/src/api/axios.ts 使用 resolveApiBaseUrl() 初始化 baseURL
  • frontend/src/api/authClient.ts 同步使用同一 baseURL。
  • 当桌面端服务端地址变化时,需要更新两个 Axios 实例的 defaults.baseURL
  • 现有 API path 继续保持 /api/v1/...,不修改业务 API 文件。

服务端配置入口

第一阶段需要一个轻量的桌面端服务端设置入口。

建议实现方式:

  • 桌面端启动时,如果没有服务端地址,则在登录页前展示服务端设置界面。
  • 登录页提供“服务器设置”入口,允许修改当前服务端地址。
  • 保存前调用 ${serverUrl}/health 做连通性检查。
  • 连通性检查失败时允许用户重新输入,不自动降级到离线模式。
  • Web 端不显示桌面端服务器设置入口。

建议新增文件:

frontend/src/views/DesktopServerSettings.vue
frontend/src/router/desktopGuard.ts
frontend/src/runtime/desktopServerConfig.ts

路由策略:

  • 保持现有 Web 路由结构。
  • 桌面端未配置服务端时,将用户导向 /desktop/server-settings
  • /login 页面中允许打开服务器设置。
  • Web 端访问 /desktop/server-settings 时重定向到 /login 或显示不可用状态。

认证和会话策略

第一阶段保持现有认证机制:

  • 登录仍使用后端登录公钥和加密登录流程。
  • token 仍通过 frontend/src/utils/auth.ts 存储在 localStorage
  • 会话超时、token keep-alive、401 refresh 仍沿用现有逻辑。

本阶段只允许做为 Tauri 接入所必需的最小改动:

  • API baseURL 可切换。
  • 服务端地址变化时清理当前 token 和项目上下文,要求重新登录。
  • 不引入桌面安全存储;该事项归入第二阶段。

Tauri 权限策略

第一阶段不需要文件系统、Shell、系统通知、自动更新或单实例插件。

权限原则:

  • 只启用主窗口运行所需的最小 core capability。
  • 不开放宽泛文件系统权限。
  • 不开放 shell 执行能力。
  • 不开放远程页面访问 Tauri command 的能力。
  • 如确实需要读取 App 版本或平台信息,优先通过窄适配层处理,并明确 capability。

第一阶段建议不新增自定义 Tauri command。服务端地址配置可以先由前端 localStorage 完成。

macOS 打包路径

开发构建:

cd /Users/zcc/MyCTMS/ctms-dev/worktrees/ctms-desktop/frontend
npm run desktop:dev

生产构建:

cd /Users/zcc/MyCTMS/ctms-dev/worktrees/ctms-desktop/frontend
npm run desktop:build

DMG 构建:

cd /Users/zcc/MyCTMS/ctms-dev/worktrees/ctms-desktop/frontend
npm run desktop:bundle:dmg

正式分发前需要:

  • Apple Developer 账号。
  • macOS 代码签名证书。
  • notarization 所需 App Store Connect API 或 Apple ID 凭据。
  • 明确是否分发 DMG,第一阶段推荐 DMG。

第一阶段可以先产出未签名或 ad-hoc 签名的内部开发构建,但不能把它描述为正式可分发版本。

实施步骤

  1. 初始化 Tauri

    • 安装 @tauri-apps/cli
    • frontend/ 下生成 src-tauri/
    • 固定基础配置:app name、window title、bundle identifier、devUrl、frontendDist。
  2. 调整 Vite

    • 引入 Tauri 兼容配置。
    • 保持 Docker/nginx 开发代理不破坏。
    • 使用环境变量控制代理和 HMR。
  3. 新增运行时适配层

    • 添加 platform.ts
    • 添加 apiBaseUrl.ts
    • 添加 desktopServerConfig.ts
    • 新增单元测试覆盖 URL 规范化、Web/Tauri 分支和非法 URL 拒绝。
  4. 改造 API client

    • axios.ts 使用统一 baseURL。
    • authClient.ts 使用统一 baseURL。
    • 服务端地址变化后刷新 Axios baseURL。
    • 保持 API path 和业务模块不变。
  5. 添加桌面服务端设置界面

    • 桌面端未配置服务端时拦截到设置页。
    • 保存时校验 URL 和 /health
    • 修改服务端地址时清理当前登录态和项目上下文。
  6. 最小 Tauri 权限

    • 检查 capabilities/default.json
    • 移除第一阶段不需要的插件和权限。
    • 不新增自定义 command,除非实现过程证明必要。
  7. macOS 验证和文档

    • 运行 Web 构建、类型检查、单元测试。
    • 运行 Tauri dev。
    • 验证 macOS 打包。
    • 补充桌面端运行说明。

验收清单

功能验收:

  • macOS 桌面 App 可以启动。
  • 首次启动未配置服务端时进入服务器设置。
  • 服务端地址保存前会校验 /health
  • 配置有效服务端后可以登录。
  • 登录后能进入项目列表和项目工作区。
  • 现有权限控制、401 refresh、会话超时行为与 Web 端一致。
  • 切换服务端地址会清理当前登录态。

工程验收:

  • npm run build 通过。
  • npm run type-check 通过。
  • npm run test:unit 通过,或明确记录失败原因。
  • npm run desktop:dev 可启动 macOS 窗口。
  • npm run desktop:build 可完成构建。
  • Web 端 Docker/nginx 访问不回归。

边界验收:

  • 没有新增本地业务数据缓存。
  • 没有内嵌后端服务。
  • 没有本地数据库。
  • 没有离线队列或同步机制。
  • Tauri API 没有散落在业务页面中。
  • Tauri capability 没有开放第一阶段不需要的文件系统或 shell 权限。

风险和决策点

  • bundle identifier 需要正式确认,建议在第一阶段实现前由产品或组织负责人定稿。
  • 桌面端连接公开 CTMS 服务时,生产环境应使用 HTTPS;本地开发可允许 localhost HTTP。
  • 当前后端 CORS 是宽松配置。第一阶段可先不改后端,但正式分发前应评估是否收紧允许来源。
  • token 第一阶段仍在 localStorage,这是有意识的阶段性选择;安全存储迁移必须排入第二阶段。
  • macOS 正式分发需要 Apple Developer、签名和 notarization,不应等到最后一天处理。

参考资料