换基线:把「底座换代」做进后台(站点数据一行不动)
导出是「底座为底 + 只覆盖托管表」,所以底座必须是手机导出的包。底座跟着数据集走, 手机重新导出后想换代,以前只能整包重新导入成新数据集(站点补录的行、主题、备注都得重收拾)。 新动作 /admin/baseline(后台首页加入口)就是给同一份数据的底座换代用的。 三道闸,顺序不能挪: 1. 重合判据:新包里的到访 UUID 与站点侧带 UUID 的到访比。一条都对不上直接拒 (连 force 也不给过)——干跑只验结构,一份不相干的包照样导得出,但换下去站点 每行都在新底座里认不出身份,全按新行插到最大编号之后,真机上就是「这些到访 全变成新的」。重合率不到一半要显式确认;判据没过不当场报错了事:包已经收进 uploads,页面给一个「我确认,强制替换」按钮,不必重传几十 MB。 2. 干跑导出:底座缺表/缺实体编号在这步挡住,不会出现「换完了才发现导不出、 原来那份已经不知去哪」。 3. 旧底座留档 + 记档,换错了可一键回滚。 两个坑: - 留档名不能只用秒级时间戳。「替换后紧接着回滚」落在同一秒时,回滚那次 rename 会把 刚生成的留档覆盖掉,于是回滚回了个寂寞(TestRollbackBaselineRestoresPrevious 当场红)。 改用 baselineBackupName():20060102-150405 + 冲突自增。 - ensureBaseline 必须先看记档。只认 datasets.sha256(= 最初那份包)的话,底座一丢就静默 重建回旧包,上一次换基线白做且毫无提示。抽出 ensureBaselineTo(ctx, dsID, dst) 共用; 「重建」入口写临时文件再 rename,不做破坏性删除。 回归用例 7 条(internal/web/baseline_swap_test.go):成功路径断言「换底座前后导出包里 ZVISIT 的 UUID 集合逐条一致」——编号会换、身份不该换,谁在底座里没对上立刻亮; 记档优先重建带反证(清掉记档后同一条路必须走不通);部分重合需确认、完全对不上 force 也不给过、非包文件第一步就挡住、回滚还原且当前那份也留档、页面渲染到底。 验收:./scripts/verify.sh 全量 PASS=318 FAIL=0 SKIP=0。
This commit is contained in:
@@ -302,6 +302,15 @@ ALTER TABLE place_notes ADD COLUMN IF NOT EXISTS rond_note TEXT NOT NULL DEFAULT
|
||||
-- 需要把原始 .rondbackup 重新上传一次(即便内容相同也会补抓)。
|
||||
ALTER TABLE datasets ADD COLUMN IF NOT EXISTS coredata_meta JSONB;
|
||||
|
||||
-- 「换基线」的记档:底座库(baselines/<id>.sqlite)是哪一份包换出来的。
|
||||
-- 记着它有两个用处:① 底座文件丢了可以按 baseline_sha256 去 uploads 里找回同一份包重建
|
||||
-- (否则 ensureBaseline 只会退回 datasets.sha256,也就是最初那份旧包——底座会被悄悄换回去);
|
||||
-- ② 页面上能说清「现在这个底座来自哪个文件」。
|
||||
-- baseline_sha256 IS NULL = 从未换过底座,来源就是最初上传的原始包。
|
||||
ALTER TABLE datasets ADD COLUMN IF NOT EXISTS baseline_name TEXT;
|
||||
ALTER TABLE datasets ADD COLUMN IF NOT EXISTS baseline_sha256 CHAR(64);
|
||||
ALTER TABLE datasets ADD COLUMN IF NOT EXISTS baseline_at TIMESTAMPTZ;
|
||||
|
||||
-- rond 原始行留档:每条实体在 Core Data 里的**完整一行**(含站点未映射的字段)
|
||||
-- 按 JSONB 存下来。有了它,导出不再依赖基线库去补那些字段——
|
||||
-- 基线即便丢了也能精确还原,站点侧也具备完整数据,不会因为映射范围窄而漏字段。
|
||||
|
||||
Reference in New Issue
Block a user