Files
next-tjwater-server/docs/workbench-database-rollout.md
T

69 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 工作台数据库变更门禁
本规则适用于工作台、工况任务、Agent Run、事件日志、通知、预约工单和告警在项目 BizDB 中的 DDL、数据回填、种子写入与清理操作。MetaDB、TimescaleDB 和外围系统数据库不在本文范围内。
## 当前基线
截至 2026-09-24,`014_operational_tasks.sql` 和 `015_workbench_events_and_task_runs.sql` 已应用到 `tjwater_v2`、`szh_v2`、`md_v2`、`fengyang_v2` 和 `zjb`。这是已有基线,不代表后续迁移可以继续批量应用。
`017_workbench_schema_comments.sql` 只为 `workbench` schema 及其 17 张表和关键列增加数据库可见注释。它先在 `tjwater_v2` 应用;其他项目数据库保持原状,直到 `tjwater_v2` 验证通过并获得明确扩展确认。
`018_remove_synthetic_check_task_projections.sql` 清理曾被错误同步为预约任务的通用合成检查投影。它按完整 `peripheral_sample:<work_order_id>` 标识关联外围源,只匹配 `general` 类型、没有调查动作回执关联且由专用 seed actor 创建的旧检查任务;不使用用户可编辑的标题或工单状态作为删除依据。`workbench.work_orders` 中三条演示工单、投诉与爆管事件以及调查产生的现场采样工单均不在清理范围。同步器使用同一专用 seed actor 阻止旧种子检查再次生成。
预约工单结构调整无需 DDL。`seed_workbench_work_orders.py --project-id <已核对的项目 UUID>` 只重建该项目的三条演示预约投影,保留工单 ID 和标题,改为单层字段与显式活动记录。执行前必须核对脚本删除谓词实际命中的 ID;它不修改 `peripheral_sample.work_orders`、历史修订或调查任务。其他项目不得随 `tjwater_v2` 自动重建。
后续数据库变更默认只写入 `tjwater_v2`。其他项目保持现状,必须等 `tjwater_v2` 验证通过并由维护者明确确认后,再逐库扩展。禁止把“所有活跃项目”作为写操作的默认范围。
## 变更顺序
1. 核对目标 DSN,确认物理数据库名为 `tjwater_v2`,并确认没有其他项目共享该 BizDB。
2. 对目标库做完整、可恢复的备份。备份需通过 `pg_restore --list` 或等价方式检查,路径和校验值记录在部署记录中,不提交到仓库。
3. 在强制回滚事务或由备份恢复出的临时库中执行完整迁移。只做静态 SQL 检查不能替代这一步。
4. 只在 `tjwater_v2` 提交迁移,提交后立即核对表、列、约束、索引、回填数量和项目 ID。
5. 完成接口、工作进程和浏览器验收。未通过时停止扩展,保留备份和现场信息。
6. 维护者确认验收结果后,按一个项目一次的方式扩展。每个项目重新执行备份、回滚演练和验收,不复用 `tjwater_v2` 的通过结论。
SQL 文件包含自己的 `BEGIN` 和 `COMMIT` 时,不能在外层简单包一层 `ROLLBACK` 充当演练。演练工具需要移除脚本自己的事务边界,或在由备份恢复出的临时数据库中运行。
## 验收条件
`tjwater_v2` 同时满足以下条件后,才可以讨论扩展:
- 迁移重复执行不会产生重复记录或改变已经确认的终态数据。
- 表、约束和索引与迁移定义一致,没有其他项目 ID 的记录。
- 带 Bearer 和 `X-Project-Id` 的 `sync-snapshot` 返回 200,游标、任务和通知可以解析。
- SSE 可以连接、发送 keepalive,并能从持久游标补读事件。
- 至少一条合成调查完成 queued、running、waiting_human 的主路径,计划、报告和通知属于同一执行代次。
- Agent 或 Server 重启后,旧 Run 和旧会话不能覆盖当前代次。
- Server、Agent 和前端的相关自动化测试通过,联调期间没有新增 5xx、跨项目数据或重复事件。
没有定义固定观察时长。验收记录至少包含执行时间、代码提交、迁移编号、备份标识、自动化测试结果和真实接口结果,由维护者决定是否扩大范围。
## 维护脚本也受范围限制
会枚举 Metadata DB 中所有活跃路由并写入数据库的脚本,属于跨项目变更。此类脚本必须提供显式项目参数,并默认拒绝全项目写入。
`cleanup_workbench_events.py` 会枚举所有活跃项目,但已经支持 `--project-id`。dry-run 可以查看全部项目;写入模式必须显式传入经核对属于 `tjwater_v2` 的项目 UUID,禁止省略 `--project-id`。种子、导入、回填和修复脚本同样不能把所有活跃项目作为隐式目标。
## 当前设计需要收敛的部分
现有设计保留以下主干:
- `operational_tasks` 保存业务任务,`operational_task_runs` 保存每一代 Agent 执行。两者生命周期不同,分表有助于租约恢复和阻止旧代次写回。
- `domain_event_log` 保存可重放事件,`LISTEN/NOTIFY` 只负责唤醒。当前规模不需要增加 Redis、Kafka 或新的中继服务。
- 通知表表达用户收件箱,事件日志表达状态变化。两者不能合并。
- 证据、计划、报告和动作修订需要保留历史版本,独立表符合审计和并发更新要求。
以下部分不再扩展:
- `operational_tasks` 仍保存执行代次、执行请求号、Agent session 和租约字段,同时 Run 表也保存同类数据。新代码以 Run 表为准,不再增加任务表上的执行字段。待 `tjwater_v2` 稳定后,再设计前向迁移移除兼容字段。
- `status`、`lifecycle_status` 和任务 JSON 中的状态存在重复表达。新接口以 `lifecycle_status` 为业务生命周期,以 Run 状态为执行状态,不再增加第四套状态字段。
- 定时任务表和 schedule API 不在当前产品主路径。相关结构保留兼容,不继续增加调度能力,除非 `tjwater_v2` 出现明确业务需求。
- JSON 文档与标量列只保留查询、约束或兼容所需的重复字段。新增字段应先确定唯一权威来源,不能同时在多处独立计算。
新增表需要同时满足三个条件:对象有独立生命周期,访问或保留策略与现有表不同,并且 `tjwater_v2` 的真实用例证明复用现有结构会造成明显问题。否则优先收敛现有模型。
## 失败与回滚
任何数据库出现迁移失败、接口 5xx、跨项目记录、Run 代次错乱或游标异常时,立即停止后续项目。未提交的事务直接回滚;已经提交且不能安全前向修复时,按该项目的迁移前备份恢复。不要为保持各项目版本一致而继续扩大故障范围。