9.0 KiB
Phase 22: Add-from-Catalog & Thread Integration - Context
Gathered: 2026-04-06 Status: Ready for planning
## Phase BoundaryWire the actual add-to-collection and add-to-thread flows from the catalog search overlay and global item detail pages. Currently, the CatalogSearchOverlay has a stub handleAddStub and the global item detail page has a console.log placeholder. This phase makes those buttons functional: adding a catalog item to collection creates a reference item with globalItemId, and adding to a thread creates a candidate with globalItemId. Thread resolution with catalog-linked candidates already works (Phase 19).
Add-to-Collection Flow
- D-01: Clicking "Add" on a catalog search card (in collection mode) or "Add to Collection" on the global item detail page opens a compact confirmation modal.
- D-02: The modal contains: category dropdown (pre-populated from user's categories, defaulting to the global item's category if a match exists), optional notes field, optional purchase price field, and "Add to Collection" / "Cancel" buttons.
- D-03: Submitting the modal calls
POST /api/itemswithglobalItemIdset to the catalog item's ID, plus the personal fields (categoryId, notes, purchasePriceCents). Name, weight, price come from global item via service layer merge (Phase 19 pattern). - D-04: After successful add, show a brief success toast ("Added to Collection"). User stays in the search overlay (or remains on the detail page) to continue browsing/adding.
- D-05: The modal reuses form field patterns from ItemForm (category dropdown, notes textarea) but is a standalone lightweight component — not the full ItemForm.
Add-to-Thread Flow (Existing Thread)
- D-06: When
catalogSearchMode === "thread"and user clicks "Add" on a search card, show a modal with a thread picker dropdown listing active (non-resolved) threads. - D-07: User selects a thread, then the modal creates a candidate via
POST /api/threads/:threadId/candidateswithglobalItemId,name(from global item brand+model),categoryId(from thread's category), and other global item data. - D-08: After successful candidate add, show success toast ("Added to [Thread Name]"). User stays in search overlay.
- D-09: If no active threads exist, the thread picker shows an empty state with a "Create Thread First" link/button that opens the existing CreateThreadModal.
Start New Thread Flow (FAB "Start Thread")
- D-10: "Start Thread" from FAB opens catalog search in thread mode (
catalogSearchMode === "thread"). - D-11: When the user clicks "Add" on the first item and no thread is selected yet, show a combined modal: thread name + category fields (matching CreateThreadModal) plus the candidate is auto-added upon thread creation.
- D-12: After the thread is created with its first candidate, subsequent "Add" clicks in the same search session default to adding to the just-created thread (thread ID stored in overlay state).
- D-13: The thread picker dropdown (D-06) also includes a "New Thread..." option that triggers the combined creation flow.
Global Item Detail Page Integration
- D-14: The "Add to Collection" button on
/global-items/:idtriggers the same add-to-collection modal (D-01-D-05), passing the global item's data. - D-15: Add an "Add to Thread" button alongside "Add to Collection" on the detail page, triggering the thread picker modal (D-06-D-09).
Catalog Search Overlay Updates
- D-16: Replace
handleAddStubwith actual handler that opens the appropriate modal based oncatalogSearchMode. - D-17: In "collection" mode, Add button opens add-to-collection modal directly.
- D-18: In "thread" mode, Add button opens thread picker modal.
- D-19: Add a session-level
selectedThreadIdstate to CatalogSearchOverlay (or UIStore) to remember the thread selection within a search session.
UIStore / State Changes
- D-20: Add modal state:
addToCollectionModal: { open: boolean; globalItemId: number | null }. - D-21: Add modal state:
addToThreadModal: { open: boolean; globalItemId: number | null; globalItemName: string | null }. - D-22: Add session thread tracking:
catalogSessionThreadId: number | null— reset when overlay closes.
Claude's Discretion
- Modal animation style and exact layout proportions
- Whether category dropdown auto-selects based on global item category name match or leaves unselected
- Toast notification library/pattern (existing toast pattern if one exists, or simple inline notification)
- Whether the thread picker shows thread category alongside name
- Exact field ordering in the add-to-collection modal
- Whether purchase price field uses currency formatting input or plain number
<canonical_refs>
Canonical References
Downstream agents MUST read these before planning or implementing.
Design Spec
docs/superpowers/specs/2026-04-05-catalog-driven-gear-flow-design.md— Full catalog-driven gear flow vision. Phase 22 implements Flows 1 and 2 (add-to-collection, add-to-thread).
Key Components to Modify
src/client/components/CatalogSearchOverlay.tsx— ReplacehandleAddStubwith real handlers (lines 111-114)src/client/routes/global-items/$globalItemId.tsx— Wire "Add to Collection" button (line 133)src/client/stores/uiStore.ts— Add modal states for add-to-collection and add-to-thread
Existing Hooks/Mutations to Use
src/client/hooks/useItems.ts—useCreateItem()for adding reference items to collectionsrc/client/hooks/useCandidates.ts—useCreateCandidate(threadId)for adding catalog items as thread candidatessrc/client/hooks/useGlobalItems.ts—useGlobalItem(id)for fetching global item details
Schemas (support globalItemId already)
src/shared/schemas.ts—createItemSchemahasglobalItemIdoptional field (line 13),createCandidateSchemahasglobalItemId(line 63)
Services (reference item pattern already works)
src/server/services/item.service.ts— Creates reference items whenglobalItemIdis providedsrc/server/services/thread.service.ts—resolveThread()handles catalog-linked candidates (line 312+)
Prior Phase Context
.planning/phases/19-reference-item-model-tags-schema/19-CONTEXT.md— Reference item model decisions (D-01 through D-13).planning/phases/20-fab-full-screen-catalog-search/20-CONTEXT.md— Catalog search overlay decisions, UIStore patterns.planning/phases/21-item-catalog-detail-pages/21-CONTEXT.md— Detail page stubs that need wiring
Requirements
.planning/REQUIREMENTS.md— CATFLOW-03, CATFLOW-05, CATFLOW-06
</canonical_refs>
<code_context>
Existing Code Insights
Reusable Assets
useCreateItem()hook — creates items via POST /api/items, already supportsglobalItemIdfielduseCreateCandidate(threadId)hook — creates candidates via POST /api/threads/:threadId/candidates, supportsglobalItemIdCreateThreadModal— modal pattern with form fields, can inform the combined thread+candidate creation modalCatalogSearchOverlay— already hascatalogSearchModeto distinguish collection vs thread flowsuseCategories()hook — for category dropdown in confirmation modaluseThreads()hook — for thread picker dropdownuseFormatters()— weight/price formatting for modal displayuseGlobalItem(id)— fetch individual global item details
Established Patterns
- Zustand UIStore for modal open/close state
- TanStack React Query mutations with
invalidateQuerieson success - Compact modals with backdrop dimming (CreateThreadModal pattern)
apiPostfor creating resources- Category dropdown pattern from ItemForm (select with category list)
Integration Points
CatalogSearchOverlay.tsxline 111-114 —handleAddStubreplacementglobal-items/$globalItemId.tsxline 133 — "Add to Collection" button wiringuiStore.ts— new modal state slices- New components:
AddToCollectionModal,AddToThreadModal(or combinedCatalogAddModal)
</code_context>
## Specific Ideas- The add-to-collection modal should be lightweight — category picker + optional notes + purchase price. Not a full item form. One click to add.
- Thread picker should show thread name and category for easy identification.
- The "Start Thread" flow should feel seamless — user picks an item, names their thread, and the candidate is created in one action.
- Success feedback should be non-intrusive (toast, not a redirect) to support adding multiple items in one session.
- "Add Manually" link in catalog search empty state — Phase 23
- Manual entry fallback for items not in catalog — Phase 23
- Bulk add multiple items at once — future phase
- "Quick add" without any confirmation (one-tap add with defaults) — future optimization
- Quantity selection during add (default to 1) — could be future enhancement
Phase: 22-add-from-catalog-thread-integration Context gathered: 2026-04-06