Files

9.0 KiB

Phase 22: Add-from-Catalog & Thread Integration - Context

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

## Phase Boundary

Wire 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).

## Implementation Decisions

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/items with globalItemId set 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/candidates with globalItemId, 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/:id triggers 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 handleAddStub with actual handler that opens the appropriate modal based on catalogSearchMode.
  • 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 selectedThreadId state 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 — Replace handleAddStub with 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.tsuseCreateItem() for adding reference items to collection
  • src/client/hooks/useCandidates.tsuseCreateCandidate(threadId) for adding catalog items as thread candidates
  • src/client/hooks/useGlobalItems.tsuseGlobalItem(id) for fetching global item details

Schemas (support globalItemId already)

  • src/shared/schemas.tscreateItemSchema has globalItemId optional field (line 13), createCandidateSchema has globalItemId (line 63)

Services (reference item pattern already works)

  • src/server/services/item.service.ts — Creates reference items when globalItemId is provided
  • src/server/services/thread.service.tsresolveThread() 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 supports globalItemId field
  • useCreateCandidate(threadId) hook — creates candidates via POST /api/threads/:threadId/candidates, supports globalItemId
  • CreateThreadModal — modal pattern with form fields, can inform the combined thread+candidate creation modal
  • CatalogSearchOverlay — already has catalogSearchMode to distinguish collection vs thread flows
  • useCategories() hook — for category dropdown in confirmation modal
  • useThreads() hook — for thread picker dropdown
  • useFormatters() — weight/price formatting for modal display
  • useGlobalItem(id) — fetch individual global item details

Established Patterns

  • Zustand UIStore for modal open/close state
  • TanStack React Query mutations with invalidateQueries on success
  • Compact modals with backdrop dimming (CreateThreadModal pattern)
  • apiPost for creating resources
  • Category dropdown pattern from ItemForm (select with category list)

Integration Points

  • CatalogSearchOverlay.tsx line 111-114 — handleAddStub replacement
  • global-items/$globalItemId.tsx line 133 — "Add to Collection" button wiring
  • uiStore.ts — new modal state slices
  • New components: AddToCollectionModal, AddToThreadModal (or combined CatalogAddModal)

</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.
## Deferred Ideas
  • "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