Browse Source

docs: add user data backup design for export and migration

Define a user-centric backup/export design that prioritizes file and data portability, with masking policy, manifest checksums, and async task flow.

Made-with: Cursor
main
npmrun 2 weeks ago
parent
commit
026434b036
  1. 198
      docs/superpowers/specs/2026-04-24-user-data-backup-design.md

198
docs/superpowers/specs/2026-04-24-user-data-backup-design.md

@ -0,0 +1,198 @@
# 用户数据备份设计(以导出/迁移为核心)
## 1. 背景与目标
本设计面向 `person-panel` 的“用户数据可携带性”场景,核心目标是让用户可以导出自己的文件与业务数据,并可用于后续迁移或恢复到兼容系统。
已确认目标与约束:
- 目标类型:用户可导出/迁移数据(非灾备优先)
- 交付形态:目录结构 + 清单 JSON
- 范围:用户全量业务数据(排除敏感凭据)
- 敏感策略:导出时可选原始/脱敏,默认脱敏
## 2. 设计原则
- 可迁移优先:导出格式稳定、可版本化、可校验
- 文件与数据一体:业务 JSON 与媒体文件同时导出
- 安全默认:默认脱敏,且永不导出高敏字段
- 一致性可解释:导出基于固定时间截点,避免数据漂移
- 演进兼容:通过 `schemaVersion` 管理未来格式升级
## 3. 总体架构
采用“异步导出任务 + 标准导出包”模式。
### 3.1 API 入口
- `POST /api/me/export/request`
- 创建导出任务
- 参数:`maskPolicy`(`masked` | `raw`,默认 `masked`
- `GET /api/me/export/tasks`
- 查询当前用户导出任务列表与状态
- `GET /api/me/export/tasks/:id/download`
- 下载导出结果(目录打包或直接目录挂载下载,按部署实现)
### 3.2 任务状态机
- `queued`:任务已创建,待执行
- `running`:导出中
- `succeeded`:导出完成,可下载
- `failed`:导出失败,包含错误信息
- `expired`:产物过期被清理
### 3.3 一致性模型
任务进入 `running` 时写入 `exportCutoffAt`。所有 SQL 查询统一加上时间边界(可按表字段映射),保证导出结果在逻辑上对应同一时间点快照。
## 4. 导出包规范(v1)
### 4.1 目录结构
```text
export-<userId>-<taskId>/
manifest.json
data/
user.json
profile.json
timeline.json
posts.json
comments.json
media-assets.json
media-refs.json
...(其他用户归属资源)
files/
<storageKey 或分层路径>
```
### 4.2 manifest.json(关键字段)
- `schemaVersion`: `1`
- `exportedAt`: 导出完成时间(ISO8601 UTC)
- `exportCutoffAt`: 截点时间(ISO8601 UTC)
- `userId`: 用户 ID
- `maskPolicy`: `masked``raw`
- `stats`: 各资源条数、文件数、总字节数
- `checksums`:
- `data`: 每个 JSON 文件的 SHA256
- `files`: 每个文件的 SHA256 + 相对路径
### 4.3 编码与类型规范
- JSON 使用 UTF-8
- 时间统一 ISO8601(UTC)
- 枚举保持稳定字符串值
- 布尔/数值不做字符串化
## 5. 数据边界与脱敏规则
### 5.1 导出范围(全量用户业务)
按“该用户可归属”原则导出:
- 用户基础信息(非敏感)
- 个人资料与配置
- 时间线、文章、评论等内容
- 媒体元数据(`mediaAssets`)与引用关系(`mediaRefs`)
- 其他用户域业务资源(按服务注册表补齐)
### 5.2 永不导出字段
无论 `maskPolicy` 取值,以下字段均不导出:
- 密码哈希与密码重置类 token
- 登录会话 token / 刷新 token
- API 密钥、签名密钥、内部凭据
- 不可归属该用户的他人敏感数据
### 5.3 可配置脱敏字段
导出时支持策略切换:
- `masked`(默认):
- 邮箱:保留前后缀,隐藏中间
- 手机号:保留前 3 后 2
- IP:保留网段,隐藏主机位
- 设备标识:部分掩码
- `raw`
- 输出原值,但仍遵循“永不导出字段”排除规则
## 6. 文件导出策略(重点)
### 6.1 文件来源
从用户关联的 `mediaAssets` 读取 `storageKey`,在媒体目录(当前项目已有公开上传目录)中查找实体文件,复制到导出包 `files/` 下。
### 6.2 文件-数据关联
- `data/media-assets.json` 记录资产元数据与 `storageKey`
- `data/media-refs.json` 记录 `assetId` 与业务对象关联
- 导入方据此可重建资源引用关系
### 6.3 完整性校验
每个导出文件生成 SHA256 写入 `manifest.checksums.files`。导入前可进行全量核验,防止传输损坏或篡改。
## 7. 执行流程与失败恢复
### 7.1 执行步骤
1. 创建任务(`queued`)
2. Worker 抢占任务并置 `running`
3. 记录 `exportCutoffAt`
4. 分页导出各资源 JSON 到 `data/`
5. 收集并复制媒体文件到 `files/`
6. 计算校验并生成 `manifest.json`
7. 置 `succeeded` 并返回下载能力
### 7.2 失败策略
- 任一步异常置 `failed`,记录 `errorCode/errorMessage`
- 任务目录按 `taskId` 隔离,失败不会污染其他任务
- 用户可重试,创建新任务而非复用失败产物
## 8. 安全与性能控制
### 8.1 安全控制
- 仅允许用户导出/下载自己的任务
- 下载链接短时有效(建议 10 分钟)
- 导出产物过期清理(建议 24~72 小时)
- 保留审计日志(发起人、时间、策略、结果)
### 8.2 性能控制
- 大表分页读取,避免内存峰值过高
- 文件复制并发数限流,避免 IO 打满
- 单用户同一时刻仅允许 1 个导出任务
## 9. 测试与验收标准
### 9.1 测试建议
- 单元测试:
- 字段白/黑名单过滤
- `masked`/`raw` 脱敏策略
- `manifest` 校验信息生成
- 集成测试:
- 用户全量导出流程(含媒体文件)
- 导出期间数据变动下的一致性行为
- 权限边界(越权访问导出任务)
### 9.2 验收标准
- 导出包包含该用户全量业务数据与关联文件
- 永不导出字段在任何策略下都不存在
- `masked``raw` 行为符合预期
- `manifest` 校验通过,引用关系可重建
- 中等数据量用户导出耗时在可接受范围
## 10. 分阶段落地计划(建议)
- Phase 1:后端导出任务 + 导出包生成 + 基础下载
- Phase 2:前端“数据导出中心”页面(发起、进度、下载、失败重试)
- Phase 3:导入校验工具(离线校验 `manifest` 与文件完整性)
---
该设计聚焦“用户文件和数据可迁移”,优先保证格式稳定、数据完整与安全边界,便于后续演进到导入能力与跨环境迁移能力。
Loading…
Cancel
Save