mobile-note-sync-architecture
GitHub移动端笔记同步架构规范,涵盖本地优先、多端一致性、单一写入及防空覆盖规则。指导Agent处理Pull/Push链路、字段合并、UI分层约束及守卫测试,确保数据最终一致与架构合规。
Trigger Scenarios
Install
npx skills add MimicHunterZ/PocketMind --skill mobile-note-sync-architecture -g -y
SKILL.md
Frontmatter
{
"name": "mobile-note-sync-architecture",
"metadata": {
"tags": [
"flutter",
"sync",
"isar",
"riverpod",
"lww",
"offline-first",
"guard-test"
],
"updated": "2026-03-28",
"version": "1.0.1"
},
"description": "PocketMind 移动端笔记同步架构专项 Skill。当涉及以下问题时必须触发:预览字段(previewTitle等)被同步覆盖、多端一致性与离线冲突问题、同步链路改造(Pull\/Push)、UI层违规调用底层Provider、抓取\/轮询等写入未进入同步队列、或维护同步守卫测试。"
}
PocketMind 移动端同步架构 Skill(当前实现版)
1. 核心触发场景
本技能重点解决移动端数据的防空覆盖、Pull-first + Push 多端一致性、单一写入事务以及底层架构分层问题。凡涉及核心同步链路相关的修改,必须严格遵守以下规则。
2. 当前业务目标(必须遵守)
- 本地优先 + 离线可写:用户写操作先落本地,再异步同步。
- 跨端最终一致:通过 Pull-first + Push 逐步收敛。
- 写路径单一:所有写操作必须走统一入口,禁止旁路写。
- UI 单层交互:UI 页面层只和
NoteService交互,不直接碰同步底层。 - 预览字段防空覆盖:服务端空值或缺失字段不能抹掉端侧抓取结果。
- 可回归验证:改同步链路必须补/改守卫测试并运行
test/sync。
3. 架构总览(当前代码)
UI(Page/Widget)
-> NoteService (统一业务入口)
-> LocalWriteCoordinator (原子双写:业务表 + MutationEntry)
-> Isar(Note/Category/MutationEntry)
-> SyncEngine.kick()
-> PullCoordinator (先拉增量)
-> PushCoordinator (再推本地 pending)
后台衍生写入链路(抓取/轮询/回调)
-> NoteService.persistDerivedNoteForSync()
-> LocalWriteCoordinator.writeNote()
-> MutationEntry 入队
-> SyncEngine.kick()
关键点:
SyncEngine是网络同步唯一入口,采用 single-flight(单飞 + 追尾)。PullCoordinator在本地有 pending 时走字段级合并;无 pending 时走粗粒度 LWW。PushCoordinator以mutationId做幂等,支持 accepted / conflict / retryable / failed 四类结果处理。
4. 关键文件与职责(修改同步时优先看)
-
mobile/lib/service/note_service.dart- 统一业务入口。
- 含
persistDerivedNoteForSync、triggerSyncNow、URL 队列调度。
-
mobile/lib/sync/local_write_coordinator.dart- 唯一合法写入协调器。
- 单事务完成业务表写入 + MutationEntry 追加。
-
mobile/lib/sync/sync_engine.dart- 同步调度中枢(Pull-first + Push)。
-
mobile/lib/sync/pull_coordinator.dart- 增量拉取、分页游标推进、字段级合并。
-
mobile/lib/sync/push_coordinator.dart- pending 批量推送、冲突回滚、重试与失败管理。
-
mobile/lib/sync/note_sync_payload_mapper.dart- 服务端快照映射。
- 预览字段非空覆盖与
previewImageUrl回退保护。
-
mobile/lib/sync/resource_fetch_scheduler.dart- PENDING 资源抓取调度。
- 抓取成功后必须通过
NoteService.persistDerivedNoteForSync。
-
mobile/lib/service/ai_polling_service.dart -
mobile/lib/service/call_back_dispatcher.dart- 两条后台链路都必须走统一衍生写入口。
-
mobile/lib/page/home/sync_settings_page.dart
- UI 触发同步需调用
NoteService.triggerSyncNow。
mobile/lib/providers/sync_providers.dart
- 同步与抓取调度器依赖注入。
5. 强约束与禁令(高优先级)
- 禁止新增任何绕过
LocalWriteCoordinator的业务写入。 - 禁止恢复或新增
saveSyncInternalNote旁路 API。 - 禁止 UI 页面层直接依赖:
noteRepositoryProviderlocalWriteCoordinatorProvidersyncEngineProvider
- 禁止将服务端
null/空串的previewTitle|previewDescription|previewContent直接覆盖本地有效值。 - 禁止在同步关键路径中破坏 Pull-first 顺序。
- 修改同步字段时,必须同时检查 Pull 合并逻辑、Push 回滚逻辑、Mapper 映射逻辑三处是否一致。
6. 字段合并规则(现行业务规则)
6.1 本地无 pending mutation
- 使用粗粒度 LWW:
server.updatedAt >= local.updatedAt则服务端胜。 - 服务端胜时可全量覆盖(保留 Isar id)。
6.2 本地有 pending mutation
- 走字段级合并:只覆盖“服务端托管字段”。
- 本地锁定字段(不可被服务端覆盖):
titlecontenturlcategoryIdtime
tags使用并集合并,保持本地顺序优先(见TagListUtils.mergeLocalAndServer)。
6.3 preview 字段
previewTitle|previewDescription|previewContent使用非空覆盖策略。previewImageUrl在服务端未携带该字段时保留本地值(fallback)。
7. 标准改造流程(给后续 Agent)
- 先定位改动属于哪一层:UI / Service / Coordinator / Mapper / Test。
- 若涉及“写入”,先确认是否经过
NoteService->LocalWriteCoordinator。 - 若涉及“服务端覆盖本地”,同时检查:
note_sync_payload_mapper.dartpull_coordinator.dart的_mergeServerManagedFieldspush_coordinator.dart的 409 冲突回滚分支
- 若新增后台链路(爬虫/轮询/回调),必须调用
persistDerivedNoteForSync。 - 修改后至少运行
flutter test test/sync。
8. 必跑测试(最小回归集)
-
mobile/test/sync/write_path_guard_test.dart- 防止旁路写符号回流。
-
mobile/test/sync/ui_layer_boundary_guard_test.dart- 防止 UI 直接依赖同步底层 Provider。
-
mobile/test/sync/derived_sync_write_usage_test.dart- 确保 AI 轮询/后台回调都走统一写入口。
-
mobile/test/sync/note_sync_payload_mapper_test.dart- 确保 preview 字段防空覆盖规则不回归。
-
命令:
cd mobile
flutter test test/sync
9. 常见问题与处理指引
-
症状:分享后 preview 字段又丢了。
- 优先检查
NoteSyncPayloadMapper._resolvePreviewField与 Pull 合并逻辑。
- 优先检查
-
症状:本地抓取到了内容,但另一端看不到。
- 检查是否走了
persistDerivedNoteForSync,是否产生 MutationEntry。
- 检查是否走了
-
症状:UI 一改就触发分层守卫测试失败。
- 检查 UI 页面是否直接引用了底层 Provider,改为通过
NoteService。
- 检查 UI 页面是否直接引用了底层 Provider,改为通过
-
症状:同步频繁并发、网络抖动时反复请求。
- 检查是否破坏了
SyncEngine的 single-flight(_isPulling+_hasPendingKick)。
- 检查是否破坏了
10. 变更维护要求
当以下文件发生实质行为变化时,必须同步更新本 Skill:
mobile/lib/service/note_service.dartmobile/lib/sync/local_write_coordinator.dartmobile/lib/sync/sync_engine.dartmobile/lib/sync/pull_coordinator.dartmobile/lib/sync/push_coordinator.dartmobile/lib/sync/note_sync_payload_mapper.dartmobile/lib/sync/resource_fetch_scheduler.dartmobile/test/sync/*.dart
更新要求:
- 同步更新“业务目标”和“禁令”章节。
- 同步更新“字段合并规则”。
- 同步更新“必跑测试”章节,保持与当前守卫策略一致。
Version History
- c1dc382 Current 2026-08-20 13:18


