Files
knowledge-governance/internal/platform/postgres/migrations/000045_backup_schedule.up.sql
T
姚章浩 3f603aa293 feat(backup): 系统设置里的存储与备份——定时时间与储存天数可配、下发到目标主机 cron
需求:整库逻辑备份做定时,但要在「系统设置 → 存储与备份」里设置定时时间与储存天数。

后端
- migration 000045 backup_schedule(单行:enabled/schedule_time/retention_days/retention_months/
  last_applied_*),store + 领域校验(HH:MM、1~365 天、0~24 月,非法值 400 且不落库不下发)
- internal/backuphost:通过 ssh 在目标主机上读回/下发计划并立即备份(未接线时 Available=false,
  页面降级提示;主机侧错误带输出回传)。最近一次只认有 MANIFEST.json 的完整目录,跳 *.incomplete
- 接口 GET/PUT /api/v1/backup-schedule、GET …/host、POST …/apply、POST …/run;
  写操作经 classifyRole 限管理员;run 为异步 202 + 在途单飞(http 写超时 30s,备份约 35s)
- openapi.yaml 补齐 5 条路由(契约测试要求每条都写 400/500)

主机侧
- scripts/install_backup_schedule.sh(幂等):写 /etc/knowledge-governance/backup-schedule.env 与
  /etc/cron.d/kb-logical-backup,参数校验,--show/--disable,最后一行 SCHEDULE_APPLIED 供平台核对
- logical-backup.sh 从该文件读保留策略;失败或被中断把目录改名 *.incomplete,不留'像成功'的半成品
- install --show 只回显计划行(原先把 SHELL=/PATH= 当计划显示)

前端
- web/src/backupSchedule.ts(严格解析:缺计划字段即报错,不把默认值伪装成设置)
- BackupScheduleSection:容器 + 纯视图(管理员表单/只读、已一致/待下发、在途轮询)

运行前提(已落实):运行镜像加 openssh-client,且容器 uid 1000 在 /etc/passwd 有名字
(否则 ssh 报 No user exists for uid 1000);凭据只读挂载 secrets/backup-host(git 忽略)

实测:主机 cron 每天 03:30 / 保留 7 天 / 每月 3 份;立即备份一次 34 秒 / 742.7 MiB / 失败 0;
Go 与前端测试全绿(170 vitest)。
2026-10-09 13:50:23 +08:00

20 lines
1.1 KiB
SQL

-- 整库逻辑备份(pg_dump 目录格式,scripts/logical-backup.sh)的定时计划由平台
-- 「系统设置 → 存储与备份」管理:定时时间与保留策略存在这里,下发后在**目标库所在主机**
-- 上落成 /etc/cron.d 条目。备份必须在数据面主机本地执行(内网直连 RDS、内网写盘),
-- 平台只下发计划并读回结果,见 docs/PRODUCTION_BACKUP_RECOVERY.md。
--
-- 单行表:last_applied_* 记录最后一次成功下发的结果,供页面显示"当前主机上的计划"。
CREATE TABLE backup_schedule (
id TEXT PRIMARY KEY DEFAULT 'active' CHECK (id = 'active'),
enabled BOOLEAN NOT NULL DEFAULT FALSE,
schedule_time VARCHAR(5) NOT NULL DEFAULT '03:30',
retention_days INTEGER NOT NULL DEFAULT 7,
retention_months INTEGER NOT NULL DEFAULT 3,
last_applied_at TIMESTAMPTZ,
last_applied_summary TEXT NOT NULL DEFAULT '',
updated_by VARCHAR(64) NOT NULL DEFAULT '',
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
INSERT INTO backup_schedule(id, updated_by) VALUES('active', 'system:migration')
ON CONFLICT (id) DO NOTHING;