Skip to content

Repository files navigation

Stockroom Ledger

CI Release License: MIT

A full-stack inventory operations console for receiving, dispatching, transferring, and reconciling stock across locations without losing the audit trail.

Stockroom Ledger inventory operations console

Live demo

Open Stockroom Ledger — a public sandbox with seeded inventory data. Its temporary database can reset when the Vercel container scales down; the Docker deployment below uses a persistent volume.

Why this project exists

Inventory demos are often CRUD tables with no meaningful consistency rules. Stockroom Ledger focuses on the failure cases that matter when quantities represent real goods:

  • atomic multi-location transfers—both balances change or neither does;
  • idempotency keys so retried requests do not duplicate a movement;
  • optimistic version checks that reject writes from stale browser state;
  • audited cycle counts that preserve expected quantity, counted quantity, and signed variance;
  • non-negative stock constraints and bounded request validation;
  • an append-only movement ledger with actor, reason, route, and timestamp;
  • integer currency and quantity storage to avoid rounding ambiguity;
  • seeded data so the workflow can be evaluated immediately.

The interface makes these guarantees visible in the transaction panel and shows each location's current revision beside its balance.

Run with Docker

docker compose up --build -d
curl -f http://127.0.0.1:8000/healthz

Open http://127.0.0.1:8000. The SQLite database is stored in the stockroom-data volume.

The container runs as UID 1001 with a read-only root filesystem, dropped Linux capabilities, no-new-privileges, a health check, and explicit CPU, memory, and process limits.

API

Interactive OpenAPI documentation is available at /docs.

Method Route Purpose
GET /api/dashboard Read metrics, balances, locations, movements, and cycle counts
POST /api/movements Commit a receipt, dispatch, or transfer
POST /api/cycle-counts Reconcile a physical count against a versioned balance
GET /healthz Container and process health probe

Every inventory mutation requires an Idempotency-Key header. A repeated key returns the original result with replayed: true and does not change inventory twice.

curl -X POST http://127.0.0.1:8000/api/movements \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: receiving-note-2048' \
  -d '{
    "kind": "transfer",
    "productId": "prd-lamp",
    "fromLocationId": "loc-north",
    "toLocationId": "loc-retail",
    "quantity": 5,
    "reason": "Rebalance retail display stock",
    "actor": "Hassan Ak",
    "expectedSourceVersion": 1,
    "expectedDestinationVersion": 1
  }'

Architecture

The repository keeps UI, HTTP, and persistence concerns separate:

React + TypeScript
        │ same-origin JSON
        ▼
FastAPI routes + Pydantic contracts
        │
        ▼
transaction service ── idempotency / version / stock / count checks
        │
        ▼
SQLite WAL ── product / location / balance / movement / cycle count

FastAPI serves the production frontend from the same origin, so the deployed application needs no permissive CORS policy. SQLite writes use BEGIN IMMEDIATE to serialize inventory mutations before validation and commit.

Development

Requirements: Python 3.12+, Node.js 24+, and pnpm 11+.

# API
cd backend
python -m venv .venv
.venv/Scripts/python -m pip install -e ".[dev]"  # Windows
.venv/Scripts/uvicorn stockroom.main:app --reload

# UI, in another terminal
cd frontend
pnpm install
pnpm dev

Run the quality gates:

cd backend && ruff check src tests && ruff format --check src tests && pytest
cd frontend && pnpm lint && pnpm test && pnpm build
docker build -t stockroom-ledger:test .

Backend tests cover the seeded dashboard, atomic transfers, idempotent retries, cycle-count reconciliation, stale-count rollback, insufficient stock, validation, and security headers. Frontend tests cover rendering plus complete versioned movement and count requests.

Operations and rollback

Back up the stockroom-data volume before upgrading storage code. Releases are immutable tags, and the Compose file pins the application version.

To roll back, check out the previous release, rebuild, and verify the health endpoint before resuming writes:

git checkout v1.0.0
docker compose up --build -d --force-recreate
curl -f http://127.0.0.1:8000/healthz

License

MIT © Hassan Ak

About

Transactional inventory operations with audited cycle counts, idempotent writes, and optimistic concurrency.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages