Files
iboard/docs/021任务.md
T
2026-10-27 07:30:30 +08:00

291 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 0.2.1 发布任务 — 目标与现状
> 最后更新:2026-10-27 08:20
> 分支:`dev-0.2` 与 `master` 均已发布(`a1c267b`)
> 状态:**全部完成** —— 生产已切 0.2.1 单端口架构,master 发布 CI 通过,Android APK 与 Windows 安装包均已产出
## 零、执行结果速览(2026-10-27 已完成)
| 项目 | 结果 |
| --- | --- |
| 生产地址 | `https://iboard.honor3.com` → baihu **3001**(NPM + 有效证书) |
| 生产架构 | `iboard-prod-app-1`(3001 对外) + `iboard-prod-pg-1`(内网) + `iboard-prod-powersync-1`(内网) |
| 端口 | **只剩 3001**;13001 / 13002 / 13443 全部下线 |
| 数据迁移 | MySQL → PG 完成:Project 3、Task 25、BoardColumn 12、User 1、CheckIn 17、News 19、IndicatorPoint 245、Mihome 等全部迁入 |
| 旧生产 | 容器 `iboard` 已 **stop(未删除)**,`docker start iboard` 可秒级回滚 |
| 登录态 | `JWT_SECRET` 沿用 `iboard`,现有用户无需重新登录 |
| 米家凭证 | `/app/iboard/cache` → `deploy/prod/data/cache`(`auth.txt` + `apizero/`) |
| E2E 验证 | 在线:项目卡片 + `ADMIN-16`/`ADMIN-18` 编号;断网:徽标出现、任务页数据完整、无 fail fetch;恢复:徽标消失 |
| master 发布 | 已推 `master`(`a1c267b`);CI `build-image` **10/10 步成功**(版本校验 / 前端 / OTA 签名包 / 镜像 / 部署步按设计跳过) |
| Android | `android-1.0` CI **16/16 步成功**,APK 20MB(versionName 0.2.1)已发布到 Gitea packages |
| Windows | 本地 `npm run build:win` 成功:NSIS 6.9MB + 便携 zip 7.9MB |
### 迁移过程中踩到并修掉的坑
1. `prisma/migrations/` 是 **MySQL 语法**(反引号),PG 无法 `migrate deploy` → 改用 `prisma db push --accept-data-loss` 按 schema 建表。
2. `db push` 首次因参数不被识别而输出帮助(表结构停在旧 schema,缺 `autoArchive`)→ 去掉错误参数重跑,列已补齐。
3. 新库缺 **uuid 镜像触发器**(`projectUuid`/`columnUuid`/`parentUuid`/`taskUuid`)→ 从 0.2.1 验证库导出 5 个函数 + 5 个触发器,落库并入库 `deploy/prod/sql/uuid-triggers.sql`。
4. bash 把 `$$` 展开成 PID 导致 TRUNCATE 脚本报错 → 改用 SQL 文件传入。
5. baihu 上 `docker build` 缺 buildx → 改用 `docker compose build`。
---
## 一、任务目标(用户原始要求)
1. 域名 `iboard.honor3.com` 已指向 3000 端口、HTTPS 证书已配好 → 客户端全面切到该域名。
2. **Windows 外壳 + 离线编辑功能正式合并到 `dev-0.2`**,完整版本号 **0.2.1**。
3. 确保 **Android** 功能正常(通过 CI 编译验证,不在本地装 Android 工具链)。
4. 确保 **CI/CD** 正常。
5. Windows **本地打包正常**即可。
6. `dev-0.2` 更新完成后 **通过 `master` 分支发布**。
7. 追加要求:**不要再有 13002 这类独立端口**,所有版本合并成一套。
---
## 二、已完成
### 2.1 分支合并
| 内容 | 结果 |
| --- | --- |
| `dev-0.2.1`(离线编辑 + 项目编号 + PG/PowerSync)→ `dev-0.2` | 已合并 `e689e44` |
| `dev-windows-0.1`(Windows 外壳:托盘/悬浮球/吸附/自启动)→ `dev-0.2` | 已按路径迁入 `eef2969` |
| `dev-0.2` → `android-1.0`(触发 APK 构建) | 已合并 `4958359` |
| 冲突处理 | `projects.js`/`tasks.js`/`api/task.js` 手工合并,**两边功能都保留**(`autoArchive` 归档 + `code` 编号) |
| 归档功能补齐到本地库 | `src/api/task.js` 新增 `archive`/`unarchive`/`archivedList`;`schema.js` 加 `archived/archivedAt/archiveSource/autoArchive`;`sync-config.yaml` 与 upload 处理器同步 |
| Prisma 客户端补齐 | dev-0.2 原来缺任务模块 6 个模型,已重新 generate `fc23919` |
### 2.2 版本与域名
- 版本统一 **0.2.1**:`package.json` / `src-tauri/tauri.conf.json` / `Cargo.toml` / `Cargo.lock`(`scripts/ci/check-version.mjs` 通过)
- 域名切 `https://iboard.honor3.com`:
- `src/api/client.js` 注释、`.env.shell`、`scripts/wsl/build-apk.sh`、`.gitea/workflows/android-build.yml`、`.gitea/workflows/docker-build.yml`、`Dockerfile`(`OTA_PUBLIC_BASE`)、`tauri.conf.json`(OTA endpoint + CSP)
- 旧域名 `bh.vps.honor3.com:3001` 仅保留在 CSP 白名单里做滚动兼容
### 2.3 单端口架构(去掉 13002)
| 改动 | 位置 |
| --- | --- |
| Express 增加 `/sync`、`/socket` 同域反代到内网 powersync | `server/powersync-proxy.js` + `server/index.js`(挂在 `express.json()` 之前,支持长连接) |
| 生产编排:app(3001 对外) + pg(内网) + powersync(内网) | `deploy/prod/docker-compose.yml` |
| 生产部署脚本(幂等:迁移 → publication → 起栈 → 健康检查) | `scripts/deploy/prod.sh` |
| PG 初始化(powersync_storage 用户) | `deploy/prod/initdb/01-powersync-storage.sh` |
| 逻辑复制 publication(**建表后**执行) | `deploy/prod/sql/publication.sql` |
| 部署文档 | `deploy/prod/README.md`、`.env.example` |
| CI 部署段改为调用宿主脚本,未配 PG secrets 时自动跳过 | `.gitea/workflows/docker-build.yml` |
### 2.4 Windows 本地打包 — 通过 ✅
`npm run build:win` 全流程成功(本机需 Node 20.19+;已用便携 Node 20.18.1 之外的 Node 24 验证过 vite 构建):
| 产物 | 路径 | 大小 |
| --- | --- | --- |
| 安装包 | `artifacts/windows/iBoard_0.2.1_x64-setup.exe` | 6.9 MB |
| 便携版 zip | `artifacts/windows/iBoard_0.2.1_x64-portable.zip` | 7.9 MB |
外壳能力(继承 dev-windows-0.1):托盘、悬浮球吸附、自动隐藏、单实例、自启动、窗口尺寸单值配置
(`%APPDATA%\com.iboard.app\shell-config.json` 的 `window_width`,高度按 405:720 锁定推导)。
离线能力(继承 0.2.1):GET 响应本地缓存、同步凭证持久化(离线不清库)、左上角「离线」徽标。
### 2.5 Android CI — 通过 ✅
- 触发:`android-1.0` 分支 push(`4ded8e3`)
- 结果:**16 个步骤全部 success**,`Build release APK` + `Publish APK to Gitea packages` 成功
- 产物:`app-universal-release.apk`(20 MB),versionName = **0.2.1**
已发布到 `http://git.honor3.com/api/packages/Fullstack/generic/iboard/1.0-4ded8e30/`
- 首次失败原因:runner 宿主机(baihu)磁盘 **95%** → `No space left on device`;
清理悬空镜像 + 构建缓存后释放 11.5 GB,重跑通过。**磁盘现已 60%(39 GB 可用)**
### 2.6 CI/CD 现状
| Workflow | 触发 | 状态 |
| --- | --- | --- |
| `docker-build.yml` | `master` push | 改造完成,未在 master 上验证(部署段会因缺 secrets 跳过) |
| `android-build.yml` | `android-*` push | **已验证通过** |
| `ota-build.yml` / `sync-registry.yml` | 参照原逻辑 | 未改动 |
---
## 三、当前卡点(生产切换未执行)
生产镜像 **已构建成功**:`iboard:latest` = `db6b27b851b8`(924 MB,2026-10-26 22:53)
baihu 上当前跑着两套:
| 容器 | 用途 | 端口 |
| --- | --- | --- |
| `iboard`(旧) | **现网生产**,MySQL(宿主 3306) | 3001 |
| `iboard-021-app-1` 等 4 个 | 0.2.1 验证栈 | 13001 / 13002 / 13443 |
| (未启动)`iboard-prod` | **新生产栈**(PG + PowerSync + app) | 3001(计划) |
`/app/iboard-prod` 已上传源码、`deploy/prod/.env` 已生成(6 个密钥,600 权限)。
**剩余步骤(约 4 步)**:
1. 起新栈(先用 `HOST_PORT=13011` 灰度,不动现网)
2. 数据迁移:现网 MySQL → 新 PG(`scripts/etl-mariadb-to-pg.mjs`,只读源库)
3. 验证:健康检查、登录、任务列表、离线编辑(断网后仍可读)、同步回流
4. 切换:停 `iboard` 旧容器 → 新栈改绑 3001 → 域名 `iboard.honor3.com` 生效 → 下线验证栈(13001/13002/13443)
然后 `dev-0.2` → `master` 合并推送,触发 CI 发布。
---
## 四、需要确认的信息(阻塞项)
1. **Gitea Actions Secrets 是否要配 PG 密钥?**
需配:`PG_PASSWORD`、`PS_STORAGE_PASSWORD`、`JWT_SECRET`、`POWERSYNC_JWT_SECRET`、`POWERSYNC_JWT_KEY_B64`。
不配的话:master 的 CI 只构建镜像不部署,生产靠手工执行 `scripts/deploy/prod.sh`(当前默认路径)。
2. **生产数据迁移的时间窗口**:迁移需短暂停写(现网 MySQL 只读快照)。是否可以挑一个低峰时间、期间 (~10 分钟) 站点只读?
3. **现网 MySQL 里的米家凭证/缓存**:`/app/iboard/cache`(`auth.txt` 等)是否要一并搬到新栈的 `deploy/prod/data/cache`?
4. **用户密码**:迁移只搬数据,`JWT_SECRET` 若换新,所有人需重新登录;是否沿用现网 `JWT_SECRET`(`iboard`)以保持登录态?**建议换新**(当前值过弱)。
5. **域名端口说明**:`iboard.honor3.com` 实际反代到 baihu **3001**(NPM 配置:`114.134.187.170:3001`,SSL 强制)。
你提到"已转向 3000 端口"——请确认指的是 `honor3.com` 根域(→ homepage)而非 `iboard` 子域,
否则需要调整 NPM 的 forward_port。
---
## 五、关键路径与命令速查
```bash
# 仓库
C:\Users\Rabbit\Documents\workbetch\iboard # dev-0.2 主工作区
C:\Users\Rabbit\Documents\workbetch\iboard-dev-0.2.1 # 研究分支 worktree
C:\Users\Rabbit\Documents\workbetch\iboard-dev-windows # Windows 外壳 worktree
# 服务器
ssh root@baihu # 生产 + CI runner(baihu 上跑 act_runner,注册名 baishe)
ssh root@baishe # 反代(NPM)、Gitea、homepage
# 生产目录
/app/iboard-prod/deploy/prod/{docker-compose.yml,.env,data/,powersync/,sql/,initdb/}
# 常用
docker compose -f /app/iboard-prod/deploy/prod/docker-compose.yml --env-file /app/iboard-prod/deploy/prod/.env ps
bash /app/iboard-prod/scripts/deploy/prod.sh
curl -s https://iboard.honor3.com/api/health
```
## 五之二、后续动作执行步骤(已确认方案,按序执行)
### 决策确认(2026-10-27)
| 项 | 决定 |
| --- | --- |
| PG 密钥 | **不进 Gitea Secrets**,直接写在服务器 `/app/iboard-prod/deploy/prod/.env`(600) |
| 迁移时机 | 立即执行 |
| 米家凭证 | 保留,`/app/iboard/cache` 搬到新栈 `deploy/prod/data/cache` |
| `JWT_SECRET` | 沿用现网值(`iboard`),保持现有登录态 |
| 域名 | `iboard.honor3.com` → baihu **3001**(NPM 已配好,SSL 强制) |
### 步骤 A:准备(不改动现网)
```bash
# A1. 沿用现网 JWT_SECRET (其余密钥保持已生成的随机值)
cd /app/iboard-prod/deploy/prod
sed -i 's/^JWT_SECRET=.*/JWT_SECRET=iboard/' .env
# A2. 搬米家缓存 (auth.txt 等)
mkdir -p data/cache
rsync -a /app/iboard/cache/ data/cache/
# A3. 保留旧镜像用于回滚
docker tag iboard:latest iboard:mysql-final # 需在重新构建前执行; 若已覆盖见"回滚预案"
```
### 步骤 B:起灰度栈(不动现网 3001)
```bash
cd /app/iboard-prod/deploy/prod
HOST_PORT=13011 docker compose --project-name iboard-prod \
--env-file .env -f docker-compose.yml up -d pg
# 迁移建表
docker run --rm --network iboard-prod_default \
-e DATABASE_URL="postgresql://iboard:$(grep ^PG_PASSWORD .env | cut -d= -f2)@pg:5432/iboard" \
iboard:latest npx prisma migrate deploy
# 建 publication (必须在建表之后)
docker compose --project-name iboard-prod --env-file .env -f docker-compose.yml exec -T pg \
psql -U iboard -d iboard -v ON_ERROR_STOP=1 -f /dev/stdin < sql/publication.sql
# 起 app + powersync (只有 13011 对外)
HOST_PORT=13011 docker compose --project-name iboard-prod \
--env-file .env -f docker-compose.yml up -d app powersync
# 验收
curl -s http://127.0.0.1:13011/api/health # {"ok":true,...}
ss -tlnp | grep -E ':(13011|5432|8080)\b' # 只应看到 13011
```
### 步骤 C:数据迁移(MySQL → PG)
```bash
docker run --rm --network iboard-prod_default \
-e DATABASE_URL="postgresql://iboard:<PG_PASSWORD>@pg:5432/iboard" \
-e SRC_DATABASE_URL="mysql://root:<MYSQL_PASSWORD>@<host>:3306/iboard" \
iboard:latest node scripts/etl-mariadb-to-pg.mjs
# 迁移后重启同步服务重建快照
docker compose --project-name iboard-prod --env-file .env -f docker-compose.yml restart powersync
```
**验收**:项目 3 个(ADMIN / IBOARD / P3F921)、任务 ~22 条、用户 1 个(admin@iboard.local);
`docker compose logs powersync` 显示 replication 已激活且无报错。
### 步骤 D:功能验证(13011)
- 登录 `admin@iboard.local`
- 任务页:项目卡片、任务编号(如 `ADMIN-16`)
- **离线验证**:断网后列表仍可读、左上角出现「离线」徽标,恢复网络自动同步回流
- 监控 / 宏观 / 打卡页有数据
### 步骤 E:切换生产
```bash
# E1. 停旧容器 (MySQL 版)
docker rm -vf iboard || true
# E2. 新栈改绑 3001
cd /app/iboard-prod/deploy/prod
HOST_PORT=3001 docker compose --project-name iboard-prod \
--env-file .env -f docker-compose.yml up -d app
curl -s https://iboard.honor3.com/api/health # 经 NPM + 证书
# E3. 下线 0.2.1 验证栈 (释放 13001/13002/13443)
cd /app/iboard-0.2.1/deploy/0.2.1 && docker compose down
```
**验收**:`https://iboard.honor3.com` 可登录、任务正常、离线可编辑;
`ss -tlnp` 只剩 3001(外加仅供本机的 3306)。
### 步骤 F:发布
```bash
git checkout master && git merge dev-0.2 --no-edit
git push origin master # 触发 CI: 构建镜像 + OTA
```
CI 未配 PG secrets → 只构建不部署;生产已由步骤 B~E 手工就绪。
### 回滚预案
| 场景 | 动作 |
| --- | --- |
| 新栈起不来 | 旧容器未停,现网不受影响,回步骤 B 排查 |
| 迁移数据不对 | 清空 `deploy/prod/data/pg` 后重跑 ETL |
| 切换后严重故障 | 用 `iboard:mysql-final` 旧镜像按原 MySQL 参数恢复 3001 |
## 六、已知遗留
- `dev-0.2.1` / `dev-windows-0.1` 两个 worktree 分支内容已全部并入 `dev-0.2`,可择机删除。
- `tmp-offline-edit` 分支 = `1cd5b85`,历史遗留,可删。
- 临时测试脚本 `scripts/_browser-test.mjs`、`scripts/_shell-offline-test.mjs` 含真实口令,**不要入库**。
- 0.2.1 验证库里可能残留测试任务(`浏览器验证任务` / `IBOARD-8`),迁移后建议清理。
- `node_modules` 曾在多种 Node 版本间切换,如遇 esbuild 权限报错,清 `node_modules` 重装即可。