11 KiB
11 KiB
Stack Research
Domain: Self-hosted AI-powered hardware inventory system (Go + React) Researched: 2026-04-09 Confidence: MEDIUM-HIGH (core stack confirmed via search; some library versions from training data)
Recommended Stack
Core Technologies
| Technology | Version | Purpose | Why Recommended |
|---|---|---|---|
| Go | 1.22+ | Backend API, USB/serial control, AI orchestration | Native concurrency for USB polling + HTTP serving; single binary deployment; no runtime dependency; best-in-class serial I/O on macOS |
| React | 18.x | SPA frontend | Mature ecosystem, hooks-based state management, excellent TypeScript support; right level of complexity for a single-operator tool |
| TypeScript | 5.x | Frontend type safety | Catches API contract drift early; NetBox has complex nested types that benefit from strict typing |
| Tailwind CSS | 3.x | Utility-first styling | ClickHouse-inspired design system maps well to utility classes; no CSS file sprawl; dark theme with arbitrary values is trivial |
| SQLite (via mattn/go-sqlite3) | 3.x / v1.14+ | Local-only storage (chat history, config, session state) | Zero-dependency embedded DB; perfectly suited for single-operator append-heavy chat logs; no separate process |
| oMLX | latest | Local LLM inference server on Mac Mini M4 | Native Apple Silicon MLX backend, OpenAI-compatible API endpoint, paged SSD KV caching, continuous batching; supports Gemma 4 VLM natively; drop-in for any OpenAI-SDK client |
Go Backend Libraries
| Library | Version | Purpose | When to Use |
|---|---|---|---|
| github.com/netbox-community/go-netbox/v4 | v4.x | NetBox REST API client | All CRUD against NetBox — officially maintained, generated from NetBox OpenAPI spec |
| go.bug.st/serial | v1.x | USB serial communication | Printer + cable tester I/O; actively maintained, cross-platform, better API than tarm/serial; supports port enumeration |
| github.com/gin-gonic/gin | v1.9+ | HTTP router and middleware | Fast, well-documented, large middleware ecosystem; handles file uploads for photo intake cleanly |
| github.com/mattn/go-sqlite3 | v1.14+ | SQLite driver (cgo) | Standard Go SQLite driver; use with database/sql for portability |
| github.com/jmoiern/sqlx | v1.3+ | database/sql extension | Named params and struct scanning reduce boilerplate for chat history queries |
| github.com/sashabaranov/go-openai | v1.x | OpenAI-compatible client | Handles both oMLX local endpoint and OpenRouter remote; single client, swap base URL per tier |
| github.com/skip2/go-qrcode | v0.0.0 | QR code generation | Generate HW-XXXXX QR codes server-side before sending to printer |
| github.com/google/uuid | v1.x | UUID generation | HW-XXXXX ID assignment; deterministic or random depending on design choice |
| github.com/spf13/viper | v1.x | Config management | YAML/env config for AI endpoints, NetBox URL/token, USB port paths |
Frontend Libraries
| Library | Version | Purpose | When to Use |
|---|---|---|---|
| Vite | 5.x | Build tool and dev server | Fastest HMR in class; Go backend runs separately, Vite proxies API calls in dev |
| TanStack Query (React Query) | v5 | Server state management | NetBox data is server state not client state; handles caching, refetch, stale-while-revalidate |
| TanStack Router | v1 | Type-safe routing | Better TypeScript integration than React Router v6 for complex nested routes |
| Zustand | v4 | Client state (UI state, chat) | Lightweight, no boilerplate, perfect for chat message buffer and USB device status |
| shadcn/ui | latest | Component primitives | Radix UI + Tailwind, fully owned code (not a dependency), dark mode first, ClickHouse aesthetic compatible |
| react-dropzone | v14 | Photo drag-and-drop | Standard library for file upload UX; works with multipart form to Go backend |
| react-hot-toast | v2 | Toast notifications | Inventory actions (label printed, test passed) need lightweight non-blocking feedback |
| lucide-react | latest | Icon set | Consistent, tree-shakeable, TypeScript-native, pairs well with shadcn/ui |
Development Tools
| Tool | Purpose | Notes |
|---|---|---|
| Air (cosmtrek/air) | Go hot reload in development | Watch + rebuild backend on save; configure alongside Vite proxy |
| golangci-lint | Go linting | Run in CI; catches serial/concurrent code issues early |
| ESLint + typescript-eslint | Frontend linting | Strict TypeScript rules; catch NetBox API type drift |
| Prettier | Frontend formatting | Single config, no debates |
| Bruno (or httpie) | API testing | Test NetBox integration and Go endpoints locally without Postman account |
Installation
# Go backend — initialize module
go mod init git.georgsen.dk/hwlab
# Core Go dependencies
go get github.com/gin-gonic/gin@latest
go get github.com/netbox-community/go-netbox/v4@latest
go get go.bug.st/serial@latest
go get github.com/mattn/go-sqlite3@latest
go get github.com/jmoiern/sqlx@latest
go get github.com/sashabaranov/go-openai@latest
go get github.com/skip2/go-qrcode@latest
go get github.com/google/uuid@latest
go get github.com/spf13/viper@latest
# Frontend — scaffold
npm create vite@latest frontend -- --template react-ts
cd frontend
# Frontend core dependencies
npm install @tanstack/react-query @tanstack/react-router zustand
npm install react-dropzone react-hot-toast lucide-react
npm install class-variance-authority clsx tailwind-merge # shadcn/ui deps
# shadcn/ui init (run in frontend dir)
npx shadcn@latest init
# Dev dependencies
npm install -D @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint prettier tailwindcss autoprefixer postcss
Alternatives Considered
| Recommended | Alternative | When to Use Alternative |
|---|---|---|
| go.bug.st/serial | tarm/serial | tarm/serial is adequate if you only need basic read/write and already have it; go.bug.st/serial is preferred for new projects due to active maintenance and port listing |
| gin-gonic/gin | chi, echo, fiber | chi if you want stdlib-compatible handlers; echo for similar feature set; fiber if you need extreme HTTP throughput (not relevant here) |
| go-openai (sashabaranov) | Custom HTTP client | Custom client only if you need streaming SSE to browser — go-openai supports streaming too, prefer it |
| TanStack Router | React Router v6 | React Router v6 is fine if team is already familiar; TanStack Router has stronger TypeScript guarantees for route params |
| TanStack Query | SWR | SWR is lighter but TanStack Query has better devtools and mutation handling for NetBox writes |
| mattn/go-sqlite3 (cgo) | modernc.org/sqlite (pure Go) | Use modernc.org/sqlite if you want zero cgo dependency (simpler cross-compilation); slightly slower but avoids gcc requirement |
| oMLX | Ollama | Ollama works but oMLX has better Apple Silicon performance via MLX backend; Gemma 4 VLM continuous batching support is oMLX-specific |
What NOT to Use
| Avoid | Why | Use Instead |
|---|---|---|
| GORM | Heavy ORM abstraction for what is essentially two tables (chat logs, config); migrations and reflection overhead not worth it for SQLite local-only store | database/sql + sqlx directly |
| tarm/serial | Last commit 2018, unmaintained, no port enumeration, open issues unaddressed | go.bug.st/serial |
| Redux (React) | Massive boilerplate for a solo-operator SPA; overkill when TanStack Query handles server state | Zustand + TanStack Query |
| axios | Unnecessary HTTP client abstraction; TanStack Query works with native fetch; one fewer dependency | fetch API directly inside TanStack Query |
| Next.js | SSR/SSG overhead not needed — Go handles the API, React is a pure SPA served as static files | Vite + React SPA |
| llama.cpp Go bindings | Not optimized for Apple Silicon; MLX backend (oMLX) is 2-4x faster on M-series; cgo binding complexity | oMLX via OpenAI-compatible HTTP |
| Direct NetBox HTTP calls (no client) | NetBox v4 API has 200+ endpoints; go-netbox generates typed structs from OpenAPI spec — manual HTTP is brittle | go-netbox/v4 |
Stack Patterns by Variant
For the AI tier routing (local vs remote):
- Use a single
go-openaiclient instance per tier, configured withBaseURLpointing to oMLX (http://localhost:PORT/v1) for Tier 1, andhttps://openrouter.ai/api/v1for Tier 2/3 - Switch by returning the appropriate client from a factory based on model config
- Do NOT hardcode tier selection in business logic — make it config-driven from the start
For USB serial (printer + testers):
- Use
go.bug.st/serialwith a dedicated goroutine per device, communicating via channels - Do not share a serial.Port across goroutines — open one port per device, serialize writes in the owning goroutine
- USB device paths on macOS follow
/dev/cu.usbserial-*or/dev/cu.usbmodem*; useserial.GetPortsList()to enumerate at startup
For photo intake (multipart upload):
- Accept multipart/form-data in Gin; decode image in Go; send as base64 in the OpenAI vision API call to oMLX
- Store the original photo in a local temp directory only until the NetBox record is created; do not persist photos in HWLab itself
- Gemma 4 E4B fits comfortably in 16GB; Gemma 4 26B A4B needs TurboQuant KV offload — benchmark before committing to 26B
For NetBox custom fields:
- go-netbox v4 represents custom fields as
map[string]interface{}; define typed wrapper structs in your own code to handlehw_id,condition,quality_gateetc. - Custom fields must be created in NetBox admin before the Go code can write them — treat this as infrastructure provisioning (Phase 1 task)
Version Compatibility
| Package | Compatible With | Notes |
|---|---|---|
| go-netbox/v4 | NetBox 4.x | Generated from NetBox 4.x OpenAPI; not compatible with NetBox 3.x API responses |
| mattn/go-sqlite3 v1.14+ | Go 1.21+ | Requires cgo; needs gcc or Xcode CLT on macOS |
| shadcn/ui | React 18, Tailwind 3.x | shadcn v2+ requires Tailwind 3.x; not yet tested with Tailwind 4 alpha |
| oMLX | macOS 15+, Apple Silicon M1+ | Won't run on Intel Mac or Linux |
| go-openai v1.x | OpenAI API v1, OpenRouter, oMLX | Any OpenAI-compatible endpoint works; set BaseURL in ClientConfig |
Sources
- github.com/jundot/omlx — oMLX feature set, Gemma 4 VLM support confirmed (HIGH confidence)
- github.com/netbox-community/go-netbox — Official Go client, v4 confirmed (HIGH confidence)
- go.bug.st/serial pkg.go.dev — Active maintenance confirmed, preferred over tarm/serial (HIGH confidence)
- omlx.ai — macOS 15+ requirement, 16GB minimum RAM, MLX backend (HIGH confidence)
- WebSearch: tarm/serial maintenance status — last substantive commit 2018, multiple forks active (MEDIUM confidence)
- Training data: gin, TanStack Query, Zustand, Vite, shadcn/ui versions — standard 2025 React/Go stack (MEDIUM confidence, verify pinned versions before first install)
Stack research for: HWLab — self-hosted AI hardware inventory (Go + React + oMLX + NetBox) Researched: 2026-04-09