Zeeshaun 9a7d6544ef
All checks were successful
Deploy Promiscuity Auth API / deploy (push) Successful in 46s
Deploy Promiscuity Character API / deploy (push) Successful in 46s
Deploy Promiscuity Locations API / deploy (push) Successful in 46s
k8s smoke test / test (push) Successful in 7s
Adding inventory microservice
2026-03-15 10:21:49 -05:00

5.0 KiB

InventoryApi document shapes

This service stores one MongoDB document per inventory item record.

Inbound JSON documents

  • GrantInventoryItemRequest (POST /api/inventory/by-owner/{ownerType}/{ownerId}/grant)

    {
      "itemKey": "string",
      "quantity": 1,
      "preferredSlot": 0
    }
    

    preferredSlot is optional. If omitted, the service finds a valid destination slot.

  • MoveInventoryItemRequest (POST /api/inventory/by-owner/{ownerType}/{ownerId}/move)

    {
      "itemId": "uuid-string",
      "toSlot": 1,
      "quantity": 1
    }
    

    quantity is optional. If omitted, move the full stack.

  • TransferInventoryItemRequest (POST /api/inventory/transfer)

    {
      "itemId": "uuid-string",
      "fromOwnerType": "character",
      "fromOwnerId": "string",
      "toOwnerType": "location",
      "toOwnerId": "string",
      "toSlot": 0,
      "quantity": 1
    }
    

    toSlot and quantity are optional. If omitted, the service finds a valid destination and transfers the full stack.

  • ConsumeInventoryItemRequest (POST /api/inventory/items/{itemId}/consume)

    {
      "quantity": 1
    }
    
  • EquipInventoryItemRequest (POST /api/inventory/items/{itemId}/equip)

    {
      "ownerId": "string",
      "equipmentSlot": "weapon"
    }
    

    Only valid for items currently owned by a character inventory.

  • UnequipInventoryItemRequest (POST /api/inventory/items/{itemId}/unequip)

    {
      "ownerId": "string",
      "preferredSlot": 0
    }
    

    Only valid for items currently equipped by a character.

Stored documents (MongoDB)

  • InventoryItem
    {
      "id": "string (UUID)",
      "itemKey": "wood",
      "quantity": 12,
      "ownerType": "character",
      "ownerId": "string (ObjectId or stable external id)",
      "ownerUserId": "string (ObjectId from auth token, null for public world owners)",
      "slot": 0,
      "equippedSlot": null,
      "createdUtc": "string (ISO-8601 datetime)",
      "updatedUtc": "string (ISO-8601 datetime)"
    }
    

Equipped character item example:

{
  "id": "string (UUID)",
  "itemKey": "pistol",
  "quantity": 1,
  "ownerType": "character",
  "ownerId": "string (Character ObjectId)",
  "ownerUserId": "string (ObjectId from auth token)",
  "slot": null,
  "equippedSlot": "weapon",
  "createdUtc": "string (ISO-8601 datetime)",
  "updatedUtc": "string (ISO-8601 datetime)"
}

Location stack example:

{
  "id": "string (UUID)",
  "itemKey": "wood",
  "quantity": 12,
  "ownerType": "location",
  "ownerId": "string (Location ObjectId)",
  "ownerUserId": null,
  "slot": 3,
  "equippedSlot": null,
  "createdUtc": "string (ISO-8601 datetime)",
  "updatedUtc": "string (ISO-8601 datetime)"
}

Outbound JSON documents

  • InventoryItemResponse

    {
      "id": "string (UUID)",
      "itemKey": "wood",
      "quantity": 12,
      "ownerType": "character",
      "ownerId": "string",
      "slot": 0,
      "equippedSlot": null,
      "updatedUtc": "string (ISO-8601 datetime)"
    }
    
  • InventoryOwnerResponse (GET /api/inventory/by-owner/{ownerType}/{ownerId})

    {
      "ownerType": "character",
      "ownerId": "string",
      "items": [
        {
          "id": "string (UUID)",
          "itemKey": "wood",
          "quantity": 12,
          "ownerType": "character",
          "ownerId": "string",
          "slot": 0,
          "equippedSlot": null,
          "updatedUtc": "string (ISO-8601 datetime)"
        }
      ]
    }
    
  • TransferInventoryResponse (POST /api/inventory/transfer)

    {
      "movedItemId": "string (UUID)",
      "fromOwnerType": "character",
      "fromOwnerId": "string",
      "toOwnerType": "location",
      "toOwnerId": "string",
      "fromItems": [],
      "toItems": []
    }
    

Validation rules

  • ownerType must be a supported container type
  • ownerId must map to an existing owning entity where applicable
  • non-SUPER callers may only access owned character items unless explicit gameplay rules allow a world container read/write
  • quantity must be greater than 0
  • non-stackable items must have quantity = 1
  • equipped items must have slot = null
  • unequipped bag items must have equippedSlot = null
  • an item must not have both slot and equippedSlot populated
  • slot occupancy must be unique for (ownerType, ownerId, slot) where slot != null
  • equipment occupancy must be unique for (ownerType, ownerId, equippedSlot) where equippedSlot != null

Recommended indexes

  • unique on id
  • index on (ownerType, ownerId)
  • unique on (ownerType, ownerId, slot) for bag slots
  • unique on (ownerType, ownerId, equippedSlot) for equipped slots
  • index on itemKey

Behavior rules

  • moving a full non-stackable item should update its owner and slot in place
  • moving part of a stack should split the stack and create a new item record with a new UUID for the moved quantity
  • moving into a compatible stack should merge quantities and delete or reduce the source record
  • cross-owner transfer should be transactional when it mutates multiple records
  • auctions should reference itemId values directly instead of copying item state into the auction document