Files

4.8 KiB

Phase 36: Admin Role & Panel Foundation - Context

Gathered: 2026-04-19 Status: Ready for planning

## Phase Boundary

Add an isAdmin boolean to the users table, protect the /admin route (server middleware + client guard), build a structured admin shell with sidebar navigation, and surface isAdmin to the client via /api/auth/me. Admin status is granted directly via SQL/Drizzle Studio — no CLI script needed.

## Implementation Decisions

Schema

  • D-01: Add isAdmin boolean NOT NULL DEFAULT false to the users table via Drizzle migration.
  • D-02: No Logto role claims — isAdmin lives entirely in the GearBox database.

Admin Grant Mechanism

  • D-03: No CLI script. Developers grant/revoke admin status via direct SQL (UPDATE users SET is_admin = true WHERE ...) or Drizzle Studio. This is acceptable for a single-admin app.

Route Protection

  • D-04: New requireAdmin middleware (extends requireAuth) — returns 403 JSON for any non-admin hitting /api/admin/* endpoints.
  • D-05: TanStack Router beforeLoad guard on the /admin client route — redirects non-admin users to home (/). Belt-and-suspenders: server 403 + client redirect.
  • D-06: Show a conditional "Admin" link for admin users in the user avatar/menu area of the top nav (not a top-level nav item). Keeps it scoped to account-level actions.
  • D-07: isAdmin is surfaced to the client by adding it to the /api/auth/me response. No separate query needed.

Admin Panel Layout

  • D-08: /admin renders a structured shell with a sidebar nav — not an empty placeholder. The shell has two nav items: Items and Tags (matching phases 37 and 38 respectively). Both are disabled/coming-soon in this phase.
  • D-09: This layout is the reusable admin frame — phases 37 and 38 replace the placeholder content areas without reworking the shell.

Claude's Discretion

  • Exact visual styling of the admin shell (consistent with app's light/minimal aesthetic)
  • Whether to add a dedicated /admin server-side route handler or reuse the SPA catch-all
  • How to structure the requireAdmin middleware relative to requireAuth (wrapping vs. separate)

<canonical_refs>

Canonical References

Downstream agents MUST read these before planning or implementing.

Auth & Middleware

  • src/server/middleware/auth.ts — existing requireAuth middleware; requireAdmin should follow the same pattern
  • src/server/services/auth.service.tsgetOrCreateUser and user DB patterns

Database Schema

  • src/db/schema.tsusers table definition; add isAdmin here
  • src/server/routes/auth.ts/api/auth/me endpoint; add isAdmin to response

Client Routing & Nav

  • src/client/routes/__root.tsx — root layout with top nav + user menu; add conditional Admin link
  • src/client/routes/ — TanStack Router file-based routes; create admin.tsx and admin/ directory

Requirements

  • .planning/REQUIREMENTS.md — ROLE-01, ROLE-02, ADMN-01

</canonical_refs>

<code_context>

Existing Code Insights

Reusable Assets

  • requireAuth middleware (src/server/middleware/auth.ts): requireAdmin follows the same Context/Next signature — call requireAuth first, then check isAdmin from the resolved user record
  • Existing Hono route patterns in src/server/routes/ — admin routes follow the same structure
  • TanStack Router file-based routing — /admin becomes src/client/routes/admin.tsx (or admin/index.tsx)

Established Patterns

  • Auth middleware sets userId on Hono context; requireAdmin reads the users record to check isAdmin
  • /api/auth/me already returns { user, authenticated } — add isAdmin to the user object
  • Light/airy design aesthetic — admin shell should match app visual style (white, minimal, no visual clutter)

Integration Points

  • src/server/index.ts: Register new /api/admin/* routes behind requireAdmin
  • src/client/routes/__root.tsx: Conditional Admin link in user menu (reads isAdmin from auth query)
  • src/db/schema.ts + migration: isAdmin column on users table

</code_context>

## Specific Ideas
  • Admin sidebar: two sections "Items" (phase 37) and "Tags" (phase 38) — both greyed out / "Coming soon" in this phase
  • The admin shell is the persistent frame; phases 37/38 inject content into a <Outlet> or equivalent
## Deferred Ideas
  • Logto UI-based admin management — not possible without switching to Logto role claims (explicitly ruled out)
  • Users section in admin sidebar — not in current roadmap, deferred to a future milestone if needed
  • Formal CLI tool for admin grant — deemed unnecessary given direct SQL access

Phase: 36-admin-role-panel-foundation Context gathered: 2026-04-19