# InventoryApi

## Purpose
Owns item-instance state.

This service should answer:
- what item records currently belong to a character, location, or other container owner
- where each item currently is
- whether an item move, split, merge, equip, or consume action is valid
- which specific item instance is being traded, auctioned, or transferred

This service should not own:
- auth/token issuance
- character identity creation
- location generation
- auction bidding logic

## Ownership model
- every inventory record has an `ownerType` and `ownerId`
- `USER` can read and mutate items owned by their own characters
- `USER` can read and mutate location/container items only when gameplay rules allow it
- `SUPER` can read and mutate any inventory item
- access should be resolved through the current owner, not from the item id alone

## Initial design
Use one MongoDB document per inventory item record.

Practical interpretation:
- non-stackable items: one document per item instance
- stackable items: one document per stack

Reasons:
- every item or stack gets a stable UUID, which is useful for auctions, trade, mail, and auditing
- ownership transfer is explicit and cheap: update `ownerType`, `ownerId`, and slot fields
- future item metadata like durability, rarity rolls, or provenance can live on the item document
- auction listings can point to specific item ids instead of vague stack descriptions

Tradeoffs:
- inventory reads are queries over many documents instead of one aggregate read
- stack merging and slot enforcement need careful indexes and mutation logic
- transfers should use transactions when they touch multiple item documents

## Suggested endpoints
- `GET /api/inventory/by-owner/{ownerType}/{ownerId}`
  Return all item records currently owned by that container owner.
- `POST /api/inventory/by-owner/{ownerType}/{ownerId}/grant`
  Create a new item record or add quantity into an existing compatible stack.
- `POST /api/inventory/by-owner/{ownerType}/{ownerId}/move`
  Move an item or stack within the same owner inventory.
- `POST /api/inventory/transfer`
  Move quantity from one owner inventory to another.
- `POST /api/inventory/items/{itemId}/consume`
  Consume quantity from a specific item record.
- `POST /api/inventory/items/{itemId}/equip`
  Equip a specific item into a character equipment slot.
- `POST /api/inventory/items/{itemId}/unequip`
  Return an equipped item to a character inventory slot.

Notes:
- `equip` and `unequip` only make sense for character-owned items
- `transfer` is the core world interaction primitive for looting, dropping, trading, chest interaction, and auction handoff
- a future AuctionApi can reserve or re-own specific item ids without redesigning InventoryApi

## Item identity
Every inventory record should have a stable UUID string such as:
- `a8d4218b-5e20-4e47-8b5f-0f0f0b9d7e10`

Each record also carries an `itemKey` such as:
- `wood`
- `stone`
- `pistol`
- `small_health_potion`

Recommended distinction:
- `id`: unique item-record identifier used for ownership changes, auctions, and references
- `itemKey`: item definition identifier used to decide stackability and gameplay behavior

## Recommended stored shape
Each item document should include:
- `id`
- `itemKey`
- `quantity`
- `ownerType`
- `ownerId`
- `slot`
- `equippedSlot`
- `ownerUserId` when applicable
- `createdUtc`
- `updatedUtc`

Optional future fields:
- `durability`
- `rarity`
- `instanceData`
- `listingId`
- `reservedUntilUtc`

## MVP rules
- an item record must belong to exactly one owner at a time
- stackable items may share `itemKey` but should still be represented by one stack record per occupied slot
- non-stackable items must always have `quantity = 1`
- equipped items should set `equippedSlot` and clear `slot`
- unequipped bag items should set `slot` and clear `equippedSlot`
- slot occupancy must be unique per `(ownerType, ownerId, slot)`
- all mutating endpoints should be idempotent where practical

## Definition source
Item behavior is fully data-driven through the `ItemDefinitions` collection inside `InventoryApi`.

That means:
- no hardcoded stack-size rules
- no automatic item-definition seeding
- item instances can only be created for `itemKey` values that already exist in `ItemDefinitions`

## Client shape
The Godot client should fetch all items for the currently relevant owner and group them into a bag view locally.

Good pattern:
- login/select character
- `GET /api/inventory/by-owner/character/{characterId}`
- when opening a stash or world container: `GET /api/inventory/by-owner/location/{locationId}`
- cache the returned item records locally
- call transfer/equip/consume endpoints using specific `itemId` values
- replace local state with the server response after each mutation
