docs(02-02): complete thread frontend UI plan

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-15 11:48:10 +01:00
parent 7d043a8585
commit edcef3fcda
3 changed files with 140 additions and 13 deletions

View File

@@ -45,7 +45,7 @@ Plans:
2. User can add candidate products to a thread with weight, price, notes, and product link 2. User can add candidate products to a thread with weight, price, notes, and product link
3. User can edit and remove candidates from an active thread 3. User can edit and remove candidates from an active thread
4. User can resolve a thread by selecting a winning candidate, which automatically creates a new item in their collection and archives the thread 4. User can resolve a thread by selecting a winning candidate, which automatically creates a new item in their collection and archives the thread
**Plans:** 3 plans **Plans:** 2/3 plans executed
Plans: Plans:
- [ ] 02-01-PLAN.md — Backend API: thread/candidate CRUD, resolution transaction, with TDD - [ ] 02-01-PLAN.md — Backend API: thread/candidate CRUD, resolution transaction, with TDD
@@ -75,5 +75,5 @@ Phases execute in numeric order: 1 -> 2 -> 3
| Phase | Plans Complete | Status | Completed | | Phase | Plans Complete | Status | Completed |
|-------|----------------|--------|-----------| |-------|----------------|--------|-----------|
| 1. Foundation and Collection | 4/4 | Complete | 2026-03-14 | | 1. Foundation and Collection | 4/4 | Complete | 2026-03-14 |
| 2. Planning Threads | 0/3 | In progress | - | | 2. Planning Threads | 2/3 | In Progress| |
| 3. Setups and Dashboard | 0/0 | Not started | - | | 3. Setups and Dashboard | 0/0 | Not started | - |

View File

@@ -2,15 +2,15 @@
gsd_state_version: 1.0 gsd_state_version: 1.0
milestone: v1.0 milestone: v1.0
milestone_name: milestone milestone_name: milestone
status: in-progress status: executing
stopped_at: Completed 02-01-PLAN.md stopped_at: Completed 02-02-PLAN.md
last_updated: "2026-03-15T10:39:24Z" last_updated: "2026-03-15T10:46:26Z"
last_activity: 2026-03-15 — Completed 02-01 thread backend API last_activity: 2026-03-15 — Completed 02-02 thread frontend UI
progress: progress:
total_phases: 3 total_phases: 3
completed_phases: 1 completed_phases: 1
total_plans: 7 total_plans: 7
completed_plans: 5 completed_plans: 6
percent: 71 percent: 71
--- ---
@@ -26,11 +26,11 @@ See: .planning/PROJECT.md (updated 2026-03-14)
## Current Position ## Current Position
Phase: 2 of 3 (Planning Threads) Phase: 2 of 3 (Planning Threads)
Plan: 1 of 3 in current phase Plan: 2 of 3 in current phase
Status: In progress Status: In progress
Last activity: 2026-03-15 — Completed 02-01 thread backend API Last activity: 2026-03-15 — Completed 02-02 thread frontend UI
Progress: [███████---] 71% Progress: [█████████░] 86%
## Performance Metrics ## Performance Metrics
@@ -54,6 +54,7 @@ Progress: [███████---] 71%
| Phase 01 P03 | 3min | 2 tasks | 16 files | | Phase 01 P03 | 3min | 2 tasks | 16 files |
| Phase 01 P04 | 3min | 2 tasks | 5 files | | Phase 01 P04 | 3min | 2 tasks | 5 files |
| Phase 02 P01 | 5min | 2 tasks | 9 files | | Phase 02 P01 | 5min | 2 tasks | 9 files |
| Phase 02 P02 | 4min | 2 tasks | 10 files |
## Accumulated Context ## Accumulated Context
@@ -75,6 +76,9 @@ Recent decisions affecting current work:
- [Phase 02-01]: Drizzle sql template literals use raw table.column refs in correlated subqueries (not interpolated) - [Phase 02-01]: Drizzle sql template literals use raw table.column refs in correlated subqueries (not interpolated)
- [Phase 02-01]: Thread deletion collects candidate image filenames before cascade for filesystem cleanup - [Phase 02-01]: Thread deletion collects candidate image filenames before cascade for filesystem cleanup
- [Phase 02-01]: Resolution validates categoryId existence, falls back to Uncategorized (id=1) - [Phase 02-01]: Resolution validates categoryId existence, falls back to Uncategorized (id=1)
- [Phase 02-02]: Tab navigation uses URL search params (?tab=gear|planning) for shareable URLs
- [Phase 02-02]: Candidate panel runs as separate SlideOutPanel instance with independent uiStore state
- [Phase 02-02]: Resolution invalidates threads, items, and totals queries for cross-tab data freshness
### Pending Todos ### Pending Todos
@@ -87,6 +91,6 @@ None yet.
## Session Continuity ## Session Continuity
Last session: 2026-03-15T10:39:24Z Last session: 2026-03-15T10:46:26Z
Stopped at: Completed 02-01-PLAN.md Stopped at: Completed 02-02-PLAN.md
Resume file: .planning/phases/02-planning-threads/02-01-SUMMARY.md Resume file: .planning/phases/02-planning-threads/02-02-SUMMARY.md

View File

@@ -0,0 +1,123 @@
---
phase: 02-planning-threads
plan: 02
subsystem: ui
tags: [react, tanstack-router, tanstack-query, zustand, tabs, threads, candidates]
requires:
- phase: 02-planning-threads
provides: Thread and candidate API endpoints at /api/threads
- phase: 01-foundation-and-collection
provides: SlideOutPanel, ConfirmDialog, ItemCard, ItemForm, CategoryPicker, ImageUpload, uiStore pattern
provides:
- Tabbed home page with gear/planning views
- Thread list with card UI showing candidate count and price range
- Thread detail page with candidate card grid
- Candidate add/edit via slide-out panel with same fields as items
- Thread resolution flow with confirmation dialog and collection integration
- TanStack Query hooks for thread and candidate CRUD
affects: [03-setups-and-dashboard]
tech-stack:
added: []
patterns: [tab navigation via URL search params, dual slide-out panel pattern, cross-query invalidation on resolution]
key-files:
created:
- src/client/hooks/useThreads.ts
- src/client/hooks/useCandidates.ts
- src/client/components/ThreadTabs.tsx
- src/client/components/ThreadCard.tsx
- src/client/components/CandidateCard.tsx
- src/client/components/CandidateForm.tsx
- src/client/routes/threads/$threadId.tsx
modified:
- src/client/stores/uiStore.ts
- src/client/routes/index.tsx
- src/client/routes/__root.tsx
key-decisions:
- "Tab navigation uses URL search params (?tab=gear|planning) via TanStack Router validateSearch for shareable URLs"
- "Candidate panel runs alongside item panel as separate SlideOutPanel instance, controlled by independent uiStore state"
- "Resolution invalidates threads, items, and totals queries for cross-tab data freshness"
- "FAB hidden on thread detail pages to avoid confusion between item add and candidate add"
patterns-established:
- "Tab navigation pattern: URL search params with z.enum().catch() for default, ThreadTabs renders underline indicator"
- "Dual panel pattern: root layout renders two SlideOutPanel instances with independent open/close state"
- "Cross-query invalidation: useResolveThread invalidates threads + items + totals on success"
requirements-completed: [THRD-01, THRD-02, THRD-03, THRD-04]
duration: 4min
completed: 2026-03-15
---
# Phase 2 Plan 02: Thread Frontend UI Summary
**Tabbed home page with thread list cards, candidate grid detail view, slide-out candidate CRUD, and resolution flow that adds winners to the collection**
## Performance
- **Duration:** 4 min
- **Started:** 2026-03-15T10:42:22Z
- **Completed:** 2026-03-15T10:46:26Z
- **Tasks:** 2
- **Files modified:** 10
## Accomplishments
- Tabbed home page switching between My Gear collection and Planning thread list
- Thread cards displaying name, candidate count, creation date, and price range chips
- Thread detail page with candidate card grid matching ItemCard visual style
- Candidate add/edit via slide-out panel with all item fields (name, weight, price, category, notes, URL, image)
- Resolution confirmation dialog that picks winner, creates collection item, and archives thread
- 63 existing tests still pass with zero regressions
## Task Commits
Each task was committed atomically:
1. **Task 1: Hooks, store, tab navigation, and thread list** - `a9d624d` (feat)
2. **Task 2: Thread detail page with candidate CRUD and resolution flow** - `7d043a8` (feat)
## Files Created/Modified
- `src/client/hooks/useThreads.ts` - TanStack Query hooks for thread CRUD and resolution
- `src/client/hooks/useCandidates.ts` - TanStack Query mutation hooks for candidate CRUD
- `src/client/stores/uiStore.ts` - Extended with candidate panel and resolve dialog state
- `src/client/components/ThreadTabs.tsx` - Tab switcher with active underline indicator
- `src/client/components/ThreadCard.tsx` - Thread list card with candidate count and price range chips
- `src/client/components/CandidateCard.tsx` - Candidate card with edit, delete, and pick winner actions
- `src/client/components/CandidateForm.tsx` - Candidate form with dollar-to-cents conversion
- `src/client/routes/index.tsx` - Refactored to tabbed HomePage with CollectionView and PlanningView
- `src/client/routes/threads/$threadId.tsx` - Thread detail page with candidate grid
- `src/client/routes/__root.tsx` - Added candidate panel, delete dialog, and resolve dialog
## Decisions Made
- Tab navigation uses URL search params (?tab=gear|planning) for shareable/bookmarkable URLs
- Candidate panel is a separate SlideOutPanel instance with independent state in uiStore
- Resolution invalidates threads, items, and totals queries to keep cross-tab data fresh
- FAB hidden on thread detail pages to avoid confusion between item add and candidate add
- useMatchRoute detects thread detail page in root layout for candidate panel context
## Deviations from Plan
None - plan executed exactly as written.
## Issues Encountered
None.
## User Setup Required
None - no external service configuration required.
## Next Phase Readiness
- Full thread planning workflow operational end-to-end
- Thread and candidate UI consumes all API endpoints from Plan 01
- Ready for Phase 3 (Setups and Dashboard) which may reference threads for impact preview
---
*Phase: 02-planning-threads*
*Completed: 2026-03-15*
## Self-Check: PASSED
All 10 files verified present. Both commit hashes (a9d624d, 7d043a8) verified in git log.