数据备份与恢复

WesCraft 的数据安全架构基于 wesgine 的三层 SQLite 韧性模型,支持自动降级、快照验证和完整的 Cell 导出/导入。

数据目录结构

WesCraft 的所有数据存储在 XDG 规范目录下:

$XDG_DATA_HOME/wescraft/
│  # macOS: ~/Library/Application Support/wescraft/
│  # Linux: ~/.local/share/wescraft/
│
├── hypervisor.db                  # Hypervisor 层:Cell 注册表
│
├── cells/personal/                # Cell 数据(个人版)
│   ├── meta.db                    # Layer 1: Cell 元数据
│   ├── sessions.db                # Layer 2: 会话与记忆
│   ├── state.db                   # Layer 3: 运行时状态(Traces/Observe)
│   ├── knowledge/                 # 知识库文件
│   ├── skills/                    # Tier C 技能包
│   ├── .scratch/                  # 临时计算域(Run 结束后 GC)
│   └── .cell.lock                 # 进程排他锁
│
├── wescraft.db                    # 应用层数据
│   # 页面、Block、收集箱、任务、文件索引等
│   # 12+ 表 + 2 FTS5 虚拟表 + 触发器
│
└── db/wescode_auth.db             # 登录 session(跨 Cell 共享)

三层 SQLite 架构

层数据库内容损坏影响范围
Layer 1meta.dbCell 元数据、Agent 配置不影响 sessions/state
Layer 2sessions.db会话、消息、记忆不影响 meta/state
Layer 3state.db运行时追踪、观测数据不影响 meta/sessions

INV-RESIL-03:单层损坏不扩散。sessions.db 损坏不影响 memory/observe;state.db 损坏不影响 sessions。

Cell Export / Import

导出整个 Cell

# 通过 API 导出
GET /cells/{cellID}/export
→ 返回 tar.gz 流

# 通过管理端点导出
GET /admin/cells/{cellID}/export
→ 返回 tar.gz 流

导出包含:

内容包含说明
meta.db✅Cell 元数据
sessions.db✅会话和记忆
state.db✅运行时状态
workspace/✅(可选跳过)工作区文件
knowledge/✅知识库
skills/✅技能包
.scratch/❌永不包含

导入 Cell

# 从 tar.gz 恢复
POST /admin/cells/import
Content-Type: application/gzip
Body: <tar.gz 文件>
Query: ?overwrite=1  # 可选:覆盖已存在的 Cell

使用场景

数据库安全

进程排他锁

INV-RESIL-04:同一 Cell 同一时刻只有一个写入者。通过 flock(.cell.lock) 实现:

Cell 目录/
└── .cell.lock    # 进程级排他锁

如果遇到 ErrCellLocked 错误,说明有其他进程正在使用该 Cell。

mmap 禁用

INV-RESIL-08:PRAGMA mmap_size=0 消除整类 SQLITE_IOERR_MMAP 故障。WesCraft 的所有 SQLite 连接都禁用了 mmap。

VACUUM 安全

INV-RESIL-09:VACUUM 中断等于全损。WesCraft 不执行自动 VACUUM,只在 SQLiteBackup(VACUUM INTO)中使用。

快照验证

PRAGMA quick_check

INV-RESIL-05:每次快照后立即执行 PRAGMA quick_check,损坏的快照直接丢弃:

-- 快照验证流程
VACUUM INTO '/path/to/snapshot.db'  -- 原子快照
PRAGMA quick_check                   -- 完整性验证
-- 验证失败 → 丢弃快照 + 告警

SQLiteBackup

使用 VACUUM INTO 实现原子快照,是唯一安全的备份方式。

禁止的备份方式:

方式问题
cp *.db忽略 -wal / -shm,数据不一致
只拷单个 DBCell 有 meta/sessions/state 三个 DB
VACUUM中断等于全损

损坏恢复

Boot 永远成功

INV-RESIL-01:无论何种数据损坏,Boot 都返回 nil error。降级是合法状态:

启动 → 检测到损坏 → 降级启动(标记 Degraded)→ 新请求正常处理

唯一的 boot 失败是 ErrCellLocked(进程竞争,非数据问题)。

INV-RESIL-02

Runtime().Run() 永远可用。降级只影响历史数据访问,不影响新请求处理。

损坏文件保留

INV-RESIL-07:损坏的 DB 文件归档到 corrupt/ 目录供诊断,不直接删除:

cells/personal/
├── meta.db           # 当前(可能是新建的)
├── sessions.db
├── state.db
└── corrupt/
    ├── meta.db.20260914_200000    # 损坏的原始文件
    └── sessions.db.20260901_...

Journal 只追加

INV-RESIL-06:Journal 文件没有 seek/truncate,只有 O_APPEND 写入。保证故障恢复数据的完整性。

迁移管理

INV-MIGRATE-01 机制

wescraft.db 的每一次 schema 变更对应一个 MigrationStep:

// internal/store/appdb_migrations.go
type MigrationStep struct {
    Version int
    Name    string
    Migrate func(tx *sql.Tx) error
}

Boot 时执行流程:

1. 读取 PRAGMA user_version
2. 按序执行未应用的步骤
3. 每步一个事务:DDL + PRAGMA user_version = N + commit
4. 全部成功 → DB 可用

降级策略

迁移步骤失败
  → 关闭 DB
  → 归档旧文件为 .migration-failed
  → 清除 -wal / -shm
  → 重新打开全新 DB
  → 再次执行完整迁移链
  → 第二次失败 → fatal error

代价:丢失页面、数据库、采集箱、任务、文件索引等数据。但远好过启动崩溃——用户可以重新配置。

wescraft.db 迁移

当前 V1 迁移包含:

内容数量
业务表12+
FTS5 虚拟表2
触发器若干
索引若干

RebuildFTS:每次 boot 时执行 FTS5 重建安全网,确保全文搜索索引与数据一致。

迁移与幂等

INV-RESIL-10:所有迁移全幂等。任何迁移重跑 N 次结果一致。FTS5 虚拟表使用 sqlite_master 存在性检查(部分 SQLite 构建不支持 CREATE VIRTUAL TABLE IF NOT EXISTS)。

备份建议

定期备份

# 方式一:Cell Export(推荐)
curl -o backup-$(date +%Y%m%d).tar.gz \
  http://localhost:3100/admin/cells/personal/export

# 方式二:文件级备份(注意三件套)
# 必须同时备份 .db + .db-wal + .db-shm
cp -a ~/Library/Application\ Support/wescraft/ \
  ~/Backups/wescraft-$(date +%Y%m%d)/

备份清单

文件必须备份说明
hypervisor.db✅Cell 注册信息
cells/personal/meta.db✅Cell 元数据
cells/personal/sessions.db✅会话和记忆
cells/personal/state.db⚠️可重建但包含历史追踪
wescraft.db✅应用层核心数据
cells/personal/knowledge/✅知识库文件
cells/personal/skills/⚠️可重装
config.yaml✅用户配置

恢复流程

  1. 停止 WesCraft
  2. 替换数据目录下的文件
  3. 启动 WesCraft
  4. 系统自动检测数据状态
  5. 必要时执行迁移或降级启动

注意事项