docs(37): capture phase context
This commit is contained in:
116
.planning/phases/37-admin-global-item-management/37-CONTEXT.md
Normal file
116
.planning/phases/37-admin-global-item-management/37-CONTEXT.md
Normal file
@@ -0,0 +1,116 @@
|
||||
# Phase 37: Admin — Global Item Management - Context
|
||||
|
||||
**Gathered:** 2026-04-19
|
||||
**Status:** Ready for planning
|
||||
|
||||
<domain>
|
||||
## 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.
|
||||
|
||||
</domain>
|
||||
|
||||
<decisions>
|
||||
## 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)
|
||||
|
||||
</decisions>
|
||||
|
||||
<canonical_refs>
|
||||
## Canonical References
|
||||
|
||||
**Downstream agents MUST read these before planning or implementing.**
|
||||
|
||||
### Existing Service Layer
|
||||
- `src/server/services/global-item.service.ts` — `searchGlobalItems`, `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.ts` — `requireAdmin` 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.ts` — `globalItems`, `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.ts` — `apiGet`, `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>
|
||||
|
||||
<specifics>
|
||||
## 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
|
||||
|
||||
</specifics>
|
||||
|
||||
<deferred>
|
||||
## 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
|
||||
|
||||
</deferred>
|
||||
|
||||
---
|
||||
|
||||
*Phase: 37-admin-global-item-management*
|
||||
*Context gathered: 2026-04-19*
|
||||
@@ -0,0 +1,75 @@
|
||||
# Phase 37: Admin — Global Item Management - Discussion Log
|
||||
|
||||
> **Audit trail only.** Do not use as input to planning, research, or execution agents.
|
||||
> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
|
||||
|
||||
**Date:** 2026-04-19
|
||||
**Phase:** 37 — Admin — Global Item Management
|
||||
**Areas discussed:** List view style, Edit workflow, Brand/manufacturer field, Delete confirmation
|
||||
|
||||
---
|
||||
|
||||
## List view style
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Data table | Dense rows with columns for brand, model, category, weight, price, tags, owner count. Sortable, scannable, admin-appropriate. | ✓ |
|
||||
| Card grid | Consistent with public catalog. Reuses GearImage/card patterns but wastes space for data management. | |
|
||||
| List rows (compact) | Single-line rows with brand/model + a few stats. Middle ground. | |
|
||||
|
||||
**User's choice:** Data table
|
||||
|
||||
**Table columns selected:** Brand + Model, Category + Weight + Price, Tags, Owner count
|
||||
|
||||
**Pagination:** Server-side infinite scroll — load next page on scroll, not explicit next/prev buttons
|
||||
|
||||
---
|
||||
|
||||
## Edit workflow
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Dedicated edit page /admin/items/$id | Full-page form, bookmarkable, consistent with detail page pattern. | ✓ |
|
||||
| Slide-over drawer | Slides in over list, keeps list context. Requires new drawer component. | |
|
||||
|
||||
**User's choice:** Dedicated edit page
|
||||
|
||||
**Delete location:** Edit page only (not on list)
|
||||
|
||||
---
|
||||
|
||||
## Brand/manufacturer field
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Dropdown of existing manufacturers | Admin picks from list fetched from /api/manufacturers. Safe, no duplicates. | ✓ |
|
||||
| Free-text with auto-match | Admin types brand; matched or created on save. Risks duplicates. | |
|
||||
|
||||
**User's choice:** Dropdown of existing manufacturers
|
||||
|
||||
---
|
||||
|
||||
## Delete confirmation
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Impact-aware | Show item name + owner count: "3 users have this in their collection. This cannot be undone." | ✓ |
|
||||
| Simple confirmation | "Are you sure? This cannot be undone." No extra data. | |
|
||||
|
||||
**User's choice:** Impact-aware confirmation with owner count
|
||||
|
||||
---
|
||||
|
||||
## Claude's Discretion
|
||||
|
||||
- Column sort order and default sort
|
||||
- Tags column display (chips vs count badge)
|
||||
- Edit form field layout (single vs two-column)
|
||||
- IntersectionObserver implementation for infinite scroll trigger
|
||||
- Delete button styling and position on edit page
|
||||
|
||||
## Deferred Ideas
|
||||
|
||||
- Manufacturer creation from within admin panel (out of scope for this phase)
|
||||
- Bulk delete / bulk edit from the list
|
||||
- Column sorting (not in success criteria; Claude's discretion)
|
||||
Reference in New Issue
Block a user