概述 —— 它的作用
InfraGuard 的顶部导航采用 角色优先的信息架构(IA):先按 角色(工作区域)分支,再在每个区域 内部 展开为业务流程。三条原则:
- 菜单由数据库驱动,而非硬编码。 每个菜单节点都从
infr_sitemap表(应用自有、独立)读取,Blade 中不写死任何内容。 - 角色边界 = 权限边界。 每个节点的
min_req(最小user_level)就是 访问控制线。只有当user_level >= min_req时节点才显示,并且同一规则在路由上于服务端强制执行(纵深防御)。 - 标签始终经过翻译键。 屏幕文本通过
__()/Locales::menuLabel()解析为全部 8 种语言。
指标(CPU、负载、5 分钟窗口……)不是 顶级菜单项——它们作为实体标签页和过滤器存在于各个画面内部。划分的依据是“谁(哪个角色)做什么”,而不是“哪个指标”。
在 InfraGuard 中,“域名”仅指 Web 的 TLD(
aaa.bbb.com)。按职责划分的工作区分称为 “角色 / 区域”。这 8 个顶级菜单项正是这些角色区域。
使用场景
- 首次登录时,了解 各项功能位于何处。
- 排查 某个画面为何看不到(级别不足,还是语言回退)。
- 需要 新增或重构 菜单并重新运行种子程序时(管理员/开发者)。
- 核实其他级别的用户 能看到什么。
界面布局
菜单横向排列于顶栏(infr-topbar)。从左到右:
| 区域 | 内容 |
|---|---|
| 品牌 | InfraGuard 徽标(盾牌+监控脉冲)→ 点击进入概览(/) |
| 角色菜单 | infr-nav —— 8 个角色区域,悬停展开子项面板 |
| 右侧操作 | 移动端菜单开关 · 语言切换器 · 主题切换 · 用户菜单 |
每个顶级项渲染为 MDI 图标 + 标签 +(若有子项)折角箭头;子项显示在下拉面板(infr-nav__panel)中。当前路径与某个子项的 href 匹配时,顶级项会带上 is-active(概览仅在路径恰好为 / 时才处于激活状态)。
8 个角色区域
这是 SitemapSeeder 构建的顶级树。进入某个区域时,body_class 会应用到 <body> 上,以限定页面样式的作用域。
| # | 角色区域 | 归属 | body_class |
最小 user_level |
|---|---|---|---|---|
| 1 | 概览 | 公共 | infr-overview |
1 |
| 2 | 基础设施 | 基础设施运维 | infr-infra |
1 |
| 3 | 服务 | 服务运维 | infr-service |
1 |
| 4 | 安全 | 安全运营 | infr-security |
2 |
| 5 | 备份与恢复 | 基础设施(兼任) | infr-backup |
2 |
| 6 | 资产 | 公共参考(CMDB) | infr-asset |
1 |
| 7 | 管理 | 管理员 | infr-admin |
10 |
| 8 | 开发 | super_admin | infr-dev |
9 |
各区域的子项
每个子项都带有自己的 min_req(通常与父项相同,有时会提高)。
基础设施(min_req 1)
| 项目 | 路径 | min_req |
|---|---|---|
| 健康状态 | /infra/health |
1 |
| 服务器 | /infra/servers |
1 |
| 存储与 RAID | /infra/storage |
1 |
| 端口连接 | /infra/traffic/ports |
1 |
| IP 连接 | /infra/traffic/ips |
1 |
| 流量 | /infra/traffic/net |
1 |
| 告警 | /infra/alert |
1 |
服务(min_req 1)
| 项目 | 路径 | min_req |
|---|---|---|
| 概览 | /service |
1 |
| Web | /service/web |
1 |
| 数据库 | /service/database |
1 |
| 会话 | /service/session |
1 |
| 目录 | /service/catalog |
1 |
| 项目 | /service/projects |
1 |
| 问题处理 | /service/resolution |
2 |
安全(min_req 2 —— 所有项均为 2)
| 项目 | 路径 |
|---|---|
| 概览 | /security |
| 威胁 | /security/threats |
| 检测 | /security/detections |
| 规则集 | /security/rulesets |
| 防火墙 | /security/firewall |
| 封禁列表与信誉 | /security/blocklist |
| 白名单 | /security/whitelist |
| 安全诊断 | /security/diagnostics |
| 问题处理 | /security/resolution |
备份与恢复(min_req 2):计划看板 /backup/board · 备份脚本 /backup/scripts · 保管库 /backup/vaults · 恢复与验证 /backup/recovery。
资产(min_req 1):清单 /asset/inventory · 实例 /asset/instances · 硬件 /asset/hardware · 存储与文件 /asset/storage。
管理(min_req 10 —— 所有项均为 10):用户与角色 /admin/users · 采集器 /admin/collectors · 运维策略 /admin/ops-policy · API 密钥 /admin/api-keys · 规则与阈值 /admin/rules · 信誉 API /admin/reputation-providers · AI 适配器 /admin/ai-providers · 邮件适配器 /admin/mail-providers · 短信适配器 /admin/sms-providers · 本地化 /admin/localization · 审计 /admin/audit。
开发(min_req 9 —— 所有项均为 9):Dev Overview /dev · Doctor /dev/doctor · Runtime & Leader /dev/leader · Slow Queries/Requests/Jobs/Outgoing · Exceptions · Cache · Servers · Usage · Pulse /pulse · Horizon /horizon。
使用方法
浏览菜单
悬停某个顶级项即可打开其面板。点击某项会跳转到对应画面,并把该区域的 body_class 应用到 <body>。在窄屏上,右上角的汉堡按钮(data-nav-toggle)用于展开菜单。
你的级别能看到什么
登录时,InfrAuth 中间件会把 users.user_level 同步到会话键 infr_user_level。渲染时,Menu::for_user($level) 遍历整棵树,并 递归隐藏 所有满足 min_req > your level 的节点。例如:
- 级别 1(demo):可见概览 · 基础设施 · 服务 · 资产——但看不到安全(2)、备份(2)、管理(10)或开发(9)。
- 级别 5(staff):在上述基础上增加安全 · 备份与恢复(两者均为 2)。
- 级别 10(admin):全部可见,包括管理(10)与开发(9)。
开发(9)与管理(10)的阈值不同。级别恰好为 9 的 super_admin 能看到开发,但看不到管理;管理员(10)两者皆可见。
新增或重构菜单(管理员/开发者)
目前还没有菜单编辑界面。这棵树的权威来源是代码(database/seeders/SitemapSeeder.php),种子程序每次运行都会 删除所有行并重新创建(权威重同步)。
# 编辑树之后重新同步(只影响 infr_sitemap —— 旧有数据是安全的)
php artisan db:seed --class=SitemapSeeder
种子程序最后会调用 Menu::flush(),因此变更立即生效。如果新项目显示的是原始(英文)名称,说明缺少翻译键——按 Str::slug(name, '_') 规则在 resources/lang/{ko,en}/menu.php 中补一个(例如 Storage & RAID → storage_raid)。
切勿运行
migrate:fresh。InfraGuard 与旧有的 stats-design MySQL 共用同一个连接。若只想刷新菜单,请仅使用db:seed --class=SitemapSeeder。
数据来源
infr_sitemap 表
一张应用自有的独立表(与旧有的无前缀 sitemap 不同)。模型:App\Models\Infr\InfrSitemap。
| 列 | 含义 |
|---|---|
parent_id |
0 = 顶级,否则为父节点 id |
seq |
同级排序顺序 |
depth |
0 = 角色区域,1 = 子项 |
name |
原始名称(标签键的来源) |
href |
链接路径(# = 不可点击的父节点) |
icon |
MDI 字形(例如 mdi-server) |
body_class |
仅顶级——进入时的 <body> 类名 |
is_view |
为 1 时纳入树中 |
min_req |
最小 user_level(权限边界) |
App\Support\Menu —— 树构建器 + 缓存
Menu::tree()—— 按seq、id顺序读取is_view=1的行,组装成递归树,并用rememberForever(键infr:menu:v2)缓存。若 Redis 不可用,则回退到不带缓存的build()。Menu::for_user($level)—— 按min_req > $level递归过滤这棵树。Menu::flush()—— 使缓存失效(由种子程序调用)。
缓存中保存的是 原始
name;翻译在渲染时通过Locales::menuLabel()完成。因此 切换语言无需清空缓存。 反之,新增或重命名节点则需要重新执行种子程序(它会清空缓存)。
标签翻译
App\Support\Locales::menuLabel($name) 查找键 menu. + Str::slug($name, '_')。键存在则翻译,否则返回原始名称(安全回退)。语言包位于 resources/lang/{locale}/menu.php。
// 渲染处(nav.blade.php)
{{ \App\Support\Locales::menuLabel($top['name']) }}
// "Storage & RAID" → __('menu.storage_raid') → "Storage & RAID" (en) / "存储与 RAID" (zh)
会话与中间件
InfrAuth—— 认证时把users.user_level同步到会话infr_user_level。这是菜单过滤器的输入。InfrLevel(infr.level:N)—— 路由闸门。若infr_user_level < N则返回 403(服务端强制执行,独立于菜单隐藏)。InfrAdmin/InfrDev—— 保护管理(≥10)与开发(≥9)路由组。
访问权限
级别(user_level) |
别名 | 菜单中可见 |
|---|---|---|
| 1 | demo/viewer | 概览 · 基础设施 · 服务 · 资产(基本只读) |
| 5 | staff | + 安全 · 备份与恢复 |
| 9 | super_admin | + 开发 |
| 10 | admin | + 管理(以及开发) |
- 隐藏菜单只是便利措施和第一道防线。 真正的管控由每条路由上的
infr.level:N/InfrAdmin/InfrDev中间件在服务端强制执行(直接输入 URL 仍会得到 403)。 - 破坏性/安全操作(封禁、还原、规则变更……)通常还会在各画面内部由单独的写入级别再次把关(例如写入 ≥2、管理员 ≥10),并记入审计日志。
级别定义参见 RBAC 级别;角色与团队管理参见 角色与团队。
故障排查与常见问题
某个菜单项不见了。
通常是级别不足。请确认你的 user_level ≥ 该节点的 min_req(见上方表格)。管理员可在 用户与团队 中调整级别。
新增的菜单项显示为英文(原始)名称。
menu.php 语言包缺少翻译键。请按 Str::slug(name,'_') 规则同时在 resources/lang/ko/menu.php 与 en/menu.php 中补上。即使缺键,画面仍会以原始名称安全运行。
我运行了种子程序,但菜单没有变化。
可能是缓存过期。种子程序最后会调用 Menu::flush(),你也可以尝试 php artisan cache:clear。若 Redis 已停止,Menu 会在每个请求中回退到 build(),因此缓存不可能是原因。
我切换了语言,但只有菜单标签没变。
标签在渲染时解析,不做缓存。请确认目标语言的 menu.php 中存在该键;若不存在,请到 本地化 页面查看启用与翻译状态。
有人能通过直接输入 URL 访问被隐藏的画面吗?
不能。即使菜单被隐藏,路由中间件(infr.level:N 等)也会在服务端返回 403。
相关内容
- RBAC 级别 ——
user_level与min_req如何评估 - 角色与团队 —— 角色、团队与负责人
- 本地化 —— 语言切换与回退
- 主题 —— 明/暗色令牌
- 用户与团队(管理) —— 调整级别
- 概览(着陆页) —— 统一健康状态首页

