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

34 KiB
Raw Blame History

Admin 多站点环境状态总览总控面板设计

背景

Admin 当前 /dashboard/analytics 仍是 Vben 示例分析页,展示用户量、访问量、下载量和图表等静态数据。它不能回答线上排障最常见的问题:

  • 当前 API/Admin/QQBot/NapCat/插件平台是否真实可用。
  • Jenkins 构建、K8s 发布和线上 Pod 是否对齐到目标提交。
  • NAS、本地开发、腾讯云和 r4se 这些不同站点之间的 WireGuard、Caddy、OpenClash/Mihomo 等基础链路是否可观测。
  • 哪些节点是健康、降级、隔离、未配置、无权限、只读可查或高风险禁用。

用户已确认采用 ASite 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 只读观测来源。

参考链接:

已确认决策

  1. /dashboard/analytics 改造成“环境总览”工作台,不保留 Vben 示例静态图表。
  2. 页面采用 ASite Command Center。
  3. 页面第一屏必须同时看到:
    • 全局状态条。
    • 左侧站点导航。
    • 中心环境拓扑。
    • 右侧证据与安全动作。
    • 底部最近事件。
  4. 站点模型采用 Site -> Node/Host -> Service -> Signal,不再只围绕 NAS 单环境建模。
  5. 第一版站点包含:
    • nas-prodNAS/K8s/Jenkins/API/Admin/MySQL/Redis/Loki/MinIO/WordPress/QQBot/NapCat/插件平台。
    • local-dev:本地 API/Admin/dev proxy/本地 MySQL 或开发依赖。
    • tencent-cloud:腾讯云 CVM、WireGuard、Caddy。
    • r4seWireGuard、OpenClash/Mihomo。
  6. API 统一聚合Admin 不直接访问 Jenkins、K8s、腾讯云、Caddy、Mihomo 或远程主机。
  7. 第一版只允许低风险动作:刷新、只读自检、打开日志、跳转已有页面、打开外部只读入口。
  8. 重启 Pod、触发 Jenkins 部署、DB 写入、重建 NapCat 容器、修改 Caddy/OpenClash、启停插件或定时任务等高风险动作第一版必须显示为 disabled action并写明原因。
  9. Jenkins/K8s 必须接入只读观测缺配置、403、超时或网络失败时显示失败证据不能伪造成健康。
  10. 腾讯云/r4se 第一版以只读观测为目标;无法直接观测的 WireGuard 全局 peer 状态必须明确显示证据缺口,不抓取私有 WebUI。
  11. Figma 官方写入不作为本轮主链路;页面布局通过本地 visual companion 和中文 spec 收敛,避免 Figma 官方限流。
  12. 事件层采用 HTTP 快照 + 后端 MQTT 收口 + API SSE 推送的混合方案:GET /system/environment/dashboardPOST /system/environment/self-check 继续作为状态快照与兜底MQTT 只负责后端 topic 事件订阅、recent event materialize 和 cache invalidationGET /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 拉取 dashboardSSE 断线后的浏览器自动重连和服务端连接保活不属于状态刷新轮询。

页面布局

桌面端第一屏

┌──────────────────────────────────────────────────────────────────────────────┐
│ 全局状态条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 收口事件。它可以运行在 localmqtt 模式: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 必须包含 observedAtexpiresAt。过期 retained message 只能显示为 unknownunwired,不能显示绿色健康。
  • 普通运行事件不使用 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 或本地事件后,先经过 EnvironmentEventBusEnvironmentEventMaterializer 和脱敏,再向 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 reachabilityAPI 所在网络到腾讯云 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:站点 degradedisolated,由网络证据决定。
  • WireGuard/入口不可达:站点 isolated
  • 核心入口可达但部分节点失败:站点 degraded
  • 只有配置缺失或证据不足:站点 unknown
  • 所有核心节点正常:站点 online

unknownunwired 必须单独计数,不得合并成健康。

信号源映射

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 缺失:unknownevidence jenkins-readonly-auth-missing
  • 403unknownevidence jenkins-readonly-forbidden
  • 最近 build failed若当前线上镜像不受影响则 degraded,若线上目标部署失败则 down

Kubernetes / K3s

来源:

  • Kubernetes API。

读取资源:

  • Deployment get / status
  • Pod list with 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 403unknownevidence k8s-readonly-rbac-forbidden
  • Deployment 未就绪:down
  • Pod restartCount 增长或 warning eventdegraded

Tencent Cloud

来源:

  • Tencent Cloud CVM / Cloud Monitor read-only API。

读取字段:

  • instanceId / instanceName。
  • instanceState。
  • region / zone。
  • CPU、内存、磁盘、网络指标摘要。
  • 公网/内网 IP 脱敏展示。

禁止:

  • 重启实例。
  • 修改安全组。
  • 修改公网 IP、EIP、DNS。
  • 修改云产品配置。

失败语义:

  • credential missingunknown
  • API forbiddenunknown
  • CVM stopped/unreachabledown 或站点 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 disabledunknown
  • remote unreachable站点 isolated
  • API 401/403unknown

安全总控 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-pod
  • trigger-jenkins-deploy
  • run-db-migration
  • recreate-napcat-container
  • plugin-enable-disable
  • plugin-task-run-once
  • minio-create-bucket
  • wordpress-import
  • reload-caddy
  • edit-caddy-config
  • switch-openclash-proxy
  • restart-openclash
  • restart-tencent-cvm
  • modify-wireguard-peer

每个 disabled action 必须返回:

  • riskLevel: 'high'
  • enabled: false
  • disabledReason
  • requiredPermission
  • 后续安全条件,例如二次确认、审计日志、回滚路径、只读预检、最小权限凭据。

前端设计

改造位置:

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 聚合 TTL10-30 秒。
  • self-check 可绕过 dashboard TTL但仍对每个信号源设置 timeout。
  • QQBot/NapCat 复用现有 runtime TTL不强制刷新所有账号。
  • Jenkins/K8s/Tencent/Caddy/Mihomo 每个 adapter 独立短超时。
  • 远程站点失败只降级对应站点,不拖垮整个接口。

证据必须标注:

  • checkedAt
  • sourceKind
  • ttlMs
  • isStale

验收标准

设计验收

  • 用户确认本 spec 后,进入 Superpowers writing-plans。
  • 实施计划必须拆 API 合同、API 聚合、远程只读 adapter、Admin 页面、测试/线上闭环五部分。

API 验收

  • GET /system/environment/dashboard 本地真实请求返回 Vben 包装。
  • GET /system/environment/events/stream 本地真实请求返回 SSE 流,能收到 heartbeat 或 synthetic event。
  • 响应包含 sitessummaryCardstopology.nodestopology.edgesactionsrecentEvents
  • 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-IDsnapshot-required 恢复一致性。
  • 线上页面展示 NAS、local-dev、Tencent Cloud、r4se 四类站点。
  • Jenkins/K8s 展示真实只读观测证据Jenkins 最近 build/commit/resultK8s 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 入库。
  • 安全动作审计表。
  • 二次确认和权限码控制的高风险动作。
  • 环境变更历史趋势。
  • 定时自检和告警推送。

这些扩展必须继续遵守:读态优先、动作分级、证据脱敏、失败局部降级、高风险动作有审计与回滚路径。