Files
iboard/docs/021任务.md
T

14 KiB
Raw Blame History

0.2.1 发布任务 — 目标与现状

最后更新:2026-10-27 08:05 分支:dev-0.2(已推送) 状态:生产已切换到 0.2.1 单端口架构并验证通过;剩余 "合 master 发布" 一步

零、执行结果速览(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;恢复:徽标消失

迁移过程中踩到并修掉的坑

  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。


五、关键路径与命令速查

# 仓库
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:准备(不改动现网)

# 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)

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)

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:切换生产

# 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:发布

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 重装即可。