Files
ctms/docs/desktop-phase-2-design.md
T
Cheng Zhou d5279b124f
Storage Persistence Guard / storage-persistence-audit (push) Has been cancelled
Client Quality Gates / Shared client and Web (push) Has been cancelled
Client Quality Gates / macOS Desktop (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
release(main): 同步 dev 最新候选改动
2026-07-16 17:15:50 +08:00

163 lines
6.7 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 桌面端第二阶段执行设计
## 范围与边界
第二阶段基于已合入 `dev` 的 Tauri 基线推进。每个评审单元从最新 `dev` 创建短期 `codex/*` 分支,合入后删除,不建立长期桌面主线。
本阶段只增强在线桌面客户端能力:
- 安全运行时与诊断。
- 原生文件选择、保存、打开。
- 服务端持久系统通知。
- 签名更新、发布流水线与 Windows 打包准备。
本阶段明确不实现离线登录、离线缓存、本地业务数据库、本地业务队列、后台业务同步或本地权限裁决。所有业务数据、权限、审计和认证判定仍以 FastAPI 后端为准。
## 运行时边界
共享业务模块只能通过 `frontend/src/runtime/` 使用平台能力。非 runtime 模块不得直接导入 Tauri API。
`ClientRuntime` 第二阶段能力包括:
- `secureSessionStorage`
- `files`
- `notifications`
- `updates`
- `capabilities.secureSessionStorage/nativeFiles/systemNotifications/automaticUpdates`
能力标志只在对应运行时可用或初始化成功后开启。Web 端继续使用浏览器能力,不申请系统通知权限,不启动桌面通知轮询,也不触发 updater。
## 安全会话存储
桌面端 token 存入系统凭据库:
- macOSKeychain。
- WindowsCredential Manager。
桌面端登录使用后端签发的在线会话 token,可在系统凭据库中保存最长 30 天,以支持重启 App 后免输入密码。启动恢复后仍必须使用后端 token 校验和 `/auth/me` 用户状态校验;服务端不可达或会话被后端拒绝时不得进入离线模式。
Rust 仅暴露固定 service 下的读取、写入、删除命令。凭据 account 使用规范化服务端 origin 的 SHA-256,避免明文服务端地址散落在系统凭据项名称中。
应用挂载前异步初始化 token
1. Web 端继续读取 `localStorage.ctms_token`
2. 桌面端先删除 legacy `localStorage.ctms_token`
3. 若 legacy token 仍有效,则迁移为带 30 天本机到期时间的系统凭据库会话记录。
4. 若迁移或读取凭据失败,则内存 token 置空并要求重新登录,不回退明文存储。
登出、服务器切换、认证失效时必须同步清除内存 token 和当前服务端 origin 对应的系统凭据。
## 原生文件能力
公共接口固定为:
```ts
pickFiles(options): Promise<File[]>
saveFile({ suggestedName, mimeType, data }): Promise<"saved" | "cancelled">
openFile({ suggestedName, mimeType, data }): Promise<void>
```
桌面端使用 Tauri dialog、fs、opener 插件。权限范围只覆盖用户当次选择的文件路径和 `$TEMP/ctms-desktop/**`,不启用 persisted-scope,不开放目录遍历或 shell。外部打开文件时写入随机临时目录,并使用净化后的文件名;启动和退出时清理临时目录,用户主动保存的文件不自动删除。
下载与预览统一先通过 Axios Bearer 请求取得 Blob,再交给文件适配器。附件全局下载接口只接受 `Authorization` header,不再接受 `?token=`
## 系统通知
通知订阅由用户在个人设置中主动开启。开启时才请求 OS 权限并创建服务端订阅;`enabled_at` 设为当前时间,不补发历史分发记录。关闭后客户端停止领取通知,重新开启时重新设定起点。
后端新增:
- `desktop_notification_subscriptions`
- `desktop_notification_deliveries`
API
- `GET/PUT /api/v1/desktop-notifications/subscription`
- `POST /api/v1/desktop-notifications/claim`
- `POST /api/v1/desktop-notifications/ack`
- `POST /api/v1/desktop-notifications/{distribution_id}/read`
claim 跨有效项目查询当前用户未读且未解决的通用业务提醒,使用五分钟租约、唯一约束和事务防重。客户端显示系统通知后 ack;显示失败则等待租约到期后重试。系统通知只是通用提醒 Feed 的可选投递通道,不单独维护文件分发提醒来源。
系统通知正文只显示通用内容:
- 标题:`CTMS 待办提醒`
- 正文:`有新的业务提醒待查看`
项目、文件、版本等详细信息仅在应用内列表显示,避免锁屏泄露。
## 诊断元数据与 CORS
Axios 请求附加:
- `X-CTMS-Client-Type`
- `X-CTMS-Client-Version`
- `X-CTMS-Client-Platform`
- `X-CTMS-Build-Channel`
- `X-CTMS-Build-Commit`
后端安全访问日志保存这些 nullable 字段,并支持按客户端类型/版本筛选。这些字段只用于诊断与排障,不参与授权。
CORS origin 由环境变量白名单控制,并显式允许桌面 origin、开发 origin 和上述请求头。
Tauri CSP 禁止远程脚本和 shell 入口,仅允许 HTTPS API、本地开发地址、blob 预览与必要资源。
## 单实例
单实例插件必须最先注册。重复启动时只恢复、显示并聚焦主窗口,不处理命令行参数、深链或业务动作。
## 自动更新与发布
正式 release 构建启用 updater。客户端从当前 CTMS origin 派生固定清单路径:
```text
/desktop-updates/stable/latest.json
```
生产只允许 HTTPS;本地测试只允许 localhost HTTP。
更新检查策略:
- 启动延迟 30 秒检查。
- 之后每 6 小时检查。
- 发现更新时展示版本和发布说明。
- 用户确认后下载、验签、安装并重启。
- 用户选择“稍后”后,同版本 24 小时内不再提示。
- 不做静默安装,不中断正在录入的业务流程。
Tauri 配置必须嵌入 updater 公钥并生成 updater artifacts。生产私钥只能存放在组织密钥库或 CI secret,不进仓库。macOS 更新制品为 `.app.tar.gz``.sig`
release tag 流水线应从同一提交构建 Web 与桌面端:
1. 校验 `frontend/package.json`、Tauri 配置、Cargo manifest/lock 版本一致。
2. 构建 macOS Universal。
3. 完成 Apple 签名和公证。
4. 使用 updater 私钥签名更新包。
5. 生成 DMG、更新包、签名、`latest.json` 与校验清单。
6. 先上传不可变制品,最后原子替换 `latest.json`
`latest.json` 同时提供 `darwin-aarch64``darwin-x86_64`,指向同一个 Universal 更新制品。
## Windows 准备
第二阶段只验证 Windows x64 NSIS 构建兼容,不发布正式 Windows 安装包。
验证范围:
- Windows Credential Manager。
- 路径净化与临时目录限制。
- 系统通知编译兼容。
- updater 编译兼容。
- WebView2 前置条件。
- 用户级安装假设。
- 后续代码签名要求。
## 验收重点
- `localStorage`、URL、日志和系统通知正文不包含 token。
- 附件下载不再接受 query-token。
- 业务模块不直接导入 Tauri API。
- Web 构建、类型检查和单测不回归。
- macOS `.app` 构建可重复。
- Keychain 会话、文件入口、通知权限、重复启动聚焦和签名更新链路完成端到端验证。