Files
cmshoppe/docs/update-check.md
chengmaandClaude Opus 4.8 46adc32e2d
Tests / Python 3.11 / Windows (push) Has been cancelled
docs: add update-check contract (T-559 done)
新增 docs/update-check.md:版本检查接口的服务端响应契约、客户端字段读取、
强制规则与发版约定(方案A force_update / 方案B min_supported_version);
README 加索引;T-559 标 DONE。客户端无需改代码(T-544 已实现)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 14:46:03 +08:00

107 lines
5.1 KiB
Markdown
Raw Permalink 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.
# 版本检查接口契约(启动强制升级)
> 客户端在启动时请求版本接口,判断是否需要**强制升级**。本文是**服务端响应格式的权威契约**——字段以 `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...`),系统浏览器能正确打开。
- 若将来要"非强制也温和提示(可跳过、不阻断)",需在客户端加一个非强制分支,另立任务。