Sync: add ses and networking notes

This commit is contained in:
2026-04-24 20:38:20 +08:00
parent e4f6f463cb
commit 7903d703b9
12 changed files with 925 additions and 9 deletions

View File

@@ -4,7 +4,7 @@
> **版本**: v1.0
> **日期**: 2026-04-24
> **权威源**: 本文件是 `public` schema 所有表的唯一权威定义
> **设计依据**: 系统管理模块 PRD`PRD/系统管理/系统管理模块PRD.md`
> **设计依据**: 系统管理模块 PRD`PRD/系统管理/系统管理模块PRD.md`;客户端发布管理模块 PRD`PRD/发布管理/客户端发布管理模块PRD.md`
> **索引文档**: [`DATA_MODEL.md §三`](./DATA_MODEL.md)(仅保留摘要索引,开发以本文件为准)
---
@@ -31,7 +31,8 @@ PostgreSQL Instance
│ ├── backup_records 备份记录
│ ├── export_tasks 数据导出
│ ├── system_versions 版本历史
── upgrade_events 升级记录
── upgrade_events 升级记录
│ └── client_releases 客户端版本发布
├── tenant_abc schema租户业务层见各子文档
└── tenant_xyz schema
@@ -54,6 +55,7 @@ PostgreSQL Instance
| `public.export_tasks` | 数据导出异步任务CSV/JSON/SQL Dump | §2.4 |
| `public.system_versions` | 平台版本历史,唯一 current 约束 | §2.5 |
| `public.upgrade_events` | 升级/回滚事件,含灰度租户维度进度快照 | §2.5 |
| `public.client_releases` | Windows 客户端发布版本,含安装包 URL、SHA256、强制更新标记 | §2.6 |
---
@@ -376,6 +378,87 @@ CREATE TABLE public.upgrade_events (
CREATE INDEX idx_upgrade_events_status ON public.upgrade_events(status, created_at DESC);
```
### 2.6 客户端发布管理
```sql
-- ────────────────────────────────────────────────────────────
-- 6. 客户端发布管理
-- ────────────────────────────────────────────────────────────
-- 设计依据: 客户端发布管理模块 PRD §5.3
-- 说明: 本表属于 shared_appspublic schema所有租户共享同一套客户端版本
-- 不做多租户隔离。
-- 客户端版本发布表
CREATE TABLE public.client_releases (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- 版本标识
version VARCHAR(20) UNIQUE NOT NULL,
-- SemVer 格式,如 '1.2.3';由应用层校验格式,数据库层仅保证唯一性
platform VARCHAR(20) NOT NULL DEFAULT 'win32'
CHECK (platform IN ('win32')),
-- 当前仅支持 Windows后续支持 darwin / linux 时扩展 CHECK
arch VARCHAR(10) NOT NULL DEFAULT 'x64'
CHECK (arch IN ('x64', 'arm64')),
-- 版本类型与状态
release_type VARCHAR(10) NOT NULL DEFAULT 'normal'
CHECK (release_type IN ('normal', 'force')),
-- normal = 普通更新提示但可延后force = 强制升级,不可跳过
status VARCHAR(10) NOT NULL DEFAULT 'draft'
CHECK (status IN ('draft', 'published', 'archived')),
-- draft = 草稿不对外生效published = 已发布客户端可感知archived = 已下线
-- 兼容性约束
min_required_version VARCHAR(20),
-- 低于该版本的客户端将被强制要求升级NULL = 无最低版本限制
-- 由应用层在查询时比较 SemVer数据库层不做运算
-- 安装包EXE
download_url TEXT NOT NULL,
-- Cloudflare R2 公开 URL格式
-- https://download.fonrey.com/releases/v{version}/fonrey-setup-{version}-win.exe
checksum_sha256 VARCHAR(64) NOT NULL,
-- 安装包 SHA256 十六进制字符串64 位),客户端下载完成后校验
file_size_bytes BIGINT,
-- 安装包字节大小,用于前端展示下载大小
-- 便携版ZIP可选
portable_url TEXT,
-- 无需安装的 ZIP 版本,供无管理员权限的企业环境使用
portable_checksum_sha256 VARCHAR(64),
-- 更新内容
release_notes TEXT NOT NULL,
-- 对外展示的更新日志Markdown 格式,最多 2000 字
internal_notes TEXT,
-- 内部技术说明,不对外展示
-- 统计
download_count INTEGER NOT NULL DEFAULT 0,
-- 该版本安装包被下载次数,由应用层在每次下载时原子递增
-- 时间与操作人
published_at TIMESTAMPTZ,
-- 首次设为 published 时记录,后续状态变更不更新此字段
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by UUID REFERENCES public.platform_admins(id) ON DELETE SET NULL,
published_by UUID REFERENCES public.platform_admins(id) ON DELETE SET NULL
);
-- 只允许一条 published 记录(同平台+架构下的当前生效版本)
CREATE UNIQUE INDEX idx_client_releases_published
ON public.client_releases(platform, arch)
WHERE status = 'published';
-- 快速查找草稿/已发布版本(管理后台列表查询)
CREATE INDEX idx_client_releases_status ON public.client_releases(status, created_at DESC);
-- 按版本号快速定位(客户端更新检测时传入 current_version 查询)
CREATE INDEX idx_client_releases_version ON public.client_releases(version);
```
---
## 三、关键约束与禁止操作
@@ -391,6 +474,9 @@ CREATE INDEX idx_upgrade_events_status ON public.upgrade_events(status, created_
| `platform_admins``staff` 完全独立 | 不共享表、不共享 auth 系统 |
| MFA 强制 | `platform_admins.mfa_enabled` 在首次 TOTP 确认后才变 TRUE登录流必须检查 |
| `admin_sessions` 30 分钟滚动超时 | 应用层每次活跃请求更新 `expires_at = NOW() + 30min` |
| `client_releases` 唯一 published | `idx_client_releases_published` 部分唯一索引保证同平台+架构下只有一条 `status='published'` |
| `client_releases` 不可跨租户隔离 | 本表属于 public schema所有租户共享禁止在租户 schema 中创建副本 |
| `client_releases.download_count` 原子递增 | 必须使用 `UPDATE ... SET download_count = download_count + 1`,禁止先读后写 |
---
@@ -468,6 +554,27 @@ FROM public.backup_records br
JOIN public.tenants t ON t.id = br.tenant_id
WHERE br.status IN ('pending', 'in_progress')
ORDER BY br.created_at DESC;
-- 客户端更新检测查询当前生效版本platform=win32, arch=x64
SELECT version, release_type, download_url, portable_url,
checksum_sha256, file_size_bytes, release_notes, published_at
FROM public.client_releases
WHERE platform = 'win32'
AND arch = 'x64'
AND status = 'published'
LIMIT 1;
-- 客户端版本管理列表(管理后台,含各状态版本)
SELECT version, platform, arch, release_type, status,
download_count, published_at, created_at
FROM public.client_releases
ORDER BY created_at DESC;
-- 统计各版本活跃客户端数(需结合客户端上报心跳表,当前仅记录下载量)
SELECT version, download_count
FROM public.client_releases
WHERE status IN ('published', 'archived')
ORDER BY published_at DESC;
```
### 5.2 禁止查询
@@ -478,6 +585,8 @@ ORDER BY br.created_at DESC;
| `DELETE FROM public.platform_audit_logs` | append-only 审计表 |
| `UPDATE public.tenants SET schema_name = ...` | schema 名绑定 PG 物理 schema |
| `UPDATE public.domains SET domain = ...` | 域名路由不可变 |
| `UPDATE public.client_releases SET version = ...` | 版本号创建后不可修改,变更须新建记录 |
| 在租户 schema 中创建 `client_releases` 副本 | 本表属于 public schema多租户共享禁止下沉到租户层 |
---
@@ -486,3 +595,4 @@ ORDER BY br.created_at DESC;
| 版本 | 日期 | 变更 |
|------|------|------|
| v1.0 | 2026-04-24 | 从 `DATA_MODEL.md §三` 独立拆分;内容等价于 v1.2 DATA_MODEL.md §三 |
| v1.1 | 2026-04-24 | 新增 §2.6 `client_releases` 表(客户端发布管理);同步更新表清单、约束规则、查询模式 |

View File

@@ -0,0 +1,407 @@
# PRD: 客户端发布管理模块
**状态**: Draft
**作者**: 产品经理
**最后更新**: 2026-04-24v1.0 初稿)
**版本**: 1.0
**所属系统**: Fonrey 房产经纪管理系统
**关联模块**: 系统管理、权限管理
**干系人**: 工程负责人、运维负责人、系统管理员
---
## 1. 问题陈述
### 背景
Fonrey 房产经纪管理系统当前为纯 Web 应用,依赖用户自行通过浏览器访问。然而在实际部署场景中,经纪公司的终端设备环境高度复杂:
- **浏览器版本参差不齐**:经纪人使用的 Windows 设备可能运行 IE11、旧版 Edge、或未更新的 Chrome导致 HTMX + Alpine.js 等现代前端技术出现兼容性问题,系统体验碎片化
- **交付和部署门槛高**IT 能力薄弱的经纪公司无法独立配置浏览器访问方式URL 记忆成本高,容易访问错误版本
- **版本管理缺失**:后端服务升级后,用户仍可能使用旧版缓存页面操作,导致接口不兼容和功能异常
- **无官方入口**:用户通过私发链接访问系统,存在钓鱼仿冒风险,且无法统一品牌形象
### 目标用户
| 角色 | 使用场景 | 使用频率 |
|------|---------|----------|
| 一线经纪人 | 下载安装客户端、日常登录使用系统、接受自动更新 | 每日 |
| 店长/经理 | 同上 | 每日 |
| 系统管理员 | 发布新版本、管理安装包下载地址、监控客户端版本分布 | 按需 |
| IT 运维人员 | 维护更新服务器、签名证书、构建发布流水线 | 按发布周期 |
### 核心痛点
1. **无法控制用户使用的浏览器环境**,兼容性问题无法从根源解决
2. **升级依赖用户主动刷新浏览器**,后端 API 变更时旧客户端可能造成数据错误
3. **缺乏官方分发渠道**,无法向终端用户传递信任感和版本一致性保障
4. **SaaS 多租户管理系统需要统一、可控的客户端入口**,避免因客户端环境差异导致的支持成本上升
---
## 2. 目标与成功指标
| 目标 | 指标 | 当前基准 | 目标值 | 衡量周期 |
|------|------|---------|--------|---------|
| 消除浏览器兼容性问题 | 因浏览器兼容产生的支持工单数 | 待统计 | 降低 ≥ 90% | 上线后 60 天 |
| 提升版本一致性 | 在线用户中使用最新版本客户端的比例 | 0%(无客户端) | ≥ 95% | 版本发布后 7 天 |
| 降低部署门槛 | 新客户从获取安装包到完成首次登录的时间 | 无基准 | ≤ 10 分钟 | 上线后首批客户反馈 |
| 自动更新成功率 | 客户端自动更新完成率(收到更新通知 → 升级完成) | 无基准 | ≥ 98% | 每次版本发布后 48 小时 |
---
## 3. 非目标(本期不做)
- **不支持 macOS / Linux 客户端**:目标用户群体 99% 使用 WindowsmacOS 版本为后续规划
- **不支持移动端 AppiOS / Android**:移动端为 v2 规划,本期不涉及
- **不开发私有化部署的离线安装方案**:本期聚焦 SaaS 在线版,私有化部署另行规划
- **不包含客户端内置的离线模式**:系统需联网使用,客户端不缓存业务数据供离线访问
- **不包含客户端层面的安全加固(如代码混淆、反逆向)**:本期以功能交付为优先,安全加固列入后续迭代
---
## 4. 用户故事与验收标准
---
### Story 1经纪人下载并安装客户端
**As** 一线经纪人,**I want** 通过公司提供的网址下载一个安装程序并完成安装,**So that** 我可以立即打开登录界面使用 Fonrey 系统,无需手动配置浏览器。
**验收标准**
- [ ] 官方下载页面可通过指定 URL 访问,页面展示最新版本号、发布日期及下载按钮
- [ ] 下载产物为单一 `.exe` 安装包(或免安装便携版 `.zip`),文件大小控制在合理范围内
- [ ] 双击安装包后,安装向导步骤不超过 3 步(下一步 → 选择安装路径 → 安装),无需勾选额外组件
- [ ] 安装完成后,桌面自动生成快捷方式(图标为 Fonrey 品牌 Logo
- [ ] 首次启动后直接显示登录界面,无需用户手动输入任何 URL
- [ ] 安装包经过代码签名Windows SmartScreen 不弹出"无法识别的应用"警告
- [ ] 安装过程无需管理员权限(支持用户级安装到 `%APPDATA%` 目录),降低企业 IT 审批障碍
---
### Story 2经纪人使用客户端正常登录并使用系统
**As** 一线经纪人,**I want** 打开客户端后直接访问 Fonrey 系统的完整功能,**So that** 我的日常使用体验与使用 Chrome 浏览器无差异,且不受本机安装的浏览器版本影响。
**验收标准**
- [ ] 客户端内嵌现代 Chromium 内核(如基于 Electron 或 WebView2版本不低于 Chromium 100支持现代 Web 标准ES2020、CSS Grid、Fetch API 等)
- [ ] HTMX 局部刷新、Alpine.js 状态交互、Tailwind CSS 样式在客户端中渲染效果与 Chrome 最新版一致
- [ ] 支持 Cookie / Session 存储,登录状态在客户端关闭后保留(复用 Django Session 机制)
- [ ] 文件上传图片、附件、文件下载Excel 导出)在客户端中正常工作
- [ ] 客户端窗口支持最大化、最小化、拖拽调整大小,支持多显示器
- [ ] 客户端标题栏显示应用名称和当前版本号(如:`Fonrey 房睿 v1.2.3`
- [ ] 客户端不显示浏览器默认的地址栏、书签栏、扩展工具栏,保持沉浸式应用体验
---
### Story 3客户端感知新版本并自动升级
**As** 一线经纪人,**I want** 客户端在有新版本时自动提示并完成升级,**So that** 我无需手动下载安装,始终使用最新版本,不会因版本落后导致功能异常。
**验收标准**
- [ ] 客户端启动时及运行期间(每隔 4 小时)自动向更新服务器检查最新版本
- [ ] 有新版本时,客户端右下角弹出非阻断式通知:"发现新版本 vX.X.X点击立即更新",用户可选择"立即更新"或"稍后提醒"
- [ ] 点击"立即更新"后,客户端在后台静默下载更新包,进度条显示下载进度
- [ ] 下载完成后提示用户"更新已就绪,重启客户端完成安装",用户选择"立即重启"或"下次启动时安装"
- [ ] 重启后,新版本生效,标题栏版本号更新,历史会话自动恢复(用户无需重新登录)
- [ ] 支持强制更新模式:服务端可标记某版本为"强制升级",客户端不展示"稍后提醒"选项,必须升级后方可继续使用(用于重大 API 兼容性变更场景)
- [ ] 更新失败时(网络中断、磁盘空间不足等),客户端显示错误提示并保持当前版本正常运行,不影响用户当前操作
---
### Story 4系统管理员发布新版本
**As** 系统管理员,**I want** 通过管理后台上传新版客户端安装包并配置版本信息,**So that** 客户端能感知到更新并引导用户升级。
**验收标准**
- [ ] 系统管理后台提供"客户端版本管理"页面(位于系统管理模块下)
- [ ] 支持上传 `.exe` 安装包,并填写版本号(遵循 SemVer`X.Y.Z`)、版本说明(更新日志,支持 Markdown、发布日期
- [ ] 支持设置版本类型:普通更新 / 强制更新
- [ ] 支持设置版本状态:草稿(不对外生效)/ 已发布 / 已下线
- [ ] 发布后,更新服务器 API 即时返回最新版本信息,客户端下次检测时可感知
- [ ] 支持版本回滚:将指定历史版本重新设为"已发布",自动将当前版本标记为已下线
- [ ] 支持查看各版本的下载量和活跃客户端版本分布统计
---
### Story 5管理员监控客户端版本分布
**As** 系统管理员,**I want** 查看当前所有在线客户端的版本分布情况,**So that** 了解升级覆盖率,对仍在使用旧版本的客户端发出提醒或强制升级。
**验收标准**
- [ ] 客户端版本管理页面展示版本分布统计:各版本在线客户端数量及占比(饼图或条形图)
- [ ] 支持按租户维度查看版本分布(多租户场景下,区分不同经纪公司的版本使用情况)
- [ ] 支持对指定版本范围的用户推送"强制更新"通知(如:将所有低于 v1.5.0 的客户端标记为强制更新)
---
## 5. 功能详细说明
### 5.1 技术架构选型
#### 5.1.1 客户端技术方案
基于 Fonrey 现有技术栈Django + HTMX + Alpine.js + Tailwind CSS后端已采用 Docker Compose 部署),客户端本质是一个**内嵌现代 Chromium 内核的原生 Windows 应用外壳Shell**,其核心职责是:
1. 提供操作系统级原生窗口(标题栏、任务栏图标、托盘)
2. 内嵌高版本 Chromium 内核加载 Fonrey Web 应用 URL
3. 实现版本检测与自动更新逻辑
4. 处理文件下载、本地存储等 OS 级能力
**推荐方案Electron主选**
| 维度 | Electron | Tauri | WebView2 封装 |
|------|---------|-------|--------------|
| 内核控制 | ✅ 捆绑 Chromium100% 可控 | ❌ 依赖系统 WebView版本不可控 | ⚠️ 依赖 Windows 内置 WebView2 Runtime |
| 包体大小 | ~150MB可接受 | ~5MB | ~5MB |
| 生态成熟度 | ✅ 最成熟,社区最大 | ✅ 较新但活跃 | ⚠️ 微软官方但文档偏少 |
| 自动更新支持 | ✅ `electron-updater` 成熟方案 | ✅ 内置更新器 | ⚠️ 需自行实现 |
| 跨平台 | ✅ Win/Mac/Linux | ✅ | ❌ 仅 Windows |
| 团队技术匹配 | ✅ 主进程用 Node.js渲染层纯 Web | ⚠️ 主进程需 Rust | ✅ 主进程用 C# |
| **推荐度** | **✅ 主选** | 次选 | 备选 |
**选型决策**:采用 **Electron + electron-updater**。理由:
- 内嵌 Chromium 内核是本需求的核心约束Electron 是唯一能 100% 保证内核版本可控的主流方案
- `electron-updater` 配合 GitHub Releases 或自建 S3/R2 存储可实现完整的版本管理与自动更新流程,开发成本最低
- 渲染层完全复用 Fonrey 现有 Web 技术栈,无需新增前端框架学习成本
- 团队具备 JavaScript/Node.js 能力,主进程开发门槛可控
**技术决策**:客户端不内置任何业务逻辑,所有业务功能由服务端 Fonrey Web 应用提供。客户端仅负责加载 Web 应用、更新管理和 OS 级能力(窗口、托盘、文件下载路径)。
---
#### 5.1.2 更新服务架构
更新机制采用**差量检测 + 全量包下载**模式:
```
客户端启动 / 定时检测每4小时
GET /api/client/updates/latest?platform=win32&arch=x64&current_version=1.2.0
更新服务器Fonrey 后端 Django API
返回:{ latest_version, download_url, release_notes, force_update, checksum }
├── 无更新 → 继续正常运行
└── 有更新 → 弹出通知
├── 用户点击"立即更新" → 后台下载 .exe / NSIS 更新包
│ │
│ └── 下载完成 → 校验 SHA256 → 提示重启安装
└── 用户选择"稍后" → 下次启动再提示
```
**更新包存储**:上传至 Cloudflare R2与现有对象存储一致通过 Cloudflare CDN 加速下载,全国用户均可获得稳定下载速度。
**版本 API 端点**(新增至 Django 后端):
| 端点 | 方法 | 说明 |
|------|------|------|
| `/api/client/updates/latest/` | GET | 客户端查询最新版本,返回版本信息和下载 URL |
| `/api/client/updates/` | GET | 管理端查询版本列表(需认证) |
| `/api/client/updates/` | POST | 管理端发布新版本(需管理员权限) |
| `/api/client/updates/<id>/` | PATCH | 管理端修改版本状态(发布/下线/强制) |
---
#### 5.1.3 安装包签名与分发
**代码签名**
- 使用 EV 代码签名证书(推荐购买 DigiCert 或 Sectigo EV 证书)
- 通过 `electron-builder` 在 CI/CD 构建时自动签名
- 签名后安装包经 Windows SmartScreen 审核,用户安装时不触发安全警告
**安装包分发**
- 官方下载页:独立 HTML 页面托管于 Cloudflare Pages 或 Nginx 静态站
- 页面展示:最新版本号 + 发布日期 + 更新日志 + 下载按钮
- 下载 URL 格式:`https://download.fonrey.com/releases/v1.2.3/fonrey-setup-1.2.3-win.exe`
- 同时提供便携版Portable`fonrey-portable-1.2.3-win.zip`,供无安装权限的企业环境使用
---
### 5.2 客户端功能规格
#### 5.2.1 主窗口
| 属性 | 规格 |
|------|------|
| 默认窗口尺寸 | 1280 × 800最小1024 × 600 |
| 标题栏 | 显示 `Fonrey 房睿 v{version}`,含原生最小化/最大化/关闭按钮 |
| 内嵌 URL | 启动时加载 `https://{tenant}.fonrey.com`(或私有化部署地址,可配置) |
| 地址栏 | 不显示(沉浸式应用模式) |
| 右键菜单 | 仅保留"复制"/"粘贴"/"检查元素(仅开发模式)",移除"查看源代码"等浏览器默认项 |
| 外部链接 | 点击 `target="_blank"` 链接时,在系统默认浏览器中打开,不在客户端内新窗口打开 |
#### 5.2.2 系统托盘
| 功能 | 说明 |
|------|------|
| 托盘图标 | Fonrey Logo鼠标悬停显示 `Fonrey 房睿 - 已连接` / `- 离线` |
| 右键菜单 | 打开主窗口 / 检查更新 / 关于 / 退出 |
| 最小化行为 | 点击关闭按钮时最小化至托盘(不退出程序),用户通过托盘图标恢复窗口 |
#### 5.2.3 网络状态感知
| 状态 | 客户端行为 |
|------|-----------|
| 正常联网 | 加载 Fonrey Web 应用,状态栏显示"已连接" |
| 网络断开 | 显示全屏提示页:"网络连接已断开,请检查您的网络后重试",提供"重新连接"按钮 |
| 服务器维护 | 服务器返回 503 时,展示维护提示页(内容由服务端控制) |
#### 5.2.4 文件下载处理
- Excel 导出等文件下载触发时,客户端调用系统原生"另存为"对话框,用户选择保存路径
- 下载完成后,状态栏显示"下载完成,点击打开"提示,点击可直接打开文件
---
### 5.3 版本管理后台(系统管理模块新增页面)
**页面路径**:系统管理 → 客户端发布管理
#### 5.3.1 版本列表
| 列 | 说明 |
|----|------|
| 版本号 | SemVer 格式,如 `v1.2.3` |
| 版本类型 | 普通更新 / 强制更新(红色标签) |
| 状态 | 草稿 / 已发布(绿色)/ 已下线(灰色) |
| 发布时间 | 版本设为已发布的时间 |
| 下载量 | 该版本安装包被下载次数 |
| 操作 | 发布 / 下线 / 编辑 / 复制下载链接 |
#### 5.3.2 新增/编辑版本表单
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| 版本号 | 文本输入 | 是 | 格式:`X.Y.Z`,自动校验 SemVer 格式 |
| 版本类型 | 单选 | 是 | 普通更新 / 强制更新 |
| 最低兼容版本 | 文本输入 | 否 | 低于该版本的客户端将被强制更新(如填写 `1.0.0`,则低于此版本的客户端强制升级) |
| 安装包EXE | 文件上传 | 是 | 上传至 Cloudflare R2最大 500MB |
| 便携版ZIP | 文件上传 | 否 | 同上 |
| SHA256 校验值 | 文本输入(自动填充) | 是 | 上传后系统自动计算并填充,用于客户端下载完成后校验完整性 |
| 更新日志 | Markdown 文本区域 | 是 | 展示给用户看的版本说明,最多 2000 字 |
| 发布说明(内部) | 文本区域 | 否 | 仅内部查看的技术说明,不对外展示 |
| 状态 | 单选 | 是 | 草稿 / 立即发布 |
#### 5.3.3 版本分布统计
| 图表 | 说明 |
|------|------|
| 版本分布饼图 | 按客户端版本号统计当前活跃用户数量及占比 |
| 升级进度趋势图 | 新版本发布后,各天累计升级完成的用户比例(折线图) |
| 租户版本明细 | 按租户(经纪公司)展示其员工的客户端版本分布 |
---
### 5.4 更新 API 规格
#### GET `/api/client/updates/latest/`
**请求参数Query String**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `platform` | string | 是 | 平台标识,如 `win32` |
| `arch` | string | 是 | CPU 架构,如 `x64` / `arm64` |
| `current_version` | string | 是 | 客户端当前版本号,如 `1.2.0` |
**响应示例(有新版本)**
```json
{
"has_update": true,
"latest_version": "1.3.0",
"force_update": false,
"download_url": "https://download.fonrey.com/releases/v1.3.0/fonrey-setup-1.3.0-win.exe",
"portable_url": "https://download.fonrey.com/releases/v1.3.0/fonrey-portable-1.3.0-win.zip",
"checksum_sha256": "a1b2c3d4...",
"release_notes": "## v1.3.0 更新内容\n- 新增客源智能配房功能\n- 修复房源列表筛选条件保存异常",
"release_date": "2026-05-01"
}
```
**响应示例(已是最新)**
```json
{
"has_update": false,
"latest_version": "1.3.0"
}
```
---
## 6. 技术实现注意事项
### 6.1 依赖关系
| 依赖项 | 说明 | 负责方 | 风险等级 |
|--------|------|--------|---------|
| Electron 框架 | 客户端技术基础,需评估 LicenseMIT商业可用 | 前端/客户端工程师 | 低 |
| EV 代码签名证书 | 需提前申请EV 证书审核周期 1-2 周 | IT/运维 | 中(需提前排期) |
| Cloudflare R2 存储桶 | 存放安装包,利用现有账号新增 bucket | 运维 | 低 |
| `electron-updater` | 自动更新库,需配合更新 API 端点实现 | 客户端工程师 | 低 |
| Django 更新 API | 新增 `/api/client/updates/` 相关接口 | 后端工程师 | 低 |
| CI/CD 构建流水线 | 自动构建、签名、上传安装包 | 运维/DevOps | 中 |
### 6.2 已知风险
| 风险 | 可能性 | 影响 | 缓解措施 |
|------|--------|------|---------|
| EV 证书申请延迟 | 中 | 高(无签名包无法正常分发) | MVP 阶段可使用普通 OV 证书临时过渡,但需向用户说明安全警告原因 |
| Electron 包体过大导致下载放弃 | 低 | 中 | 使用 `electron-builder``asar` 压缩 + 分片下载;首包控制在 150MB 以内 |
| 企业网络拦截 CDN 下载 | 中 | 中 | 提供备用下载 URL直连服务器支持客户手动下载后本地安装 |
| 自动更新期间用户强制关闭 | 低 | 低 | 更新包下载完成后才替换原文件,下载中断不影响现有版本正常运行 |
| 多租户场景下 URL 配置问题 | 低 | 高 | 客户端启动时加载的 URL 通过配置文件指定支持定制化部署SaaS 版统一指向主域名 |
### 6.3 开放问题(开发启动前必须解决)
- [ ] **租户 URL 如何分发到客户端?** 选项 A客户端硬编码主域名由服务端重定向到租户子域`fonrey.com``{tenant}.fonrey.com`);选项 B安装包内置配置文件由销售/运维在分发给客户前填写租户子域。——**Owner**: 产品 + 工程 **Deadline**: 开发启动前
- [ ] **代码签名证书采购主体和预算是否确认?****Owner**: IT 负责人 **Deadline**: 立项后 1 周
- [ ] **CI/CD 平台选型是否确定?**GitHub Actions / Jenkins / 其他)— **Owner**: 运维负责人 **Deadline**: 开发启动前
- [ ] **便携版Portable ZIP是否纳入 v1 范围?** 便携版可解决企业无安装权限场景,但增加测试成本。— **Owner**: PM **Deadline**: 立项后 1 周
---
## 7. 发布计划
| 阶段 | 时间 | 受众 | 成功门槛 |
|------|------|------|---------|
| 内部 Alpha | 开发完成后 1 周 | 内部团队 + 1 家种子客户 | 核心流程无 P0 Bug自动更新机制验证通过 |
| 封闭 Beta | Alpha + 2 周 | 3-5 家头部客户 | 安装成功率 ≥ 95%,自动更新成功率 ≥ 95%,无 P0/P1 Bug |
| 正式发布GA | Beta + 1 周 | 全部客户 | Beta 阶段目标达成 |
**回滚标准**:若正式发布后 24 小时内出现以下情况,立即下线该版本并恢复上一稳定版本为"已发布"
- 自动更新失败率 > 5%
- 客户端白屏/崩溃率 > 2%
- 收到 P0 级安全漏洞报告
---
## 8. 附录
### 8.1 竞品参考
| 产品 | 客户端方案 | 更新机制 |
|------|-----------|---------|
| 企业微信 | Electron + 自研内核 | 强制更新,启动时自动下载 |
| 飞书 | Electron | 后台静默更新,重启生效 |
| 钉钉 | Electron | 同上 |
> 房产经纪行业的竞品(如房客多、云客优)均采用 Electron 方案,验证了技术路线的合理性。
### 8.2 术语表
| 术语 | 定义 |
|------|------|
| SemVer | 语义化版本控制Semantic Versioning`主版本号.次版本号.补丁号`,如 `1.2.3` |
| Electron | 由 GitHub 开发的开源框架,允许使用 Web 技术HTML/CSS/JS构建跨平台桌面应用内嵌 Chromium 和 Node.js |
| electron-updater | Electron 生态中成熟的自动更新库,支持增量更新和全量更新 |
| EV 证书 | Extended Validation 代码签名证书,由 CA 机构颁发,可消除 Windows SmartScreen 安全警告 |
| SHA256 | 安全散列算法,用于验证下载文件的完整性,防止篡改或下载损坏 |
| Portable | 便携版,无需安装,解压即用,适合无管理员权限的企业环境 |

View File

@@ -82,5 +82,74 @@ fonrey/
## 7. 外部服务 (External Services)
- **监控**Sentry (已配置用于错误追踪) 。
- **对象存储**Cloudflare R2 (用于房源/客源图片与附件) 。
- **地图服务**:待规划 (本期不涉及底层地图建设) 。
- **对象存储**Cloudflare R2 (用于房源/客源图片与附件;同时用于客户端安装包存储与分发) 。
- **地图服务**:待规划 (本期不涉及底层地图建设) 。
---
## 8. 客户端发布技术栈 (Desktop Client Stack)
> 本节对应 PRD`Project/fonrey/PRD/发布管理/客户端发布管理模块PRD.md`
> 所有决策均已在 PRD 中完成选型论证,此处为最终结论,直接执行。
### 8.1 客户端框架
- **框架**[Electron](https://www.electronjs.org/)(当前稳定版)
- **内核**Electron 捆绑的 Chromium版本随 Electron 版本固定,不依赖系统浏览器)
- **主进程语言**Node.jsJavaScript / TypeScript
- **渲染层**:直接加载 Fonrey Web 应用 URL100% 复用现有 HTMX + Alpine.js + Tailwind CSS 技术栈,**渲染层不新增任何框架**
### 8.2 自动更新
- **更新库**`electron-updater``electron-builder` 生态,成熟方案)
- **更新包存储**Cloudflare R2复用现有存储账号新增 `releases` bucket
- **更新包分发**Cloudflare CDN 加速(复用现有 CDN 配置)
- **更新检测端点**Django 后端新增 `/api/client/updates/latest/`GET公开接口无需登录
- **检测时机**:客户端启动时 + 每 4 小时轮询一次
- **更新模式**:后台静默下载,下载完成后提示用户重启;服务端可将版本标记为"强制更新",客户端不可跳过
### 8.3 安装包构建与签名
- **构建工具**`electron-builder`(输出 NSIS 安装包 `.exe` + 便携版 `.zip`
- **目标平台**Windows x64优先ARM64 按需支持
- **代码签名**EV 代码签名证书DigiCert 或 Sectigo由 CI/CD 在构建时自动签名,消除 Windows SmartScreen 警告
- **CI/CD**待确认平台GitHub Actions / Jenkins构建流水线负责编译 → 签名 → 上传 R2 → 调用发布 API
### 8.4 Django 后端新增模块
在现有 `fonrey/apps/` 目录下新增:
```
apps/
└── release/ # 客户端发布管理
├── models.py # ClientRelease版本号、类型、状态、下载URL、SHA256、更新日志
├── views.py # 公开更新检测 API + 管理后台 CRUD 视图
├── urls.py
└── admin.py
```
**`ClientRelease` 模型关键字段**
| 字段 | 类型 | 说明 |
|------|------|------|
| `version` | CharField | SemVer 格式,如 `1.2.3`,唯一索引 |
| `platform` | CharField | 平台标识,如 `win32` |
| `arch` | CharField | CPU 架构,如 `x64` |
| `release_type` | CharField | `normal` / `force`(强制更新) |
| `status` | CharField | `draft` / `published` / `archived` |
| `download_url` | URLField | EXE 安装包 Cloudflare R2 URL |
| `portable_url` | URLField | ZIP 便携版 URL可选 |
| `checksum_sha256` | CharField | 安装包 SHA256 校验值 |
| `min_required_version` | CharField | 低于此版本的客户端强制升级(可选) |
| `release_notes` | TextField | Markdown 格式更新日志 |
| `published_at` | DateTimeField | 发布时间 |
**`ClientRelease` 属于 `shared_apps`(公共 Schema**,不属于租户隔离范围,所有租户共享同一套客户端版本。
### 8.5 客户端关键约定
- **❌ Do NOT** 在 Electron 渲染进程中使用 `nodeIntegration: true`,保持 Web 沙箱安全
- **❌ Do NOT** 在客户端内嵌任何业务逻辑或本地数据库,所有业务数据由服务端提供
- **❌ Do NOT** 在客户端内新开多个 `BrowserWindow` 加载内部页面,所有导航在单窗口 SPA 内完成(外部链接除外,需在系统浏览器打开)
- 客户端版本号必须与服务端 `ClientRelease.version` 严格一致,通过 `package.json``version` 字段统一管理
- 更新包下载完成后,必须校验 SHA256 与服务端返回值一致后才能执行安装,防止下载损坏或中间人攻击