API (api-v2)

Inventory & locations

Stock is held per variant per location, and every change is an immutable adjustment with a reason. Locations carry shelves, tills and drawers. Places proxies address lookup, and Jarde applies spreadsheet stock counts.


Inventory

Tables:

  • inventory_item: cost, tracked, min_stock (reorder point)
  • inventory_level: per location, with a free-text shelf
  • inventory_adjustment: the immutable movement ledger
RouteGuard
/merchant/inventory/v1/list, adjust, movements, transfer, transfer/bulkperm inventory.write (also applied to reads, because there's no inventory.read code)
  • adjust takes the absolute on-hand quantity and records the delta.
  • transfer writes a transfer_out / transfer_in pair sharing a transferGroupId.
  • transfer/bulk (bulkTransferStock, PR #84) moves many lines in one transaction: every line moves or none does. It returns a result per line.
  • inventory-screen is an orchestrator that composes the list view across modules.

Adjustment reasons

order_placed, pos_sale, refund_restock, return_restock, order_cancelled, delivery_failed, manual, stock_count, transfer_out, transfer_in

Gaps

  • Staff location scope isn't enforced on writes here (documented in the router).

Locations & shelves

Tables: location, location_shelf

RouteGuard
/merchant/locations/v1/get-shop-locationsperm products.view
get-locationsoScoped
createwide locations.write
update, deleteat locations.write
get-shelvesat products.view
add-shelf, remove-shelfapp shelves + at locations.write
  • Coordinates are validated. There's no plan cap on locations.
  • Without the shelves app, the dashboard lists shelf labels found on inventory_level.shelf. Declared shelves are still marked In progress (.scratch/location-shelves/spec.md).
  • A till is a (shop, location) pair. There's no device or terminal entity.

Places

RouteGuard
/merchant/places/v1/autocomplete, get-place, geocode, reverse-geocodeauthenticated
  • A proxy over Google Places (New), Geocoding and Time Zone, keyed by GOOGLE_MAPS_API_KEY.
  • Every lookup fails soft, returning empty results instead of errors.
  • Results are biased toward Beirut (PLACES_BIAS_CENTER, PLACES_BIAS_RADIUS_M).
  • The dashboard renders maps with MapLibre and keyless OpenFreeMap tiles (dashboard ADR 0003).

Jarde (stock count app)

RouteGuard
/merchant/jarde/v1/plan, applyapp jarde + inventory.write
  • Input: rows of barcode, quantity, and optionally branch name. The dashboard parses CSV or XLSX, and accepts English or Arabic headers (barcode, ISBN or EAN).
  • plan matches rows and returns a preview: counts, net change, shortages, and per-row problems. The pure planner is jarde.plan.ts.
  • apply writes stock_count adjustments. Counted quantities replace on-hand stock. Rows absent from the sheet are untouched.
  • Rows at branches the caller can't write to are refused one row at a time.
Previous
Orders, refunds & returns