feat: add pocketbase sqlite exporter

This commit is contained in:
Codex
2026-06-30 09:30:00 +08:00
parent 959e612211
commit 2510d736a4
10 changed files with 841 additions and 11 deletions

View File

@@ -74,7 +74,11 @@
3. 真实导入 dry-run
- 从 PocketBase 导出现有用户、题库、单词、知识手册、分数线、订单、权益数据。
- 已补 `npm run pb:import:dry-run` 静态迁移报告工具、`--profile=production` 生产迁移门禁、关键集合/关键字段覆盖率检查、strict warning 门禁测试和真实数据迁移验收 runbook拿到真实导出后先跑 `npm run pb:import:dry-run -- --profile=production --json --fail-on-warnings`,再跑 `pb:import:json``pb:import:validate` 和业务抽样
- 已补 `npm run pb:export:sqlite` 只读 SQLite 导出工具,默认从 `F:\project\参考\旧题库数据库文件\data.db` 导出到 `.gitignore` 覆盖的 `pb_export/`,并生成 `sqlite-export-manifest.json``storage-manifest.json` 和脱敏统计
- 已补 `npm run pb:import:dry-run` 静态迁移报告工具、`--profile=production` 生产迁移门禁、关键集合/关键字段覆盖率检查、strict warning 门禁测试和真实数据迁移验收 runbook真实 SQLite 已导出 58 个业务 collection、248555 条记录,并跑过 production dry-run。
- 当前真实 dry-run 剩余 blocker30 个订单缺 `userId`,其中 7 个 paid22 个知识手册章节缺 `subjectId`。正式导入前必须补自动修复/隔离 mapper 和人工复核报告。
- 当前真实 dry-run 剩余 mapper gap`user_answer_records` 85442 条、`mock_exam_configs` 48 条、`referral_qrcodes` 79 条、`commission_settings` 1 条。它们分别对应学习历史/错题归因、全真模拟蓝图、推广码/小程序码、分佣设置,后续要进入标准化导入。
- 处理完 blocker 后再跑 `npm run pb:import:dry-run -- --profile=production --json --fail-on-warnings`,再跑 `pb:import:json``pb:import:validate` 和业务抽样。
- 对题目 JSON、单词、知识手册、分数线、视频走后端 preview/import API 做二次验证。
4. 部署配置

View File

@@ -56,7 +56,7 @@ F:\project\参考\旧题库数据库文件
storage/
```
`data.db``auxiliary.db` 必须按只读源处理,不能直接在旧库上执行修复 SQL。后续应由本地转换脚本把 PocketBase SQLite 集合导出为规范 JSON再进入下面的 dry-run/import 管线;`storage/` 中的附件、题图、PDF、视频封面等资源同步生成资源迁移清单,最终进入 `content_assets` 和对象存储,不允许把旧本地路径或长效 URL 直接写给前端。
`data.db``auxiliary.db` 必须按只读源处理,不能直接在旧库上执行修复 SQL。当前已补 `npm run pb:export:sqlite`,会用只读 SQLite 连接把 PocketBase collection 导出为规范 JSON再进入下面的 dry-run/import 管线;`storage/` 中的附件、题图、PDF、视频封面等资源同步生成资源迁移清单,最终进入 `content_assets` 和对象存储,不允许把旧本地路径或长效 URL 直接写给前端。
把 PocketBase 导出的集合 JSON 放到仓库根目录:
@@ -93,20 +93,61 @@ $env:PB_EXPORT_DIR="F:\migration\pb_export_20260630"
npm run pb:import:dry-run
```
如果输入源仍是 SQLite而不是 JSON 目录,下一阶段需要先补 `scripts/import-pocketbase` 的 SQLite 只读导出命令,建议输出到仓库外或 `.gitignore` 覆盖的 `pb_export/`
如果输入源仍是 SQLite而不是 JSON 目录,先执行 `scripts/import-pocketbase` 的 SQLite 只读导出命令,建议输出到仓库外或 `.gitignore` 覆盖的 `pb_export/`
```powershell
$env:PB_SQLITE_DIR="F:\project\参考\旧题库数据库文件"
$env:PB_EXPORT_DIR="F:\project\pb_export"
# 规划命令npm run pb:export:sqlite
npm run pb:export:sqlite
```
导出脚本要求
导出脚本行为
- 使用只读 SQLite 连接,禁止修改 `data.db``auxiliary.db``storage/`
- 每个 PocketBase collection 输出一个 JSON 文件,并保留旧 `id``created``updated`、relation 字段和文件字段。
- `users`、订单、支付、openid/unionid、手机号等敏感字段默认脱敏写 dry-run 报告;正式导入只在后端 mapper 中进入受控身份/订单/审计表
- 资源文件字段只输出相对路径、hash、size、mime 和旧 collection/record/file 三元组,后续由对象存储迁移步骤转为 `content_assets`
- `password``tokenKey``secret``wechatSessionKey`、短信验证码等密钥类字段默认不会写入普通 JSON`openid/unionid` 默认也会移除,只在 `sqlite-export-manifest.json` 里记录字段和数量。后续如果确实要迁移第三方登录身份,必须走单独的加密身份迁移链路,不混入普通 `pb_export`
- 手机号、邮箱、业务旧 ID、订单、题目、学习记录等迁移必需字段会保留用于自营 ToC 租户的数据归属和售后追溯
- 资源清单输出到 `storage-manifest.json`包含相对路径、hash、size、mime 和旧 collection/record/file 三元组,后续由对象存储迁移步骤转为 `content_assets`
- `auxiliary.db` 默认只写 `_logs` 的数量和 level 摘要,不导出完整日志正文,避免把 UA、请求参数或历史 token 放进迁移数据包。
可选环境变量:
```powershell
$env:PB_SQLITE_DATA_DB="F:\project\参考\旧题库数据库文件\data.db"
$env:PB_SQLITE_AUX_DB="F:\project\参考\旧题库数据库文件\auxiliary.db"
$env:PB_SQLITE_STORAGE_DIR="F:\project\参考\旧题库数据库文件\storage"
$env:PB_SQLITE_COLLECTIONS="users,regions,subjects,categories,questions"
$env:PB_SQLITE_BATCH_SIZE="2000"
```
正常迁移不要设置 `PB_SQLITE_INCLUDE_SENSITIVE_IDENTITIES=true`。这个开关只允许在加密迁移工作区临时使用,并且导出的身份文件不得提交 Git。
当前真实库只读导出基线:
```text
data.db: 58 个业务 collection248555 条记录
questions: 74102
users: 3670
orders: 636
user_answer_records: 85442
vocabulary: 3500
handbook_entries: 2676
storage-manifest: 9 个原始资源文件
auxiliary.db: _logs 121715 条,仅摘要
```
最近一次 production dry-run 仍有 2 个 blocker需要在正式导入前处理
- `orders.userId` 覆盖率 95.3%30 个订单缺用户,其中 7 个为已支付订单。处理策略应优先从支付通知、手机号、订单号或人工售后记录找回用户;找不回的已支付订单必须进入人工异常台账,不允许静默开权益。
- `handbook_chapters.subjectId` 覆盖率 94.4%22 个章节缺所属手册。处理策略应按章节标题和条目归属归并到正确 `handbook_subjects`,无法归并的放入迁移隔离手册并标记待人工复核。
production dry-run 还有这些 warning属于后续 mapper 或运营处理项:
- `user_answer_records` 85442 条尚未规范化到新练习历史/答题记录模型。
- `mock_exam_configs` 48 条尚未规范化到 `practice_blueprints`
- `referral_qrcodes` 79 条尚未规范化到新推广码/小程序码模型。
- `commission_settings` 1 条需要迁移到新分佣设置。
- `dashboard_cache`、空 `customer_messages/smscodes/tenant_config` 可不作为正式数据源,必要时只保留审计摘要。
## 阶段 1静态 Dry-Run
@@ -150,6 +191,7 @@ dry-run 会检查:
- 用户、题目、订单、SVIP、激活码、单词、手册、分数线、视频等业务数量。
- `production` profile 会额外检查生产迁移必需集合:`users``questions``subjects``categories``orders``svip_plans``codes``vocabulary_units``vocabulary``handbook_subjects``handbook_chapters``handbook_entries`
- `migrationReadiness.criticalFieldCoverage` 会统计关键字段覆盖率,例如 `users.phone``questions.subjectId/categoryId/content``orders.userId/planId/status``codes.code`、单词和手册的归属字段;生产模式下低于阈值会变成 blocker。
- 对 SQLite 导出,`questions.categoryId` 会把 `nodeId` 视为新架构有效归属,`vocabulary.unitId` 会兼容旧字段 `unit`
准入标准: