# GearBox ## What This Is A web-based gear management and purchase planning app. Users catalog their gear collections (bikepacking, sim racing, or any hobby), track weight, price, and source details, search and filter by name or category, and use planning threads to research and compare new purchases with status tracking. Named setups let users compose loadouts with weight classification (base/worn/consumable), donut chart visualization, and live totals in selectable units. Built as a single-user app with a clean, minimalist interface. ## Core Value Make it effortless to manage gear and plan new purchases — see how a potential buy affects your total setup weight and cost before committing. ## Requirements ### Validated - ✓ Gear collection with item CRUD (name, weight, price, category, notes, product link) — v1.0 - ✓ Image uploads for gear items — v1.0 - ✓ User-defined categories with automatic weight/cost totals — v1.0 - ✓ Planning threads for purchase research with candidate products — v1.0 - ✓ Thread resolution: pick a winner, it moves to collection — v1.0 - ✓ Named setups (loadouts) composed from collection items — v1.0 - ✓ Live weight and cost totals per setup — v1.0 - ✓ Dashboard home page with summary cards — v1.0 - ✓ Onboarding wizard for first-time setup — v1.0 - ✓ Thread creation with category assignment via modal dialog — v1.1 - ✓ Planning tab with educational empty state and pill tab navigation — v1.1 - ✓ Image display on item detail views and gear cards with placeholders — v1.1 - ✓ Hero image upload area with preview and click-to-upload — v1.1 - ✓ Lucide icon picker for categories (119 curated icons, 8 groups) — v1.1 - ✓ Automatic emoji-to-Lucide icon migration for existing categories — v1.1 - ✓ Search items by name with instant filtering — v1.2 - ✓ Filter collection items by category with icon-aware dropdown — v1.2 - ✓ Combined text search with category filter and result count — v1.2 - ✓ One-action filter clear — v1.2 - ✓ Weight unit selection (g, oz, lb, kg) with persistence — v1.2 - ✓ All weight displays respect selected unit across entire app — v1.2 - ✓ Per-setup item classification (base weight, worn, consumable) — v1.2 - ✓ Setup weight subtotals by classification — v1.2 - ✓ Donut chart visualization with category/classification toggle — v1.2 - ✓ Chart hover tooltips with weight and percentage — v1.2 - ✓ Candidate status tracking (researching/ordered/arrived) — v1.2 - ✓ Planning category filter with Lucide icons — v1.2 ### Active (No active milestone — use `/gsd:new-milestone` to start next) ### Future - [ ] Side-by-side candidate comparison on weight and price - [ ] Candidate ranking/prioritization within threads - [ ] Impact preview: how a candidate affects setup weight/cost - [ ] CSV import/export for gear collections - [ ] Multi-user accounts with authentication - [ ] Collection sharing and social features (public profiles, shared setups) - [ ] Auto-fill product information (price, weight, images) from external sources ### Out of Scope - Custom comparison parameters — complexity trap, weight/price covers 80% of cases - Mobile native app — web-first, responsive design sufficient - Price tracking / deal alerts — requires scraping, fragile - Barcode scanning / product database — requires external database - Community gear database — requires moderation, accounts - Real-time weather integration — only outdoor-specific, GearBox is hobby-agnostic ## Context Shipped v1.2 with 7,310 LOC TypeScript. Tech stack: React 19, Hono, Drizzle ORM, SQLite, TanStack Router/Query, Tailwind CSS v4, Lucide React, Recharts, all on Bun. Primary use case is bikepacking gear but data model is hobby-agnostic. Replaces spreadsheet-based gear tracking workflow. 121 tests (service-level and route-level integration). ## Constraints - **Runtime**: Bun — used as package manager and runtime - **Design**: Light, airy, minimalist — white/light backgrounds, lots of whitespace, no visual clutter - **Navigation**: Dashboard-based home page, not sidebar or top-nav tabs - **Scope**: No auth, single user for v1 ## Key Decisions | Decision | Rationale | Outcome | |----------|-----------|---------| | No auth for v1 | Single user, simplicity first | ✓ Good | | Generic data model | Support any hobby, not just bikepacking | ✓ Good | | Dashboard navigation | Clean entry point, not persistent nav | ✓ Good | | Bun runtime | User preference | ✓ Good | | Service layer with DI | Accept db as first param for testability | ✓ Good | | Hono context variables for DB | Enables in-memory SQLite integration tests | ✓ Good | | Prices stored as cents | Avoids float rounding issues | ✓ Good | | Vite proxy dev setup | Required by TanStack Router plugin | ✓ Good | | drizzle-kit needs better-sqlite3 | bun:sqlite not supported by CLI | ✓ Good | | Tab navigation via URL params | Shareable URLs between gear/planning | ✓ Good | | Setup item sync: delete-all + re-insert | Simpler than diffing, atomic in transaction | ✓ Good | | Onboarding state in SQLite settings | Source of truth in DB, not Zustand | ✓ Good | | Stay with SQLite | Single-user app, no need for Postgres complexity | ✓ Good | | Lucide Icons for categories | Best outdoor/gear icon coverage, tree-shakeable, clean style | ✓ Good | | categoryId on threads (NOT NULL FK) | Every thread belongs to a category | ✓ Good | | Modal dialog for thread creation | Cleaner UX, supports category selection | ✓ Good | | Hero image area at top of forms | Image-first UX, 4:3 aspect ratio consistent with cards | ✓ Good | | Emoji-to-icon automatic migration | One-time schema rename + data conversion via Drizzle migration | ✓ Good | | ALTER TABLE RENAME COLUMN for SQLite | Simpler than table recreation for column rename | ✓ Good | | Weight conversion precision: g=0dp, oz=1dp, lb=2dp, kg=2dp | Matches common usage conventions | ✓ Good | | Unit toggle in TotalsBar (not settings page) | Visible, quick access for frequent switching | ✓ Good | | CategoryFilterDropdown separate from CategoryPicker | Filter vs form concerns are different | ✓ Good | | No debounce on search input | Collection under 1000 items, instant feedback | ✓ Good | | StatusBadge popup with click-outside dismiss | Consistent with CategoryPicker pattern | ✓ Good | | Classification on setupItems join table | Same item can have different roles per setup | ✓ Good | | Click-to-cycle for ClassificationBadge | Only 3 values, simpler than popup | ✓ Good | | Classification-preserving sync via Map | Save metadata before delete, restore after re-insert | ✓ Good | | Recharts for charting | Mature React chart library, composable API | ✓ Good | --- *Last updated: 2026-03-16 after v1.2 milestone*