Skip to content

feat(dashboard): 监控大盘改版,体检判定挪到服务端算,并把入口归入后台管理 - #211

Merged
fxbin merged 5 commits into
mainfrom
issue-209-dashboard-ui
Nov 2, 2026
Merged

fxbin merged 5 commits into
mainfrom
issue-209-dashboard-ui

Conversation

@fxbin

@fxbin fxbin commented Nov 2, 2026

Copy link
Copy Markdown
Owner

背景

内置监控大盘 /dashboard(后端直出 HTML)一直挂在系统里,但有三个问题叠在一起:

  1. 没有入口——后台侧边栏里找不到它,运维只能手动敲地址。
  2. 不像这个产品——深海军蓝霓虹皮肤 + 7 张等权 KPI 卡,与 TopicEye 其余页面的浅底橙色系不是一套东西;数字彩虹化但无语义;首屏没有结论,用户得自己在一堆数字里找哪个有问题。
  3. 判定逻辑藏在页面 JS 里、零测试覆盖——阈值、单位换算、枚举大小写各写一份,错了没有任何东西会报警。

改了什么

判定口径挪到服务端(app/services/metrics_checks.py 新增)

体检项的定义(阈值、单位、严重程度映射、「有没有样本」的判据)与判定全部在服务端,GET /api/v1/metrics/checks 返回每项的当前值、展示串、阈值说明、状态与计数汇总。前端只负责把结论画出来。

原因有三件只有服务端知道的事:

前端自己判会出的错 服务端为什么不会
接口返回延迟是秒、阈值按毫秒读 → P95 检查永远不触发 值与阈值同源,换算只有一处
熔断器状态是小写枚举 closed/open/half_open,写错大小写就把熔断判成「正常」 枚举由服务端定义,映射同源
LLM 一次都没调用时成功率是 0%,拿去比阈值就成了「严重」 服务端知道分母是 0 还是真有 0 次调用

沿用本仓库已有做法(前端体验指标的阈值与 p75 口径同样真源在 service 层)。

大盘改版

  • 首屏只有一个主角:顶部判定条,一句话结论 + 超标项直达按钮。
  • 体检表取代等权 KPI 卡:8 项检查,每行给「指标 / 当前值 / 阈值 / 迷你趋势 / 状态」,点行就地展开趋势大图与相关日志。
  • 色彩收成灰 / 橙 / 红三档;数字用等宽表格数字;趋势图下移,首屏不再被图表挤满。
  • 配色回到产品浅底 + 品牌橙,小字用深色变体(品牌橙在白底上只有 2.8:1,当文字读不清)。

入口归入后台管理

frontend/src/lib/admin-nav.ts 新增「监控大盘」(系统组)。它是壳外独立页面(后端直出 HTML,经 rewrite 同源暴露),因此:

  • inShell: false——那个页面没有壳内顶栏,不进面包屑;
  • standalone: true——侧边栏用原生 <a> 整页跳转,Next 客户端路由要的是 RSC 载荷,后端给的是整页 HTML。

独立复核

复核者跑了 5 条定向变异(熔断状态大小写、P95 秒→毫秒换算、LLM 零调用当有样本、关掉 invert 分支、阈值比较 > 改 >=),全部被测试抓到——判定规则本身没问题。

复核另外挖出判定之外的几处,已全部修掉并补用例:

  • 错误率 / 连接池两行的趋势与当前值不同口径(当前值是比率,趋势画的是累计个数,纵轴还会把「37 次」标成「37.0%」);
  • 运行时状态卡里自己抄了一份阈值与熔断状态映射,与服务端判定各执一词;
  • 认不出来的熔断状态值被默认判成「正常」;
  • 阈值文案写「< 500ms 合格」而实现是等于阈值也算合格;
  • 慢查询拿进程启动至今的累计计数比固定阈值,跑久了必然「超标」——已改成「每小时多少次」;
  • 读不到慢查询计数时回落成 0,把「没取到」说成「一次都没有」;
  • 汇总里「判不出档位」的项被算进了通过数。

Verification

检查 结果
backend/tests/test_metrics_checks.py 判定口径单测(无数据、枚举、单位、阈值边界、汇总口径、慢查询速率)
backend/tests/test_metrics_auth.py 新端点已进匿名 / 非管理员拒绝参数表,并补管理员可用性断言
make layering 通过(判定在 service,端点只取快照转发)
cd backend && uv run ruff check . && uv run ruff format --check . 通过
cd frontend && npx tsc --noEmit 通过
cd frontend && npm run test:coverage 46 个文件 / 379 条用例全绿
notes 校验器(state-root clone 内) pass,41 篇 0 problem
本地起后端实测 四个页签渲染正常、无控制台错误;体检行点击可就地展开趋势与日志;默认做法检查(对比度、卡片套卡片)全部清零

不做

  • 不把大盘搬进 Next 页面(套壳会变成双层导航,iframe 还要额外处理加载态)。
  • 不给体检项加告警推送(services/metrics_alerting.py 已有服务端告警)。
  • 不做大盘的历史回放与时间游标。

closes #209

fxbin added 5 commits November 2, 2026 00:59
大盘原本是深色霓虹皮肤加七张等权 KPI 卡,跟产品其余页面不像一套;首屏也没有
结论,用户得自己在一堆数字里找哪个有问题。改成顶部一条判定条先给结论,下面
体检表列出八项检查(指标、当前值、阈值、迷你趋势、状态),点某一行就地展开
趋势大图和相关日志。配色收成灰橙红三档。

判定逻辑从页面 JS 挪到 app/services/metrics_checks.py:单位换算、阈值比较、
「没有样本」和「样本值是 0」的区分都只有服务端分得清。挪的过程中查出三个
真实缺陷——熔断器状态是小写枚举而判定表写的是大写,熔断中的实例会被显示成
正常;延迟接口给秒而阈值按毫秒读,P95 检查永远不会触发;LLM 一次都没调用
时成功率是 0%,拿去比阈值会被判成严重。三条都补了回归测试。
监控大盘一直在 /dashboard 上挂着,但后台导航里没有它,运维只能手动敲地址。
在导航清单里加一条「监控大盘」,放系统组。

它是壳外的独立页面(后端直出 HTML,经 rewrite 同源暴露),所以不进面包屑,
侧边栏用原生 a 标签整页跳转——Next 的客户端路由要的是 RSC 载荷,后端给的是
整页 HTML。清单新增 standalone 标记把这件事显式记下来。
写清判定为什么放服务端(单位、枚举大小写、没有样本与值为 0 的区别都只有
服务端分得清)、改版方向、入口归入后台管理的做法,以及推翻旧笔记里「避免
新增导航项」那条便利性理由的理由。
独立复核跑完五条定向变异后,又挖出判定之外的几处,一并修掉:

错误率和连接池两行的趋势跟当前值不是一个口径——当前值是比率,趋势画的却是
累计个数,纵轴还会把「37 次」标成「37.0%」;运行时状态卡里自己抄了一份
阈值和熔断状态映射,跟服务端判定各执一词;认不出来的熔断状态值被默认判成
正常;阈值文案写「< 500ms 合格」而实现是等于阈值也算合格;慢查询拿进程启动
至今的累计计数去比固定阈值,跑久了必然超标;读不到慢查询计数时回落成 0,
把「没取到」说成「一次都没有」;汇总里「判不出档位」的项被算进了通过数。

顺带把新端点补进 metrics 的鉴权测试参数表,并给判定口径补齐这几处的用例。
把判定搬到服务端只是搬走了第一份口径,前端留着阈值、状态映射或另算一份趋势
就会重新长出第二份。写进笔记的是这条教训,以及逐条修了什么。
@fxbin
fxbin merged commit 07ad03f into main Nov 2, 2026
8 checks passed
@fxbin
fxbin deleted the issue-209-dashboard-ui branch November 2, 2026 13:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

监控大盘改版:回到产品本色 + 入口归入后台管理

1 participant