Files
ctms/docs/desktop-phase-1-design.md
T
2026-06-30 17:25:03 +08:00

332 lines
12 KiB
Markdown
Raw Blame History

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.
# 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.ts``frontend/src/api/authClient.ts``baseURL` 都是 `/`
- API 调用路径均为 `/api/v1/...`
- Web 端依赖 nginx 同域反代 `/api`
- Tauri 打包后页面运行在桌面 WebView 中,不能继续假设 `/api` 一定代表 CTMS 服务端。
- `frontend/src/utils/auth.ts` 当前使用 `localStorage` 保存 token。
- `frontend/src/session/sessionManager.ts` 依赖 `localStorage``sessionStorage``BroadcastChannel`
第一阶段的核心改动是先解决“桌面端如何知道并访问服务端地址”,同时尽量不触碰业务页面。
## 目标架构
```mermaid
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 目录放在现有前端工程内:
```text
frontend/
src-tauri/
tauri.conf.json
Cargo.toml
src/
main.rs
capabilities/
default.json
```
建议新增脚本:
```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 port`8888`
- `/api` 代理目标:`http://backend:8000`
为兼容 Web、Docker 和 Tauri,建议改成环境变量驱动:
- `VITE_DEV_API_PROXY_TARGET`:默认 `http://backend:8000`
- `VITE_HMR_CLIENT_PORT`Docker/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_*`
## 服务端地址配置
新增运行时适配层:
```text
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://localhost``http://127.0.0.1``https://...`。非本地生产服务不接受明文 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 端不显示桌面端服务器设置入口。
建议新增文件:
```text
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 打包路径
开发构建:
```bash
cd /Users/zcc/MyCTMS/ctms-dev/worktrees/ctms-desktop/frontend
npm run desktop:dev
```
生产构建:
```bash
cd /Users/zcc/MyCTMS/ctms-dev/worktrees/ctms-desktop/frontend
npm run desktop:build
```
DMG 构建:
```bash
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,不应等到最后一天处理。
## 参考资料
- Tauri 创建项目与向现有前端加入 Taurihttps://tauri.app/start/create-project/
- Tauri + Vite 配置:https://tauri.app/start/frontend/vite/
- Tauri capabilitieshttps://tauri.app/security/capabilities/
- Tauri DMG 分发:https://tauri.app/distribute/dmg/
- Tauri macOS 签名与公证:https://tauri.app/distribute/sign/macos/
- Tauri updater 资料,供第二阶段使用:https://tauri.app/plugin/updater/