Files
iboard/docs/V0.2/离线编辑模块/PowerSync可行性研究报告.md
jif2.zhang 74e1e7dd13
Docker Build and Push / build-image (push) Successful in 1m25s
feat(V0.2): 标题30字+智能拆分 / 时间标记 MM-dd / 时间词前缀 (T-TK-14~16)
- 标题上限收紧至 30 字 (服务端校验+详情编辑框); 快速添加输入框
  放宽到 200 字: 超长时在 30 字内分隔符处截断为标题, 完整原文进描述
- Task.markDate (DateTime, 迁移 20261025120000): 详情页 DatePicker
  选择/清除, 列表行与看板卡显示 MM-dd 小标签
- 快速添加时间词前缀: 今天/明天/后天/本周/下周/本月/下月 开头
  (后跟分隔符) 自动设为时间标记并移出标题; 本周=本周日, 本月=月末
- 需求/功能/数据库设计文档同步更新 T-TK-14~16 与 Task 表字段
2026-10-25 11:47:44 +08:00

10 KiB
Raw Permalink Blame History

基于 PowerSync 的离线编辑可行性研究报告

项 内容
版本 V0.2
日期 2026-10-25
评估对象 PowerSync(powersync.com,开源 self-hosted + 云服务)
评估目标 项目离线操作(本地编辑)+ 联网后自动同步
结论(TL;DR) 技术上可行,但落地成本高、风险中高。不建议全量接入;若确需离线,建议仅对「打卡 / 清单 / 任务」等用户编辑域做局部接入,且需要先解决 MariaDB 兼容与主键策略两个前置问题。

1. 项目现状约束(评估输入)

结合代码库(package.json、prisma/schema.prisma、server/index.js)梳理:

  1. 前端:React 18 SPA(antd-mobile),通过 axios 调 /api/* REST 接口;src/api、src/hooks、src/pages 均以"请求 → state → 渲染"模式组织,无任何本地持久化数据层。
  2. 桌面/移动端:Tauri 2(Windows WebView2 桌面 + Android System WebView),意味着前端运行在 WebView 内,浏览器类 SDK 是候选。
  3. 后端:Express + Prisma,数据库为 MariaDB / MySQL(provider = "mysql")。
  4. 认证:自签 JWT(jsonwebtoken),登录接口在 /api/auth。
  5. 写路径:全部业务写操作走 REST(打卡、清单、任务模块);同时存在大量服务端定时写入(cron:新闻、指标、监控、米家采样等,见 server/cron.js)。
  6. 数据模型:约 25 张表,主键全部为 Int @id @default(autoincrement()) 自增整数,多表带复合唯一约束(如 CheckIn @@unique([habitId, date, seq]))。
  7. 数据体量特征:两类数据并存——
    • 用户编辑域(Habit / CheckIn / CheckList* / 任务模块 10 张表):冲突敏感、离线价值高;
    • 服务端只读时序域(News / Indicator / ServerNodeHistory / MihomeEnv* 等):append-only、量大、离线价值中等(缓存即可满足)。

2. PowerSync 是什么、怎么工作

  • 架构:客户端本地 SQLite(Web 端为 WASM SQLite,存 OPFS/IndexedDB)↔ PowerSync Service(self-hosted 开源组件或云服务)↔ 源数据库。服务端通过 逻辑复制/变更流 捕获源库写入,按 Sync Rules 定义的下推子集同步到每个客户端的本地 SQLite。
  • 写路径(官方推荐模式):客户端离线写本地 SQLite → 进入 upload queue → 联网后由前端把变更批量 POST 到现有后端 API → 后端用原有方式(本项目即 Prisma)写库 → 变更流捕获 → 广播回各端。
  • 认证:客户端持后端签发的 JWT 连接同步服务;PowerSync 只做校验,不签发(可复用现有 jsonwebtoken 体系)。
  • 服务端直写的表(cron 产生)也能被变更流捕获并下推,不需要改造写入方。

参考:PowerSync Service(GitHub)、源数据库支持。


3. 逐项可行性分析

3.1 数据库兼容性 —— ⚠️ 主要风险点

  • PowerSync 对源库支持:PostgreSQL(GA)、MongoDB、SQL Server;MySQL 仍处于 Beta(基于 binlog 复制,见 MySQL Beta 公告、Alpha 公告)。
  • 本项目用的是 MariaDB。MariaDB 的 binlog 格式与 MySQL 8 有差异(GTID、行事件细节),PowerSync MySQL 插件(@powersync/mysql-zongji 系)对 MariaDB 没有官方兼容承诺,需要实测验证,很可能踩坑。
  • 结论:要么实测 MariaDB + MySQL-beta 通路(风险高),要么把数据库迁到 PostgreSQL(PowerSync 最成熟路径,Prisma 迁移成本可控但涉及全部表和线上数据)。这是"能不能用"的第一道门槛。

3.2 数据模型适配 —— 改造成本大

  • PowerSync Sync Rules 要求同步表有稳定的行标识,强烈建议 UUID 文本主键;而本项目全部是自增整数主键,且客户端离线创建记录时无法预知自增 id。
  • 离线创建的通用解法:主键改为客户端生成的 UUID(char(36)),或新增 uuid 列 + 应用层幂等 upsert。对用户编辑域的 10 余张表意味着一次不小的 schema 迁移 + 全部相关路由改造(迁移原则"只增不改"仍可遵守,但外键列类型变更工作量大)。
  • DateTime、Json 类型可映射(客户端以 ISO 文本/JSON 文本存储),但 BigInt(监控表)在 JS 端需按文本处理,注意精度。
  • 复合唯一约束(CheckIn(habitId,date,seq)、BoardColumn(projectId,name) 等)在离线多端并发下会冲突,需在 upload 处理端路由里做服务端仲裁(如 seq 重排、重名加后缀),现有路由大多不具备幂等/仲裁语义。

3.3 写路径(离线编辑 + 上行同步)—— 模式契合,但需逐路由改造

  • PowerSync 的 upload-queue → 后端 API 模式与现有 Express 架构天然契合:不需要后端暴露直接写库的通口,各业务路由补成"接收客户端 UUID + 幂等 upsert"即可。
  • 打卡/清单/任务的路由数量约 3 个 router 文件(checkin / checklists / projects / tasks),逐个改造为幂等是可控的。
  • 服务端 cron 写入的表(新闻/指标/监控/米家)无需改造写入方,只需在 Sync Rules 里定义是否下推。

3.4 读路径与前端数据层 —— 全面前重写

这是工作量最大的部分:

  • 现有 src/api + axios + useEffect 模式必须替换为 PowerSync 本地 SQLite 查询 + @powersync/react 的响应式 hooks(useQuery 等),否则离线读不到数据。
  • 涉及 src/pages 下全部用户编辑域页面(checkin、task),以及若要离线浏览还需覆盖 news/macro/monitor 的只读缓存页。
  • 工作量量级:相当于把前端数据层重构一遍;可与"离线只读缓存(HTTP 缓存)"分层实施以降低风险。

3.5 客户端运行环境 —— 大体可行,Android 需验证

  • 浏览器 / Tauri 桌面(WebView2):PowerSync Web SDK(WASM SQLite + OPFS)在 Chromium 系 WebView 已被官方支持,可行。
  • Tauri Android(System WebView):WASM SQLite 性能与 OPFS 在部分国产/旧版 WebView 上存在兼容性风险,需真机验证;备选方案是封装原生 SQLite(官方 Capacitor 插件思路可借鉴,但 Tauri 无官方插件,需自研 Rust 命令桥接,成本额外增加)。
  • 时序大表(ServerNodeHistory 每分钟一条、MihomeEnv*)不建议纳入同步——Sync Rules 需做时间窗过滤(如仅近 7 天),否则客户端存储和同步流量都会失控。

3.6 认证与部署 —— 可行

  • JWT 可复用:新增一个 /api/powersync/token 端点为已登录用户签发 PowerSync 接受的 token,改造小。
  • 部署:self-hosted 需在现有 Express 之外多跑一个 powersync-service 进程(含 Mongo 存储元数据或云实例),并暴露 WebSocket 端口;或使用 PowerSync Cloud。运维面增加一个组件。

3.7 冲突解决

  • PowerSync 本身不做自动合并,只提供上传队列与冲突回调;对"最后写入胜出"友好的字段(清单勾选、任务标题/状态)默认策略够用;对 CheckIn.seq、BoardColumn.sortOrder 这类"位置/序号型"数据需要自定义仲裁逻辑(上传端或同步流中处理),设计上可解,但要专门做。

4. 风险与成本汇总

# 风险/成本项 等级 说明
1 MariaDB 兼容性未验证,MySQL 支持仅 Beta 高 很可能需要迁移 PostgreSQL
2 前端数据层全面重构(axios → 本地 SQLite 查询) 高 涉及所有相关页面
3 用户编辑域主键整数自增 → UUID 迁移 中高 schema + 路由幂等改造
4 复合唯一约束的离线冲突仲裁 中 CheckIn.seq、列名、排序等
5 Android WebView WASM SQLite/OPFS 兼容 中 需真机验证
6 新增 self-hosted 组件的运维 中 多一个常驻服务
7 时序大表同步范围控制 低 Sync Rules 时间窗过滤即可

对照收益:真正需要离线编辑的只有打卡 / 清单 / 任务三个域(数据量小、单用户为主、冲突场景有限);其余域离线只读缓存即可满足。


5. 结论与建议

5.1 结论

可行,但不建议以"全项目接入 PowerSync"的方式落地。 PowerSync 的同步模型与项目的 Express API 写路径契合、认证可复用、桌面端可行;但 MariaDB/MySQL-beta 兼容、整数自增主键、前端数据层全面重构三座大山使总成本明显高于当前阶段的收益。

5.2 建议(按优先序)

  1. 首选(低成本方案):不引入 PowerSync,为用户编辑域实现轻量离线队列——前端把写请求落到 localStorage/IndexedDB 待发队列(含客户端生成的 UUID),联网后重放到现有 REST API(路由补幂等 upsert);只读页用 HTTP 缓存 + SW。可覆盖约 80% 的离线诉求,改动局限在 src/api 层与少量路由。
  2. 若决定采用 PowerSync:
    • 前置 1:源库迁移 PostgreSQL(避开 MySQL Beta + MariaDB 兼容雷区);
    • 前置 2:仅将用户编辑域(Habit/CheckIn/CheckList*/任务模块)纳入 Sync Rules,时序与监控表排除或做时间窗过滤;
    • 前置 3:这些表的主键/唯一标识改造为客户端可生成的 UUID;
    • 分阶段:先桌面端(WebView2)验证全链路,再攻 Android WebView 兼容性;
    • 冲突策略:字段级 LWW 为主,seq/sortOrder 类服务端仲裁。
  3. 不建议:为离线只读域(新闻/指标/监控)上 PowerSync——用简单缓存即可,同步引擎属于过度设计。

6. 参考资料