# 用户数据备份设计(以导出/迁移为核心) ## 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--/ manifest.json data/ user.json profile.json timeline.json posts.json comments.json media-assets.json media-refs.json ...(其他用户归属资源) files/ ``` ### 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` 与文件完整性) --- 该设计聚焦“用户文件和数据可迁移”,优先保证格式稳定、数据完整与安全边界,便于后续演进到导入能力与跨环境迁移能力。