init: ops-assistant codebase

This commit is contained in:
OpenClaw Agent
2026-03-19 21:23:28 +08:00
commit 81deba4766
94 changed files with 10767 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
# API Response Convention
统一响应格式JSON 接口):
- 成功:
```json
{
"code": "OK",
"message": "ok|success|...",
"data": { }
}
```
- 失败:
```json
{
"code": "ERR_...",
"message": "..."
}
```
## 约定
1. 所有 `/api/v1/*` JSON 接口使用统一结构。
2. 文件流接口(如 CSV 导出)成功时返回文件内容;失败时返回统一错误 JSON。
3. 权限失败统一 `ERR_PERMISSION_DENIED`
4. 执行失败统一至少返回一个业务错误码(例如 `ERR_STEP_FAILED`)。
5. `message` 用于人类可读,`code` 用于前端逻辑分支。
## 已接入范围2026-03-10
- Ops: jobs/list/detail/cancel/retry
- Flags: list/patch
- Channels: list/patch/publish/reload/enable/disable/disable-all/test/apply
- Records: list/delete
- Audit: list

150
docs/ai_command_guide.md Normal file
View File

@@ -0,0 +1,150 @@
# AI 命令解释知识库(用于自然语言→标准命令翻译)
## 总原则
- 目标:把用户的自然语言翻译成**唯一**的标准命令。
- 只输出一行命令,不要解释。
- 不能确定时输出 `FAIL`
- 标准命令必须以 `/` 开头。
---
## OPS 模块
### /help
**用途**:显示 OPS 可用命令清单(同 /start /ops help
**常见自然语**
- 你能做什么 / 你会什么
- 功能 / 菜单 / 帮助 / help
- 查看命令 / 看下命令
**输出命令**
- `/help`
### /ops modules
**用途**:查看模块启用状态。
**常见自然语**
- 模块状态 / 查看模块
- ops 模块 / ops modules
**输出命令**
- `/ops modules`
---
## CPA 模块
### /cpa help
**用途**:显示 CPA 模块可用命令。
**常见自然语**
- cpa 帮助 / cpa help
**输出命令**
- `/cpa help`
**用途**:查询 CPA 服务状态与 usage 快照。
**常见自然语**
- cpa状态 / CPA状态 / cpa status / cpastatus
- cpa 服务状态 / cpa 运行状态 / cpa 正常吗
- 查下 cpa / 看下 cpa 状态
**输出命令**
- `/cpa status`
### /cpa usage backup
**用途**:导出实时 usage 并打包备份。
**常见自然语**
- cpa 备份 / 备份 cpa
- 备份 usage / cpa usage 备份
- 导出 cpa 使用情况
**输出命令**
- `/cpa usage backup`
### /cpa usage restore <backup_id>
**用途**:从备份恢复 usage。
**常见自然语**
- 恢复 cpa / 回滚 cpa
- 用备份 <id> 恢复
- 恢复 usage <id>
**输出命令**
- `/cpa usage restore <backup_id>`
---
## Cloudflare 模块
### /cf status
**用途**:查看 Cloudflare 配置状态。
**常见自然语**
- cf 状态 / cloudflare 状态
- cf 配置怎么样
**输出命令**
- `/cf status`
### /cf zones
**用途**:列出 zone 列表。
**常见自然语**
- cf zones / cf 区域列表 / 站点列表
**输出命令**
- `/cf zones`
### /cf dns list <zone_id>
**用途**:列出指定 zone 的 DNS 记录。
**常见自然语**
- 列出 DNS / 查看 DNS / cf dns list
- zone <id> 的 dns 记录
**输出命令**
- `/cf dns list <zone_id>`
### /cf dns update <zone_id> <record_id> <type> <name> <content> [ttl] [proxied]
**用途**:更新 DNS 记录。
**常见自然语**
- 更新 dns / 修改解析
- 把 <name> 改成 <ip>
**输出命令**
- `/cf dns update <zone_id> <record_id> <type> <name> <content> [ttl] [proxied]`
### /cf dnsadd <name> <content> [true] [type]
**用途**:新增 DNS 记录name 自动匹配 zone
**常见自然语**
- 新增解析 / 添加 DNS
- 增加 <name> -> <ip>
**输出命令**
- `/cf dnsadd <name> <content> [true] [type]`
### /cf dnsset <record_id> <content> [true]
**用途**:按 record_id 修改内容(可选开启代理)。
**常见自然语**
- 更新记录内容 / 改 IP
**输出命令**
- `/cf dnsset <record_id> <content> [true]`
### /cf dnsdel <record_id> YES
**用途**:删除 DNS 记录(需 YES 确认)。
**常见自然语**
- 删除 DNS 记录 / 删解析
**输出命令**
- `/cf dnsdel <record_id> YES`
### /cf dnsproxy <record_id> on|off
**用途**:切换代理开关(不改 content
**常见自然语**
- 开启/关闭代理
**输出命令**
- `/cf dnsproxy <record_id> on|off`
### /cf workers list
**用途**:列出 Workers。
**常见自然语**
- 列出 workers / cf workers
**输出命令**
- `/cf workers list`
---
## Mail 模块
### /mail status
**用途**:查看邮件服务/配置状态。
**常见自然语**
- 邮件状态 / mail 状态
- 邮箱配置是否正常
**输出命令**
- `/mail status`
---
## 兜底规则
- 无法确定命令或缺少关键参数时输出 `FAIL`
- 不要猜测 zone_id/record_id/backup_id 等关键参数。

104
docs/architecture-core.md Normal file
View File

@@ -0,0 +1,104 @@
# Ops-Assistant Core Architecture (v0.0.1)
> 目标程序可独立运行AI 可选接入但无执行权;新通道/新功能模块可低成本适配接入。
## 1. 设计红线(强约束)
1. **执行权唯一入口**:所有变更类动作只能经 `Command -> Policy -> Runbook Engine`
2. **AI 不可执行**AI 仅能做建议/解释,不可直接调用执行器。
3. **通道与业务解耦**TG/QQ/Feishu 仅适配输入输出,不承载业务规则。
4. **模块与核心解耦**CPA/CF/Mail 仅注册命令和构建 runbook 请求。
5. **全链路可审计**job/step、operator、request_id、risk_level、input_json 必须可追溯。
---
## 2. 分层结构
1) **Channel Adapter 层**
- 责任:收消息、身份映射、回消息。
- 输入:平台消息。
- 输出统一消息结构text/operator/channel
2) **Command Runtime 层**
- 责任:命令解析、路由、参数校验。
- 输出模块请求Module Request
3) **Policy Gate 层**
- 责任权限、feature flag、confirm token、dry-run。
- 输出:允许/拒绝(含原因)。
4) **Runbook Engine 层**
- 责任:确定性执行 step白名单动作、锁、超时、断言、取消。
5) **Audit/State 层**
- 责任:记录 job/step 状态和执行证据。
6) **AI Advisor可选**
- 责任:建议命令、参数补全、解释结果。
- 限制:**无执行器句柄、无 DB 写权限、无外部动作权限**。
---
## 3. 接入标准
### 3.1 新通道接入(最小接口)
- 实现统一消息输入
- 实现统一回复输出
- 提供身份映射operator_id
> 新通道不允许直接操作 runbook / db。
### 3.2 新功能模块接入(最小接口)
- 注册命令前缀(如 `/cpa` `/cf` `/mail`
- 输入校验
- 构建 runbook 请求name + inputs + meta + policy
> 新模块不允许直接执行 shell/ssh只能请求 runbook 引擎。
### 3.3 当前注册机制
- Parser 按 `/xxx` 自动识别 `module=xxx`
- Registry 支持两种注册:
- 精确命令注册(`Register("/health", ...)`
- 模块前缀注册(`RegisterModule("cpa", ...)`
- 推荐新模块使用 `RegisterModule`,降低接入成本。
---
## 4. AI 介入模式
- `off`:完全关闭 AI默认可用
- `suggest`:允许 AI 给出命令建议,不自动执行
- `explain`:允许 AI 解释结果,不自动执行
### 安全边界
- AI 输出必须是文本建议,不是可执行指令。
- 任何执行动作都需要用户命令触发并通过 Policy Gate。
---
## 5. 统一执行链
`Channel -> Command -> Module.BuildRequest -> Policy.Check -> Runbook.Execute -> Audit -> Reply`
这条链是扩展 CF/Mail 时的唯一合法路径。
---
## 6. 当前状态与后续
### 已具备
- Runbook 引擎(执行/锁/超时/取消)
- CPA 模块status/backup/restore
- 任务审计jobs/steps
- CF/Mail 模块骨架(`/cf status``/mail status` 占位)
### 下一步(框架整理)
1. 将模块内零散 gate 逻辑统一沉淀到 `core/policy`
2. 形成通道适配模板和模块适配模板
3. 引入 `core/ai` 的 Noop Advisor默认 off
4. 在 CF/Mail 骨架上补齐真实 runbook不改核心
### 模块管理可观测性
- 聊天命令:`/ops modules` 查看注册模块与启用状态
- Web 首页:模块状态卡片(读取 `enable_module_*`
- 模块启停:统一通过 feature flag 管理,不改代码路径

View File

@@ -0,0 +1,89 @@
# Ops-Assistant 后端独立化完成清单Phase 1~6
更新日期2026-03-10
---
## 总览
目标:`ops-assistant` 后端从旧 `xiaji-go` 记账心智中独立,形成 Ops 场景可扩展架构。
当前结论:
- ✅ 核心链路已成型:`Command -> Module -> Policy -> Runbook -> Audit -> Reply`
- ✅ 三模块CPA/CF/Mail已纳入统一执行骨架CF/Mail 为安全占位 runbook
- ✅ Ops Web 数据面已具备dashboard/modules/jobs/channels/audit/flags
- ✅ Legacy 兼容层已进入可观测可下线阶段usage/trend/readiness
---
## Phase 状态
## Phase 1API 基础收口
- ✅ 新增/改造接口统一 `{code,message,data}`
- ✅ 导出类接口保留文件流(`/api/v1/export`
- ✅ 失败路径统一 JSON 错误
## Phase 2模块管理后端
-`GET /api/v1/modules`
-`POST /api/v1/modules/:module/toggle`
- ✅ toggle reason 必填
- ✅ toggle 幂等 noop 返回
- ✅ 关键模块保护:禁止禁用 `cpa`
## Phase 3Dashboard 聚合后端
-`GET /api/v1/dashboard/overview`
-`GET /api/v1/dashboard/summary`
- ✅ jobs 列表多维筛选(见 Phase 4
## Phase 4Ops Jobs 能力增强
-`GET /api/v1/ops/jobs` 支持筛选:
- `limit/status/target/runbook/request_id/operator/risk_level/q/from/to`
-`GET /api/v1/ops/jobs/request/:requestID`(含 `total`
-`GET /api/v1/ops/jobs/:id``step_stats/step_total/duration`
-`POST /api/v1/ops/jobs/:id/cancel`reason 必填,状态校验)
-`POST /api/v1/ops/jobs/:id/retry`reason 必填,仅 failed
## Phase 5策略与风控中心化阶段性
-`policy.CheckGate` 作为 gate 核心校验
- ✅ 新增 `policy.ParseCommonFlags`,统一 `--dry-run/--confirm`
- ✅ CPA 移除重复 guard不再分散解析
- ✅ CF/Mail 切到 Runner + Gate + Runbook 模式
- ⏳ 待补:更细粒度 permission/gate 模板化(跨模块统一声明)
## Phase 6兼容层收缩与下线准备
- ✅ legacy 路由包装审计:
- `/api/records`
- `/delete/:id`
- `/export`
- ✅ 访问 legacy 自动写审计:`legacy.route.access`
- ✅ legacy deprecated 响应头:
- `X-API-Deprecated: true`
- `X-API-Replacement`
- `Warning: 299 ...`
- ✅ 迁移观测接口:
- `GET /api/v1/admin/legacy/usage`
- `GET /api/v1/admin/legacy/trend?days=...`
- `GET /api/v1/admin/legacy/readiness?days=...&zero_days=...`
---
## 仍在进行 / 建议下一步
1) Policy 进一步模板化
-`NeedFlag/RequireConfirm/AllowDryRun` 配置抽成模块命令描述,减少模块内手写。
2) Channel Adapter 统一化
- TG/QQ/Feishu 进一步收敛到 `core/ports/channel.go` 统一适配层。
3) Legacy 软下线流程
-`readiness.ready=true` 连续多日后,先灰度关闭 legacy再完全移除路由映射。
4) 发布前整理
- 清理工作区改动并提交;执行 `make release-check`
---
## 关键验证
- 最近多轮 `go build ./cmd/main.go` 均通过(仅 gojieba C++ deprecation warning非阻塞
- 双服务并存策略维持不变:`xiaji-go``ops-assistant` 并行。

123
docs/cf-commands-design.md Normal file
View File

@@ -0,0 +1,123 @@
# CF 命令设计ops-assistant v1
## 目标
为 ops-assistant 提供 Cloudflare DNS 管理能力,保证幂等、安全、可审计。
---
## 1. 命令清单
- `/cf zones`
- 列出可用 Zonename/id
- `/cf dnslist <zone> [name] [type]`
- 示例:`/cf dnslist example.com`
- 示例:`/cf dnslist example.com www A`
- `/cf dnsadd <fqdn> <ip> [--type A/AAAA/CNAME] [--ttl 120] [--proxied on/off]`
- 示例:`/cf dnsadd test.fnos.xx.kg 1.2.3.4`
- `/cf dnsset <fqdn> <ip> [--type A/AAAA/CNAME] [--ttl 120] [--proxied on/off]`
- 存在则更新,不存在则创建
- `/cf dnsdel <fqdn> --type <A/AAAA/CNAME>`
- **必须带 `--type`**
- **需二次确认 `YES`**
- `/cf dnsproxy <fqdn> on|off`
- 仅更新 proxied
- `/cf health`
- Token/权限可用性检查
---
## 2. 权限与安全
- `read` 角色:仅允许 `zones / dnslist / health`
- `admin` 角色:允许所有命令
- `dnsdel` 必须二次确认 `YES`
---
## 3. 参数校验
- `fqdn` 必须属于某个 Zone`<sub>.<zone>`
- `ip` 校验:
- `A` → IPv4
- `AAAA` → IPv6
- `type` 默认 `A`
- `ttl` 默认 `120`
- `proxied` 默认保持原值(仅 dnsproxy/dnsset 明确修改)
---
## 4. 幂等与更新规则
### `/cf dnsadd`
1) 查询同名同类型记录
2) 存在 → 返回“已存在”
3) 不存在 → 创建
### `/cf dnsset`
- 若任一字段不同则更新:
- `content`
- `ttl`
- `proxied`
- content 相同但 ttl/proxied 不同 → 仍执行更新
### `/cf dnsdel`
- 必须带 `--type`
- 仅删除指定 type 记录
---
## 5. 输出规范
### 成功
```
✅ DNS操作成功
- name: <fqdn>
- type: <type>
- content: <ip>
- ttl: <ttl>
- proxied: <true/false>
- id: <record_id>
```
### 已存在
```
DNS记录已存在未变更
- name: <fqdn>
- type: <type>
- content: <ip>
- id: <record_id>
```
### 失败
```
❌ DNS操作失败
- reason: <鉴权/参数/CF错误>
- detail: <error_message>
```
---
## 6. 审计日志(必写)
字段:
- `ts / actor / cmd / zone / fqdn / action / record_id / result / detail`
示例:
```json
{
"ts": "2026-03-14T15:02:10+08:00",
"actor": "kory",
"cmd": "/cf dnsadd test.fnos.xx.kg 1.2.3.4",
"zone": "fnos.xx.kg",
"record_id": "xxxxx",
"action": "create",
"result": "ok",
"detail": {"type":"A","ttl":120,"proxied":false}
}
```

View File

@@ -0,0 +1,39 @@
# CF DNS Runbook 事故复盘2026-03-13
## 背景
在 ops-assistant 中新增 CF 模块命令(/cf dnsadd/dnsset/dnsdel/dnsproxy并进行自测时出现多次失败与反复修复导致进度延误。
## 现象
- `/cf dnsadd test.fnos.xx.kg 127.0.0.1` 连续失败多次。
- Cloudflare API 返回 `Invalid request headers`
- runbook 步骤日志只回显脚本文本,未见真实 API 返回。
## 根因
1) **认证方式误判**
- 将 API Token 误当作 API Key使用了 `X-Auth-Email/X-Auth-Key` 方式,导致 CF 返回 `Invalid request headers`
- 修复后改回 Bearer 才验证 token 可用。
2) **runbook 执行方式不稳定ssh heredoc/转义)**
- runbook 使用 `ssh.exec` 远端执行,命令通过 `bash -lc` + `ssh "..."` 传递。
- heredoc 在多层转义/引用中被破坏,脚本未执行或被 shell 解释掉stderr 只回显脚本内容。
- `python3 -c` 内联也因换行/转义导致 `SyntaxError`
## 卡点分析
- **卡点本质不是 Token**,而是 **远端执行链路中的脚本传递/转义失效**
- 缺少一条稳定的“文本脚本传递”方式,导致同一命令多次失败、定位耗时。
## 最终解决
- 改为 **base64 + python3 -c exec(...)** 的方式传递脚本,避免多层引用与换行问题。
- `/cf dnsadd test.fnos.xx.kg 127.0.0.1` 成功创建记录。
- record id: `acd49e048bc74c1b16d935b69f5aac54`
- job: `27`
## 经验与改进
1) **认证方式先验确认**:明确 Token vs Key 的调用差异。
2) **避免 heredoc 跨 ssh**:优先 `base64|python3``python3 -c` 单行命令。
3) **失败输出必须可见**stderr/stdout 要确保能返回实际 API 响应,禁止“只回显脚本文本”。
4) **阶段性汇报必须带证据**:无日志/产物不使用“完成/已执行”。
## 待办
- 将 dnsset/dnsdel/dnsproxy 全部切换为稳定执行方式base64 + python3 -c
- 评估是否引入 `local.exec`,避免本地项目走 ssh 远端执行。

View File

@@ -0,0 +1,28 @@
# Channel Adapter Template
目标:新通道只做 I/O 适配,不耦合业务执行。
## 责任边界
- 接收平台消息并标准化为统一结构
- 调用 `ops.Service.Handle(...)` 处理命令
- 将文本回复回传到平台
## 禁止事项
- 不在通道内直接执行 shell/ssh/http 运维动作
- 不在通道内做模块业务判断(应交给 command/module
## 最小流程
1. `Normalize(raw)` -> `UnifiedMessage`
2. `handled, out := opsSvc.Handle(msg.OperatorID, msg.Text)`
3. `if handled { Reply(out) }`
4. 未处理消息再回退到历史业务逻辑(如记账)
## 接入检查
- [ ] 仅实现消息适配与回复
- [ ] 已接入 opsSvc.Handle
- [ ] 未绕过 policy/runbook
- [ ] 错误信息对用户可读

View File

@@ -0,0 +1,79 @@
# CF DNS 命令修复与扩展记录2026-03-19
## 背景
用户要求:
- `/cf dnsproxy` 支持直接用域名,例如:`/cf dnsproxy ima.good.xx.kg on`
- `/cf dnsadd` 最后参数用 `on/off` 表示是否开启代理
线上报错:
- `yaml: line 8: did not find expected key`
- `/cf dnsproxy` 解析失败bash: bad substitution
## 改动概览
1) **命令解析**
- `internal/module/cf/commands.go`
- `/cf dnsproxy` 支持 `record_id|name`
- `/cf dnsadd` 支持 `on/off`(兼容 true/false当未提供 on/off 时把第4参数视为类型
2) **帮助文案**
- `internal/module/cf/module.go`
- `internal/core/ops/service.go`
- 更新 `/cf dnsadd``/cf dnsproxy` 的参数示例
3) **runbook 修复**
- `runbooks/cf_dns_proxy.yaml`
- 解决 YAML 行内命令渲染与变量替换问题
- 修复 `${env.INPUT_RECORD_ID}` 未替换导致 bash 报错
- 加入占位值 `__empty__`,避免空变量导致替换缺失
- `update_dns` 中 JSON 通过单引号包裹,避免 shell 分词/换行破坏
4) **ops-runner 支持**
- `cmd/ops-runner/main.go`
- 增加 `/cf dnsproxy` 支持
- `/cf dnsadd` 参数改为 on/off
## 问题与修复记录
### 1. YAML 解析错误
- 现象:`yaml: line 8: did not find expected key`
- 原因runbook 中 command 复杂引号/换行组合导致 YAML 解析失败
- 修复:重写 `cf_dns_proxy.yaml` command 区块
### 2. dnsproxy 变量替换失败
- 现象:`bash: ${env.INPUT_RECORD_ID}: bad substitution`
- 原因输入为空时没有替换占位shell 直接解析 `${env.INPUT_RECORD_ID}`
- 修复InputsFn 总是注入 `record_id/name` 占位值runbook 将 `__empty__` 转为空
### 3. dnsproxy update 失败JSON 被 shell 吞掉)
- 现象:`bash: line 1: true,: command not found`
- 原因:`${steps.resolve_dns.output}` 未加引号JSON 被 shell 拆分
- 修复:`INPUT_JSON='${steps.resolve_dns.output}'`
### 4. dnsadd on/off 支持
- 现象:`DNS record type "on" is invalid`
- 原因:解析逻辑未识别 on/off误当作类型
- 修复InputsFn 与 ops-runner 同步支持 `on/off`
### 5. 测试记录创建失败127.0.0.1
- 现象:`Target 127.0.0.1 is not allowed for a proxied record`
- 处理:改用公网 IP 199.188.198.12
## 测试结果
1) 新增测试记录
```
/cf dnsadd test001.good.xx.kg 199.188.198.12 on
```
- 成功创建proxied=true
2) 代理切换
```
/cf dnsproxy ima.good.xx.kg on
```
- 成功更新proxied=true
## 产物
- 修复代码与 runbook
- 版本化二进制输出dist/ 目录)
## 注意事项
- proxied=on 不能指向 127.0.0.1 等内网回环地址
- runbook command 中 JSON 建议统一使用单引号包裹

View File

@@ -0,0 +1,491 @@
# Ops-Assistant 前端对接文档(给 Gemini
> 目的:让前端可独立完成 ops-assistant 新后台页面,不依赖旧 xiaji 记账页面心智。
> 基址:同源(已登录后直接请求 `/api/v1/*`
> 鉴权Cookie Session`ops_user` + `ops_token`
---
## 0. 统一响应约定(必须)
### 成功
```json
{
"code": "OK",
"message": "ok",
"data": { ... }
}
```
### 失败
```json
{
"code": "ERR_XXX",
"message": "可读错误信息"
}
```
### 前端统一处理建议
- `if (!res.ok)`: 显示 `message`
- `if (res.ok)`: 使用 `data`
- 不再使用 `error/status` 老字段
> 例外:`GET /api/v1/export` 成功是文件流下载,不是 JSON。
---
## 1. 权限与用户信息
### 1.1 获取当前用户
**GET** `/api/v1/me`
### data 字段
- `username`
- `role`
- `user_id`
- `permissions[]`
- `flags{}`
- `effective_capabilities{}`
### capability 常用键
- `can_view_ops`
- `can_cancel_ops`
- `can_retry_ops`
- `can_view_flags`
- `can_edit_flags`
- `can_view_channels`
- `can_edit_channels`
- `can_test_channels`
- `can_view_audit`
前端应以 capability 驱动按钮显隐。
---
## 2. Dashboard新后台首页主数据
### 2.1 获取总览
**GET** `/api/v1/dashboard/overview`
### 返回 data
```json
{
"jobs": {
"recent": [OpsJob...],
"status_count": {
"pending": 0,
"running": 0,
"success": 0,
"failed": 0,
"cancelled": 0
}
},
"modules": [
{"module":"cpa","enabled":true},
{"module":"cf","enabled":false},
{"module":"mail","enabled":false}
],
"channels": [
{"platform":"telegram","enabled":true,"status":"ok"}
]
}
```
### 2.2 获取轻量摘要(推荐首页首屏)
**GET** `/api/v1/dashboard/summary`
### 返回 data
```json
{
"jobs": {
"total": 120,
"running": 2,
"failed": 5,
"success": 98
},
"modules": {
"cpa": true,
"cf": false,
"mail": false
}
}
```
---
## 3. 模块管理Module Center
### 3.1 模块列表
**GET** `/api/v1/modules`
### 返回 data
```json
{
"modules": [
{
"module":"cpa",
"display_name":"CPA 管理",
"flag_key":"enable_module_cpa",
"enabled":true
}
]
}
```
### 3.2 切换模块开关
**POST** `/api/v1/modules/:module/toggle`
- `:module` 仅支持:`cpa|cf|mail`
### body
```json
{
"enabled": true,
"reason": "前端联调启用"
}
```
### 成功 data
```json
{
"module": "cf",
"flag_key": "enable_module_cf",
"old": false,
"new": true
}
```
### 交互建议
- 操作前确认弹窗
- 必填 reason
- 成功后刷新 `/api/v1/modules``/api/v1/dashboard/overview`
---
## 4. Ops 任务中心
### 4.1 任务列表
**GET** `/api/v1/ops/jobs?limit=50`
支持筛选 query
- `status`pending|running|success|failed|cancelled
- `target`(如 hwsg
- `runbook`(如 cpa_usage_backup
- `request_id`
- `operator`(操作者 user_idint64
- `risk_level`low|medium|high 等)
- `q`(模糊检索,命中 command/runbook/target/request_id
- `from`RFC3339按 created_at 下界过滤)
- `to`RFC3339按 created_at 上界过滤)
### data
```json
{
"jobs": [OpsJob...],
"filters": {
"limit": 50,
"status": "failed",
"target": "hwsg",
"runbook": "cpa_usage_restore",
"request_id": "ops-u1-1741563000",
"operator": "1",
"risk_level": "high",
"q": "restore",
"from": "2026-03-10T07:00:00+08:00",
"to": "2026-03-10T08:00:00+08:00"
}
}
```
### 4.2 按 request_id 反查任务
**GET** `/api/v1/ops/jobs/request/:requestID?limit=50`
### data
```json
{
"request_id":"req-20260310-abc",
"total": 3,
"jobs":[OpsJob...]
}
```
### 4.3 任务详情(含步骤 + 聚合统计)
**GET** `/api/v1/ops/jobs/:id`
### data
```json
{
"job": { ... },
"steps": [
{
"step_id":"...",
"action":"ssh.exec",
"status":"success|failed|running",
"stdout_tail":"...",
"stderr_tail":"..."
}
],
"step_stats": {
"running": 0,
"success": 3,
"failed": 1,
"skipped": 0
},
"step_total": 4,
"duration": {
"job_ms": 5321,
"steps_ms_sum": 4870
}
}
```
### 4.4 取消任务
**POST** `/api/v1/ops/jobs/:id/cancel`
body:
```json
{"reason":"人工终止,参数配置错误"}
```
### data
```json
{"id":123,"reason":"人工终止,参数配置错误"}
```
### 4.5 重试任务
**POST** `/api/v1/ops/jobs/:id/retry`
body:
```json
{"reason":"修复配置后重试"}
```
### data
```json
{"old_job_id":123,"new_job_id":456,"reason":"修复配置后重试"}
```
### 前端权限
- cancel 按钮:`can_cancel_ops`
- retry 按钮:`can_retry_ops`
### 交互约束
- cancel/retry 必须填写 reason后端强校验
- retry 仅允许 failed 状态任务
- cancel 仅允许 pending/running 状态任务
- `from/to` 参数必须是 RFC3339`2026-03-10T07:00:00+08:00`
---
## 5. 通道管理Channels
### 5.1 通道列表
**GET** `/api/v1/admin/channels`
### data
```json
{
"channels": [
{
"platform":"telegram",
"name":"Telegram Bot",
"enabled": true,
"status":"ok",
"config_json":"{}",
"draft_config_json":"{}",
"secrets":"{\"token\":\"***\"}",
"draft_secrets":"{}",
"has_draft": false
}
]
}
```
### 5.2 更新草稿
**PATCH** `/api/v1/admin/channels/:platform`
body 可包含:
- `name`
- `enabled`
- `config`
- `secrets`
### 5.3 发布草稿
**POST** `/api/v1/admin/channels/:platform/publish`
### 5.4 热加载
**POST** `/api/v1/admin/channels/reload`
### 5.5 一键全禁用
**POST** `/api/v1/admin/channels/disable-all`
### 5.6 启用/禁用单通道
- **POST** `/api/v1/admin/channels/:platform/enable`
- **POST** `/api/v1/admin/channels/:platform/disable`
### 5.7 连通性测试
**POST** `/api/v1/admin/channels/:platform/test`
### 5.8 原子应用patch + publish + reload
**POST** `/api/v1/admin/channels/:platform/apply`
> apply 失败 message 中可能包含 stage 信息patch/publish/reload
---
## 6. 审计日志
### 6.1 查询审计
**GET** `/api/v1/admin/audit`
支持 query
- `action`
- `target_type`
- `result`
- `actor_id`
- `from` (RFC3339)
- `to` (RFC3339)
- `limit` (默认100最大500)
- `offset`
### data
```json
{ "logs": [AuditLog...] }
```
---
## 7. 风险开关Flags
### 7.1 列表
**GET** `/api/v1/admin/settings/flags`
### data
```json
{ "flags": [FeatureFlag...] }
```
### 7.2 修改
**PATCH** `/api/v1/admin/settings/flags/:key`
body:
```json
{ "enabled": true, "reason": "..." }
```
> 部分 flag `RequireReason=true`reason 为空会失败。
---
## 8. 兼容层(前端新代码不要用)
以下仅兼容旧页面:
- `GET /api/records`
- `POST /delete/:id`
- `GET /export`
新前端一律使用 `/api/v1/*`
### 8.1 Legacy 使用统计(用于迁移观察)
**GET** `/api/v1/admin/legacy/usage`
### data
```json
{
"summary": [
{"route":"/api/records","count":12},
{"route":"/delete/:id","count":3},
{"route":"/export","count":1}
],
"recent": [AuditLog...]
}
```
### 8.2 Legacy 调用趋势(按天)
**GET** `/api/v1/admin/legacy/trend?days=7`
- `days` 范围:`1~90`,默认 `7`
### data
```json
{
"days": 7,
"from": "2026-03-04T00:00:00+08:00",
"trends": [
{
"route": "/api/records",
"points": [
{"day":"2026-03-04","count":2},
{"day":"2026-03-05","count":1}
]
}
]
}
```
### 8.3 Legacy 响应头(便于前端观察迁移)
访问旧路由时,响应头会包含:
- `X-API-Deprecated: true`
- `X-API-Replacement: <对应新路由>`
- `Warning: 299 - "legacy API deprecated, use ..."`
### 8.4 Legacy 下线就绪评估
**GET** `/api/v1/admin/legacy/readiness?days=7&zero_days=3`
- `days`观察窗口1~90默认 7
- `zero_days`:要求连续 0 调用天数1~30默认 3
### data
```json
{
"days": 7,
"zero_days": 3,
"window_total": 0,
"route_totals": {
"/api/records": 0,
"/delete/:id": 0,
"/export": 0
},
"consecutive_zero_days": {
"/api/records": 7,
"/delete/:id": 7,
"/export": 7
},
"ready": true,
"recommendation": "可考虑下线 legacy 路由已满足连续0调用阈值"
}
```
---
## 9. 前端落地建议(给 Gemini
1. 建立统一 `apiClient`
- `request(url, options)`
- 自动解析 `{code,message,data}`
- 非 2xx 抛 message
2. 页面优先级:
- P1Dashboardoverview + summary
- P1Ops Jobs
- P1Modules
- P2Channels
- P2Audit
3. 权限驱动 UI
- 所有按钮显隐由 `effective_capabilities` 控制
4. 状态刷新策略:
- dashboard 每 10~20s 轮询
- ops jobs running 状态 5~10s 轮询
5. 错误展示:
- toast + message 文本
- 不展示后端堆栈
---
## 10. 已知限制
- export 成功仍为文件流(设计如此)。
- gojieba 编译 warning 可忽略(非功能错误)。

View File

@@ -0,0 +1,98 @@
# Ops-Assistant 前后端联调检查清单(给前端/Gemini
更新日期2026-03-10
---
## A. 统一基础
- [ ] 所有请求走 `/api/v1/*`(禁用新代码调用 legacy 路由)
- [ ] `apiClient` 统一解析 `{code,message,data}`
- [ ] 全局错误 toast 仅展示 `message`
- [ ] 鉴权失败统一跳转登录
---
## B. 登录后初始化
- [ ]`GET /api/v1/me`
- [ ]`effective_capabilities` 控制页面和按钮显隐
- [ ] 没有权限时不渲染可操作按钮
---
## C. Dashboard
- [ ] 首屏并行请求:
- `GET /api/v1/dashboard/summary`
- `GET /api/v1/dashboard/overview`
- [ ] 状态卡片展示 jobs 统计、模块状态、通道状态
- [ ] 10~20 秒轮询刷新
---
## D. Modules 页面
- [ ] 列表:`GET /api/v1/modules`
- [ ] 开关:`POST /api/v1/modules/:module/toggle`
- [ ] reason 必填
- [ ] 处理 `message=noop`
- [ ] cpa 禁用失败提示
- [ ] 成功后刷新 modules + overview
---
## E. Ops Jobs 页面
- [ ] 列表:`GET /api/v1/ops/jobs`
- [ ] 支持筛选字段:
- [ ] status
- [ ] target
- [ ] runbook
- [ ] request_id
- [ ] operator
- [ ] risk_level
- [ ] q
- [ ] from/toRFC3339
- [ ] 展示后端回显的 `filters`
- [ ] 详情:`GET /api/v1/ops/jobs/:id`
- [ ] step_stats
- [ ] step_total
- [ ] duration.job_ms / duration.steps_ms_sum
- [ ] request_id 反查:`GET /api/v1/ops/jobs/request/:requestID`
- [ ] cancel/retry
- [ ] reason 必填
- [ ] 按权限按钮显隐can_cancel_ops / can_retry_ops
---
## F. Channels 页面
- [ ] `GET /api/v1/admin/channels`
- [ ] patch/publish/reload/apply 流程联通
- [ ] secrets 脱敏显示并正确提交
---
## G. Audit 页面
- [ ] `GET /api/v1/admin/audit`
- [ ] 支持 from/to、action、target_type、result、actor_id
---
## H. Legacy 迁移看板(管理页)
- [ ] `GET /api/v1/admin/legacy/usage`
- [ ] `GET /api/v1/admin/legacy/trend?days=7`
- [ ] `GET /api/v1/admin/legacy/readiness?days=7&zero_days=3`
- [ ] 显示 `ready` + `recommendation`
---
## I. 验收标准
- [ ] 前端无新代码依赖 legacy 路由
- [ ] 所有核心页面可在 ops-assistant 独立运行
- [ ] 权限控制、错误处理、轮询刷新行为正常
- [ ] readiness 达标后可计划 legacy 下线窗口

View File

@@ -0,0 +1,37 @@
# Module Adapter Template
目标:新功能模块以最小改动接入 `ops-assistant`
## 必备文件
- `internal/module/<name>/module.go`
- `runbooks/<name>_*.yaml`
## 推荐实现
1.`module.go` 内解析命令前缀(如 `/cf`
2. 构建 `core/module.Request`
3. 统一调用 `core/module.Runner.Run(...)`
4. 所有 gateflag/confirm/dry-run通过 `Request.Gate` 声明
## 最小示例(伪代码)
```go
req := coremodule.Request{
RunbookName: "cf_dns_upsert",
Inputs: map[string]string{"zone": zone, "name": name},
Meta: runbook.RunMeta{Target:"cf", RiskLevel:"medium"},
Gate: coremodule.Gate{NeedFlag:"allow_cf_write", RequireConfirm:true, ExpectedToken:"YES_CF", AllowDryRun:true},
DryRun: dryRun,
ConfirmToken: confirm,
}
jobID, out, err := runner.Run(cmd.Raw, userID, req)
```
## 接入检查
- [ ] 命令不直接执行 shell/ssh
- [ ] 使用统一 Runner
- [ ] 风险操作有 Gate
- [ ] 返回 job_id 可追踪
- [ ] runbook step 可审计

View File

@@ -0,0 +1,72 @@
# Ops-Assistant 多平台渠道配置与回调部署说明
## 已支持平台
- 官方 QQ Botqqbot_official
- Telegram Bottelegram
- 飞书 Botfeishu
## 配置优先级
- 启动时:`数据库 channel_configs` > `config.yaml`
- 建议使用后台页面维护渠道配置:`/channels`
## 后台入口
- 渠道配置页:`/channels`
- 渠道 API
- `GET /api/v1/admin/channels`
- `PATCH /api/v1/admin/channels/:platform`
- `POST /api/v1/admin/channels/:platform/test`
- 审计查询:`GET /api/v1/admin/audit`
## 回调地址
- 飞书 webhook: `POST /webhook/feishu`
### 飞书事件订阅配置
1. 在飞书开发者后台启用事件订阅
2. 请求网址填:`https://<你的域名>/webhook/feishu`
3. 订阅事件:`im.message.receive_v1`
4.`verification_token``app_id``app_secret` 写入渠道 secrets JSON
## 渠道 secrets JSON 示例
### telegram
```json
{
"token": "123456:ABCDEF"
}
```
### qqbot_official
```json
{
"appid": "102857798",
"secret": "xxxxxx"
}
```
### feishu
```json
{
"app_id": "cli_xxx",
"app_secret": "xxx",
"verification_token": "xxx",
"encrypt_key": "optional"
}
```
## 连接测试说明
- Telegram调用 `getMe`
- QQ调用 `getAppAccessToken`
- 飞书:调用 `tenant_access_token/internal`
测试成功会把渠道状态写成 `ok`,失败写成 `error`
## 幂等去重
- 三平台入站统一落 `message_dedup`,避免重复处理:
- telegram: `tg:<update_id>`
- qqbot_official: `qq:<type>:<message_id>`
- feishu: `event_id`(回退 message_id
## 运行建议
- 对公网暴露前请加 HTTPS飞书回调必需
- 建议将管理后台放在内网或反代鉴权后访问
- 定期审计 `audit_logs` 里渠道配置修改记录

200
docs/ops-assistant-v1.md Normal file
View File

@@ -0,0 +1,200 @@
# Ops Assistant 独立项目 v1 方案
## 目标
把高频运维动作做成**固定命令 + 固定流水线**AI 只负责解释,不参与关键执行决策。
---
## v1 范围(先做)
优先只落地 **CPA 管理中枢**
1. 固定命令入口Telegram/QQ/飞书统一)
2. RunbookYAML确定性执行器
3. 审计日志(步骤级)
4. 高风险能力默认关闭Feature Flag
后续再扩展Cloudflare DNS、邮箱转发。
---
## 目录结构(新增)
```text
ops-assistant/
├── internal/
│ ├── core/
│ │ ├── command/ # 命令解析
│ │ ├── registry/ # 命令注册与路由
│ │ ├── runbook/ # runbook 结构、执行器、锁、target 解析
│ │ └── ops/ # ops 服务编排、重试
│ └── module/
│ └── cpa/ # CPA 模块命令与高风险闸门
├── runbooks/
│ ├── cpa_status.yaml
│ ├── cpa_usage_backup.yaml
│ └── cpa_usage_restore.yaml
└── docs/
└── ops-assistant-v1.md
```
---
## 命令清单v1
- `/cpa status`
- `/cpa usage backup`
- `/cpa usage restore <backup_id>`
- `/cpa codex clean`
- `/cpa codex test`
- `/cpa codex isolate`
### 约束
- 仅允许上述命令(严格白名单)
- 每个命令映射到唯一 runbook
- 不支持自由 shell 指令输入
---
## Runbook DSLv1
仅支持这些动作:
- `ssh.exec`:远程执行固定命令
- `http.get` / `http.post`:调用固定接口
- `file.upload`:上传压缩包到 staging
- `file.extract`:解压到 staging
- `assert.json`:断言字段值
- `sleep`:延迟
每个步骤必须有:
- `id`
- `action`
- `on_fail``stop` | `continue`
所有变量只能来自:
- `inputs.*`(命令参数)
- `env.*`(服务端配置)
- `steps.<id>.output.*`(前置步骤输出)
---
## 审计与可追溯
建议新增两张表:
### 1) `ops_jobs`
- `id`
- `command`
- `runbook`
- `operator_id`
- `status`pending/running/success/failed
- `started_at`
- `ended_at`
### 2) `ops_job_steps`
- `id`
- `job_id`
- `step_id`
- `action`
- `status`
- `rc`
- `stdout_tail`
- `stderr_tail`
- `started_at`
- `ended_at`
> 所有 Bot 命令回执都返回 `job_id`,便于追踪。
---
## 风险控制
- 默认 `dry-run=true`(先演练)
- 高风险步骤restore/import必须
- 双确认(命令 + confirm token
- feature flag 开启才允许执行
- 审计日志不写明文 secrets
- 全部 secrets 走现有 `channel` 加密机制存储
---
## 与现有系统的集成点(独立项目并存)
1. **Bot 层**:在 Telegram/QQ/飞书消息处理中增加 `/cpa` 命令分流
2. **Web 层**:新增 `/ops` 页面查看任务状态与步骤日志
3. **模型层**:新增 `ops_jobs` / `ops_job_steps`
4. **配置层**:增加 `ops.targets`(如 hwsg/wjynl
---
## 阶段性进度汇报原则(必须遵守)
**模板(四要素)**
1) 阶段名(设计/实现/自测/上线等)
2) 已执行动作(具体到做了什么)
3) 可验证证据(日志、产物路径、返回码、截图等)
4) 下一步与前置条件(还差什么、需谁确认)
**硬规则**
- 无证据不使用“完成/已执行/进行中”等措辞
- 遇到卡点必须立即说明:卡点 + 原因 + 需要的唯一输入
- 先清单后执行的任务,未确认不得执行
---
## 事故复盘2026-03-13CF DNS Runbook
详见:`docs/cf-dns-runbook-incident-20260313.md`
要点摘要:
- 认证方式误判API Token 被当作 API Key
- heredoc/转义在 ssh.exec 中导致脚本未执行。
- 最终采用 base64 + python3 -c exec 稳定执行。
- 强化“阶段性汇报必须带证据”的纪律。
---
## 验收标准v1
1. `/cpa status` 能返回结构化结果(非自由文本)
2. `/cpa usage backup` 能输出:备份路径 + sha256 + usage 快照
3. `/cpa usage restore <id>` 支持双校验(立即 + 延迟)
4. 任一步骤失败时可追溯到具体 step 日志
5. 未授权命令必须被拒绝并记录审计
---
## 当前已落地2026-03-10
1. 已打通命令入口Telegram / QQ / 飞书
2. 已支持命令:
- `/cpa status`
- `/cpa usage backup`
- `/cpa usage restore <backup_id>`
3. 已提供查询接口:
- `GET /api/v1/ops/jobs`
- `GET /api/v1/ops/jobs/:id`(含 steps
4. `assert.json` 已支持真实 JSON 路径断言
5. 已增加安全闸门:
- `allow_ops_restore` feature flag默认 false
- restore 需要 `--confirm YES_RESTORE`
- 支持 `--dry-run`
6. 已支持 `ops_targets` 目标主机表(优先解析 target 名称)
## 当前 Core 强化2026-03-10 第二阶段)
1. 同 target 串行锁(避免并发覆盖)
2. 作业元信息增强:`target/risk_level/request_id/confirm_hash`
3. 统一错误码前缀(如 `ERR_FEATURE_DISABLED` / `ERR_CONFIRM_REQUIRED` / `ERR_STEP_FAILED`
4. step 超时控制(默认 45s
5. 任务取消接口:`POST /api/v1/ops/jobs/:id/cancel`
## 下一步落地建议
1. 为取消操作增加权限细分(`ops.cancel`
2. 增加 job 重试接口(仅失败任务可重试)
3. 增加步骤级超时配置runbook 可覆盖)
4. 增加 Cloudflare / Mail 模块(在 Core 验收完成后)