7.6 KiB
7.6 KiB
0.2.1 实施方案:PostgreSQL 迁移 + 任务模块离线编辑 (PowerSync)
| 项 | 内容 |
|---|---|
| 分支 | dev-0.2.1(worktree iboard-dev-0.2.1,独立临时分支,与 master / dev-0.2 隔离) |
| 日期 | 2026-10-25 |
| 依据 | PowerSync可行性研究报告,按其 5.2.2 路线执行 |
| 目标 | 在现网应用与数据不受影响的前提下,验证任务模块离线编辑 + 联网后自动双向同步;数据库由 MariaDB 迁移至 PostgreSQL |
1. 已确认决策(2026-10-25 与需求方对齐)
| 决策点 | 结论 |
|---|---|
| 技术路线 | PowerSync 全链路(自部署 powersync-service) |
| 离线范围 | 仅任务模块(Project / ProjectMember / BoardColumn / Task / TaskMember / TaskTag);打卡、清单本阶段不纳入;新闻/指标/监控等时序域仅做普通缓存 |
| 客户端 | 先 Web / Windows 外壳(WebView2)跑通全链路;Android 真机后续验证 |
| 编号 | 项目短前缀由用户自拟(2~8 位,全局唯一);任务号 = 项目内自增整数,展示 前缀-序号;编号由服务端统一分配,离线创建的任务在同步定号前显示临时标识 |
| 初始数据 | 从现网 MariaDB 只读快照导出并转换导入新 PG;0.2.1 期间产生的新数据不回写现网 |
| 端口 | Web/API 13001、PowerSync WebSocket 13002、PG 仅容器内网(调试绑 127.0.0.1:15432) |
| 部署 | 源码上传 baihu /app/iboard-0.2.1,服务器上 docker compose build;不使用原 CI/CD |
| 现网保护 | /app/iboard、宿主 3306 MySQL、3001 端口、原 CI/CD 一律不使用(快照导出仅 SELECT) |
| 磁盘 | 允许在 baihu 执行 docker 悬空镜像/构建缓存的安全清理(磁盘仅剩 9.9G) |
2. 目标架构
[Web / Tauri WebView2]
React + @powersync/react
本地 WASM SQLite (OPFS 持久化)
│ 离线: 直接读写本地库; 写操作进入 upload queue
│ 联网: 批量 POST 上行到 Express API (按 uuid 幂等 upsert)
▼
[iboard-0.2.1 Express :13001] ── Prisma (adapter-pg) ──┐
+ /api/powersync/token (为登录用户签发同步 JWT) ▼
[PostgreSQL 容器] (wal_level=logical)
▲ 逻辑复制 (publication + replication slot)
[powersync-service :13002] ── Sync Rules: 任务域 6 表 + User 只读引用, 按 ProjectMember 过滤
- 写路径:客户端本地写 → upload queue → 上行 API → Prisma 写 PG → 逻辑复制捕获 → 广播各端;
- 读路径:任务模块页面全部改读本地 SQLite(@powersync/react 响应式查询),其余页面维持 axios REST;
- 认证:复用现有 jsonwebtoken 体系,新增
/api/powersync/token签发 PowerSync 校验的 JWT。
3. 数据模型改造(原则:只增不改)
采用报告 3.2 中的「新增 uuid 列 + 应用层幂等 upsert」选项,不做全表主键 UUID 化:外键关系全部保留,存量数据迁移风险最小。
- 任务域 6 表各加
uuid varchar(36) unique(客户端创建时生成;存量行导入时回填); Project加code varchar(8) unique(用户自拟短前缀;存量项目导入时回填自动码,后续可改);Task加number int,@@unique([projectId, number])(服务端按项目 max+1 分配;离线创建的任务上行时定号,本地未定号行显示临时标识);- 主键仍为自增 Int,业务外键不动;客户端上行一律以 uuid 引用父子行,服务端解析为内部 id;
- Prisma datasource:
mysql→postgresql;本分支重建基线迁移(旧 MySQL 迁移文件移除,历史保留在 git)。
3.1 Sequential ID Mapping(落地时按官方模式补充)
按 PowerSync 官方 Sequential ID Mapping 模式实施,解决"离线新建行同步回填后本地 id 变化"问题:
- 任务域 6 表再加外键 uuid 镜像列(
Task.projectUuid/columnUuid/parentUuid、BoardColumn.projectUuid、ProjectMember.projectUuid、TaskMember/TaskTag.taskUuid),由 PG 触发器在写入时按 int 外键自动回填(迁移20261026010000_uuid_fk_mapping),库级 NOT NULL; - Sync Streams 以
uuid作为客户端主键(SELECT "uuid" AS "id"),镜像列别名输出回projectId/columnId/parentId/taskId—— 客户端 schema 与页面代码零改动; - 服务端 upload 处理器按 uuid 解析父行(
findUnique({ where: { uuid } })),解析后再写 int 外键 → 触发器回填镜像,两侧闭环一致; - 镜像列在 Prisma 模型中声明为可空(触发器保证库级非空),避免 create 校验拦截。
4. 同步与冲突
- Sync Rules 仅下发任务域 6 表 +
User(展示名称/头像用),按ProjectMember.userId = auth.parameters.userId过滤项目可见性;时序/监控/米家等表不纳入; - 上行:
POST /api/powersync/upload批处理客户端 CRUD 操作,按 uuid 幂等 upsert,更新时以服务端时间戳做 LWW 仲裁; - 冲突:字段级 LWW 为主;
BoardColumn.sortOrder/Task.sortOrder由服务端重排仲裁;并发唯一冲突(项目前缀、看板列名)返回明确错误,客户端提示重试; Task.number/Project.code由服务端唯一分配,多端并发下天然无冲突。
5. 部署拓扑(baihu /app/iboard-0.2.1)
docker compose 三服务:
| 服务 | 镜像 | 端口 | 说明 |
|---|---|---|---|
pg-021 |
postgres:16-alpine | 仅容器内网 | wal_level=logical;数据卷 ./data/pg |
powersync-021 |
powersync 官方镜像 | 13002 对外 | 连接 PG 逻辑复制 + WebSocket 下发 |
app-021 |
本仓库 Dockerfile 构建 | 13001 对外 | OTA_PUBLIC_BASE=http://bh.vps.honor3:13001 |
- 环境变量由 compose 注入:
DATABASE_URL(指向 pg-021)、JWT_SECRET(0.2.1 独立新设)、PORT=13001; - 0.2.1 容器内 cron/米家调度预计无凭证或产生重复外呼,部署时以环境开关关闭(实现于 M4)。
6. 数据迁移(一次性)
- 在 baihu 上用仓库自带
mariadb驱动以只读 SQL 从宿主 MySQL(3306) 导出全表 JSON(仅 SELECT); - 转换:回填 uuid /
Project.code(按名称自动生成,可后改)/Task.number(按项目内 createdAt 顺序);时间字段转 PG 时间戳; - PG 侧先
prisma migrate deploy建基线表,再执行 ETL 写入; - 校验:逐表行数比对 + 抽样字段比对,输出核对报告。
7. 里程碑
- M1 schema/适配层切 PG(本提交):schema 字段、db.js 适配器、基线迁移重建、本地
prisma generate通过; - M2 服务端:powersync token 端点、upload 幂等上行端点、任务域路由幂等化与编号分配逻辑;
- M3 前端:任务模块数据层切 PowerSync(本地库 + useQuery + 上传队列),桌面端联调;
- M4 compose 编排 + ETL 导数 + baihu 部署,端口/现网隔离验证;
- M5 离线-联网闭环验证(断网编辑 → 恢复自动同步 → 多端一致),Android 真机评估。
8. 开放问题 / 风险
- powersync-service 的元数据存储(bucket storage)对 MongoDB 的依赖需在部署阶段核实;若当前版本不支持用 PG 存元数据,则加一个 mongo 容器;
- Android System WebView 的 OPFS/WASM SQLite 兼容性(M5 评估,先桌面);
- 项目前缀全局唯一在多端并发下的冲突提示体验(上行返回结构化错误码);
- 0.2.1 验证期数据与现网彻底隔离,不回迁;若验证后需并回主线,另行决策迁移口径。