Skip to content

数据同步方案

本文档是 系统设计主文档 的子文档,详细描述Git同步、HTTP同步和P2P移动端同步的设计。


四、数据同步方案

4.1 Git-based同步架构

为什么选择Git:

  • ✅ 去中心化: 无需中央服务器
  • ✅ 版本控制: 完整历史记录,可回滚
  • ✅ 冲突解决: 成熟的merge算法
  • ✅ 增量同步: 只传输变化部分
  • ✅ 加密友好: 支持透明加密
  • ✅ 生态成熟: 众多托管选择 (GitHub、GitLab、自托管)

4.2 仓库结构

my-knowledge-base/ (Git仓库根目录)
├── .git/                  # Git元数据
├── .gitattributes         # Git LFS配置
├── .git-crypt/            # 加密配置 (如使用git-crypt)

├── knowledge/             # 知识文件目录
│   ├── notes/             # 笔记
│   │   ├── 2024-01-01-学习Go语言.md
│   │   └── 2024-01-02-分布式系统设计.md
│   ├── documents/         # 文档
│   │   └── 技术方案.pdf
│   ├── images/            # 图片
│   └── embeddings/        # 向量文件 (可选不加密)

├── social/                # 社交数据
│   ├── posts/             # 我的动态
│   ├── contacts/          # 联系人导出 (加密)
│   └── conversations/     # 聊天记录 (加密)

├── transactions/          # 交易数据
│   ├── listings/          # 交易列表
│   ├── contracts/         # 合约
│   └── evidence/          # 证据文件

├── databases/             # 数据库备份
│   ├── knowledge.db.enc   # 加密的SQLCipher数据库
│   ├── social.db.enc
│   └── transactions.db.enc

├── configs/               # 配置文件 (加密)
│   ├── llm_configs.json.enc
│   ├── sync_settings.json.enc
│   └── device_list.json.enc

└── .chainlesschain/       # 系统元数据
    ├── version            # 数据格式版本
    ├── device_id          # 设备唯一ID
    └── last_sync          # 最后同步时间戳

4.3 同步流程

首次克隆 (新设备):

1. 用户在新设备登录
2. 输入Git仓库地址 (HTTPS或SSH)
3. 输入仓库访问凭证 (用户名+密码/Token)
4. Git clone到本地
5. U盾/SIMKey解密数据库密钥
6. 解密数据库文件
7. 导入数据库到SQLCipher
8. 构建向量索引
9. 标记设备为已同步

增量同步 (双向):

移动端 → 云端:
1. 用户在手机上添加新笔记
2. 写入本地SQLCipher数据库
3. 保存文件到knowledge/目录
4. Git add + commit
5. 后台任务检测到变更
6. 通过移动网络git push到远程仓库
7. 推送成功后更新同步状态

云端 → PC端:
1. PC端定期 (每5分钟) 执行git fetch
2. 检测到远程有新commit
3. 执行git pull
4. 解密新文件
5. 更新SQLCipher数据库
6. 重建向量索引
7. 通知用户有新内容

冲突解决:

场景: 用户在手机和PC上同时编辑同一笔记

1. 手机和PC都commit到本地
2. 手机先push成功
3. PC尝试push,被拒绝 (non-fast-forward)
4. PC执行git pull --rebase
5. Git尝试自动合并:
   - 成功: 自动完成
   - 冲突: 生成冲突标记文件
6. 应用检测到冲突
7. 展示冲突内容给用户:
   <<<<<<< HEAD (PC版本)
   这是PC上的修改
   =======
   这是手机上的修改
   >>>>>>> remote (手机版本)
8. 用户手动选择保留哪个版本或合并
9. 解决后提交并push

4.4 托管选项

选项优点缺点适用场景
GitHub私有仓库免费,稳定,大空间数据在GitHub服务器数据已加密,信任GitHub
GitLab自托管完全控制,无限空间需要自己维护服务器技术能力强,隐私要求高
Gitea (轻量)资源占用少,易部署功能相对简单家庭服务器,NAS
Git + 加密云盘利用现有云存储需要手动同步已有大容量云盘
P2P Git无中心服务器设备需同时在线极致去中心化需求

推荐方案: GitHub私有仓库 + Git-crypt加密

  • 所有敏感数据用git-crypt透明加密
  • 只有拥有密钥的设备能解密
  • GitHub只看到加密后的乱码
  • 免费用户可建无限私有仓库

4.5 移动端与PC端P2P同步 ⭐新增 (v0.20.0)

4.5.1 架构设计

技术栈:

┌─────────────┐         WebSocket信令服务器         ┌─────────────┐
│  移动端App   │◄──────────────┬──────────────────►│  PC端应用    │
│ (uni-app)   │                │                    │  (Electron)  │
└─────────────┘                │                    └─────────────┘
      ▲                        │                           ▲
      │    WebRTC DataChannel  │                           │
      └────────────────────────┴───────────────────────────┘
                          P2P直连通讯

核心组件:

  • PC端:
    • mobile-bridge.js: 移动端桥接管理器 (499行)
    • device-pairing-handler.js: 设备配对处理器 (305行)
    • knowledge-sync-handler.js: 知识库同步处理器 (442行)
    • project-sync-handler.js: 项目同步处理器 (516行)
    • pc-status-handler.js: PC状态监控处理器 (388行)
  • 移动端:
    • device-pairing.js: 设备配对服务
    • knowledge-sync.js: 知识库同步服务
    • project-sync.js: 项目同步服务
    • pc-status.js: PC状态监控服务
  • 信令服务器:
    • signaling-server/index.js: WebSocket信令服务器 (492行)
    • 端口: 9003 (避免与其他服务冲突)
    • 支持离线消息队列 (24小时保留)

4.5.2 设备配对流程

方式一: PC端扫描移动端二维码

移动端操作流程:
1. 打开"设备配对"页面
2. 生成6位配对码和二维码
   - 格式: {"code":"123456","peerId":"mobile-peer-id"}
3. 等待PC端扫描 (5分钟有效期)

PC端操作流程:
1. 点击"扫描移动设备"按钮
2. 使用摄像头扫描二维码
3. 解析配对码和移动端Peer ID
4. 通过信令服务器建立WebRTC连接
5. 验证配对码
6. 完成配对,保存设备信息

方式二: 配对码手动输入

适用场景: PC端无摄像头或摄像头不可用
1. 移动端显示6位数字配对码
2. PC端手动输入配对码
3. 系统查询信令服务器获取移动端Peer ID
4. 建立WebRTC连接并验证

4.5.3 数据同步功能

知识库同步 (knowledge-sync-handler.js):

javascript
支持的操作:
- listNotes: 获取笔记列表 (支持分页、排序、文件夹筛选)
- getNote: 获取笔记详情 (完整Markdown内容)
- searchNotes: 全文搜索笔记
- getFolders: 获取文件夹树形结构
- getTags: 获取标签列表和统计
- 本地缓存策略: 减少重复请求

数据流向: PC SQLCipher → 序列化 → WebRTC → 移动端缓存

项目同步 (project-sync-handler.js):

javascript
支持的操作:
- listProjects: 获取项目列表
- getProject: 获取项目详情
- listProjectFiles: 获取项目文件列表 (树形结构)
- getFileContent: 读取文件内容
- getFileStats: 获取文件统计信息
- createProject: 创建新项目
- updateFile: 更新文件内容

特性:
- 支持大文件分块传输 (1MB chunks)
- 文件类型检测 (二进制/文本)
- 实时项目状态同步

PC状态监控 (pc-status-handler.js):

javascript
监控指标:
- CPU使用率、内存使用情况
- 磁盘空间、网络速度
- 活动应用程序列表
- AI服务状态 (LLM、向量数据库)
- 笔记/项目数量统计

更新频率:
- 基础指标: 每10秒
- AI服务状态: 每30秒
- 按需查询: 移动端随时请求

4.5.4 技术特点

P2P通信:

  • 使用WebRTC DataChannel进行端到端传输
  • 信令服务器仅用于连接建立,不传输数据
  • 支持NAT穿透 (STUN/TURN)
  • 离线消息队列: 移动端离线时缓存消息

安全性:

  • WebRTC内置DTLS加密 (类似HTTPS)
  • 配对码验证 (6位随机数字,5分钟有效)
  • 设备白名单机制
  • 每次连接重新协商密钥

性能优化:

  • 数据分块传输 (大文件1MB chunk)
  • 本地缓存策略 (减少重复请求)
  • 增量同步 (只传输变化部分)
  • 压缩传输 (可选)

容错机制:

  • 自动重连 (指数退避策略)
  • 请求超时处理 (30秒)
  • 错误重试机制
  • 连接状态监控

4.5.5 使用场景

场景一: 移动端查看知识库

1. 用户外出时想查看笔记
2. 移动端连接PC (通过信令服务器)
3. 请求笔记列表 (分页加载)
4. 点击查看详情 (从PC实时读取)
5. 本地缓存常用笔记 (离线可访问)

场景二: 移动端访问项目文件

1. 用户需要在手机上查看项目代码
2. 移动端连接PC
3. 浏览项目文件树
4. 选择文件查看内容
5. 支持搜索和筛选

场景三: 监控PC运行状态

1. 用户外出想了解PC端AI任务进展
2. 移动端连接PC
3. 实时查看CPU/内存/网络状态
4. 查看AI服务运行情况
5. 查看知识库和项目统计

4.5.6 部署和测试

信令服务器部署:

bash
cd signaling-server
npm install
node index.js  # 监听9003端口

# Docker部署
docker build -t chainlesschain-signaling .
docker run -d -p 9003:9003 chainlesschain-signaling

测试脚本:

bash
# 测试设备配对
node test-pairing.js

# 测试数据同步
node test-data-sync.js

# 测试移动端客户端
node test-mobile-client.js

# 测试PC端配对
node test-pc-pairing.js

相关文档:

  • MOBILE_PC_SYNC.md: 完整系统设计文档 (489行)
  • QUICKSTART_MOBILE_PC.md: 快速开始指南 (352行)
  • TEST_MOBILE_PC_INTEGRATION.md: 集成测试指南 (310行)

4.6 多目标同步抽象 ⭐新增 (v5.0.3.36+, Phase 3b/3c, 2026-05-06)

4.6.1 架构

之前同步是单目标硬编码(renderer 直接调 electronAPI.sync.incremental)。Phase 3b 引入 SyncProvider 抽象

┌─────────────────────────────────────────────────────────────┐
│ Renderer (V5/V6 desktop-app-vue / web-panel)                │
│                                                             │
│ syncScheduler                                               │
│ ├─ runOnce(force?)  ── 遍历 enabled providers 串行执行       │
│ ├─ start(intervalMin) / stop()  ── 全局周期 setInterval     │
│ ├─ runProviderOnce(id)  ── 单 provider 手动触发             │
│ └─ 持久化 (localStorage):                                   │
│      cc.sync.autoSync                                       │
│      cc.sync.intervalMin                                    │
│      cc.sync.providers.<id>.enabled                         │
│                                                             │
│ syncProviders/                                              │
│ ├─ backend.ts   → electronAPI.sync.incremental + sync.start │
│ ├─ git.ts       → electronAPI.git.sync (markdown + push)    │
│ ├─ p2p.ts       → electronAPI.p2p.startDeviceSync (fan-out) │
│ ├─ webdav.ts    → electronAPI.sync.webdav.run (Phase 3c)    │
│ ├─ mobile.ts    → placeholder (Phase 3d)                    │
│ └─ oss.ts       → placeholder (Phase 3c S3/OSS 跟进)        │
└─────────────────────────────────────────────────────────────┘

4.6.2 SyncProvider 接口

typescript
export interface SyncProvider {
  id: string                                  // localStorage key suffix
  name: string                                // 中文显示名
  description: string                         // 卡片副标题
  available: () => Promise<boolean> | boolean // IPC/能力是否就绪
  runOnce: () => Promise<SyncProviderResult>  // 单次同步
  configRoute?: string                        // 跳转配置子页(可选)
  placeholder?: boolean                       // true = "敬请期待"
}

interface SyncProviderResult {
  success: boolean
  error?: string
  detail?: string                             // 给 UI 显示的可读细节
}

4.6.3 web-shell parity(Phase 3b 适配 + Phase 3c WebDAV/Git)

web-shell 模式(默认 Phase 1.6)下 renderer 是 web-panel SPA,不能直接调 electronAPI。改用 WS topic 直连主进程:

WS topic主进程 handler用途
sync.statussync-status-handlers.js直接 raw SQL 查 cli_sync_state / cli_sync_conflicts 计数
sync.push / sync.pull同上调 sync-manager.js (ESM) pushResources/pullResources
sync.conflicts / sync.resolve同上列出 + 解决冲突(local/remote 两策略)
sync.webdav.{test,run,config-get,config-set,config-clear}sync-webdav-handlers.jsWebDAV 凭证 + 一轮同步
git.config-{get,set,clear}git-config-handlers.jsGit 仓库配置

为什么不用 ws.execute('sync …') 子进程:CLI 子进程会再开一份 better-sqlite3 连接,Windows + WAL 下与主进程抢锁失败 → "database disk image is malformed"。in-process WS handler 共用 main 已开的 db handle,零冲突。

4.6.4 schema 隔离(CLI v2 表 rename)

CLI v1 的 sync_state / sync_conflicts / sync_log 跟桌面 P2P sync 同名表撞了(不同 schema)。Phase 3c 后续修复:

  • CLI 表整体 RENAME 为 cli_sync_state / cli_sync_conflicts / cli_sync_log(首次启动一次性 ALTER)
  • handler 的 _safeCountQuery swallow "no such table" 返回 0(用户尚未同步过任何资源)

4.6.5 入口点

  • 桌面 V5/V6:托盘菜单 → 同步 → 同步设置… → /settings/sync
  • web-shell:托盘菜单 → 同步 → 同步设置… → /sync-settings(web-panel SPA route)
  • 手动单 provider:Settings 页 → 每个 provider 卡片 → "立即同步"按钮
  • 全局自动:开关 + 间隔输入框(1–1440 分钟)

4.6.6 后续

  • Phase 3c 待补:S3 / OSS provider(aws-sdk + 凭证加密)
  • Phase 3d 待补:Mobile provider 接 mobile-sync-manager.js
  • 托盘 autoSync checkbox 跟 renderer 状态的双向绑定(目前菜单展开时可能 stale 一次)

ChainlessChain 系统设计文档 — 面向开发者