A backend prototype for a distributed inventory management system built with Node.js, Express and SQLite. It demonstrates key distributed systems concepts such as optimistic locking, idempotency, store-level partitioning and batch synchronization.
- Optimistic Locking β Version-based concurrency control to prevent lost updates in concurrent environments.
- Idempotency β All write operations support
Idempotency-Keyheader for safe retries on network failures. - Store-level Partitioning β Each SKU tracks inventory per store independently.
- Batch Synchronization β Bulk push endpoint to reconcile inventory from multiple stores.
- ACID Transactions β SQLite transactions ensure data integrity on all writes.
- Centralized Error Handling β Structured JSON error responses with meaningful codes and timestamps.
| Layer | Technology |
|---|---|
| Runtime | Node.js 18+ |
| Framework | Express.js |
| Database | SQLite via better-sqlite3 |
| Testing | Jest + Supertest |
| Logging | Morgan |
| ID Generation | UUID v4 |
distributed-inventory-system/
βββ src/
β βββ server.js # Main application server & API routes
β βββ error-handler.js # Centralized error handling middleware
βββ tests/
β βββ inventory.test.js # Core API tests
β βββ error-handling.test.js # Error handling tests
βββ data/
β βββ inventory.db # SQLite database (auto-created on first run)
βββ scripts/
β βββ simulate_concurrent_requests.py # Concurrency simulation script
βββ api-design.md
βββ setup-instructions.md
βββ postman-examples.md
βββ package.json
- Node.js 18+ and npm
- Git (optional)
# Clone the repository
git clone <repository-url> distributed-inventory-system
cd distributed-inventory-system
# Install dependencies
npm installnpm start
# Server starts at http://localhost:3000The SQLite database is created automatically at data/inventory.db and seeded with sample data on first run.
# Run all tests
npm test
# Run with coverage report
npm run test:coverage
# Run in watch mode
npm run test:watchhttp://localhost:3000
| Header | Description |
|---|---|
X-Store-Id |
Identifies the store making the request |
Idempotency-Key |
Unique key to ensure operation idempotency |
Content-Type |
application/json (required for POST/PUT) |
Health check.
Response:
{ "status": "ok", "now": "2026-03-02T10:00:00.000Z" }Get aggregated inventory across all stores for a given SKU.
Response:
{
"sku": "sku-123",
"total": 15,
"per_store": [
{ "store_id": "store-1", "quantity": 10, "version": 1, "last_updated": "..." },
{ "store_id": "store-2", "quantity": 5, "version": 1, "last_updated": "..." }
]
}Set the quantity for a SKU in a specific store. Supports idempotency.
Headers: X-Store-Id, Idempotency-Key (optional)
Body:
{ "quantity": 15 }Response:
{ "sku": "sku-123", "store_id": "store-1", "quantity": 15, "version": 2, "last_updated": "..." }Adjust inventory by a delta value using optimistic locking. The client must provide expectedVersion to prevent lost updates.
Headers: X-Store-Id, Idempotency-Key (optional)
Body:
{ "delta": -3, "expectedVersion": 1 }Response:
{ "sku": "sku-123", "store_id": "store-1", "quantity": 7, "version": 2, "last_updated": "..." }Error β Version Mismatch (409):
{ "error": "version_mismatch", "currentVersion": 3 }Error β Insufficient Stock (400):
{ "error": "insufficient_stock" }Batch synchronization β push multiple SKU quantities from a store to the central system. Supports idempotency.
Headers: Idempotency-Key (optional)
Body:
[
{ "sku": "sku-123", "quantity": 20, "store_id": "store-1" },
{ "sku": "sku-456", "quantity": 8, "store_id": "store-1" }
]Response:
{ "changed": [ { "sku": "sku-123", "store_id": "store-1", "quantity": 20, "version": 3, "last_updated": "..." } ] }Critical stock operations prioritize strong consistency. When expectedVersion mismatches (concurrent update detected), the request is rejected with 409 Conflict so the client can re-fetch and retry with the latest version. This prevents overselling.
Each inventory record carries a version field that increments on every write. Clients submit the expectedVersion they last read; if it no longer matches the database, the update is rejected.
Write operations (PUT, POST) accept an Idempotency-Key header. If the same key is seen again, the original response is returned immediately β enabling safe retries after network failures without side effects.
Each (sku, store_id) pair is tracked independently, supporting a distributed model where each physical store manages its own stock and syncs periodically to the central system.
A Python script is provided to simulate concurrent requests and observe optimistic locking in action:
python scripts/simulate_concurrent_requests.py| File | Description |
|---|---|
api-design.md |
API design decisions and endpoint overview |
postman-examples.md |
Ready-to-use Postman request examples |
setup-instructions.md |
Detailed setup and configuration guide |
tech-stack.md |
Technology choices and GenAI integration |
project-plan.md |
Project planning notes |
Desarrollado con cariΓ±o por @JhonSnakee