Files
vibetree/README.md
T
Owen fb85c9edbb Add asset checkout, quantity/uniqueness, contacts, and QR labels
Checkout:
- assets.AssignUser + POST /app/assets/{id}/checkout assign/unassign an
  asset's user independent of the full edit form. New shared
  #checkoutModal, wired from a "Check Out..." context-menu action, backed
  by GET /app/assets/{id} and GET /app/users/options JSON endpoints.

Quantity / uniqueness:
- Item types gain an IsUnique flag (checked by default, matching prior
  behavior). Assets gain a Quantity column, fixed at 1 for unique types
  and adjustable via +/- steppers (POST /app/assets/{id}/quantity) for
  non-unique ones. Flipping a type back to unique clamps existing assets'
  quantity back to 1. CSV import/export gained a Quantity column.
  Migration 0003_quantity.sql.

Contacts:
- New models.RoleContact: an assignable person who cannot sign in
  (User.CanLogin). Migration 0004_contacts.sql rebuilds the users table
  (SQLite can't alter a CHECK constraint in place) to allow the role.
  Users form/list updated; contact creation auto-generates an unusable
  password since the login path is blocked by role regardless.

QR asset tags and printable labels:
- Each asset's QR code (via github.com/skip2/go-qrcode, pure Go) encodes
  an absolute /scan/<tag> URL; GET /scan/{tag} resolves it and redirects
  into /inventory?asset=<id>, which app.js picks up on load to
  auto-select that asset - works from a phone camera or a USB
  scanner-as-keyboard-wedge pointed at the address bar.
- GET /labels renders a print-ready sheet (right-click an asset for one
  label, a folder for every asset in it) with a template switcher between
  Avery 5160 (verified dimensions) and 61526 asset tag labels (best-effort
  layout, flagged as such on the page).

Also refreshed README to reflect the right-click-first tree UX and all of
the above.
2026-08-17 16:28:14 -05:00

219 lines
9.0 KiB
Markdown

# 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 asset tags and printable labels
Every asset can have a QR-coded 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). The QR code encodes an absolute
`/scan/<Asset ID>` URL, so scanning it with a phone camera — or a USB
barcode/QR scanner focused on the browser's address bar — opens straight to
that asset.
The print page supports two label sheet layouts, switchable from a dropdown
on the page itself:
- **Avery 5160** (1" x 2-5/8", 30/sheet) — standard address labels, 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.
## 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_<field_key>` 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.