Back to Open Inventory

Documentation

From clone tofirst record.

A practical path through local Docker deployment, secure configuration, the REST API, and the operational details that keep your inventory durable.

Start here

What you are deploying

Open Inventory is a Next.js application backed by PostgreSQL. The checked-in Compose stack starts the database, runs every bundled migration, then starts the application with persistent volumes for database data and local uploads.

Application

A standalone Next.js production image.

Database

PostgreSQL 16 with migration gating.

Storage

Persistent local uploads or Openinary.

Authentication

Local passwords, Auth0, or standards-based OIDC.

01 · Installation

Choose the easiest path for your server

Run the guided Docker installer on any host with Git, Docker Compose v2, OpenSSL, and curl, or import the catalog-ready definitions for Dokploy and Coolify. All three paths use the same production image, migrations, health check, and persistent storage model.

Docker Compose

Clone the repository and let the installer create secure settings and start the complete stack.

Quick start

Dokploy template

Import the platform-native definition now; it is ready for one-click catalog inclusion.

Open Dokploy files

Coolify template

Import the matching service definition now; it is ready for one-click catalog inclusion.

Open Coolify files

Docker quick start

The installer creates a private .env, generates the required secrets and a bootstrap administrator, starts PostgreSQL and Open Inventory, and waits for the health check. You do not need Node.js or a manually prepared password hash for this path.

three commands
git clone https://github.com/Utzel-Butzel/inventory.git
cd inventory
./scripts/install.sh

First login

When installation finishes, the terminal prints the admin email (by default [email protected]) and an automatically generated bootstrap password. Sign in at http://localhost:3000, then change the password under Settings → Users. The production start converts the bootstrap value to bcrypt before the server starts and removes its plaintext value from the running process; the database stores only the hash after the first successful login.

Dokploy and Coolify

Pick your platform, open its deploy directory, and import the included template or Compose definition. It configures PostgreSQL, persistent uploads, port 3000, and/api/health. The platform generates the bootstrap password as a secret; find it in Dokploy's or Coolify's environment UI for the initial login. Change the password in Settings → Users; the bootstrap credential cannot replace an existing account.

02 · Configuration

Keep the core local. Add only what you need.

Database and local files can stay on your infrastructure. Maps, hosted storage, identity providers, and AI services are explicit integrations you can configure or leave disabled.

Accounts and roles

The guided deployment paths generate the first bootstrap login automatically. Browser sign-in can use local passwords, Auth0, and one generic OpenID Connect provider; roles and memberships stay in Open Inventory.

File storage

Use the persistent local upload volume by default, or point Open Inventory at an Openinary service.

AI assistance

OpenAI-compatible analysis and OpenAI or Google image editing are optional. Nothing is sent to an AI provider until you configure and use it.

Maps and location

Street and satellite defaults require external tile services. Compatible tile URLs can be replaced with your own infrastructure.

Browse the complete environment reference

03 · Authentication

Choose the sign-in methods for your deployment.

Auth.js powers browser authentication. The enabled methods are selected for the whole container through environment variables, while organizations, memberships, roles, and permissions remain in the Open Inventory database.

Default

Local password

Works immediately and also powers password-to-token login in the native iOS app.

Built in

Auth0

Add one Auth0 application and expose it beside or instead of local password login.

Generic

OpenID Connect

Connect one standards-based issuer such as Supabase, Keycloak, or Zitadel.

Identity is external; access stays local.

Before an Auth0 or OIDC user can sign in, create an active Open Inventory user with the same email address. The provider must return email_verified: true. Open Inventory then resolves the current organization membership, role, and permissions from its own database on every request.

Required application settings

Use the public HTTPS origin that users and the identity provider can reach. Generate a unique secret for every deployment.

.env · required
AUTH_URL=https://inventory.example.com
AUTH_SECRET=replace-with-a-long-random-secret
AUTH_TRUST_HOST=true

Auth0

Register https://inventory.example.com/api/auth/callback/auth0 as an allowed callback URL, then add the application credentials.

.env · Auth0
AUTH0_CLIENT_ID=your-client-id
AUTH0_CLIENT_SECRET=your-client-secret
AUTH0_DOMAIN=your-tenant.eu.auth0.com

Supabase or another OIDC issuer

The provider ID becomes the final callback path. For this example, register https://inventory.example.com/api/auth/callback/supabase.

.env · OpenID Connect
AUTH_OIDC_PROVIDER_ID=supabase
AUTH_OIDC_PROVIDER_NAME=Supabase
AUTH_OIDC_ISSUER=https://your-project.supabase.co/auth/v1
AUTH_OIDC_CLIENT_ID=your-client-id
AUTH_OIDC_CLIENT_SECRET=your-client-secret
AUTH_OIDC_SCOPES=openid email profile

Roll out without locking yourself out

  1. Keep AUTH_PASSWORD_ENABLED=true.
  2. Configure the provider and create a matching local user.
  3. Redeploy and test the external login in a private browser window.
  4. Only then disable passwords if the deployment must be external-only.

The current iOS client uses the password-to-token endpoint and cannot sign in to an external-only deployment.

Open the complete authentication provider guide

04 · Integration

A scoped API, described in the repository.

Administrators can issue expiring, revocable bearer tokens. The public OpenAPI 3.1 files document resource, stock, scan, purchase-order, authentication, and statistics endpoints.

JSON REST API

Stable versioned routes under /api/v1.

Scoped tokens

Read, write, and AI permissions.

OpenAPI 3.1

YAML and JSON descriptions included.

Using the app · Variants & assembly

Track finished stock per variant

Each variant is a full inventory record with its own resource ID, SKU, barcode, and stock. Variants belong to a product family with a primary item. OpenPaper L White and Black therefore remain independently bookable after assembly.

  1. 1. Prepare variants and recipes

    Create variants on the primary item, connect existing records, or generate configurations from option groups. Variants inherit the primary bill of materials. Define differing components on each variant, such as a white frame replacing the black frame.

  2. 2. Build the output variant

    On the primary item’s build form, choose the finished item / output variant. The form loads its bill of materials and stock. Building one white device consumes its PCB and white frame and credits only the white variant’s finished stock. Component consumption and finished output either commit together or roll back completely.

  3. 3. Issue the finished item

    Open the sold variant’s stock and book an issue there. Only that variant loses stock, and the family total decreases accordingly. The PCB and frame are not consumed a second time.

Variant balances, unassigned stock, and the family total

The primary item lists variants with their individual balances. Its stock view also shows unassigned primary stock and the family total. Example after building one white variant:

StockQuantity
OpenPaper L White1
OpenPaper L Black0
Unassigned on the primary item2
Total stock3

Total stock = sum of all variant balances + unassigned primary stock

GET /api/v1/resources/{primaryId}/stock returns family.variants with each variant’s quantity, plus family.summary containing totalQuantity, variantQuantity, and primaryQuantity. resource.quantity remains the primary item’s own unassigned balance. Do not add it to the family total again. All values in this response use the same database snapshot. Reading the family requires stock.read access to every member.

Build through the API

Replace placeholders with your resource UUIDs and API token. Use a new Idempotency-Key for each new operation; reuse the same key when retrying the identical request. Builds require this header.

POST /api/v1/resources/{primaryId}/stock/builds
Authorization: Bearer <API_TOKEN>
Content-Type: application/json
Idempotency-Key: <unique-build-key>

{
  "quantity": 1,
  "outputResourceId": "<whiteVariantId>"
}

outputResourceId must identify the requested resource or one of its direct variants. Alternatively, call POST /api/v1/resources/{whiteVariantId}/stock/builds directly with quantity. To deliberately produce unassigned stock, explicitly set outputResourceId to the primary item’s ID.

When calling through the primary item, you may omit outputResourceId if componentResourceSelections maps stable BOM slot IDs to selected component IDs and the complete resulting recipe matches exactly one output variant. Each selected component must be the slot’s component or one of its direct variants. No match or multiple matches return HTTP 422; choose the output explicitly in that case.

Issue through the API

POST /api/v1/resources/{whiteVariantId}/stock/movements
Authorization: Bearer <API_TOKEN>
Content-Type: application/json
Idempotency-Key: <unique-issue-key>

{
  "delta": -1,
  "type": "issue",
  "note": "Order #1234"
}

The resource path contains the variant’s ID. The body uses delta and type; it does not use an additional variant_id field or a separate legacy variant endpoint. A negative delta reduces stock.

Negative stock follows organization policy

With “Allow negative stock” off (allowNegativeStock = false), an issue below zero returns HTTP 409. With it on, bulk stock may fall below zero, and the family view includes those negative balances. Serialized stock still requires actual available units. Receipts can recover an existing negative balance even when protection is enabled.

Open the full API reference

05 · Operations

Make durability part of the deployment.

Open Inventory keeps database records and stored media as one logical dataset. Back them up together, test recovery, and use the built-in health endpoint for deployment checks.

Deployment checklist

The boring things that keep the useful things safe.

  • Health check returns 200 at /api/health
  • Database and upload volumes are persistent
  • PostgreSQL and uploads are backed up together
  • Login, upload, and token flows are smoke-tested
  • Remote AUTH_URL is the exact HTTPS origin
  • AI and storage credentials are set only when used

Need the complete reference?

The repository README covers Docker, Dokploy, Coolify, authentication, stock behavior, native iOS, and every environment variable.

Open README