Skip to content

Comments

feat(backup): add v2 backup system refactor plan document#12659

Draft
GeorgeDong32 wants to merge 3 commits intov2from
refactor/v2/backup-system
Draft

feat(backup): add v2 backup system refactor plan document#12659
GeorgeDong32 wants to merge 3 commits intov2from
refactor/v2/backup-system

Conversation

@GeorgeDong32
Copy link
Collaborator

@GeorgeDong32 GeorgeDong32 commented Jan 30, 2026

Cherry Studio 备份系统重构设计文档 v2.0

状态:Draft
关联:Plan Document

目录


背景与目标

现有备份系统(V1)存在以下问题:

  1. 内存限制:使用 JSON.stringify 整体序列化,数据量超过 512MB 时触发 V8 内存限制导致崩溃;
  2. 架构陈旧:依赖已弃用的 BackupManager 和文件复制机制,不兼容 V2 的 SQLite 架构;
  3. 缺乏增量:仅支持全量备份,随着数据增长,备份时间和体积不可控;
  4. Base64 问题:图片以 Base64 内联存储在 JSON 中,极易导致解析失败;
  5. 不支持合并:缺乏对话合并策略,多设备数据同步困难。

新版系统要实现:

  • 流式处理:采用 JSONL + Stream,突破内存限制,支持 GB 级数据备份;
  • V2 原生:基于 DataApiService 和 Drizzle ORM,与新架构无缝集成;
  • 增量备份:基于时间戳检测变更,显著减少备份体积和时间;
  • 附件分离:Base64 图片分离存储为二进制文件,确保稳定性;
  • 跨平台可靠:统一路径分隔符、编码和时间戳格式;
  • 安全加密:支持压缩后 AES-256-GCM 加密。

核心原则

  1. 内存友好

    • 严禁全量加载:所有大数据操作必须流式处理(Generator / Stream);
    • 分批读写:数据库查询采用 Cursor/Offset 分页。
  2. 事务原子性

    • 导入/恢复过程必须在数据库事务中执行;
    • 失败自动回滚,确保数据一致性;
    • 文件写入采用“写临时文件 -> 原子重命名”策略。
  3. 向后兼容

    • 必须支持导入 V1 (localStorage/indexedDB) 格式的备份文件;
    • 提供版本迁移器 (VersionMigrator) 自动升级数据结构。

架构分层

┌──────────────────────────────────────────────┐
│                  Backup System V2            │
├──────────────────────────────────────────────┤
│ 📋 Shared Types (packages/shared/backup)     │
│   - types.ts: BackupManifest, BackupDomain   │
│   - options.ts: BackupOptions, Strategy      │
│   - tree.ts: MessageTreeRef (结构引用)       │
│                                              │
│ 🎮 Orchestrator (src/main/services/backup)   │
│   - BackupOrchestrator: 流程编排             │
│   - StreamSerializer/Parser: 流处理核心      │
│   - VersionMigrator: 版本兼容                │
│                                              │
│ 🔌 Exporters (Data -> JSONL)                 │
│   - TopicExporter: 对话树流式导出            │
│   - FileExporter: 附件分离与去重             │
│   - PreferenceExporter: 偏好设置             │
│                                              │
│ 📥 Importers (JSONL -> Data)                 │
│   - TopicImporter: ID 映射与树重建           │
│   - ConflictResolver: 冲突解决策略           │
│                                              │
│ 🔒 Security & Utils                          │
│   - BackupEncryptor: AES-256-GCM             │
│   - BackupValidator: xxHash 校验             │
└──────────────────────────────────────────────┘

关键实现

1. 导出格式 (ZIP + JSONL)

采用混合格式:

  • manifest.json: 元数据与统计信息
  • topics/messages/chunk_*.jsonl: 消息数据分片(流式写入)
  • files/blobs/{hash}.bin: 附件文件(去重存储)
  • tree_refs.jsonl: 轻量级树结构引用,用于快速重建与冲突检测

2. 流式序列化

// Generator 模式分批读取,结合 Transform 流写入
async function* streamMessages(db, topicIds) {
  // ...分批查询数据库...
  yield message;
}
pipeline(streamMessages(), jsonlStringifier, fileStream);

3. Base64 图片分离

  • 导出时:检测 ImageBlock -> 提取 Base64 -> 计算 Hash -> 存入 files/blobs/ -> JSON 中替换为 {"image_ref": "hash"}
  • 导入时:读取 image_ref -> 从 ZIP 中查找二进制文件 -> 还原

4. 增量备份

基于 updatedAt 时间戳:

  • 记录上次备份时间;
  • 查询 updatedAt > lastBackupTime 的记录;
  • 生成仅包含变更数据的增量包 (changes/ 目录)。

数据流

导出流程

  1. BackupOrchestrator 初始化,写入 manifest.json (pending 状态);
  2. 启动 archiver ZIP 流;
  3. 并行/串行调用各 Exporter
    • TopicExporter: 流式读取 DB -> 写入 messages.jsonl -> 提取图片 -> FileExporter
  4. 完成所有流,更新 manifest.json (stats, checksum),finalize ZIP;
  5. (可选) 调用 BackupEncryptor 进行加密。

导入流程

  1. BackupValidator 校验文件完整性 (xxHash);
  2. 开启数据库事务 SAVEPOINT
  3. VersionMigrator 检查并适配版本;
  4. 按依赖顺序调用 Importer
    • Preference -> Assistant -> Topic (处理 ID 冲突) -> File
  5. 提交事务或回滚。

迁移与兼容性

  • V1 兼容: LegacyImporter 专门处理 V1 格式 (JSON dump),将其转换为 V2 内存对象后通过 V2 写入逻辑入库。
  • ID 冲突: 提供 SKIP, OVERWRITE, RENAME 策略,RENAME 模式下自动维护 ID Map 更新引用。

执行计划

  • Phase 1: 基础设施 (P0) - 类型定义、流处理工具、目录结构
  • Phase 2: 导出功能 (P0) - 核心 Exporters、ZIP 生成、附件分离
  • Phase 3: 导入功能 (P0) - 核心 Importers、事务控制、V1 兼容
  • Phase 4: 高级特性 (P1) - 增量备份、加密、跨平台适配
  • Phase 5: 验证交付 - 压力测试、集成测试

Add GroupsExporter and PreferencesExporter to the backup service.

- Implement GroupsExporter to stream group rows into a JSONL file.
  - Count groups, create domain directory, write groups ordered by
    createdAt (desc), compute file checksum and sizes, and return export
    metadata.
  - Use a streaming JsonlStringifier piped to a write stream to avoid
    buffering all data in memory and update export progress as rows are
    processed.

- Implement PreferencesExporter skeleton with filtering rules.
  - Fetch preferences and filter out sensitive and machine-specific
    keys using regex patterns and a key whitelist to avoid writing
    secrets (tokens, passwords, API keys, credentials, auth).
  - Prepare grouped preference data structure and set domain progress.
  - Ensure preferences are exported in a structured JSON format (file
    creation and finalization handled in exporter flow).

Rationale: add domain-specific backup exporters to persist groups and
non-sensitive preferences reliably and efficiently, with progress
reporting and integrity checks.
@DeJeune DeJeune added this to the v2.0.0 milestone Feb 10, 2026
@DeJeune DeJeune added the v2 label Feb 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants