diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 5d11597..daeaa12 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -60,15 +60,11 @@ Requirements for this milestone. Each maps to roadmap phases. ### Item & Catalog Detail Pages -- [ ] **DETAIL-01**: Clicking a collection item navigates to a full detail page (`/items/:id`) showing all item data -- [ ] **DETAIL-02**: Clicking a catalog search result navigates to a public detail page (`/global-items/:id`) with "Add to Collection" button -- [ ] **DETAIL-03**: Item detail page has edit mode toggle for modifying personal fields (notes, category, quantity, purchase price) +- [x] **DETAIL-01**: Clicking a collection item navigates to a full detail page (`/items/:id`) showing all item data +- [x] **DETAIL-02**: Clicking a catalog search result navigates to a public detail page (`/global-items/:id`) with "Add to Collection" button +- [x] **DETAIL-03**: Item detail page has edit mode toggle for modifying personal fields (notes, category, quantity, purchase price) - [x] **DETAIL-04**: Thread candidates navigate to detail pages instead of opening slide-out panels -<<<<<<< HEAD -- [ ] **DETAIL-05**: Slide-out panels for items and candidates are removed from the application -======= - [x] **DETAIL-05**: Slide-out panels for items and candidates are removed from the application ->>>>>>> worktree-agent-a00c5cfa ### Tags @@ -189,11 +185,7 @@ Which phases cover which requirements. Updated during roadmap creation. | DETAIL-02 | Phase 21 | Pending | | DETAIL-03 | Phase 21 | Pending | | DETAIL-04 | Phase 21 | Complete | -<<<<<<< HEAD -| DETAIL-05 | Phase 21 | Pending | -======= | DETAIL-05 | Phase 21 | Complete | ->>>>>>> worktree-agent-a00c5cfa **Coverage:** - v2.0 requirements: 45 total diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index a0da163..3f24f63 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -266,6 +266,6 @@ Plans: | 18. Global Items & Public Profiles | v2.0 | 4/5 | Complete | 2026-04-05 | | 19. Reference Item Model & Tags Schema | v2.0 | 3/3 | Complete | 2026-04-05 | | 20. FAB & Full-Screen Catalog Search | v2.0 | 2/2 | Complete | 2026-04-06 | -| 21. Item & Catalog Detail Pages | v2.0 | 1/1 | Complete | 2026-04-06 | +| 21. Item & Catalog Detail Pages | v2.0 | 1/1 | Complete | 2026-04-06 | | 22. Add-from-Catalog & Thread Integration | v2.0 | 0/? | Not started | - | | 23. Manual Entry Fallback | v2.0 | 0/? | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 5aafd11..578490d 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -4,13 +4,13 @@ milestone: v1.3 milestone_name: Research & Decision Tools status: planning stopped_at: Completed 21-03-PLAN.md -last_updated: "2026-04-06T13:14:25.653Z" +last_updated: "2026-04-06T13:22:54.821Z" last_activity: 2026-04-06 progress: total_phases: 15 - completed_phases: 13 - total_plans: 38 - completed_plans: 37 + completed_phases: 14 + total_plans: 41 + completed_plans: 39 percent: 0 --- @@ -25,7 +25,7 @@ See: .planning/PROJECT.md (updated 2026-04-03) ## Current Position -Phase: 20 of 18 (PostgreSQL Migration) +Phase: 21 of 18 (PostgreSQL Migration) Plan: Not started Status: Ready to plan Last activity: 2026-04-06 diff --git a/.planning/phases/21-item-catalog-detail-pages/21-VERIFICATION.md b/.planning/phases/21-item-catalog-detail-pages/21-VERIFICATION.md new file mode 100644 index 0000000..5d6210e --- /dev/null +++ b/.planning/phases/21-item-catalog-detail-pages/21-VERIFICATION.md @@ -0,0 +1,204 @@ +--- +phase: 21-item-catalog-detail-pages +verified: 2026-04-06T13:20:31Z +status: gaps_found +score: 11/13 must-haves verified +re_verification: false +gaps: + - truth: "Lint passes cleanly" + status: failed + reason: "bun run lint exits with 20 errors and 19 warnings. Phase-21 files contribute format errors in threads/$threadId/index.tsx (missing semicolons) and unused parameter warnings in ItemCard.tsx and CandidateCard.tsx introduced or exposed by the navigation refactor." + artifacts: + - path: "src/client/routes/threads/$threadId/index.tsx" + issue: "Format error: missing semicolons on two expression statements (lines 39, 65 in diff output)" + - path: "src/client/components/ItemCard.tsx" + issue: "noUnusedFunctionParameters: imageFilename destructured but not used in render (imageUrl is used instead)" + - path: "src/client/components/CandidateCard.tsx" + issue: "noUnusedFunctionParameters: imageFilename destructured but not used in render" + missing: + - "Run biome format --write on src/client/routes/threads/$threadId/index.tsx" + - "Remove imageFilename from destructured props in ItemCard.tsx and CandidateCard.tsx, or prefix with _ if intentionally unused" + - truth: "REQUIREMENTS.md merge conflict resolved — all DETAIL requirements show correct status" + status: failed + reason: "REQUIREMENTS.md has unresolved git merge conflicts at lines 67-71 and 192-196 covering DETAIL-01, DETAIL-02, DETAIL-03, and DETAIL-05. HEAD branch shows them as Pending (unchecked); worktree-agent-a00c5cfa branch shows DETAIL-05 as Complete. The conflict must be resolved so requirements reflect actual implementation state." + artifacts: + - path: ".planning/REQUIREMENTS.md" + issue: "<<<<<<< HEAD / >>>>>>> worktree-agent-a00c5cfa conflict markers at lines 67-71 and 192-196" + missing: + - "Resolve merge conflict: mark DETAIL-01, DETAIL-02, DETAIL-03, DETAIL-04, DETAIL-05 all as [x] Complete in REQUIREMENTS.md" +human_verification: + - test: "Navigate to /items/:id and click Edit, modify a field, click Save" + expected: "Field updates persist on page reload; read-only view shows updated value" + why_human: "Cannot verify mutation side-effects without running the server" + - test: "Navigate to /threads/:threadId/candidates/:candidateId and click 'Pick as winner'" + expected: "ResolveDialog opens with the correct candidate pre-selected" + why_human: "Dialog interaction requires a live browser" + - test: "Open catalog search, click a result card (not the Add button)" + expected: "Overlay closes and browser navigates to /global-items/:id" + why_human: "Navigation + overlay close sequence requires live browser" +--- + +# Phase 21: Item & Catalog Detail Pages — Verification Report + +**Phase Goal:** Collection items and catalog entries have full detail pages, replacing the slide-out panel pattern +**Verified:** 2026-04-06T13:20:31Z +**Status:** gaps_found (11/13 must-haves verified) +**Re-verification:** No — initial verification + +--- + +## Goal Achievement + +### Observable Truths + +| # | Truth | Status | Evidence | +|---|-------|--------|----------| +| 1 | Navigating to /items/:id renders a full detail page with all item data | ✓ VERIFIED | `src/client/routes/items/$itemId.tsx` (454 lines), createFileRoute("/items/$itemId"), renders name, weight/price badges, notes, quantity, product link, image | +| 2 | Item detail page shows hero image, name, weight/price/category badges, notes, quantity, purchase price, product link | ✓ VERIFIED | File substantive at 454 lines; isLoading/isError states handled; ImageUpload and CategoryPicker wired in edit mode | +| 3 | Clicking Edit toggles fields to editable inputs; Save persists via updateItem mutation | ✓ VERIFIED | `isEditing` state + `useUpdateItem()` with `onSuccess: () => setIsEditing(false)` confirmed in file | +| 4 | Navigating to /global-items/:id shows enhanced catalog page with Add to Collection button | ✓ VERIFIED | `src/client/routes/global-items/$globalItemId.tsx` has button at line 131; stub documented per plan (Phase 22 wires it) | +| 5 | Catalog detail page shows hero image, brand, model, specs, description, owner count | ✓ VERIFIED | useGlobalItem hook connected; 148-line file with all sections present | +| 6 | Navigating to /threads/:threadId/candidates/:candidateId renders a full candidate detail page | ✓ VERIFIED | `src/client/routes/threads/$threadId/candidates/$candidateId.tsx` (506 lines), createFileRoute with correct path | +| 7 | Candidate detail page shows name, weight, price, notes, pros, cons, status, product link, image | ✓ VERIFIED | useThread + candidates.find pattern; isEditing toggle; all fields confirmed in 506-line file | +| 8 | Thread detail page at /threads/:threadId still works after route restructuring | ✓ VERIFIED | `src/client/routes/threads/$threadId/index.tsx` exists (629 lines); flat `$threadId.tsx` deleted; routeTree.gen.ts has no entry for old flat path | +| 9 | Add candidate button on thread page uses modal dialog instead of slide-out panel | ✓ VERIFIED | `addCandidateOpen` state + `AddCandidateModal` component + `useCreateCandidate` wired; no `openCandidateAddPanel` reference remains | +| 10 | Clicking an ItemCard navigates to /items/:id | ✓ VERIFIED | `useNavigate` + `navigate({ to: "/items/$itemId", params: ... })` in ItemCard.tsx; `openEditPanel` fully removed | +| 11 | Clicking a CandidateCard navigates to /threads/:threadId/candidates/:candidateId | ✓ VERIFIED | `useNavigate` + correct params in CandidateCard.tsx; `openCandidateEditPanel` removed | +| 12 | Lint passes cleanly | ✗ FAILED | `bun run lint` exits with 20 errors. Phase-21 files contribute: format error in `threads/$threadId/index.tsx` (missing semicolons), unused `imageFilename` param in `ItemCard.tsx` and `CandidateCard.tsx` | +| 13 | REQUIREMENTS.md merge conflict resolved — all DETAIL requirements reflect correct status | ✗ FAILED | Unresolved `<<<<<<< HEAD` / `>>>>>>>` conflict markers at lines 67-71 and 192-196; DETAIL-01, -02, -03, -05 checkboxes in conflict | + +**Score:** 11/13 truths verified + +--- + +### Required Artifacts + +| Artifact | Expected | Status | Details | +|----------|----------|--------|---------| +| `src/client/routes/items/$itemId.tsx` | Private item detail page with edit mode | ✓ VERIFIED | 454 lines; substantive; registered in routeTree.gen.ts | +| `src/client/routes/global-items/$globalItemId.tsx` | Enhanced catalog detail page with Add to Collection stub | ✓ VERIFIED | 148 lines; button present; useGlobalItem wired | +| `src/client/routes/threads/$threadId/index.tsx` | Restructured thread detail page | ✓ VERIFIED | 629 lines; moved from flat file; AddCandidateModal inline | +| `src/client/routes/threads/$threadId/candidates/$candidateId.tsx` | Candidate detail page with edit mode | ✓ VERIFIED | 506 lines; useThread + useUpdateCandidate wired | +| `src/client/components/ItemCard.tsx` | ItemCard with navigation instead of panel open | ✓ VERIFIED | useNavigate present; openEditPanel absent | +| `src/client/components/CandidateCard.tsx` | CandidateCard with navigation | ✓ VERIFIED | useNavigate present; openCandidateEditPanel absent | +| `src/client/components/CandidateListItem.tsx` | CandidateListItem with navigation | ✓ VERIFIED | useNavigate + correct candidate+thread params | +| `src/client/routes/__root.tsx` | Root layout without slide-out panels | ✓ VERIFIED | No SlideOutPanel, ItemForm, CandidateForm imports; no panelMode references | +| `src/client/stores/uiStore.ts` | UIStore without panel state | ✓ VERIFIED | openEditPanel, openAddPanel, closePanel, openCandidateEditPanel, openCandidateAddPanel, closeCandidatePanel all absent; openConfirmDelete and openResolveDialog preserved | +| `src/client/components/SlideOutPanel.tsx` | Component file still exists on disk | ✓ VERIFIED | File present at expected path | +| `src/client/components/ItemForm.tsx` | Component file still exists on disk | ✓ VERIFIED | File present; refactored to onClose prop pattern | +| `src/client/components/CandidateForm.tsx` | Component file still exists on disk | ✓ VERIFIED | File present; refactored to onClose prop pattern | + +--- + +### Key Link Verification + +| From | To | Via | Status | Details | +|------|----|-----|--------|---------| +| `items/$itemId.tsx` | useItem hook | `useItem(Number(itemId))` | ✓ WIRED | Line 32: type assertion used to access imageUrl enrichment | +| `items/$itemId.tsx` | useUpdateItem mutation | `updateItem.mutate(...)` | ✓ WIRED | Line 40 import + mutation called in save handler | +| `global-items/$globalItemId.tsx` | Add to Collection button | button element + onClick | ✓ WIRED (stub) | console.log stub per plan — Phase 22 wires actual flow | +| `candidates/$candidateId.tsx` | useThread hook | `useThread(threadId)` + `candidates.find` | ✓ WIRED | Lines 35, 57; finds candidate from thread array | +| `candidates/$candidateId.tsx` | useUpdateCandidate mutation | `updateCandidate.mutate(...)` | ✓ WIRED | Line 36 init + called in save handler | +| `ItemCard.tsx` | /items/$itemId route | `useNavigate → /items/$itemId` | ✓ WIRED | Lines 40, 48 — navigate with itemId params | +| `CandidateCard.tsx` | /threads/$threadId/candidates/$candidateId route | `useNavigate → /threads/$threadId/candidates/$candidateId` | ✓ WIRED | Lines 50, 62 — navigate with both params | +| `CatalogSearchOverlay.tsx` | /global-items/$globalItemId route | `useNavigate → /global-items/$globalItemId` | ✓ WIRED | Lines 101, 106 — closeCatalogSearch then navigate | + +--- + +### Data-Flow Trace (Level 4) + +| Artifact | Data Variable | Source | Produces Real Data | Status | +|----------|---------------|--------|--------------------|--------| +| `items/$itemId.tsx` | `item` (ItemWithCategory) | `useItem(Number(itemId))` → `apiGet("/api/items/:id")` → Drizzle query | Yes — existing API endpoint with DB query | ✓ FLOWING | +| `global-items/$globalItemId.tsx` | `item` (GlobalItemWithDetails) | `useGlobalItem(Number(globalItemId))` → `apiGet("/api/global-items/:id")` | Yes — existing API endpoint | ✓ FLOWING | +| `candidates/$candidateId.tsx` | `candidate` (from thread.candidates array) | `useThread(threadId)` → `apiGet("/api/threads/:id")` → includes candidates | Yes — thread API returns candidates array | ✓ FLOWING | +| `threads/$threadId/index.tsx` | `thread` (ThreadWithCandidates) | `useThread(threadId)` → same API | Yes — pre-existing data flow preserved | ✓ FLOWING | + +--- + +### Behavioral Spot-Checks + +| Behavior | Check | Result | Status | +|----------|-------|--------|--------| +| Route tree includes all 3 new routes | grep routeTree.gen.ts for /items/$itemId, /global-items/$globalItemId, /threads/.../candidates/$candidateId | All 3 found at lines 60, 65, 76 | ✓ PASS | +| No dead panel references in src/client/ | grep for openEditPanel, openCandidateEditPanel, panelMode, candidatePanelMode | 0 results | ✓ PASS | +| openCandidateAddPanel removed from thread index | grep threads/$threadId/index.tsx | 0 matches | ✓ PASS | +| Old flat $threadId.tsx deleted | ls src/client/routes/threads/$threadId.tsx | FLAT_FILE_REMOVED | ✓ PASS | +| UIStore preserves required dialog state | grep openConfirmDelete, openResolveDialog in uiStore.ts | Both present with implementations | ✓ PASS | +| Lint clean | bun run lint | 20 errors, 19 warnings | ✗ FAIL | + +--- + +### Requirements Coverage + +| Requirement | Source Plan | Description | Status | Evidence | +|-------------|------------|-------------|--------|----------| +| DETAIL-01 | 21-01 | Clicking a collection item navigates to full detail page (`/items/:id`) showing all item data | ✓ SATISFIED | Route exists (454 lines), ItemCard navigates to it, route registered in routeTree.gen.ts | +| DETAIL-02 | 21-01 | Clicking a catalog search result navigates to public detail page (`/global-items/:id`) with "Add to Collection" button | ✓ SATISFIED | CatalogSearchOverlay.tsx navigates to /global-items/$globalItemId; button present in route file (stub per plan) | +| DETAIL-03 | 21-01 | Item detail page has edit mode toggle for modifying personal fields | ✓ SATISFIED | isEditing state, all personal fields (notes, category, quantity, purchase price) have editable inputs in edit mode | +| DETAIL-04 | 21-02, 21-03 | Thread candidates navigate to detail pages instead of opening slide-out panels | ✓ SATISFIED | CandidateCard and CandidateListItem navigate to /threads/$threadId/candidates/$candidateId; candidate detail page exists | +| DETAIL-05 | 21-03 | Slide-out panels for items and candidates are removed from the application | ✓ SATISFIED | No SlideOutPanel usage in __root.tsx; panel state removed from UIStore; component files preserved on disk per plan | + +**Note:** REQUIREMENTS.md has an unresolved merge conflict covering these requirements. The implementation satisfies all five, but the tracking file needs conflict resolution to reflect the correct [x] Complete state for DETAIL-01 through DETAIL-05. + +**Orphaned requirements:** None. All 5 requirement IDs from phase plans (DETAIL-01 through DETAIL-05) are accounted for. + +--- + +### Anti-Patterns Found + +| File | Line | Pattern | Severity | Impact | +|------|------|---------|----------|--------| +| `src/client/routes/global-items/$globalItemId.tsx` | 133 | `console.log("Add to collection — wired in Phase 22")` | ℹ️ Info | Documented intentional stub; Phase 22 wires actual flow | +| `src/client/routes/threads/$threadId/index.tsx` | 39, 65 | Missing semicolons (format error) | ⚠️ Warning | Causes lint failure; cosmetic only, no runtime impact | +| `src/client/components/ItemCard.tsx` | 32 | `imageFilename` destructured but unused in render (imageUrl used instead) | ⚠️ Warning | Lint error; pre-existing pattern from Phase 17 image refactor; no runtime impact | +| `src/client/components/CandidateCard.tsx` | 37 | Same `imageFilename` unused parameter | ⚠️ Warning | Same root cause as ItemCard | + +No blocker anti-patterns found. The "Add to Collection" console.log stub is explicitly planned for Phase 22 and does not block the phase goal. + +--- + +### Human Verification Required + +#### 1. Item Detail Edit Mode Persistence + +**Test:** Navigate to `/items/:id` for an existing item. Click "Edit", change the item name or notes, click "Save". +**Expected:** Page returns to read-only view showing the updated values. Refreshing the page shows the saved data. +**Why human:** Mutation side-effects (React Query cache invalidation + server write) cannot be verified by static code inspection. + +#### 2. Candidate "Pick as winner" Dialog + +**Test:** Navigate to `/threads/:threadId/candidates/:candidateId` for a candidate in an active thread. Click "Pick as winner". +**Expected:** ResolveDialog opens with correct thread and candidate pre-selected. +**Why human:** Dialog render triggered by UIStore state change requires live browser. + +#### 3. Catalog Search Card Click Navigation + +**Test:** Open catalog search overlay, click on a search result card body (not the "Add" button). +**Expected:** Overlay closes and browser navigates to `/global-items/:id` for that item. +**Why human:** Two-step interaction (closeCatalogSearch + navigate) requires live browser to verify sequencing. + +#### 4. Add Candidate Modal on Thread Page + +**Test:** Navigate to `/threads/:threadId`, click "Add Candidate". +**Expected:** Modal dialog opens with all form fields (name, weight, price, category, notes, URL, image, pros, cons). Submitting creates a new candidate visible on the thread page. +**Why human:** Modal render and form submission require live browser. + +--- + +### Gaps Summary + +Two gaps block a clean pass: + +**Gap 1 — Lint failures in phase-21 files.** `bun run lint` reports 20 errors total. The phase-21 files contribute: +- `src/client/routes/threads/$threadId/index.tsx`: Biome format error (missing semicolons at two expression statement positions). Quick fix: `bunx @biomejs/biome format --write src/client/routes/threads/\$threadId/index.tsx`. +- `src/client/components/ItemCard.tsx` and `CandidateCard.tsx`: `imageFilename` is in the destructuring props but not used in the render (they use `imageUrl` from the same API enrichment). This was exposed by the Phase 17 image refactor and carried forward. Fix: remove `imageFilename` from the destructured parameter list, or rename to `_imageFilename` if it needs to remain in the interface for API compatibility. + +**Gap 2 — REQUIREMENTS.md merge conflict.** The file has `<<<<<<< HEAD` / `>>>>>>>` markers at lines 67-71 and 192-196 around the DETAIL requirements section. This prevents the requirements table from accurately showing phase completion status. The conflict should be resolved by accepting the worktree-agent-a00c5cfa side which marks DETAIL-05 as [x] Complete, and additionally marking DETAIL-01, DETAIL-02, DETAIL-03 as [x] Complete (the implementation satisfies all of them per this verification). + +Both gaps are low-effort fixes and do not represent missing functionality. The core goal — full detail pages replacing slide-out panels — is fully achieved. + +--- + +_Verified: 2026-04-06T13:20:31Z_ +_Verifier: Claude (gsd-verifier)_