- Add sortOrder REAL column to threadCandidates schema (default 0)
- Add sort_order column to test helper CREATE TABLE
- Add reorderCandidatesSchema to shared/schemas.ts
- Add ReorderCandidates type to shared/types.ts
- getThreadWithCandidates now orders candidates by sort_order ASC
- createCandidate appends at max sort_order + 1000 (first = 1000)
- Add reorderCandidates service function (transaction, active-only guard)
- Add 5 new tests: ordering, appending, reorder success, resolved guard, missing thread
- createCandidate stores and returns pros/cons fields
- createCandidate returns null when pros/cons not provided
- updateCandidate can set and clear pros/cons
- getThreadWithCandidates includes pros/cons on each candidate
Redesign WeightSummaryCard stats from a disconnected 4-column grid to a
compact legend-style list with color dots, percentages, and a divider
before the total row. Switch chart and legend colors to a neutral gray
palette.
Add a currency selector to settings (USD, EUR, GBP, JPY, CAD, AUD) that
changes the displayed symbol across the app. This is visual only — no
value conversion is performed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Archive roadmap and requirements to milestones/, evolve PROJECT.md
with validated requirements, update retrospective, and reorganize
ROADMAP.md with milestone groupings.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create 09-02-SUMMARY.md with execution results
- Update STATE.md with completion status and decisions
- Mark CLAS-02, VIZZ-01, VIZZ-02, VIZZ-03 requirements complete
- Create 09-01-SUMMARY.md with execution details
- Update STATE.md to phase 9, plan 1 of 2 complete
- Mark CLAS-01, CLAS-03, CLAS-04 requirements complete
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add classification text column (default 'base') to setupItems schema
- Add classificationSchema and updateClassificationSchema Zod validators
- Add UpdateClassification type inferred from Zod schema
- Implement updateItemClassification service function
- Modify getSetupWithItems to return classification field
- Modify syncSetupItems to preserve classifications across re-sync
- Add tests for classification CRUD, preservation, and cross-setup independence
- Generate and apply Drizzle migration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- StatusBadge: clickable pill badge with popup menu (researching/ordered/arrived)
- Muted gray styling, LucideIcon per status, click-outside dismiss, Escape key support
- CandidateCard: status + onStatusChange props, StatusBadge in pill row after category
- Thread detail page: passes candidate.status and useUpdateCandidate for onStatusChange
- Fix Biome formatting for candidateStatusSchema enum
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Sticky search/filter toolbar with text input and CategoryFilterDropdown
- useMemo-based filtering by name (search) and categoryId (dropdown)
- "Showing X of Y items" count when filters active
- Flat grid (no category headers) when any filter is active
- "No items match your search" empty state for filtered results
- Replace PlanningView native select with CategoryFilterDropdown
- Schema: status TEXT NOT NULL DEFAULT 'researching' on thread_candidates
- Zod: candidateStatusSchema enum (researching/ordered/arrived) added to createCandidateSchema
- Service: getThreadWithCandidates selects status, createCandidate sets status, updateCandidate accepts status
- Client hooks: CandidateWithCategory and CandidateResponse types include status field
- Migration generated and applied
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 5 tests: create with/without status, update status, getThreadWithCandidates includes status
- Test helper updated with status column in thread_candidates CREATE TABLE
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Searchable dropdown with Lucide icons per category option
- "All categories" as first option with null value
- Click-outside and Escape key dismissal
- Clear button on trigger when category selected
- Auto-focus search input when dropdown opens
- State reset (search text) when dropdown closes
- Add segmented g/oz/lb/kg toggle to TotalsBar with settings persistence
- Pass unit parameter to all 8 formatWeight call sites across components and routes
- Import useWeightUnit hook in ItemCard, CandidateCard, CategoryHeader, SetupCard, ItemPicker, Dashboard, SetupDetail
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- SUMMARY.md with TDD results and 21-test coverage
- STATE.md updated to Plan 2 of 2, 17% progress
- ROADMAP.md marks 07-01 complete (1/2 plans)
- REQUIREMENTS.md marks UNIT-02, UNIT-03 complete
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Wraps useSetting("weightUnit") with typed WeightUnit return
- Validates stored value against known units (g, oz, lb, kg)
- Defaults to "g" when no setting exists (backward compatible)
- Fix config.json formatting (tabs per biome config)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Tests for all 4 units (g, oz, lb, kg) with known gram values
- Null and undefined handling for each unit
- Default parameter backward compatibility
- Zero and precision edge cases
- 11 pass (existing behavior), 10 fail (new unit conversion)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Setups now lives alongside My Gear and Planning under /collection?tab=setups
instead of its own /setups route. Dashboard card updated to link to the new
tab. Setup detail pages (/setups/:id) remain unchanged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Lucide package icon as SVG favicon (white stroke) and display it
next to the GearBox title in the TotalsBar.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Switch all interactive UI elements (buttons, focus rings, active tabs,
FAB, links, spinners) from blue to gray to match icon colors for a
more cohesive look. Mute card badge text colors to pastels (blue-400,
green-500, purple-500) to keep the focus on card content.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add README with Docker setup instructions for self-hosting. Update
docker-compose.yml to use the pre-built registry image instead of
local build, and add a healthcheck against /api/health.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
drizzle-kit push depends on better-sqlite3 which isn't supported in
Bun, causing migrations to fail and the server to crash-loop in prod.
Replace with drizzle-orm/bun-sqlite/migrator that applies the existing
SQL migration files using the native bun:sqlite driver.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Run biome check --write --unsafe to fix tabs, import ordering, and
non-null assertions across entire codebase. Disable a11y rules not
applicable to this single-user app. Exclude auto-generated routeTree.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Install python3/make/g++ in Dockerfile deps stage for drizzle-kit's
better-sqlite3 dependency. Use --ignore-scripts in CI workflows since
lint, test, and build don't need the native module.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add multi-stage Dockerfile, docker-compose with persistent volumes,
and Gitea Actions workflows for CI (lint/test/build) and releases
(tag, Docker image push, changelog). Support DATABASE_PATH env var
for configurable SQLite location to enable proper volume mounting.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add project instructions for Claude Code, the initial database migration,
and ignore the .claude/ local config directory.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Show an external link icon on ItemCard and CandidateCard that opens a
confirmation dialog before navigating to product URLs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace all raw emoji characters in dashboard cards, empty states,
and onboarding wizard with LucideIcon components for visual consistency.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Archive v1.1 artifacts (roadmap, requirements, phases) to milestones/.
Evolve PROJECT.md with shipped requirements and new key decisions.
Reorganize ROADMAP.md with collapsed milestone groupings.
Update retrospective with v1.1 lessons.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Route tree regenerated after icon migration changes
- Old EmojiPicker.tsx and emojiData.ts files removed (were untracked)
- Zero emoji references remain in src/
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rename categoryEmoji to categoryIcon in ItemCard, CandidateCard, ThreadCard, ItemPicker
- Import and render LucideIcon at appropriate sizes (36px placeholder, 14-16px badges)
- Update hook interfaces to match server API (categoryIcon instead of categoryEmoji)
- Rename iconData.ts to iconData.tsx (contains JSX)
- Update useCategories mutation type to use icon instead of emoji
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Portal-based popover with Lucide icon grid organized by 8 groups
- Search filters icons by name and keywords across all groups
- Click-outside and Escape key close the popover
- Trigger button displays selected icon or "+" placeholder
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Install lucide-react v0.577.0
- Create iconData.ts with 119 curated icons across 8 groups
- Add LucideIcon component with kebab-to-PascalCase conversion and fallback
- Export EMOJI_TO_ICON_MAP for migration compatibility
- Build succeeds with new dependency
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rename emoji column to icon in schema, Zod schemas, and all services
- Add Drizzle migration with emoji-to-icon data conversion
- Update test helper, seed, and all test files for icon field
- All 87 tests pass with new icon-based schema
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace conditional image rendering with always-present 4:3 aspect ratio area
- Show category emoji centered on gray background when no image exists
- Ensures consistent card heights across grid layouts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Full-width 4:3 aspect ratio hero image area with rounded corners
- Placeholder state: gray background with ImagePlus icon and helper text
- Preview state: object-cover image with circular X remove button
- Upload state: semi-transparent spinner overlay
- Entire area clickable to upload/replace image
- Moved ImageUpload to first element in both ItemForm and CandidateForm
- Removed redundant "Image" label wrappers
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Root cause: Zod schemas for createItem and createCandidate did not
include imageFilename field, so @hono/zod-validator silently stripped
it from validated payloads before reaching the service layer
- Images uploaded successfully but filename was never persisted to DB
- Added imageFilename as optional string to both createItemSchema and
createCandidateSchema
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>