# HeiXiu 构建 & 发布手册

> 面向前端发版 + 后端 API 对接

---

## 一、整体架构

```
┌──────────────────┐         ┌──────────────────┐         ┌──────────────────┐
│   客户端 (Electron)│         │   ECS (API 服务)   │         │   OSS (阿里云)    │
│                  │  GET    │                  │         │                  │
│ 版本检查 ─────────┼────────▶│ /api/v1/update/  │         │                  │
│                  │         │    check         │         │                  │
│                  │◀────────│ 返回 JSON        │         │                  │
│                  │         │ (含 blockmap 信息) │         │                  │
│                  │         │                  │         │                  │
│ 增量下载（未来）────┼─────────┼──────────────────┼────────▶│ 静态文件托管      │
│ 仅下载变化块        │◀────────┼──────────────────┼─────────│ .exe + .blockmap  │
│                  │         │                  │         │                  │
│ 本地重建安装包      │         │                  │         │                  │
│ 校验 SHA512       │         │                  │         │                  │
│ NSIS /S 静默安装   │         │                  │         │                  │
│ → app.quit()     │         │                  │         │                  │
└──────────────────┘         └──────────────────┘         └──────────────────┘
```

> **当前状态**：客户端已集成 `electron-updater` + 自定义 `HeiXiuProvider`，支持增量下载。`electron-builder` 打包已生成
`.exe.blockmap` 文件。主进程通过 `netRequest` 调用自有 API 获取版本信息，electron-updater 自动处理差分下载和 SHA512 校验。

| 角色  | 技术                          | 职责                                         |
|-----|-----------------------------|--------------------------------------------|
| 客户端 | Electron + electron-updater | 调用 API → 下载 blockmap → 差分下载 → 重建 → 校验 → 安装 |
| ECS | 任意后端语言                      | 提供版本检查 API（含 blockmap 信息）                  |
| OSS | 阿里云对象存储                     | 托管 .exe / .dmg / .AppImage + .blockmap     |

---

## 二、项目脚本速查

### 总入口：`build/build.mjs`

```bash
node build/build.mjs --help             # 查看完整帮助
npm run build:win                       # 打包 Windows 个人版 Stable（快捷命令）
```

### npm 命令速查

```bash
# 构建（仅打包，不上传/发布）
npm run build:win                       # Windows 个人版 Stable
npm run build:win:enterprise            # Windows 企业版 Stable
npm run build:win:beta                  # Windows 个人版 Beta 渠道
npm run build:win:alpha                 # Windows 个人版 Alpha 渠道
npm run build:mac                       # macOS 个人版
npm run build:mac:enterprise            # macOS 企业版
npm run build:linux                     # Linux 个人版
npm run build:linux:enterprise          # Linux 企业版

# 版本管理
npm run version:patch                   # 0.0.28 → 0.0.29
npm run version:minor                   # 0.0.28 → 0.1.0
npm run version:pre-beta                # 0.0.29 → 0.0.30-beta.1
npm run version:pre-alpha               # 0.0.29 → 0.0.30-alpha.1

# 工具
npm run build:clean                     # 清理 release/ + dist/ + dist-electron/

# 独立脚本（需传参数）
node build/scripts/generate-update-info.mjs <平台> <版本> [渠道] [版本类型] [ossPrefix]
node build/scripts/upload-oss.mjs <平台> <版本> [渠道] [ossPrefix]
node build/scripts/publish-release.mjs <平台> <版本> [渠道] [版本类型] [ossPrefix]
```

### `build/build.mjs` 操作组合

| 操作          | 说明                                                         |
|-------------|------------------------------------------------------------|
| `--build`   | 构建（校验 → tsc → vite → electron-builder → update-info.json） |
| `--clean`   | 清理旧产物                                                      |
| `--sign`    | 代码签名（配合 `--cert` 或环境变量）                                    |
| `--upload`  | 上传 OSS                                                     |
| `--publish` | POST 版本信息到后端 API                                           |
| `--all`     | 全流程 = clean + build + sign + upload + publish              |
| `--edition` | 版本类型：personal（默认）或 enterprise                             |
| `--channel` | 发布渠道：stable（默认）、beta 或 alpha                             |

---

## 三、渠道与灰度测试

### 渠道体系

| 渠道 | OSS 路径 | 生命周期 | 适用场景 |
|------|----------|----------|----------|
| `stable` | `releases/{version}/` | 永久 | 正式发布 |
| `beta` | `releases/beta/{version}/` | 可设 OSS 30 天自动过期 | 灰度测试 |
| `alpha` | `releases/{version}/alpha/` | 手动管理 | 内部开发测试 |

### 灰度发布工作流

```bash
# 1. 创建 beta 预发布版本号
npm run version:pre-beta              # 0.0.29 → 0.0.30-beta.1

# 2. 写 CHANGELOG.md 更新日志

# 3. 构建并发布到 beta 渠道
node build/build.mjs --win --channel beta --upload --publish

# 4. 后端 API 设置 rolloutPercent: 10 → 30 → 100 逐步放量
#    客户端通过 deviceFingerprint 哈希分组（同一用户始终在同一组）
```

### 灰度原理

1. 客户端 `HeiXiuProvider` 请求 `/api/v1/update/check` 时携带 `channel`、`edition`、`deviceFingerprint`
2. 服务端根据 `rolloutPercent` + `deviceFingerprint` 哈希判断是否返回新版本
3. `src/shared/utils/rollout.ts` 提供 `isInRolloutGroup()` / `getRolloutGroup()` 工具函数

---

## 四、发版工作流

### 路径 A：快速打包（日常开发 / 内部测试）

```bash
# 1. 升级版本号
npm run version:patch              # package.json + CHANGELOG.md 自动更新

# 2. 写更新日志
#    CHANGELOG.md → 编辑自动生成的 ## 0.1.0（日期）条目

# 3. 打包
npm run build:win

# 4. 产物在 release/0.1.0/ 下：
#    - xxx-Setup.exe（安装包）
#    - xxx-Setup.exe.blockmap（块映射，增量更新用）
#    - xxx-update-info.json（channel、SHA512、blockmap 等全字段）

# 5. 手动上传 exe + .blockmap 到 OSS releases/0.1.0/
# 6. 将 update-info.json 内容录入数据库 releases 表
```

### 路径 B：先上传再确定 URL

```bash
# 打包
npm run build:win

# 上传到 OSS（自动打印实际 URL）
node build/scripts/upload-oss.mjs win32 0.1.0

# 用实际 URL 重新生成 update-info.json
node build/scripts/generate-update-info.mjs win32 0.1.0 stable personal \
  --url "https://heixiu.oss-cn-hangzhou.aliyuncs.com/releases/0.1.0/xxx.exe"

# 将 update-info.json 录入数据库
```

### 路径 C：全自动（上传 + 发布一条龙）

```bash
# 一步到位（需先配置环境变量）
OSS_ENDPOINT=oss-cn-hangzhou.aliyuncs.com \
OSS_BUCKET=heixiu \
OSS_ACCESS_KEY_ID=xxx \
OSS_ACCESS_KEY_SECRET=xxx \
UPDATE_API_KEY=xxx \
node build/build.mjs --win --upload --publish
```

---

## 五、代码签名

### 证书获取

| 平台      | 格式                | 渠道                              | 年费       |
|---------|-------------------|---------------------------------|----------|
| Windows | `.pfx` / `.p12`   | DigiCert / Sectigo / GlobalSign | $200-700 |
| macOS   | `.p12` / Keychain | Apple Developer Program         | $99      |

> EV 证书立即消除 SmartScreen 警告；OV 证书需积累下载量。

### 签名方式

```bash
# 方式 1：build.mjs 参数
node build/build.mjs --win --sign --cert ./cert.pfx --cert-password xxx

# 方式 2：环境变量（CI/CD 友好）
CSC_LINK=/path/to/cert.pfx CSC_KEY_PASSWORD=xxx npm run build:win
```

> SHA512 校验值会在签名后自动计算（签名改变文件字节，必须先签后校）。

---

## 六、API 接口

客户端调用的两个端点，完整规格见 [test-server/README.md](test-server/README.md)。

### GET /api/v1/update/check

客户端版本检查，请求参数：

| 参数 | 类型 | 说明 |
|------|------|------|
| `platform` | string | `win32` / `darwin` / `linux` |
| `version` | string | 当前客户端版本号 |
| `channel` | string | 客户端渠道：`stable` / `beta` / `alpha` |
| `edition` | string | 版本类型：`personal` / `enterprise` |
| `deviceFingerprint` | string | 设备指纹（SHA-256 前 16 位，灰度分组用） |

响应字段含 `channel`、`rolloutPercent` 等灰度相关字段。

### POST /api/v1/releases

前端构建脚本发布新版本，需 `Authorization: Bearer <UPDATE_API_KEY>` 鉴权。请求体包含 `channel`、`edition` 等字段。

---

## 七、客户端行为

| 场景    | 行为                                             |
|-------|------------------------------------------------|
| 启动    | 5 秒后静默检查更新（仅检查，不自动下载）                          |
| 手动检查  | 点击按钮 → 调用 API → 展示结果                           |
| 发现新版本 | 展示版本号 + 更新日志 + "查看详情"弹窗 + "下载更新"按钮             |
| 下载    | 用户点击"下载更新" → electron-updater 差分下载 → SHA512 校验 |
| 安装    | 下载完成后用户点击"安装更新" → quitAndInstall → NSIS /S     |
| 强制更新  | `forceUpdate=true` 时不可跳过                       |
| 开发模式  | 不跳过（已取消注释），通过 `.env.development` 指向测试服务器       |

### 环境变量加载顺序（主进程）

```
① OS 环境变量（set UPDATE_API_URL=...）  ← 最高优先级，不覆盖
② .env.local（不进 git，个人覆盖用）
③ .env.{mode}（开发→.env.development，打包→.env.production）
④ updater.ts 硬编码默认值（https://www.heixiu.com）
```

### 测试场景

```powershell
# 场景 1：npm run dev 自动走 .env.development → http://127.0.0.1:8000

# 场景 2：打包后连本地测试（方式 A — .env.local）
echo UPDATE_API_URL=http://127.0.0.1:8000 > .env.local
.\release\0.0.3\win-unpacked\船长·HeiXiu.exe

# 场景 3：打包后连本地测试（方式 B — OS 环境变量）
set UPDATE_API_URL=http://127.0.0.1:8000 && .\release\0.0.3\win-unpacked\船长·HeiXiu.exe

# 启动测试服务器
cd test-server && python server.py --release-dir ../release --port 8000
```

---

## 八、环境变量速查

| 变量                      | 默认值                                                    | 用途                   |
|-------------------------|--------------------------------------------------------|----------------------|
| `UPDATE_API_URL`        | `https://www.heixiu.com`                               | 版本检查 API 基地址         |
| `UPDATE_API_KEY`        | —                                                      | 发布 API 鉴权 Key        |
| `UPDATE_DOWNLOAD_BASE`  | `https://heixiu.oss-cn-hangzhou.aliyuncs.com/releases` | 预判 URL 基地址           |
| `OSS_ENDPOINT`          | —                                                      | 阿里云 OSS endpoint     |
| `OSS_BUCKET`            | —                                                      | 阿里云 OSS bucket       |
| `OSS_ACCESS_KEY_ID`     | —                                                      | 阿里云 AccessKey ID     |
| `OSS_ACCESS_KEY_SECRET` | —                                                      | 阿里云 AccessKey Secret |
| `OSS_BASE_PATH`         | `releases`                                             | OSS 内基路径             |
| `CSC_LINK`              | —                                                      | 签名证书路径               |
| `CSC_KEY_PASSWORD`      | —                                                      | 签名证书密码               |
| `UPDATE_FORCE`          | `false`                                                | 强制更新标记（打包时）          |
| `UPDATE_CHANGELOG`      | 读取 CHANGELOG.md                                        | 覆盖更新日志（CI/CD）        |

### .env 文件说明

| 文件                 | 何时加载                | 进 git | 用途                   |
|--------------------|---------------------|:-----:|----------------------|
| `.env.development` | `npm run dev`       |   ✅   | 开发环境（API 指向本地/测试服务器） |
| `.env.production`  | `npm run build:xxx` |   ❌   | 生产构建（API 指向正式服务器）    |
| `.env.local`       | 始终（后加载，覆盖前者）        |   ❌   | 个人特殊配置（如打包后连本地测试）    |

> **重要**：`.env.production` 和 `.env.local` 不打包进 ASAR。打包后运行 `.exe` 时这些文件不存在，自动使用 `updater.ts`
> 硬编码默认值。如需覆盖，使用 OS 环境变量或 `.env.local` 放在 exe 同目录（需配合 `loadEnvFile()` 的路径查找）。

---

## 九、文件结构

```
ele-heixiu/
├ build/                        ← 构建系统（2026-06-29 重构）
│ ├ build.mjs                   ← 构建总管（npm run build 入口）
│ ├ electron-builder.js         ← electron-builder 配置（从 package.json 提取）
│ ├ README.md                   ← 构建系统文档
│ └ scripts/
│     ├ clean.mjs               ← 清理产物
│     ├ pre-build-check.mjs     ← 构建前校验（Git/CHANGELOG/版本一致性）
│     ├ generate-update-info.mjs← 生成 update-info.json（SHA512 + blockmap + channel）
│     ├ upload-oss.mjs          ← 上传 OSS（安装包 + blockmap）
│     ├ publish-release.mjs     ← 发布到 API（axios）
│     └ bump-version.mjs        ← 版本号管理（major/minor/patch/pre）
├ CHANGELOG.md                  ← 更新日志（打包时自动提取）
├ UpdateA.md                    ← 本文档
├ package.json                  ← 不含 "build" 字段（已提取到 build/electron-builder.js）
├ release/                      ← 构建产物目录
│ ├ .build-meta.json            ← 最近一次构建元数据
│ └ 0.1.0/                      ← Stable 版本
│     ├ xxx-Setup.exe
│     ├ xxx-Setup.exe.blockmap  ← 差分更新块映射文件
│     └ xxx-update-info.json
├ dist/                         ← Vite 前端产物
└ dist-electron/                ← Electron 主进程产物
```

---

_如有接口或流程变更，请同步更新此文档。_
