From 46adc32e2d627389ddd81be377a77a78e6802181 Mon Sep 17 00:00:00 2001 From: chengma Date: Wed, 8 Jul 2026 14:46:03 +0800 Subject: [PATCH] docs: add update-check contract (T-559 done) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 docs/update-check.md:版本检查接口的服务端响应契约、客户端字段读取、 强制规则与发版约定(方案A force_update / 方案B min_supported_version); README 加索引;T-559 标 DONE。客户端无需改代码(T-544 已实现)。 Co-Authored-By: Claude Opus 4.8 --- docs/README.md | 1 + docs/tasks/T-559.md | 7 ++- docs/update-check.md | 106 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 docs/update-check.md diff --git a/docs/README.md b/docs/README.md index 7aee07f..790a7b6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -28,6 +28,7 @@ - [工程评估](engineering-review.md):全栈视角评估工程基础设施与可维护性(依赖清单 / CI / 打包 / gui.py 拆分 / lint),含 P0-P2 与优先级。 - [打包与分发](packaging.md):PyInstaller 免安装 exe 打包命令、排除本地数据规则和用户手动更新方式。 - [对接 cmhub AI 网关设计](cmhub-integration-design.md):把生文/生图从本地直连改为对接 cmhub 计费网关的设计方案、改动边界与待确认问题。 +- [版本检查接口契约](update-check.md):启动强制升级的服务端响应格式、客户端读取字段、强制规则与发版约定。 ## 运行环境安装 diff --git a/docs/tasks/T-559.md b/docs/tasks/T-559.md index 1e301bb..d2fc8f9 100644 --- a/docs/tasks/T-559.md +++ b/docs/tasks/T-559.md @@ -3,7 +3,7 @@ id: T-559 title: 版本检查响应契约 + 强制升级约定(force_update)固化进仓库 phase: 7 deps: [T-544] -status: TODO +status: DONE created: 2026-07-08 --- @@ -45,4 +45,7 @@ created: 2026-07-08 ## 执行记录 -(做完在此记录:改了哪些文件、跑的验证命令与结果、决策) +- 2026-07-08:完成 T-559。 +- 文档:新增 `docs/update-check.md`——接口/客户端字段读取(对照 `app/update_check.py` 的 `parse_update_info`/`is_forced_update`:`version`|`latest_version`、`force_update`、`min_supported_version`、`download_url`、`sha256`、`release_notes`|`message`,顶层或 `release` 里都认)/强制规则/客户端行为(T-544 已实现)/失败放行/发版约定(方案A `force_update:true`、方案B `min_supported_version`)/三份示例响应。`docs/README.md` 加索引一行。 +- 未改客户端代码:`app/update_check.py`/`app/version.py`/启动流程按契约已实现(T-544);服务端返回 `force_update` 属本仓库外配置。 +- 验证:纯文档任务,字段逐条对照 `app/update_check.py` 源码确认一致;未跑单测(无代码改动)。 diff --git a/docs/update-check.md b/docs/update-check.md new file mode 100644 index 0000000..b592067 --- /dev/null +++ b/docs/update-check.md @@ -0,0 +1,106 @@ +# 版本检查接口契约(启动强制升级) + +> 客户端在启动时请求版本接口,判断是否需要**强制升级**。本文是**服务端响应格式的权威契约**——字段以 `app/update_check.py` 的实际读取逻辑为准,服务端按此返回,避免格式漂移。 +> 客户端逻辑已由 T-544 实现,本文不要求改客户端代码;发强制版时按「发版约定」配置服务端响应即可。 + +## 一、接口 + +- 客户端在 `main()` 启动流程里、进主界面之前请求(`app/gui/__init__.py` 的 `_run_startup_update_gate` → `app/update_check.py`)。 +- URL 硬编码于 `app/version.py`: + ``` + APP_UPDATE_CHECK_URL = "https://cm.833729.com/api/v1/client/releases/latest?platform=windows" + ``` +- 方法:`GET`,请求头 `Accept: application/json`、`User-Agent: cmshopee/<版本>`。 +- 客户端当前版本见 `app/version.py` 的 `APP_VERSION`。 + +## 二、客户端读取的字段(`update_check.parse_update_info`) + +响应是一个 JSON 对象。以下字段**顶层 payload 或 `release` 子对象里都认**(客户端按 `payload.get(x) or release.get(x)` 取,顶层优先): + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| `version` / `latest_version` | string | 最新版本号。客户端取 `payload.latest_version` 或 `release.version`。**`latest_version` 与 `min_supported_version` 至少要有一个**,否则客户端判为"接口缺字段"、按失败放行 | +| `force_update` | bool | 是否强制升级。`true`/`1`/`yes`/`y`/`on`(大小写不敏感)都识别为真 | +| `min_supported_version` | string | 最低支持版本;本地低于它一律强制 | +| `download_url` | string(URL) | 「下载新版」按钮打开的地址(用系统浏览器打开)| +| `sha256` | string | 安装包校验值;**第一版不校验,可留空** | +| `release_notes` / `message` | string | 升级说明,显示在强制升级弹窗里。客户端取 `message` 或 `release_notes` | + +版本号比较用**语义化数字段比较**(`compare_versions`,逐段比数字),不是字符串字典序:`0.1.10 > 0.1.9`。 + +## 三、强制规则(`is_forced_update`) + +满足**任一**即判为强制: + +1. `force_update = true` **且** 本地版本 `<` `latest_version`; +2. 本地版本 `<` `min_supported_version`。 + +两者都不满足 → **非强制**。 + +## 四、客户端行为(T-544 已实现) + +- **强制**:弹**模态框**,显示 `release_notes`/`message`,按钮只有「下载新版」(打开 `download_url`)和「退出程序」;无论点哪个,**程序退出、进不了主界面** → 必须升级后才能用。 +- **非强制**:**不弹任何提示**,直接进主界面(当前无"温和可跳过提示"分支;如需另立任务)。 +- **失败放行**:接口断网、超时、返回非法 JSON、缺 `latest_version`/`min_supported_version` 时,客户端记诊断日志(`data/logs/cmshopee.log`,`step=startup_update_check`「已允许继续使用」)并**放行**,不因服务器故障导致全员打不开。 + +## 五、发版约定(服务端据此控制) + +| 想要的效果 | 服务端返回 | +| --- | --- | +| **强制升到最新**(方案 A) | `release.force_update: true` + `release.version` 高于要淘汰的客户端版本 | +| **强制淘汰旧版**(方案 B) | `min_supported_version` 设为要淘汰之上的版本(顶层或 `release` 里都可)| +| **不强制** | `force_update`/`min_supported_version` 都不给 → 客户端不弹(当前不提示)| + +## 六、示例响应 + +### 强制升级(方案 A,推荐) + +```json +{ + "platform": "windows", + "release": { + "version": "0.1.1", + "download_url": "https://cm.833729.com/media/downloads/%E8%9D%A6%E7%9A%AE%E5%9C%88%E5%84%AA%E5%8C%96%E5%8A%A9%E6%89%8B0.1.1.zip", + "sha256": "", + "release_notes": "优化了ai模块的生图的功能", + "published_at": "2026-07-08T14:30:26.935549+08:00", + "force_update": true + } +} +``` +效果:本地 `0.1.0` < `0.1.1` 且 `force_update=true` → 强制弹窗、必须升级。 + +### 强制淘汰旧版(方案 B) + +```json +{ + "platform": "windows", + "min_supported_version": "0.1.1", + "release": { + "version": "0.1.1", + "download_url": "https://cm.833729.com/media/downloads/...0.1.1.zip", + "release_notes": "优化了ai模块的生图的功能" + } +} +``` +效果:本地低于 `0.1.1` 的一律强制升级。 + +### 不强制(有新版但不逼升) + +```json +{ + "platform": "windows", + "release": { + "version": "0.1.1", + "download_url": "https://cm.833729.com/media/downloads/...0.1.1.zip", + "release_notes": "优化了ai模块的生图的功能" + } +} +``` +效果:客户端解析成功但判为非强制 → **当前不弹提示**,直接进主界面。 + +## 七、注意 + +- 服务端返回 `force_update`/`min_supported_version` 属**本仓库外的服务端配置**;客户端代码(`app/update_check.py`/`app/version.py`/启动流程)已按本契约实现,**发强制版不需要改客户端**。 +- `download_url` 里的中文可用 URL 编码(如 `%E8%9D%A6...`),系统浏览器能正确打开。 +- 若将来要"非强制也温和提示(可跳过、不阻断)",需在客户端加一个非强制分支,另立任务。