Skip to main content
Glama
hleserg

beta-inventory

by hleserg
README.md
# beta-inventory

A tiny self-hosted inventory for boxes of electronic parts.

Stick an NFC tag (plus a QR code) on a box. Tap it with your phone and the box
page opens on your LAN: what's inside, how many, a photo, a plain-language
spec sheet with pinout, and attached datasheets. Take a part for a project and
the history remembers where it went.

AI agents (Claude Code, Codex, any MCP client) can check stock, run an
inventory and write new part cards for you.

> **Status: v0 prototype.** Boxes, labels, cards, stock moves, search by
> words and by meaning, and projects work. The UI is Russian for now. Agents
> read and write over MCP; GitHub sync is next.

## Install

On a Linux box in your home network, with Docker:

```sh
git clone https://github.com/hleserg/beta-inventory && cd beta-inventory && ./install.sh
```

It asks whether labels carry an IP or a name (like `inv.lan`) and which port,
writes `.env` and starts the site. Both ways work; a name survives the server
changing its IP. Update: `git pull && ./install.sh`.

`install.sh` pulls the ready image, built for amd64 and arm64 (Raspberry Pi)
from every commit to `main`: `ghcr.io/hleserg/beta-inventory:latest` (or
`:sha-<commit>`). With no image to pull, it builds one on the box. To run your
own changes: `docker compose up -d --build`.

### A Windows laptop, no Docker

1. Install Python 3.12 or newer from [python.org](https://www.python.org/downloads/).
2. Download the code: **Code → Download ZIP** on this page, unpack it.
3. Double-click `start.bat`.

The first run takes a few minutes: it installs the packages into `.venv` and
writes `.env` with the laptop's address. When Windows asks whether Python may
use the network, allow private networks; if your Wi-Fi is set to Public, phones
won't reach the site (Settings → Network → Wi-Fi → Private).

- The site works while the window is open and the laptop is awake: on power,
  sleep Never and closing the lid Does nothing. To start with Windows, put a
  shortcut to `start.bat` into `shell:startup`.
- Labels carry the laptop's address, so reserve its IP in the router
  (docs/setup.md).
- Update: unpack the new ZIP over the old folder (`data` and `.env` stay), run
  `start.bat`.
- `TZ` in `.env` is skipped here: the history uses the laptop's time zone.

**[docs/setup.md](docs/setup.md)**: name or IP, a DNS record in the router,
the Android phone (app + writing NFC tags), iPhone, labels.

Every setting is in `.env`, described in `.env.example`; the code only holds
defaults. Most can also be changed on the site under «Настройки» (`/settings`),
which wins over `.env` until reset there. Data (SQLite, photos, files, the search model) lives in `./data`. On
first start the search model (~240 MB) downloads there; until it is ready,
search works by words only.

## Profiles: what a card looks like

Card fields are not in the code. They come from a YAML profile:
[`profiles/default.yaml`](profiles/default.yaml) is set up for electronics.
To use your own, copy it to `data/profile.yaml` (or set `PROFILE`) and edit.

Items have a two-level type: a category (Electronics) and a type inside it
(MCU module, resistor, connector…). A card gets the common fields, then the
category's, then the type's; a deeper level can override a field, e.g. a
resistor makes the photo optional and adds a required value, while only
modules require a pinout. Each field can be required and can carry a search
weight.

## What works

- **Boxes** with printable labels (QR + short ID), one at a time for a label
  printer or a batch on one sheet at real size; each label's NFC link is
  written from the phone or copied. Boxes nest and stand in places. An empty
  box asks what goes in.
- **Items** with photo, markdown description, files and per-type fields.
  Quantity lives on the box + item pair.
- **Take / return / restock / recount / empty box** — every change is a
  movement with author and project. One-of-a-kind things (tools, anything
  with a tag) go without a count: scan its tag to take it, scan a box to put
  it back.
- **NFC readers** at the shelves (`/readers`): a reader sends what it read,
  `POST /api/tap {"reader": "<its id>", "code": "<tag URL>"}`. A box's tag
  makes it the reader's current box and stands it where the reader is; a
  thing's tag then puts the thing in that box. A new reader waits on the page
  until you accept it; a portable one forgets its box after
  `READER_FORGET_MIN` minutes. The answer is 200 done, 403 not accepted yet,
  404 not a tag of ours, 409 touch a box first.
- **Search** by name, other names, description and typed fields, ranked by
  relevance; box IDs and places too. Below the word matches, a small local
  model adds items close in meaning, so "step-down" finds a buck converter.
- **Backup** in one tap (bottom of «Корзина», or `GET /backup`): a zip of the
  database and the uploads. To restore, stop the container, unzip into the
  data folder, start.
- **Projects** with a git link, to charge takes against, and what each needs:
  what is short is ordered line by line or all at once, and waits «in transit».
  With `GITHUB_OWNER` set, new repos of that account wait in an inbox until
  you take or skip them.
- **MCP for agents** at `http://<host>/mcp` (streamable HTTP, same port and
  data as the site): `search`, `get_item`, `get_box`, `card_template`,
  `list_projects`; `create_item`, `update_item` (photos and files by URL, the
  server downloads them), `change_stock` (history names the agent as author),
  `accept_project` / `skip_project` for the GitHub inbox, `project_needs` /
  `set_project_need` for what a project needs.
  Tick «Передать агенту» on a card and it shows up in `agent_queue`, together
  with the skill that says how to fill it in; `update_item` takes it off.
  Each field's `hint` in the profile tells agents what goes in it, so any MCP
  client writes a full card. Claude Code and Codex also get the skills:
  `ln -s "$PWD/skills/inventory-new-card" "$PWD/skills/inventory-enrich-card" ~/.agents/skills/`
  (Claude Code: `~/.claude/skills/`).

## Planned

- Markdown editor with toolbar, English UI.

## Non-goals

- No login, no HTTPS, no multi-user. It is meant for a home LAN. If you expose
  it, put it behind a reverse proxy with auth.
- Not an ERP: no suppliers, prices or purchase orders. A project lists what it
  needs and orders what is short «in transit», nothing more.

## License

GPL-3.0 — see [LICENSE](LICENSE).