diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md
index 4c3e4c8..e8fd93e 100644
--- a/.planning/ROADMAP.md
+++ b/.planning/ROADMAP.md
@@ -61,11 +61,12 @@ Plans:
2. User can add and remove collection items from a setup
3. User can see total weight and cost for a setup, computed live from current item data
4. User sees a dashboard home page with cards linking to their collection, active threads, and setups
-**Plans**: TBD
+**Plans:** 3 plans
Plans:
-- [ ] 03-01: TBD
-- [ ] 03-02: TBD
+- [ ] 03-01-PLAN.md — Backend TDD: setup schema, service, routes, and tests with junction table
+- [ ] 03-02-PLAN.md — Frontend: navigation restructure, dashboard, setup UI, and item picker
+- [ ] 03-03-PLAN.md — Visual verification checkpoint
## Progress
@@ -76,4 +77,4 @@ Phases execute in numeric order: 1 -> 2 -> 3
|-------|----------------|--------|-----------|
| 1. Foundation and Collection | 4/4 | Complete | 2026-03-14 |
| 2. Planning Threads | 3/3 | Complete | 2026-03-15 |
-| 3. Setups and Dashboard | 0/0 | Not started | - |
+| 3. Setups and Dashboard | 0/3 | Not started | - |
diff --git a/.planning/phases/03-setups-and-dashboard/03-01-PLAN.md b/.planning/phases/03-setups-and-dashboard/03-01-PLAN.md
new file mode 100644
index 0000000..40308f4
--- /dev/null
+++ b/.planning/phases/03-setups-and-dashboard/03-01-PLAN.md
@@ -0,0 +1,176 @@
+---
+phase: 03-setups-and-dashboard
+plan: 01
+type: tdd
+wave: 1
+depends_on: []
+files_modified:
+ - src/db/schema.ts
+ - src/shared/schemas.ts
+ - src/shared/types.ts
+ - src/server/services/setup.service.ts
+ - src/server/routes/setups.ts
+ - src/server/index.ts
+ - tests/helpers/db.ts
+ - tests/services/setup.service.test.ts
+ - tests/routes/setups.test.ts
+autonomous: true
+requirements:
+ - SETP-01
+ - SETP-02
+ - SETP-03
+
+must_haves:
+ truths:
+ - "Setup CRUD operations work (create, read, update, delete)"
+ - "Items can be added to and removed from a setup via junction table"
+ - "Setup totals (weight, cost, item count) are computed correctly via SQL aggregation"
+ - "Deleting a setup cascades to setup_items, deleting a collection item cascades from setup_items"
+ artifacts:
+ - path: "src/db/schema.ts"
+ provides: "setups and setupItems table definitions"
+ contains: "setupItems"
+ - path: "src/shared/schemas.ts"
+ provides: "Zod schemas for setup create/update/sync"
+ contains: "createSetupSchema"
+ - path: "src/shared/types.ts"
+ provides: "Setup and SetupWithItems TypeScript types"
+ contains: "CreateSetup"
+ - path: "src/server/services/setup.service.ts"
+ provides: "Setup business logic with DB injection"
+ exports: ["getAllSetups", "getSetupWithItems", "createSetup", "updateSetup", "deleteSetup", "syncSetupItems", "removeSetupItem"]
+ - path: "src/server/routes/setups.ts"
+ provides: "Hono API routes for setups"
+ contains: "setupRoutes"
+ - path: "tests/services/setup.service.test.ts"
+ provides: "Unit tests for setup service"
+ min_lines: 50
+ - path: "tests/routes/setups.test.ts"
+ provides: "Integration tests for setup API routes"
+ min_lines: 30
+ key_links:
+ - from: "src/server/routes/setups.ts"
+ to: "src/server/services/setup.service.ts"
+ via: "service function calls"
+ pattern: "setup\\.service"
+ - from: "src/server/index.ts"
+ to: "src/server/routes/setups.ts"
+ via: "route mounting"
+ pattern: "setupRoutes"
+ - from: "src/server/services/setup.service.ts"
+ to: "src/db/schema.ts"
+ via: "drizzle schema imports"
+ pattern: "import.*schema"
+---
+
+
+Build the complete setup backend: database schema (setups + setup_items junction table), shared Zod schemas/types, service layer with CRUD + item sync + totals aggregation, and Hono API routes. All with TDD.
+
+Purpose: Provides the data layer and API that the frontend (Plan 02) will consume. The many-to-many junction table is the only new DB pattern in this project.
+Output: Working API at /api/setups with full test coverage.
+
+
+
+@/home/jean-luc-makiola/.claude/get-shit-done/workflows/execute-plan.md
+@/home/jean-luc-makiola/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/STATE.md
+@.planning/phases/03-setups-and-dashboard/03-RESEARCH.md
+
+@src/db/schema.ts
+@src/shared/schemas.ts
+@src/shared/types.ts
+@src/server/index.ts
+@tests/helpers/db.ts
+
+
+
+
+From src/server/services/thread.service.ts (pattern reference):
+```typescript
+export function getAllThreads(db: Db = prodDb, includeResolved = false) { ... }
+export function getThread(db: Db = prodDb, id: number) { ... }
+export function createThread(db: Db = prodDb, data: CreateThread) { ... }
+export function deleteThread(db: Db = prodDb, id: number) { ... }
+```
+
+From src/server/routes/threads.ts (pattern reference):
+```typescript
+const threadRoutes = new Hono<{ Variables: { db: Db } }>();
+threadRoutes.get("/", (c) => { ... });
+threadRoutes.post("/", zValidator("json", createThreadSchema), (c) => { ... });
+```
+
+From tests/helpers/db.ts:
+```typescript
+export function createTestDb() { ... } // Returns in-memory Drizzle instance
+```
+
+
+
+
+ Setup Backend with Junction Table
+
+ src/db/schema.ts, src/shared/schemas.ts, src/shared/types.ts,
+ src/server/services/setup.service.ts, src/server/routes/setups.ts,
+ src/server/index.ts, tests/helpers/db.ts,
+ tests/services/setup.service.test.ts, tests/routes/setups.test.ts
+
+
+ Service layer (setup.service.ts):
+ - getAllSetups: returns setups with itemCount, totalWeight (grams), totalCost (cents) via SQL subqueries
+ - getSetupWithItems: returns single setup with full item details (joined with categories), null if not found
+ - createSetup: creates setup with name, returns created setup
+ - updateSetup: updates setup name, returns updated setup, null if not found
+ - deleteSetup: deletes setup (cascade deletes setup_items), returns boolean
+ - syncSetupItems: delete-all + re-insert in transaction, accepts setupId + itemIds array
+ - removeSetupItem: removes single item from setup by setupId + itemId
+
+ API routes (setups.ts):
+ - GET /api/setups -> list all setups with aggregated totals
+ - GET /api/setups/:id -> single setup with items
+ - POST /api/setups -> create setup (validates name via createSetupSchema)
+ - PUT /api/setups/:id -> update setup name
+ - DELETE /api/setups/:id -> delete setup
+ - PUT /api/setups/:id/items -> sync setup items (validates itemIds via syncSetupItemsSchema)
+ - DELETE /api/setups/:id/items/:itemId -> remove single item from setup
+
+ Edge cases:
+ - Syncing with empty itemIds array clears all items from setup
+ - Deleting a collection item cascades removal from all setups
+ - getAllSetups returns 0 for weight/cost when setup has no items (COALESCE)
+
+
+ 1. Add setups and setupItems tables to src/db/schema.ts (with cascade FKs)
+ 2. Add Zod schemas (createSetupSchema, updateSetupSchema, syncSetupItemsSchema) to src/shared/schemas.ts
+ 3. Add types (CreateSetup, UpdateSetup, SyncSetupItems, Setup, SetupItem) to src/shared/types.ts
+ 4. Add setups and setup_items CREATE TABLE to tests/helpers/db.ts
+ 5. Implement setup.service.ts following thread.service.ts pattern (db as first param with prod default)
+ 6. Implement setups.ts routes following threads.ts pattern (Hono with zValidator)
+ 7. Mount setupRoutes in src/server/index.ts
+ 8. Use raw SQL in Drizzle sql`` for correlated subqueries in getAllSetups (per Phase 2 decision about table.column refs)
+
+
+
+
+```bash
+bun test tests/services/setup.service.test.ts && bun test tests/routes/setups.test.ts && bun test
+```
+All setup service and route tests pass. Full test suite remains green.
+
+
+
+- Setup CRUD API responds correctly at all 7 endpoints
+- Junction table correctly links items to setups (many-to-many)
+- Totals aggregation returns correct weight/cost/count via SQL
+- Cascade delete works both directions (setup deletion, item deletion)
+- All existing tests still pass
+
+
+
diff --git a/.planning/phases/03-setups-and-dashboard/03-02-PLAN.md b/.planning/phases/03-setups-and-dashboard/03-02-PLAN.md
new file mode 100644
index 0000000..3258315
--- /dev/null
+++ b/.planning/phases/03-setups-and-dashboard/03-02-PLAN.md
@@ -0,0 +1,362 @@
+---
+phase: 03-setups-and-dashboard
+plan: 02
+type: execute
+wave: 2
+depends_on: ["03-01"]
+files_modified:
+ - src/client/routes/index.tsx
+ - src/client/routes/collection/index.tsx
+ - src/client/routes/setups/index.tsx
+ - src/client/routes/setups/$setupId.tsx
+ - src/client/routes/__root.tsx
+ - src/client/components/TotalsBar.tsx
+ - src/client/components/DashboardCard.tsx
+ - src/client/components/SetupCard.tsx
+ - src/client/components/ItemPicker.tsx
+ - src/client/components/ItemCard.tsx
+ - src/client/hooks/useSetups.ts
+ - src/client/hooks/useItems.ts
+ - src/client/stores/uiStore.ts
+autonomous: true
+requirements:
+ - SETP-01
+ - SETP-02
+ - SETP-03
+ - DASH-01
+
+must_haves:
+ truths:
+ - "User sees dashboard at / with three summary cards (Collection, Planning, Setups)"
+ - "User can navigate to /collection and see the existing gear/planning tabs"
+ - "User can create a named setup from the setups list page"
+ - "User can add/remove collection items to a setup via checklist picker"
+ - "User can see total weight and cost for a setup in the sticky bar"
+ - "GearBox title in TotalsBar links back to dashboard from all sub-pages"
+ artifacts:
+ - path: "src/client/routes/index.tsx"
+ provides: "Dashboard page with three summary cards"
+ contains: "DashboardCard"
+ - path: "src/client/routes/collection/index.tsx"
+ provides: "Gear + Planning tabs (moved from old index.tsx)"
+ contains: "CollectionView"
+ - path: "src/client/routes/setups/index.tsx"
+ provides: "Setup list with create form"
+ contains: "createFileRoute"
+ - path: "src/client/routes/setups/$setupId.tsx"
+ provides: "Setup detail with item cards and totals"
+ contains: "ItemPicker"
+ - path: "src/client/components/TotalsBar.tsx"
+ provides: "Route-aware totals bar with optional stats and linkable title"
+ contains: "linkTo"
+ - path: "src/client/components/DashboardCard.tsx"
+ provides: "Dashboard summary card component"
+ contains: "DashboardCard"
+ - path: "src/client/components/ItemPicker.tsx"
+ provides: "Checklist picker in SlideOutPanel for selecting items"
+ contains: "ItemPicker"
+ - path: "src/client/hooks/useSetups.ts"
+ provides: "TanStack Query hooks for setup CRUD"
+ exports: ["useSetups", "useSetup", "useCreateSetup", "useDeleteSetup", "useSyncSetupItems", "useRemoveSetupItem"]
+ key_links:
+ - from: "src/client/routes/index.tsx"
+ to: "src/client/hooks/useSetups.ts"
+ via: "useSetups() for setup count"
+ pattern: "useSetups"
+ - from: "src/client/routes/setups/$setupId.tsx"
+ to: "/api/setups/:id"
+ via: "useSetup() hook"
+ pattern: "useSetup"
+ - from: "src/client/routes/__root.tsx"
+ to: "src/client/components/TotalsBar.tsx"
+ via: "route-aware props"
+ pattern: "TotalsBar"
+ - from: "src/client/components/ItemPicker.tsx"
+ to: "src/client/hooks/useSetups.ts"
+ via: "useSyncSetupItems mutation"
+ pattern: "useSyncSetupItems"
+---
+
+
+Build the complete frontend: restructure navigation (move gear/planning to /collection, create dashboard at /), build setup list and detail pages with item picker, make TotalsBar route-aware, and create the dashboard home page.
+
+Purpose: Delivers the user-facing features for setups and dashboard, completing all v1 requirements.
+Output: Working dashboard, setup CRUD UI, and item picker -- all wired to the backend from Plan 01.
+
+
+
+@/home/jean-luc-makiola/.claude/get-shit-done/workflows/execute-plan.md
+@/home/jean-luc-makiola/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/PROJECT.md
+@.planning/ROADMAP.md
+@.planning/phases/03-setups-and-dashboard/03-CONTEXT.md
+@.planning/phases/03-setups-and-dashboard/03-RESEARCH.md
+@.planning/phases/03-setups-and-dashboard/03-01-SUMMARY.md
+
+@src/client/routes/__root.tsx
+@src/client/routes/index.tsx
+@src/client/components/TotalsBar.tsx
+@src/client/components/ItemCard.tsx
+@src/client/components/CategoryHeader.tsx
+@src/client/components/ThreadCard.tsx
+@src/client/components/SlideOutPanel.tsx
+@src/client/hooks/useItems.ts
+@src/client/hooks/useThreads.ts
+@src/client/hooks/useTotals.ts
+@src/client/stores/uiStore.ts
+@src/client/lib/api.ts
+
+
+
+
+From src/shared/schemas.ts (added by Plan 01):
+```typescript
+export const createSetupSchema = z.object({
+ name: z.string().min(1, "Setup name is required"),
+});
+export const updateSetupSchema = z.object({
+ name: z.string().min(1).optional(),
+});
+export const syncSetupItemsSchema = z.object({
+ itemIds: z.array(z.number().int().positive()),
+});
+```
+
+From src/shared/types.ts (added by Plan 01):
+```typescript
+export type CreateSetup = z.infer;
+export type Setup = typeof setups.$inferSelect;
+export type SetupItem = typeof setupItems.$inferSelect;
+```
+
+API endpoints from Plan 01:
+- GET /api/setups -> SetupListItem[] (with itemCount, totalWeight, totalCost)
+- GET /api/setups/:id -> SetupWithItems (setup + items array with category info)
+- POST /api/setups -> Setup
+- PUT /api/setups/:id -> Setup
+- DELETE /api/setups/:id -> { success: boolean }
+- PUT /api/setups/:id/items -> { success: boolean } (body: { itemIds: number[] })
+- DELETE /api/setups/:id/items/:itemId -> { success: boolean }
+
+
+
+From src/client/hooks/useThreads.ts:
+```typescript
+export function useThreads(includeResolved = false) {
+ return useQuery({ queryKey: ["threads", includeResolved], queryFn: ... });
+}
+export function useCreateThread() {
+ const qc = useQueryClient();
+ return useMutation({ mutationFn: ..., onSuccess: () => qc.invalidateQueries({ queryKey: ["threads"] }) });
+}
+```
+
+From src/client/lib/api.ts:
+```typescript
+export function apiGet(url: string): Promise
+export function apiPost(url: string, body: unknown): Promise
+export function apiPut(url: string, body: unknown): Promise
+export function apiDelete(url: string): Promise
+```
+
+
+
+
+
+
+ Task 1: Navigation restructure, TotalsBar refactor, and setup hooks
+
+ src/client/components/TotalsBar.tsx,
+ src/client/routes/index.tsx,
+ src/client/routes/collection/index.tsx,
+ src/client/routes/__root.tsx,
+ src/client/hooks/useSetups.ts,
+ src/client/hooks/useItems.ts,
+ src/client/components/DashboardCard.tsx,
+ src/client/stores/uiStore.ts
+
+
+ **1. Refactor TotalsBar to accept optional props (per CONTEXT.md decisions):**
+ - Add props: `title?: string`, `stats?: Array<{label: string, value: string}>`, `linkTo?: string`
+ - When no `stats` prop: show title only (for dashboard)
+ - When `stats` provided: render them instead of fetching global totals internally
+ - When `linkTo` provided: wrap title in `` (per decision: GearBox title always links to /)
+ - Default behavior (no props): fetch global totals with useTotals() and display as before (backward compatible for collection page)
+ - Dashboard passes no linkTo (already on dashboard). All other pages pass `linkTo="/"`
+
+ **2. Move current index.tsx content to collection/index.tsx:**
+ - Create `src/client/routes/collection/index.tsx`
+ - Move the entire HomePage, CollectionView, and PlanningView content from current `index.tsx`
+ - Update route: `createFileRoute("/collection/")` with same `validateSearch` for tab param
+ - Update handleTabChange to navigate to `/collection` instead of `/`
+ - The TotalsBar in __root.tsx will automatically show global stats on this page (default behavior)
+
+ **3. Rewrite index.tsx as Dashboard (per CONTEXT.md decisions):**
+ - Three equal-width cards (grid-cols-1 md:grid-cols-3 gap-6)
+ - Collection card: shows item count, total weight, total cost. Links to `/collection`. Empty state shows "Get started"
+ - Planning card: shows active thread count. Links to `/collection?tab=planning`
+ - Setups card: shows setup count. Links to `/setups`
+ - Use `useTotals()` for collection stats, `useThreads(false)` for active threads, `useSetups()` for setup count
+ - "GearBox" title only in TotalsBar (no stats on dashboard) -- pass no stats prop
+ - Clean layout: max-w-7xl, centered, lots of whitespace
+
+ **4. Create DashboardCard.tsx component:**
+ - Props: `to: string`, `title: string`, `icon: ReactNode`, `stats: Array<{label: string, value: string}>`, `emptyText?: string`
+ - Card with hover shadow transition, rounded-xl, padding
+ - Wraps in `` for navigation
+ - Shows icon, title, stats list, and optional empty state text
+
+ **5. Create useSetups.ts hooks (follows useThreads.ts pattern exactly):**
+ - `useSetups()`: queryKey ["setups"], fetches GET /api/setups
+ - `useSetup(setupId: number | null)`: queryKey ["setups", setupId], enabled when setupId != null
+ - `useCreateSetup()`: POST /api/setups, invalidates ["setups"]
+ - `useUpdateSetup(setupId: number)`: PUT /api/setups/:id, invalidates ["setups"]
+ - `useDeleteSetup()`: DELETE /api/setups/:id, invalidates ["setups"]
+ - `useSyncSetupItems(setupId: number)`: PUT /api/setups/:id/items, invalidates ["setups"]
+ - `useRemoveSetupItem(setupId: number)`: DELETE /api/setups/:id/items/:itemId, invalidates ["setups"]
+ - Define response types inline: `SetupListItem` (with itemCount, totalWeight, totalCost) and `SetupWithItems` (with items array including category info)
+
+ **6. Update __root.tsx:**
+ - Pass route-aware props to TotalsBar based on current route matching
+ - On dashboard (`/`): no stats, no linkTo
+ - On collection (`/collection`): default behavior (TotalsBar fetches its own stats), linkTo="/"
+ - On thread detail: linkTo="/" (keep current behavior)
+ - On setups: linkTo="/"
+ - On setup detail: TotalsBar with setup-specific title and stats (will be handled by setup detail page passing context)
+ - Update FAB visibility: only show on `/collection` route when gear tab is active (not on dashboard, not on setups). Match `/collection` route instead of just hiding on thread pages
+ - Update ResolveDialog onResolved navigation: change from `{ to: "/", search: { tab: "planning" } }` to `{ to: "/collection", search: { tab: "planning" } }`
+
+ **7. Add setup-related UI state to uiStore.ts:**
+ - Add `itemPickerOpen: boolean` state
+ - Add `openItemPicker()` and `closeItemPicker()` actions
+ - Add `confirmDeleteSetupId: number | null` state with open/close actions
+
+ **8. Update useItems invalidation (Pitfall 1 from research):**
+ - In `useUpdateItem` and `useDeleteItem` mutation `onSuccess`, also invalidate `["setups"]` query key
+ - This ensures setup totals update when a collection item's weight/price changes or item is deleted
+
+ IMPORTANT: After creating route files, the TanStack Router plugin will auto-regenerate `routeTree.gen.ts`. Restart the dev server if needed.
+
+
+ cd /home/jean-luc-makiola/Development/projects/GearBox && npx tsc --noEmit 2>&1 | head -30
+
+
+ - Dashboard renders at / with three summary cards showing real data
+ - Collection view with gear/planning tabs works at /collection
+ - GearBox title links back to / from all sub-pages
+ - TotalsBar shows contextual stats per page (title-only on dashboard, global on collection)
+ - FAB only appears on /collection gear tab
+ - Thread resolution redirects to /collection?tab=planning
+ - Setup query/mutation hooks are functional
+
+
+
+
+ Task 2: Setup list page, detail page, and item picker
+
+ src/client/routes/setups/index.tsx,
+ src/client/routes/setups/$setupId.tsx,
+ src/client/components/SetupCard.tsx,
+ src/client/components/ItemPicker.tsx,
+ src/client/components/ItemCard.tsx
+
+
+ **1. Create SetupCard.tsx (reference ThreadCard.tsx pattern):**
+ - Props: `id: number`, `name: string`, `itemCount: number`, `totalWeight: number`, `totalCost: number`
+ - Card with rounded-xl, shadow-sm, hover:shadow-md transition
+ - Shows setup name, item count pill, formatted weight and cost
+ - Wraps in ``
+ - Use `formatWeight` and `formatPrice` from existing `lib/formatters`
+
+ **2. Create setups list page (src/client/routes/setups/index.tsx):**
+ - Route: `createFileRoute("/setups/")`
+ - Inline name input + "Create" button at top (same pattern as thread creation in PlanningView)
+ - Uses `useSetups()` and `useCreateSetup()` hooks
+ - Grid layout: grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4
+ - Each setup rendered as SetupCard
+ - Empty state: icon + "No setups yet" message + "Create one to plan your loadout"
+ - Loading skeleton: 2 placeholder cards
+
+ **3. Create ItemPicker.tsx (checklist in SlideOutPanel, per CONTEXT.md decisions):**
+ - Props: `setupId: number`, `currentItemIds: number[]`, `isOpen: boolean`, `onClose: () => void`
+ - Renders inside a SlideOutPanel with title "Select Items"
+ - Fetches all collection items via `useItems()`
+ - Groups items by category with emoji headers (same grouping as CollectionView)
+ - Each item is a checkbox row: `[x] emoji ItemName (weight, price)`
+ - Pre-checks items already in the setup (from `currentItemIds`)
+ - Local state tracks toggled item IDs
+ - "Done" button at bottom calls `useSyncSetupItems(setupId)` with selected IDs, then closes
+ - Scrollable list for large collections (max-h with overflow-y-auto)
+ - "Cancel" closes without saving
+
+ **4. Create setup detail page (src/client/routes/setups/$setupId.tsx):**
+ - Route: `createFileRoute("/setups/$setupId")`
+ - Uses `useSetup(setupId)` to fetch setup with items
+ - Sticky TotalsBar override: pass setup name as title, setup-specific stats (item count, total weight, total cost)
+ - Compute totals client-side from items array (per research recommendation)
+ - Render a local TotalsBar-like sticky bar at top of the page with setup name + stats
+ - "Add Items" button opens ItemPicker via SlideOutPanel
+ - "Delete Setup" button with ConfirmDialog confirmation
+ - Item cards grouped by category using CategoryHeader + ItemCard (same visual as collection)
+ - Each ItemCard gets a small x remove button overlay (per CONTEXT.md: non-destructive, no confirmation)
+ - Per-category subtotals in CategoryHeader (weight/cost within this setup)
+ - Empty state when no items: "No items in this setup" + "Add Items" button
+ - On successful delete, navigate to `/setups`
+
+ **5. Modify ItemCard.tsx to support remove mode:**
+ - Add optional prop: `onRemove?: () => void`
+ - When `onRemove` provided, show a small x icon button in top-right corner of card
+ - x button calls `onRemove` on click (stops propagation to prevent edit panel opening)
+ - Subtle styling: small, semi-transparent, visible on hover or always visible but muted
+ - Does NOT change existing behavior when `onRemove` is not provided
+
+ IMPORTANT: Use `useRemoveSetupItem(setupId)` for the x button on cards. Use `useSyncSetupItems(setupId)` for the checklist picker "Done" action. These are separate mutations for separate UX patterns (per research: batch sync vs single remove).
+
+
+ cd /home/jean-luc-makiola/Development/projects/GearBox && npx tsc --noEmit 2>&1 | head -30
+
+
+ - Setup list page at /setups shows all setups with name, item count, weight, cost
+ - User can create a new setup via inline form
+ - Setup detail page shows items grouped by category with per-category subtotals
+ - Item picker opens in SlideOutPanel with category-grouped checkboxes
+ - Selecting items and clicking "Done" syncs items to setup
+ - x button on item cards removes item from setup without confirmation
+ - Delete setup button with confirmation dialog works
+ - All existing TypeScript compilation passes
+
+
+
+
+
+
+```bash
+# TypeScript compilation
+npx tsc --noEmit
+
+# All tests pass (backend + existing)
+bun test
+
+# Dev server starts without errors
+# (manual: bun run dev, check no console errors)
+```
+
+
+
+- Dashboard at / shows three summary cards with real data
+- Collection at /collection has gear + planning tabs (same as before, different URL)
+- Setups list at /setups shows setup cards with totals
+- Setup detail at /setups/:id shows items grouped by category with totals
+- Item picker allows adding/removing items via checklist
+- GearBox title links back to dashboard from all pages
+- TotalsBar shows contextual stats per page
+- All internal links updated (thread resolution, FAB visibility)
+- TypeScript compiles, all tests pass
+
+
+
diff --git a/.planning/phases/03-setups-and-dashboard/03-03-PLAN.md b/.planning/phases/03-setups-and-dashboard/03-03-PLAN.md
new file mode 100644
index 0000000..ef2dd2d
--- /dev/null
+++ b/.planning/phases/03-setups-and-dashboard/03-03-PLAN.md
@@ -0,0 +1,111 @@
+---
+phase: 03-setups-and-dashboard
+plan: 03
+type: execute
+wave: 3
+depends_on: ["03-01", "03-02"]
+files_modified: []
+autonomous: false
+requirements:
+ - SETP-01
+ - SETP-02
+ - SETP-03
+ - DASH-01
+
+must_haves:
+ truths:
+ - "All four phase requirements verified working end-to-end in browser"
+ - "Navigation restructure works correctly (/, /collection, /setups, /setups/:id)"
+ - "Setup item sync and removal work correctly"
+ - "Dashboard cards show accurate summary data"
+ artifacts: []
+ key_links: []
+---
+
+
+Verify the complete Phase 3 implementation in the browser: dashboard, navigation, setup CRUD, item picker, and totals.
+
+Purpose: Human confirmation that all features work correctly before marking phase complete.
+Output: Verified working application.
+
+
+
+@/home/jean-luc-makiola/.claude/get-shit-done/workflows/execute-plan.md
+@/home/jean-luc-makiola/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/ROADMAP.md
+@.planning/phases/03-setups-and-dashboard/03-CONTEXT.md
+@.planning/phases/03-setups-and-dashboard/03-01-SUMMARY.md
+@.planning/phases/03-setups-and-dashboard/03-02-SUMMARY.md
+
+
+
+
+
+ Task 1: Visual verification of Phase 3 features
+ Human verifies all Phase 3 features in the browser
+ Complete Phase 3: Dashboard home page, navigation restructure, setup CRUD with item management, and live totals
+
+ Start the dev server: `bun run dev`
+
+ **1. Dashboard (DASH-01):**
+ - Visit http://localhost:5173/
+ - Verify three cards: Collection (item count, weight, cost), Planning (active thread count), Setups (setup count)
+ - Verify "GearBox" title in top bar, no stats shown on dashboard
+ - Click Collection card -> navigates to /collection
+ - Click Planning card -> navigates to /collection?tab=planning
+ - Click Setups card -> navigates to /setups
+
+ **2. Navigation restructure:**
+ - At /collection: verify gear/planning tabs work as before
+ - Verify "GearBox" title in TotalsBar links back to / (dashboard)
+ - Verify floating + button only appears on /collection gear tab (not on dashboard, setups, or planning tab)
+ - Go to a thread detail page -> verify "GearBox" links back to dashboard
+
+ **3. Setup creation (SETP-01):**
+ - Navigate to /setups
+ - Create a setup named "Summer Bikepacking" using inline form
+ - Verify it appears in the list as a card
+
+ **4. Item management (SETP-02):**
+ - Click the new setup card to open detail page
+ - Click "Add Items" button
+ - Verify checklist picker opens in slide-out panel with items grouped by category
+ - Check several items, click "Done"
+ - Verify items appear on setup detail page grouped by category
+ - Click x on an item card to remove it from setup (no confirmation)
+ - Verify item disappears from setup but still exists in collection
+
+ **5. Setup totals (SETP-03):**
+ - On setup detail page, verify sticky bar shows setup name, item count, total weight, total cost
+ - Remove an item -> totals update
+ - Add items back -> totals update
+ - Go back to setups list -> verify card shows correct totals
+
+ **6. Cross-feature consistency:**
+ - Edit a collection item's weight from /collection -> check setup totals update
+ - Delete a collection item -> verify it disappears from the setup too
+ - Create a thread, resolve it -> verify dashboard Planning card count updates
+
+ Human confirms all checks pass
+ All four requirements (SETP-01, SETP-02, SETP-03, DASH-01) confirmed working in browser
+ Type "approved" or describe any issues found
+
+
+
+
+
+Human visual verification of all Phase 3 requirements.
+
+
+
+- All four requirements (SETP-01, SETP-02, SETP-03, DASH-01) confirmed working
+- Navigation restructure works without broken links
+- Visual consistency with existing collection and thread UI
+
+
+