# Electronics Inventory A self-hosted web app for managing an electronics component collection. Track components, their field values, physical storage locations, and visual panel/grid layouts. ## Features ### Components Define reusable component types (e.g. Resistor, Capacitor, IC) with custom fields per component. Components show up in inventory entries and can be navigated to directly from storage locations. - Word-split search: searching `0603 res` matches `Resistor 0603` - Selected component reflected in URL (`/components/:id`) — survives page refresh - Resizable list pane (width persisted in localStorage) - Duplicate button to quickly clone a component - Field values sorted alphabetically, rendered centrally (units, URLs as links, extensible) ### Fields Create custom field definitions (e.g. `resistance`, `capacitance`, `package`) with an optional unit suffix. Unit is appended directly to the value with no space, so you can write `4k7` for a resistance field with unit `Ω` and it displays as `4k7Ω`. URL-like field values (beginning with `http://` or `https://`) are automatically rendered as clickable links. ### Inventory Log where things are stored. Each inventory entry links a component to a storage location. Supported location types: - **Grid cell** — a specific row/column in a named grid (e.g. drawer divider box), picked visually with a graphical cell picker - *(plain entries without a grid reference work too)* Notes on inventory entries are per storage location (not per component). ### Grids Model physical storage grids (drawer organizers, parts boxes, etc.). 1. Upload a photo of the grid 2. Set up corner points to map the image to a logical grid (corners can extend outside image bounds) 3. Define row/column counts 4. Click any cell to see what's stored there — component entries are links, middle-click opens in new tab 5. Each cell shows a green count badge of how many components reference it 6. Navigating to a grid from a component detail highlights and scrolls to the relevant cell ### PDF Attachments Attach PDF datasheets or other documents to components. - PDFs are stored with a sanitized human-readable filename derived from the display name - Rename a PDF and the file on disk is also renamed, atomically (uses `renameat2 RENAME_NOREPLACE` via `tools/mv-sync`) - First-page thumbnails generated automatically via `pdftoppm` (poppler-utils) if available - Multiple components can share the same PDF - Click any thumbnail to open it full-size in a lightbox ### Templates (Name Formatters) Write JavaScript formatter functions that generate smart display names for components based on their field values. Example: ```js (c) => { const F = c.fields; if (F.resistance && F.imperial_package) { return `${F.resistance}Ω ${F.imperial_package}`; } } ``` Fields are accessed by name (e.g. `c.fields.resistance`). If the formatter returns a non-empty string it's used as the display name; otherwise the component's base name is used as fallback. Multiple formatters are tried in order. The template editor includes a test data box so you can preview the output without needing real inventory data. ### Maintenance A ⚙ menu in the top-right corner provides maintenance operations: - **Generate missing PDF thumbnails** — scans all PDFs and generates thumbnails for any that don't have one yet (useful if `pdftoppm` was unavailable at upload time) ## Requirements - Node.js >= 25 - npm - `gcc` (to build `tools/mv-sync` — only needed once) - `pdftoppm` from poppler-utils (optional, for PDF thumbnails) ## Install Install directly from the git repository — there is no npm package yet: ```bash npm install git+https://gitea.efforting.tech/mikael-lovqvists-claude-agent/electronics-inventory.git ``` Or clone if you prefer to keep the source around: ```bash git clone https://gitea.efforting.tech/mikael-lovqvists-claude-agent/electronics-inventory cd electronics-inventory npm install ``` ## Build native tools ```bash cd tools && make ``` This compiles `mv-sync`, a small helper that performs an atomic rename-without-overwrite using `renameat2(RENAME_NOREPLACE)` (Linux 3.15+). It is required for PDF file operations. ## Run ```bash npm start ``` The server starts on port 3020, bound to `localhost` only, by default. Open [http://localhost:3020](http://localhost:3020) in your browser. Both can be overridden with environment variables: ```bash PORT=8080 npm start # different port BIND_ADDRESS=0.0.0.0 npm start # all interfaces (LAN accessible) BIND_ADDRESS=192.168.1.50 npm start # specific interface PORT=8080 BIND_ADDRESS=0.0.0.0 npm start # both ``` > **Note:** The default `localhost` binding means the app is only reachable from the same machine. > Set `BIND_ADDRESS=0.0.0.0` to expose it on your local network. ## Data Storage All data is stored locally in a `data/` directory created automatically on first run: - `data/db.json` — component, field, inventory, grid, template, and PDF records (flat KV store) - `data/images/` — uploaded source images and component/inventory photos - `data/pdfs/` — uploaded PDF files and their thumbnails No external database is required. ## Project Structure ``` server.mjs Express 5 API server + SPA host lib/ storage.mjs Server-side KV store wrappers kv-store.mjs JSON file-backed key-value store ids.mjs ID generation grid-image.mjs Grid image processing helpers tools/ mv-sync.c Atomic rename helper (renameat2 RENAME_NOREPLACE) Makefile public/ app.mjs Single-page app (vanilla JS ES modules) templates.html HTML templates (lazy-loaded) style.css Styles lib/ api.mjs Fetch wrappers for the REST API dom.mjs DOM helpers views/ grid-setup.mjs Canvas-based grid corner editor ```