34 KiB
Admin 多站点环境状态总览总控面板设计
背景
Admin 当前 /dashboard/analytics 仍是 Vben 示例分析页,展示用户量、访问量、下载量和图表等静态数据。它不能回答线上排障最常见的问题:
- 当前 API/Admin/QQBot/NapCat/插件平台是否真实可用。
- Jenkins 构建、K8s 发布和线上 Pod 是否对齐到目标提交。
- NAS、本地开发、腾讯云和 r4se 这些不同站点之间的 WireGuard、Caddy、OpenClash/Mihomo 等基础链路是否可观测。
- 哪些节点是健康、降级、隔离、未配置、无权限、只读可查或高风险禁用。
用户已确认采用 A:Site Command Center 作为页面布局与架构主线:左侧站点导航,中心环境拓扑,右侧证据/动作抽屉,底部事件流。目标不是“做一个漂亮图表页”,而是把多环境状态、证据来源、低风险只读动作和高风险边界集中到一个工作台。
本设计替换前序“单环境总览 + 安全总控”口径,保留 Jenkins/K8s 只读观测结论,并扩展到腾讯云和 r4se 远程环境。
官方依据
- Ant Design 设计规范提供企业级产品原型、布局、数据展示和组件使用原则;布局采用 8px grid,卡片数据展示需要控制信息密度和行数。
- Ant Design 提供企业级中后台设计规范;组件实现以当前 Admin 实际技术栈
antdv-next为准。 antdv-next提供 Card、Statistic、Tag、Button、Tooltip、Drawer、Descriptions、Table 等中后台基础组件。- Vben Admin 定位为 Vue3/Vite/TypeScript 的中后台工程方案,当前 Admin 已采用 Vben +
antdv-next。 - Jenkins Remote Access API 支持只读获取 job/build 信息。
- Kubernetes API 支持读取 Deployment、Pod、Event 等资源,RBAC 可限制到
get/list/watch。 - Tencent Cloud CVM/Cloud Monitor API 可作为腾讯云主机状态和监控指标来源。
- Caddy Admin API 可读取当前配置和状态,但属于高权限配置 API,必须限制在内网/WireGuard 与只读路径。
- WireGuard 没有通用远程 HTTP 观测 API,只能通过本机
wg、隧道连通性或未来站点探针获得证据。 - OpenClash 本身不是稳定观测 API,底层 Mihomo/Clash external controller 可作为 r4se 只读观测来源。
参考链接:
- https://ant.design/docs/spec/introduce/
- https://ant.design/docs/spec/layout/
- https://ant.design/docs/spec/data-display/
- https://ant.design/components/overview/
- https://doc.vben.pro/en/
- https://www.jenkins.io/doc/book/using/remote-access-api/
- https://kubernetes.io/docs/concepts/overview/kubernetes-api/
- https://kubernetes.io/docs/reference/access-authn-authz/rbac/
- https://www.tencentcloud.com/document/product/213/5165
- https://caddyserver.com/docs/api
- https://www.wireguard.com/quickstart/
- https://wiki.metacubex.one/en/api/
已确认决策
/dashboard/analytics改造成“环境总览”工作台,不保留 Vben 示例静态图表。- 页面采用 A:Site Command Center。
- 页面第一屏必须同时看到:
- 全局状态条。
- 左侧站点导航。
- 中心环境拓扑。
- 右侧证据与安全动作。
- 底部最近事件。
- 站点模型采用
Site -> Node/Host -> Service -> Signal,不再只围绕 NAS 单环境建模。 - 第一版站点包含:
nas-prod:NAS/K8s/Jenkins/API/Admin/MySQL/Redis/Loki/MinIO/WordPress/QQBot/NapCat/插件平台。local-dev:本地 API/Admin/dev proxy/本地 MySQL 或开发依赖。tencent-cloud:腾讯云 CVM、WireGuard、Caddy。r4se:WireGuard、OpenClash/Mihomo。
- API 统一聚合,Admin 不直接访问 Jenkins、K8s、腾讯云、Caddy、Mihomo 或远程主机。
- 第一版只允许低风险动作:刷新、只读自检、打开日志、跳转已有页面、打开外部只读入口。
- 重启 Pod、触发 Jenkins 部署、DB 写入、重建 NapCat 容器、修改 Caddy/OpenClash、启停插件或定时任务等高风险动作,第一版必须显示为 disabled action,并写明原因。
- Jenkins/K8s 必须接入只读观测;缺配置、403、超时或网络失败时显示失败证据,不能伪造成健康。
- 腾讯云/r4se 第一版以只读观测为目标;无法直接观测的 WireGuard 全局 peer 状态必须明确显示证据缺口,不抓取私有 WebUI。
- Figma 官方写入不作为本轮主链路;页面布局通过本地 visual companion 和中文 spec 收敛,避免 Figma 官方限流。
- 事件层采用 HTTP 快照 + 后端 MQTT 收口 + API SSE 推送的混合方案:
GET /system/environment/dashboard和POST /system/environment/self-check继续作为状态快照与兜底;MQTT 只负责后端 topic 事件订阅、recent event materialize 和 cache invalidation;GET /system/environment/events/stream负责把已经脱敏和聚合后的事件推给 Admin。Admin 前端不直连 MQTT,也不跑轮询或定时刷新。
目标
- 将
/dashboard/analytics改为多站点环境状态工作台。 - 提供统一 API 合同,输出站点、摘要卡、拓扑节点、拓扑边、动作目录和事件流。
- 每个节点必须带证据:来源、检查时间、实时/缓存/推导状态、失败原因、是否脱敏。
- 让 Jenkins/K8s、腾讯云、r4se 不再是“未接入健康假象”,而是明确展示只读证据或缺口。
- 引入平台级 MQTT 事件入口,统一收口 QQBot/NapCat、Plugin Task、Jenkins/K8s、腾讯云、Caddy、WireGuard、Mihomo/OpenClash 等运行态事件。
- 提供 API SSE 实时出口,让 Admin 页面在无轮询、无定时刷新条件下接收状态变化和事件流增量。
- 后续可扩展远程站点探针,但第一版不引入写权限和高风险远程控制。
非目标
- 不在第一版执行部署、重启、数据库写入、插件启停、NapCat 容器重建、Caddy/OpenClash 修改。
- 不把 API Pod 暴露给 Docker socket、fnOS 私有 WebUI 或远程主机 root 权限。
- 不读取 K8s Secret、Jenkins console 全量日志、QQBot 大字段、原始 env、token、kubeconfig、SSH key。
- 不做营销式 hero、装饰图表、大面积单色主题或静态展示页。
- 不新增长期后台巡检表或历史趋势表,除非实施计划后续单独确认。
- 不让 MQTT 成为唯一状态真相源;broker 断连、retained message 过期或远程 agent 未接入时,dashboard 必须回退到 HTTP 快照/只读自检和明确缺口证据。
- 不让 Admin 浏览器直接连接 MQTT broker,不向前端暴露 broker 用户名、密码、token 或内部 topic。
- 不在 Admin 页面使用轮询、定时刷新或后台
setInterval拉取 dashboard;SSE 断线后的浏览器自动重连和服务端连接保活不属于状态刷新轮询。
页面布局
桌面端第一屏
┌──────────────────────────────────────────────────────────────────────────────┐
│ 全局状态条:overall status / checkedAt / degraded / isolated / unknown / 刷新 │
├──────────┬───────────────────────────────────────────────┬───────────────────┤
│ 站点导航 │ 环境拓扑主视图 │ 证据 + 安全动作 │
│ NAS │ 入口 -> 网关 -> Admin/API -> 数据/观测/业务 │ 当前选中节点 │
│ 本地 │ Jenkins -> K8s -> API Pod │ metrics/evidence │
│ 腾讯云 │ Tencent CVM -> WireGuard -> Caddy │ enabled/disabled │
│ r4se │ r4se WireGuard -> OpenClash/Mihomo │ actions │
├──────────┴───────────────────────────────────────────────┴───────────────────┤
│ 最近事件流:按严重度、站点、来源、时间排序 │
└──────────────────────────────────────────────────────────────────────────────┘
移动端/窄屏
- 全局状态条固定在顶部。
- 站点导航变为横向 segmented control。
- 拓扑按站点纵向分组。
- 证据抽屉改为底部 Drawer。
- 事件流位于拓扑之后,保留筛选与跳转。
视觉原则
- 工具型中后台,不做 hero。
- 8px spacing grid,固定节点尺寸,避免状态文案导致布局跳动。
- 使用
antdv-next组件:Card、Statistic、Tag、Button、Tooltip、Drawer、Descriptions、Table、Timeline、Alert。 - 状态色克制一致:
ok:绿色。degraded:橙色。down/blocked:红色。isolated:紫/蓝灰。unknown/unwired:灰色。
- disabled 高风险动作必须可见,不隐藏。
信息架构
全局状态条
展示:
- 总体状态。
- 最近检查时间。
- 当前选择站点。
degraded/down/blocked/isolated/unknown/unwired计数。- 刷新。
- 只读自检。
- 站点配置缺口提示。
左侧站点导航
每个站点展示:
- 站点名称。
- 站点状态。
- 核心服务短指标。
- 最近检查时间。
- 证据来源类型。
站点状态:
type EnvironmentSiteStatus =
| 'online'
| 'degraded'
| 'isolated'
| 'unknown';
语义:
online:站点入口或核心服务读态成功,且关键节点没有阻断。degraded:站点可达,但部分服务异常或缺少观测。isolated:站点不可达,例如 WireGuard down、远程 Caddy/CVM 不可访问。unknown:缺配置、缺权限、超时或没有足够证据。
中心拓扑
拓扑必须支持两种层级:
- 全环境视图:四个站点并列展示关键链路。
- 单站点视图:展示该站点内部节点和依赖关系。
节点分组:
type EnvironmentNodeGroup =
| 'entry'
| 'network'
| 'frontend'
| 'service'
| 'data'
| 'observability'
| 'qqbot'
| 'deploy'
| 'remote';
边关系:
type EnvironmentEdgeRelation =
| 'routes-to'
| 'depends-on'
| 'observes'
| 'deploys'
| 'connects'
| 'tunnels-to';
右侧证据与安全动作
点击任意站点、节点或边,右侧显示:
- 状态。
- 关键指标。
- 证据列表。
- 最后检查时间。
- 来源种类。
- 链接。
- enabled 安全动作。
- disabled 高风险动作与禁用原因。
证据抽屉不是日志正文区,只展示摘要和跳转入口。
底部事件流
事件来源:
- 系统日志摘要。
- Jenkins build 状态。
- K8s warning event。
- QQBot/NapCat runtime event。
- Plugin runtime/task event。
- 远程站点观测失败。
事件流必须支持:
- 按站点过滤。
- 按严重度过滤。
- 跳转相关页面。
- 脱敏摘要展示。
MQTT 事件收口
环境面板使用平台级 EnvironmentEventBus 收口事件。它可以运行在 local 或 mqtt 模式:local 用于本地测试和无 broker 环境,mqtt 用于线上和远程探针接入。现有 QQBot MQTT 能力只能作为事件来源之一,通过桥接映射为环境事件;环境面板不得直接依赖 QQBot 专用 topic 常量或 QqbotBusService。
建议 topic 前缀:
kt/env/{siteKey}/{nodeKey}/{serviceKey}/signal
kt/env/{siteKey}/{nodeKey}/{serviceKey}/event
kt/env/{siteKey}/self-check/result
kt/qqbot/{selfId}/runtime/event
kt/qqbot/{selfId}/napcat/login
kt/plugin/{pluginKey}/task/{taskKey}/run
MQTT 语义:
signal可以使用 retained message,但 payload 必须包含observedAt和expiresAt。过期 retained message 只能显示为unknown或unwired,不能显示绿色健康。- 普通运行事件不使用 retained message,只进入 recent event materializer。
- 状态信号和关键任务结果使用 QoS 1;普通日志摘要事件使用 QoS 0。
- payload 入库、日志、API 返回前三层都要脱敏。
- broker 断连是一个
EnvironmentEvent,同时使 dashboard cache 失效;不能因为 MQTT 断连把所有服务判定为 down。 - Admin 不直连 MQTT;前端通过 dashboard HTTP 首屏快照、self-check 主动按钮和 API SSE 长连接读取已经脱敏和聚合后的状态变化。
API SSE 实时出口
Admin 页面打开时只做一次 GET /system/environment/dashboard 获取首屏快照,然后建立 GET /system/environment/events/stream SSE 长连接。后端收到 MQTT 或本地事件后,先经过 EnvironmentEventBus、EnvironmentEventMaterializer 和脱敏,再向 SSE 订阅者推送增量事件。页面不得设置定时刷新;只有用户点击刷新/只读自检,或后端 SSE 推送 snapshot-required 时,才允许再次请求 dashboard 快照。
SSE 事件类型:
environment-event:追加 recent event,并按事件里的 site/node/service/signal 更新局部状态。environment-signal:更新某个 signal 的状态、证据和时间。snapshot-required:服务端认为客户端事件缺口过大或 cache generation 已失效,前端执行一次 dashboard 快照请求。heartbeat:连接保活,不触发状态刷新。error:展示连接或事件解析失败摘要,不能覆盖服务真实状态。
SSE 必须支持浏览器 Last-Event-ID 或等价 query 参数续接。服务端只保留有限最近事件用于断线恢复;超过 replay window 时推送 snapshot-required,避免客户端悄悄停留在旧状态。
API 合同
新增受保护接口:
GET /system/environment/dashboard
POST /system/environment/self-check
GET /system/environment/events/stream
GET /system/environment/dashboard 返回当前聚合状态。POST /system/environment/self-check 执行同一批只读检查,可以绕过 dashboard TTL,但不得触发任何写入、重启、部署、容器重建或远程配置变更。GET /system/environment/events/stream 是受保护 SSE 长连接,只推送脱敏后的环境事件和 snapshot 指令,不暴露 MQTT broker 或内部 topic。
建议目录:
src/modules/admin/platform-config/environment-dashboard/
contract/
environment-dashboard.controller.ts
dto/
environment-dashboard.dto.ts
application/
environment-dashboard.service.ts
environment-event-stream.service.ts
environment-dashboard-site.mapper.ts
environment-dashboard-status.mapper.ts
environment-dashboard-action.catalog.ts
environment-event.materializer.ts
domain/
environment-dashboard.types.ts
infrastructure/
environment-dashboard-signal.collector.ts
event/
environment-event-bus.service.ts
environment-mqtt-topic.catalog.ts
qqbot-environment-event.bridge.ts
adapters/
jenkins-readonly.adapter.ts
kubernetes-readonly.adapter.ts
tencent-cloud-readonly.adapter.ts
caddy-readonly.adapter.ts
mihomo-readonly.adapter.ts
wireguard-reachability.adapter.ts
该模块属于 Admin Platform Config,因为它面向后台运维观测和安全总控,不属于 QQBot、Blog、Asset 任一业务域。
DTO 语义
实现时应使用项目现有 class DTO 风格;下列 interface 仅定义合同语义。
type EnvironmentHealthStatus =
| 'ok'
| 'degraded'
| 'down'
| 'blocked'
| 'isolated'
| 'unknown'
| 'unwired';
interface EnvironmentDashboardDto {
checkedAt: string;
checkRunId: string;
overallStatus: EnvironmentHealthStatus;
activeSiteKey: string;
sites: EnvironmentSiteDto[];
summaryCards: EnvironmentSummaryCardDto[];
topology: EnvironmentTopologyDto;
actions: EnvironmentActionDto[];
recentEvents: EnvironmentEventDto[];
}
interface EnvironmentEventEnvelopeDto {
eventId: string;
topic: string;
siteKey: string;
nodeKey?: string;
serviceKey?: string;
signalKey?: string;
severity: EnvironmentHealthStatus;
sourceKind: 'mqtt' | 'local' | EnvironmentSignalSourceKind;
observedAt: string;
expiresAt?: string;
retained?: boolean;
summary: string;
evidence?: EnvironmentEvidenceDto[];
}
type EnvironmentStreamEventType =
| 'environment-event'
| 'environment-signal'
| 'snapshot-required'
| 'heartbeat'
| 'error';
interface EnvironmentStreamEventDto {
id: string;
type: EnvironmentStreamEventType;
data: EnvironmentEventEnvelopeDto | EnvironmentDashboardDto | EnvironmentStreamNoticeDto;
}
interface EnvironmentStreamNoticeDto {
reason: string;
summary: string;
generatedAt: string;
}
interface EnvironmentSiteDto {
key: string;
title: string;
description: string;
status: EnvironmentSiteStatus;
region?: string;
primaryEndpoint?: string;
sourceKind: EnvironmentSignalSourceKind;
metrics: EnvironmentMetricDto[];
evidence: EnvironmentEvidenceDto[];
lastCheckedAt?: string;
}
type EnvironmentSignalSourceKind =
| 'live'
| 'cached'
| 'derived'
| 'configured'
| 'external-link'
| 'unwired';
interface EnvironmentSummaryCardDto {
key: string;
siteKey?: string;
title: string;
status: EnvironmentHealthStatus;
primaryMetric: string;
secondaryMetric?: string;
source: EnvironmentSignalSourceDto;
route?: string;
}
interface EnvironmentTopologyDto {
viewMode: 'global' | 'site';
activeSiteKey?: string;
nodes: EnvironmentNodeDto[];
edges: EnvironmentEdgeDto[];
}
interface EnvironmentNodeDto {
id: string;
siteKey: string;
label: string;
group: EnvironmentNodeGroup;
status: EnvironmentHealthStatus;
sourceKind: EnvironmentSignalSourceKind;
metrics: EnvironmentMetricDto[];
evidence: EnvironmentEvidenceDto[];
links: EnvironmentNodeLinkDto[];
lastCheckedAt?: string;
}
interface EnvironmentEdgeDto {
id: string;
siteKey?: string;
source: string;
target: string;
relation: EnvironmentEdgeRelation;
status: EnvironmentHealthStatus;
evidence: EnvironmentEvidenceDto[];
}
interface EnvironmentEvidenceDto {
key: string;
title: string;
status: EnvironmentHealthStatus;
source: string;
checkedAt: string;
summary: string;
details?: Record<string, string | number | boolean | null>;
isSensitiveRedacted: boolean;
ttlMs?: number;
isStale?: boolean;
}
interface EnvironmentActionDto {
key: string;
siteKey?: string;
nodeId?: 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;
siteKey?: string;
source: string;
level: 'info' | 'warn' | 'error' | 'fatal';
title: string;
message: string;
happenedAt: string;
route?: string;
}
站点模型
nas-prod
节点:
- Caddy / TLS / reverse proxy。
- Admin static site。
- API Runtime。
- Runtime Config。
- MySQL。
- Redis / BullMQ。
- Loki / System Logs。
- MinIO。
- WordPress。
- QQBot Core。
- OneBot Reverse WS。
- NapCat Accounts。
- Plugin Platform。
- Plugin Scheduled Tasks。
- Jenkins。
- K8s Deployment。
- API Pod。
主要证据:
- Runtime health service。
- 系统日志 status/summary。
- QQBot dashboard/account/runtime summary。
- NapCat runtime detail。
- 插件平台与定时任务状态。
- MinIO connection check。
- WordPress auth/theme config check。
- Jenkins Remote Access API。
- Kubernetes API。
local-dev
节点:
- Local Admin dev server。
- Local API dev server。
- Local proxy / API base URL。
- Local MySQL / Redis if configured。
第一版可选读取:
- 如果 API 本地运行,则通过当前 Admin 配置的 API base URL 读取自身 runtime。
- 如果本地服务不可读,显示
unknown,并写明缺少本地 API 或 dev server 证据。
tencent-cloud
节点:
- Tencent CVM。
- Tencent Cloud Monitor。
- WireGuard endpoint。
- Caddy service。
- Public gateway / domain route。
主要证据:
- Tencent Cloud Monitor / CVM API:实例状态、CPU、网络、磁盘等指标。
- WireGuard reachability:API 所在网络到腾讯云 WireGuard endpoint 的连通性。
- Caddy Admin API:只读读取 config/status;仅允许 loopback/WireGuard 地址。
- Public domain probe:可选 HTTPS HEAD/GET 健康探测。
边界:
- 不在 Admin/API 里修改 Caddyfile。
- 不 reload Caddy。
- 不通过腾讯云 API 执行重启实例、修改安全组、改 DNS。
r4se
节点:
- WireGuard endpoint。
- OpenClash service。
- Mihomo/Clash external controller。
- 关键代理组/连接状态。
主要证据:
- WireGuard reachability:站点可达性和最近隧道连通性。
- Mihomo/Clash external controller:
/version、/traffic、/connections、/proxies只读摘要。
边界:
- 不抓取 OpenClash WebUI 私有接口。
- 不切换代理组。
- 不更新订阅。
- 不重启 OpenClash/Mihomo。
- 如果 external controller 未启用或无只读访问,节点显示
unknown,证据写明缺口。
状态归一规则
节点状态:
ok:信号源明确可用,关键指标正常。degraded:信号源可读,但存在局部异常,例如 Pod restart、部分账号离线、日志查询降级。down:信号源明确不可用,例如 Deployment 不可用、MinIO check failed。blocked:存在阻断业务闭环的问题,例如 runtime 核心配置缺失、QQBot worker 阻塞。isolated:远程站点或网络链路不可达,例如 WireGuard/Caddy endpoint 不通。unknown:缺配置、缺权限、超时、API 错误或证据不足。unwired:设计中存在该节点,但当前版本未接入读取能力。
总体状态按严重度聚合:
blocked > down > isolated > degraded > unknown/unwired > ok
站点状态由站点内节点聚合:
- 有
blocked或核心入口down:站点degraded或isolated,由网络证据决定。 - WireGuard/入口不可达:站点
isolated。 - 核心入口可达但部分节点失败:站点
degraded。 - 只有配置缺失或证据不足:站点
unknown。 - 所有核心节点正常:站点
online。
unknown 和 unwired 必须单独计数,不得合并成健康。
信号源映射
Runtime/API
来源:
RuntimeHealthService.getRuntimeHealth()RuntimeConfigService
要求:
- 聚合服务直接调用 service,不 HTTP 调本 API。
- 只返回 configured/missing/ok/down 摘要。
- 不暴露 env、password、token、secret。
系统日志/Loki
来源:
SystemLogService/system/logs/status/system/logs/summary
要求:
- 只返回摘要和跳转链接。
- 不返回大段原始日志。
- 不把 dashboard 自身请求刷成噪声事件。
QQBot / NapCat
来源:
QqbotDashboardService.summary()QqbotAccountService或账号列表 runtime append。QqbotNapcatAccountRuntimeService
要求:
- 区分 OneBot reverse WS、容器/WebUI、QQ 登录态。
- OneBot 心跳不能被当作 QQ 登录成功。
- 不返回
replyText、base64 图片或长日志。 - NapCat/account runtime 使用短超时和并发限制。
插件平台与定时任务
来源:
- Plugin Platform installations/capabilities/operations/runtime events。
- Plugin Task service。
要求:
- 展示已安装、启用、operation 数、任务数、最近失败数。
- 第一版不执行插件 enable/disable、task run、cron 修改。
- 动作只跳转插件平台或插件任务页。
MinIO / WordPress
来源:
MinioClientService.checkConnection(bucketName?)WordpressService.checkAuth()- WordPress/theme config read service。
要求:
- 不创建 bucket。
- 不执行 WordPress import/sync/write。
- 只显示连接、认证、主题配置读取摘要。
Jenkins
来源:
- Jenkins Remote Access API
GET .../api/json。
读取字段:
- jobPath。
- buildNumber。
- result。
- building。
- branch。
- commitSha。
- commitMessageSummary。
- startedAt。
- durationMs。
- buildUrl。
禁止:
/build/buildWithParameters- replay。
- configure。
- credential。
- console full log。
失败语义:
- token 缺失:
unknown,evidencejenkins-readonly-auth-missing。 - 403:
unknown,evidencejenkins-readonly-forbidden。 - 最近 build failed:若当前线上镜像不受影响则
degraded,若线上目标部署失败则down。
Kubernetes / K3s
来源:
- Kubernetes API。
读取资源:
- Deployment
get/status。 - Pod
listwith labelSelector。 - ReplicaSet 可选。
- Event
list。 - Metrics API 可选。
读取字段:
- namespace。
- deployment name。
- generation / observedGeneration。
- replicas / updatedReplicas / readyReplicas / availableReplicas。
- image。
- podName。
- phase。
- ready。
- restartCount。
- startedAt。
- warning event reason/message 摘要。
RBAC:
- 只允许
get/list/watch。 - 不允许
create/update/patch/delete。 - 不允许
pods/exec。 - 第一版不读取
pods/log,除非后续单独设计脱敏日志入口。 - 不允许读取 Secret。
失败语义:
- RBAC 403:
unknown,evidencek8s-readonly-rbac-forbidden。 - Deployment 未就绪:
down。 - Pod restartCount 增长或 warning event:
degraded。
Tencent Cloud
来源:
- Tencent Cloud CVM / Cloud Monitor read-only API。
读取字段:
- instanceId / instanceName。
- instanceState。
- region / zone。
- CPU、内存、磁盘、网络指标摘要。
- 公网/内网 IP 脱敏展示。
禁止:
- 重启实例。
- 修改安全组。
- 修改公网 IP、EIP、DNS。
- 修改云产品配置。
失败语义:
- credential missing:
unknown。 - API forbidden:
unknown。 - CVM stopped/unreachable:
down或站点isolated。
Caddy
来源:
- Caddy Admin API read-only paths。
- HTTPS public route probe。
要求:
- Caddy Admin API 只允许 loopback 或 WireGuard 私网地址。
- 不调用 config write、load、reload。
- 只显示当前配置摘要、route 可达性和证书/TLS 证据。
WireGuard
来源:
- API 所在节点的 WireGuard 本地状态。
- 私网 endpoint reachability。
- 未来可选 site probe。
要求:
- 第一版不假装能读取远端所有 peer。
- 只展示 API 侧可证明的 tunnel reachability、handshake/endpoint 摘要或缺口。
- 如果缺少 site probe,远端 peer 细节显示
unknown。
OpenClash / Mihomo
来源:
- Mihomo/Clash external controller read-only endpoints。
读取字段:
/version/traffic/connections/proxies摘要。
禁止:
- 切换代理。
- 修改配置。
- 重载配置。
- 更新订阅。
- 重启服务。
失败语义:
- external controller disabled:
unknown。 - remote unreachable:站点
isolated。 - API 401/403:
unknown。
安全总控 Action Catalog
第一版 enabled actions:
refresh-dashboard:重新请求 dashboard。run-readonly-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 只读入口。open-tencent-cloud-console:打开腾讯云控制台链接。open-caddy-status:打开 Caddy 只读状态链接。open-mihomo-dashboard:打开 r4se Mihomo/OpenClash 只读入口,如果已配置。
第一版 disabled actions:
restart-api-podtrigger-jenkins-deployrun-db-migrationrecreate-napcat-containerplugin-enable-disableplugin-task-run-onceminio-create-bucketwordpress-importreload-caddyedit-caddy-configswitch-openclash-proxyrestart-openclashrestart-tencent-cvmmodify-wireguard-peer
每个 disabled action 必须返回:
riskLevel: 'high'enabled: falsedisabledReasonrequiredPermission- 后续安全条件,例如二次确认、审计日志、回滚路径、只读预检、最小权限凭据。
前端设计
改造位置:
Vue/kt-template-admin/apps/web-antdv-next/src/views/dashboard/analytics/index.vue
Vue/kt-template-admin/apps/web-antdv-next/src/views/dashboard/analytics/components/
Vue/kt-template-admin/apps/web-antdv-next/src/api/system/environment.ts
路由:
- 保留
/dashboard/analytics,避免菜单和固定 tab 入口失效。 - 菜单文案改为“环境总览”或“环境状态”。
组件建议:
EnvironmentDashboardPage
EnvironmentStatusBar
EnvironmentSiteRail
EnvironmentTopologyCanvas
EnvironmentEvidenceDrawer
EnvironmentActionPanel
EnvironmentEventStream
实现约束:
- 页面 root 必须是单一稳定元素,避免 Vben route transition 空白。
- 拓扑第一版使用 DOM + CSS grid + SVG edge overlay,不引入重量图表库。
- 节点固定宽高,长文本 ellipsis + Tooltip。
- 抽屉展示 Descriptions、metrics、evidence、links、actions。
- 事件流可用 Table 或 Timeline;如果需要排序/过滤,优先 Table。
- API 请求统一通过 Admin caller/request wrapper。
后端实现约束
- Controller 使用
JwtAuthGuard。 - 返回
vbenSuccess(data)。 - Aggregator 直接调用本地 service 或只读 adapter,不 HTTP 调本 API。
- 每个信号源独立 timeout、独立
Promise.allSettled。 - 单点失败变成节点 evidence,不让 dashboard 500。
- 只有鉴权、参数或系统级不可恢复错误才让接口失败。
- 新增或触碰函数、方法、handler、job 必须补 JSDoc,参数说明写来源和用途。
- 所有外部证据入库前、日志前、返回前都必须脱敏。
- Jenkins/K8s/Tencent/Caddy/Mihomo adapter 不得包含写路径。
缓存与成本
建议第一版采用短 TTL:
- Dashboard 聚合 TTL:10-30 秒。
self-check可绕过 dashboard TTL,但仍对每个信号源设置 timeout。- QQBot/NapCat 复用现有 runtime TTL,不强制刷新所有账号。
- Jenkins/K8s/Tencent/Caddy/Mihomo 每个 adapter 独立短超时。
- 远程站点失败只降级对应站点,不拖垮整个接口。
证据必须标注:
checkedAtsourceKindttlMsisStale
验收标准
设计验收
- 用户确认本 spec 后,进入 Superpowers writing-plans。
- 实施计划必须拆 API 合同、API 聚合、远程只读 adapter、Admin 页面、测试/线上闭环五部分。
API 验收
GET /system/environment/dashboard本地真实请求返回 Vben 包装。GET /system/environment/events/stream本地真实请求返回 SSE 流,能收到 heartbeat 或 synthetic event。- 响应包含
sites、summaryCards、topology.nodes、topology.edges、actions、recentEvents。 - NAS、local-dev、Tencent Cloud、r4se 至少有节点和状态。
- Jenkins/K8s 节点由只读 adapter 提供真实 build/deployment/pod 证据或失败证据。
- 腾讯云/Caddy/WireGuard/r4se/OpenClash/Mihomo 节点有只读证据或明确缺口。
- 任一信号源失败时接口仍 200,并将对应节点标为
unknown/isolated/degraded/down。 - 不返回敏感字段或 QQBot 大字段。
Admin 验收
/dashboard/analytics不再展示 Vben 示例静态图表。- 第一屏展示全局状态条、站点导航、拓扑、证据/动作、事件流。
- 点击站点切换拓扑范围。
- 点击节点打开证据抽屉。
- enabled action 可刷新、只读自检或跳转。
- disabled high-risk action 可见且说明禁用原因。
- 页面切换无 Vue
non-element root node/ transition 空白问题。 - 页面不使用轮询或定时刷新 dashboard;状态变化由 SSE 增量事件驱动。
线上验收
- API/Admin 推送部署后,Jenkins/K8s 发布状态按现有 deploy observation 流程验证。
- 线上 Admin 页面可打开。
- 线上 dashboard 接口 200。
- 线上 events stream 可建立 SSE 连接,断线重连后能通过
Last-Event-ID或snapshot-required恢复一致性。 - 线上页面展示 NAS、local-dev、Tencent Cloud、r4se 四类站点。
- Jenkins/K8s 展示真实只读观测证据:Jenkins 最近 build/commit/result,K8s Deployment ready/updated、Pod image/restartCount。
- 腾讯云/Caddy/WireGuard/r4se/OpenClash/Mihomo 展示真实只读证据或明确缺口,不显示健康假象。
- 所有高风险动作 disabled,不能触发部署、重启 Pod、修改资源或读取 Secret。
测试计划方向
实施计划阶段应覆盖:
- API service 单测:状态严重度聚合、site 聚合、partial failure、isolated/unknown/unwired、action catalog。
- API adapter 单测:Jenkins/K8s/Tencent/Caddy/Mihomo/WireGuard 的 200、403、timeout、unreachable、failed/degraded mapping。
- API event bus 单测:MQTT topic mapping、retained message expiry、broker disconnect event、QQBot bridge 脱耦。
- API SSE 单测:event replay、Last-Event-ID 续接、heartbeat 不触发快照、replay window 缺口推
snapshot-required。 - API controller contract spec:鉴权路由、Vben response shape、self-check 只读行为。
- Admin API wrapper Vitest:请求路径和响应类型。
- Admin 页面组件测试:站点导航、拓扑节点、证据抽屉、disabled actions、事件流过滤、EventSource 消费、无 dashboard 轮询。
- 本地真实接口请求:启动或复用 API 服务调用 dashboard 接口。
- 本地浏览器 smoke:打开
/dashboard/analytics,检查 console、首屏、抽屉和动作。 - 线上 smoke:部署后调用线上接口和页面。
后续扩展
后续可以在不破坏第一版合同的基础上增加:
- 远程 site probe,解决 WireGuard 远端 peer 和 OpenClash 主机本地服务观测盲区。
- deploy observation evidence 入库。
- 安全动作审计表。
- 二次确认和权限码控制的高风险动作。
- 环境变更历史趋势。
- 定时自检和告警推送。
这些扩展必须继续遵守:读态优先、动作分级、证据脱敏、失败局部降级、高风险动作有审计与回滚路径。