Files
GearBox/.planning/phases/37-admin-global-item-management/37-CONTEXT.md

5.9 KiB

Phase 37: Admin — Global Item Management - Context

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

## Phase Boundary

Build the /admin/items list and /admin/items/$id edit page, wired into the Phase 36 admin shell. Admins can browse all global catalog items, open and edit any item's full field set, and delete items with an impact-aware confirmation. No new capabilities beyond browse/edit/delete.

## Implementation Decisions

List View

  • D-01: Data table layout — dense rows with sortable columns. No card grid. No existing table component; implement with plain Tailwind-styled HTML table.
  • D-02: Columns: Brand + Model | Category | Weight | Price | Tags (chip or count) | Owner Count | Actions.
  • D-03: Server-side infinite scroll pagination — load next page as admin scrolls down. No explicit next/prev buttons. Consistent with IntersectionObserver scroll detection. 50 items per page is a sensible default.

Edit Workflow

  • D-04: Dedicated edit page at /admin/items/$itemId — full-page form, bookmarkable. Consistent with the item/catalog detail page pattern already in the app.
  • D-05: Delete lives on the edit page only (not on the list). Admin must open an item to delete it.

Brand / Manufacturer Field

  • D-06: Dropdown of existing manufacturers (fetched from /api/manufacturers). Admin picks from the list — no free-text brand creation in this phase. Prevents accidental duplicate manufacturers.

Delete Confirmation

  • D-07: Impact-aware confirmation dialog: show item name + owner count before confirming. Example: "Delete Salsa Woodsmoke 700? 3 users have this in their collection. This cannot be undone." Owner count already available from getGlobalItemWithOwnerCount.

Claude's Discretion

  • Exact column sort order and default sort (brand asc is reasonable)
  • Whether tags column shows chips or a count badge when many tags exist
  • Form field layout on the edit page (single column vs. two-column grid for compact fields)
  • How the infinite scroll trigger is implemented (IntersectionObserver sentinel div)
  • Styling of the delete button (destructive red, positioned at bottom of edit form)

<canonical_refs>

Canonical References

Downstream agents MUST read these before planning or implementing.

Existing Service Layer

  • src/server/services/global-item.service.tssearchGlobalItems, getGlobalItemWithOwnerCount, upsertGlobalItem; DELETE function needs to be added here
  • src/server/routes/global-items.ts — existing GET/POST endpoints (public); admin DELETE will go through /api/admin/items route

Admin Infrastructure (Phase 36)

  • src/server/routes/admin.ts — admin route stub; extend with item sub-routes here
  • src/server/middleware/auth.tsrequireAdmin middleware already in place
  • src/client/routes/admin.tsx — admin shell layout with <Outlet />; "Items" nav item needs to be enabled (remove cursor-not-allowed, add active link)

Client Routes

  • src/client/routes/admin/index.tsx — admin index placeholder; stays as-is
  • TanStack Router file-based routing: create admin/items.tsx (list) and admin/items/$itemId.tsx (edit)

Database Schema

  • src/db/schema.tsglobalItems, manufacturers, tags, globalItemTags tables

Existing Reusable Hooks / Patterns

  • src/client/hooks/ — React Query hooks pattern; add useAdminGlobalItems (infinite query) and useAdminGlobalItem
  • src/client/lib/api.tsapiGet, apiDelete, apiPut fetch wrappers
  • src/server/routes/manufacturers.ts (or similar) — GET /api/manufacturers for the brand dropdown

Requirements

  • .planning/REQUIREMENTS.md — ADMN-02, ADMN-03, ADMN-04

</canonical_refs>

<code_context>

Existing Code Insights

Reusable Assets

  • getGlobalItemWithOwnerCount service function: already returns ownerCount — reuse for delete confirmation and edit page header
  • upsertGlobalItem service: handles create and update via onConflictDoUpdate; admin edit will call this directly (PUT /api/admin/items/:id)
  • ImageUpload component (src/client/components/) — reuse for image field on edit page
  • useFormatters() hook — reuse for weight/price display in the table
  • LucideIcon "package" already in the admin sidebar "Items" entry — just enable it

Established Patterns

  • Infinite scroll: Phase 26 discovery feed used cursor pagination + React Query's useInfiniteQuery — same pattern here
  • Edit forms: item/catalog detail pages use controlled form state with apiPut
  • Destructive confirmation: confirm modals exist in the app (setup delete, etc.) — reuse the same modal pattern
  • React Query invalidation: mutations call queryClient.invalidateQueries with relevant query keys

Integration Points

  • src/client/routes/admin.tsx: Change "Items" sidebar entry from <div cursor-not-allowed> to <Link to="/admin/items"> with active styling
  • src/server/index.ts: Register adminItemRoutes under /api/admin/items
  • src/server/routes/admin.ts: Mount item sub-router

</code_context>

## Specific Ideas
  • Table row click → navigate to /admin/items/$itemId
  • Edit page has a back link "← Items" to return to the list
  • Delete button at bottom of edit form, styled destructive red, triggers impact-aware modal
  • Infinite scroll sentinel: a <div ref={sentinelRef}> at bottom of table; IntersectionObserver triggers next page fetch
## Deferred Ideas
  • Manufacturer creation from within the admin panel — admin can only pick existing manufacturers in this phase; creating new ones is out of scope
  • Bulk delete / bulk edit from the list — admin-only single-item workflow for now
  • Column sorting — mentioned as a potential feature but not in ADMN-02/03/04 success criteria; Claude's discretion whether to include basic sort

Phase: 37-admin-global-item-management Context gathered: 2026-04-19