diff --git a/CLAUDE.md b/CLAUDE.md index b2b8bd2..ffc090e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -467,7 +467,7 @@ window, answering 429 with `Retry-After`; cookie sessions are untouched; it exists so a runaway script cannot take an instance down, not as the general API rate-limiting project some future ticket might build. -**The UI calls them API keys and lives at `/api-keys`, not on `/settings`.** +**The UI calls them API keys and lives at `/tokens`, not on `/settings`.** The page is reachable at **every** role, which is the whole reason it is a page: `/settings` is owner|admin throughout, so a card there hid a capability every member has. `settings.api_token_max_days` stays on `/settings` because it is @@ -1022,7 +1022,7 @@ Customer nav is three destinations — Overview, People, Billing. Settings is in | `/steps` | Reusable step library | | `/monitors`, `/monitors/new`, `/monitors/[id][/edit]` | Checks, uptime, incidents | | `/secrets`, `/secrets/[group]` | Vault | -| `/api-keys` | Personal API keys — reachable at **every** role, unlike `/settings` | +| `/tokens` | Personal API keys — reachable at **every** role, unlike `/settings` | | `/audit` | Audit log | | `/settings`, `/settings/notifications`, `/settings/license` | Members, OIDC, alerts, retention, ESO token · channels · licence | diff --git a/web/app/(app)/settings/page.tsx b/web/app/(app)/settings/page.tsx index f1688de..78d2166 100644 --- a/web/app/(app)/settings/page.tsx +++ b/web/app/(app)/settings/page.tsx @@ -297,7 +297,7 @@ export default function SettingsPage() { - {/* The cap lives here rather than on /api-keys because it is + {/* The cap lives here rather than on /tokens because it is instance policy, not one person's credentials — which is also what lets that page be reachable at every role. */}

Keys themselves are managed on{" "} - + API Keys , which every member can reach. diff --git a/web/app/(app)/api-keys/page.tsx b/web/app/(app)/tokens/page.tsx similarity index 100% rename from web/app/(app)/api-keys/page.tsx rename to web/app/(app)/tokens/page.tsx diff --git a/web/components/Sidebar.tsx b/web/components/Sidebar.tsx index 806cfab..ef316a6 100644 --- a/web/components/Sidebar.tsx +++ b/web/components/Sidebar.tsx @@ -185,7 +185,7 @@ const navGroups: NavGroup[] = [ // Not adminOnly: the API lets any member mint and revoke their own // keys, capped at their own role, so gating the page would hide a // capability they have. - { href: "/api-keys", label: "API Keys", icon: }, + { href: "/tokens", label: "API Keys", icon: }, ], }, { diff --git a/web/next.config.ts b/web/next.config.ts index 8c42919..30a10ba 100644 --- a/web/next.config.ts +++ b/web/next.config.ts @@ -8,6 +8,20 @@ const apiUrl = process.env.API_URL ?? process.env.NEXT_PUBLIC_API_URL ?? "http:/ const nextConfig: NextConfig = { output: "standalone", + async redirects() { + return [ + { + // The API keys page briefly lived at /api-keys, which every + // raw-prefix proxy in front of this app captures with its /api + // rule — nginx's `location /api` matches /api-keys, so the + // request reached the Go server and 404'd. The page is at + // /tokens now precisely because that cannot happen to it. + source: "/api-keys", + destination: "/tokens", + permanent: true, + }, + ]; + }, async rewrites() { return [ {