Commit graph

81 commits

Author SHA1 Message Date
de807ba931 docs(04-05): complete frontend USB status bar and print label plan 2026-04-10 06:58:21 +00:00
4d2d35e277 docs(04-03): complete printer driver + HTTP endpoints plan — MockDriver, SSE, rate limiter 2026-04-10 06:53:59 +00:00
9f57cbdf6c feat(04-03): LabelHandler, USBEventsHandler, router wiring, main.go USB+printer init
- LabelHandler: POST /api/labels/:deviceID/print with 1/s rate limit (T-04-09)
- USBEventsHandler: GET /api/usb/events SSE stream, exits on context cancel (T-04-11)
- router.go: two new parameters + routes wired
- main.go: USB Manager started with ctx, MockDriver connected, handlers passed to router
2026-04-10 06:52:52 +00:00
dd381eefa3 test(04-03): add failing handler tests for label print and USB SSE (TDD RED) 2026-04-10 06:50:51 +00:00
1156eff896 feat(04-03): PrinterDriver interface, MockDriver, PrtQutieDriver stub
- PrinterDriver interface: Connect/Print(bitmap,w,h)/Disconnect
- ImageToRawBitmap(): 1-bit packed row-major converter from image.Image
- MockDriver: saves PNG to SaveDir (/tmp default) for visual inspection
- PrtQutieDriver: stub returns ErrNoDevice — safe before hardware arrives
- ErrNoDevice, ErrNotConnected, ErrEmptyBitmap sentinel errors
2026-04-10 06:50:12 +00:00
b223b54a87 test(04-03): add failing printer driver tests (TDD RED) 2026-04-10 06:49:31 +00:00
2d6765077c Merge commit 'bec54df' 2026-04-10 06:47:55 +00:00
bec54df2e0 docs(04-02): complete label rendering plan — QR code + bitmap renderers 2026-04-10 06:47:13 +00:00
63b66f7a94 docs(04-01): complete USB manager plan — goroutine-per-device, VID/PID enumeration
- 10/10 tests pass with -race flag
- goroutine count stable across 5 replug cycles
- T-04-01 read buffer cap mitigated
- Known stubs: VID/PID placeholder pending hardware 2026-04-13
2026-04-10 06:46:07 +00:00
7800917500 feat(04-02): cable label renderer and IsCableDevice detection
- Add CableLabelData struct and RenderCable() producing 384x180 bitmap
- Cable template: HW ID, name, USB version/speed, wattage/test date
- IsCableDevice() detects cable records by name or AINotes heuristic
- T-04-07 mitigation applied: HWID format validated in RenderCable too
- All 5 cable tests pass (10 total in package)
2026-04-10 06:45:48 +00:00
82eaf6bed7 feat(04-01): USB Manager goroutine-per-device, poll loop, reconnect, leak-safe teardown
- Manager with injectable enumerateFunc and serialOpener for test isolation
- goroutine-per-device model: deviceLoop owns one serial port per device
- context+done-channel teardown: inner read goroutine exits on ctx.Done()
- Read buffer capped at 4096 bytes (T-04-01 threat mitigation)
- Poll loop reconciles prev/current snapshots for connect/disconnect events
- ErrDeviceNotConnected returned by Send() when device absent
- All 5 manager tests pass with -race flag; goroutine count stable across 5 replug cycles
- mockPort test helper blocks Read until Close() unblocks it (realistic behavior)
2026-04-10 06:45:26 +00:00
8cbd840cba feat(04-02): standard label renderer with QR code generation
- Add internal/labels package with LabelData struct and RenderStandard()
- QR encodes http://mac-mini.mg:8080/hw/HW-XXXXX (LBL-01)
- Label is 384x120px NRGBA, white background, basicfont text
- T-04-07 mitigation: validate HWID format before qrcode.New()
- Install github.com/skip2/go-qrcode and golang.org/x/image
- All 5 renderer tests pass
2026-04-10 06:44:11 +00:00
f5b1d3156c feat(04-01): USB device types, KnownDevices registry, VID/PID enumeration
- DeviceSpec, DeviceRole, DeviceState, DeviceEvent, Command types
- KnownDevices registry with PRT Qutie placeholder (0525:a4a7)
- enumerateConnected() with system_profiler JSON parsing + injectable test seams
- ParseVIDPID() helper with error on malformed input
- All 5 device_test.go tests pass
- go.bug.st/serial v1.6.4 added to go.mod
2026-04-10 06:43:43 +00:00
77bf4ebfd6 docs(04): create phase 4 plans — USB manager, label printing, SSE, intake integration
5 plans across 3 waves covering USB-01 through USB-04 and LBL-01 through LBL-05.
Mock drivers and goroutine-leak harness tests enable full TDD before hardware arrives.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 06:41:26 +00:00
6a8a4658a7 docs(04): auto-generated context (hardware phase) 2026-04-10 06:34:02 +00:00
ecb0c99f7b docs(phase-3): complete phase execution 2026-04-10 06:33:14 +00:00
1fe46db050 docs(03): phase 3 verification + human UAT (3 gaps deferred for review) 2026-04-10 06:33:09 +00:00
021c82875e fix(03): resolve TypeScript type mismatches from merged plans 2026-04-10 06:27:11 +00:00
e2ac3b10aa chore: merge 03-04 worktree (intake UI) — resolved router/api/AppShell conflicts 2026-04-10 06:25:29 +00:00
8c7563af9a chore: merge 03-03 worktree (dashboard+detail) — resolved router/api/AppShell conflicts 2026-04-10 06:24:20 +00:00
83e1725cd9 docs(03-05): complete PWA manifest + service worker + QR scanner plan 2026-04-10 06:23:01 +00:00
7fc7705c84 docs(03-04): complete intake wizard UI plan summary 2026-04-10 06:22:46 +00:00
d0ad1fb219 docs(03-03): complete dashboard + item detail plan summary 2026-04-10 06:22:35 +00:00
75c91a5941 feat(03-05): QR scanner page with @zxing/browser and router wiring
- web/src/pages/ScanPage.tsx: camera QR scanner with volt reticle overlay
  - extractHWID() parses both URL format and bare HW-XXXXX patterns
  - rear camera preference (back/rear/environment label matching)
  - debounce via lastScanned state prevents duplicate navigation
  - graceful camera permission denied error state
- web/src/router.tsx: lazy-loads ScanPage with Suspense fallback spinner
- web/src/lib/api.ts: typed fetch wrappers (fetchInventory, fetchInventoryItem)
- web/src/components/layout/AppShell.tsx: minimal page wrapper (stub for plan 03-03)
2026-04-10 06:22:14 +00:00
95a50f4abd feat(03-05): PWA manifest, service worker, icons, and registration hook
- web/public/manifest.json with display=standalone, theme_color=#faff69, 192+512 icons
- web/public/sw.js with app-shell cache strategy (API calls network-only)
- web/public/icons/icon-192.png and icon-512.png generated via gen-icons.cjs
- web/scripts/gen-icons.cjs pure-Node.js PNG icon generator (black canvas, volt H monogram)
- web/src/hooks/usePWA.ts registers service worker on app load
- web/index.html: added theme-color meta tag
- web/src/App.tsx: calls usePWA() hook
2026-04-10 06:22:05 +00:00
5909025677 feat(03-04): intake wizard UI — AIResultReview, ConfirmForm, IntakePage, router wiring
- AIResultReview: confidence meter (green/yellow/red), manufacturer/model/category/tags, editable name input, ai_notes card
- ConfirmForm: confirm/start-over action buttons with submitting spinner state
- AppShell: top-nav layout wrapper with HWLab logo and Inventory/Add Item nav links
- IntakePage: three-step wizard (upload → submitting → review) wired to submitIntake()
- router.tsx: lazy-loads IntakePage for /intake, Suspense+Spinner fallback
- Analyze button disabled during submitting (T-03-13 DoS mitigation)
2026-04-10 06:21:53 +00:00
19c2bb7d05 feat(03-03): DashboardPage, ItemDetailPage, FilterBar, and router wiring
- web/src/components/inventory/FilterBar.tsx: search + status dropdown + grid/list toggle
- web/src/pages/DashboardPage.tsx: / route with grid/list view, filters, loading/error/empty states
- web/src/pages/ItemDetailPage.tsx: /item/$id route, two-column desktop, single-column mobile
- web/src/router.tsx: lazy-load DashboardPage + ItemDetailPage, keep intake/scan stubs
2026-04-10 06:21:48 +00:00
1867846a9f feat(03-03): API client, TanStack Query hooks, layout shell, inventory item components
- web/src/lib/api.ts: typed fetch wrappers for GET /api/inventory and GET /api/inventory/:id
- web/src/hooks/useInventory.ts: useInventory + useInventoryItem TanStack Query hooks
- web/src/components/inventory/StatusBadge.tsx: catalog_status → Badge variant mapping
- web/src/components/inventory/ItemCard.tsx: grid card with photo, HW ID, name, status, NetBox link
- web/src/components/inventory/ItemRow.tsx: list-mode row with status color indicator
- web/src/components/layout/TopBar.tsx: sticky nav with HWLab volt brand, Add Item + Scan buttons
- web/src/components/layout/AppShell.tsx: TopBar + main content wrapper
2026-04-10 06:21:43 +00:00
709876d3a0 feat(03-04): add intake Zustand store, api.ts submitIntake, DropZone, PhotoPreview
- useIntakeStore: step tracking, photos (max 3), aiResult, editedName, error
- submitIntake(): multipart FormData POST /api/intake with IntakeResponse type
- DropZone: react-dropzone with camera capture, volt hover state, slot counter
- PhotoPreview: thumbnail grid with X remove button per photo
2026-04-10 06:20:35 +00:00
86d0a949c5 Merge commit 'a892ae1c38cf308a9652370e0c7c2e22a6d9283c' 2026-04-10 06:18:11 +00:00
f151b96f88 docs(03-01): complete frontend scaffold plan — Vite+React+ClickHouse design system 2026-04-10 06:17:42 +00:00
d38f93dd67 feat(03-01): bootstrap React+TS frontend with ClickHouse design system
- Vite 5 + React 18 + TypeScript 5 + Tailwind 3 scaffold in web/
- ClickHouse design tokens (volt, forest, canvas, charcoal, near-black) in tailwind.config.ts
- TanStack Router v1 with placeholder routes for /, /item/$id, /intake, /scan
- TanStack Query v5 QueryClientProvider + Zustand uiStore
- shadcn/ui Button (neon/forest/secondary/outline/ghost), Card, Badge with ClickHouse variants
- Vite proxy: /api -> http://localhost:8080
- Makefile: added frontend and dev-frontend targets
- Fixed: @typescript-eslint v8 for ESLint v9 compatibility; @types/node for vite.config.ts
2026-04-10 06:16:46 +00:00
a892ae1c38 docs(03-02): complete inventory endpoints plan summary 2026-04-10 06:16:09 +00:00
743611f488 feat(03-02): wire GET /api/inventory and GET /api/inventory/{id} routes
- NewRouter signature extended to accept *handlers.InventoryHandler
- GET /inventory and GET /inventory/{id} registered in /api route group
- main.go constructs handlers.NewInventoryHandler(nbClient) and passes to NewRouter
2026-04-10 06:15:12 +00:00
b0b6153b24 feat(03-02): InventoryHandler with list+detail endpoints and 7 unit tests
- InventoryNetBoxClient interface (ListDevices + GetDevice) for testability
- ListInventory returns 200 JSON array (limit=200, 502 on NetBox error)
- GetInventoryItem returns 200/404/400/502 based on ID validity and NetBox response
- deviceToResponse maps netbox.Device to InventoryItemResponse (nil PhotoURLs → [])
- 7 TDD tests: empty list, 2-item list, NetBox error, found, not found, invalid ID, server error
2026-04-10 06:14:43 +00:00
206d6886aa docs(03): mark phase 3 plans autonomous for overnight execution 2026-04-10 06:12:46 +00:00
1a9931f900 docs(03): create phase 3 plans — dashboard, intake UI, PWA (5 plans, 2 waves)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 06:12:02 +00:00
22c504247d docs(03): auto-generated context (frontend phase) 2026-04-10 06:01:54 +00:00
7b322653e7 docs(phase-2): complete phase execution 2026-04-10 06:01:10 +00:00
dcb388c7ea docs(02): phase 2 verification + human UAT 2026-04-10 06:01:06 +00:00
16cfc48644 docs(02-03): complete intake handler plan summary 2026-04-10 05:56:50 +00:00
59aa89b199 feat(02-03): wire POST /api/intake route, real WAQ handler, and NetBox defaults in config
- router.go: NewRouter accepts intakeHandler http.Handler, registers POST /api/intake
- config.go: adds NetBoxDefaultDeviceTypeID/RoleID/SiteID fields with defaults and env bindings
- main.go: creates netbox.Client, ai.Orchestrator, inventory.CatalogUpdater, handlers.IntakeHandler
- main.go: replaces NoOpHandler with NewNetBoxOpHandler(nbClient) for WAQ worker
- main.go: uses typed interface variable for WAQ to avoid nil-interface-wrapping bug
2026-04-10 05:55:41 +00:00
4fc9362519 feat(02-03): POST /api/intake handler with orchestrator and NetBox wiring
- IntakeHandler with IntakeOrchestrator/IntakeNetBoxClient/IntakeCatalogUpdater/IntakeWAQ interfaces
- Validates 1-3 photos, base64-encodes, calls Analyze, allocates HW-ID
- Quick-add mode: confidence >= threshold skips review, creates NetBox record immediately
- WAQ enqueue on NetBox failure returns 202 with queued=true
- nil WAQ + NetBox down returns 503
- Six unit tests: reject-0, reject-4, high-confidence, low-confidence, quick-add, netbox-down
- [Rule 1 - Bug] PatchCustomFields signature changed int -> int64 to match NetBoxOpsClient interface
- [Rule 1 - Bug] UpdateCatalogStatus signature changed int -> int64 for consistency with CreateDevice return type
2026-04-10 05:54:33 +00:00
e3a5fef306 docs(02-02): complete orchestrator, WAQ handler, research stub plan
- SUMMARY.md: 5 orchestrator tests, 6 handler tests all passing
- Commits: 799acd2 (orchestrator + research stub), 73eab56 (WAQ handler)
- All STRIDE threats T-02-05 through T-02-08 mitigated
2026-04-10 05:50:01 +00:00
73eab561cf feat(02-02): WAQ real NetBox op handler replacing NoOpHandler
- NewNetBoxOpHandler routes create_device → CreateDevice, patch_custom_fields → PatchCustomFields
- NetBoxOpsClient interface enables test injection without importing netbox package
- Unknown op types return error (re-queued by worker, not silently dropped — T-02-08)
- JSON payloads decoded into typed structs (T-02-07 tampering mitigation)
- 6 handler tests all passing (TDD green); NoOpHandler untouched in worker.go
2026-04-10 05:48:30 +00:00
799acd26ef feat(02-02): three-tier orchestrator with confidence routing and research stub
- Orchestrator.Analyze: tier1 → confidence check → tier2 escalation if < threshold
- CatalogStatus mapped from confidence: >= threshold → StatusIndexed, else StatusNeedsResearch
- Both tiers fail gracefully: returns zero-value IntakeResult + StatusNeedsResearch, err nil
- ResearchClient interface + NoOpResearchClient stub for Phase 7 SearXNG
- 5 TestOrchestrator* tests all passing (TDD green)
2026-04-10 05:47:41 +00:00
3eed2e9c63 docs(02-01): complete AI package foundation plan
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 05:46:05 +00:00
8c03780230 feat(02-01): AI package foundation — types, interface, mock, prompts, config extension
- internal/ai/types.go: IntakeRequest, IntakeResult, TierConfig, AIConfig domain types
- internal/ai/client.go: AIClient interface + TierClient (go-openai, BaseURL tier-routing)
- internal/ai/mock.go: MockAIClient test double with HighConfidenceResult/LowConfidenceResult fixtures
- internal/ai/prompts/intake.go: BuildIntakePrompt() JSON-extraction prompt template
- internal/config/config.go: Config.AI AIConfig field, tier defaults, env bindings, ai_config.json merge
- ai_config.json: template config with placeholder Tier2 API key
- .gitignore: add ai_config.local.json pattern for real keys (T-02-01 mitigation)
- All tests pass: TestMockAIClient, TestMockAIClientError, TestTierClientConstruction, TestAIConfigDefaults
2026-04-10 05:45:13 +00:00
6040ecc3cc feat(02-01): install go-openai and add CreateDevice to NetBox client
- go get github.com/sashabaranov/go-openai v1.41.2
- Add CreateDevice(ctx, name, assetTag, deviceTypeID, roleID, siteID) → (int64, error)
- Add DeleteDevice(ctx, id) for test cleanup
- Use Int32As* oneOf helpers for go-netbox v4 FK fields
- TestCreateDeviceValidation PASS; TestCreateDeviceLive SKIP (no live token)
2026-04-10 05:42:51 +00:00
7bebe2ed93 docs(02): create phase 2 AI pipeline plans (4 plans, 4 waves)
Wave 1: go-openai dep, CreateDevice gap, AIClient interface + mock + config
Wave 2: three-tier orchestrator, WAQ real handler, SearXNG stub
Wave 3: POST /api/intake handler, router wiring, quick add mode
Wave 4: oMLX integration test + memory checkpoint

Covers requirements: AI-01 through AI-09 (AI-04 stub only; full impl Phase 7)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 05:40:22 +00:00