# inventree A small, self-contained IT asset inventory system. The heart of inventree is a nested folder tree — like a file manager — for organizing physical and virtual IT assets (servers, switches, laptops, printers, etc.). - Single compiled Go binary, embedded HTML templates and static assets - SQLite storage (WAL mode, foreign keys, migrations) - Bootstrap 5 UI, minimal vanilla JavaScript (no Node/React/build step) - Session-based auth with two roles: Admin and User - Custom, admin-defined asset types with custom fields - CSV import/export, full-text-ish search with breadcrumbs ## Quick start ```sh go build -o inventree ./cmd/inventree ./inventree serve ``` Then open http://localhost:8080 and log in with: ``` Username: admin Password: admin ``` (This default account is created intentionally on first run. Change or disable it via the Users admin page once you're up and running.) The database file is created automatically at `data/inventree.db` on first run, with migrations applied and seed data (default statuses, item types, and the admin account) inserted. ## CLI ```sh inventree # same as `inventree serve` inventree serve # start the web server inventree version # print the version inventree database migrate # apply pending migrations and exit inventree database backup [path] # write a consistent VACUUM INTO snapshot ``` `serve` flags: | Flag | Default | Description | |---------------------|------------------------|--------------------------------------------| | `-addr` | `:8080` | Listen address | | `-db` | `data/inventree.db` | Path to the SQLite database file | | `-secure-cookies` | `false` | Mark the session cookie `Secure` (enable when serving over HTTPS) | `/healthz` is available for load balancer / container health checks. ## The inventory tree The Inventory page is the default page after login and the center of the application: a folder/asset tree on the left, and a detail panel on the right that shows whatever is selected (a folder's contents, or a single asset). - **Folders** can nest arbitrarily deep, and contain both subfolders and assets. - **Expand/collapse** state is remembered per user (persisted server-side), and folder contents are fetched lazily via small AJAX requests — the page never fully reloads when you browse the tree. - **Drag and drop** folders and assets onto another folder (or onto "Inventory" itself) to move them. Admin only. - **Right-click for everything**: it's meant to feel like a native file manager. Right-click a folder, an asset, a breadcrumb crumb, or empty tree/panel background for the actions available there (New Subfolder, Add Asset, Rename, Check Out, Move, Print Label, Delete, …) instead of hunting for a toolbar button. The main panel itself stays blank until you actually click into a folder or asset — browsing happens in the tree. - **Deleting a folder** that still contains subfolders or assets requires confirmation, and offers a safe "move contents elsewhere" option instead of an accidental cascade. A "permanently delete everything inside" option is also available for when that's genuinely what you want. - **Search** (top of the tree pane) looks across asset ID, name, folder name, item type, assigned user, notes, and custom field values, and shows each result's full folder breadcrumb. ## Item types and custom fields Admins can define arbitrary asset types (Laptop, Switch, Firewall, …) under **Item Types**, each with its own set of custom fields (text, long text, number, date, boolean, dropdown, URL, IP address), marked required or not, with a default value and display order. A representative starter set of types and fields is seeded on first run — feel free to edit or delete it. ## Checkout, quantity, and contacts - **Check out / check in**: right-click an asset → **Check Out…** to assign it to a user (or clear the assignment to check it back in). Works from any asset row, not just its detail view. - **Quantity vs. unique**: item types have a **Unique** flag (checked by default). Unique types — a laptop, a server — get one asset row per physical unit, same as before. Uncheck it for bulk/consumable types (a USB cable, a box of screws) and assets of that type are tracked as a single row with a **Quantity** and +/- steppers in the asset panel and folder tables, instead of one row per unit. Flipping a type back to Unique clamps any existing quantities back down to 1. - **Contacts**: under Settings → Users, a third role alongside Admin and User. Contacts can't sign in at all — they exist purely so you can assign assets to end users (e.g. "this laptop belongs to Jane in Accounting") without creating them a login account. A blank password is fine when creating one. ## QR/barcode asset tags and printable labels Every asset can have a scannable label printed for it: right-click an asset for **Print Label**, or right-click a folder for **Print Labels…** (every asset in that folder, recursively). Choose the code format on the print page itself: - **QR code** — encodes an absolute `/scan/` URL, so scanning it with a phone camera opens straight to that asset. - **Barcode (Code128)** — encodes the bare Asset ID, meant for a dedicated USB barcode scanner typing it into whatever's focused (e.g. the app's search box). The print page also supports three label sheet layouts, switchable from a dropdown: - **Avery 5160 / 5260** (1" x 2-5/8", 30/sheet) — standard address labels (5260 is the same grid, just rounded corners), exact published dimensions. - **61526** asset tag labels (3/4" x 2", ~48/sheet) — the grid/margins here are a best-effort layout, not a verified spec sheet, so print one test page on plain paper and check it against a real label before committing a full (often non-refundable) sheet. **Printing a batch without wasting sheet space**: Ctrl/Cmd+click (toggle) or Shift+click (range) multiple folders/assets in the tree, the same way you would in a file manager, then right-click the selection for **Print Labels (N)** — along with **Export CSV (N)**, **Edit Status…**, **Check Out…**, **Duplicate**, **Move to…**, and **Delete**, all bulk versions of the single-item actions. On the print page itself, **Start at #** lets you resume printing partway into an already-used sheet (position 1 = top-left, counting left-to-right, top-to-bottom) instead of starting a fresh one over a few peeled-off labels. ## CSV import / export - **Export**: from the tree's right-click menu, or `/export/assets.csv` (optionally scoped to a folder, with `?recursive=1` to include subfolders). Includes a `Quantity` column and one `cf_` column per distinct custom field in use. - **Folder-scoped import**: right-click a folder → **Import CSV…** imports every row directly into that folder. No `Folder` column needed — that's the whole point of doing it from a specific folder. Never available at the top level. - **Global import**: Settings → Import / Export has the full-featured version — a CSV with a `Folder` column (a `/`-separated path, e.g. `Main Office/Network`) that can optionally auto-create missing folders — plus a separate CSV import for bulk-adding/updating Statuses (`Name`, `Color`). Both matching-by-name/Asset-ID semantics and full column references with examples are documented right on that page. A full backup/restore of everything (folders, assets, types, custom fields, statuses, users) is just `inventree database backup` — it's a consistent snapshot of the whole SQLite database. ## Project layout ``` cmd/inventree/ CLI entrypoint (serve, version, database migrate/backup) internal/ auth/ session management, secure cookies database/ SQLite connection, pragmas, migrations migrations/ embedded .sql migration files models/ shared domain types folders/ nested folder tree assets/ asset CRUD, search, CSV import/export itemtypes/ admin-defined types + custom field definitions users/ accounts statuses/ configurable asset statuses settings/ key/value app settings web/ HTTP router, handlers, template rendering web/ templates/ Go html/template pages and partials (embedded) static/ Bootstrap 5, Bootstrap Icons, app.css, app.js (embedded) deploy/ systemd unit example ``` ## Development ```sh go build ./... go vet ./... go test ./... ``` The SQLite driver is [modernc.org/sqlite](https://pkg.go.dev/modernc.org/sqlite), a pure-Go implementation, so `CGO_ENABLED=0` builds work out of the box and the compiled binary has no C library dependencies. ## Docker ```sh docker compose up --build ``` This builds the image, starts inventree on port 8080, and persists the database in a named volume (`inventree-data`, mounted at `/app/data`). Or directly: ```sh docker build -t inventree . docker run -p 8080:8080 -v inventree-data:/app/data inventree ``` ## systemd See `deploy/inventree.service` for an example unit. Adjust the paths, then: ```sh sudo useradd --system --home /opt/inventree --shell /usr/sbin/nologin inventree sudo mkdir -p /opt/inventree/data sudo cp inventree /opt/inventree/inventree sudo chown -R inventree:inventree /opt/inventree sudo cp deploy/inventree.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now inventree ``` ## Scope inventree is intentionally a focused MVP: folders, assets, custom types, statuses, users, search, and CSV import/export. It does not include ticketing, purchasing, monitoring, RMM, MDM, or accounting features — if you need those, look elsewhere and integrate via CSV.