Skip to content

Operator dashboard: 14 dead nav links (entire Build + Infrastructure groups, plus Operate→Logs) 404 #121

Description

@AbirAbbas

Summary

The operator dashboard (apps/dashboard) renders a full sidebar from src/lib/nav.ts, but 14 of the declared nav routes have no corresponding App Router page and return a hard 404 ("This page could not be found"). The entire Build group and all of the Infrastructure group are dead, plus Operate → Logs.

Reproduce: open the dashboard and click any item under Build or Infrastructure, e.g. http://<dashboard>/build/agents.

Dead links (14)

There is no /build route directory at all under apps/dashboard/src/app/(admin)/, and no /operate/logs.

Build group (9)

  • /build/agents
  • /build/integrations
  • /build/webhooks
  • /build/auth
  • /build/billing
  • /build/mcp
  • /build/skills
  • /build/modules
  • /build/dashboard-plugins

Infrastructure group (4 — also under the /build/ path prefix)

  • /build/adapters
  • /build/database
  • /build/storage
  • /build/secrets

Operate group (1)

  • /operate/logs

Everything else (Home, the rest of Operate, Customers, Settings) resolves correctly.

Root cause

nav.ts is the single source of truth for the sidebar + ⌘K palette and mirrors docs/dashboard-ia.md, but the matching page.tsx files were never created for these routes. There is also no automated guard asserting that every nav href resolves to a real route, so the drift went unnoticed.

Backing data already exists

The dashboard API client (apps/dashboard/src/lib/api.ts) already exposes methods for nearly every missing page (api.agents(), api.mcp.servers(), api.skills.list(), api.modulesState(), api.plugins(), api.tools.adapters(), api.db.tables(), api.storage.list(), api.secrets.list(), api.billing.customers(), api.webhooks.endpoints(), api.harnesses.list(), api.tools.listNative()).

Two need a thin client addition where the backend endpoint already exists:

  • LogsGET /api/v1/logs (services/runtime/internal/server/logs.go) returns {lines: LogLine[]}; LogLineSchema is already defined, only the api.logs() method is missing.
  • AuthGET /api/v1/oauth/providers (services/runtime/internal/server/oauth.go) returns {providers: {name, configured, default_scopes[]}[]}; needs a schema + api.oauth.providers() method.

So all 14 can ship as real, data-backed pages following the existing operate/* page pattern (server component + graceful empty-state when the runtime endpoint isn't live).

Plan

  1. Add the two missing API client methods (logs, oauth.providers).
  2. Build all 14 pages as data-backed server components matching the established operate/* pattern (PageHeader + data render + dashed empty-state on ApiError).
  3. Add an automated route-existence test (dependency-free Node test wired into pnpm -r test) that walks every href in nav.ts and asserts a matching App Router page exists — so this class of dead link can never regress silently.
  4. Verify with pnpm --filter dashboard build (type-checks every page) + the new test + lint/prettier.

Validation contract

  • Every href declared in nav.ts (and via plugins) resolves to a rendered page — no 404s from the sidebar or ⌘K.
  • Each new page renders its data when the runtime endpoint returns data, and a clean empty-state (not a crash) when the endpoint is unavailable/returns an error.
  • Customers/* pages remain MT-gated (unchanged behavior).
  • The route-existence test fails if any nav link lacks a page, and passes once all 14 are added.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions