发布候选:整合桌面端界面与发布稳定化里程碑
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
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
This commit is contained in:
@@ -4,8 +4,12 @@ CTMS 文档入口只展示当前仍会影响开发、发布和运维决策的内
|
||||
|
||||
## 当前约束
|
||||
|
||||
- [`desktop-project-plan.md`](desktop-project-plan.md): 桌面端 Tauri 项目边界、阶段计划与必读约束
|
||||
- [`desktop-phase-1-design.md`](desktop-phase-1-design.md): 桌面端第一阶段 macOS 在线客户端详细方案
|
||||
- [`branch-governance.md`](branch-governance.md): 长期分支治理规则
|
||||
- [`guides/release-checklist.md`](guides/release-checklist.md): 发布前检查项与回归门禁
|
||||
- [`guides/client-release.md`](guides/client-release.md): Web/桌面端统一版本、构建与发布流程
|
||||
- [`guides/branch-maintenance-sop-zh.md`](guides/branch-maintenance-sop-zh.md): 分支维护、版本晋级、发布和热修复中文标准操作规程
|
||||
- [`audits/storage-persistence-governance.md`](audits/storage-persistence-governance.md): 重要数据落库治理基线
|
||||
- [`audits/module-level-permissions-transition.md`](audits/module-level-permissions-transition.md): 模块级权限迁移状态与约束
|
||||
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
# CTMS Desktop Release Stabilization Checklist
|
||||
|
||||
状态: `active`
|
||||
适用范围: Web 与 macOS Desktop 统一客户端发布
|
||||
最后更新: `2026-07-01`
|
||||
|
||||
本清单用于第一、二阶段桌面端能力完成后的准发布稳定化。它不引入离线登录、本地业务数据存储、内嵌后端服务或离线同步。
|
||||
|
||||
## 1. 发布链路门禁
|
||||
|
||||
发布候选提交必须从同一 Git 提交构建 Web 与 Desktop 制品,并完成以下检查:
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
npm ci
|
||||
npm run version:check
|
||||
npm run release:env:check
|
||||
npm run runtime:check
|
||||
npm run desktop:release:check
|
||||
npm run ui:contract
|
||||
npm run type-check
|
||||
npm run test:unit
|
||||
npm run build
|
||||
npm run desktop:build:app
|
||||
```
|
||||
|
||||
正式发布还必须确认:
|
||||
|
||||
- [ ] `frontend/package.json`、`package-lock.json`、Tauri 配置、Cargo manifest/lock 版本一致。
|
||||
- [ ] `VITE_BUILD_CHANNEL=release` 和 `VITE_BUILD_COMMIT=<release tag commit>` 由 CI 注入,且 `npm run release:env:check` 通过。
|
||||
- [ ] macOS app 已签名和公证。
|
||||
- [ ] updater `.sig` 使用组织 CI secret 或密钥库中的私钥生成,私钥未进入仓库。
|
||||
- [ ] 设置 `TAURI_SIGNING_PRIVATE_KEY`、`TAURI_SIGNING_PRIVATE_KEY_PASSWORD` 和 Apple 签名/公证变量后,以 `REQUIRE_DESKTOP_SIGNING=true` 再次执行 `npm run release:env:check`,随后执行 `npm run desktop:build -- --bundles app`。
|
||||
- [ ] 正式 updater feed 执行 `npm run desktop:update-feed:check -- --feed <latest.json> --artifacts-dir <artifact-dir>`。
|
||||
- [ ] 不可变制品先上传,`latest.json` 最后原子替换;若 feed 校验未通过,不替换线上 `latest.json`。
|
||||
- [ ] Web 与 Desktop 制品记录同一产品版本、Git 标签和完整提交 SHA。
|
||||
|
||||
## 2. 安全边界复审
|
||||
|
||||
自动门禁 `npm run desktop:release:check` 覆盖以下静态约束:
|
||||
|
||||
- [ ] Tauri bundle 启用 `app`、`dmg` 和 updater artifacts。
|
||||
- [ ] updater public key 已配置。
|
||||
- [ ] CSP 禁止 wildcard source、`unsafe-eval`、宽泛 HTTP API 访问和 `object-src`。
|
||||
- [ ] Tauri capability 不包含 shell 权限、持久文件系统 scope 或宽泛目录读写。
|
||||
- [ ] 文件系统与 opener scope 只允许 `$TEMP/ctms-desktop/**`。
|
||||
- [ ] 单实例插件先于其他桌面插件注册。
|
||||
- [ ] Tauri command 白名单仅包含凭据和更新命令。
|
||||
- [ ] 前端源码不通过 query string 传递 token。
|
||||
- [ ] `ctms_token` 只允许由 `secureSessionStorage` 处理。
|
||||
- [ ] 系统通知只能通过 `frontend/src/runtime/notifications.ts` 发送,标题和正文保持通用。
|
||||
- [ ] CI release 候选 workflow 包含 version/runtime/desktop/ui/type/unit/build/desktop app smoke 门禁。
|
||||
|
||||
人工复审还必须确认:
|
||||
|
||||
- [ ] token 不出现在 URL、日志、系统通知正文、下载链接或持久化业务缓存中。
|
||||
- [ ] 桌面端通知正文只显示通用内容,不包含项目、文件或版本详情。
|
||||
- [ ] 服务端权限、审计和业务数据持久化仍由 FastAPI 后端裁决。
|
||||
- [ ] Web 运行时不直接导入 Tauri API。
|
||||
|
||||
## 3. 端到端回归矩阵
|
||||
|
||||
| 场景 | Web | macOS Desktop | 预期 |
|
||||
| --- | --- | --- | --- |
|
||||
| 登录与项目恢复 | 必测 | 必测 | 登录成功后恢复可访问项目;401 后重新登录 |
|
||||
| 服务器地址未配置 | 不适用 | 必测 | 自动进入服务器设置,不进入业务页 |
|
||||
| 服务器地址切换 | 不适用 | 必测 | 清除当前会话和项目上下文,要求重新登录 |
|
||||
| 服务端不可达 | 必测 | 必测 | 显示可恢复错误,不进入离线模式 |
|
||||
| 附件上传 | 必测 | 必测 | Web 使用浏览器文件选择,Desktop 使用原生选择 |
|
||||
| 附件下载/保存/打开 | 必测 | 必测 | 使用 Authorization header;无 `?token=` |
|
||||
| 临时文件清理 | 不适用 | 必测 | 启动时清理 `$TEMP/ctms-desktop/**` |
|
||||
| 系统通知开启 | 不适用 | 必测 | 用户主动开启后请求 OS 权限并创建订阅 |
|
||||
| 系统通知拒绝 | 不适用 | 必测 | 开关回退,提示系统权限未开启 |
|
||||
| 通知领取与 ack | 不适用 | 必测 | 显示成功后 ack;失败等待租约重试 |
|
||||
| 单实例重复启动 | 不适用 | 必测 | 恢复、显示并聚焦主窗口 |
|
||||
| 自动更新检查 | 不适用 | 必测 | release 通道按当前 CTMS origin 派生清单 |
|
||||
| 更新稍后提醒 | 不适用 | 必测 | 同版本 24 小时内不重复提示 |
|
||||
| 更新安装失败 | 不适用 | 必测 | 不打断业务录入,显示可排障错误 |
|
||||
|
||||
## 4. 桌面体验验收
|
||||
|
||||
- [ ] 登录页显示当前桌面服务器地址,长 URL 不撑破登录面板。
|
||||
- [ ] 服务器设置页显示当前服务器、连接检查状态、HTTP 错误、超时和网络失败原因。
|
||||
- [ ] 个人中心显示客户端类型、版本、平台、构建通道、提交、服务器和能力状态。
|
||||
- [ ] 个人中心可复制诊断信息,内容不包含 token 或业务敏感数据。
|
||||
- [ ] 通知开关显示 OS 权限状态。
|
||||
- [ ] 手动检查更新能反馈“已是最新版本”、未启用更新或检查失败。
|
||||
- [ ] 关键弹窗、表单、按钮在最小窗口尺寸 `1180x760` 下不重叠、不溢出。
|
||||
- [ ] 更新弹窗只显示版本、发布日期和通用 release notes,不展示 token、下载链接或业务详情。
|
||||
|
||||
## 5. 不允许项
|
||||
|
||||
- [ ] 不实现离线登录、离线浏览、离线队列或离线同步。
|
||||
- [ ] 不在桌面端保存 CTMS 业务数据副本。
|
||||
- [ ] 不内嵌 FastAPI、PostgreSQL、SQLite 或本地业务 API 镜像。
|
||||
- [ ] 不绕过后端做本地权限裁决或本地审计回放。
|
||||
|
||||
## 6. 2026-07-01 收尾验证记录
|
||||
|
||||
本轮收尾验证在 `/Users/zcc/MyCTMS/ctms-dev/worktrees/ctms-desktop` 的 detached HEAD `c923f887` 上执行,包含当前工作区文档与 CI 门禁调整。
|
||||
|
||||
已通过的自动门禁:
|
||||
|
||||
- `cd frontend && npm run version:check`
|
||||
- `cd frontend && npm run release:env:check`
|
||||
- `cd frontend && npm run runtime:check`
|
||||
- `cd frontend && npm run desktop:release:check`
|
||||
- `cd frontend && npm run ui:contract`
|
||||
- `cd frontend && npm run type-check`
|
||||
- `cd frontend && npm run test:unit`
|
||||
- `cd frontend && npm run build`
|
||||
- `cd frontend && npm run desktop:build:app`
|
||||
- `cd frontend && node --check scripts/verify-desktop-update-feed.mjs`
|
||||
|
||||
验证结论:
|
||||
|
||||
- Tauri 运行时边界、release 静态安全门禁、构建元数据预检、版本一致性和 UI 合约均通过。
|
||||
- Web 生产构建和未签名 macOS `.app` smoke 构建均可重复执行。
|
||||
- 当前 CI 已补齐 `npm run release:env:check` 和 `npm run ui:contract`,tag 构建会将 `VITE_BUILD_CHANNEL` 规范为 `release` 并校验 tag 与版本号一致。
|
||||
- updater feed 校验脚本已完成语法检查;正式 `latest.json` 需要在签名 updater artifacts 生成后执行实物校验。
|
||||
|
||||
仍需正式发布前人工确认:
|
||||
|
||||
- macOS 签名、公证、Apple Developer 凭据和组织 updater 私钥。
|
||||
- 签名后的 updater artifacts、`.sig`、checksum manifest 和 `latest.json` 在真实发布目录内通过 `npm run desktop:update-feed:check`。
|
||||
- 不可变制品上传完成后,再原子替换线上 `latest.json`。
|
||||
- Desktop 端到端人工回归矩阵、最小窗口体验验收和系统通知/自动更新真实环境验证。
|
||||
@@ -2,11 +2,14 @@
|
||||
|
||||
状态: `snapshot`
|
||||
适用范围: `storage-persistence`
|
||||
最后更新: `2026-02-27`
|
||||
最后更新: `2026-06-30`
|
||||
|
||||
- 扫描目录: `/Users/zcc/MyCTMS/ctms-project/frontend/src`
|
||||
- 总发现数: `46`
|
||||
- 高风险: `4` / 中风险: `0` / 低风险: `42`
|
||||
- 总发现数: `36`
|
||||
- 高风险: `4` / 中风险: `0` / 低风险: `32`
|
||||
|
||||
> 2026-06-30 第二阶段更新:认证 token 已迁移到 `frontend/src/runtime/secureSessionStorage.ts`;
|
||||
> 业务入口不再直接从 `localStorage` 读取 `ctms_token`,附件下载不再使用 query-token。
|
||||
|
||||
## 明细
|
||||
|
||||
@@ -18,13 +21,6 @@
|
||||
| high | business-draft | `frontend/src/views/admin/ProjectDetail.vue` | 2984 | `localStorage.removeItem` | `storageKey.value` | 立项配置草稿本地兜底,需显式提示未落库 |
|
||||
| low | ui-preference | `frontend/src/components/Layout.vue` | 227 | `localStorage.getItem` | `"ctms_sidebar_collapsed"` | UI偏好/上下文缓存 |
|
||||
| low | ui-preference | `frontend/src/components/Layout.vue` | 390 | `localStorage.setItem` | `"ctms_sidebar_collapsed"` | UI偏好/上下文缓存 |
|
||||
| low | auth-session | `frontend/src/components/ThreadList.vue` | 72 | `localStorage.getItem` | `"ctms_token"` | 认证/会话数据(非业务主数据) |
|
||||
| low | auth-session | `frontend/src/components/attachments/AttachmentList.vue` | 132 | `localStorage.getItem` | `"ctms_token"` | 认证/会话数据(非业务主数据) |
|
||||
| low | auth-session | `frontend/src/components/attachments/AttachmentList.vue` | 137 | `localStorage.getItem` | `"ctms_token"` | 认证/会话数据(非业务主数据) |
|
||||
| low | auth-session | `frontend/src/components/attachments/AttachmentList.vue` | 168 | `localStorage.getItem` | `"ctms_token"` | 认证/会话数据(非业务主数据) |
|
||||
| low | auth-session | `frontend/src/components/fees/FeeAttachmentPanel.vue` | 169 | `localStorage.getItem` | `"ctms_token"` | 认证/会话数据(非业务主数据) |
|
||||
| low | auth-session | `frontend/src/components/fees/FeeAttachmentPanel.vue` | 174 | `localStorage.getItem` | `"ctms_token"` | 认证/会话数据(非业务主数据) |
|
||||
| low | auth-session | `frontend/src/components/fees/FeeAttachmentPanel.vue` | 223 | `localStorage.getItem` | `"ctms_token"` | 认证/会话数据(非业务主数据) |
|
||||
| low | auth-session | `frontend/src/session/sessionManager.ts` | 33 | `localStorage.setItem` | `"ctms_auth_broadcast"` | 认证/会话数据(非业务主数据) |
|
||||
| low | auth-session | `frontend/src/session/sessionManager.ts` | 181 | `sessionStorage.removeItem` | `LOGOUT_REASON_STORAGE_KEY` | 认证/会话数据(非业务主数据) |
|
||||
| low | auth-session | `frontend/src/session/sessionManager.ts` | 184 | `sessionStorage.setItem` | `LOGOUT_REASON_STORAGE_KEY` | 认证/会话数据(非业务主数据) |
|
||||
@@ -49,9 +45,6 @@
|
||||
| low | ui-preference | `frontend/src/store/study.ts` | 167 | `localStorage.removeItem` | `STUDY_ROLE_KEY` | UI偏好/上下文缓存 |
|
||||
| low | ui-preference | `frontend/src/store/study.ts` | 174 | `localStorage.setItem` | `SITE_KEY` | UI偏好/上下文缓存 |
|
||||
| low | ui-preference | `frontend/src/store/study.ts` | 176 | `localStorage.removeItem` | `SITE_KEY` | UI偏好/上下文缓存 |
|
||||
| low | auth-session | `frontend/src/utils/auth.ts` | 4 | `localStorage.getItem` | `TOKEN_KEY` | 认证/会话数据(非业务主数据) |
|
||||
| low | auth-session | `frontend/src/utils/auth.ts` | 7 | `localStorage.setItem` | `TOKEN_KEY` | 认证/会话数据(非业务主数据) |
|
||||
| low | auth-session | `frontend/src/utils/auth.ts` | 11 | `localStorage.removeItem` | `TOKEN_KEY` | 认证/会话数据(非业务主数据) |
|
||||
| low | auth-session | `frontend/src/utils/auth.ts` | 17 | `localStorage.setItem` | `CREDENTIAL_KEY` | 认证/会话数据(非业务主数据) |
|
||||
| low | auth-session | `frontend/src/utils/auth.ts` | 24 | `localStorage.getItem` | `CREDENTIAL_KEY` | 认证/会话数据(非业务主数据) |
|
||||
| low | auth-session | `frontend/src/utils/auth.ts` | 38 | `localStorage.removeItem` | `CREDENTIAL_KEY` | 认证/会话数据(非业务主数据) |
|
||||
|
||||
@@ -78,6 +78,29 @@ Meaning:
|
||||
|
||||
Direct promotion that skips stages is discouraged and must be justified in writing.
|
||||
|
||||
## 3.1 Unified Web and Desktop Mainline
|
||||
|
||||
CTMS Web and Desktop are two delivery targets of the same product version. They
|
||||
share the Vue application, API contract, and product branches.
|
||||
|
||||
Rules:
|
||||
|
||||
- Do not create long-lived `web-dev`, `desktop-dev`, `web-release`, or
|
||||
`desktop-release` branches.
|
||||
- Web and Desktop changes both follow `feature/*` -> `dev` -> `main` ->
|
||||
`release`.
|
||||
- A platform-specific feature or agent task branch is allowed while work is in
|
||||
progress, for example `feature/desktop-file-picker` or
|
||||
`codex/desktop-menu-polish`, but it must merge back into `dev`.
|
||||
- `codex/ctms-desktop` was the temporary desktop integration branch for the
|
||||
Tauri baseline. It is no longer a current desktop mainline. Do not commit,
|
||||
rebase, or push new desktop work to it unless explicitly cleaning up the
|
||||
historical branch after its accepted changes are present on `dev`.
|
||||
- Platform differences belong behind `frontend/src/runtime/`. Shared business
|
||||
modules must not import Tauri APIs directly.
|
||||
- A release tag identifies one product source state. Web and Desktop artifacts
|
||||
for that release must be built from the same tag and Git commit.
|
||||
|
||||
## 4. Branch Entry Rules
|
||||
|
||||
### Changes allowed into `dev`
|
||||
@@ -214,6 +237,13 @@ Rules:
|
||||
- tags are created on `release`, not on `dev`
|
||||
- a tag must point to the exact production release commit
|
||||
- patch hotfixes on `release` should increment the patch version
|
||||
- Web and Desktop use the same semantic version. Do not add a separate Desktop
|
||||
product version.
|
||||
- Desktop packaging-only rebuilds may add build metadata to the artifact name,
|
||||
but must retain the product version and record the source commit.
|
||||
- Before creating a tag, run `cd frontend && npm run version:check`.
|
||||
- Change the shared client version with
|
||||
`cd frontend && npm run version:set -- <version>`.
|
||||
|
||||
## 7. Hotfix Back-Merge Rules
|
||||
|
||||
|
||||
@@ -0,0 +1,331 @@
|
||||
# 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 创建项目与向现有前端加入 Tauri:https://tauri.app/start/create-project/
|
||||
- Tauri + Vite 配置:https://tauri.app/start/frontend/vite/
|
||||
- Tauri capabilities:https://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/
|
||||
@@ -0,0 +1,160 @@
|
||||
# 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 存入系统凭据库:
|
||||
|
||||
- macOS:Keychain。
|
||||
- Windows:Credential Manager。
|
||||
|
||||
Rust 仅暴露固定 service 下的读取、写入、删除命令。凭据 account 使用规范化服务端 origin 的 SHA-256,避免明文服务端地址散落在系统凭据项名称中。
|
||||
|
||||
应用挂载前异步初始化 token:
|
||||
|
||||
1. Web 端继续读取 `localStorage.ctms_token`。
|
||||
2. 桌面端先删除 legacy `localStorage.ctms_token`。
|
||||
3. 若 legacy token 仍有效,则迁移到系统凭据库。
|
||||
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;显示失败则等待租约到期后重试。
|
||||
|
||||
系统通知正文只显示通用内容:
|
||||
|
||||
- 标题:`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 会话、文件入口、通知权限、重复启动聚焦和签名更新链路完成端到端验证。
|
||||
@@ -0,0 +1,144 @@
|
||||
# CTMS 桌面端项目计划书
|
||||
|
||||
## 目的
|
||||
|
||||
本文档是 CTMS 桌面端工作的长期方向约束。每次开始任何桌面端相关任务前,都必须先阅读本文档,包括 Tauri 初始化、macOS 打包、Windows 适配、桌面端存储、文件集成、系统通知、安全边界和发布流程。
|
||||
|
||||
桌面端必须服务于现有 CTMS Web 应用和后端架构。目标是为当前 CTMS 服务提供原生桌面入口,而不是创建一个独立的离线产品。
|
||||
|
||||
## 不可突破的边界
|
||||
|
||||
- 技术路线固定为 Tauri。
|
||||
- 第一开发目标是 macOS 桌面端。
|
||||
- Windows 仍只作为第二阶段兼容性验证目标,未获明确批准前不发布正式安装包。
|
||||
- 当前桌面端工作只允许在第一、二阶段边界内做修复、稳定化、体验收口和发布准备,不新增第三阶段能力。
|
||||
- 不做离线功能。
|
||||
- 不在桌面 App 内嵌本地后端服务。
|
||||
- 不在桌面 App 内嵌或分发本地数据库来保存 CTMS 业务数据。
|
||||
- 不实现离线同步、冲突解决、本地业务数据队列、本地优先工作流。
|
||||
- 不把 CTMS 业务 UI 拆成一套独立的桌面端产品;除非桌面能力确实需要小范围适配层。
|
||||
- FastAPI 后端仍是业务权威来源。权限裁决、审计判断、认证、业务数据持久化都保持在服务端。
|
||||
|
||||
## 当前技术基线
|
||||
|
||||
桌面端工作基于当前 CTMS Web 技术栈:
|
||||
|
||||
- 前端:Vue 3、Vite、TypeScript、Element Plus、Pinia、Vue Router、Axios、ECharts。
|
||||
- 后端:FastAPI、Uvicorn、SQLAlchemy、Alembic。
|
||||
- 数据库:PostgreSQL。
|
||||
- 当前部署:Docker Compose、nginx 托管前端静态资源、nginx 反代 `/api`。
|
||||
|
||||
桌面端应复用现有前端代码和 API 契约。任何共享适配层都应保持小而明确,并可测试。
|
||||
|
||||
## 已完成阶段边界
|
||||
|
||||
第一阶段 macOS 在线桌面壳和第二阶段原生能力主体改造已经形成。详细历史方案见 [`desktop-phase-1-design.md`](desktop-phase-1-design.md) 和 [`desktop-phase-2-design.md`](desktop-phase-2-design.md)。
|
||||
|
||||
后续不再按第一阶段空白项目初始化 Tauri,也不再扩展第二阶段以外的新桌面产品能力。当前允许推进的工作仅包括:
|
||||
|
||||
- 修复既有 Tauri、运行时适配层、文件、通知、凭据、更新、菜单/快捷键和打包问题。
|
||||
- 稳定 Web 与 Desktop 共用业务代码,确保平台差异继续收敛在 `frontend/src/runtime/` 后面。
|
||||
- 完成 macOS 正式发布前的签名、公证、updater 签名、制品发布、CI 门禁和人工回归。
|
||||
- 做 Windows 第二阶段兼容性验证,但不发布正式 Windows 安装包。
|
||||
|
||||
仍然不允许:
|
||||
|
||||
- 离线登录、离线浏览、离线队列、离线同步或本地优先工作流。
|
||||
- 本地 PostgreSQL、SQLite、IndexedDB 业务数据缓存或本地 API 镜像。
|
||||
- 内嵌 Python/FastAPI 后端服务。
|
||||
- 绕过后端做本地权限裁决、本地审计缓存或审计回放。
|
||||
- 为桌面端复制或重写一套独立业务 UI。
|
||||
|
||||
## 架构方向
|
||||
|
||||
使用运行时适配层,不在业务页面里散落平台判断。
|
||||
|
||||
当前已采用并必须继续保持的适配层边界:
|
||||
|
||||
- `platform`:识别 Web、macOS 桌面端、Windows 桌面端。
|
||||
- `apiBaseUrl`:分别解析 Web 和桌面端的服务端 API 地址。
|
||||
- `desktopServerConfig`:管理桌面服务端地址配置和切换事件。
|
||||
- `secureSessionStorage`:隔离浏览器 token 存储与桌面系统凭据库。
|
||||
- `files`:隔离浏览器上传下载与原生文件能力。
|
||||
- `notifications`:隔离 Web 通知与桌面系统通知。
|
||||
- `updates`:隔离桌面自动更新检查与安装入口。
|
||||
- `appMetadata`:在可用时提供桌面 App 版本、平台、构建通道。
|
||||
- `desktopMenu` 和 `desktopUiPreferences`:承接桌面菜单命令、最近访问和收藏等桌面体验状态。
|
||||
- `clientRuntime`:作为业务侧获取平台能力的聚合入口。
|
||||
|
||||
业务模块应调用这些适配层,而不是直接调用 Tauri API。Tauri command 应保持窄职责,不包含 CTMS 业务规则。
|
||||
|
||||
## 安全与合规方向
|
||||
|
||||
- 将桌面端视为受监管业务系统的在线客户端。
|
||||
- 非本地服务连接优先使用 HTTPS。
|
||||
- 认证与授权决策保留在后端。
|
||||
- 审计敏感决策保留在后端。
|
||||
- 敏感凭据必须继续使用明确批准的安全存储方案。
|
||||
- 不向前端暴露宽泛文件系统访问权限。
|
||||
- Tauri 权限保持最小化,并按功能精确授权。
|
||||
- 每个新增 Tauri command 都需要被视为桌面端安全边界的一部分进行审查。
|
||||
|
||||
## 分支与工作区
|
||||
|
||||
桌面端工作在以下位置开发:
|
||||
|
||||
- Worktree:`/Users/zcc/MyCTMS/ctms-dev/worktrees/ctms-desktop`
|
||||
- 短期分支:Agent 默认使用 `codex/<任务名称>`,也可按任务类型使用 `feature/*`、`fix/*`、`docs/*` 或 `release-prep/*`;所有普通桌面端工作都必须从最新 `dev` 创建
|
||||
|
||||
当前代码状态:Tauri 基线和第二阶段原生能力已经形成,后续桌面端工作默认是第二阶段范围内的修复、稳定化、体验收口和发布准备。`codex/ctms-desktop` 是历史临时集成分支,不再作为当前工作线;不得继续向该分支提交、变基或推送新的桌面端工作,除非用户明确要求做收尾或删除分支。
|
||||
|
||||
## 2026-07-01 审查结论与后续方向
|
||||
|
||||
本轮审查结论:桌面端已经完成从 Tauri 接入基线到第二阶段原生能力的主体改造,不再按空白桌面项目推进。当前重点不是扩展离线或本地业务能力,而是围绕既有在线桌面客户端做准发布稳定化。
|
||||
|
||||
已形成的能力边界:
|
||||
|
||||
- Tauri 工程、macOS App/DMG/updater artifacts 配置已经存在。
|
||||
- `frontend/src/runtime/` 已作为平台能力统一入口,业务代码不得绕过该适配层直接使用 Tauri API。
|
||||
- 桌面服务器地址、API baseURL、客户端元数据请求头、安全 session 存储、原生文件能力、系统通知、单实例、菜单/快捷键和自动更新入口已经形成。
|
||||
- 后端已经包含桌面通知订阅/投递状态、相关 API 和客户端诊断请求头支持。
|
||||
- 已有 `npm run version:check`、`npm run runtime:check`、`npm run desktop:release:check` 等门禁用于约束版本、运行时边界和桌面发布安全边界。
|
||||
|
||||
后续优化优先级:
|
||||
|
||||
1. 发布稳定化:补齐 macOS 签名、公证、组织 updater 私钥签名、release tag 构建变量注入、不可变制品上传和 `latest.json` 原子替换。
|
||||
2. 端到端回归:按 `docs/audits/desktop-release-stabilization-checklist.md` 覆盖服务器配置、服务器切换清会话、Keychain/凭据库、附件上传下载、系统通知、单实例和自动更新失败恢复。
|
||||
3. 安全复审:持续确认 token 不进入 URL、日志、系统通知正文、下载链接或明文持久化;Tauri command、capability、CSP 和 updater 改动必须同步评估发布门禁。
|
||||
4. 桌面体验收口:重点检查登录、服务器设置、个人中心诊断信息、通知开关、更新弹窗和最小窗口 `1180x760` 下的布局稳定性。
|
||||
5. CI 与发布流程:Web 与 Desktop 必须从同一提交、同一语义化版本号和同一正式标签构建;发布候选应执行本文档列出的相关质量门禁。
|
||||
6. Windows 兼容验证:仅作为第二阶段兼容性目标,验证 Credential Manager、路径处理、通知/updater 编译、WebView2 和安装器假设;未获明确批准前不发布正式 Windows 安装包。
|
||||
|
||||
如果后续任务试图新增离线登录、本地业务数据存储、内嵌后端、本地业务队列、离线同步或绕过后端权限审计,应先修改并评审本计划书,不能直接实现。
|
||||
|
||||
## 当前质量门禁
|
||||
|
||||
前端或桌面端代码变更应按影响范围执行相关检查。发布、桌面端适配层、Tauri 配置或安全边界相关变更至少考虑:
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
npm run version:check
|
||||
npm run runtime:check
|
||||
npm run desktop:release:check
|
||||
npm run ui:contract
|
||||
npm run type-check
|
||||
npm run test:unit
|
||||
npm run build
|
||||
npm run desktop:build:app
|
||||
```
|
||||
|
||||
正式桌面发布构建仍必须使用组织批准的 updater 签名私钥和 Apple 签名/公证流程;未签名或 ad-hoc 构建只能作为内部验证构建描述。文档-only 变更可以不执行完整代码门禁,但必须在结果说明中明确未运行。
|
||||
|
||||
## 每次开发前必须执行的检查
|
||||
|
||||
开始任何桌面端相关任务前:
|
||||
|
||||
- 先阅读本文档。
|
||||
- 确认任务属于第一阶段或第二阶段。
|
||||
- 确认任务不会引入离线能力。
|
||||
- 确认实现不会破坏 Web 运行时。
|
||||
- 确认 Tauri API 使用被隔离在适配层之后,除非有明确记录的理由。
|
||||
- 确认不会重复初始化 Tauri 或绕过既有 `frontend/src/runtime/` 运行时边界。
|
||||
- 涉及 Tauri 权限、CSP、updater、凭据、文件或通知能力时,确认桌面发布检查脚本和发布清单是否需要同步更新。
|
||||
|
||||
如果用户请求与本文档冲突,先停止实现并确认范围,不要直接推进。
|
||||
@@ -0,0 +1,493 @@
|
||||
# CTMS 分支维护与版本更新标准操作规程
|
||||
|
||||
## 一、目的
|
||||
|
||||
本规程用于统一 CTMS 网页端和桌面端的代码提交、分支维护、版本晋级、正式发布及生产热修复流程。
|
||||
|
||||
CTMS 网页端和桌面端属于同一个产品,必须共用:
|
||||
|
||||
- 同一个代码仓库
|
||||
- 同一套业务核心代码
|
||||
- 同一条版本晋级链路
|
||||
- 同一个语义化版本号
|
||||
- 同一个正式发布标签
|
||||
- 同一个源代码提交
|
||||
|
||||
不得为网页端和桌面端分别建立长期开发、测试或发布分支。
|
||||
|
||||
## 二、长期分支职责
|
||||
|
||||
| 分支 | 职责 | 允许进入的内容 | 稳定性要求 |
|
||||
| --- | --- | --- | --- |
|
||||
| `dev` | 日常开发与集成 | 已评审的功能、修复和重构 | 可持续集成 |
|
||||
| `main` | 下一正式版本候选 | 从 `dev` 晋级的完整版本范围、候选版本修复 | 原则上可部署 |
|
||||
| `release` | 当前生产稳定版本 | 从 `main` 验收通过的正式版本、生产热修复 | 最高 |
|
||||
|
||||
默认晋级方向:
|
||||
|
||||
```text
|
||||
功能分支 -> dev -> main -> release -> 正式版本标签
|
||||
```
|
||||
|
||||
禁止以下长期分支:
|
||||
|
||||
```text
|
||||
web-dev
|
||||
desktop-dev
|
||||
web-release
|
||||
desktop-release
|
||||
macos-main
|
||||
windows-main
|
||||
```
|
||||
|
||||
桌面端差异必须放在 `frontend/src/runtime/` 适配层之后,不通过长期分支保存平台差异。
|
||||
|
||||
## 三、临时分支命名
|
||||
|
||||
| 类型 | 命名格式 | 示例 |
|
||||
| --- | --- | --- |
|
||||
| 新功能 | `feature/<功能名称>` | `feature/desktop-file-picker` |
|
||||
| 缺陷修复 | `fix/<问题名称>` | `fix/session-timeout` |
|
||||
| 生产热修复 | `hotfix/<问题名称>` | `hotfix/login-loop` |
|
||||
| 文档调整 | `docs/<文档名称>` | `docs/release-sop` |
|
||||
| 发布准备 | `release-prep/<版本号>` | `release-prep/v1.2.0` |
|
||||
| Agent 临时任务 | `codex/<任务名称>` | `codex/desktop-menu-polish` |
|
||||
|
||||
分支名称使用小写英文和连字符,不使用个人姓名、日期或模糊名称。
|
||||
|
||||
## 四、日常功能开发流程
|
||||
|
||||
### 1. 从最新 `dev` 创建分支
|
||||
|
||||
```bash
|
||||
git fetch origin
|
||||
git switch dev
|
||||
git pull --ff-only origin dev
|
||||
git switch -c feature/<功能名称>
|
||||
```
|
||||
|
||||
不得从旧功能分支、`main` 或 `release` 创建普通功能分支。
|
||||
|
||||
### 2. 开发过程中同步 `dev`
|
||||
|
||||
短期分支优先使用变基保持提交清晰:
|
||||
|
||||
```bash
|
||||
git fetch origin
|
||||
git rebase origin/dev
|
||||
```
|
||||
|
||||
已经由多人共同使用的分支,不得擅自强制推送。此时可使用合并:
|
||||
|
||||
```bash
|
||||
git fetch origin
|
||||
git merge origin/dev
|
||||
```
|
||||
|
||||
### 3. 提交前检查
|
||||
|
||||
前端或桌面端改动至少执行:
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
npm run version:check
|
||||
npm run runtime:check
|
||||
npm run desktop:release:check
|
||||
npm run ui:contract
|
||||
npm run type-check
|
||||
npm run test:unit
|
||||
npm run build
|
||||
npm run desktop:build:app
|
||||
```
|
||||
|
||||
涉及 Tauri、macOS 打包或桌面适配层时,还必须在 macOS 执行:
|
||||
|
||||
```bash
|
||||
npm run desktop:build:app
|
||||
```
|
||||
|
||||
正式桌面发布构建仍必须设置 updater 签名私钥后执行
|
||||
`npm run desktop:build -- --bundles app`。
|
||||
|
||||
后端改动应补充执行受影响模块的后端测试、迁移检查和接口回归。
|
||||
|
||||
### 4. 创建提交
|
||||
|
||||
只暂存本次任务相关文件:
|
||||
|
||||
```bash
|
||||
git status
|
||||
git add <本次任务相关文件>
|
||||
git diff --cached
|
||||
git diff --cached --check
|
||||
git commit -m "<类型>(<范围>): <变更说明>"
|
||||
```
|
||||
|
||||
推荐提交类型:
|
||||
|
||||
| 类型 | 用途 |
|
||||
| --- | --- |
|
||||
| `feat` | 新功能 |
|
||||
| `fix` | 缺陷修复 |
|
||||
| `refactor` | 不改变业务行为的重构 |
|
||||
| `test` | 测试调整 |
|
||||
| `docs` | 文档调整 |
|
||||
| `build` | 构建和依赖调整 |
|
||||
| `ci` | 持续集成调整 |
|
||||
|
||||
示例:
|
||||
|
||||
```text
|
||||
feat(desktop): 增加原生文件选择适配器
|
||||
fix(auth): 修复会话超时后的重复跳转
|
||||
refactor(client): 统一网页端和桌面端运行时入口
|
||||
```
|
||||
|
||||
一次提交只处理一个明确目的。不得将无关格式化、个人配置或临时产物混入提交。
|
||||
|
||||
### 5. 推送并创建合并请求
|
||||
|
||||
```bash
|
||||
git push -u origin feature/<功能名称>
|
||||
```
|
||||
|
||||
创建:
|
||||
|
||||
```text
|
||||
feature/<功能名称> -> dev
|
||||
```
|
||||
|
||||
合并要求:
|
||||
|
||||
- 代码评审通过
|
||||
- 必要测试通过
|
||||
- 客户端质量门禁通过
|
||||
- 没有误提交密钥、环境文件或构建产物
|
||||
- 桌面能力符合第一阶段或第二阶段边界
|
||||
|
||||
功能分支进入 `dev` 可使用合并请求合并或变基合并。提交过于零散时应先整理。
|
||||
|
||||
### 6. 合并后清理
|
||||
|
||||
确认改动已经进入远程 `dev` 后删除临时分支:
|
||||
|
||||
```bash
|
||||
git switch dev
|
||||
git pull --ff-only origin dev
|
||||
git branch -d feature/<功能名称>
|
||||
git push origin --delete feature/<功能名称>
|
||||
```
|
||||
|
||||
工作树正在使用的分支不能直接删除,应先切换分支或移除对应工作树。
|
||||
|
||||
## 五、历史桌面集成分支约束
|
||||
|
||||
`codex/ctms-desktop` 是第一阶段 Tauri 基线使用过的历史临时集成分支,不作为当前桌面端工作线,也不作为长期桌面主线。
|
||||
|
||||
当前约束:
|
||||
|
||||
- 不得继续向 `codex/ctms-desktop` 提交、变基或推送新的桌面端工作。
|
||||
- 如本地或远程仍保留该分支,只能用于追溯历史或在确认已合入 `dev` 后删除。
|
||||
- 后续桌面功能、修复、稳定化和发布准备必须从最新 `dev` 创建短期 `feature/*`、`fix/*`、`docs/*`、`release-prep/*` 或 `codex/*` 分支。
|
||||
- Agent 创建分支默认使用 `codex/<任务名称>`,并在任务合入 `dev` 后删除。
|
||||
- 如果工作区处于 detached HEAD 或包含尚未归属到分支的提交,执行分支切换、提交、推送或变基前必须先确认目标基线和处理方式。
|
||||
|
||||
## 六、从 `dev` 晋级到 `main`
|
||||
|
||||
当一个版本范围在 `dev` 完成集成后,创建:
|
||||
|
||||
```text
|
||||
dev -> main
|
||||
```
|
||||
|
||||
进入 `main` 前必须确认:
|
||||
|
||||
- 本版本范围已经冻结
|
||||
- 未完成功能已经排除或关闭入口
|
||||
- 前后端测试通过
|
||||
- 网页端构建通过
|
||||
- macOS 桌面端构建通过
|
||||
- 数据库迁移经过验证
|
||||
- 已知风险和回滚方式已记录
|
||||
|
||||
正式创建晋级合并请求前,应按照第七节完成统一版本号更新,并确保版本提交已经进入 `dev`。
|
||||
|
||||
按照当前仓库治理规则,`dev` 进入 `main` 使用压缩合并,并使用版本候选级提交说明:
|
||||
|
||||
```text
|
||||
release(main): 准备 v1.2.0 候选版本
|
||||
```
|
||||
|
||||
不得从功能分支直接跳过 `dev` 合并到 `main`。
|
||||
|
||||
## 七、统一更新客户端版本
|
||||
|
||||
网页端和桌面端只能使用同一个产品版本号。
|
||||
|
||||
从最新 `dev` 创建发布准备分支:
|
||||
|
||||
```bash
|
||||
git fetch origin
|
||||
git switch dev
|
||||
git pull --ff-only origin dev
|
||||
git switch -c release-prep/v1.2.0
|
||||
```
|
||||
|
||||
统一更新版本并提交:
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
npm run version:set -- 1.2.0
|
||||
npm run version:check
|
||||
cd ..
|
||||
git add frontend/package.json frontend/package-lock.json frontend/src-tauri/tauri.conf.json
|
||||
git add frontend/src-tauri/Cargo.toml frontend/src-tauri/Cargo.lock
|
||||
git commit -m "build(release): 更新客户端版本至 v1.2.0"
|
||||
git push -u origin release-prep/v1.2.0
|
||||
```
|
||||
|
||||
创建 `release-prep/v1.2.0 -> dev` 合并请求。合并后再执行 `dev -> main` 的版本晋级。
|
||||
|
||||
该命令同步更新:
|
||||
|
||||
- `frontend/package.json`
|
||||
- `frontend/package-lock.json`
|
||||
- `frontend/src-tauri/tauri.conf.json`
|
||||
- `frontend/src-tauri/Cargo.toml`
|
||||
- `frontend/src-tauri/Cargo.lock`
|
||||
|
||||
版本号遵循:
|
||||
|
||||
| 类型 | 示例 | 使用场景 |
|
||||
| --- | --- | --- |
|
||||
| 主版本 | `2.0.0` | 不兼容变更或重大架构调整 |
|
||||
| 次版本 | `1.3.0` | 向后兼容的新功能 |
|
||||
| 修订版本 | `1.2.1` | 向后兼容的缺陷修复 |
|
||||
|
||||
禁止单独设置桌面端版本号。
|
||||
|
||||
## 八、从 `main` 发布到 `release`
|
||||
|
||||
候选版本验收通过后,创建:
|
||||
|
||||
```text
|
||||
main -> release
|
||||
```
|
||||
|
||||
按照当前仓库治理规则,使用普通合并提交,保留候选版本与生产版本之间的关系。
|
||||
|
||||
合并前必须确认:
|
||||
|
||||
- 回归测试通过
|
||||
- 数据库迁移和回滚方案确认
|
||||
- 网页端生产构建通过
|
||||
- 桌面端生产构建通过
|
||||
- 发布说明完成
|
||||
- 生产配置和密钥不在仓库中
|
||||
- 正式版本号已经统一
|
||||
|
||||
合并后立即在 `release` 的准确提交上创建标签:
|
||||
|
||||
```bash
|
||||
git switch release
|
||||
git pull --ff-only origin release
|
||||
git tag -a v1.2.0 -m "CTMS v1.2.0"
|
||||
git push origin v1.2.0
|
||||
```
|
||||
|
||||
网页端和桌面端必须从同一个 `v1.2.0` 标签构建。不得从不同分支、不同提交或本地未提交状态构建正式制品。
|
||||
|
||||
发布记录至少包含:
|
||||
|
||||
- 产品版本号
|
||||
- Git 标签
|
||||
- 完整提交编号
|
||||
- 网页端制品编号
|
||||
- 桌面端制品编号
|
||||
- 数据库迁移版本
|
||||
- 发布日期和负责人
|
||||
|
||||
## 九、生产热修复流程
|
||||
|
||||
### 1. 从 `release` 创建热修复分支
|
||||
|
||||
```bash
|
||||
git fetch origin
|
||||
git switch release
|
||||
git pull --ff-only origin release
|
||||
git switch -c hotfix/<问题名称>
|
||||
```
|
||||
|
||||
热修复只能包含解决生产问题所需的最小改动,不得顺带加入新功能或大规模重构。
|
||||
|
||||
### 2. 更新修订版本
|
||||
|
||||
例如从 `1.2.0` 更新到 `1.2.1`:
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
npm run version:set -- 1.2.1
|
||||
npm run version:check
|
||||
cd ..
|
||||
```
|
||||
|
||||
### 3. 验证并提交
|
||||
|
||||
```bash
|
||||
git add <热修复相关文件和版本文件>
|
||||
git diff --cached --check
|
||||
git commit -m "fix(<范围>): <生产问题说明>"
|
||||
git push -u origin hotfix/<问题名称>
|
||||
```
|
||||
|
||||
创建:
|
||||
|
||||
```text
|
||||
hotfix/<问题名称> -> release
|
||||
```
|
||||
|
||||
### 4. 合并并创建标签
|
||||
|
||||
热修复合并到 `release` 并验证后创建 `v1.2.1` 标签。
|
||||
|
||||
### 5. 强制回合并
|
||||
|
||||
生产热修复必须立即回合并:
|
||||
|
||||
```text
|
||||
release -> main -> dev
|
||||
```
|
||||
|
||||
不得假设 `main` 或 `dev` 已经包含相同修复。发生冲突时必须立即解决并在合并请求中记录原因。
|
||||
|
||||
## 十、冲突处理规则
|
||||
|
||||
发生冲突时:
|
||||
|
||||
1. 先确认冲突两侧的业务意图。
|
||||
2. 不使用整文件覆盖方式跳过判断。
|
||||
3. 保留双方仍然有效的修改。
|
||||
4. 重新执行受影响测试。
|
||||
5. 在合并请求中记录冲突文件和处理结果。
|
||||
|
||||
禁止使用以下方式处理普通同步冲突:
|
||||
|
||||
```bash
|
||||
git reset --hard
|
||||
git checkout -- <文件>
|
||||
```
|
||||
|
||||
除非已经明确确认可以丢弃本地修改,否则不得执行破坏性命令。
|
||||
|
||||
## 十一、分支保护建议
|
||||
|
||||
### `release`
|
||||
|
||||
- 禁止直接推送
|
||||
- 必须通过合并请求
|
||||
- 至少一名评审人批准
|
||||
- 必须通过状态检查
|
||||
- 正式标签只由发布负责人创建
|
||||
|
||||
### `main`
|
||||
|
||||
- 禁止直接推送
|
||||
- 必须通过合并请求
|
||||
- 必须完成回归和构建检查
|
||||
- 只接收版本候选内容
|
||||
|
||||
### `dev`
|
||||
|
||||
- 优先通过合并请求
|
||||
- 必须通过相关测试
|
||||
- 禁止提交密钥和本地配置
|
||||
- 禁止合入明确不可构建的代码
|
||||
|
||||
## 十二、每周分支维护
|
||||
|
||||
每周至少执行一次:
|
||||
|
||||
```bash
|
||||
git fetch --prune origin
|
||||
git branch -vv
|
||||
git log --oneline --decorate --graph --all -30
|
||||
```
|
||||
|
||||
检查事项:
|
||||
|
||||
- 已合并临时分支是否删除
|
||||
- 是否出现未经批准的长期平台分支
|
||||
- `dev`、`main`、`release` 是否符合各自职责
|
||||
- 生产热修复是否已回合并到 `main` 和 `dev`
|
||||
- 版本文件是否一致
|
||||
- 正式标签是否准确指向 `release`
|
||||
- 持续集成门禁是否持续通过
|
||||
|
||||
## 十三、禁止事项
|
||||
|
||||
- 禁止长期维护网页端和桌面端平行分支
|
||||
- 禁止通过复制代码维护桌面端业务页面
|
||||
- 禁止在业务模块中直接使用 Tauri API
|
||||
- 禁止在不同提交上构建同一版本的网页端和桌面端
|
||||
- 禁止未经 `dev` 和 `main` 直接向 `release` 发布普通功能
|
||||
- 禁止生产热修复只进入 `release` 而不回合并
|
||||
- 禁止在正式构建中包含未提交文件
|
||||
- 禁止提交 `.env`、密钥、证书、令牌和个人配置
|
||||
- 禁止提交 `node_modules`、`dist`、Tauri `target` 等构建产物
|
||||
|
||||
## 十四、发布前最终检查清单
|
||||
|
||||
- [ ] 本次发布范围已经冻结
|
||||
- [ ] `dev` 集成测试通过
|
||||
- [ ] `main` 候选版本验收通过
|
||||
- [ ] 网页端与桌面端版本一致
|
||||
- [ ] `npm run version:check` 通过
|
||||
- [ ] `npm run runtime:check` 通过
|
||||
- [ ] `npm run desktop:release:check` 通过
|
||||
- [ ] `npm run ui:contract` 通过
|
||||
- [ ] `npm run type-check` 通过
|
||||
- [ ] `npm run test:unit` 通过
|
||||
- [ ] `npm run build` 通过
|
||||
- [ ] `npm run desktop:build:app` 通过
|
||||
- [ ] 正式桌面发布构建已使用 updater 签名私钥执行
|
||||
- [ ] 数据库迁移与回滚方案确认
|
||||
- [ ] 发布说明完成
|
||||
- [ ] `main -> release` 合并完成
|
||||
- [ ] 正式标签创建在准确的 `release` 提交上
|
||||
- [ ] 网页端和桌面端从同一标签构建
|
||||
- [ ] 发布记录包含版本、标签和完整提交编号
|
||||
|
||||
## 十五、流程速查
|
||||
|
||||
普通功能:
|
||||
|
||||
```text
|
||||
最新 dev
|
||||
-> feature/*
|
||||
-> 开发、测试、评审
|
||||
-> dev
|
||||
-> 删除临时分支
|
||||
```
|
||||
|
||||
正式发布:
|
||||
|
||||
```text
|
||||
dev
|
||||
-> main
|
||||
-> 统一版本号
|
||||
-> 回归与验收
|
||||
-> release
|
||||
-> 创建 vX.Y.Z 标签
|
||||
-> 同一标签构建网页端和桌面端
|
||||
```
|
||||
|
||||
生产热修复:
|
||||
|
||||
```text
|
||||
release
|
||||
-> hotfix/*
|
||||
-> release
|
||||
-> 创建修订版本标签
|
||||
-> main
|
||||
-> dev
|
||||
```
|
||||
@@ -0,0 +1,177 @@
|
||||
# CTMS Web and Desktop Release Guide
|
||||
|
||||
## Release Unit
|
||||
|
||||
CTMS uses one repository, one promotion path, and one product version. Web and
|
||||
Desktop are build targets from the same source commit, not separately versioned
|
||||
products.
|
||||
|
||||
The release identity consists of:
|
||||
|
||||
- semantic version, for example `1.8.0`
|
||||
- Git tag, for example `v1.8.0`
|
||||
- full Git commit SHA
|
||||
- build channel: `dev`, `main`, or `release`
|
||||
- client type: `web` or `desktop`
|
||||
|
||||
## Runtime Boundary
|
||||
|
||||
Shared Vue business code lives under `frontend/src/`. Platform decisions are
|
||||
exposed through `frontend/src/runtime/index.ts`.
|
||||
|
||||
The runtime contract currently provides:
|
||||
|
||||
- API base URL resolution
|
||||
- Web, macOS, Windows, and Linux runtime identification
|
||||
- app version, source commit, build channel, and client type metadata
|
||||
- explicit capability flags
|
||||
- Desktop server address configuration
|
||||
- secure session storage
|
||||
- file picker/save/open adapters
|
||||
- desktop system notification adapters
|
||||
- desktop updater adapters
|
||||
|
||||
Business modules must use this public runtime entry point. They must not inspect
|
||||
Tauri globals or import Tauri packages directly. Native files, notifications,
|
||||
secure session storage, and automatic updates must remain behind
|
||||
`frontend/src/runtime/` and explicit capability flags.
|
||||
|
||||
## Version Change
|
||||
|
||||
Update every client manifest with one command:
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
npm run version:set -- 1.8.0
|
||||
npm run version:check
|
||||
```
|
||||
|
||||
This synchronizes:
|
||||
|
||||
- `frontend/package.json`
|
||||
- `frontend/package-lock.json`
|
||||
- `frontend/src-tauri/tauri.conf.json`
|
||||
- `frontend/src-tauri/Cargo.toml`
|
||||
- `frontend/src-tauri/Cargo.lock`
|
||||
|
||||
Manual edits that leave these files inconsistent fail CI.
|
||||
|
||||
## Stabilization Gates
|
||||
|
||||
Client release candidates must pass the shared Web checks and the Desktop
|
||||
release/security gate before promotion:
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
npm run version:check
|
||||
npm run release:env:check
|
||||
npm run runtime:check
|
||||
npm run desktop:release:check
|
||||
npm run ui:contract
|
||||
npm run type-check
|
||||
npm run test:unit
|
||||
npm run build
|
||||
npm run desktop:build:app
|
||||
```
|
||||
|
||||
`release:env:check` verifies build channel and commit metadata, and can be
|
||||
made strict for signed Desktop builds with `REQUIRE_DESKTOP_SIGNING=true`.
|
||||
`desktop:release:check` statically verifies the Tauri bundle, updater public
|
||||
key, CSP, capability scopes, command allowlist, query-token ban, generic system
|
||||
notification boundary, CI gate coverage, and secure session token boundary. The
|
||||
full manual release, security, regression, and Desktop UX checklist lives in
|
||||
`docs/audits/desktop-release-stabilization-checklist.md`.
|
||||
|
||||
## Promotion
|
||||
|
||||
1. Merge feature branches into `dev`.
|
||||
2. Require the shared client/Web and macOS Desktop CI jobs to pass.
|
||||
3. Promote the accepted scope from `dev` to `main`.
|
||||
4. Set the release version and complete regression testing on `main`.
|
||||
5. Promote `main` to `release`.
|
||||
6. Create the matching `vX.Y.Z` tag on the accepted `release` commit.
|
||||
7. Build both Web and Desktop artifacts from that exact tag.
|
||||
|
||||
Build metadata is injected by CI:
|
||||
|
||||
```bash
|
||||
VITE_BUILD_CHANNEL=release
|
||||
VITE_BUILD_COMMIT="$(git rev-parse HEAD)"
|
||||
```
|
||||
|
||||
These values support diagnostics but do not replace the semantic version.
|
||||
|
||||
## Desktop Updater
|
||||
|
||||
Formal Desktop release builds must use Tauri updater signatures. The application
|
||||
embeds the updater public key in `frontend/src-tauri/tauri.conf.json`; the
|
||||
private key must live only in the organization key vault or CI secret store.
|
||||
|
||||
Runtime update checks derive the feed from the currently configured CTMS origin:
|
||||
|
||||
```text
|
||||
/desktop-updates/stable/latest.json
|
||||
```
|
||||
|
||||
Production update feeds must use HTTPS. Local update testing may use HTTP only
|
||||
for `localhost`, `127.0.0.1`, or `::1`.
|
||||
|
||||
The release pipeline must:
|
||||
|
||||
1. build from the accepted release tag and commit;
|
||||
2. build macOS Universal desktop artifacts;
|
||||
3. sign and notarize the macOS app;
|
||||
4. produce updater artifacts and `.sig` files with the updater private key;
|
||||
5. generate `latest.json` and a checksum manifest;
|
||||
6. verify the feed with `npm run desktop:update-feed:check -- --feed <latest.json> --artifacts-dir <artifact-dir>`;
|
||||
7. upload immutable artifacts first;
|
||||
8. atomically replace `latest.json` last.
|
||||
|
||||
For Universal macOS artifacts, `latest.json` must provide both
|
||||
`darwin-aarch64` and `darwin-x86_64` entries pointing at the same Universal
|
||||
update package.
|
||||
|
||||
## Windows Build Readiness
|
||||
|
||||
Second-phase Windows work is limited to CI compatibility validation. A
|
||||
`windows-latest` x64 NSIS build may be produced for verification, but it is not
|
||||
a formal deliverable until Windows code signing and release support are
|
||||
approved.
|
||||
|
||||
Windows validation must cover:
|
||||
|
||||
- WebView2 runtime prerequisite behavior;
|
||||
- user-level installer assumptions;
|
||||
- Windows Credential Manager session storage;
|
||||
- path handling and temporary file cleanup;
|
||||
- notification and updater compilation;
|
||||
- future code-signing requirements.
|
||||
|
||||
## Required Checks
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
npm ci
|
||||
npm run version:check
|
||||
export VITE_BUILD_CHANNEL=release
|
||||
export VITE_BUILD_COMMIT="$(git rev-parse HEAD)"
|
||||
npm run release:env:check
|
||||
npm run runtime:check
|
||||
npm run desktop:release:check
|
||||
npm run ui:contract
|
||||
npm run type-check
|
||||
npm run test:unit
|
||||
npm run build
|
||||
npm run desktop:build:app
|
||||
export TAURI_SIGNING_PRIVATE_KEY="$UPDATER_PRIVATE_KEY"
|
||||
export TAURI_SIGNING_PRIVATE_KEY_PASSWORD="$UPDATER_PRIVATE_KEY_PASSWORD"
|
||||
export REQUIRE_DESKTOP_SIGNING=true
|
||||
npm run release:env:check
|
||||
npm run desktop:build -- --bundles app
|
||||
npm run desktop:update-feed:check -- --feed src-tauri/target/release/bundle/latest.json --artifacts-dir src-tauri/target/release/bundle
|
||||
```
|
||||
|
||||
The Desktop build must run on macOS for the current first-phase target. A signed
|
||||
or notarized public release additionally requires the Apple credentials defined
|
||||
by the release owner. A formal second-phase desktop release also requires the
|
||||
updater signing key; unsigned internal builds are not formal distributions.
|
||||
Reference in New Issue
Block a user