Files
GearBox/.planning/phases/36-admin-role-panel-foundation/36-02-SUMMARY.md

3.0 KiB

plan, phase, title, status, completed
plan phase title status completed
36-02 36 Client /admin route, admin shell with sidebar, UserMenu admin link complete 2026-04-19

What Was Built

Client-side admin foundation for Phase 36:

  1. AuthState.isAdminsrc/client/hooks/useAuth.ts AuthState interface updated with isAdmin?: boolean in the user object type. The hook fetches from /api/auth/me which now returns this field after plan 36-01.

  2. Admin layout routesrc/client/routes/admin.tsx with createFileRoute("/admin"):

    • useEffect guard redirects non-admin users to / (chosen over beforeLoad because router context is {} — no queryClient available at route load time).
    • Returns null while loading or if not admin — no flash of admin shell.
    • Sidebar with "Admin" heading and two disabled nav items: "Items" (package icon, "Soon" badge) and "Tags" (tag icon, "Soon" badge).
    • <Outlet /> renders child routes in the main content area.
  3. Admin index placeholdersrc/client/routes/admin/index.tsx with createFileRoute("/admin/"):

    • Centered placeholder with shield icon, "Admin Panel" text, and "Select a section from the sidebar" subtext.
  4. UserMenu Admin linksrc/client/components/UserMenu.tsx:

    • Conditional {auth?.user?.isAdmin && (...)} block renders an Admin link (shield icon, to="/admin") at the top of the dropdown menu.
    • Followed by a border-t border-gray-100 my-1 divider before the existing Profile link.
    • Non-admin users see no Admin link or divider.
  5. Route tree regeneratedsrc/client/routeTree.gen.ts updated with /admin and /admin/ routes.

  6. __root.tsx unchanged/admin is correctly absent from isPublicRoute, so unauthenticated users hitting /admin are redirected to /login by the root guard. The admin route's own guard handles non-admin authenticated users.

Key Files

  • src/client/hooks/useAuth.ts — isAdmin? in AuthState interface
  • src/client/routes/admin.tsx — admin layout with sidebar shell and guard
  • src/client/routes/admin/index.tsx — admin index placeholder
  • src/client/components/UserMenu.tsx — conditional Admin link
  • src/client/routeTree.gen.ts — regenerated with /admin routes

Deviations

  • Used useEffect + navigate guard instead of beforeLoad — the plan's primary recommendation. beforeLoad was documented as an alternative but requires queryClient in router context which is not configured (context: {}). The useEffect approach is functionally equivalent and renders null during the auth check so no flash occurs.

Self-Check: PASSED

  • src/client/routes/admin.tsx exists with createFileRoute("/admin") and guard logic
  • src/client/routes/admin/index.tsx exists with placeholder UI
  • Admin sidebar renders "Items" (package icon) and "Tags" (tag icon) both disabled with "Soon" badge
  • Non-admin redirect implemented via useEffect
  • UserMenu shows Admin link when auth.user.isAdmin is true
  • bun run build exits 0
  • routeTree.gen.ts includes /admin and /admin/ routes