用户的反馈是对的:上一轮只砍掉了"冻结/锁定"两个按钮,但一条文档从"已批准"到"发出"实际仍要
~9 次交互(找条目→勾选→填名→建批→滚到清单→找批次→授权→输语句→提交),因为"批次仪式"本身
还留在路径上。
- 新端点 POST /api/v1/release-batches/publish-now:在同一操作里先建批(SealImmediately,冻结
即锁定)再授权生产发布,返回 {batch, execution}。
- 不放松任何约束:请求门禁(403)、备份恢复验证门禁(412)、管理员身份(401)、固定确认语句(400)、
发布前快照硬门禁(409)、建批门禁(422) 全部沿用既有实现,无旁路;名称可省(服务端固定回退名,
保证重放指纹一致)。
- 界面:审核行上直接「发布到生产」(管理员 + 门禁开启时显示),工具栏支持选中多条一次发布;
复用既有确认弹窗(固定语句)。批次名不再是必经步骤。
- 实测(面板):点行级按钮 → 输 `publish-to-production` → 提交 → 批次 rb-bee80550…(sealed)
+ 执行 rx-3d831129…(completed, 项级 verified) → 页面回滚 rx-43835fac…(rolled_back, absent)。
测试:publish_now_test.go(四道关卡 + 组合调用 + 名称回退)与 reviewRelease.test.ts(请求体/回传/错误原因);
Go 26 包、前端 183 条全过。
10 KiB
现行用户操作流程(Runbook)
按"实际干活顺序"排列的现在的操作流程。标注:**【新】本期新增(含本次会话与 f4e1ecc/6496ee3/9155bd3 的 dws 取件)|【变】既有流程本期有改动|【既有】**未变,仍照旧走。
逐条验收证据请看 docs/USER_FLOWS_ACCEPTANCE.md;细节规则看各自专题文档。
统一入口 http://127.0.0.1:8088/(测试栈,右侧面板可直接操作)。角色:管理员 / 文档工程师 / 只读。
0. 开工前:环境与凭据自检
| 项 | 怎么做 | 成功标志 |
|---|---|---|
| 测试/生产 WeKnora | 系统设置 → 服务配置 | 生产端"已启用 · 可提交生产请求";测试端探测正常 |
| 钉钉取件凭据 【新】 | 容器内 HOME=/data/home dws auth status --readonly -f json |
authenticated:true、refresh_token_valid:true(必须带 HOME=/data/home,否则误报未登录) |
| 备份主机接线 | 系统设置 → 存储与备份 | "目标主机 weknora-test · 已连接" |
【新】dws 凭据续期(30 天轮换,到期前 7 天)
dws auth login --device # 目标机执行,本人浏览器授权
dws wiki +space-list --limit 1 -f json # 真实调用验证,期望 ok:true
出现 code=credentials → 立即停批,不要重试风暴;授权后 --retry-failed 续跑。
1. 取件(内容进来)【变:钉钉优先走 dws】
- 登录 → 来源与目录 → 选内容来源(钉钉知识库 / 国内工业 AList / PP 清单)。
- 展开目录、勾选要取的条目 → 取件(后台入队)。
- 看 解析监控:应出现"处理中"。
- 钉钉来源现在优先用 dws 取字节(
adoc→导出 docx,axls→转 xlsx,其余→drive 直下),不再依赖浏览器扫码会话;仅当 dws 报可重试错误(429/5xx/超时/连接层/服务端导出失败/dws 缺失)才回落老路径。 - 平台侧判定全部保留(后缀路由、PPT 必须 PDF 双胞胎、magic、大小上限、sha256、spool 原子写、空壳检查)——dws 只取字节。
- 想强制只用 dws 或完全绕过:
ARTIFACT_DINGTALK_FETCHER=dws|legacy(默认auto)。 - 在线文档并发不要超过 4(当前配置 2 ✓)。
- 失败进 死信,可"重排";轮次键
artifact-fetch:<version>:r<n>。
2. 标注与目录范围 【既有】
来源与目录 → 勾选 → 标记 对内 / 对外 / 不需要(目录级标记决定整目录)。
- 路由到哪个测试库由 系统设置 → 测试知识库绑定 决定;
不需要不入库。
3. 发布准备:勾选 → 建批 → 锁定 【变:P0-1 建批时冻结 + P0-2 自动批准】
发布管理 → 审核要发布的知识:
- 最快路径(推荐,单个或几条):在已批准那条上直接点
发布到生产→ 输入固定语句 → 提交。服务端在同一个动作里完成「建批(冻结+锁定)→ 授权生产发布」,无需填批次名、无需先建批再锁定。 - 需要一批多条时:勾选 → 填批次名 →
创建并锁定清单(建批即锁定),再到发布清单点授权发布。 - 不再需要
生成新版本/确认冻结:服务端在"建批这一下"把当前实时计划冻结成一份已确认版本并绑定该批次。 语义不变——批一旦建立,清单/摘要/验收轮次/目标库绑定全部不可变、回滚按它走;变的只是"谁在什么时候按固化键"。 - 同一份计划复用同一版本(摘要一致即复用),所以连续建批不会堆版本;计划变了才新建一版。
- 审核:
TEST_AUTO_REVIEW_POLICY=off|internal(默认,仅对内)|all。默认下对内知识验收通过即由系统批准 (审核记录reviewer_ref=system:auto),对外仍需人工;策略可在容器环境变量调整,界面上只读展示当前值。 人工随时可驳回/改判;系统只允许写"第一条"审核,永远不会覆盖人工结论。 - 建批即锁定:清单在建批那一刻冻结并立即密封,批次不可再改;锁定后才能授权生产发布。锁定 ≠ 上线。
- 批量批准按人工身份记录(reviewer=当前登录人),人工可以推翻自己先前的驳回;系统自动批准(
system:auto)永远只写第一条、不覆盖任何人工结论。
4. 待入库 → 处理 【既有】
文档工作台/待入库列表 → 选中 → 开始处理 → 上传 → 解析 → 索引 → completed。
- 监控在 解析监控:处理中 / 需要你出手 / 需下架 / 死信 / 已完成 / 知识库差异 / 知识库解析进度。
5. 发布/导入之前:必须先留档(硬门禁)****【新】
目标库现场必须先留档,否则发布被拒(release_target_snapshot_missing,不可重试,目标库一行不碰)。
bash scripts/target_kb_snapshot.sh # 默认云内执行;PG 8 表 + 该库在 ES 的全部文档
- 产出:
$KB_BACKUP_ROOT/target-kb-snapshots/<UTC>-<kb8>/(PG JSONL +es_documents.jsonl.gz+MANIFEST.json(sha256/每库 ES 计数) +export.sql+README.md)。 - 实测:2 分 52 秒(ES 字节留目标主机);
PULL_ES=1拉回本机则 19 分 40 秒。 - 门禁自动核验"覆盖该库 + 24h 内 + PG 与 ES 两层齐备 + 哈希可校验";复核用
go run ./cmd/guardcheck <快照根> <kb_id>。
6. 授权发布 → 读回验证 【变:页面通道】
发布管理 → 授权发布 → 逐字输入确认语句 publish-to-production → 确认执行。
- 双闸(请求门禁 + 备份恢复门禁)+ 执行门禁;页面不录入/不显示 token,也没有"一键发布"。
- 执行完成后看
查看结果:completed+verified;目标库出现该文档。
7. 回滚 / 重排 【变:页面通道】
- 回滚:
查看结果→回滚→ 确认语句rollback-production-release。回滚后目标库该知识停用(不删知识行),wiki 页保持。 - 重排失败执行:失败项 →
重排→ 确认语句retry-production-release(只重置失败项;verified/rolled_back保持;不改写历史AuthorizedBy)。
8. 系统设置里现在要维护什么
审核策略目前由容器环境变量
TEST_AUTO_REVIEW_POLICY控制(api 与 worker 共用 compose 锚点,默认internal)。 界面上「审核要发布的知识」标题下方会显示当前生效值。
| 分区 | 谁 | 现在要管什么 |
|---|---|---|
| 服务配置 | 管理员 | 测试地址 / 生产地址 / 生产 ID / 知识库 ID(保存时真探活,无效才拒) |
| 测试知识库绑定 | 管理员 | 标注往哪个测试库路由(对内 ≠ 对外) |
| 生产知识库绑定 | 管理员 | 源库 → 目标库映射(发布写哪个生产库) |
| 存储与备份 【新】 | 管理员 | 定时时间 + 储存天数(+每月归档、启用开关)→ 保存并下发到主机;另有 重新下发当前设置、立即备份一次;页面显示主机上实际生效的计划、cron 条目、最近一次结果与"已一致/待下发" |
| 刷新策略 | 文档工程师 | 文档/资源刷新间隔、停滞判定、finalizing 时长(版本化 + 原子切换) |
| 成员与角色 | 管理员 | 成员与 viewer/engineer/admin |
9. 备份与恢复运维 【新】
| 层 | 怎么做 | 频率/现状 |
|---|---|---|
| 导入前留档(PG 行 + ES 文档) | scripts/target_kb_snapshot.sh |
每次发布前(2m52s) |
| 硬门禁 | 自动(发布链已内置) | 每次写目标库前 |
| 整库逻辑备份(自管,落在自己机器) | 页面 立即备份一次,或主机 logical-backup.sh |
每天 03:30 / 保留 7 天 / 每月另留 3 份(33 秒 / 742.6 MiB / 8 库 / 失败 0) |
| ES 快照 | 仓库 kb_backup + SLM kb-hourly(3 天)/kb-daily(7 天) |
自动;首个快照 36 秒 / 4.7 GB |
| OSS 版本控制 | 桶 dobot-weknora-test 已开启 |
覆盖/删除可按 VersionId 回滚 |
| RDS 托管备份 | 阿里云控制台自管(按决定:本期不做) | — |
| 目录契约 【新】 | scripts/backup_layout.sh(任意主机同一份) |
/srv/kb-backups/{target-kb-snapshots,rds-logical,es-snapshots,logs} |
| 回填演练 【新】 | python3 scripts/restore_drill.py --snapshot-dir <留档> --target-url <本地测试库> |
13,539 行回填、抽样逐字段一致、残留 0 |
换主机(测试云主机 → 未来生产云主机):① 新机跑同一份 backup_layout.sh;② compose 的 ES 挂载源与留档挂载源指向 $KB_BACKUP_ROOT;③ 门禁配置 target_snapshot.root 保持容器内路径不用改;④ 授权发布前先跑一次留档。
10. 出事了怎么恢复(按事故类型,越快越靠前)
| 事故 | 首选 | 耗时 |
|---|---|---|
| 某 KB 的 wiki/元数据被覆盖 | 留档回填(restore_drill.py 同法,或快照 README.md 的 SQL) |
秒~分钟 |
| 检索/向量异常、索引误删 | ES 快照 restore(kb_backup)或按 es_documents.jsonl.gz 以 _id 重建 |
分钟 |
| OSS 对象被覆盖/删除 | OSS 版本控制回滚单对象/前缀 | 秒~分钟 |
| 整库改坏要带走一份 | 自管逻辑备份 pg_restore -d <库> -j4 <库>.dir |
分钟~十分钟 |
| 整实例级、要回到某个时刻 | RDS 快照 / PITR → 新实例 → 按 KB 取行 | 10~30 分钟 |
本次新增/变化速查(对照旧流程)
| # | 变化 | 影响你的操作 |
|---|---|---|
| 1 | 钉钉取件走 dws 【新】 | 取件不再依赖扫码会话;但凭据 30 天要续期(runbook 见 §0) |
| 2 | 发布前必须留档(PG+ES)【新】 | 发布前多一步 target_kb_snapshot.sh,否则门禁拒发 |
| 3 | 整库逻辑备份定时 【新】 | 在 系统设置 → 存储与备份 设时间与储存天数(保存即下发主机 cron) |
| 4 | 生产动作页面通道 【变】 | 授权发布/重排/回滚在页面上、各需逐字确认语句 |
| 5 | 目标知识库可选 【变】 | 生产库绑定里可分别指定对内/对外目标库(不再要求同 ID) |
| 6 | wiki 归属门禁 【变】 | 共享知识库发布不再整库清空:只替换本包拥有的页面 |
| 7 | 回填演练 + 目录契约 【新】 | 出事可验证地回填;换机器只改一处配置 |