kt-template-online-api/docs/superpowers/specs/2026-06-18-admin-environment-dashboard-design.md

588 lines
20 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.

# Admin 全环境状态总览总控面板设计
## 背景
Admin 当前 `/dashboard/analytics` 仍是 Vben 示例页,展示用户量、访问量、下载量和图表等静态演示数据。它没有反映线上真实环境,也不能帮助判断 API、QQBot、NapCat、插件平台、系统日志、MinIO、WordPress、Jenkins/K8s 等链路的当前状态。
用户已确认将分析页改造成线上全环境状态总览总控面板,并选择方案 B**总览 + 安全总控**,同时增加**环境拓扑**作为主视图。这个页面的目标不是“再做一个漂亮 Dashboard”而是把线上环境状态、证据来源、可执行的低风险动作和高风险动作边界集中展示出来让后续排障、上线观察和 QQBot 闭环不再靠散落入口。
本设计基于主线程和两个只读 subagent 的盘点结果:
- Admin `/dashboard/analytics` 当前是静态页面,可整体替换。
- Admin 已有 QQBot、插件任务、系统日志、Blog/Asset 等 API wrapper但没有统一环境状态 wrapper。
- API 已有 runtime health、系统日志、QQBot 汇总、NapCat runtime、插件平台、插件任务、MinIO 和 WordPress 信号源。
- API 源码内没有 Jenkins/K8s/部署状态 Controller 或 Service实时部署观察目前主要靠 `mcp/ktWorkflow` 与 NAS/K8s 外部命令。
因此第一版必须采用“API 统一聚合合同 + Admin 拓扑消费”的结构页面不散拼多个旧接口API 不伪造未接入的环境状态;高风险动作先显式禁用或跳转,不直接执行。
## 已确认决策
1. `/dashboard/analytics` 改造成环境状态总览总控面板,不继续保留 Vben 示例图表。
2. 采用方案 B顶部总览、环境拓扑、右侧安全总控、底部最近事件/证据。
3. 环境拓扑必须是第一屏核心区域展示从入口、网关、Admin、API、数据层、对象存储、日志、WordPress、QQBot、NapCat、插件平台、定时任务到 Jenkins/K8s 的链路。
4. 第一版只允许低风险动作:刷新、执行只读自检、打开日志、跳转到已有管理页、打开外部只读入口。
5. 重启 Pod、触发 Jenkins 部署、DB 写入、重建 NapCat 容器、启停插件或定时任务等高风险动作,第一版只能作为 disabled action 展示原因和未来入口。
6. API 聚合接口必须受 Admin JWT 保护,返回 Vben 统一响应不泄露密钥、token、原始 env、QQBot 大字段或未脱敏日志。
7. Jenkins/K8s 如果暂时没有可由 API 安全读取的凭据或适配器,也必须在拓扑中显示为 `unknown` / `unwired`,不能从页面消失或伪造成正常。
## 目标
- 将 Admin 分析页变成可用于线上日常观察的环境总览入口。
- 提供统一 API 合同,输出状态卡片、拓扑节点、拓扑边、操作目录和最近事件。
- 把现有分散信号源收敛到一个只读聚合服务,保持每个信号源可独立降级。
- 在 UI 上明确区分 `ok`、`degraded`、`down`、`blocked`、`unknown`、`unwired`。
- 用证据字段解释每个状态来自哪里、何时检查、是否实时、是否缓存、失败原因是什么。
- 为后续接入 Jenkins/K8s 只读观测、部署记录、任务运行历史和自动化恢复留出合同扩展点。
## 非目标
- 不在第一版执行部署、重启、数据库写入、插件启停、NapCat 容器重建等高风险动作。
- 不把 Admin 页面做成营销式图表页或静态展示页。
- 不绕过现有 QQBot、NapCat、插件平台、WordPress、MinIO 的业务边界。
- 不要求 API Pod 内直接持有生产 kubeconfig、Jenkins 写权限或 NAS SSH 写权限。
- 不把外部不可读的 Jenkins/K8s 状态假装成健康。
- 不在本轮新增长期运行的后台巡检任务或历史表,除非后续实施计划明确需要。
## 信息架构
页面仍使用 `/dashboard/analytics` 路由,但语义改为“环境总览”。布局从上到下为:
1. **全局状态条**
- 当前环境总体状态。
- 最近检查时间。
- 降级节点数量。
- 阻断节点数量。
- 未接入节点数量。
- 一键刷新和只读自检入口。
2. **核心指标卡**
- API Runtime。
- 日志/Loki。
- QQBot 在线账号与发送状态。
- NapCat 登录态/容器态。
- 插件平台与定时任务。
- 存储/WordPress。
- 部署链路。
3. **环境拓扑主视图**
- 使用横向分层拓扑,不使用营销图表。
- 节点展示状态、短指标、来源标识和最近检查时间。
- 边展示调用关系、依赖关系或部署关系。
- 点击节点打开右侧证据抽屉。
4. **安全总控面板**
- 展示 action catalog。
- 可执行项仅限刷新、只读自检、打开日志、跳转页面、打开外链。
- 高风险项以 disabled 状态展示原因、所需权限和后续实施条件。
5. **最近事件/证据流**
- 聚合系统日志状态、插件 runtime event、QQBot/NapCat 关键错误摘要。
- 不展示 QQBot `replyText`、base64 图片、大段日志正文或敏感配置。
## 环境拓扑
第一版拓扑节点按区域分组:
```text
入口层
admin.kwitsukasa.top / blog / API public route
-> Caddy / TLS / reverse proxy
前端层
-> Admin static site
-> Blog public frontend
服务层
-> API Runtime
-> Runtime Config
-> Auth/Admin Platform Config
数据与观测层
-> MySQL
-> Redis / BullMQ
-> Loki / System Logs
-> MinIO
-> WordPress
QQBot 层
-> QQBot Core
-> OneBot Reverse WS
-> NapCat Accounts
-> Plugin Platform
-> Plugin Scheduled Tasks
部署层
-> Jenkins
-> K8s Deployment
-> API Pod
```
节点的状态来源分为:
- `live`API 当前请求中实时读取。
- `cached`API 使用已有缓存或短 TTL 运行态证据。
- `derived`:从其他信号推导,例如 QQBot 汇总推导 bus 状态。
- `configured`:只知道配置存在或缺失。
- `external-link`只能提供外部入口API 不能直接读取。
- `unwired`:设计中必须存在,但当前未接入真实信号。
拓扑节点不得因为没有接入真实读取就隐藏。未接入的 Jenkins/K8s 节点第一版应显示为 `unknown``unwired`并在证据抽屉写明“API 当前没有只读观测适配器”。
## API 合同
新增受保护接口:
```text
GET /system/environment/dashboard
POST /system/environment/self-check
```
`GET /system/environment/dashboard` 返回当前聚合状态。`POST /system/environment/self-check` 只执行同一批只读检查,不执行写入、重启、部署或容器重建;它可以返回新的检查结果和本次 `checkRunId`,但第一版不要求落库。
建议目录:
```text
src/modules/admin/platform-config/environment-dashboard/
contract/
environment-dashboard.controller.ts
dto/
environment-dashboard.dto.ts
application/
environment-dashboard.service.ts
environment-dashboard-status.mapper.ts
environment-dashboard-action.catalog.ts
domain/
environment-dashboard.types.ts
infrastructure/
environment-dashboard-signal.collector.ts
```
该模块属于 Admin Platform Config因为它面向后台环境观测和安全总控不属于 QQBot、Blog、Asset 任一业务域。
### DTO
```ts
type EnvironmentHealthStatus =
| 'ok'
| 'degraded'
| 'down'
| 'blocked'
| 'unknown'
| 'unwired';
interface EnvironmentDashboardDto {
checkedAt: string;
checkRunId: string;
overallStatus: EnvironmentHealthStatus;
summaryCards: EnvironmentSummaryCardDto[];
topology: EnvironmentTopologyDto;
actions: EnvironmentActionDto[];
recentEvents: EnvironmentEventDto[];
}
interface EnvironmentSummaryCardDto {
key: string;
title: string;
status: EnvironmentHealthStatus;
primaryMetric: string;
secondaryMetric?: string;
source: EnvironmentSignalSourceDto;
route?: string;
}
interface EnvironmentTopologyDto {
nodes: EnvironmentNodeDto[];
edges: EnvironmentEdgeDto[];
}
interface EnvironmentNodeDto {
id: string;
label: string;
group: 'entry' | 'frontend' | 'service' | 'data' | 'observability' | 'qqbot' | 'deploy';
status: EnvironmentHealthStatus;
sourceKind: 'live' | 'cached' | 'derived' | 'configured' | 'external-link' | 'unwired';
metrics: EnvironmentMetricDto[];
evidence: EnvironmentEvidenceDto[];
links: EnvironmentNodeLinkDto[];
lastCheckedAt?: string;
}
interface EnvironmentEdgeDto {
id: string;
source: string;
target: string;
relation: 'routes-to' | 'depends-on' | 'observes' | 'deploys' | 'connects';
status: EnvironmentHealthStatus;
}
interface EnvironmentActionDto {
key: string;
label: string;
description: string;
kind: 'refresh' | 'self-check' | 'open-route' | 'open-url' | 'disabled-future';
riskLevel: 'safe' | 'medium' | 'high';
enabled: boolean;
targetRoute?: string;
targetUrl?: string;
disabledReason?: string;
requiredPermission?: string;
}
interface EnvironmentEventDto {
id: string;
source: string;
level: 'info' | 'warn' | 'error' | 'fatal';
title: string;
message: string;
happenedAt: string;
route?: string;
}
```
实现时应使用项目现有 class DTO 风格,不需要逐字照搬 interface上述结构是合同语义。
### 状态归一规则
- `ok`:信号源明确可用,关键指标正常。
- `degraded`:信号源可读,但存在局部异常,例如少量账号离线、日志查询降级、插件部分失败。
- `down`:信号源明确不可用,例如 MinIO 检查失败、WordPress auth check 失败。
- `blocked`:存在会阻断业务闭环的问题,例如 API runtime 配置缺失、QQBot worker 阻塞。
- `unknown`:检查失败、超时或没有足够证据判断。
- `unwired`:设计上存在该节点,但当前版本尚未接入读取能力。
总体状态按严重度聚合:
```text
blocked > down > degraded > unknown/unwired > ok
```
`unknown``unwired` 不应覆盖真实 `down``blocked`,但必须在 UI 上单独计数,避免被误认为健康。
## 信号源映射
### Runtime/API
来源:
- `RuntimeHealthService.getRuntimeHealth()`
- `RuntimeConfigService` 配置检查结果
节点:
- API Runtime
- Runtime Config
- MySQL
- Loki configured
- MinIO configured
- WordPress configured
- QQBot/NapCat configured
注意:
- `/health/runtime` 是无鉴权 plain JSON新的 Admin 聚合接口不能直接 HTTP 调自己,应直接调用 service。
- 返回给 Admin 的证据必须脱敏,保留 configured/missing 语义即可。
### 系统日志/Loki
来源:
- `SystemLogService`
- `/system/logs/status`
- `/system/logs/summary`
节点:
- Loki / System Logs
事件:
- 最近错误等级摘要。
- 日志查询状态。
注意:
- 不返回大段原始日志。
- 页面跳转到现有系统日志页面时可附带 level/source filter。
### QQBot Core / NapCat
来源:
- `QqbotDashboardService.summary()`
- `QqbotAccountService` 或账号列表已有 runtime append 结果
- `QqbotNapcatAccountRuntimeService`
- NapCat runtime detail 现有摘要
节点:
- QQBot Core
- OneBot Reverse WS
- NapCat Accounts
指标:
- 账号总数。
- 在线账号数。
- 启用账号数。
- 发送成功/失败。
- bus/runtime 状态。
- NapCat 容器/WebUI/QQ 登录态分布。
注意:
- 账号列表可能触发 runtime TTL 检查,聚合服务需要短超时和并发限制。
- OneBot reverse WS 心跳不能被当作 QQ 登录成功拓扑证据必须区分容器、OneBot、WebUI、QQ 登录态。
### 插件平台与定时任务
来源:
- Plugin Platform installations/capabilities/operations/runtime events。
- Plugin Task page/status service。
节点:
- Plugin Platform
- Plugin Operations
- Plugin Scheduled Tasks
指标:
- 已安装插件数量。
- enabled 插件数量。
- operation 数量。
- worker/runtime event 最近异常。
- 定时任务总数、启用数、最近失败数。
注意:
- 第一版面板不执行插件 enable/disable、task run、cron 修改。
- 相关操作只跳转到插件管理或插件任务页。
### MinIO / Asset
来源:
- `MinioClientService.checkConnection(bucketName?)`
- `/minio/check` 现有能力对应的 service。
节点:
- MinIO
指标:
- bucket 名称。
- bucket 是否存在。
- 连接检查状态。
注意:
- 不在 Dashboard 创建 bucket。
- `createAssetBucket`、上传、删除都不是第一版安全动作。
### WordPress / Blog
来源:
- `WordpressService.checkAuth()`
- WordPress theme/blog theme config 读取能力。
节点:
- WordPress
- Blog Frontend
指标:
- WordPress auth check。
- theme config 读取状态。
- public blog route 可用性如果 API 内有 service 可读,则作为 live否则第一版仅展示 configured/external-link。
注意:
- 不执行 WordPress import、sync 或写入。
### Jenkins / K8s / NAS
来源:
- 第一版默认 `unwired` / `external-link`
- 如果后续配置只读 Jenkins token、只读 K8s service account 或 deploy-observation evidence 文件,才能升级为 `live``cached`
节点:
- Jenkins
- K8s Deployment
- API Pod
- NAS Runtime
第一版行为:
- 拓扑上显示节点。
- 提供外部链接或“未配置只读观测适配器”的证据。
- 高风险动作如“触发部署”“重启 Pod”“查看敏感 Secret”全部 disabled。
后续扩展:
- 新增只读 deploy evidence adapter。
- 读取最近 Jenkins build number、commit、result。
- 读取 K8s deployment generation/ready/updated/pod restartCount。
- 只读证据仍必须脱敏,不暴露 kubeconfig、token、Secret。
## 安全总控 Action Catalog
第一版 enabled actions
- `refresh-dashboard`:重新请求 dashboard。
- `run-readonly-self-check`:调用 `POST /system/environment/self-check`,只执行只读检查。
- `open-system-logs`:跳转系统日志页。
- `open-qqbot-dashboard`:跳转 QQBot Dashboard。
- `open-napcat-runtime`:跳转 NapCat runtime/账号详情相关页面。
- `open-plugin-platform`:跳转插件平台页。
- `open-plugin-tasks`:跳转插件任务页。
- `open-asset-page`:跳转资产/MinIO 相关页面。
- `open-wordpress-page`:跳转 Blog/WordPress 管理页。
- `open-jenkins`:如果配置外链则打开 Jenkins。
- `open-k8s-dashboard`:如果配置外链则打开 K8s Dashboard。
第一版 disabled actions
- `restart-api-pod`
- `trigger-jenkins-deploy`
- `run-db-migration`
- `recreate-napcat-container`
- `plugin-enable-disable`
- `plugin-task-run-once`
- `minio-create-bucket`
- `wordpress-import`
每个 disabled action 必须返回:
- `riskLevel: 'high'`
- `enabled: false`
- `disabledReason`
- `requiredPermission`
- 后续所需安全条件,例如二次确认、审计日志、回滚路径、只读预检。
## 前端设计
改造位置:
```text
apps/web-antdv-next/src/views/dashboard/analytics/index.vue
apps/web-antdv-next/src/views/dashboard/analytics/components/
apps/web-antdv-next/src/api/system/environment.ts
```
路由:
- 保留 `/dashboard/analytics`,避免菜单和固定 tab 入口失效。
- 菜单文案可改为“环境总览”或“环境状态”。
- 如果后台菜单组件选择依赖 `componentKeys`,需要补齐 `/dashboard/` 组件扫描。
页面结构:
- 使用 `Page autoContentHeight`
- 使用 Ant Design Vue Next 的 `Card`、`Statistic`、`Tag`、`Button`、`Tooltip`、`Drawer`、`Timeline`、`Alert`、`Descriptions`。
- 拓扑可使用 DOM + CSS grid/SVG edge overlay 实现,不引入重量图表库。
- 每个拓扑节点使用固定尺寸,避免状态文字变化导致布局跳动。
- 节点点击打开证据抽屉,抽屉展示 metrics、evidence、links、lastCheckedAt。
- 安全总控按钮必须用图标 + tooltip高风险 disabled action 不隐藏。
- 页面禁止使用旧示例中的营销图表和静态数据。
视觉原则:
- 运维工具风格,信息密度高、层级清晰、颜色克制。
- 不做 hero不做装饰渐变不做大面积单色主题。
- `ok/degraded/down/blocked/unknown/unwired` 使用一致的状态色和文字。
- 拓扑主视图必须在桌面第一屏可见;移动端可纵向分组堆叠。
## 后端实现约束
- Controller 使用 `JwtAuthGuard`
- 返回 `vbenSuccess(data)`
- Aggregator 通过 service 直接调用现有能力,不通过 HTTP 请求本 API。
- 每个信号源独立 timeout、独立 `Promise.allSettled`,单点失败不能拖垮整个 dashboard。
- 信号源失败必须变成节点 evidence而不是抛出 500。
- 只有认证、参数、系统级不可恢复错误才让接口失败。
- 新增或触碰函数、方法、handler、job 必须补 JSDoc参数说明要写来源和用途。
- 不泄露 secrets、token、password、raw env、kubeconfig、SSH 信息、QQBot 大字段。
- QQBot 摘要不得返回 `replyText`、base64 图片或过长日志。
- Jenkins/K8s 未接入时返回 `unwired`,不得伪造健康。
## 缓存与成本
建议第一版采用短 TTL 聚合缓存:
- 默认 dashboard TTL10-30 秒。
- `self-check` 可绕过 dashboard TTL但仍给单个信号源设置 timeout。
- NapCat/account runtime 读取复用现有 TTL不强制刷新所有账号。
- WordPress/MinIO 外部探测设置独立短超时。
- Loki summary 查询失败时只降级日志节点。
缓存返回需要在 evidence 中标注:
- `checkedAt`
- `sourceKind`
- `ttlMs`
- `isStale`
## 验收标准
### 设计验收
- 用户确认本 spec 后,进入 Superpowers writing-plans。
- 实施计划必须拆 API 合同、API 聚合、Admin 页面、测试/线上闭环四部分。
### API 验收
- `GET /system/environment/dashboard` 本地真实请求返回 Vben 包装。
- 响应中包含 summaryCards、topology.nodes、topology.edges、actions、recentEvents。
- Jenkins/K8s 未配置时显示 `unwired``external-link`,不导致接口失败。
- 任一可模拟信号源失败时接口仍 200并将对应节点标为 `unknown` / `degraded` / `down`
- 不返回敏感字段或 QQBot 大字段。
### Admin 验收
- `/dashboard/analytics` 不再展示 Vben 示例静态图表。
- 第一屏展示总体状态、拓扑和安全总控。
- 节点点击能打开证据抽屉。
- enabled action 可执行刷新、只读自检或跳转。
- disabled high-risk action 可见且说明禁用原因。
- 页面切换无 Vue `non-element root node` / transition 空白问题。
### 线上验收
- API/Admin 推送部署后Jenkins/K8s 发布状态需按现有 deploy observation 流程验证。
- 线上 Admin 页面可打开。
- 线上 dashboard 接口 200。
- 线上页面至少展示 API Runtime、System Logs、QQBot、NapCat、Plugin Platform、MinIO、WordPress、Jenkins/K8s 节点。
- 对未接入的 Jenkins/K8s 节点,页面明确展示未接入证据而非健康假象。
## 测试计划方向
实施计划阶段应覆盖:
- API service 单测状态严重度聚合、partial failure、unwired 节点、action catalog。
- API controller contract spec鉴权路由、Vben response shape、self-check 只读行为。
- Admin API wrapper Vitest请求路径和响应类型。
- Admin 页面组件测试拓扑节点、证据抽屉、disabled actions。
- 本地真实接口请求:启动或复用 API 服务调用 dashboard 接口。
- 本地浏览器 smoke打开 `/dashboard/analytics`,检查 console、首屏、抽屉和动作。
- 线上 smoke部署后调用线上接口和页面。
## 后续扩展
后续可以在不破坏第一版合同的基础上增加:
- 只读 Jenkins build adapter。
- 只读 K8s deployment/pod adapter。
- deploy observation evidence 入库或文件读取。
- 安全动作审计表。
- 二次确认和权限码控制的高风险动作。
- 环境变更历史趋势。
- 定时自检和告警推送。
这些扩展必须继续遵守:读态优先、动作分级、证据脱敏、失败局部降级、高风险动作有审计与回滚路径。