# バッチ設計書 37-migrate_icons

## 概要

本ドキュメントは、InvenTreeシステムにおけるアイコンマイグレーションバッチ（migrate_icons）の設計仕様を定義する。

### 本バッチの処理概要

migrate_iconsは、古いFontAwesomeアイコン形式から新しいアイコンライブラリ形式へのマイグレーションを支援するDjango管理コマンドである。

**業務上の目的・背景**：InvenTreeはユーザーインターフェースでカスタムアイコンを使用できる機能を提供しており、以前はFontAwesomeアイコンを使用していた。システムのアップデートに伴い、新しいアイコンライブラリに移行する必要が生じた。本バッチは、データベースに保存されている古い形式のアイコン参照を新しい形式に変換するプロセスを自動化する。このバッチは2段階のプロセス（マップファイルの生成とインポート）を提供し、管理者がマイグレーションを安全かつ制御可能な方法で実行できるようにする。

**バッチの実行タイミング**：手動実行（CLIコマンド）。以下の場面で実行される：
- InvenTreeのメジャーアップデート時（アイコンライブラリの変更時）
- アイコンマイグレーションが必要な場合のみ

**主要な処理内容**：
1. 出力モード：現在使用されている古いアイコンを検出し、マッピングファイル（JSON）を生成
2. 入力モード：マッピングファイルを読み込み、検証後にデータベースを更新
3. 対象モデル：StockLocation、StockLocationType、PartCategory

**前後の処理との関連**：
- 前提：マイグレーション対象のアイコンを使用しているデータが存在すること
- 後続：新しいアイコン形式でUIが表示される

**影響範囲**：
- StockLocationテーブルのcustom_iconカラム
- StockLocationTypeテーブルのiconカラム
- PartCategoryテーブルの_iconカラム

## バッチ種別

データマイグレーション / 設定変換

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 随時（手動、通常はアップデート時のみ） |
| 実行時刻 | 任意 |
| 実行曜日 | 任意 |
| 実行日 | 任意 |
| トリガー | 手動 |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| Django環境 | Django環境が正しく設定されていること |
| モデル存在 | StockLocation、StockLocationType、PartCategoryモデルが存在すること |
| アイコン検証 | common.icons.validate_icon関数が利用可能であること |

### 実行可否判定

- --output-fileまたは--input-fileのいずれか一方のみが指定されていること
- 両方指定または両方未指定の場合はCommandError

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| --output-file | str | No* | None | マッピングファイルの出力先パス |
| --input-file | str | No* | None | マッピングファイルの入力元パス |
| --include-items | flag | No | False | 出力時にアイテム情報を含めるか |
| --import-now | flag | No | False | マッピングを即座にインポートするか |

*注: --output-fileまたは--input-fileのいずれか一方は必須

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| StockLocation | DBテーブル | 在庫場所のアイコン情報 |
| StockLocationType | DBテーブル | 在庫場所タイプのアイコン情報 |
| PartCategory | DBテーブル | パーツカテゴリのアイコン情報 |
| マッピングファイル | JSON | 古いアイコン→新しいアイコンの変換マップ |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| 指定ファイル（出力モード） | JSON | アイコンマッピング情報 |
| コンソール | テキスト | 処理状況・結果 |

### 出力ファイル仕様（出力モード）

| 項目 | 内容 |
|-----|------|
| ファイル名 | --output-fileで指定 |
| 出力先 | 指定パス |
| 文字コード | UTF-8 |
| フォーマット | JSON（インデント: 2スペース） |

### 出力JSONスキーマ

```json
{
  "<古いアイコン名>": {
    "items": [  // --include-items指定時のみ
      {"model": "<モデル名>", "id": <ID>}
    ],
    "new_icon": ""  // 新しいアイコン名（手動で入力が必要）
  }
}
```

## 処理フロー

### 処理シーケンス（出力モード）

```
1. 引数検証
   └─ --output-fileが指定されていることを確認
2. モデルごとにアイコン付きアイテムを検索
   └─ StockLocation.custom_icon
   └─ StockLocationType.icon
   └─ PartCategory._icon
3. 各アイテムのアイコンを検証
   └─ validate_icon()で既に有効なアイコンはスキップ
4. 古いアイコンをマップに追加
   └─ --include-items時はアイテム情報も追加
5. JSONファイルに書き出し
```

### 処理シーケンス（入力モード）

```
1. 引数検証
   └─ --input-fileが指定されていることを確認
2. JSONファイル読み込み
3. 検証フェーズ
   └─ 全ての新アイコンがvalidate_icon()で有効か確認
   └─ 必要な全ての古いアイコンがマップに含まれているか確認
4. エラーがあれば処理中断
5. --import-now指定時のみDBを更新
   └─ 各モデルのアイコンフィールドを更新
   └─ item.save()で保存
```

### フローチャート

```mermaid
flowchart TD
    A[バッチ開始] --> B{引数チェック}
    B -->|両方指定| C[CommandError]
    B -->|両方未指定| C
    B -->|output-file指定| D[出力モード]
    B -->|input-file指定| E[入力モード]

    D --> F[モデルループ]
    F --> G[アイコン付きアイテム取得]
    G --> H{アイコン有効?}
    H -->|Yes| I[スキップ]
    H -->|No| J[マップに追加]
    I --> K{次のアイテム?}
    J --> K
    K -->|Yes| G
    K -->|No| L[JSONファイル出力]
    L --> M[バッチ終了]

    E --> N[JSONファイル読み込み]
    N --> O[新アイコン検証]
    O --> P[必要アイコン確認]
    P --> Q{エラーあり?}
    Q -->|Yes| R[エラー表示・終了]
    Q -->|No| S{import-now?}
    S -->|No| T[検証完了メッセージ]
    S -->|Yes| U[DBアップデート]
    U --> V[完了メッセージ]
    T --> M
    V --> M
```

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

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

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| アイコン検索 | stock_stocklocation | SELECT | custom_iconがnullでないレコードを取得 |
| アイコン検索 | stock_stocklocationtype | SELECT | iconがnullでないレコードを取得 |
| アイコン検索 | part_partcategory | SELECT | _iconがnullでないレコードを取得 |
| アイコン更新 | stock_stocklocation | UPDATE | custom_iconを新アイコンに更新 |
| アイコン更新 | stock_stocklocationtype | UPDATE | iconを新アイコンに更新 |
| アイコン更新 | part_partcategory | UPDATE | _iconを新アイコンに更新 |

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

#### stock_stocklocation

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | custom_icon | NOT NULL AND != '' | アイコン付きレコード |
| UPDATE | custom_icon | マップの新アイコン値 | --import-now時のみ |

#### stock_stocklocationtype

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | icon | NOT NULL AND != '' | アイコン付きレコード |
| UPDATE | icon | マップの新アイコン値 | --import-now時のみ |

#### part_partcategory

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | _icon | NOT NULL AND != '' | アイコン付きレコード |
| UPDATE | _icon | マップの新アイコン値 | --import-now時のみ |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | CommandError | --input-fileと--output-file両方指定 | いずれか一方のみを指定 |
| - | CommandError | --input-fileと--output-file両方未指定 | いずれか一方を指定 |
| - | CommandError | --include-itemsを--output-fileなしで使用 | --output-fileと共に使用 |
| - | CommandError | --import-nowを--input-fileなしで使用 | --input-fileと共に使用 |
| - | ValidationError | 新アイコンが無効 | マッピングファイルを修正 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし（手動再実行） |
| リトライ間隔 | N/A |
| リトライ対象エラー | N/A |

### 障害時対応

1. エラーメッセージを確認
2. マッピングファイルの内容を確認・修正
3. 問題解決後に再実行

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | 各item.save()単位 |
| コミットタイミング | save()完了時に自動コミット |
| ロールバック条件 | 個別save()エラー時（全体のロールバックなし） |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 数十〜数千件のアイコン設定 |
| 目標処理時間 | 数秒〜数分（データ量に依存） |
| メモリ使用量上限 | 中程度（マッピングデータをメモリに保持） |

## 排他制御

同時実行の制御は行わない。マイグレーション中は他のアイコン更新操作を避けることを推奨。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 進捗ログ | モデル処理開始時 | "Processing model {Model} with icon field {field}" |
| 結果ログ | 出力完了時 | "Writing icon map for {n} icons" |
| 結果ログ | 出力完了時 | "Icon map written to {path}" |
| 検証エラー | 無効アイコン検出時 | "[ERR] Invalid icon: '{old}' -> '{new}'" |
| 検証エラー | マップ欠落時 | "[ERR] Icon '{icon}' not found in icon map" |
| 完了ログ | インポート完了時 | "Icon map successfully imported - changed {n} items" |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| なし | - | - |

## 備考

- 本コマンドは2段階のプロセスで実行することを推奨
  1. まず--output-fileでマッピングファイルを生成
  2. マッピングファイルを手動で編集し、new_iconを設定
  3. --input-fileで検証
  4. --input-file --import-nowでDBを更新
- 既に有効な形式のアイコンは自動的にスキップされる
- マッピングファイルは管理者が手動で新アイコン名を入力する必要がある
- --import-nowフラグを使用しない限り、DBへの変更は行われない（安全）
