Skip to content

admin: read admin_path_prefix from /auth/me + build admin URLs from it#48

Merged
mastermanas805 merged 1 commit into
mainfrom
feat/admin-path-prefix-ui-fresh
May 13, 2026
Merged

admin: read admin_path_prefix from /auth/me + build admin URLs from it#48
mastermanas805 merged 1 commit into
mainfrom
feat/admin-path-prefix-ui-fresh

Conversation

@mastermanas805
Copy link
Copy Markdown
Member

Summary

Pairs with api PR #50. The admin customer-management endpoints now register on the agent API under /api/v1/<prefix>/customers/... where <prefix> is a 32+ char alphanumeric secret with the same blast radius as a session token. This PR teaches the dashboard to read the prefix from /auth/me and build the URLs from it client-side.

Changes:

  • AuthMeResponse extended with admin_path_prefix?: string.
  • fetchMe() stashes the value in a module-local var; logout() clears it.
  • getAdminPathPrefix() + setAdminPathPrefix() are the only public read/write seams; buildAdminURL() is the single point that turns the stash into a request path.
  • The 4 admin API functions (listAdminCustomers, getAdminCustomer, setAdminCustomerTier, issueAdminCustomerPromo) call buildAdminURL() instead of hardcoding /api/v1/admin/. With no prefix loaded, every builder throws APIError{status:403, code:"admin_endpoints_unavailable"}.
  • AdminCustomersPage's route gate is now is_platform_admin && admin_path_prefix (belt-and-braces — the flag without a prefix would render a broken page).
  • AppShell hides the sidebar link under the same compound condition.
  • The prefix is treated as a credential: never logged, never echoed into rendered UI text.

Test plan

  • npm test — 382/382 unit tests pass (17 test files); 6 new tests in src/api/index.test.ts:
    • fetchMe stashes admin_path_prefix when the API serves it
    • fetchMe leaves the prefix empty when the API omits the field
    • logout clears the stashed admin prefix
    • admin builders mint /api/v1/<prefix>/customers when the prefix is set
    • admin builders throw admin_endpoints_unavailable when the prefix is empty
    • admin builders never include /admin/ in the request URL (covers the "prefix contains 'admin' substring" edge case)
  • npx tsc --noEmit — clean
  • AdminCustomersPage.test.tsx mock updated to surface admin_path_prefix so the page gate sees both signals
  • Manual: deploy + admin user verifies the page loads with a fresh /auth/me; non-admin user verifies the sidebar link is hidden and direct navigation to /app/admin/customers redirects to /

🤖 Generated with Claude Code

Pairs with api PR for ADMIN_PATH_PREFIX. The admin customer-management
endpoints now live under /api/v1/<prefix>/customers/... rather than the
guessable /api/v1/admin/customers/... — the prefix is a 32+ char alnum
secret with the same blast radius as a session token.

Changes:
  - AuthMeResponse extended with admin_path_prefix?: string.
  - fetchMe() stashes the value in a module-local var; logout() clears it.
  - getAdminPathPrefix() + setAdminPathPrefix() exported for tests + the
    route gate; buildAdminURL() is the single point that turns the stash
    into a request path.
  - The 4 admin API functions (listAdminCustomers, getAdminCustomer,
    setAdminCustomerTier, issueAdminCustomerPromo) call buildAdminURL()
    instead of hardcoding /api/v1/admin/. With no prefix loaded, every
    builder throws APIError{status:403, code:"admin_endpoints_unavailable"}.
  - AdminCustomersPage's gate is now is_platform_admin AND admin_path_prefix
    (belt-and-braces — flag-without-prefix would render a broken page).
  - AppShell hides the sidebar link under the same compound condition.
  - The prefix is treated as a credential: never logged, never echoed
    into rendered UI text.

Tests: 6 new unit tests in api/index.test.ts cover the stash/clear/
URL-build/throw paths; existing 382 unit tests still pass; tsc clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mastermanas805 mastermanas805 merged commit 59e1d1f into main May 13, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant