Files
GearBox/docs/superpowers/specs/2026-04-03-v1.4-collection-tools-design.md
2026-04-03 18:00:02 +02:00

4.4 KiB

v1.4 Collection Tools Design

Date: 2026-04-03 Milestone: v1.4 Collection Tools Scope: Setup impact preview, item quantity, CSV import/export, item duplication

Feature 1: Setup Impact Preview

Already fully designed in .planning/phases/13-setup-impact-preview/. Two plans exist:

  • 13-01: Pure computeImpactDeltas function + useImpactDeltas hook + uiStore state (TDD)
  • 13-02: SetupImpactSelector + ImpactDeltaBadge components wired into thread detail

Execute the existing plans as-is. No design changes needed.

Feature 2: Item Quantity

Schema

Add quantity INTEGER NOT NULL DEFAULT 1 to items table via Drizzle migration.

quantity: integer("quantity").notNull().default(1),

Validation

Add to createItemSchema in src/shared/schemas.ts:

quantity: z.number().int().positive().optional(),

Flows to updateItemSchema via .partial() automatically.

Service Layer

No special business logic — quantity is a stored field.

Totals computation changes:

  • totals.service.ts: getCategoryTotals() and getGlobalTotals() must multiply weightGrams * quantity and priceCents * quantity in their SQL SUM aggregations.
  • setup.service.ts: getSetupWithItems() and getAllSetups() — when computing setup totals, multiply item weight/price by the item's quantity.

UI

  • ItemForm: Number input for quantity (min=1), placed below price field. Defaults to 1.
  • ItemCard: Show "x2" badge next to item name when quantity > 1. No badge when quantity is 1.
  • Totals: Already computed server-side with the quantity multiplication. No client-side changes for totals.
  • Setup weight/cost: The item's quantity determines its weight/cost contribution when included in a setup (one setup_items row, but totals reflect quantity).

Thread Resolution

When a thread is resolved and a candidate is copied to an item, the new item gets quantity: 1 (default). No special handling needed.

Feature 3: CSV Import/Export

Export

Endpoint: GET /api/items/export

  • Returns CSV with headers: name,quantity,weightGrams,priceCents,category,notes,productUrl
  • Content-Type: text/csv
  • Content-Disposition: attachment; filename="gearbox-export.csv"
  • Weight in grams, price in cents (raw values, no formatting)
  • Category column contains category name (not ID)

Service: exportItemsCsv(db) returns a CSV string. Joins items with categories for name lookup.

Import

Endpoint: POST /api/items/import

  • Accepts multipart form upload (CSV file)
  • Parses rows, validates required fields (name is required, others optional)
  • Category matching: looks up by name (case-insensitive). Creates new category if not found.
  • Quantity defaults to 1 if not present in CSV
  • Returns { imported: number, created_categories: string[], errors: string[] }
  • Skips rows with errors, continues processing remaining rows

Service: importItemsCsv(db, csvContent: string) parses and inserts items.

UI

Settings page gets an "Import/Export" section:

  • "Export CSV" button — triggers download via GET /api/items/export
  • "Import CSV" file input — accepts .csv files, shows count of parsed rows, confirm button to upload
  • Success/error feedback after import completes

Feature 4: Item Duplication

API

Endpoint: POST /api/items/:id/duplicate

  • Copies all fields from source item: name, weightGrams, priceCents, categoryId, notes, productUrl, imageFilename, imageSourceUrl, quantity
  • Appends " (copy)" to the name
  • New createdAt/updatedAt timestamps
  • Returns the new item

Service: duplicateItem(db, id) — fetches source item, inserts copy, returns new item.

UI

  • Add "Duplicate" action to ItemCard (alongside existing edit/delete actions)
  • Duplicating opens the edit panel pre-filled with the new item so the user can rename or adjust

Phase Ordering

  1. Item Quantity — schema change first since CSV import/export and totals depend on it
  2. Setup Impact Preview — execute existing Phase 13 plans
  3. Item Duplication — small, self-contained
  4. CSV Import/Export — depends on quantity field existing in schema

Out of Scope

  • Quantity per setup (setup_items.quantity) — items table quantity is sufficient for v1.4
  • CSV export with formatted weights/prices — raw values are more portable
  • Image export/import via CSV — images are local files, not CSV-compatible
  • Bulk edit from CSV preview — import creates, doesn't update existing items