12 KiB
For AI assistants: Read this entire file before writing any code. All decisions here are final. Do not suggest alternatives unless asked.
Fonrey 客户端发布管理技术方案
版本: 1.0
项目: Fonrey 房产经纪管理系统
技术栈: Django 4.x + HTMX + PostgreSQL 16(public schema)+ Redis + Celery + Electron + electron-updater + Cloudflare R2/CDN
关联 PRD: PRD/发布管理/客户端发布管理模块PRD.md(v1.2)
关联数据模型: DATA_MODEL/DATA_MODEL_PUBLIC.md(client_releases / client_heartbeats)
关联枚举字典: DATA_MODEL/ENUMS.md(含中文显示标签)
关联契约规范: TECH_STACK/API_CONTRACT.md
最后更新: 2026-04-30
变更历史
| 日期 | 变更人 | 变更内容 |
|---|---|---|
| 2026-04-30 | Atlas | 补充“变更历史”章节(文档治理) |
一、文档定位与边界
本文件定义客户端发布管理模块(apps/release)的实现口径:
- Electron 客户端壳应用与运行时安全边界
- EV 代码签名与构建发布链路
- Heartbeat 上报与版本分布统计方案
- 自动升级、强制升级与失败回退策略
- 客户端下载完整性校验(SHA256)
- R2 版本资产管理(对象键、状态流转、回滚)
- 公司下载站点(官网)分发方案
- 便携版(Portable ZIP)落地方案
本文件不重复 DDL。表结构与索引以
DATA_MODEL_PUBLIC.md为唯一权威。
二、范围定义(以 PRD v1.2 为准)
2.1 P0 必须覆盖
- Windows 客户端(win32)下载安装与登录使用
- 平台运营后台版本管理(草稿/发布/下线、普通/强制)
- 自动更新(启动 + 每 4 小时检测)
- SHA256 完整性校验(EXE/ZIP)
- Heartbeat(启动时上报)与版本分布/租户活跃统计
- 官方下载页(公司站点)
- 便携版 ZIP(可选上传、受控分发)
2.2 非目标(本期不做)
- macOS / Linux 客户端
- 移动端 App
- 客户端离线模式
- 客户端反逆向加固(v2)
三、模块架构边界
3.1 模块职责(apps/release)
- 管理端:客户端版本元数据管理、发布状态流转、回滚
- 公共接口:客户端更新检测、下载引导、Heartbeat 上报
- 统计接口:版本分布、租户活跃数、历史装机总数
- 资产管理:R2 对象键规范、发布包引用与审计
3.2 分层与鉴权
| 子能力 | Schema | 鉴权 | 说明 |
|---|---|---|---|
| 版本管理后台 API | public | Platform Admin 必须认证 | 跨租户统一运营能力 |
| 更新检测 API | public | 公开(客户端调用) | 仅返回当前发布版本,不暴露草稿/下线版本 |
| Heartbeat API | public | 已登录客户端会话或签名设备票据 | 防伪造上报、防刷统计 |
| 统计 API | public | Platform Admin 必须认证 | 提供 Story 5 所需聚合指标 |
3.3 外部依赖
| 依赖 | 用途 |
|---|---|
| Electron + electron-updater | 客户端壳应用、更新下载与安装 |
| electron-builder | 打包 NSIS EXE + Portable ZIP |
| EV 代码签名证书 | Windows SmartScreen 信任 |
| Cloudflare R2 + CDN | 发布包存储与分发 |
| Celery | 异步计算 checksum / 文件扫描 / 可选预热 |
四、API 设计原则
- 路径以 PRD 为准:统一使用
/api/release/...命名空间。 - 只允许单一生效版本:同
platform + arch仅 1 条published。 - 公开接口最小暴露:客户端仅获取更新必要字段,不返回后台内部字段。
- 统计可信优先:Heartbeat 仅“启动上报”,按
(tenant_id, device_id)Upsert。 - 完整性优先于安装:校验失败禁止安装,保留当前版本可用。
- 强制更新可控:
release_type=force+min_required_version双保险。
五、端点清单(核心)
5.1 页面路由(平台运营后台)
| 路径 | 方法 | 鉴权 | 说明 |
|---|---|---|---|
/platform/release/updates/ |
GET | Platform Admin | 版本列表页 |
/platform/release/updates/new/ |
GET | Platform Admin | 新建版本页 |
/platform/release/updates/{id}/edit/ |
GET | Platform Admin | 编辑版本页 |
/platform/release/metrics/ |
GET | Platform Admin | 版本分布与租户活跃榜 |
5.2 JSON API(对齐 PRD + 数据模型)
| 端点 | 方法 | 说明 |
|---|---|---|
/api/release/updates/latest/ |
GET | 客户端检查最新版本(公开) |
/api/release/updates/ |
GET | 管理端查询版本列表 |
/api/release/updates/ |
POST | 管理端创建版本(草稿/发布) |
/api/release/updates/{id}/ |
PATCH | 修改状态、版本类型、日志 |
/api/release/updates/{id}/rollback/ |
POST | 回滚至历史版本(原子切换 published) |
/api/release/heartbeats/ |
POST | 客户端启动上报(Upsert) |
/api/release/metrics/version-distribution/ |
GET | 版本活跃分布 |
/api/release/metrics/tenant-installs/ |
GET | 指定租户活跃安装数 + 历史装机数 |
/api/release/metrics/tenant-leaderboard/ |
GET | 全平台租户活跃榜 |
说明:
heartbeats/metrics为实现 Story 5 与DATA_MODEL_PUBLIC聚合查询所需端点,归属同一模块。
六、关键 API 规范(请求/响应)
6.1 更新检测
GET /api/release/updates/latest/?platform=win32&arch=x64¤t_version=1.2.0
响应(有更新):
{
"has_update": true,
"latest_version": "1.3.0",
"force_update": false,
"min_required_version": "1.0.0",
"download_url": "https://download.fonrey.com/releases/system/v1.3.0/fonrey-setup-1.3.0-win.exe",
"portable_url": "https://download.fonrey.com/releases/system/v1.3.0/fonrey-portable-1.3.0-win.zip",
"checksum_sha256": "<exe_sha256>",
"portable_checksum_sha256": "<zip_sha256>",
"file_size_bytes": 157286400,
"release_notes": "## v1.3.0\n- ...",
"release_date": "2026-05-01"
}
6.2 Heartbeat 上报
POST /api/release/heartbeats/
{
"device_id": "9e6de37b-8c49-4f9b-af47-52f4e5b8b7f2",
"client_version": "1.3.0",
"platform": "win32",
"arch": "x64",
"os_version": "Windows 11 23H2"
}
处理要求:
- 服务端从登录上下文解析
tenant_id、user_id - 使用
INSERT ... ON CONFLICT (tenant_id, device_id) DO UPDATE - 更新
last_seen_at与launch_count = launch_count + 1
6.3 版本发布(管理端)
POST /api/release/updates/
{
"version": "1.3.0",
"platform": "win32",
"arch": "x64",
"release_type": "normal",
"min_required_version": "1.0.0",
"download_url": "https://download.fonrey.com/releases/system/v1.3.0/fonrey-setup-1.3.0-win.exe",
"portable_url": "https://download.fonrey.com/releases/system/v1.3.0/fonrey-portable-1.3.0-win.zip",
"checksum_sha256": "<exe_sha256>",
"portable_checksum_sha256": "<zip_sha256>",
"release_notes": "## v1.3.0\n- ...",
"status": "published"
}
七、HTMX 交互约定(平台运营后台)
- 列表筛选(状态/版本号)使用 HTMX 局刷表格区域
- 发布/下线/回滚操作使用确认弹窗 + 局部刷新
- 成功:
HX-Trigger: toast-success - 失败:
HX-Trigger: toast-error(同时返回标准错误码)
模板建议:
templates/release/updates_list.htmltemplates/release/fragments/updates_table.htmltemplates/release/fragments/version_distribution_chart.htmltemplates/release/fragments/tenant_leaderboard_table.html
八、权限与数据范围
8.1 最小权限矩阵
| 能力 | permission_code |
|---|---|
| 客户端版本列表查看 | platform.release.view.allow |
| 创建/编辑发布版本 | platform.release.edit.allow |
| 发布/下线/回滚 | platform.release.publish.allow |
| 版本分布与租户统计查看 | platform.release.metrics.view.allow |
8.2 范围规则
- 所有管理能力仅 Platform Admin 可访问
- Tenant Admin / Agent 不可访问平台发布后台
- 数据物理存储在 public schema,逻辑上属于平台级共享数据
九、异步任务与缓存策略
9.1 异步任务
| 任务 | 触发时机 | 说明 |
|---|---|---|
release_compute_checksum_task |
文件上传后 | 计算 EXE/ZIP SHA256 并回填 |
release_publish_cdn_warmup_task |
版本发布后 | 可选,预热热点下载节点 |
release_scan_artifact_task |
文件上传后 | 可选,执行恶意文件扫描与审计 |
9.2 Redis Key 建议
| Key | TTL | 说明 |
|---|---|---|
release:latest:{platform}:{arch} |
60s | 最新发布版本缓存 |
release:metrics:version_distribution |
60s | 版本分布聚合缓存 |
release:metrics:tenant:{tenant_id} |
60s | 单租户安装/活跃统计缓存 |
release:download:ratelimit:{ip} |
60s | 下载链接接口限流 |
十、性能与可靠性约束
- 更新检测接口:
p95 < 120ms(缓存命中) - Heartbeat 写入:
p95 < 80ms - 版本列表页:
p95 < 200ms - 发布状态切换使用事务,保证“下线旧版 + 发布新版”原子完成
- 任意更新失败不影响当前版本继续运行(可恢复原则)
十一、安全与合规
- Electron 必须启用:
contextIsolation=true、nodeIntegration=false、sandbox=true。 - 更新包仅允许 HTTPS 下载;域名白名单固定为
download.fonrey.com。 - EV 证书私钥仅在 CI 密钥库中可用,禁止落盘到开发机。
- 校验值由服务端生成并签名传输(至少 TLS + 服务端可信源)。
- Heartbeat 接口必须防重放/防刷(鉴权 + 频控 + 审计)。
- 管理端操作(发布、回滚、下线)全部记录审计日志。
十二、错误码建议
| code | HTTP | 中文含义 |
|---|---|---|
RELEASE_VERSION_INVALID |
400 | 版本号不符合 SemVer |
RELEASE_PUBLISHED_CONFLICT |
409 | 当前平台架构已存在发布版本 |
RELEASE_ARTIFACT_NOT_FOUND |
404 | 发布包不存在或不可访问 |
RELEASE_CHECKSUM_MISMATCH |
400 | 安装包完整性校验失败 |
RELEASE_HEARTBEAT_INVALID |
400 | 心跳参数非法 |
RELEASE_PERMISSION_DENIED |
403 | 权限不足 |
RELEASE_RATE_LIMITED |
429 | 请求过于频繁 |
十三、测试映射(P0)
| Story | 测试关注点 |
|---|---|
| Story 1 下载安装 | 官网下载链接可用、签名有效、安装步骤 ≤3、首次启动直达登录 |
| Story 2 客户端使用 | Chromium 内核能力、HTMX/Alpine/Tailwind 渲染一致性、文件上传下载 |
| Story 3 自动升级 | 启动 + 4h 检测、普通更新/强制更新分支、失败可恢复 |
| Story 4 发布管理 | 版本创建/发布/下线/回滚、唯一 published 约束 |
| Story 5 版本分布 | Heartbeat Upsert、活跃统计(24h)、租户活跃榜排序 |
测试文件建议:tests/integration/release/test_us_release.py
十四、落地顺序建议
apps/release模型/服务/API 基础骨架(先打通/api/release/updates/latest/)- 平台运营后台版本管理页(列表 + 新建 + 发布/下线)
- Electron 壳应用最小可运行版本(加载 Web + 标题版本)
- 自动更新链路(electron-updater + 后端 latest API)
- Heartbeat 上报 + 统计 API + 后台图表
- 官网下载页上线(公司域名)
- 便携版 ZIP 与企业无安装权限场景验收
十五、文档同步规则
- PRD 发布管理模块变更:同步本文件
client_releases/client_heartbeats字段变更:同步DATA_MODEL_PUBLIC.md- 枚举值变更:同步
DATA_MODEL/ENUMS.md(含中文标签) - API 包络/错误契约变更:同步
TECH_STACK/API_CONTRACT.md - 若将来新增独立测试用例文档:同步
TECH_STACK/测试规范.md与测试用例注册表
附:你关注的 8 个专题落地结论
- Electron 方案:采用 Electron + electron-updater,客户端坚持“壳应用”原则。
- EV 证书方案:CI 自动签名,证书私钥仅在密钥管理系统。
- Heartbeat 方案:仅启动上报,
(tenant_id, device_id)Upsert,支撑活跃与版本分布。 - 自动升级方案:启动 + 每 4h 轮询,普通/强制双模式,失败可恢复。
- 完整性验证:下载后先 SHA256 校验,再安装;失败禁止覆盖当前版本。
- R2 版本管理:
releases/system/v{version}/...路径规范,发布状态驱动可见性。 - 公司网站下载:
download.fonrey.com静态下载页 + 版本信息 + 更新日志。 - 便携版实现:electron-builder 输出 ZIP,首次运行写入用户目录配置,不修改系统级安装。