# 機能設計書 48-在庫アイテム管理

## 概要

本ドキュメントは、Medusaコマースプラットフォームにおける在庫アイテム管理機能の設計を記述する。在庫アイテム（InventoryItem）は、商品バリアントと在庫を紐付けるためのエンティティであり、SKU、原産国、HSコード、寸法・重量などの物理的属性を管理する。複数のロケーションにまたがる在庫管理の基盤となる。

### 本機能の処理概要

**業務上の目的・背景**：ECサイトにおいて、商品の在庫を複数の倉庫・ロケーションで管理する必要がある。在庫アイテム管理は、商品バリアントから独立して在庫を管理することで、同一商品を複数ロケーションで在庫追跡し、物理的な商品属性（重量、寸法、HSコードなど）を一元管理するための基盤を提供する。

**機能の利用シーン**：
- 新規商品バリアントに対する在庫アイテムの作成
- 在庫アイテムの物理属性（重量、寸法など）の更新
- 在庫アイテムのSKU管理
- 在庫アイテムの検索・一覧表示
- 在庫アイテムの削除（在庫レベル・予約も同時削除）

**主要な処理内容**：
1. 在庫アイテムの作成（createInventoryItems）
2. 在庫アイテムの更新（updateInventoryItems）
3. 在庫アイテムの削除（deleteInventoryItems）
4. 在庫アイテムの取得・一覧表示（listInventoryItems, retrieveInventoryItem）
5. 利用可能在庫数の取得（retrieveAvailableQuantity）
6. 在庫確認（confirmInventory）

**関連システム・外部連携**：
- 在庫レベル管理（ロケーション別在庫数量）
- 在庫予約管理（注文時の在庫引当）
- 商品バリアント（商品との紐付け）

**権限による制御**：管理画面からの操作は管理者権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 13 | 商品在庫編集画面 | 主機能 | 商品在庫の管理 |
| 18 | 商品バリアント作成画面 | 補助機能 | バリアント在庫の設定 |
| 23 | バリアント詳細画面 | 補助機能 | バリアント在庫情報の表示 |
| 25 | バリアント在庫管理画面 | 主機能 | バリアントの在庫アイテム管理 |
| 91 | 在庫一覧画面 | 主機能 | 在庫アイテム一覧の取得・表示 |
| 92 | 在庫作成画面 | 主機能 | 新規在庫アイテムの作成 |
| 93 | 在庫詳細画面 | 主機能 | 在庫アイテム詳細の表示 |
| 94 | 在庫編集画面 | 主機能 | 在庫アイテム情報の編集 |
| 95 | 在庫属性編集画面 | 主機能 | 在庫アイテム属性の編集 |
| 99 | 在庫メタデータ編集画面 | 主機能 | 在庫メタデータの編集 |

## 機能種別

CRUD操作、在庫管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| sku | string | No | 在庫管理コード（Stock Keeping Unit） | ユニーク制約（deleted_at IS NULL） |
| title | string | No | 在庫アイテムのタイトル | searchable |
| description | string | No | 説明 | searchable |
| origin_country | string | No | 原産国コード | - |
| hs_code | string | No | HSコード（関税分類コード） | searchable |
| mid_code | string | No | MIDコード（製造者識別コード） | searchable |
| material | string | No | 素材 | - |
| weight | number | No | 重量 | - |
| length | number | No | 長さ | - |
| height | number | No | 高さ | - |
| width | number | No | 幅 | - |
| requires_shipping | boolean | No | 配送必要フラグ | デフォルト: true |
| thumbnail | string | No | サムネイル画像URL | - |
| metadata | object | No | カスタムメタデータ | JSON形式 |

### 入力データソース

- 管理画面からのフォーム入力
- Admin API経由
- 商品バリアント作成時の自動作成

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | string | 在庫アイテムID（iitem_xxx形式） |
| sku | string | 在庫管理コード |
| title | string | タイトル |
| description | string | 説明 |
| origin_country | string | 原産国コード |
| hs_code | string | HSコード |
| mid_code | string | MIDコード |
| material | string | 素材 |
| weight | number | 重量 |
| length | number | 長さ |
| height | number | 高さ |
| width | number | 幅 |
| requires_shipping | boolean | 配送必要フラグ |
| thumbnail | string | サムネイル画像URL |
| metadata | object | メタデータ |
| reserved_quantity | number | 予約済み数量（計算フィールド） |
| stocked_quantity | number | 在庫数量（計算フィールド） |
| created_at | datetime | 作成日時 |
| updated_at | datetime | 更新日時 |

### 出力先

- API Response（JSON形式）
- DBテーブル：inventory_item

## 処理フロー

### 処理シーケンス

```
1. 入力データの受信
   └─ 在庫アイテム情報を含む

2. 入力データのサニタイズ
   └─ sanitizeInventoryItemInput()でlocation_levelsを除去

3. 在庫アイテムの作成/更新
   └─ inventoryItemService_.create/update()

4. シリアライズとレスポンス返却
   └─ baseRepository_.serialize()
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[入力データ受信]
    B --> C[sanitizeInventoryItemInput]
    C --> D{操作種別}
    D -->|作成| E[inventoryItemService_.create]
    D -->|更新| F[inventoryItemService_.update]
    D -->|削除| G[在庫アイテム削除]
    E --> H[シリアライズ]
    F --> H
    G --> I[カスケード削除]
    I --> J[location_levels削除]
    I --> K[reservation_items削除]
    H --> L[イベント発行]
    J --> L
    K --> L
    L --> M[レスポンス返却]
    M --> N[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-48-01 | SKUユニーク制約 | SKUは削除されていないレコード間でユニーク | 作成・更新時 |
| BR-48-02 | カスケード削除 | 在庫アイテム削除時に関連するlocation_levelsとreservation_itemsも削除 | 削除時 |
| BR-48-03 | 配送必要フラグデフォルト | requires_shippingのデフォルト値はtrue | 作成時 |
| BR-48-04 | 計算フィールド | reserved_quantityとstocked_quantityは関連在庫レベルから計算 | 取得時 |

### 計算ロジック

- **利用可能数量**: `retrieveAvailableQuantity(inventoryItemId, locationIds)` - 在庫レベルサービスで計算
- **在庫確認**: `confirmInventory(inventoryItemId, locationIds, quantity)` - 利用可能数量 >= 要求数量

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| createInventoryItems | inventory_item | INSERT | 新規在庫アイテム作成 |
| updateInventoryItems | inventory_item | UPDATE | 在庫アイテム更新 |
| deleteInventoryItems | inventory_item | DELETE | 在庫アイテム削除 |
| deleteInventoryItems | inventory_level | DELETE | カスケード削除 |
| deleteInventoryItems | reservation_item | DELETE | カスケード削除 |

### テーブル別操作詳細

#### inventory_item

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id | 自動生成（iitem_xxx形式） | プライマリキー |
| INSERT | sku | 入力値 | ユニークインデックス（deleted_at IS NULLの場合） |
| INSERT | origin_country | 入力値 | nullable |
| INSERT | hs_code | 入力値 | nullable, searchable |
| INSERT | mid_code | 入力値 | nullable, searchable |
| INSERT | material | 入力値 | nullable |
| INSERT | weight | 入力値 | nullable |
| INSERT | length | 入力値 | nullable |
| INSERT | height | 入力値 | nullable |
| INSERT | width | 入力値 | nullable |
| INSERT | requires_shipping | 入力値 | デフォルト: true |
| INSERT | description | 入力値 | nullable, searchable |
| INSERT | title | 入力値 | nullable, searchable |
| INSERT | thumbnail | 入力値 | nullable |
| INSERT | metadata | 入力値 | nullable, JSON |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| NOT_FOUND | MedusaError | 指定した在庫アイテムが存在しない | 正しいIDを指定 |
| DUPLICATE_ERROR | DBエラー | SKUが重複している | 別のSKUを使用 |

### リトライ仕様

トランザクションレベルでのリトライ対応。

## トランザクション仕様

- 作成・更新・削除は@InjectTransactionManager()デコレータによりトランザクション管理
- カスケード削除もトランザクション内で実行

## パフォーマンス要件

- SKUにユニークインデックス設定済み（deleted_at IS NULL条件）
- sku, hs_code, mid_code, description, titleはsearchable属性で検索最適化

## セキュリティ考慮事項

- 管理者認証必須
- メタデータに機密情報を格納しない

## 備考

- IDプレフィックスは「iitem」
- reserved_quantityとstocked_quantityは計算フィールドとして定義
- location_levelsとreservation_itemsへのhasMany関係を持つ

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | inventory-item.ts | `packages/modules/inventory/src/models/inventory-item.ts` | エンティティ定義 |
| 1-2 | inventory-level.ts | `packages/modules/inventory/src/models/inventory-level.ts` | ロケーション別在庫 |
| 1-3 | reservation-item.ts | `packages/modules/inventory/src/models/reservation-item.ts` | 予約アイテム |

**読解のコツ**: InventoryItemは物理的な商品属性（寸法、重量、HSコードなど）を持ち、location_levelsとreservation_itemsへのhasManyリレーションを持つ。reserved_quantityとstocked_quantityは計算フィールドとして定義されている。

#### Step 2: モジュールサービスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | inventory-module.ts | `packages/modules/inventory/src/services/inventory-module.ts` | モジュールサービス本体 |

**主要処理フロー**:
- **211-221行目**: `sanitizeInventoryItemInput()` - location_levelsを入力から除去
- **312-350行目**: `createInventoryItems()` - 在庫アイテム作成
- **395-438行目**: `updateInventoryItems()` - 在庫アイテム更新
- **1032-1058行目**: `retrieveAvailableQuantity()` - 利用可能数量取得
- **1068-1095行目**: `retrieveStockedQuantity()` - 在庫数量取得
- **1142-1155行目**: `confirmInventory()` - 在庫確認

#### Step 3: 在庫数量取得を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | inventory-module.ts | `packages/modules/inventory/src/services/inventory-module.ts` | 数量取得メソッド |

**主要処理フロー**:
- **1032-1058行目**: `retrieveAvailableQuantity()` - inventoryLevelService_.getAvailableQuantity()を呼び出し
- **1097-1132行目**: `retrieveReservedQuantity()` - inventoryLevelService_.getReservedQuantity()を呼び出し
- **1142-1155行目**: `confirmInventory()` - 利用可能数量 >= 要求数量をチェック

### プログラム呼び出し階層図

```
InventoryModuleService
    │
    ├─ createInventoryItems() [public]
    │      ├─ sanitizeInventoryItemInput() [private]
    │      └─ createInventoryItems_() [protected]
    │             └─ inventoryItemService_.create()
    │
    ├─ updateInventoryItems() [public]
    │      ├─ sanitizeInventoryItemInput() [private]
    │      └─ updateInventoryItems_() [protected]
    │             └─ inventoryItemService_.update()
    │
    ├─ retrieveAvailableQuantity() [public]
    │      ├─ inventoryItemService_.retrieve()
    │      └─ inventoryLevelService_.getAvailableQuantity()
    │
    ├─ retrieveStockedQuantity() [public]
    │      ├─ inventoryItemService_.retrieve()
    │      └─ inventoryLevelService_.retrieveStockedQuantity()
    │
    ├─ retrieveReservedQuantity() [public]
    │      ├─ inventoryItemService_.retrieve()
    │      └─ inventoryLevelService_.getReservedQuantity()
    │
    └─ confirmInventory() [public]
           └─ retrieveAvailableQuantity()
                  └─ MathBN.gte(available, quantity)
```

### データフロー図

```
[入力]                      [処理]                              [出力]

CreateInventoryItemInput   InventoryModuleService             InventoryItemDTO
         │                          │                                │
         ▼                          ▼                                ▼
    ┌──────────┐           ┌─────────────────┐              ┌──────────────┐
    │ API      │ ────────▶ │ sanitize +      │ ───────────▶ │ JSON Response│
    │ Request  │           │ create/update   │              │ (serialized) │
    └──────────┘           └─────────────────┘              └──────────────┘
                                   │
                                   ▼
                           ┌───────────────┐
                           │ inventory_item│
                           │ table         │
                           └───────────────┘
                                   │
                        ┌──────────┴──────────┐
                        ▼                     ▼
                ┌──────────────┐      ┌──────────────┐
                │ location_    │      │ reservation_ │
                │ levels       │      │ items        │
                └──────────────┘      └──────────────┘

[在庫確認フロー]

在庫アイテムID + ロケーションID         confirmInventory               boolean
         │                                   │                            │
         ▼                                   ▼                            ▼
    ┌──────────┐                    ┌─────────────────┐           ┌──────────┐
    │ 確認     │ ─────────────────▶ │ retrieveAvail   │ ────────▶ │ true/    │
    │ リクエスト│                   │ ableQuantity    │           │ false    │
    └──────────┘                    └─────────────────┘           └──────────┘
                                           │
                                           ▼
                                   ┌───────────────┐
                                   │ MathBN.gte    │
                                   │ (available,   │
                                   │ quantity)     │
                                   └───────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| inventory-module.ts | `packages/modules/inventory/src/services/inventory-module.ts` | ソース | モジュールサービス本体 |
| inventory-item.ts | `packages/modules/inventory/src/models/inventory-item.ts` | ソース | 在庫アイテムエンティティ |
| inventory-level.ts | `packages/modules/inventory/src/models/inventory-level.ts` | ソース | 在庫レベルエンティティ |
| reservation-item.ts | `packages/modules/inventory/src/models/reservation-item.ts` | ソース | 予約アイテムエンティティ |
