Compare commits

..

13 Commits

9 changed files with 366 additions and 173 deletions
+12 -7
View File
@@ -1,8 +1,13 @@
**
!server/Dockerfile
!server/requirements.txt
!server/main.py
!server/db.py
!server/minio_tool.py
!server/tables.sql
!server/admin.html
!update-server/
!update-server/Dockerfile
!update-server/requirements.txt
!update-server/main.py
!update-server/db.py
!update-server/minio_tool.py
!update-server/tables.sql
!update-server/app/
!update-server/app/**
!update-server/admin-ui/
!update-server/admin-ui/dist/
!update-server/admin-ui/dist/**
+82 -44
View File
@@ -27,12 +27,20 @@ Desktop.ini
*.rar
# Requirement / handover documents kept outside Git
client/*.pdf
client/*.doc
client/*.docx
server/*.doc
server/*.docx
server/*交付说明*.md
update-client/*.pdf
update-client/*.doc
update-client/*.docx
update-client/Docs/*.pdf
update-client/Docs/*.doc
update-client/Docs/*.docx
update-client/private/
update-client/pdf_requirements.txt
update-server/*.pdf
update-server/*.doc
update-server/*.docx
update-server/Docs/*.pdf
update-server/Docs/*.doc
update-server/Docs/*.docx
# C/C++ generated artifacts outside build directories
*.obj
@@ -48,53 +56,88 @@ server/*交付说明*.md
*.exe
# Client: CMake / Visual Studio build outputs
client/out/
client/build/
client/build-*/
client/cmake-build-*/
client/.cmake/
client/CMakeFiles/
client/CMakeCache.txt
client/CMakeSettings.json
client/CMakeUserPresets.json
client/Testing/
update-client/out/
update-client/build/
update-client/build-*/
update-client/cmake-build-*/
update-client/.cmake/
update-client/CMakeFiles/
update-client/CMakeCache.txt
update-client/CMakeSettings.json
update-client/CMakeUserPresets.json
update-client/Testing/
# Client: third-party/business binary drops and generated packages
client/App/
client/dist/
update-client/thirdparty/
update-client/App/
update-client/dist/
# Client: local runtime state and credentials
update-client/config/app_config.json
update-client/config/client_identity.dat
update-client/config/local_state.json
update-client/config/version_policy.dat
update-client/config/*.local.json
update-client/config/*private*.pem
update-client/config/*private*.key
update-client/update/
update-client/update_temp/
# Server: Python environments and caches
update-server/venv/
update-server/.venv/
update-server/__pycache__/
update-server/**/*.py[cod]
update-server/.pytest_cache/
update-server/.mypy_cache/
update-server/.ruff_cache/
update-server/.coverage
update-server/htmlcov/
# Server: local configuration and secrets
update-server/.env
update-server/.env.*
!update-server/.env.example
!update-server/.env.docker.example
update-server/admin_token.sha256
update-server/keys/*private*.pem
update-server/keys/*private*.key
# Server: runtime databases, uploads, object storage and generated packages
update-server/*.db
update-server/*.db-journal
update-server/*.db-wal
update-server/*.db-shm
update-server/local_uploads/
update-server/upload_spool/
update-server/crash_storage/
update-server/minio_data/
update-server/runtime/
update-server/dist/
update-server/minio
# Server: runtime files
update-server/*.pid
update-server/*.log
# Docker/local generated files
.dockerignore.local
# Legacy paths before splitting into update-client/update-server submodules
client/out/
client/build/
client/App/
client/dist/
client/config/app_config.json
client/config/client_identity.dat
client/config/local_state.json
client/config/version_policy.dat
client/config/*.local.json
client/config/*private*.pem
client/config/*private*.key
client/update/
client/update_temp/
# Server: Python environments and caches
server/venv/
server/.venv/
server/__pycache__/
server/**/*.py[cod]
server/.pytest_cache/
server/.mypy_cache/
server/.ruff_cache/
server/.coverage
server/htmlcov/
# Server: local configuration and secrets
server/.env
server/.env.*
!server/.env.example
!server/.env.docker.example
server/admin_token.sha256
server/keys/*private*.pem
server/keys/*private*.key
# Server: runtime databases, uploads, object storage and generated packages
server/*.db
server/*.db-journal
server/*.db-wal
@@ -106,10 +149,5 @@ server/minio_data/
server/runtime/
server/dist/
server/minio
# Server: runtime files
server/*.pid
server/*.log
# Docker/local generated files
.dockerignore.local
+4 -4
View File
@@ -1,8 +1,8 @@
[submodule "server"]
path = server
[submodule "update-server"]
path = update-server
url = https://git.alimzs.com:6443/nikelaluo/update-server.git
branch = master
[submodule "client"]
path = client
[submodule "update-client"]
path = update-client
url = https://git.alimzs.com:6443/nikelaluo/update-client.git
branch = master
Submodule client deleted from b06e003502
Submodule server deleted from 9a6ac1e4ed
Submodule
+1
Submodule update-client added at d9e32c6cea
Submodule
+1
Submodule update-server added at 801622904c
+73
View File
@@ -0,0 +1,73 @@
# 项目交付状态一页纸
这份只看当前状态,不记录开发历史。更详细的背景和概念看 `项目总览.md`
## 项目是什么
这是 SimCAE 自动升级、授权、版本发布和崩溃报告服务的一套客户端 SDK + 服务端后台。
```text
update-client/ Launcher / Updater / Bootstrap、SDK 打包、客户端接入文档
update-server/ FastAPI 后端、Vue 管理后台、Docker 离线部署包
```
## 当前可以交付什么
- Windows/Linux 客户端升级运行时:`Launcher``Updater``Bootstrap`
- 客户端 SDK 包:包含运行程序、配置模板、接入文档、最终客户端打包脚本。
- 服务端 Docker 离线部署包:包含 API 镜像、管理后台、MinIO、compose 文件、配置模板和 Manifest 签名密钥。
- 管理后台:基于 pure-admin-thin / Vue3 / Element Plus / TypeScript / Vite。
- 后端:基于 FastAPI,已经按 routes / services / repositories / schemas / core 分层,并支持 JWT / RBAC。
- 后端自动化测试:pytest,覆盖登录/JWT、License/设备、更新检查、发布和崩溃报告核心流程。
## 已完成的核心功能
- 应用、渠道、版本发布、策略管理。
- License 授权、设备登记、设备数限制。
- Manifest 生成、SHA-256 文件校验、私钥签名、公钥验签。
- 客户端检查更新、下载、安装、健康检查、失败回滚。
- 升级日志、下载日志、管理员审计日志。
- 发布清单 `发布清单.txt` / `release_manifest.txt`,支持选择发布哪些文件、排除哪些文件。
- 发布压缩包支持 zip、tar.gz、tgz、tar.bz2、tbz2、rar。
- 发布任务后台化:上传完成后,服务端后台继续处理,页面轮询任务状态。
- 崩溃报告上传、查询、文件下载和符号包上传接口。
- Git 标签清单:管理后台策略可控制 Launcher 是否生成 `tags.txt`;服务端用 `GITEA_TOKEN` 拉取仓库 tags,客户端永远拿不到 token,只拿整理后的文本。
## 当前要特别注意
- `keys/manifest_private_key.pem` 必须在真实服务端部署包里,但不能进 Git、不能给客户端、不能公开传播。
- 客户端 SDK 里的 `manifest_public_key.pem` 必须和服务端私钥配套。
- `config/server_config.json` 会编进客户端程序;改服务端地址后必须重新编译 Launcher / Updater / Bootstrap。
- `GITEA_TOKEN` 只允许放在服务端 `.env`,不要写进客户端配置、不要给 Launcher、不要提交 Git。
- `app_config.json` 首次启动会导入当前用户配置区,非空配置导入后会清空为 `{}`
- Manifest 缓存和设备身份等运行态文件默认在当前用户数据目录,不再默认写安装目录。
- 公网部署前仍建议改默认 token/password、配置 HTTPS、限制 MinIO 控制台暴露范围、收紧 CORS。
## 打包入口
客户端 SDK
```powershell
cd update-client
.\scripts\package-sdk.ps1 -SourceDir .\out\bin\Release -OutputDir .\dist\UpdateClientSDK -ZipFile .\dist\UpdateClientSDK.zip -SdkVersion 0.1.0
```
服务端 Docker 离线包:
```bash
cd update-server
bash ./scripts/package-offline-server.sh --version 0.1.0 --output-dir ./dist/SimCAEServerDockerPackage
```
服务端自动化测试:
```bash
cd update-server
./venv/bin/python3 -m pytest -q
```
## 还不算完成的事情
- 真实 Linux 版 SimCAE 主程序还没有交付联调。
- 公网生产级安全加固还未全部自动化,例如登录限流、HTTPS 自动化、默认密钥强制替换。
- 数据库迁移仍是 `tables.sql` + 手写兼容逻辑,长期维护可考虑 Alembic。
+193 -116
View File
@@ -2,15 +2,25 @@
本文档用于总览当前项目的目标、已实现能力、主要目录、交付物和后续注意事项。适合在提交代码、交接项目或给他人快速了解项目时阅读。
如果只想快速判断“现在能交付什么、还要注意什么”,先看根目录的 `项目交付状态一页纸.md`
## 一、项目整体是什么
本项目是一套面向 Windows 客户端软件的自动升级与版本控制系统,并补充实现了 SimCAE 崩溃报告后端接口。
本项目是一套面向 Windows/Linux 客户端软件的自动升级与版本控制系统,并补充实现了 SimCAE 崩溃报告后端接口。
整体分为两部分:
```text
client/ Windows 客户端升级运行时、SDK 打包脚本、接入说明文档
server/ FastAPI 服务端、后台页面、Docker 部署和离线交付脚本
update-client/ Windows/Linux 客户端升级运行时、SDK 打包脚本、接入说明文档
update-server/ FastAPI 服务端、后台页面、Docker 部署和离线交付脚本
```
文档放置约定:
```text
项目总览.md 项目整体说明,保留在总仓库根目录
update-client/Docs/ 客户端说明文档
update-server/Docs/ 服务端说明文档
```
客户端负责:
@@ -37,18 +47,19 @@ server/ FastAPI 服务端、后台页面、Docker 部署和离线交付脚本
客户端核心程序:
```text
Launcher.exe 用户入口,检查更新并启动业务主程序
Updater.exe 下载、校验、安装、提交或回滚
Bootstrap.exe 辅助替换运行中的 EXE/DLL
MainApp.exe 当前仓库内的示例业务程序
Launcher.exe / Launcher 用户入口,检查更新并启动业务主程序
Updater.exe / Updater 下载、校验、安装、提交或回滚
Bootstrap.exe / Bootstrap 辅助替换运行中的 EXE/DLL 或 Linux 可执行文件
MainApp.exe / MainApp 当前仓库内的示例业务程序
```
已经实现的能力:
- 读取 `config/app_config.json` 配置
- 首次启动时把 `config/app_config.json` 导入当前 Windows 用户注册表,后续普通运行配置优先从注册表读取;如果解析后的 JSON 内容变化,下一次启动会自动重新导入,并清理 `config/client_identity.dat``config/version_policy.dat`
- 服务端 API 地址 `api_base_url` 不再写入 `app_config.json` 或注册表,而是写入 `config/server_config.json` 并通过 `config/server_config.qrc` 编译进 Launcher / Updater。
- 首次设备登记和本地设备身份校验。
- License 校验。
- `license_key` 为空时,`Launcher.exe` 会弹窗让用户粘贴后台创建的 License,并写入 `config/app_config.json`。当前实现会先检查配置项;即使本地已有 `config/client_identity.dat`,只要清空 `license_key` 仍会提示用户补填 License。
- `license_key` 为空时,`Launcher.exe` 会弹窗让用户粘贴后台创建的 License,并写入注册表。当前实现会先检查配置项;即使本地已有 `config/client_identity.dat`,只要清空 `license_key` 仍会提示用户补填 License。
- License 过期、错误、禁用、设备数达到上限或设备身份凭证与授权不匹配时,`Launcher.exe` 会引导用户重新输入 License,而不是要求用户手动查找配置文件。
- 版本策略校验。
- 防止策略序号回退。
@@ -60,33 +71,53 @@ MainApp.exe 当前仓库内的示例业务程序
- 升级后健康检查 `--health-file`,业务程序启动成功后写入 `ok`
- 升级失败回滚。
- 升级日志和下载日志上报服务端。
- `server/admin.html` 管理后台布局已优化,升级日志和下载日志默认折叠
- Git 标签清单生成:如果服务端策略开启,`Launcher` 会请求服务端生成 Git tags 文本,并写入 `Launcher` 同目录下的 `tags.txt`;客户端不会接触 Git token
- Launcher / Updater / Bootstrap 已支持 Windows 和 Linux Qt 跨平台编译。
## 三、客户端 SDK 交付状态
已经提供 SDK 打包脚本:
已经提供 Windows 和 Linux SDK/客户端打包脚本:
```text
client/package-sdk.ps1
client/package-client.ps1
update-client/scripts/package-sdk.ps1
update-client/scripts/package-client.ps1
update-client/scripts/package-sdk.sh
update-client/scripts/package-client.sh
```
`package-sdk.ps1` 用于生成给业务开发者接入的 SDK 包。当前 SDK 包结构设计为
客户端文档现在统一放在
```text
update-client/Docs/00-先读我-客户端文档入口.txt
update-client/Docs/01-客户端接入打包部署指南.md
update-client/Docs/02-编译环境和第三方依赖说明.md
```
`package-sdk.ps1` / `package-sdk.sh` 用于生成给业务开发者接入的 SDK 包。当前 SDK 包结构设计为:
```text
UpdateClientSDK/
SimCAE自动升级SDK接入说明_v0.1.docx
sdk_manifest.json
Docs/
00-先读我-客户端文档入口.txt
01-客户端接入打包部署指南.md
02-编译环境和第三方依赖说明.md
bin/
config/
app_config.json
manifest_public_key.pem
Common/
ConfigHelper.h/.cpp
TicketHelper.h/.cpp
scripts/
SimCAE自动升级SDK接入说明_v0.1.docx 可选,本地存在时才会随包复制
```
为了降低接入方理解成本,SDK 根目录只保留一个 Word 说明文档作为入口
为了降低接入方理解成本,SDK 包内默认带 `Docs/00-先读我-客户端文档入口.txt`。Word 接入说明是可选增强,`.docx` 不进 Gitfresh clone 没有 Word 时也能打包 SDK
Word 文档已经说明:
Linux 当前已完成 Qt 跨平台编译、Linux SDK 打包脚本、Linux 最终客户端打包脚本、Linux 配置模板和部署说明。真实 Linux 版 SimCAE 主程序还未由业务开发方交付,因此真实业务联调暂未完成。
客户端接入文档已经说明:
- 拿到 `UpdateClientSDK.zip` 后怎么操作。
- 如何复制 SDK 运行时到业务软件 Release 目录。
@@ -99,14 +130,37 @@ Word 文档已经说明:
## 四、服务端当前已实现
服务端使用 FastAPI,主要文件
服务端采用的成熟框架和模板生态
- 后端 HTTP 框架:`FastAPI`,运行服务使用 `Uvicorn`,请求模型和参数校验使用 FastAPI 自带的 `Pydantic` 体系。
- 后端工程结构:参考 FastAPI 官方 full-stack 模板、FastAPI Users 等成熟 FastAPI 后台项目的分层方式,拆成 `routes / services / repositories / schemas / core`
- 管理后台前端:使用 GitHub 上的 `pure-admin-thin` / `vue-pure-admin` 生态,技术栈是 `Vue3 + Element Plus + TypeScript + Vite`
- 存储组件:元数据使用 SQLite,版本文件和崩溃文件使用 MinIO 对象存储。
- Git 标签清单:服务端支持通过 `GITEA_BASE_URL` / `GITEA_TOKEN` 访问 Gitea API,管理后台策略页可以控制 Launcher 是否生成 `tags.txt`,并在后台预览当前仓库 tags。`GITEA_TOKEN` 只保存在服务端 `.env`,不会返回给客户端。
- 当前说明:后端已经完成工程化分层,并已加入用户名/密码登录、Argon2 密码哈希、JWT access/refresh token、RBAC 权限检查和管理员用户管理页面。当前实现是轻量用户体系,后续仍可继续接入 FastAPI Users 等更完整的成熟认证组件。
- 自动化测试:使用 pytest,测试会创建隔离的临时数据库、临时 Manifest 私钥和临时存储目录,覆盖管理员登录/JWT、License/设备登记、更新检查、发布事务和崩溃报告核心流程。
当前后端已经从早期单文件形态拆成分层结构,主要入口和目录:
```text
server/main.py
server/db.py
server/tables.sql
server/minio_tool.py
server/admin.html 服务端管理后台页面,Docker 构建时复制进镜像
update-server/main.py 应用启动、数据库初始化、MinIO 初始化、全局客户端鉴权
update-server/app/api/routes/ 管理端、客户端更新、崩溃报告等 HTTP 路由
update-server/app/services/ 发布、签名、License、设备凭证、崩溃报告等业务逻辑
update-server/app/repositories/ SQLite 数据库读写层
update-server/app/schemas/ Pydantic 请求模型
update-server/db.py
update-server/tables.sql
update-server/minio_tool.py
update-server/admin-ui/ 新版管理后台源码
```
服务端文档现在统一放在:
```text
update-server/Docs/00-先读我-服务端文档入口.txt
update-server/Docs/01-服务端Docker打包部署指南.md
update-server/Docs/02-崩溃报告接口联调指南.md
update-server/Docs/03-后端工程化结构说明.md
```
已经实现的能力:
@@ -116,6 +170,7 @@ server/admin.html 服务端管理后台页面,Docker 构建时复制进镜像
- License 管理。
- 设备首次登记。
- 版本发布。
- 版本发布已支持后台任务模式:浏览器上传完成后,服务端继续在后台校验、入库和上传 MinIO,管理页面轮询任务状态。
- 版本发布支持两种方式:选择软件发布根目录,或上传压缩好的发布包。管理页面已经拆成“软件根目录/压缩发布包”两个发布方式,避免用户误以为只能选择文件夹。
- 压缩发布包支持 `zip``tar.gz``tgz``tar.bz2``tbz2``rar`;服务端会先解压,再按 `RELEASE_MAIN_EXECUTABLE` 校验主程序路径。
- Manifest 生成和私钥签名。
@@ -125,6 +180,7 @@ server/admin.html 服务端管理后台页面,Docker 构建时复制进镜像
- 升级结果上报。
- 文件下载日志记录。
- 后台管理页面。
- 后端已经按 `routes / services / repositories / schemas` 拆分,`main.py` 不再堆业务接口。
- Docker 运行。
- Docker 离线部署包生成。
@@ -161,20 +217,20 @@ POST /api/v1/symbols
服务端 Docker 文件:
```text
server/Dockerfile
server/docker-compose.yml
server/docker-compose.image.yml
server/package-offline-server.sh
server/.env.example
server/.env.docker.example
update-server/Dockerfile
update-server/docker-compose.yml
update-server/docker-compose.image.yml
update-server/scripts/package-offline-server.sh
update-server/.env.example
update-server/.env.docker.example
```
Ubuntu 主流程使用:
```bash
cd server
cd update-server
bash ./package-offline-server.sh \
bash ./scripts/package-offline-server.sh \
--version 0.1.0 \
--output-dir ./dist/SimCAEServerDockerPackage
```
@@ -182,7 +238,7 @@ bash ./package-offline-server.sh \
生成:
```text
server/dist/SimCAEServerDockerPackage.tar.gz
update-server/dist/SimCAEServerDockerPackage.tar.gz
```
该包中包含:
@@ -202,8 +258,8 @@ server/dist/SimCAEServerDockerPackage.tar.gz
注意:Docker 镜像包只包含软件本体和部署配置,不包含已经运行出来的数据。当前服务器上的数据库、上传过的版本文件、崩溃报告等数据在:
```text
server/runtime/
server/minio_data/
update-server/runtime/
update-server/minio_data/
```
如果要完整迁移现有服务数据,需要额外备份和恢复这两个目录。
@@ -257,15 +313,15 @@ manifest_public_key.pem
不建议提交:
- `client/App/`
- `client/out/`
- `client/dist/`
- `server/dist/`
- `server/runtime/`
- `server/minio_data/`
- `server/*.db`
- `server/.env`
- `server/keys/manifest_private_key.pem`
- `update-client/App/`
- `update-client/out/`
- `update-client/dist/`
- `update-server/dist/`
- `update-server/runtime/`
- `update-server/minio_data/`
- `update-server/*.db`
- `update-server/.env`
- `update-server/keys/manifest_private_key.pem`
- 任何真实 token、License、私钥和运行日志。
## 九、SimCAE 安装根目录模式
@@ -291,9 +347,9 @@ SimCAE/
## 十、运行目录权限说明
当前客户端 SDK 默认把运行时状态写`Launcher.exe` 所在目录下,包括 `config/app_config.json``config/client_identity.dat``config/local_state.json``config/version_policy.dat``update/``update_temp/`。当 SDK 放在 `SimCAE/bin` 时,更新事务、备份、暂存文件、下载断点和 Manifest 缓存都`SimCAE/bin/update/`,不会再在 `SimCAE/` 根目录生成顶层 `update/`因此联调目录必须允许当前 Windows 用户写入。
当前客户端 SDK 把部署配置源放`Launcher.exe` 所在目录下 `config/app_config.json`,启动时同步到当前用户的 QSettings 配置区;Windows 下对应注册表路径 `HKEY_CURRENT_USER\Software\Marsco\UpdateClientSDK\installations\<安装目录SHA256>\config`Linux 下由 Qt QSettings 写入当前用户配置目录。服务端 API 地址 `api_base_url` 是例外:它位于源码 `config/server_config.json`,通过 `config/server_config.qrc` 编译进程序,不再写入 `app_config.json` 或注册表。如果检测到 `app_config.json` 变化,SDK 会删除当前用户数据目录里的 `client_identity.dat``version_policy.dat``local_state.json`,避免旧授权身份、旧策略或旧防回滚状态继续生效。设备身份、状态、策略、更新事务、备份、暂存文件、下载断点和 Manifest 缓存默认位于当前用户数据目录,例如 Windows:`%LOCALAPPDATA%\Marsco\UpdateClientSDK\installations\<安装目录SHA256>\`。当 SDK 放`SimCAE/bin`,不会再在 `SimCAE/` 根目录生成顶层 `update/`
如果把软件放在 `C:\Program Files\SimCAE\bin` 并用普通用户启动,Windows 会拒绝写入,首次启动可能提示 `cannot save installation id`。当前建议先在 `D:\SimCAE_Release` 或桌面目录联调;正式要安装到 `Program Files` 时,需要补管理员提权、Windows 服务,或将运行时状态迁移到 `ProgramData` / `AppData`
如果把软件放在 `C:\Program Files\SimCAE\bin` 并用普通用户启动,普通配置值已经不需要写回 `app_config.json`;但设备身份、状态、策略、更新缓存等文件仍可能需要写安装目录。当前代码对小型状态文件写入已有管理员权限确认;正式要完整安装到 `Program Files` 并自动升级大文件时,后续仍建议补 Windows 服务,或将更多运行时状态迁移到 `ProgramData` / `AppData`
## 十一、后续待办
@@ -309,12 +365,12 @@ SimCAE/
## 附录:原项目进度记录
以下内容迁移自原 `client/项目进度.txt`,用于保留更详细的阶段性进度、功能清单和概念说明。
以下内容迁移自原 `update-client/项目进度.txt`,用于保留更详细的阶段性进度、功能清单和概念说明。
```text
软件自动升级与版本控制系统——项目进度
更新时间:2026-07-07
依据:《软件自动升级与版本控制系统开发设计文档 v0.1》、《SimCAE_Crash_Report后端接口规范》及当前 server/client 源码
依据:《软件自动升级与版本控制系统开发设计文档 v0.1》、《SimCAE_Crash_Report后端接口规范》及当前 update-server/update-client 源码
============================================================
一、项目进度概述
@@ -360,17 +416,22 @@ SimCAE 崩溃报告后端已经完成第一阶段核心接口:接收 SimCAECra
说明:MainApp 当前读取 Demo DLL 内容并显示 Hash 标识,但还没有通过 QLibrary 真正加载并调用插件接口,因此“插件实际加载”只算部分完成。
2.2 本地 JSON 配置
2.2 本地配置
已实现:
1. 使用 config/app_config.json 保存客户端配置
2. 支持旧 client.ini 自动迁移
3. 保存 API 地址、App ID、当前版本、渠道、设备 ID、客户端 Token、启动 Token、平台和架构
4. 更新成功后写入 current_version
5. 使用 QSaveFile 原子写入主要配置
6. 运行时配置不进入发布包
7. 已配置项目 .gitignore
1. 使用 `config/app_config.json` 作为部署配置源文件
2. Launcher / Updater / MainApp 启动时按解析后的 JSON 内容 SHA-256 判断配置是否变化,变化后自动导入当前 Windows 用户注册表
3. 注册表路径为 `HKEY_CURRENT_USER\Software\Marsco\UpdateClientSDK\installations\<安装目录SHA256>\config`
4. 后续运行配置优先从注册表读取,运行时动态值写入注册表
5. 检测到 JSON 变化后自动清理 `client_identity.dat` 和 `version_policy.dat`
6. 支持旧 client.ini 自动迁移
7. 保存 App ID、当前版本、渠道、设备 ID、客户端 Token、启动 Token、平台和架构
8. 使用 `config/server_config.json` + `config/server_config.qrc` 把 API 地址编译进程序,避免写入 `app_config.json` 或注册表。
8. 更新成功后写入 current_version。
9. 文件型本地状态仍使用 QSaveFile 原子写入。
10. 运行时配置不进入发布包。
11. 已配置项目 .gitignore。
2.3 服务端基础能力
@@ -614,20 +675,23 @@ Updater 启动时会读取旧事务,并根据状态尝试恢复或回滚。
已实现:
1. 管理员令牌输入、隐藏、显示和保存
2. 修改管理员令牌
3. 创建和选择应用
4. 选择软件根目录发布
5. 切换到“压缩发布包”模式上传压缩包发布,支持 zip、tar.gz、tgz、tar.bz2、tbz2、rar
6. stable、preview、dev 渠道选择
7. 版本列表
8. 设置最新版本
9. 删除版本和云端文件
10. 版本策略读取和保存
11. 升级日志
12. 调试输出
13. 发布文件预览、大小和状态提示
14. 页面美化和响应式布局
1. 用户名和密码登录管理后台
2. 登录成功后由服务端签发 JWT access token 和 refresh token,管理接口使用 `Authorization: Bearer ...` 调用
3. 管理员密码修改
4. RBAC 角色权限校验,目前内置超级管理员、发布管理员、授权管理员、审计人员和崩溃报告管理员
5. 管理员用户管理:创建用户、编辑显示名称和角色、启用/禁用、重置密码,并防止禁用最后一个超级管理员
6. 创建和选择应用
7. 选择软件根目录发布
8. 切换到“压缩发布包”模式上传压缩包发布,支持 zip、tar.gz、tgz、tar.bz2、tbz2、rar
9. stable、preview、dev 渠道选择
10. 版本列表
11. 设置最新版本
12. 删除版本和云端文件
13. 版本策略读取和保存
14. 升级日志
15. 调试输出。
16. 发布文件预览、大小和状态提示。
17. 页面美化和响应式布局。
2.16 一次性短期启动票据
@@ -665,14 +729,14 @@ Updater 启动时会读取旧事务,并根据状态尝试恢复或回滚。
3. 服务端逐请求验证设备凭证、授权状态、设备禁用状态、app_id 和 channel。
4. License 授权:licenses 和 license_devices 表,支持有效期、启用/禁用、最大设备数和设备占用。
5. 授权密钥只保存 SHA-256,明文只在创建时返回一次。
6. Launcher 首次启动时如果没有 License,会弹窗要求用户输入并自动写入配置;当前实现会先检查 `license_key` 配置项,即使本地已有 `client_identity.dat`,清空 `license_key` 仍会触发输入框。
6. Launcher 首次启动时如果没有 License,会弹窗要求用户输入并自动写入注册表;当前实现会先检查 `license_key` 配置项,即使本地已有 `client_identity.dat`,清空 `license_key` 仍会触发输入框。
7. License 错误、过期、禁用、设备数达到上限或设备身份与授权不匹配时,Launcher 会清理旧设备身份并引导用户重新输入 License。
8. 动态渠道:channels 表按 app_id 隔离,管理后台支持新增、编辑、启用和停用。
9. 发布、策略、授权、设备登记和更新检查统一校验渠道。
10. 离线更新包:管理后台可生成 MUPD0001/.upd 包,包内包含签名 Manifest、包头签名、文件偏移、大小和 SHA-256。
11. Launcher/Updater 支持导入离线包,离线安装复用现有事务、Bootstrap、校验、健康确认和回滚机制。
12. 下载日志:记录下载授权、客户端完成结果、文件大小、IP、User-Agent 和时间。
13. 管理员审计日志:记录 /admin 写操作、管理员令牌指纹、路径、结果、状态码、IP 和 User-Agent。
13. 管理员审计日志:记录 /admin 写操作、管理员账号、角色、鉴权方式、路径、结果、状态码、IP 和 User-Agent。
2.19 SimCAE Crash Report 后端第一阶段
@@ -761,16 +825,26 @@ RSA 签名已经实现,但仍缺少:
3.7 管理员登录
当前采用单管理员 Token,服务端用 .env 中的 ADMIN_TOKEN 校验,并且已经记录 /admin 写操作审计
当前管理后台已经从单管理员 Token 升级为用户名/密码登录、JWT access/refresh token 和 RBAC 权限检查
尚缺少
已实现
1. admin_users 表。
2. 正式登录接口
3. Token 过期时间
4. 多管理员和角色权限
5. 登录失败审计
6. 会话吊销和 Token 轮换流程
2. admin_refresh_tokens 表
3. 初始管理员自动创建
4. Argon2 密码哈希
5. JWT access token 和 refresh token
6. 角色权限映射,例如 super_admin、release_admin、license_admin、auditor、crash_admin
7. 管理员用户管理接口和页面:列表、创建、编辑角色、启用/禁用、重置密码。
8. 管理后台写操作审计记录管理员用户名、角色、认证方式和操作结果。
`ADMIN_TOKEN` 仍保留为旧脚本兼容令牌、JWT_SECRET 未配置时的默认签名密钥,以及 CRASH_ADMIN_TOKEN 为空时的崩溃报告管理兜底令牌。
仍可继续加强:
1. 登录失败审计和频率限制。
2. 更细粒度的会话管理和 Token 轮换策略。
3. 接入 FastAPI Users 或同类成熟用户认证模块,替换当前轻量用户表。
3.8 数据库结构
@@ -905,12 +979,12 @@ RSA 签名已经实现,但仍缺少:
1. admin_audit_logs 表。
2. 统一中间件记录所有 /admin 写操作。
3. 记录管理员令牌截断 Hash 指纹,不保存令牌明文。
3. 记录管理员账号、角色、鉴权方式和兼容令牌截断 Hash 指纹,不保存令牌明文。
4. 记录操作路径、HTTP 方法、查询目标、成功/失败、状态码、IP、User-Agent 和时间。
5. 鉴权失败及业务失败同样进入审计。
6. 审计日志查询 API 和管理后台列表。
审计中间件不保存请求正文,避免 License 密钥、新管理员令牌等敏感内容进入日志。
审计中间件不保存请求正文,避免 License 密钥、新密码、兼容令牌等敏感内容进入日志。
4.11 代码签名
@@ -922,7 +996,7 @@ RSA 签名已经实现,但仍缺少:
4.13 多平台
目前只支持 Windows x64,尚未支持 Windows ARM64、Linux、macOS多平台 Manifest 分流。
Windows x64 已完成主要联调;Linux x64 已完成 Qt 跨平台编译、SDK 打包脚本、客户端打包脚本、配置模板和服务端发布配置支持。尚未完成 Windows ARM64、macOS多平台 Manifest 分流,以及真实 Linux 版 SimCAE 主程序实机联调
============================================================
五、需求文档 Demo 里程碑状态
@@ -1001,7 +1075,7 @@ SimCAE Crash Report 第一阶段——已实现。
8.1 服务端是什么
服务端在 server/ 下,核心是 FastAPI 应用。它负责:
服务端在 update-server/ 下,核心是 FastAPI 应用。它负责:
1. 管理应用、版本、渠道和策略。
2. 接收管理员发布的软件文件。
@@ -1010,7 +1084,7 @@ SimCAE Crash Report 第一阶段——已实现。
5. 对 Manifest、策略、设备身份、离线包做 RSA 签名。
6. 给客户端签发临时下载 URL。
7. 接收升级结果、下载结果、设备登记和 License 授权。
8. 提供 admin.html 管理网页
8. 提供新版 admin-ui 管理后台;旧版 admin.html 已在开发阶段移除,不再保留兼容入口
9. 接收 SimCAE 崩溃报告和符号包。
服务端主要存储有三类:
@@ -1021,7 +1095,7 @@ SimCAE Crash Report 第一阶段——已实现。
8.2 客户端是什么
客户端在 client/ 下,主要由几个程序配合:
客户端在 update-client/ 下,主要由几个程序配合:
1. Launcher.exe:入口程序。负责检查更新、验证策略、决定是否启动 MainApp 或 Updater。
2. Updater.exe:真正下载和安装文件的程序。负责 Manifest 验证、差异下载、断点续传、备份、校验、提交或回滚。
@@ -1233,10 +1307,10 @@ symbols.zip 就是 CI 或发布流程上传的符号包。它按 product、appVe
1. CLIENT_API_TOKEN:客户端安装包自带的公共门槛,用于首次设备登记等基础访问。
2. license_key:客户授权密钥,证明这个客户/项目有权使用某个 app/channel,并限制设备数和有效期。
3. device_id/client_identity.dat:服务端给某台安装实例签发的设备身份,之后每次更新请求都要带。
4. X-Admin-Token:管理后台请求头里传的管理员令牌;当前服务端用 .env 里的 ADMIN_TOKEN 校验
4. 管理后台 JWT:网页登录成功后使用 `Authorization: Bearer <accessToken>` 调用后台接口
5. CRASH_REPORT_TOKENSimCAECrashReporter.exe 上传崩溃报告用的 Bearer Token。
6. CRASH_SYMBOL_TOKENCI 上传 symbols.zip 用的 Bearer Token。
7. CRASH_ADMIN_TOKEN:查询和下载崩溃原始文件用;如果不配置,就复用当前管理员令牌。
7. CRASH_ADMIN_TOKEN:查询和下载崩溃原始文件用;如果不配置,就复用 ADMIN_TOKEN 作为崩溃报告管理兜底令牌。
简单理解:
@@ -1257,8 +1331,8 @@ SDK 是 Software Development Kit,中文通常叫“软件开发工具包”。
1. 可直接使用的二进制文件,例如 Launcher.exe、Updater.exe、Bootstrap.exe。
2. 必要的运行时文件。对 SimCAE 这种自身已带 Qt 的软件,SDK 默认不再携带 Qt DLL,避免覆盖业务软件原有运行库。
3. 配置模板,例如 app_config.example.json。
4. 接入文档,例如如何配置 app_id、channel、api_base_url、license_key。
3. 配置模板,例如 app_config.example.json 和 server_config.json
4. 接入文档,例如如何配置 app_id、channel、qrc 服务端地址、license_key。
5. 打包脚本,例如 package-client.ps1。
6. 示例项目或 Demo。
7. API/命令行约定,例如主程序必须由 Launcher 启动,MainApp 需要写健康标记。
@@ -1305,6 +1379,8 @@ UpdateClientSDK/
Bootstrap.exe
config/
app_config.json
server_config.json
server_config.qrc
manifest_public_key.pem
scripts/
install-sdk.ps1
@@ -1313,19 +1389,20 @@ UpdateClientSDK/
对接方真正拿到后,通常只需要做这些事:
1. 把 SDK 的 Launcher、Updater、Bootstrap 放到业务软件运行目录。
2. 设置 app_config.jsonserver 地址、app_id、channel、当前版本、主程序名等。`license_key` 可以预先填入;如果为空,用户首次启动 Launcher 时会弹窗粘贴授权密钥。
3. 以后让用户启动 Launcher.exe
4. 在管理后台创建应用、License、渠道和发布版本
5. 发布新版本时选择干净的 Release 输出目录,或切换到“压缩发布包”模式上传 zip/tar.gz/tar.bz2/rar 等压缩发布包
2. 设置 app_config.jsonapp_id、channel、当前版本、主程序名等。`license_key` 可以预先填入;如果为空,用户首次启动 Launcher 时会弹窗粘贴授权密钥。
3. 设置 config/server_config.json:服务端 API 地址。该文件必须在编译 Launcher/Updater 前写好,因为它会被 qrc 编进程序
4. 以后让用户启动 Launcher.exe
5. 在管理后台创建应用、License、渠道和发布版本
6. 发布新版本时选择干净的 Release 输出目录,或切换到“压缩发布包”模式上传 zip/tar.gz/tar.bz2/rar 等压缩发布包。
10.4 当前已有 package-client.ps1 的作用
client/package-client.ps1 已经是 SDK/客户端包雏形。
update-client/scripts/package-client.ps1 已经是 SDK/客户端包雏形。
它目前会做这些事:
1. 从 out/bin 收集已编译好的客户端文件。
2. 检查必填配置,例如 app_id、channel、api_base_url、current_version、client_token、launch_token、license_key、主程序名等。
2. 检查必填配置,例如 app_id、channel、current_version、client_token、launch_token、license_key、主程序名等。
3. 检查 Launcher、Updater、Bootstrap、MainApp 是否存在。
4. 拒绝 PDB、ILK、Debug Qt DLL 等调试产物进入发布包。
5. 检查主程序是否被嵌套放错目录。
@@ -1357,11 +1434,11 @@ client/package-client.ps1 已经是 SDK/客户端包雏形。
- app_id=mycad
- channel=stable
- main_executable=MyCAD.exe
- api_base_url=http://服务器IP:8000
- license_key=服务端生成的授权密钥
6. 用户桌面快捷方式指向 Launcher.exe
7. 管理员以后在后台发布 MyCAD 的新版本
8. 用户启动 Launcher.exe 时自动检查、下载、替换并启动 MyCAD.exe
6. config/server_config.json 里写 `api_base_url=http://服务器IP:8000`,并重新编译 Launcher/Updater
7. 用户桌面快捷方式指向 Launcher.exe
8. 管理员以后在后台发布 MyCAD 的新版本
9. 用户启动 Launcher.exe 时自动检查、下载、替换并启动 MyCAD.exe。
这就是“把客户端升级能力作为 SDK 给其他软件使用”。
@@ -1369,7 +1446,7 @@ client/package-client.ps1 已经是 SDK/客户端包雏形。
Docker 可以理解为“把服务端运行环境打包成一个标准盒子”。
本机直接运行 server/venv/bin/python3 main.py 时,依赖的是当前机器上的 Python 虚拟环境、当前目录、当前配置文件。
本机直接运行 update-server/venv/bin/python3 main.py 时,依赖的是当前机器上的 Python 虚拟环境、当前目录、当前配置文件。
Docker 运行时,依赖的是镜像里的 Python、镜像里的依赖、容器里的 /app 目录和 docker-compose.yml 映射进去的数据目录。
@@ -1383,17 +1460,17 @@ Docker 运行时,依赖的是镜像里的 Python、镜像里的依赖、容器
10.7 当前服务端 Docker 已经具备什么
当前 server/Dockerfile 已经具备:
当前 update-server/Dockerfile 已经具备:
1. 使用 python:3.12-slim 作为基础镜像。
2. 安装 server/requirements.txt 里的 FastAPI、MinIO、cryptography 等依赖。
2. 安装 update-server/requirements.txt 里的 FastAPI、MinIO、cryptography 等依赖。
3. 拷贝 main.py、db.py、minio_tool.py、tables.sql。
4. 拷贝 server/admin.html 到容器内 /app/admin.html
4. 拷贝 admin-ui/dist 管理后台静态文件到容器内 /app/admin-ui/dist
5. 使用非 root 用户 updateapp 运行。
6. 暴露 8000 端口。
7. 提供 healthcheck。
当前 server/docker-compose.yml 已经具备:
当前 update-server/docker-compose.yml 已经具备:
1. minio:对象存储,保存升级文件。
2. minio-init:首次启动时创建 bucket。
@@ -1411,7 +1488,7 @@ Docker 运行时,依赖的是镜像里的 Python、镜像里的依赖、容器
1. 进入 server 目录。
2. 准备 .env。
3. 设置 ADMIN_TOKEN、CLIENT_API_TOKEN、MINIO_ACCESS_KEY、MINIO_SECRET_KEY、MINIO_BUCKET、MINIO_PUBLIC_ENDPOINT、CRASH_REPORT_TOKEN、CRASH_SYMBOL_TOKEN。
3. 设置 ADMIN_USERNAME、ADMIN_PASSWORD、ADMIN_JWT_SECRET、ADMIN_TOKEN、CLIENT_API_TOKEN、MINIO_ACCESS_KEY、MINIO_SECRET_KEY、MINIO_BUCKET、MINIO_PUBLIC_ENDPOINT、CRASH_REPORT_TOKEN、CRASH_SYMBOL_TOKEN。
4. 准备签名私钥 keys/manifest_private_key.pem。
5. 准备 runtime、minio_data 等持久化目录。
6. 执行 docker compose build。
@@ -1422,7 +1499,7 @@ Docker 运行时,依赖的是镜像里的 Python、镜像里的依赖、容器
示例命令:
cd server
cd update-server
cp -n .env.example .env
mkdir -p runtime minio_data keys
docker compose config
@@ -1477,8 +1554,8 @@ Docker 是给“服务端部署人员”用的。
建议下一步做两个包:
1. server/docker 部署包:给运维或服务器部署人员。
2. client/UpdateClientSDK.zip:给其他软件开发人员。
1. update-server/docker 部署包:给运维或服务器部署人员。
2. update-client/UpdateClientSDK.zip:给其他软件开发人员。
10.11 现在具体怎么做
@@ -1488,7 +1565,7 @@ Docker 是给“服务端部署人员”用的。
1. 进入 server 目录。
2. 复制 .env.example 为 .env。
3. 修改 ADMIN_TOKEN、CLIENT_API_TOKEN、MINIO_ACCESS_KEY、MINIO_SECRET_KEY、MINIO_BUCKET、MINIO_PUBLIC_ENDPOINT、CRASH_REPORT_TOKEN、CRASH_SYMBOL_TOKEN。
3. 修改 ADMIN_USERNAME、ADMIN_PASSWORD、ADMIN_JWT_SECRET、ADMIN_TOKEN、CLIENT_API_TOKEN、MINIO_ACCESS_KEY、MINIO_SECRET_KEY、MINIO_BUCKET、MINIO_PUBLIC_ENDPOINT、CRASH_REPORT_TOKEN、CRASH_SYMBOL_TOKEN。
4. 准备 keys/manifest_private_key.pem。
5. 执行 docker compose config,确认配置无误。
6. 执行 docker compose build。
@@ -1499,21 +1576,21 @@ Docker 是给“服务端部署人员”用的。
第二步:准备客户端 SDK 包。
1. 确认 client/out/bin 是 Release 输出目录。
1. 确认 update-client/out/bin 是 Release 输出目录。
2. 确认 out/bin 里有 Launcher.exe、Updater.exe、Bootstrap.exe。SimCAE 场景下不要把 SDK 自带 Qt DLL 覆盖到 SimCAE 的 bin 目录。
3. 确认 config/manifest_public_key.pem 是服务端私钥对应的公钥。
4. 填好 client/config/app_config.example.json 里的示例字段。
4. 填好 update-client/config/app_config.example.json 里的示例字段。
5. 在 Windows PowerShell 执行:
cd client
.\package-sdk.ps1 -SourceDir .\out\bin -OutputDir .\dist\UpdateClientSDK -ZipFile .\dist\UpdateClientSDK.zip -SdkVersion 0.1.0
cd update-client
.\scripts\package-sdk.ps1 -SourceDir .\out\bin -OutputDir .\dist\UpdateClientSDK -ZipFile .\dist\UpdateClientSDK.zip -SdkVersion 0.1.0
第三步:给接入方一个最小验证方式。
1. 解压 UpdateClientSDK.zip。
2. 把接入方自己的 YourApp.exe 放到 bin 目录同级的最终产品目录中。
3. 把 config/app_config.example.json 复制成 config/app_config.json。
4. 修改 app_id、channel、api_base_url、client_token、license_key、main_executable。
4. 修改 app_id、channel、client_token、license_key、main_executable,并确认 SDK 二进制已用正确的 config/server_config.json 编译
5. 从 Launcher.exe 启动。
6. 确认能登记设备、拉取策略、启动业务主程序。
@@ -1521,12 +1598,12 @@ cd client
SDK 是给开发者看的;具体产品给客户安装时,使用 package-client.ps1
cd client
.\package-client.ps1 -SourceDir .\out\bin -ConfigFile .\config\app_config.json -OutputDir .\dist\UpdateClient -ZipFile .\dist\UpdateClient.zip
cd update-client
.\scripts\package-client.ps1 -SourceDir .\out\bin -ConfigFile .\config\app_config.json -OutputDir .\dist\UpdateClient -ZipFile .\dist\UpdateClient.zip
第五步:补接入方文档和 Demo。
1. SDK 根目录只保留一个 Word 接入说明作为入口,打开包后一眼能看到
1. SDK 包内提供 Docs/00-先读我-客户端文档入口.txt 作为默认入口;Word 说明作为可选增强
2. 准备一个最小 MainApp 示例,演示 --ticket-file 和 --health-file。
3. 准备一份常见错误说明。
4. 准备一份服务端 Docker 部署说明。