Files
iboard/docs/V0.2/离线编辑模块/0.2.1实施方案.md
T

7.6 KiB
Raw Blame History

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. 数据迁移(一次性)

  1. 在 baihu 上用仓库自带 mariadb 驱动以只读 SQL 从宿主 MySQL(3306) 导出全表 JSON(仅 SELECT);
  2. 转换:回填 uuid / Project.code(按名称自动生成,可后改)/ Task.number(按项目内 createdAt 顺序);时间字段转 PG 时间戳;
  3. PG 侧先 prisma migrate deploy 建基线表,再执行 ETL 写入;
  4. 校验:逐表行数比对 + 抽样字段比对,输出核对报告。

7. 里程碑

  1. M1 schema/适配层切 PG(本提交):schema 字段、db.js 适配器、基线迁移重建、本地 prisma generate 通过;
  2. M2 服务端:powersync token 端点、upload 幂等上行端点、任务域路由幂等化与编号分配逻辑;
  3. M3 前端:任务模块数据层切 PowerSync(本地库 + useQuery + 上传队列),桌面端联调;
  4. M4 compose 编排 + ETL 导数 + baihu 部署,端口/现网隔离验证;
  5. M5 离线-联网闭环验证(断网编辑 → 恢复自动同步 → 多端一致),Android 真机评估。

8. 开放问题 / 风险

  • powersync-service 的元数据存储(bucket storage)对 MongoDB 的依赖需在部署阶段核实;若当前版本不支持用 PG 存元数据,则加一个 mongo 容器;
  • Android System WebView 的 OPFS/WASM SQLite 兼容性(M5 评估,先桌面);
  • 项目前缀全局唯一在多端并发下的冲突提示体验(上行返回结构化错误码);
  • 0.2.1 验证期数据与现网彻底隔离,不回迁;若验证后需并回主线,另行决策迁移口径。