docs(03-03): complete dashboard + item detail plan summary

This commit is contained in:
Mikkel Georgsen 2026-04-10 06:22:35 +00:00
parent 19c2bb7d05
commit d0ad1fb219

View file

@ -0,0 +1,145 @@
---
phase: 03-dashboard-intake-ui
plan: "03"
subsystem: ui
tags: [react, typescript, tanstack-query, tanstack-router, zustand, tailwind, clickhouse-design, inventory]
# Dependency graph
requires:
- web/src/store/ui.ts (useUIStore — viewMode, setViewMode)
- web/src/components/ui/badge.tsx (Badge with status variants)
- web/src/components/ui/button.tsx (Button with forest/ghost/outline variants)
- web/src/components/ui/card.tsx (Card, CardHeader, CardTitle, CardContent, CardFooter)
- internal/api/handlers.InventoryItemResponse (JSON shape from GET /api/inventory)
provides:
- web/src/lib/api.ts (InventoryItem type, fetchInventory, fetchInventoryItem)
- web/src/hooks/useInventory.ts (useInventory, useInventoryItem TanStack Query hooks)
- web/src/components/layout/AppShell.tsx (TopBar + main content wrapper)
- web/src/components/layout/TopBar.tsx (sticky nav with HWLab branding)
- web/src/components/inventory/StatusBadge.tsx (catalog_status color-coded badge)
- web/src/components/inventory/ItemCard.tsx (grid card component)
- web/src/components/inventory/ItemRow.tsx (list-mode row component)
- web/src/components/inventory/FilterBar.tsx (search + status filter + view toggle)
- web/src/pages/DashboardPage.tsx (/ route — inventory grid/list)
- web/src/pages/ItemDetailPage.tsx (/item/$id route — full detail view)
affects:
- web/src/router.tsx (indexRoute + itemRoute updated to lazy-load real pages)
- 03-04, 03-05 (intake + scan pages reuse AppShell and TopBar)
# Tech tracking
tech-stack:
added: []
patterns:
- TanStack Query useQuery with typed fetchJSON wrapper (no axios)
- Zustand viewMode persists grid/list toggle across navigation within session
- lazy() + Suspense for route-level code splitting (DashboardPage + ItemDetailPage split into separate chunks)
- client-side filter via useMemo — no server-side filtering for <200 items
- label-upper CSS class applied to uppercase tracked labels
key-files:
created:
- web/src/lib/api.ts
- web/src/hooks/useInventory.ts
- web/src/components/inventory/StatusBadge.tsx
- web/src/components/inventory/ItemCard.tsx
- web/src/components/inventory/ItemRow.tsx
- web/src/components/layout/TopBar.tsx
- web/src/components/layout/AppShell.tsx
- web/src/components/inventory/FilterBar.tsx
- web/src/pages/DashboardPage.tsx
- web/src/pages/ItemDetailPage.tsx
modified:
- web/src/router.tsx
key-decisions:
- id: DASH-01
summary: "lazy() + Suspense for DashboardPage and ItemDetailPage — creates separate JS chunks (9.17KB + 4.10KB) keeping initial bundle lean"
- id: DASH-02
summary: "Client-side filtering via useMemo on items array — acceptable for <=200 item limit from API; no server-side filter params needed"
- id: DASH-03
summary: "fetchJSON generic wraps raw fetch with typed error handling — no axios dependency, consistent with project WHAT NOT TO USE list"
# Metrics
duration: 12min
completed: 2026-04-10
---
# Phase 3 Plan 03: Dashboard + Item Detail Pages Summary
**Inventory dashboard and item detail views wired to GET /api/inventory with ClickHouse design (volt/canvas/charcoal), grid/list toggle via Zustand, client-side search+filter, and mobile-responsive two-column detail layout**
## Performance
- **Duration:** ~12 min
- **Completed:** 2026-04-10
- **Tasks:** 2
- **Files created:** 10
- **Files modified:** 1
## Accomplishments
- `web/src/lib/api.ts` — typed `fetchInventory` / `fetchInventoryItem` using native fetch with error unwrapping; exports `InventoryItem` interface matching backend JSON shape
- `web/src/hooks/useInventory.ts``useInventory()` and `useInventoryItem(id)` TanStack Query hooks with proper query keys for cache invalidation
- `AppShell` + `TopBar` — sticky dark header with volt "HWLab" brand, forest-green "Add Item" button, outline "Scan" button; main content area with 7xl max-width
- `StatusBadge` — maps `catalog_status` string to 6 color-coded Badge variants (indexed=green, draft=gray, needs_research=yellow, researched=blue, complete=forest, destructive=red)
- `ItemCard` — grid card with aspect-video photo (or Package placeholder icon), volt HW ID, item name, StatusBadge, ai_notes preview (2-line clamp), hover volt border, View in NetBox link
- `ItemRow` — list-mode row with 4px status color indicator bar, HW ID, name, badge, ai_notes (hidden on mobile), hover reveal NetBox link
- `FilterBar` — search input with icon, catalog_status dropdown, item count label, grid/list toggle (Zustand viewMode)
- `DashboardPage` — full inventory view with loading/error/empty states, responsive grid (1→2→3→4→5 cols by breakpoint), list view in border container
- `ItemDetailPage` — back nav, header with HW ID + name + status + NetBox action, two-column lg (photos left, fields right) single-column mobile, ai_notes card, test_data pretty-printed JSON code block
- `router.tsx` updated — DashboardPage and ItemDetailPage lazy-loaded via `lazy()` + `Suspense` with Spinner fallback; intake/scan stubs preserved
## Task Commits
1. **Task 1: API client, hooks, layout, components**`1867846`
2. **Task 2: Pages, FilterBar, router wiring**`19c2bb7`
## Files Created/Modified
| File | Purpose |
|------|---------|
| `web/src/lib/api.ts` | Typed fetch wrappers + InventoryItem interface |
| `web/src/hooks/useInventory.ts` | TanStack Query hooks |
| `web/src/components/inventory/StatusBadge.tsx` | Status → Badge color mapping |
| `web/src/components/inventory/ItemCard.tsx` | Grid card (photo, HW ID, name, status, action) |
| `web/src/components/inventory/ItemRow.tsx` | List-mode row with status color bar |
| `web/src/components/layout/TopBar.tsx` | Sticky app header with navigation |
| `web/src/components/layout/AppShell.tsx` | TopBar + main content wrapper |
| `web/src/components/inventory/FilterBar.tsx` | Search + status filter + view toggle |
| `web/src/pages/DashboardPage.tsx` | / route — inventory grid/list with filters |
| `web/src/pages/ItemDetailPage.tsx` | /item/$id route — detail view, mobile responsive |
| `web/src/router.tsx` | Lazy-loaded real pages replacing stubs |
## Deviations from Plan
None — plan executed exactly as written.
## Known Stubs
None — all data flows from `useInventory` / `useInventoryItem` hooks which call the real backend API. No hardcoded or mock data in any component. Empty state and loading state are functional UI states, not stubs.
## Threat Surface Coverage
No new network endpoints, auth paths, or trust boundary changes introduced — this plan is purely frontend components consuming the existing GET /api/inventory endpoints established in Plan 03-02.
## Self-Check
Files created:
- web/src/lib/api.ts: FOUND
- web/src/hooks/useInventory.ts: FOUND
- web/src/components/inventory/StatusBadge.tsx: FOUND
- web/src/components/inventory/ItemCard.tsx: FOUND
- web/src/components/inventory/ItemRow.tsx: FOUND
- web/src/components/layout/TopBar.tsx: FOUND
- web/src/components/layout/AppShell.tsx: FOUND
- web/src/components/inventory/FilterBar.tsx: FOUND
- web/src/pages/DashboardPage.tsx: FOUND
- web/src/pages/ItemDetailPage.tsx: FOUND
Commits:
- 1867846: feat(03-03): API client, TanStack Query hooks, layout shell, inventory item components
- 19c2bb7: feat(03-03): DashboardPage, ItemDetailPage, FilterBar, and router wiring
`npm run build`: PASS (1717 modules, 0 TypeScript errors, dist/assets/ written)
## Self-Check: PASSED