# 機能設計書 8-商品画像管理

## 概要

本ドキュメントは、Medusaコマースプラットフォームにおける商品画像（Product Image）管理機能の設計を記述する。

### 本機能の処理概要

**業務上の目的・背景**：
商品画像は、商品およびバリアントに関連付けられるメディア資産を管理する。商品に複数の画像を登録し、表示順序（rank）を設定できる。v2.11.2以降では、画像とバリアントの多対多関連もサポートされ、バリアント固有の画像設定が可能になった。

**機能の利用シーン**：
- 商品作成時に画像を添付
- 商品の画像追加・差し替え
- 画像の表示順序変更
- バリアント固有の画像設定（サイズ・色別画像）
- 不要な画像の削除

**主要な処理内容**：
1. 商品作成/更新時に画像を一括登録
2. 画像とバリアントの関連付け管理
3. 画像の表示順序（rank）管理
4. 商品削除時の画像カスケード削除

**関連システム・外部連携**：
- 商品モジュール（Product Module）：商品と画像の1対多関連
- 商品バリアント：バリアントと画像の多対多関連
- ファイルストレージ：画像URLの保存先

**権限による制御**：
- Admin API経由のアクセスには認証が必要（AuthenticatedMedusaRequest）
- 画像の管理操作は管理者権限を持つユーザーのみ実行可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 8 | 商品編集画面 | 主画面 | 画像のアップロード・削除・並び替え |

## 機能種別

CRUD操作（商品の子リソースとしてのCRUD）

## 入力仕様

### 入力パラメータ

#### 商品作成/更新時の画像（POST /admin/products, POST /admin/products/:id）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| images | array | No | 画像配列 | - |
| images[].url | string | Yes | 画像URL | URL形式 |
| images[].rank | number | No | 表示順序 | デフォルト0 |
| images[].metadata | object | No | メタデータ | JSON形式 |

#### バリアントと画像の関連付け（POST /admin/products/:id/images/:image_id/variants/batch）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| add | array | No | 追加するバリアントID配列 | - |
| remove | array | No | 削除するバリアントID配列 | - |

### 入力データソース

- 管理画面（Admin Dashboard）からのファイルアップロード
- REST API経由のJSON/リクエストボディ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | string | 画像ID（img_xxx形式） |
| url | string | 画像URL |
| rank | number | 表示順序 |
| metadata | object | メタデータ |
| product_id | string | 所属商品ID |
| variants | array | 関連バリアント配列（v2.11.2以降） |
| created_at | datetime | 作成日時 |
| updated_at | datetime | 更新日時 |
| deleted_at | datetime | 削除日時 |

### 出力先

- REST APIレスポンス（JSON形式、商品レスポンスの一部として）
- 管理画面への表示

## 処理フロー

### 処理シーケンス

```
1. 商品作成時の画像登録フロー
   ├─ 商品データ準備
   ├─ 画像データを含めて商品作成
   └─ 画像がカスケード作成される

2. 商品更新時の画像更新フロー
   ├─ 既存商品の取得
   ├─ 画像配列の差分更新
   └─ 更新された商品を返却

3. バリアント画像関連付けフロー
   ├─ batchImageVariantsWorkflow実行
   ├─ addImageToVariantsStep（追加）
   ├─ removeImageFromVariantsStep（削除）
   └─ サムネイル更新（削除時）

4. 商品削除時の画像カスケード削除
   └─ cascades.delete設定により自動削除
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-I01 | 画像所属 | 画像は必ず1つの商品に所属する | 画像作成時 |
| BR-I02 | 順序指定 | rankによる表示順序の制御（デフォルト0） | 一覧表示時 |
| BR-I03 | カスケード削除 | 商品削除時に関連画像も削除される | 商品削除時 |
| BR-I04 | バリアント多重関連 | 1つの画像は複数のバリアントに関連付け可能 | v2.11.2以降 |
| BR-I05 | サムネイル更新 | バリアントから画像を削除時、サムネイルも更新 | 関連削除時 |

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 作成 | image | INSERT | 画像レコードの挿入 |
| 取得 | image | SELECT | 画像の取得 |
| 更新 | image | UPDATE | 画像の更新 |
| 削除 | image | UPDATE | deleted_atの設定（論理削除） |
| 関連 | product_variant_product_image | INSERT/DELETE | バリアント関連管理 |

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

#### image

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id | 自動生成（img_xxx形式） | generateEntityId使用 |
| INSERT | url | リクエストの値 | 必須 |
| INSERT | rank | リクエストの値 or 0 | デフォルト0 |
| INSERT | product_id | 所属商品のID | 外部キー |
| DELETE | deleted_at | 現在日時 | 論理削除 |

### インデックス情報

| インデックス名 | カラム | 用途 |
|--------------|--------|------|
| IDX_product_image_url | url | URL検索 |
| IDX_product_image_rank | rank | 順序ソート |
| IDX_product_image_url_rank_product_id | url, rank, product_id | 複合検索 |
| IDX_product_image_rank_product_id | rank, product_id | 商品内順序取得 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| NOT_FOUND | 404 | 指定IDの画像が存在しない | 正しいIDを指定 |
| NOT_FOUND | 404 | 指定IDの商品が存在しない | 正しいIDを指定 |
| INVALID_DATA | 400 | URLが不正 | 正しいURL形式を指定 |

## 備考

- 画像のIDプレフィックスは「img」
- テーブル名は「image」（product_imageではない）
- 商品削除時にcascadesで自動削除
- v2.11.2以降でバリアントとの多対多関連をサポート

---

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | product-image.ts | `packages/modules/product/src/models/product-image.ts` | 画像モデル定義 |

**主要処理フロー（product-image.ts）**:
- **6-25行目**: ProductImageモデル定義
- **10行目**: IDプレフィックス「img」
- **11行目**: urlフィールド
- **13行目**: rankフィールド（default(0)）
- **14-16行目**: 商品とのbelongsToリレーション
- **20-23行目**: バリアントとの多対多リレーション（v2.11.2）
- **26-51行目**: インデックス定義（url, rank, 複合）

#### Step 2: 商品モデルとの関連を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | product.ts | `packages/modules/product/src/models/product.ts` | 商品からの画像参照 |

**主要処理フロー（product.ts）**:
- **49-51行目**: imagesとのhasMany関係
- **63行目**: cascades.deleteにimagesを含む

#### Step 3: ワークフローを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | batch-image-variants.ts | `packages/core/core-flows/src/product/workflows/batch-image-variants.ts` | 画像-バリアント関連管理 |

**主要処理フロー（batch-image-variants.ts）**:
- **74-171行目**: batchImageVariantsWorkflow定義
- **87-90行目**: parallelizeで追加・削除を同時実行
- **88行目**: addImageToVariantsStep
- **89行目**: removeImageFromVariantsStep
- **92-146行目**: バリアントサムネイル更新処理
- **154-160行目**: 条件付きバリアント更新

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

```
[Admin Dashboard / REST Client]
    │
    ▼
POST /admin/products (商品作成)
    │
    ├──▶ createProductsWorkflow
    │       └── 画像はProductデータの一部として作成
    │
POST /admin/products/:id (商品更新)
    │
    ├──▶ updateProductsWorkflow
    │       └── 画像は差分更新
    │
POST /admin/products/:id/images/:image_id/variants/batch
    │
    └──▶ batchImageVariantsWorkflow
            ├── addImageToVariantsStep
            ├── removeImageFromVariantsStep
            └── updateProductVariantsStep (サムネイル更新)
```

### データフロー図

```
┌─────────────────────────────────────────────────────────┐
│                     Admin API Layer                      │
│  ┌─────────────────────────────────────────────────────┐│
│  │            商品CRUD / 画像バッチ操作                 ││
│  │  ┌────────────────┐  ┌─────────────────────────┐   ││
│  │  │ products/      │  │ images/:id/variants/   │   ││
│  │  │ (画像含む)     │  │ batch                  │   ││
│  │  └───────┬────────┘  └───────────┬─────────────┘   ││
│  └──────────┼───────────────────────┼─────────────────┘│
└─────────────┼───────────────────────┼──────────────────┘
              │                       │
              ▼                       ▼
┌─────────────────────────────────────────────────────────┐
│                   Workflow Layer                         │
│  ┌────────────────────┬───────────────────────────────┐ │
│  │ createProducts/    │  batchImageVariants          │ │
│  │ updateProducts     │  Workflow                    │ │
│  │ Workflow           │                              │ │
│  └─────────┬──────────┴─────────────┬────────────────┘ │
│            │                        │                   │
│            ▼                        ▼                   │
│  ┌────────────────────────────────────────────────────┐ │
│  │           Product Module (Product Image)          │ │
│  │  ┌────────────┬────────────┬────────────────────┐ │ │
│  │  │   create   │   update   │   バリアント関連    │ │ │
│  │  └─────┬──────┴─────┬──────┴─────────┬──────────┘ │ │
│  └────────┼────────────┼────────────────┼────────────┘ │
└───────────┼────────────┼────────────────┼──────────────┘
            │            │                │
            ▼            ▼                ▼
┌─────────────────────────────────────────────────────────┐
│                   Database Layer                         │
│  ┌───────────────────────────────────────────────────┐  │
│  │                  image table                      │  │
│  │  id (img_xxx) | url | rank | product_id          │  │
│  └──────────────────────┬────────────────────────────┘  │
│                         │ belongsTo                     │
│                         ▼                               │
│  ┌───────────────────────────────────────────────────┐  │
│  │                  product table                    │  │
│  │                   hasMany                         │  │
│  └───────────────────────────────────────────────────┘  │
│                                                         │
│  ┌───────────────────────────────────────────────────┐  │
│  │      product_variant_product_image (中間)         │  │
│  │          image_id | variant_id                   │  │
│  └───────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| product-image.ts | `packages/modules/product/src/models/product-image.ts` | モデル | 画像エンティティ定義 |
| product.ts | `packages/modules/product/src/models/product.ts` | モデル | 商品からの参照定義 |
| product-variant-product-image.ts | `packages/modules/product/src/models/product-variant-product-image.ts` | モデル | 中間テーブル定義 |
| batch-image-variants.ts | `packages/core/core-flows/src/product/workflows/batch-image-variants.ts` | ワークフロー | 画像-バリアント関連管理 |
| create-products.ts | `packages/core/core-flows/src/product/workflows/create-products.ts` | ワークフロー | 商品作成（画像含む） |
| update-products.ts | `packages/core/core-flows/src/product/workflows/update-products.ts` | ワークフロー | 商品更新（画像含む） |
