Skip to content

refactor: rename Metrics gear URL /history → /metrics + themed 404 - #97

Merged
sarg3nt merged 3 commits into
mainfrom
feature/rename-metrics-url
May 15, 2026
Merged

refactor: rename Metrics gear URL /history → /metrics + themed 404#97
sarg3nt merged 3 commits into
mainfrom
feature/rename-metrics-url

Conversation

@sarg3nt

@sarg3nt sarg3nt commented May 15, 2026

Copy link
Copy Markdown
Owner

Summary

Two related changes that close out the "what does history mean in this codebase" question:

  1. Rename the Metrics gear URL from /history to /metrics end-to-end (page route, API endpoints, handler functions, file name, templ component, sidebar, JS callers, docs).
  2. Add a themed static 404 page wired into chi's NotFound. Anyone with a bookmark to the old /history URL will now land on a Gearbox-styled 404 instead of the browser's default — and the handler is intentionally static (no templ, no auth, no DB) so a typo'd URL can't be a side channel for fingerprinting session state.

Why now

The Metrics gear was historically called "history" because the page shows time-series. That name leaked everywhere: the URL, the API endpoints, the templ file (history.templ), the handler functions (HistoryPage, APIStatsHistoryHandler, …), and assorted comments. With #95's "metric source" / "primary source" terminology landing, the dual naming has become genuinely confusing — particularly because there are other legitimate "history" concepts in the codebase (OS-update apt/zypper history, HAProxy config change history) that should keep their names.

Renaming the Metrics-gear identity isolates "history" to those genuinely-distinct concepts, so a future reader sees history and knows it means OS-update or config-change history, not the Metrics page.

What's renamed

Routes:

  • Page: /history/metrics
  • API: /api/{boxID}/history/stats/api/{boxID}/metrics/stats
  • API: /api/{boxID}/history/metrics/api/{boxID}/metrics/system
  • API: /api/{boxID}/history/backend/{name}/api/{boxID}/metrics/backend/{name} (coexists with the existing /metrics/backend/{name}/details drill-down from #87)

Go identifiers:

  • HistoryPageMetricsPage
  • APIStatsHistoryHandlerAPIMetricsStatsHandler
  • APIBackendHistoryHandlerAPIMetricsBackendHandler
  • APISystemMetricsHistoryHandlerAPIMetricsSystemHandler
  • pages.History() templ component → pages.Metrics()

Files:

  • templates/pages/history.templtemplates/pages/metrics.templ

Docs / comments / sidebar:

  • metrics/README.md routes table, architecture diagram, development snippet
  • cmd/server/main.go route-group comment
  • handler/pages.go migration-history comment
  • models/permissions.go field comment
  • docs/gears.md gear list
  • templates/layouts/base.templ sidebar links (regular + draggable) + current-path match
  • static/js/gears/gears-page.js URL map (both copies)
  • 8 fetch URLs across metrics.templ, details.templ, chart_partials.templ

Intentionally kept as "history"

These are legitimately distinct concepts; renaming would obscure their meaning:

  • DB tables stats_history, system_metrics_history, backend_history — the rows ARE historical records. Renaming requires a migration with no user-visible benefit; the names accurately describe what they contain. The DB read methods (GetStatsHistory, etc.) keep their names for the same reason.
  • Snapshot interval / retention config HistoryIntervalSeconds, store_history, history_retention_days — these control how the historical record is kept.
  • OS-update package-manager history — apt/zypper/dnf/pacman/apk/yum history. /api/v1/system/updates/history, parseAptHistoryLog, /var/log/apt/history.log, /os-updates/history on the dashboard. Untouched.
  • HAProxy config change history/{boxID}/haproxy/config/history, change_history.templ, APIHAProxyConfigHistory. Untouched.

Themed static 404

Wired via r.NotFound(handler.NotFoundHandler) on the root chi router so it inherits only the global middleware (security headers, asset config) and not the auth / session / DB middleware on the protected route groups.

Security posture (enforced by tests):

  • No templ rendering, no auth lookup, no DB queries.
  • HTML is a Go const — no filesystem or template lookup at request time.
  • Inline CSS only — works even if the static-asset bundle didn't load.
  • Does not echo any part of the request (URL, headers, cookies) into the response — guards against the page becoming a reflection vector. TestNotFoundHandlerDoesNotEchoRequestData probes for marker strings in the response body and fails if any leak.
  • Cache-Control: no-store so a 404 doesn't outlive a deploy that later adds the missing route.

Visual: dashboard's blue accent (#2563eb), system fonts (no external font loading), prefers-color-scheme-aware.

Agent module

No changes. The agent's history references are all OS-update package-manager history (apt/zypper/dnf/pacman/apk/yum), which is the legitimate concept. Verified by grep — nothing left that ties to the Metrics gear's identity.

Test plan

  • make test — full gearbox suite green.
  • make test on gearbox-agent — 15 packages green (no changes; verifying nothing collateral).
  • go vet ./... clean.
  • 3 new tests for NotFoundHandler — status/body, no-reflection, stable across HTTP methods.
  • Manual smoke: /metrics loads charts on light-hugger.
  • Manual smoke: visiting /history (the old URL) lands on the themed 404 with a working "Back to dashboard" link.
  • Manual smoke: typing a garbage URL like /lolnope lands on the themed 404.

Follow-up

Separate branch in the next PR: fix the scales.y.ticks.stepSize: 1 would result generating up to 8681 ticks. Limiting to 1000. Chart.js warning spam. Pre-existing issue — three places force stepSize: 1 where precision: 0 would give the intended "integer ticks only" behaviour without making Chart.js generate thousands of tick marks when the data range is large.

🤖 Generated with Claude Code

sarg3nt added 2 commits May 14, 2026 18:00
The Metrics gear was historically called "history" because the page
shows time-series data. That name leaked into the URL (/history), the
API endpoints (/api/{boxID}/history/*), the templ file
(history.templ), the handler functions (HistoryPage,
APIStatsHistoryHandler, …), and assorted comments / docs / README
entries. With nginx / Apache / Caddy / Traefik detection now landing
(issue #95) and "metric source" / "primary source" terminology in the
new code, the dual naming has become genuinely confusing.

This commit renames the metrics-gear identity end-to-end:

- Page route: /history → /metrics (plugin.go SidebarItem.Path,
  base.templ path-prefix match + sidebar links, gears-page.js).
- API routes:
  /api/{boxID}/history/stats             → /api/{boxID}/metrics/stats
  /api/{boxID}/history/metrics           → /api/{boxID}/metrics/system
  /api/{boxID}/history/backend/{name}    → /api/{boxID}/metrics/backend/{name}
  (Last one coexists with /metrics/backend/{name}/details — the
  time-series endpoint vs the drill-down details endpoint added in #87.)
- Handler functions:
  HistoryPage                  → MetricsPage
  APIStatsHistoryHandler       → APIMetricsStatsHandler
  APIBackendHistoryHandler     → APIMetricsBackendHandler
  APISystemMetricsHistoryHandler → APIMetricsSystemHandler
- File: pages/history.templ → pages/metrics.templ
  (templ component History() → Metrics())
- JS callers: history.templ + details.templ + chart_partials.templ
  (8 fetch() URLs updated).
- Docs: metrics gear README routes table + architecture diagram +
  development snippet; cmd/server/main.go route-group comment;
  pages.go migration-history comment; permissions.go field comment;
  docs/gears.md gear list.

Intentionally **kept** as legitimate "history" concepts (per design
discussion):

- DB tables stats_history, system_metrics_history, backend_history —
  the rows ARE historical records. Renaming requires a migration with
  no user-visible benefit; the names accurately describe what they
  contain. The DB query methods that read them (GetStatsHistory,
  GetBackendHistory, GetSystemMetricsHistory) keep their names for
  the same reason.
- Snapshot interval / retention config: HistoryIntervalSeconds,
  store_history, history_retention_days — these control how the
  historical record is kept. Same reasoning.
- Local `history` variable names inside the renamed handler functions
  — they reflect what the DB methods return.
- OS-update apt/zypper/dnf/pacman history — distinct concept.
  /api/v1/system/updates/history on the agent, /os-updates/history on
  the dashboard, parseAptHistoryLog, /var/log/apt/history.log, etc.
  All untouched.
- HAProxy config change history — distinct concept.
  /{boxID}/haproxy/config/history,
  templates/pages/haproxy_config/change_history.templ, etc. Untouched.

Agent module: no changes. The agent's "history" references are all
OS-update package-manager history (apt/zypper/dnf/pacman/apk/yum),
which is the legitimate concept.

Tests + build green on both modules.
Wires chi's NotFound to a self-contained handler so a typo'd URL (or a
bookmark to the now-renamed /history) lands on a small Gearbox-themed
page instead of the browser's default 404. Particularly relevant after
the /history → /metrics rename in this PR — anyone with a bookmark to
the old URL will hit this.

Security posture: the handler is deliberately static end-to-end.

- No templ rendering, no auth middleware, no DB / agent lookups.
- HTML is a Go const so there's no filesystem or template lookup at
  request time.
- Inline CSS only (no <link> tags) so the response works even if the
  static-asset bundle didn't load.
- No request data echoed into the response (test enforces this) —
  guards against the page becoming a reflection vector.
- `Cache-Control: no-store` so a 404 doesn't outlive a deploy that
  later adds the missing route.

Tests:
- TestNotFoundHandlerStatusAndBody: 404 status, HTML body, Cache-
  Control, expected copy.
- TestNotFoundHandlerDoesNotEchoRequestData: URL/header/cookie probes
  don't appear in the response body — handler is fully static.
- TestNotFoundHandlerStableAcrossMethods: GET/POST/PUT/DELETE/PATCH
  all return the same 404 page.

Visual: matches the dashboard's blue accent (#2563eb), uses system
fonts (no external font loading), `prefers-color-scheme`-aware so it
renders in dark mode without JS.
Copilot AI review requested due to automatic review settings May 15, 2026 01:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR renames the Metrics gear's URL surface from /history to /metrics end-to-end (page route, three API endpoints, handler functions, templ component, sidebar entries, JS callers, docs/comments) and adds a themed static 404 handler wired into chi's NotFound. DB tables, retention config, OS-update package-manager history, and HAProxy config-change history intentionally retain the "history" name. The 404 handler is deliberately self-contained (inline HTML const, no auth/DB/templ) so unmatched URLs cannot leak session state, and ships with three new tests.

Changes:

  • Rename /history/metrics (page route, three API endpoints, Go identifiers, templ component, sidebar/JS/docs).
  • Add NotFoundHandler with a themed inline-HTML 404 page wired via r.NotFound(...), plus tests asserting status, no request-data reflection, and stability across HTTP methods.
  • Update Metrics gear README, package doc comments, gears.md, and main.go route-group comments to reflect the rename.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
gearbox/cmd/server/main.go Wires NotFoundHandler on root router; renames three API routes; updates route-group comment.
gearbox/internal/framework/handler/not_found.go New static 404 handler with inline-HTML const.
gearbox/internal/framework/handler/not_found_test.go Tests for status/headers/body, no-reflection, and method stability.
gearbox/internal/framework/handler/api_stats.go Renames three handler funcs to APIMetrics{Stats,Backend,System}Handler with updated docs.
gearbox/internal/framework/handler/pages.go Comment update for MetricsPage mapping.
gearbox/internal/framework/templates/pages/metrics.templ Templ component renamed HistoryMetrics; updated fetch URLs and Base layout path.
gearbox/internal/framework/templates/pages/details.templ Updates backend-history fetch to /metrics/backend/....
gearbox/internal/framework/templates/layouts/base.templ Sidebar links and current-path matcher use /metrics.
gearbox/internal/framework/models/permissions.go Updates metrics:view permission comment.
gearbox/internal/gears/metrics/plugin.go Updates package doc, gear display name/description, sidebar path, route comments.
gearbox/internal/gears/metrics/handlers.go Renames HistoryPageMetricsPage and updates log/render calls.
gearbox/internal/gears/metrics/chart_partials.templ Updates 6 fetch URLs from /history/* to /metrics/{stats,system}.
gearbox/internal/gears/metrics/README.md Updates routes table, file layout, dev snippet, and adds rename note.
gearbox/static/js/gears/gears-page.js Updates two metrics → /history URL maps to /metrics.
docs/gears.md Updates gear list entry for Metrics.

Comment thread gearbox/internal/gears/metrics/README.md Outdated
@sarg3nt
sarg3nt merged commit 669318f into main May 15, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants