manicanldes-backend/docs/commerce-api.md

3.9 KiB
Raw Blame History

Phase 1C commerce API

All routes use /api/v1. Protected routes require a bearer session and current permissions. Organization and user scope come from the session. PUT replaces editable input fields. Module schemas define the field contracts.

Routes Permission
GET /products, /products/:id, /catalog-groups catalog.read
POST /products, PUT /products/:id, POST /products/:id/variants, PUT /products/:id/variants/:variantId catalog.manage
POST /catalog-groups, PUT /catalog-groups/:id catalog.manage
PATCH /products/:id/status catalog.publish
GET /storefront/:organizationId/products and /:id Public, throttled
GET/POST /addresses, PUT/DELETE /addresses/:id Authenticated, own addresses
GET /inventory/warehouses, /inventory/stock-items, /inventory/stock-items/:id, /inventory/stock-items/:id/ledger inventory.read
POST /inventory/warehouses, /inventory/stock-items inventory.manage
POST /inventory/adjustments inventory.adjust
POST /inventory/reservations, GET /inventory/reservations/:id, POST /inventory/reservations/:id/release inventory.reserve; reads/releases belong to creator
POST /inventory/reservations/:id/commit inventory.commit, same organization

Products begin as drafts. Publishing requires an active variant; archived products cannot be edited. Groups are categories or collections. Public lists contain summaries; details expose published products and active variants. Price input is a positive decimal string with two fractional digits, stored as exact Decimal(12,2) with explicit currency. Output may omit trailing zeroes. Lists and nested inputs are bounded.

Addresses are private, limited to 20 per user and have one default enforced by a partial unique index. Deleting the default selects a replacement when possible. Private address values are excluded from audits.

Stock quantities are integers. Opening stock is an adjustment. Adjustments require stockItemId, nonzero delta, reason and UUID idempotencyKey. Reservations require stockItemId, positive quantity, UUID idempotencyKey and optional ttlMinutes (160, default 15). Matching retries return the original result; changed input conflicts.

Availability equals on-hand stock minus unexpired active reservations. Stock row locks serialize changes. Expired holds stop consuming availability and cannot be committed. Release and commit are idempotent. Commit decrements stock and appends one ledger entry in the same transaction. A database trigger rejects ledger updates/deletes.

Existing system roles receive permissions through migration; custom roles require explicit grants. This phase covers finished goods. Checkout/orders and pricing snapshots follow in Phase 1D; procurement and production in Phase 2.