1) 版本对齐分支 - package.json / tauri.conf.json / Cargo.toml / Cargo.lock: 0.1.0 -> 0.2.0, OTA 包版本变为 0.2.0-ota - 新增 scripts/ci/check-version.mjs: 分支 dev-x.y 与 package.json 版本不一致时 CI 直接失败 - docker-build.yml / ota-build.yml: min_binary_version 与前端版本解耦, 固定 0.1.0 (现有 APK 原生层仍是 0.1.0, 抬高会导致旧 APK 收不到更新) 2) 我的页 OTA「开发版本」开关 (默认关, 持久化 localStorage.iboard_ota_dev_mode) - 关: 按版本号逐字段比较 (src/utils/version.js), 服务端 version 更高才算新 - 开: 按 build sequence 判新 (hotswap checkUpdate), 每次构建都能推到设备 - Web 端: 开发口径退化为版本不同即算新; 生产口径严格比较大小 3) 打卡 Tab 移到最左并默认选中, 移除特效开关 - BottomNav: 打卡/宏观/监控/我; 删除 home 图标 - App: / 与 404 均重定向到 /checkin - RingProgress/Celebrate: 删除 effectsEnabled/setEffectsEnabled, 特效恒开 - HabitView: 去掉头部「特效开/关」按钮 4) 取消首页 Tab, 报警/新闻并入宏观 - 新增 pages/macro/AlertsView.jsx、NewsView.jsx; 删除 HomePage.jsx - MacroPage: 6 个子 Tab (油价/经济数据/策略研究/经济文章/报警/新闻), 报警角标保留 - 新闻详情 /news/:id -> /macro/news/:id (宏观 Tab 保持高亮) 5) 文档: 需求文档补 F-OT 需求点与已决策项; 设计文档新增 §10 变更记录与判新设计; 界面设计.html 11 屏 (Tab 4 项/去掉特效开关/宏观合并/我的 OTA 开关 关+开 两态)
169 lines
8.3 KiB
Plaintext
169 lines
8.3 KiB
Plaintext
# iBoard
|
||
用于收集和整理经济数据,但是以策略为主体重新组织。
|
||
|
||
## 版本管理
|
||
|
||
版本号遵循 `主版本.次版本.修订号`,**唯一手动管理点是 `package.json` 的 `version` 字段**(当前 `0.2.0`)。
|
||
版本号必须与所在分支对应:`dev-0.2` 分支上就该是 `0.2.x`(CI 有 `scripts/ci/check-version.mjs` 强校验,不一致直接失败)。
|
||
发版时只改这一处,以下位置必须保持一致(改版本时一并核对):
|
||
|
||
| 文件 | 字段 | 说明 |
|
||
| --- | --- | --- |
|
||
| `package.json` | `version` | **唯一源**,前端 `src/version.js` 与 OTA 打包脚本均读取此值 |
|
||
| `src-tauri/tauri.conf.json` | `version` | Tauri 应用版本(Android/桌面包版本) |
|
||
| `src-tauri/Cargo.toml` | `[package].version` | Rust 包版本,需与 tauri.conf.json 一致 |
|
||
| `src-tauri/Cargo.lock` | `name = "iboard"` 条目 | 同上,随 Cargo.toml 一起改 |
|
||
|
||
说明:
|
||
- `src/version.js` 从 `package.json` 取值,前端"我"页与 OTA 检查接口展示的即此版本,不要另写死版本号。
|
||
- OTA 升级包的 `version` 字段 = `<package.json version>-ota`(见 `scripts/build-ota.mjs`),
|
||
所以版本号错位会直接导致线上 OTA 判新失准。
|
||
- `BUILD_ID` 每次编译自动生成(见 `vite.config.js` 的 `__BUILD_ID__`),无需手动维护。
|
||
- `ota-package/latest.json` 为运行时产物,不纳入版本管理。
|
||
|
||
## 分支与 CI/CD (Gitea Actions)
|
||
|
||
分支按版本命名:`dev-0.1`、`dev-0.2`…… 对应 `docs/V<版本>/` 下的需求/设计文档。
|
||
|
||
| 分支 | 触发的 workflow | 行为 |
|
||
| --- | --- | --- |
|
||
| `main` / `master` | `docker-build.yml` | 生产发布:构建前端 → 生成签名 OTA 包 → 打 Docker 镜像 → 数据库自动升级 → 重启容器 `iboard` (宿主 3001) |
|
||
| `dev-*` | `docker-build.yml` | **与生产同环境**:推送即构建、迁移数据库、部署(开发分支直接顶掉生产,含 OTA 热更) |
|
||
| `android-*` | `android-build.yml` | 打签名 release APK 并上传到 Gitea Generic Package Registry |
|
||
| 手动 | `ota-build.yml` / `sync-registry.yml` | 单独出 OTA 包 / 同步 secrets 到注册中心 |
|
||
|
||
数据库升级约定:
|
||
- 唯一入口是 `prisma/migrations/` 下的迁移文件,由 `npx prisma migrate deploy` 在**启新容器之前**执行
|
||
(幂等,无新迁移时为 no-op);迁移失败会中断 workflow,不会用新镜像顶掉仍在运行的旧容器。
|
||
- `dev-*` 与 `main/master` 共用同一个 MariaDB 库(同一个 `DATABASE_URL` secret),
|
||
因此开发分支上的迁移会直接作用到该库结构,合入前请确认迁移可回滚。
|
||
- 本地改了 `prisma/schema.prisma` 后:写迁移 SQL → `npx prisma migrate deploy` 验证 → 提交迁移目录。
|
||
|
||
- 首页主要是放经济文章
|
||
- 数据主要是放各种经济数据和图表。
|
||
- 策略是放按照经济理论组织的相关数据和图表的对比。
|
||
|
||
|
||
|
||
## 首页
|
||
首页显示新闻模块和报警模块的数据,按照时间最新优先,无限滚动,直到数据库中没有数据为止。
|
||
|
||
|
||
### 新闻模块
|
||
增加一个新闻模块,数据来源是每日夜间 3点,通过妙想 MCP 获取国内外最新经济政治新闻,按影响大小排序10条。
|
||
存入数据库。
|
||
|
||
|
||
### 报警模块
|
||
World Bank 中的数据只用来对比妙想 MCP 拉取的数据正确性。当同一时间的同一项数据不同时,记录一个报警。
|
||
|
||
## 监控
|
||
监控分为服务器监控和服务监控两部分。
|
||
服务器监控对接 komari,地址:https://komari.honor3.com/
|
||
|
||
|
||
|
||
## 前端 OTA 升级
|
||
|
||
只升级前端资源 (`dist/`), **不触碰** Tauri 框架/原生层, 不重打 APK.
|
||
底层使用 [`tauri-plugin-hotswap`](https://github.com/denniskribl/tauri-plugin-hotswap)
|
||
(签名/回滚/资源替换全部由插件处理).
|
||
|
||
### 工作流
|
||
|
||
```
|
||
开发者 服务端
|
||
npm run build ──┐
|
||
scripts/build-ota.mjs │ 生成 iboard-ota.tar.gz + minisign 签名
|
||
│ 输出 latest.json (sequence/version/...)
|
||
▼
|
||
ota-package/ ── 部署到服务器 ──▶ /srv/iboard/ota-package
|
||
│
|
||
▼
|
||
GET /api/ota/check/<seq>
|
||
客户端 (Tauri) │
|
||
启动 ─▶ notifyReady() ▼
|
||
我页 ─▶ checkUpdate() ◀──── 200 + manifest (含 url/signature) ─────┘
|
||
applyUpdate() ─▶ 下载 tar.gz ─▶ minisign 校验 ─▶ 解压到 AppData/ota-dist
|
||
location.reload() ─▶ 后续资源从 tauri://localhost 优先命中覆盖包
|
||
```
|
||
|
||
### 首次部署
|
||
|
||
1. **生成签名密钥** (一次性):
|
||
```bash
|
||
# 安装 minisign: Windows (scoop) / macOS (brew) / Linux (apt)
|
||
node scripts/ota-genkey.mjs
|
||
# 产物: ota-package/hotswap.{key, pub}
|
||
```
|
||
2. **把公钥写入 `src-tauri/tauri.conf.json`** 的 `plugins.hotswap.pubkey` 字段
|
||
(脚本会打印).
|
||
3. **配置 endpoint** (`src-tauri/tauri.conf.json`):
|
||
```json
|
||
"hotswap": {
|
||
"endpoint": "https://your-server/api/ota/check/{{current_sequence}}",
|
||
"pubkey": "RWR...",
|
||
"require_https": true
|
||
}
|
||
```
|
||
4. **服务端环境变量** `OTA_PACKAGE_DIR` 指向 `ota-package/` 所在目录.
|
||
|
||
### 发布新版前端
|
||
|
||
```bash
|
||
npm run build # 生成 dist/
|
||
node scripts/build-ota.mjs # 打成 tar.gz + 签名 + latest.json
|
||
# sequence 默认 = Date.now(), 也可 --sequence 43 手动指定
|
||
# 也可加 --notes "修复登录按钮" --min-binary 0.1.0
|
||
```
|
||
|
||
然后把 `ota-package/` 下两个文件 (`iboard-ota.tar.gz` + `latest.json`) 同步到
|
||
服务端 `OTA_PACKAGE_DIR` 指向的目录. sequence 单调递增即可.
|
||
|
||
### 客户端使用
|
||
|
||
打开 App 的"我"页, 点 [检查更新] → [立即升级] 即可. 失败会自动回滚到内置 dist.
|
||
|
||
> **注意:** Tauri 2 的 dev 模式 (`tauri dev`) 会代理到 Vite dev server, **OTA 不生效**.
|
||
> OTA 仅在 release/打包构建中可用, 测试请用 `tauri build` 产物.
|
||
|
||
### 客户端判新口径(V0.2 新增)
|
||
|
||
"我"页 OTA 组内有一个 **开发版本** 开关(默认关闭),切换"怎么算新版本":
|
||
|
||
| 开关 | 判新依据 | 适用 |
|
||
| --- | --- | --- |
|
||
| 关(默认) | **版本号**逐字段比大小(`0.2.0-ota` > `0.1.0` 才算新) | 生产。旧分支被重建(sequence 变大但版本号更小)时不会把设备拉回旧版 |
|
||
| 开 | **build sequence**(服务端 sequence 比本地大就算新) | 开发联调。每次构建都能推到设备 |
|
||
|
||
- 开关值持久化在设备端 `localStorage.iboard_ota_dev_mode`(`'1'`/`'0'`),默认 `'0'`。
|
||
- 版本比较在 `src/utils/version.js`(纯函数,`src/api/ota.js` 统一封装两种模式)。
|
||
- **`min_binary_version` 与应用版本是两件事**:前者是前端 bundle 要求的最低原生二进制版本,
|
||
当前 APK 原生层仍是 `0.1.0`,所以 CI 里固定传 `--min-binary 0.1.0`(见 `docker-build.yml` 的
|
||
`OTA_MIN_BINARY`)。只改前端版本号时**不要**跟着抬这个值,否则旧 APK 会收不到更新。
|
||
|
||
### Web 端
|
||
|
||
Web 浏览器访问 (同源) 时, 服务端返回简化版 manifest, 仅显示"有新版本请刷新".
|
||
Web 端不会自动下载包, 也不会替换前端代码.
|
||
|
||
|
||
### CI 自动签名 (Gitea Actions)
|
||
|
||
.gitea/workflows/ota-build.yml 是手动触发的 OTA 打包工作流 (每次发版前点一次).
|
||
|
||
**配置 secret** (Gitea 仓库 -> Settings -> Actions -> Secrets):
|
||
- MINISIGN_PRIVATE_KEY: 完整 .key 文件内容, **整段** (含首行 `untrusted comment: minisign encrypted secret key` 和 base64 行), 整段作为多行 secret 粘贴即可.
|
||
|
||
**使用流程**:
|
||
1. 在 Gitea Actions 页面选 OTA Frontend Build & Sign -> Run workflow
|
||
2. 填 sequence (可选, 不填用时间戳) 和
|
||
otes (可选)
|
||
3. CI 跑完会在 artifact 里看到 ota-package/iboard-ota.tar.gz + latest.json + iboard-ota.tar.gz.minisig
|
||
4. 下载 artifact, scp 到服务器 OTA_PACKAGE_DIR 目录
|
||
5. 客户端"我"页 [检查更新] 即可触发升级
|
||
|
||
**注意**:
|
||
- CI 用的私钥必须**与** auri.conf.json 里 plugins.hotswap.pubkey **配对**; 换密钥时需要同时更新 CI secret 和 conf.
|
||
- 不要把私钥 commit 到 git, 整个 ota-package/hotswap.key 已被 .gitignore 排除.
|