docs(11-02): complete drag-to-reorder ranking UI plan

- Add 11-02-SUMMARY.md with implementation details and deviation docs
- Update STATE.md: progress 100%, decisions, session record
- Update ROADMAP.md: phase 11 complete (2/2 plans with summaries)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-16 22:30:32 +01:00
parent 94c07e79c2
commit 4304d0fcd7
3 changed files with 97 additions and 9 deletions

View File

@@ -41,7 +41,7 @@
**Milestone Goal:** Give users the tools to actually decide between candidates — compare details side-by-side, see how a pick impacts their setup, and rank/annotate their options. **Milestone Goal:** Give users the tools to actually decide between candidates — compare details side-by-side, see how a pick impacts their setup, and rank/annotate their options.
- [x] **Phase 10: Schema Foundation + Pros/Cons Fields** — Migrate schema and deliver pros/cons annotation UI (completed 2026-03-16) - [x] **Phase 10: Schema Foundation + Pros/Cons Fields** — Migrate schema and deliver pros/cons annotation UI (completed 2026-03-16)
- [ ] **Phase 11: Candidate Ranking** — Drag-to-reorder priority ranking with rank badges - [x] **Phase 11: Candidate Ranking** — Drag-to-reorder priority ranking with rank badges (completed 2026-03-16)
- [ ] **Phase 12: Comparison View** — Side-by-side tabular comparison with relative deltas - [ ] **Phase 12: Comparison View** — Side-by-side tabular comparison with relative deltas
- [ ] **Phase 13: Setup Impact Preview** — Per-candidate weight and cost delta against a selected setup - [ ] **Phase 13: Setup Impact Preview** — Per-candidate weight and cost delta against a selected setup
@@ -69,7 +69,7 @@ Plans:
2. The reordered sequence is still intact after navigating away and returning 2. The reordered sequence is still intact after navigating away and returning
3. The top three candidates display gold, silver, and bronze rank badges respectively 3. The top three candidates display gold, silver, and bronze rank badges respectively
4. Drag handles and rank badges are absent on a resolved thread; candidates render in static order 4. Drag handles and rank badges are absent on a resolved thread; candidates render in static order
**Plans:** 1/2 plans executed **Plans:** 2/2 plans complete
Plans: Plans:
- [ ] 11-01-PLAN.md — Schema migration, reorder service/route, sort_order persistence + tests - [ ] 11-01-PLAN.md — Schema migration, reorder service/route, sort_order persistence + tests
- [ ] 11-02-PLAN.md — Drag-to-reorder UI, list/grid toggle, rank badges, resolved-thread guard - [ ] 11-02-PLAN.md — Drag-to-reorder UI, list/grid toggle, rank badges, resolved-thread guard
@@ -110,6 +110,6 @@ Plans:
| 8. Search, Filter, and Candidate Status | v1.2 | 2/2 | Complete | 2026-03-16 | | 8. Search, Filter, and Candidate Status | v1.2 | 2/2 | Complete | 2026-03-16 |
| 9. Weight Classification and Visualization | v1.2 | 2/2 | Complete | 2026-03-16 | | 9. Weight Classification and Visualization | v1.2 | 2/2 | Complete | 2026-03-16 |
| 10. Schema Foundation + Pros/Cons Fields | v1.3 | 1/1 | Complete | 2026-03-16 | | 10. Schema Foundation + Pros/Cons Fields | v1.3 | 1/1 | Complete | 2026-03-16 |
| 11. Candidate Ranking | 1/2 | In Progress| | - | | 11. Candidate Ranking | 2/2 | Complete | 2026-03-16 | - |
| 12. Comparison View | v1.3 | 0/TBD | Not started | - | | 12. Comparison View | v1.3 | 0/TBD | Not started | - |
| 13. Setup Impact Preview | v1.3 | 0/TBD | Not started | - | | 13. Setup Impact Preview | v1.3 | 0/TBD | Not started | - |

View File

@@ -3,14 +3,14 @@ gsd_state_version: 1.0
milestone: v1.3 milestone: v1.3
milestone_name: Research & Decision Tools milestone_name: Research & Decision Tools
status: planning status: planning
stopped_at: Completed 11-candidate-ranking/11-01-PLAN.md stopped_at: Completed 11-candidate-ranking/11-02-PLAN.md
last_updated: "2026-03-16T21:23:51.903Z" last_updated: "2026-03-16T21:30:15.460Z"
last_activity: 2026-03-16 — Roadmap created for v1.3 milestone last_activity: 2026-03-16 — Roadmap created for v1.3 milestone
progress: progress:
total_phases: 4 total_phases: 4
completed_phases: 1 completed_phases: 2
total_plans: 3 total_plans: 3
completed_plans: 2 completed_plans: 3
percent: 0 percent: 0
--- ---
@@ -52,6 +52,7 @@ Progress: [░░░░░░░░░░] 0%
*Updated after each plan completion* *Updated after each plan completion*
| Phase 10-schema-foundation-pros-cons-fields P01 | 6min | 2 tasks | 9 files | | Phase 10-schema-foundation-pros-cons-fields P01 | 6min | 2 tasks | 9 files |
| Phase 11-candidate-ranking P01 | 4min | 2 tasks | 8 files | | Phase 11-candidate-ranking P01 | 4min | 2 tasks | 8 files |
| Phase 11-candidate-ranking P02 | 4min | 3 tasks | 7 files |
## Accumulated Context ## Accumulated Context
@@ -69,6 +70,8 @@ Key v1.3 research findings (see research/SUMMARY.md):
- [Phase 11-candidate-ranking]: sortOrder uses REAL type for future fractional midpoint insertions without bulk rewrites - [Phase 11-candidate-ranking]: sortOrder uses REAL type for future fractional midpoint insertions without bulk rewrites
- [Phase 11-candidate-ranking]: 1000-gap sort_order strategy: first=1000, append=max+1000, reorder resets to (index+1)*1000 - [Phase 11-candidate-ranking]: 1000-gap sort_order strategy: first=1000, append=max+1000, reorder resets to (index+1)*1000
- [Phase 11-candidate-ranking]: Applied sort_order migration via sqlite3 CLI directly to avoid Drizzle data-loss warning on existing rows - [Phase 11-candidate-ranking]: Applied sort_order migration via sqlite3 CLI directly to avoid Drizzle data-loss warning on existing rows
- [Phase 11-candidate-ranking]: Resolved thread list view uses plain div (not Reorder.Group) — no drag, rank badges visible
- [Phase 11-candidate-ranking]: RankBadge exported from CandidateListItem for reuse in CandidateCard grid view
### Pending Todos ### Pending Todos
@@ -80,6 +83,6 @@ None active.
## Session Continuity ## Session Continuity
Last session: 2026-03-16T21:23:51.901Z Last session: 2026-03-16T21:30:15.459Z
Stopped at: Completed 11-candidate-ranking/11-01-PLAN.md Stopped at: Completed 11-candidate-ranking/11-02-PLAN.md
Resume file: None Resume file: None

View File

@@ -0,0 +1,85 @@
---
phase: 11-candidate-ranking
plan: "02"
subsystem: client-ui
tags: [drag-reorder, framer-motion, rank-badges, view-toggle, list-view]
dependency_graph:
requires: [11-01]
provides: [drag-to-reorder-ui, rank-badges, list-grid-toggle]
affects: [threads/$threadId.tsx, CandidateCard, CandidateListItem, uiStore, useCandidates]
tech_stack:
added: []
patterns:
- framer-motion Reorder.Group + Reorder.Item with useDragControls for drag handle
- tempItems pattern to prevent React Query flicker during optimistic drag
- RankBadge exported from CandidateListItem for reuse across views
- candidateViewMode in uiStore for list/grid toggle state
key_files:
created:
- src/client/components/CandidateListItem.tsx
modified:
- src/client/hooks/useCandidates.ts
- src/client/stores/uiStore.ts
- src/client/components/CandidateCard.tsx
- src/client/routes/threads/$threadId.tsx
- src/client/lib/iconData.tsx
- src/client/hooks/useThreads.ts
decisions:
- Resolved thread list view uses plain div (not Reorder.Group) — no drag, rank badges visible
- handleDragEnd fires on Reorder.Group onPointerUp to debounce reorder API call
- biome-ignore applied to useExhaustiveDependencies for thread?.candidates dep — intentional trigger
metrics:
duration: 4min
completed: 2026-03-16T21:29:07Z
tasks_completed: 3
files_changed: 7
---
# Phase 11 Plan 02: Drag-to-Reorder UI Summary
Drag-to-reorder candidate ranking with list/grid view toggle, gold/silver/bronze rank badges, and framer-motion Reorder.Group with tempItems flicker prevention.
## What Was Built
### Task 1: useReorderCandidates hook + uiStore view mode + CandidateListItem component
- Added `useReorderCandidates` mutation hook to `useCandidates.ts` using `apiPatch` to hit `PATCH /api/threads/:id/candidates/reorder`
- Added `candidateViewMode: "list" | "grid"` and `setCandidateViewMode` to `uiStore.ts`
- Created `CandidateListItem.tsx` — horizontal card for list view with drag handle (GripVertical), RankBadge (medal icon), 48x48 image thumbnail, badge row (weight/price/category/status/pros-cons), and hover-reveal action buttons
- Exported `RankBadge` component (gold `#D4AF37`, silver `#C0C0C0`, bronze `#CD7F32`) for reuse
- Added `style` prop support to `LucideIcon` for colored medal icons
- Added `pros` and `cons` fields to `CandidateWithCategory` in `useThreads.ts` (Rule 2 auto-fix — missing after Phase 10)
### Task 2: Thread detail page with view toggle, Reorder.Group, rank badges in grid view
- Updated `CandidateCard.tsx`: added `rank?: number` prop and renders `<RankBadge rank={rank} />` in badge row
- Updated `threads/$threadId.tsx`:
- List/grid view toggle (LayoutList / LayoutGrid icons) using `candidateViewMode` from uiStore
- Active list view: `<Reorder.Group>` wrapping `<CandidateListItem>` instances for drag-to-reorder
- Resolved list view: plain `<div>` with `<CandidateListItem isActive={false}>` — rank badges visible, drag handles hidden
- Grid view: existing `<CandidateCard>` grid with `rank={index + 1}` passed to each card
- `tempItems` state: holds in-progress drag order, falls back to `thread.candidates` when null
- `handleDragEnd`: fires `reorderMutation.mutate({ orderedIds })` and clears tempItems on settled
- `useEffect` clears tempItems when `thread?.candidates` reference changes (fresh server data)
### Task 3: Human verification (auto-approved — auto_chain_active)
## Deviations from Plan
### Auto-fixed Issues
**1. [Rule 2 - Missing] Added pros/cons fields to CandidateWithCategory in useThreads.ts**
- **Found during:** Task 1 (needed by CandidateListItem)
- **Issue:** `CandidateWithCategory` interface in `useThreads.ts` was missing `pros` and `cons` fields added in Phase 10. CandidateListItem needed these to render the "+/- Notes" badge.
- **Fix:** Added `pros: string | null` and `cons: string | null` to the interface
- **Files modified:** `src/client/hooks/useThreads.ts`
- **Commit:** acfa995
**2. [Rule 2 - Missing] Added style prop to LucideIcon component**
- **Found during:** Task 1 (needed by RankBadge for medal colors)
- **Issue:** LucideIcon only accepted `className` for styling; RankBadge needed inline `style={{ color }}` for gold/silver/bronze hex colors not achievable via Tailwind
- **Fix:** Added optional `style?: React.CSSProperties` prop to LucideIcon and passed through to icon component
- **Files modified:** `src/client/lib/iconData.tsx`
- **Commit:** acfa995
## Self-Check: PASSED
All created/modified files exist. Both task commits (acfa995, 94c07e7) confirmed in git log.