245 lines
19 KiB
Markdown
245 lines
19 KiB
Markdown
# Feature Research: v1.2 Collection Power-Ups
|
|
|
|
**Domain:** Gear management -- search/filter, weight classification, weight visualization, candidate status tracking, weight unit selection
|
|
**Researched:** 2026-03-16
|
|
**Confidence:** HIGH
|
|
**Scope:** New features only. v1.0/v1.1 features (item CRUD, categories, threads, setups, dashboard, onboarding, images, icons) are already shipped.
|
|
|
|
## Table Stakes
|
|
|
|
Features that gear management users expect. Missing these makes the app feel incomplete for collections beyond ~20 items.
|
|
|
|
| Feature | Why Expected | Complexity | Dependencies on Existing |
|
|
|---------|--------------|------------|--------------------------|
|
|
| Search items by name | Every competitor with an inventory concept has search. Hikt highlights "searchable digital closet." PackLight Supporter Edition has inventory search. Once a collection exceeds 30 items, scrolling to find something is painful. LighterPack notably lacks this and users complain. | LOW | Items query (`useItems`), collection view. Client-side only -- no API changes needed for <500 items. |
|
|
| Filter items by category | Already partially exists in Planning view (category dropdown for threads). Collection view groups by category visually but has no filter. Users need to quickly narrow to "show me just my shelter items." | LOW | Categories query (`useCategories`), collection view. Client-side filtering of already-fetched items. |
|
|
| Weight unit selection (g, oz, lb, kg) | Universal across all competitors. LighterPack supports toggling between g/oz/lb/kg. Packrat offers per-item input in any unit with display conversion. Backpacking Light forum users specifically praise apps that let you "enter item weights in grams and switch the entire display to lbs & oz." Gear specs come in mixed units -- a sleeping bag in lbs/oz, a fuel canister in grams. | LOW | `formatWeight()` in `lib/formatters.ts`, `settings` table (already exists with key/value store), TotalsBar, ItemCard, CandidateCard, SetupCard -- every weight display. |
|
|
| Weight classification (base/worn/consumable) | LighterPack pioneered this three-way split and it is now universal. Hikt, PackLight, Packstack, HikeLite, 99Boulders spreadsheet -- all support it. "Base weight" is the core metric of the ultralight community. Without classification, weight totals are a single number with no actionable insight. | MEDIUM | `setup_items` join table (needs new column), setup detail view, setup service, totals computation. Schema migration required. |
|
|
|
|
## Differentiators
|
|
|
|
Features that set GearBox apart or add meaningful value beyond what competitors offer.
|
|
|
|
| Feature | Value Proposition | Complexity | Dependencies on Existing |
|
|
|---------|-------------------|------------|--------------------------|
|
|
| Weight distribution visualization (donut/pie chart) | LighterPack's pie chart is iconic and widely cited as its best feature. "The pie chart at the top is a great way to visualize how your pack weight breaks down by category." PackLight uses bar graphs. GearBox can do this per-setup with a modern donut chart that also shows base/worn/consumable breakdown -- a combination no competitor offers cleanly. | MEDIUM | Totals data (already computed server-side per category), weight classification (new), a chart library (react-minimal-pie-chart at 2kB or Recharts). |
|
|
| Candidate status tracking (researching/ordered/arrived) | No competitor has this. Research confirmed: the specific workflow of tracking purchase status through stages does not exist in any gear management app. This is unique to GearBox's planning thread concept. It makes threads a living document of the purchase lifecycle, not just a comparison tool. | LOW | `thread_candidates` table (needs new `status` column), CandidateCard, CandidateForm. Simple text field migration. |
|
|
| Planning category filter with icon-aware dropdown | Already partially built as a plain `<select>` in PlanningView. Upgrading to show Lucide icons alongside category names makes filtering feel polished and consistent with the icon picker UX. | LOW | Existing CategoryPicker component pattern, existing category filter state in PlanningView. |
|
|
| Weight classification shown per-setup (not global) | In LighterPack, worn/consumable flags are per-item within a list. In GearBox, items exist in a global collection and appear in multiple setups. The same jacket might be "worn" in a summer bikepacking setup but "base weight" (packed in panniers) in a winter setup. Classification belongs on the setup_items join, not on the item itself. This is architecturally superior to competitors. | MEDIUM | `setup_items` table schema, setup sync endpoint, setup detail UI. |
|
|
|
|
## Anti-Features
|
|
|
|
Features to explicitly NOT build in this milestone.
|
|
|
|
| Anti-Feature | Why Avoid | What to Do Instead |
|
|
|--------------|-----------|-------------------|
|
|
| Per-item weight input in multiple units | Packrat lets you enter "2 lb 3 oz" per item. This adds parsing complexity, ambiguous storage, and conversion bugs. | Store grams internally (already done). Convert for display only. Users enter grams; if they want oz input, they convert mentally or we add a unit toggle on the input field later. |
|
|
| Interactive chart drill-down (click to zoom) | LighterPack lets you click pie slices to zoom into category breakdowns. Adds significant interaction complexity. | Static donut chart with hover tooltips. Drill-down is a future enhancement. |
|
|
| Weight goals / targets ("your target base weight is X") | Some apps show ultralight thresholds. Adds opinionated norms that conflict with hobby-agnostic design. | Show the numbers. Let users interpret them. |
|
|
| Custom weight classification labels | Beyond base/worn/consumable. Some users want "luxury" or "shared" categories. | Three classifications cover 95% of use cases. The notes field handles edge cases. |
|
|
| Server-side search / full-text search | SQLite FTS5 or similar. Premature for a single-user app with <1000 items. | Client-side filtering of the already-fetched items array. Simpler, faster for the expected data scale. |
|
|
| Worn/consumable at the global item level | Tempting to add a classification column to the `items` table. | Classification varies by setup context. A rain shell is "worn" on a day hike but "base weight" (packed) on a bike tour. The join table `setup_items` is the correct location. |
|
|
|
|
## Feature Details
|
|
|
|
### 1. Search and Filter
|
|
|
|
**What users expect:** A text input that filters visible items by name as you type. A category dropdown or pill selector to filter by category. Both should work together (search within a category).
|
|
|
|
**Domain patterns observed:**
|
|
- Hikt: Searchable gear closet with category and specification filters
|
|
- PackLight: Inventory search (premium feature) with category organization
|
|
- Backpacking Light Calculator: Search filter in gear locker and within packs
|
|
- LighterPack: No text search -- widely considered a gap
|
|
|
|
**Recommended implementation:**
|
|
- Sticky search bar above the collection grid with a text input and category filter dropdown
|
|
- Client-side filtering using `Array.filter()` on the items array from `useItems()`
|
|
- Case-insensitive substring match on item name
|
|
- Category filter as pills or dropdown (reuse the pattern from PlanningView)
|
|
- URL search params for filter state (shareable filtered views, consistent with existing `?tab=` pattern)
|
|
- Clear filters button when any filter is active
|
|
- Result count displayed ("showing 12 of 47 items")
|
|
|
|
**Complexity:** LOW. Pure client-side. No API changes. ~100 lines of new component code plus minor state management.
|
|
|
|
### 2. Weight Classification (Base/Worn/Consumable)
|
|
|
|
**What users expect:** Every item in a setup can be marked as one of three types:
|
|
- **Base weight**: Items carried in the pack. The fixed weight of your loadout. This is the primary metric ultralight hikers optimize.
|
|
- **Worn weight**: Items on your body while hiking (shoes, primary clothing, watch, sunglasses). Not counted toward pack weight but tracked as part of "skin-out" weight.
|
|
- **Consumable weight**: Items that deplete during a trip (food, water, fuel, sunscreen). Variable weight not counted toward base weight.
|
|
|
|
**Domain patterns observed:**
|
|
- LighterPack: Per-item icons (shirt icon = worn, flame icon = consumable). Default = base weight. Totals show base/worn/consumable/total separately.
|
|
- Packstack: "Separates base weight, worn weight, and consumables so you always know exactly what your pack weighs."
|
|
- HikeLite: "Mark heavy clothing as worn to see your true base weight."
|
|
- 99Boulders spreadsheet: Column with dropdown: WORN / CONSUMABLE / - (dash = base).
|
|
|
|
**Critical design decision -- classification scope:**
|
|
In LighterPack, items only exist within lists, so the flag is per-item-per-list inherently. In GearBox, items live in a global collection and are referenced by setups. The classification MUST live on the `setup_items` join table, not on the `items` table. Reason: the same item can have different classifications in different setups (a puffy jacket is "worn" on a cold-weather hike but "base weight" in a three-season setup where it stays packed).
|
|
|
|
**Recommended implementation:**
|
|
- Add `classification TEXT NOT NULL DEFAULT 'base'` column to `setup_items` table
|
|
- Valid values: `"base"`, `"worn"`, `"consumable"`
|
|
- Default to `"base"` (most items are base weight; this matches user expectation)
|
|
- UI: Small segmented control or icon toggle on each item within the setup detail view
|
|
- LighterPack-style icons: backpack icon (base), shirt icon (worn), flame/droplet icon (consumable)
|
|
- Setup totals recalculated: show base weight, worn weight, consumable weight, and total (skin-out) as four separate numbers
|
|
- SQL aggregation update: `SUM(CASE WHEN classification = 'base' THEN weight_grams ELSE 0 END)` etc.
|
|
|
|
**Complexity:** MEDIUM. Requires schema migration, API changes (sync endpoint must accept classification), service layer updates, and UI for per-item classification within setup views.
|
|
|
|
### 3. Weight Distribution Visualization
|
|
|
|
**What users expect:** A chart showing where the weight is. By category is standard. By classification (base/worn/consumable) is a bonus.
|
|
|
|
**Domain patterns observed:**
|
|
- LighterPack: Color-coded pie chart by category, click to drill down. "As you enter each piece of equipment, a pie chart immediately displays a breakdown of where your weight is appropriated." Colors are customizable per category.
|
|
- PackLight: Bar graph comparing category weights
|
|
- OutPack: Category breakdown graph
|
|
|
|
**Two chart contexts:**
|
|
1. **Collection-level**: Weight by category across the whole collection. Uses existing `useTotals()` data.
|
|
2. **Setup-level**: Weight by category AND by classification within a specific setup. More useful because setups represent actual loadouts.
|
|
|
|
**Recommended implementation:**
|
|
- Donut chart (modern feel, consistent with GearBox's minimalist aesthetic)
|
|
- Library: `react-minimal-pie-chart` (2kB gzipped, zero dependencies, SVG-based) over Recharts (40kB+). GearBox only needs pie/donut -- no line charts, bar charts, etc.
|
|
- Setup detail view: Donut chart showing weight by category, with center text showing total base weight
|
|
- Optional toggle: switch between "by category" and "by classification" views
|
|
- Color assignment: Derive from category or classification type (base = neutral gray, worn = blue, consumable = amber)
|
|
- Hover tooltips showing category name, weight, and percentage
|
|
- Responsive: Chart should work on mobile viewports
|
|
|
|
**Complexity:** MEDIUM. New dependency, new component, integration with totals data. The chart itself is straightforward; the data aggregation for per-setup-per-category-per-classification is the main work.
|
|
|
|
### 4. Candidate Status Tracking
|
|
|
|
**What users expect:** This is novel -- no competitor has it. The workflow mirrors real purchase behavior:
|
|
1. **Researching** (default): You found this product, added it to a thread, and are evaluating it
|
|
2. **Ordered**: You decided to buy it and placed an order
|
|
3. **Arrived**: The product has been delivered. Ready for thread resolution.
|
|
|
|
**Why this matters:** Without status tracking, threads are a flat list of candidates. With it, threads become a living purchase tracker. A user can see at a glance "I ordered the Nemo Tensor, still researching two other pads."
|
|
|
|
**Recommended implementation:**
|
|
- Add `status TEXT NOT NULL DEFAULT 'researching'` column to `thread_candidates` table
|
|
- Valid values: `"researching"`, `"ordered"`, `"arrived"`
|
|
- UI: Status badge on CandidateCard (small colored pill, similar to existing weight/price badges)
|
|
- Color scheme: researching = gray/neutral, ordered = amber/yellow, arrived = green
|
|
- Status change: Dropdown or simple click-to-cycle on the candidate card
|
|
- Thread-level summary: Show count by status ("2 researching, 1 ordered")
|
|
- When resolving a thread, only candidates with status "arrived" should be selectable as winners (soft constraint -- show a warning, not a hard block, since users may resolve with a "researching" candidate they just bought in-store)
|
|
|
|
**Complexity:** LOW. Simple column addition, enum-like text field, badge rendering, optional status transition UI.
|
|
|
|
### 5. Weight Unit Selection
|
|
|
|
**What users expect:** Choose a preferred unit (grams, ounces, pounds, kilograms) and have ALL weight displays in the app use that unit. LighterPack toggles between g/oz/lb/kg at the top level. The BPL Calculator app lets you "enter item weights in grams and switch the entire display to lbs & oz."
|
|
|
|
**Domain patterns observed:**
|
|
- LighterPack: Toggle at list level between lb/oz/g/kg. Only changes summary display, not per-item display.
|
|
- Packrat: "Input items in different units, choose how they're displayed, and freely convert between them."
|
|
- BPL Calculator: Global settings change, applied to all displays
|
|
- WeighMyGear: Input locked to grams, less intuitive
|
|
|
|
**Recommended implementation:**
|
|
- Store preference in existing `settings` table as `{ key: "weightUnit", value: "g" }` (default: grams)
|
|
- Supported units: `g` (grams), `oz` (ounces), `lb` (pounds + ounces), `kg` (kilograms)
|
|
- Conversion constants: 1 oz = 28.3495g, 1 lb = 453.592g, 1 kg = 1000g
|
|
- Display format per unit:
|
|
- `g`: "450g" (round to integer)
|
|
- `oz`: "15.9 oz" (one decimal)
|
|
- `lb`: "2 lb 3 oz" (pounds + remainder ounces, traditional format)
|
|
- `kg`: "1.45 kg" (two decimals)
|
|
- Update `formatWeight()` to accept unit parameter or read from a React context/hook
|
|
- Settings UI: Simple dropdown or segmented control, accessible from a settings page or inline in the TotalsBar
|
|
- Internal storage stays as grams (already the case with `weight_grams` column)
|
|
- Affects: TotalsBar, ItemCard, CandidateCard, SetupCard, CategoryHeader, setup detail view, chart tooltips
|
|
|
|
**Complexity:** LOW. No schema changes. Update the `formatWeight()` function, add a settings hook, propagate the unit to all display points. The main effort is touching every component that displays weight (there are ~6-8 call sites).
|
|
|
|
### 6. Planning Category Filter with Icon-Aware Dropdown
|
|
|
|
**What users expect:** The existing category filter in PlanningView is a plain `<select>` without icons. Since categories now have Lucide icons (v1.1), the filter should show them.
|
|
|
|
**Recommended implementation:**
|
|
- Replace the native `<select>` with a custom dropdown component that renders `<LucideIcon>` alongside category names
|
|
- Match the visual style of the CategoryPicker used in thread creation
|
|
- Same functionality, better visual consistency
|
|
|
|
**Complexity:** LOW. UI-only change. Replace ~20 lines of `<select>` with a custom dropdown component.
|
|
|
|
## Feature Dependencies
|
|
|
|
```
|
|
[Weight Unit Selection] --independent-- (affects all displays, no schema changes)
|
|
|
|
|
+-- should ship first (all other features benefit from correct unit display)
|
|
|
|
[Search & Filter] --independent-- (pure client-side, no schema changes)
|
|
|
|
|
+-- no dependencies on other v1.2 features
|
|
|
|
[Candidate Status Tracking] --independent-- (schema change on thread_candidates only)
|
|
|
|
|
+-- no dependencies on other v1.2 features
|
|
|
|
[Weight Classification] --depends-on--> [existing setup_items table]
|
|
|
|
|
+-- schema migration on setup_items
|
|
+-- enables [Weight Distribution Visualization]
|
|
|
|
[Weight Distribution Visualization] --depends-on--> [Weight Classification]
|
|
|
|
|
+-- needs classification data to show base/worn/consumable breakdown
|
|
+-- can show by-category chart without classification (partial value)
|
|
+-- new dependency: react-minimal-pie-chart
|
|
|
|
[Planning Category Filter Icons] --depends-on--> [existing CategoryPicker pattern]
|
|
|
|
|
+-- pure UI enhancement
|
|
```
|
|
|
|
### Implementation Order Rationale
|
|
|
|
1. **Weight Unit Selection** first -- touches formatting everywhere, foundational for all subsequent weight displays
|
|
2. **Search & Filter** second -- standalone, immediately useful, low risk
|
|
3. **Candidate Status Tracking** third -- standalone schema change, simple
|
|
4. **Planning Category Filter** fourth -- quick UI polish
|
|
5. **Weight Classification** fifth -- most complex schema change, affects setup data model
|
|
6. **Weight Distribution Visualization** last -- depends on classification, needs chart library, highest UI complexity
|
|
|
|
## Complexity Summary
|
|
|
|
| Feature | Schema Change | API Change | New Dependency | UI Scope | Overall |
|
|
|---------|---------------|------------|----------------|----------|---------|
|
|
| Search & Filter | None | None | None | Collection view only | LOW |
|
|
| Weight Unit Selection | None (uses settings) | None (settings API exists) | None | All weight displays (~8 components) | LOW |
|
|
| Candidate Status Tracking | `thread_candidates.status` column | Update candidate CRUD | None | CandidateCard, CandidateForm | LOW |
|
|
| Planning Category Filter | None | None | None | PlanningView dropdown | LOW |
|
|
| Weight Classification | `setup_items.classification` column | Update setup sync + detail endpoints | None | Setup detail view | MEDIUM |
|
|
| Weight Distribution Chart | None | Possibly new totals endpoint | react-minimal-pie-chart (~2kB) | New chart component | MEDIUM |
|
|
|
|
## Sources
|
|
|
|
- [LighterPack](https://lighterpack.com/) -- weight classification and pie chart visualization patterns
|
|
- [LighterPack Tutorial (99Boulders)](https://www.99boulders.com/lighterpack-tutorial) -- detailed feature walkthrough
|
|
- [LighterPack Tutorial (Backpackers.com)](https://backpackers.com/blog/how-to-calculate-backpack-weight-with-lighterpack/) -- base/worn/consumable definitions
|
|
- [Hikt](https://hikt.app/) -- searchable gear closet, base vs worn weight display
|
|
- [PackLight (iOS)](https://apps.apple.com/us/app/packlight-for-backpacking/id1054845207) -- search, custom categories, bar graph visualization
|
|
- [Packstack](https://www.packstack.io/) -- base/worn/consumable weight separation
|
|
- [HikeLite](https://hikeliteapp.com/) -- worn weight marking, CSV import format
|
|
- [Packrat](https://www.packrat.app/) -- flexible weight unit input and display conversion
|
|
- [BPL Calculator Forum Discussion](https://backpackinglight.com/forums/topic/new-backpacking-hiking-weight-calculator-app/) -- unit conversion UX, search filter patterns
|
|
- [react-minimal-pie-chart (GitHub)](https://github.com/toomuchdesign/react-minimal-pie-chart) -- 2kB lightweight chart library
|
|
- [Best React Chart Libraries 2025 (LogRocket)](https://blog.logrocket.com/best-react-chart-libraries-2025/) -- chart library comparison
|
|
- [LighterPack GitHub Issues](https://github.com/galenmaly/lighterpack/issues) -- user feature requests
|
|
- [OutPack](https://outpack.app/) -- modern LighterPack alternative with category breakdown graphs
|
|
- [Pack Weight Calculator Guide (BackpackPeek)](https://backpackpeek.com/blog/pack-weight-calculator-base-weight-guide) -- base weight calculation methodology
|
|
|
|
---
|
|
*Feature research for: v1.2 Collection Power-Ups (search/filter, weight classification, visualization, candidate status, weight units)*
|
|
*Researched: 2026-03-16*
|