InfraGuard

Navigation · Role-First Menu

InfraGuard's role-first, DB-driven menu (infr_sitemap + min_req) — the 8 role areas and how the role boundary equals the permission boundary.

Overview — what it does

InfraGuard's top navigation is a role-first information architecture (IA): it branches by role (work area) first, then unfolds into task flows within each area. Three principles:

  1. The menu is DB-driven, not hardcoded. Every menu node is read from the infr_sitemap table (app-owned, independent). Nothing is baked into Blade.
  2. Role boundary = permission boundary. Each node's min_req (minimum user_level) is the access control line. A node is shown only when user_level >= min_req, and the same rule is enforced server-side on the route (defense in depth).
  3. Labels always go through translation keys. On-screen text is resolved via __() / Locales::menuLabel() for all 8 languages.

Metrics (CPU, load, 5-minute windows, …) are not top-level menu items — they live as entity tabs and filters inside each screen. The split is "who (which role) does what," not "which metric."

In InfraGuard, "domain" means only a web TLD (aaa.bbb.com). Work split by responsibility is called "role / area." The 8 top-level menu items are those role areas.


When to use


Layout

The menu sits horizontally in the top bar (infr-topbar). Left to right:

Region Content
Brand InfraGuard logo (shield + monitoring pulse) → clicks to Overview (/)
Role menu infr-nav — 8 role areas, hover reveals a sub-item panel
Right actions mobile menu toggle · locale switcher · theme toggle · user menu

Each top-level item renders as an MDI icon + label + (if it has children) a chevron; children appear in a dropdown panel (infr-nav__panel). When the current path matches a child href, the top-level item gets is-active (Overview is active only when the path is exactly /).

The 8 role areas

This is the top-level tree the SitemapSeeder builds. The body_class is applied to <body> when you enter an area, scoping page styles.

# Role area Owner body_class Min user_level
1 Overview shared infr-overview 1
2 Infrastructure infra ops infr-infra 1
3 Service service ops infr-service 1
4 Security security ops infr-security 2
5 Backup & Recovery infra (also) infr-backup 2
6 Assets shared reference (CMDB) infr-asset 1
7 Administration admin infr-admin 10
8 Development super_admin infr-dev 9

Sub-items per area

Each sub-item carries its own min_req (usually the same as its parent, sometimes raised).

Infrastructure (min_req 1)

Item Path min_req
Health /infra/health 1
Servers /infra/servers 1
Storage & RAID /infra/storage 1
Port Connections /infra/traffic/ports 1
IP Connections /infra/traffic/ips 1
Traffic /infra/traffic/net 1
Alerts /infra/alert 1

Service (min_req 1)

Item Path min_req
Overview /service 1
Web /service/web 1
Database /service/database 1
Sessions /service/session 1
Catalog /service/catalog 1
Projects /service/projects 1
Problem Resolution /service/resolution 2

Security (min_req 2 — all items 2)

Item Path
Overview /security
Threats /security/threats
Detections /security/detections
Rulesets /security/rulesets
Firewall /security/firewall
Blocklist & Reputation /security/blocklist
Whitelist /security/whitelist
Security Diagnostics /security/diagnostics
Problem Resolution /security/resolution

Backup & Recovery (min_req 2): Schedule Board /backup/board · Backup Scripts /backup/scripts · Vaults /backup/vaults · Recovery & Validation /backup/recovery.

Assets (min_req 1): Inventory /asset/inventory · Instances /asset/instances · Hardware /asset/hardware · Storage & Files /asset/storage.

Administration (min_req 10 — all items 10): Users & Roles /admin/users · Collectors /admin/collectors · Operations Policy /admin/ops-policy · API Keys /admin/api-keys · Rules & Thresholds /admin/rules · Reputation API /admin/reputation-providers · AI Adapters /admin/ai-providers · Mail Adapters /admin/mail-providers · SMS Adapters /admin/sms-providers · Localization /admin/localization · Audit /admin/audit.

Development (min_req 9 — all items 9): Dev Overview /dev · Doctor /dev/doctor · Runtime & Leader /dev/leader · Slow Queries/Requests/Jobs/Outgoing · Exceptions · Cache · Servers · Usage · Pulse /pulse · Horizon /horizon.


How to use

Navigating

Hover a top-level item to open its panel. Clicking an item navigates to the screen and applies that area's body_class to <body>. On narrow screens, the top-right hamburger (data-nav-toggle) expands the menu.

What your level sees

At login, the InfrAuth middleware syncs users.user_level into the session key infr_user_level. At render, Menu::for_user($level) walks the tree and recursively hides any node whose min_req > your level. For example:

Development (9) and Administration (10) have different thresholds. A super_admin at exactly level 9 sees Development but not Administration. An admin (10) sees both.

Adding or restructuring the menu (admin/dev)

There is no menu-editing UI yet. The tree's source of truth is code (database/seeders/SitemapSeeder.php), and the seeder deletes all rows and recreates them on every run (canonical resync).

# After editing the tree, resync (touches infr_sitemap only — legacy data is safe)
php artisan db:seed --class=SitemapSeeder

The seeder calls Menu::flush() at the end, so changes take effect immediately. If a new item shows its raw (English) name, it lacks a translation key — add one under resources/lang/{ko,en}/menu.php using the Str::slug(name, '_') rule (e.g. Storage & RAID → storage_raid).

Never run migrate:fresh. InfraGuard shares a connection with the legacy stats-design MySQL. To refresh only the menu, use db:seed --class=SitemapSeeder exclusively.


Data sources

The infr_sitemap table

An independent, app-owned table (distinct from the legacy unprefixed sitemap). Model: App\Models\Infr\InfrSitemap.

Column Meaning
parent_id 0 = top level, else parent node id
seq sibling sort order
depth 0 = role area, 1 = sub-item
name raw name (source of the label key)
href link path (# = non-linking parent)
icon MDI glyph (e.g. mdi-server)
body_class top-level only — <body> class on entry
is_view 1 to include in the tree
min_req minimum user_level (permission boundary)

App\Support\Menu — tree builder + cache

The cache stores the raw name; translation happens at render time via Locales::menuLabel(). So switching languages requires no cache flush. Conversely, adding or renaming nodes requires a re-seed (which flushes).

Label translation

App\Support\Locales::menuLabel($name) looks up the key menu. + Str::slug($name, '_'). If the key exists it translates, otherwise it returns the raw name (safe fallback). Packs live in resources/lang/{locale}/menu.php.

// In the render (nav.blade.php)
{{ \App\Support\Locales::menuLabel($top['name']) }}
// "Storage & RAID" → __('menu.storage_raid') → "Storage & RAID" (en) / "스토리지 · RAID" (ko)

Session and middleware


Access

Level (user_level) Alias Visible in the menu
1 demo/viewer Overview · Infrastructure · Service · Assets (mostly read)
5 staff + Security · Backup & Recovery
9 super_admin + Development
10 admin + Administration (and Development)

For level definitions see RBAC levels; for role/team management see Roles & Teams.


Troubleshooting & FAQ

A menu item is missing. Usually an insufficient level. Check that your user_level is ≥ that node's min_req (see tables above). Admins adjust levels in Users & Teams.

A newly added menu item shows its English (raw) name. The menu.php pack lacks a translation key. Add one to both resources/lang/ko/menu.php and en/menu.php using the Str::slug(name,'_') rule. The screen still works safely with the raw name if the key is absent.

I ran the seeder but the menu didn't change. Stale cache is possible. The seeder calls Menu::flush() at the end, but you can also try php artisan cache:clear. If Redis is down, Menu falls back to build() per request, so caching cannot be the culprit.

I switched languages but only the menu labels didn't change. Labels are resolved at render time, not cached. Verify the target language's menu.php has the key. If not, check activation/translation status on the Localization page.

Can someone reach a hidden screen by typing the URL? No. Even when the menu is hidden, the route middleware (infr.level:N, etc.) returns 403 server-side.


Related

The top navigation, grouped by role area
The top navigation, grouped by role area
The account menu at the far right
The account menu at the far right