主题
26 更新产品开发文档
讲解官方热更新机制与发布/回滚流程,对应 UpgradeService 与后台「系统更新」。
版本号约定
定义在 app\common\Version:
| 常量 | 当前值 | 作用 |
|---|---|---|
NAME | 可得财务 | 系统名 |
SLUG | kede-finance | 英文标识(检查更新时上报) |
VERSION | 0.1.0 | 语义化版本(展示用) |
BUILD | 1 | 构建序号,热更新按此递增比对 |
判断「是否有更新」只看
BUILD:远端build > 本地 BUILD即有更新。发布新版务必递增BUILD。
热更新流程(UpgradeService)
检查 check() → 下载 → 校验(SHA256/验签) → 备份 → 应用(解压覆盖) → 迁移(SQL) → 写日志1. 检查更新
GET {UPGRADE_SERVER}/api/upgrade/check?slug=&version=&build=
→ { status:200, data:{ version, build, notes, download_url, sha256, signature, force } }更新服务器地址优先取后台配置 general.upgrade_server,否则 .env 的 APP.UPGRADE_SERVER。
2. 应用更新
UpgradeService::apply() 依次:
- 下载
download_url的 zip(120s 超时); - 完整性:
sha256比对(hash_equals);若配置了RELEASE_PUBLIC_KEY且包带signature,再做 RSA 验签防篡改; - 备份:打包当前
app/、config/、route/、public/admin、public/index.html到runtime/backup/backup_<build>_<时间>.zip; - 应用:解压覆盖到项目根;
- 迁移:执行包内
upgrade/*.sql(文件名升序,支持{PREFIX}占位替换表前缀),执行后删除; - 记录:写
kd_upgrade_logs,触发钩子AfterUpgrade。
任一步失败抛 \RuntimeException 并把原因写入日志、原样透出(不静默兜底)。
3. 回滚
UpgradeService::rollback(backupFile) 从 runtime/backup/ 取指定备份解压覆盖,触发 AfterRollback。basename() 防目录穿越。
后台接口
| 操作 | 接口 |
|---|---|
| 当前版本 | GET /admin/upgrade/index |
| 检查更新 | POST /admin/upgrade/check |
| 应用更新 | POST /admin/upgrade/apply |
| 回滚 | POST /admin/upgrade/rollback(参数 backup_file) |
需要 upgrade 权限模块。
发布更新包(官方侧)
更新包是一个 zip,解压后覆盖项目根目录,约定包含:
更新包.zip
├── app/ # 变更的后端代码
├── public/admin/ # 变更的后台 SPA 产物(如有)
├── public/assets/ # 变更的前台 SPA 产物(如有)
├── public/index.html # 前台入口(如有)
└── upgrade/ # 本次升级的增量 SQL
└── 0002_xxx.sql # 用 {PREFIX} 占位表前缀,按文件名升序执行发布步骤建议:
- 递增
Version::BUILD(必要时升VERSION); - 构建前端产物(
deploy/package.sh或单独npm run build); - 仅打包变更文件 +
upgrade/*.sql成 zip; - 计算
sha256,如启用验签则用私钥对包体签名(base64),并在客户端填RELEASE_PUBLIC_KEY; - 在更新服务器登记:
version、build、notes、download_url、sha256、signature、force。
SQL 迁移编写规范
- 文件放更新包
upgrade/下,命名带递增序号(如0002_add_xxx.sql); - 表名用
{PREFIX}占位(运行时替换为实际前缀,如kd_); - 语句以
;\n分隔;保持幂等(ADD COLUMN IF NOT EXISTS思路或先判断); - 与代码侧
SchemaPatch二选一:紧急补列可放SchemaPatch(自动幂等补丁),版本化结构变更走更新包 SQL。
注意事项
- 应用更新会覆盖代码,自定义改动应做成插件/主题或单独保管,避免被覆盖;
- 更新前确保
runtime/与项目根可写; - 生产更新建议低峰执行并先确认备份生成;
force=true的强制更新用于安全修复,前端应提示用户尽快更新。
下一篇:27 错误码大全