fix: 备份覆盖补全(动作库/系统配置入清单)+ 覆盖自检与未登记表告警;发布流程/红线文档更新
问题(2026-09-10 用户反馈):动作库"没有备份"。实测导出 zip 里 agent_action 数据其实在 (导出是 users.db 全库快照),但清单/预览没列它 → 看起来像没备份。同类还有 app_meta。 修复(core/system_backup.py): - SUMMARY_TABLES 补 agent_action(动作库) 与 app_meta(系统配置) + 中文标签; - 导出侧**覆盖自检**:登记表若在快照缺失 → manifest.coverage_missing + 日志告警; - 导入侧**反向自检**:备份含未登记表 → 预览告警提示登记(extra_tables); - 顶部注释写明新增持久化表必须登记(红线)。 其余: - monitor.html:数据备份面板文案改为明列全部业务表 + 指引(预览见表行数 / 新增表须登记); - doc/DEPLOY.md §3.5:新增「备份覆盖清单(红线)」小节(含清单与两侧自检说明); - doc/DEVELOPMENT.md:§5.6 增「备份覆盖红线」;§6 发布流程重写为分支流程 (本机建分支 → 用户确认 → 合 dev → dev 整体就绪 → 合 main → 220 部署,附部署命令); - doc/ARCHITECTURE.md §3.6:补备份覆盖登记提示。 实测:导出清单 12 表(含动作库 3 行、系统配置 8 行),coverage_missing 空;上传预览同样显示、 extra_tables 空。
This commit is contained in:
+21
-2
@@ -38,16 +38,21 @@ DB_FILE = os.path.join(DATA_DIR, "users.db")
|
||||
# 判定「本平台备份库」的必需表(缺任何一张即拒绝导入)
|
||||
REQUIRED_TABLES = ("app_meta", "user", "task_job", "device_group")
|
||||
# 预览/清单里展示行数的业务表(存在才统计)
|
||||
# ⚠️ 红线:**新增任何持久化表,必须同步登记到这里**——备份覆盖清单以此为准,
|
||||
# 漏登记的表在导出清单/预览里不可见(2026-09-10 动作库 agent_action 即因此
|
||||
# 被误判为"没有备份":数据其实在 users.db 快照里,只是清单没列)。
|
||||
SUMMARY_TABLES = (
|
||||
"user", "device_group", "task_job", "custom_action",
|
||||
"app_meta", "user", "device_group", "task_job", "custom_action",
|
||||
"apk_file", "device", "pending_device",
|
||||
"agent_conversation", "agent_experience", "experience_audit",
|
||||
"agent_conversation", "agent_experience", "experience_audit", "agent_action",
|
||||
)
|
||||
TABLE_LABELS = {
|
||||
"app_meta": "系统配置(app_meta)",
|
||||
"user": "用户", "device_group": "设备分组", "task_job": "任务计划",
|
||||
"custom_action": "自定义动作", "apk_file": "APK 记录", "device": "设备池",
|
||||
"pending_device": "待连接设备", "agent_conversation": "AI 会话",
|
||||
"agent_experience": "经验库", "experience_audit": "经验巡检",
|
||||
"agent_action": "动作库",
|
||||
}
|
||||
_STAGE_TTL = 1800 # 导入暂存有效期(秒)
|
||||
|
||||
@@ -193,6 +198,13 @@ def create_export(include_apk=True):
|
||||
"tables": _summary_info(con),
|
||||
"apks": apk_meta,
|
||||
}
|
||||
# 覆盖自检:登记在册的业务表若在快照里缺失(新增功能忘了登记 / 建表失败),
|
||||
# 显式告警并写进 manifest——避免"以为备份了其实没有"(备份覆盖红线)。
|
||||
_present = {t["table"] for t in manifest["tables"]}
|
||||
_missing = [t for t in SUMMARY_TABLES if t not in _present]
|
||||
if _missing:
|
||||
manifest["coverage_missing"] = _missing
|
||||
_log.warning(f"备份覆盖检查:以下登记表未纳入快照,请确认是否应备份: {_missing}")
|
||||
finally:
|
||||
con.close()
|
||||
|
||||
@@ -241,6 +253,12 @@ def validate_backup(db_file):
|
||||
warnings.append("备份缺少部分可选表(" + "、".join(
|
||||
TABLE_LABELS.get(t, t) for t in missing_optional)
|
||||
+ "),应用后启动会自动补建空表")
|
||||
# 反向自检:备份里有"未登记"的表 → 提醒把它纳入覆盖清单(红线)
|
||||
extra_tables = sorted(t for t in tables
|
||||
if t not in SUMMARY_TABLES and not t.startswith("sqlite_"))
|
||||
if extra_tables:
|
||||
warnings.append("备份含未登记的其它表(" + "、".join(extra_tables)
|
||||
+ ")——如属业务数据,请登记进 core/system_backup.py 的覆盖清单")
|
||||
warnings.append("备份为全量快照:含用户口令哈希、AI 配置里的 API Key 等敏感信息,请妥善保管")
|
||||
return True, {
|
||||
"integrity": integrity,
|
||||
@@ -248,6 +266,7 @@ def validate_backup(db_file):
|
||||
"current_schema_version": CURRENT_SCHEMA_VERSION,
|
||||
"tables": _summary_info(con),
|
||||
"missing_optional": missing_optional,
|
||||
"extra_tables": extra_tables,
|
||||
"warnings": warnings,
|
||||
}
|
||||
except sqlite3.Error as e:
|
||||
|
||||
@@ -187,6 +187,8 @@ SQLAlchemy 模型,存于 `data/users.db`:
|
||||
> - `app_meta`(KV):`_migrate_schema()` 内建表,存 `schema_version`、`discovery_*`、agent 配置 `agent_*` 等;
|
||||
> - `agent_conversation` / `agent_experience` / `experience_audit`:AI 控制台会话 / 任务级经验(配方)/ 经验巡检(`web/agent_api.py` 顶部 `CREATE TABLE IF NOT EXISTS`)。
|
||||
> - `agent_action`:**动作经验库**(命名动作 = 可复用单元,steps 用编辑器 schema 且带元素定位、禁坐标);由任务成功后从**成功步骤**蒸馏,执行前按名字/别名召回并注入(`web/agent_api.py` `_distill_actions/_find_actions`)。
|
||||
>
|
||||
> **备份覆盖(红线)**:持久化表须登记进 `core/system_backup.py` 的 `SUMMARY_TABLES`(→ 导出清单/预览可见、覆盖自检生效),并同步 `doc/DEPLOY.md` §3.5;未登记的表在备份预览里不可见,会被误判为"没备份"。
|
||||
|
||||
**数据库初始化**(`init_db`):
|
||||
- 创建所有表
|
||||
|
||||
@@ -246,6 +246,15 @@ server {
|
||||
- **导出**:`POST /api/system/backup/export` → 用 sqlite 在线备份 API 对 `data/users.db` 做一致快照,打包 zip(`users.db` + `manifest.json` + 可选 `apks/*.apk`)
|
||||
- **导入**:上传 zip/`.db` → 校验预览(完整性/必需表/schema 版本告警)→ 确认后自动把当前库快照到 `data/backups/pre_restore_*.db`(安全网可回滚)→ 落 `data/restore_pending/` → **重启 web_server 生效**(web_server 在 `init_db` 前自动消费恢复任务)
|
||||
|
||||
**备份覆盖清单(红线)**:覆盖清单 = `core/system_backup.py` 的 `SUMMARY_TABLES`,当前包含
|
||||
`app_meta`(系统配置) / `user` / `device_group` / `task_job` / `custom_action` / `apk_file` / `device` /
|
||||
`pending_device` / `agent_conversation` / `agent_experience` / `experience_audit` / `agent_action`(动作库)。
|
||||
|
||||
> **新增任何持久化表,必须同步登记进该清单**——否则导出清单/预览里看不到它,会被误判为"没有备份"
|
||||
> (2026-09-10 动作库 `agent_action` 即因此被误判:数据其实在 `users.db` 快照里,只是清单漏列)。
|
||||
> 导出侧有**覆盖自检**(登记表若缺失 → `manifest.coverage_missing` + 日志告警);导入侧有**反向自检**
|
||||
> (备份含未登记表 → 预览告警提示登记)。
|
||||
|
||||
目录与常量:
|
||||
|
||||
| 目录 | 用途 |
|
||||
|
||||
+29
-7
@@ -231,20 +231,42 @@ tasks/<app>/
|
||||
| MCP 工具 | [MCP.md](MCP.md) 与 [MCP_DESIGN.md](MCP_DESIGN.md) |
|
||||
| 对外接入 / 数字员工知识库 | [staffdeck/KNOWLEDGE_BASE.md](staffdeck/KNOWLEDGE_BASE.md) 与 [staffdeck/JOB_SPEC.md](staffdeck/JOB_SPEC.md) |
|
||||
|
||||
> **备份覆盖红线(2026-09-10 新增)**:**新增任何持久化表**(业务数据)时,必须同步把它登记进
|
||||
> `core/system_backup.py` 的 `SUMMARY_TABLES`(并在 `TABLE_LABELS` 给中文名)+ 更新
|
||||
> [DEPLOY.md](DEPLOY.md) §3.5 的覆盖清单。理由:清单漏登记 → 导出预览看不到该表 → 会被误判为
|
||||
> "没有备份"(动作库 `agent_action` 就踩过)。导出侧有覆盖自检、导入侧有未登记表反向告警。
|
||||
|
||||
注:STF_REMOVAL.md 是历史迁移记录,不改写。
|
||||
|
||||
---
|
||||
|
||||
## 6. 发布流程
|
||||
## 6. 发布流程(团队约定,2026-09-10 更新)
|
||||
|
||||
详见 **[doc/DEPLOY.md](DEPLOY.md)**。摘要:
|
||||
**每个改动都走分支,确认后再并 dev;dev 整体就绪后才并 main 上生产。**
|
||||
|
||||
1. dev 开发测试完成
|
||||
2. 负责人确认 → 合并到 main
|
||||
3. 负责人确认 → 生产 220 `git pull`
|
||||
4. 重启 python-app 容器生效
|
||||
```
|
||||
① 本机新建分支 fix/xxx 或 feat/xxx(从 dev 切出)
|
||||
② 分支上开发 + 自测 本机跑通(服务/接口/页面)
|
||||
③ 交负责人确认 ★ 未经确认不合 dev
|
||||
④ 合并到 dev 确认通过后(fast-forward 或 merge)
|
||||
⑤ dev 整体就绪 dev 上功能齐全、验证完毕
|
||||
⑥ 合并到 main ★ 负责人确认后
|
||||
⑦ 生产 220 部署 git pull → 重启 python-app 容器 → 验证
|
||||
```
|
||||
|
||||
**发布前检查**:生产容器 adb key、依赖、数据库迁移。
|
||||
**生产 220 部署(目录 `/mnt/data/openstf/auto_control`,容器 `python-app` 挂到 `/app`)**:
|
||||
|
||||
```bash
|
||||
cd /mnt/data/openstf/auto_control
|
||||
git fetch origin && git checkout main && git pull --ff-only origin main
|
||||
docker restart python-app # 入口 scripts/start.sh:依赖守卫 → 拉起 MCP → exec web_server
|
||||
# 验证:curl -s http://127.0.0.1:18050/api/health ; ss -ltnp | grep -E ':(18050|8033|20242)'
|
||||
```
|
||||
|
||||
**发布前检查**:生产容器 adb key、依赖(新增依赖看 `requirements.txt`)、数据库迁移(`create_all` 自动补新表)、
|
||||
以及"新增持久化表是否已登记进备份覆盖清单"(见 §5.6 红线)。
|
||||
|
||||
**数据迁移**:用平台自带「系统 → 数据备份导出/导入」;导入后需**重启容器**才生效(见 [DEPLOY.md](DEPLOY.md) §3.5)。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -911,9 +911,10 @@ body{background:var(--bg);font-family:var(--body);color:var(--text);font-size:14
|
||||
<!-- 子分栏 1:数据备份 -->
|
||||
<div class="sub-panel active" id="system-sub-backup">
|
||||
<div class="help">
|
||||
<b>导出</b>当前系统数据为 zip:含 <code>users.db</code>(用户 / 任务计划 / 设备分组 / 自定义动作 /
|
||||
设备池 / AI 会话 / 经验库等全部表,SQLite 在线一致快照)+ 可选的 <code>apks/</code> 应用文件。
|
||||
恢复用:换机 / 整库迁移 / 出问题前留底。
|
||||
<b>导出</b>当前系统数据为 zip:含 <code>users.db</code> 在线一致快照(<b>全部业务表</b>:用户 / 任务计划 / 设备分组 /
|
||||
自定义动作 / APK 记录 / 设备池 / 待连接设备 / AI 会话 / 经验库 / 经验巡检 / <b>动作库</b> / 系统配置)+ 可选的
|
||||
<code>apks/</code> 应用文件。恢复用:换机 / 整库迁移 / 出问题前留底。
|
||||
<br><span class="text-muted">清单见预览的「表数据行数」;新增持久化表须登记进备份覆盖清单(红线,见 doc/DEPLOY.md §3.5)。</span>
|
||||
</div>
|
||||
<div class="toolbar" style="gap:8px">
|
||||
<label style="display:inline-flex;align-items:center;gap:4px;margin:0 6px">
|
||||
|
||||
Reference in New Issue
Block a user