删除、迁出、备份与恢复数据
目标读者:项目开发者与本地运营者。
当前为 0.4 Alpha 数据生命周期,原地升级 G4 当前数据;不要重复旧 Alpha reset。不恢复旧账号、旧 JWT 或 SDK v1/v2 队列。archived 仍是反馈处理状态。
开发者操作
项目有效 owner/admin 可以删除反馈、关闭项目;只有组织 owner 可以关闭组织及全部所属项目。在 Console 的反馈详情、项目概览/设置或组织设置中选择动作,逐字输入显示的目标 ID。服务端检查当前账号、session 和真实 membership。Project Key 不能读取、删除或迁出租户数据,system_admin 也没有跨租户特权。
确认后停止新的读取、上传和下载签名;关闭同时撤销对应 Key、清除作用域 membership。其他项目/组织和 G4 匿名历史引用保留。回执区分 pending、failed、completed,只有原请求账号可以查看;保留其 Console 链接,维护后刷新。超时表示尚未确认,应对同一目标重试。只有实际对象删除确认后才移除相关元数据。已下载副本无法收回,旧 signed URL 可能持续到原到期时间或对象实际删除。
任一当前项目成员都可选择“迁出项目数据”。完整 ZIP 包含有权查看的反馈、评论、实际附件及 manifest.json 文件大小/SHA-256 清单。Viewer 联系方式由服务端裁剪,不含账号记录、密码/hash、token、Project Key、邀请或 signed URL。上限为 1000 份报告和 128 MiB 未压缩数据;超限或不完整时整体失败。请私密保存下载物、核对清单,并在不再需要时删除副本。
保留与维护
反馈、评论和附件从报告 received_at 起精确保留 90 天,追加评论/附件和重试不续期。完整备份 7 天;去敏操作审计和已完成回执的请求人关联 180 天。SDK 本地仍独立保留 7 天。即使维护未运行,到期读取也会被拒绝。
从 Infra 执行 scripts/data-maintenance.sh --action inspect 获取部署 ID,后续显式指定同一 ID;没有 --apply 时为预演:
最小示例
./scripts/data-maintenance.sh --action cleanup --deployment-id "$deployment_id" --batch 50
./scripts/data-maintenance.sh --action cleanup --deployment-id "$deployment_id" --batch 50 --apply
./scripts/data-maintenance.sh --action reconcile --deployment-id "$deployment_id"
每次对象/报告预算为 1–100,另有独立有限批次处理到期与辅助记录;仍有 pending 时继续运行。失败退出码非零,引用保留以便重试。未完成元数据的上传意图等待一小时静默期后清理,包括已补偿删除、对象不存在的记录。来源不明对象只报告摘要,不按相似前缀删除。bucket 必须私有、未启用版本化,其唯一存储标记必须与数据库一致。为拒绝任意迟到重放,部署生命周期内保留最小作用域/身份 UUID 和客户端 ID 摘要,不保留原反馈正文或联系方式。过期 session/code 可清理,但发放预算窗口不会提前重置。
运营备份与隔离恢复
正常 dev-apps-up.sh 在 migration 后初始化/检查独立 recovery-journal、recovery-witness volume。每个已确认的限制动作均已独立落盘。两份 authority 不纳入数据库/对象备份;缺失、陈旧、损坏或未完成时,两 API 都拒绝开放。只有原权威数据库能用 --action reconcile-recovery --deployment-id "$deployment_id" --apply 校正中断动作。
从 Infra 创建私有备份根并执行协调脚本:
python3 scripts/backup-local.py --root "$PWD/.backups"
python3 scripts/backup-local.py --root "$PWD/.backups" --apply
export DATA_BACKUP_ROOT="$PWD/.backups"
./scripts/data-maintenance.sh --action prune-backups --deployment-id "$deployment_id" --output /backup-data --batch 20
./scripts/data-maintenance.sh --action prune-backups --deployment-id "$deployment_id" --output /backup-data --batch 20 --apply
脚本停止源端访问,真实执行 pg_dump、保存注册对象字节、校验全部 checksum,并将 manifest 登记到独立 catalog 后才恢复源端。近期未完成上传、未知对象或已接受附件缺失都会阻止完成。部分目录不算备份。备份包含敏感数据库和对象内容,目录须 0700、文件 0600;记录脚本返回的目录和 manifest hash。
选择完整且未过期的 backup_name,保持当前源 Compose project/environment,先验证,再取得冻结源端的最新 cutover seal:
./scripts/data-maintenance.sh --action verify-backup --deployment-id "$deployment_id" --output "/backup-data/$backup_name"
umask 077
mkdir -p .restore-control
export DATA_CONTROL_ROOT="$PWD/.restore-control"
./scripts/data-maintenance.sh --action begin-cutover --deployment-id "$deployment_id" --apply > "$DATA_CONTROL_ROOT/cutover.json"
另建空白本地 Compose project、私有 bucket、独立环境文件、空闲端口和凭据。恢复前不运行目标的 migration、seed 或 API;绝不能覆盖源端或现有业务数据库。以下变量须指向该明确准备的空目标,source_project 是仍冻结的原源端:
docker compose --file docker-compose.yml --env-file "$restore_env" --project-name "$restore_project" up -d postgres minio
docker compose --file docker-compose.yml --env-file "$restore_env" --project-name "$restore_project" run --rm --no-deps minio-init
export RECOVERY_AUTHORITY_PROJECT="$source_project"
python3 scripts/restore-local.py --backup "$DATA_BACKUP_ROOT/$backup_name" --seal "$DATA_CONTROL_ROOT/cutover.json" --target-project "$restore_project" --target-env "$restore_env" --authority-project "$source_project"
python3 scripts/restore-local.py --backup "$DATA_BACKUP_ROOT/$backup_name" --seal "$DATA_CONTROL_ROOT/cutover.json" --target-project "$restore_project" --target-env "$restore_env" --authority-project "$source_project" --apply
恢复向空目标存储写入校验后的字节,重放最新删除、账号、Key、成员和 SDK gate 事实,物理清理已删/到期对象后才开放。任何失败都保持目标隔离,对同一备份与 seal 重试。仅在返回 completed 后启动目标 API,并保留 RECOVERY_AUTHORITY_PROJECT,让 dev-apps-up.sh 使用外部 authority override。不可对原源端运行 down -v,这会删除替代部署仍使用的 authority。原源端保持停止;退役其数据或迁移 authority 必须按运营者审核的范围进行。
所有恢复的 session、code、pending 邀请无效,存续账号须走现有邮件重置密码流程后重新登录;注销/禁用账号仍被阻止。个人注销不会误撤销共享项目的有效 Key;已撤销 Key、关闭作用域保持不可用。恢复点后的内容和回执元数据可能丢失,只有明确记录的校正事实独立保留;不能捏造不在快照内的必要 owner 身份,应改用足够新的备份。
python3 scripts/check-g5-data.py --recovery 使用合成数据重现真实 PG/MinIO 及失败门禁。这是本地受控恢复证据,不是生产 RPO/RTO、灾难耐久性或 SLA。G6 才确定实际独立存储、调度、告警、凭据、邮件送达及恢复目标。
在写入 dump 字节前,独立 catalog 先登记未完成备份。prune-backups 也会按原始 7 天期限清理这些记录,重试不续期。源端恢复后,可用 --action discard-backup --output "/backup-data/$backup_name"、确切 deployment ID 和 --apply 立即丢弃指定半成品;已批准备份或未知文件会被拒绝。脚本被杀后先查看 recovery-status,只以确切的源端 nonce 执行 resume-source --fence-id "$fence_id" --apply;无法证明归属时继续关闭。
恢复脚本在 pg_restore 前验证独立批准与全部文件,拒绝运行中的目标 API 和没有匹配恢复检查点的非空数据库,并在 seal 目录保存私密检查点。导入中断只允许对同一最初空库、未变备份/seal/环境重跑;进入校正阶段后不再导入旧 dump。目标环境和控制文件需 0600,控制目录需 0700。成功后 API 仍停止,由运营者使用外部 authority 绑定启动。
常见错误
仅有 PostgreSQL dump 不是完整备份。旧日志与旧数据库一起复制不能证明最新 authority。S3 失败不能算清理完成,源 bucket 不能作为恢复目标,不可手工清除恢复门禁。
下一步
复核账号恢复,先运行隔离验证,再将流程用于真实数据。生产运营承诺属于 G6。