# バッチ設計書 27-rebuild_thumbnails

## 概要

本ドキュメントは、欠落しているサムネイル画像を再生成するDjango管理コマンド「rebuild_thumbnails」の設計仕様を定義する。

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

このコマンドは、InvenTreeシステムにおける部品（Part）および企業（Company）の画像に対して、欠落しているサムネイルおよびプレビュー画像を再生成し、画像表示の一貫性を確保する。

**業務上の目的・背景**：InvenTreeでは、部品や企業に対して画像を添付でき、これらの画像にはサムネイルとプレビューが自動生成される。データインポートやファイルシステムの問題により、元画像は存在するがサムネイルが欠落する場合がある。本コマンドは、全ての画像を走査し、欠落しているサムネイル・プレビューを再生成することで、UIでの画像表示を正常化する。

**バッチの実行タイミング**：手動実行（CLI）。データインポート後やストレージ復元後に実行される。

**主要な処理内容**：
1. 画像が設定されている全てのPartレコードを走査
2. 各部品の画像に対して、サムネイルとプレビューの存在を確認
3. 欠落している場合は画像バリエーションを再生成
4. 同様の処理をCompanyレコードに対しても実行

**前後の処理との関連**：データインポート後に実行することを推奨。他のバッチとの依存関係はない。

**影響範囲**：メディアファイルシステム上のサムネイル・プレビュー画像ファイルの生成に影響する。データベースへの変更はない。

## バッチ種別

メディア管理 / ファイル再生成 / CLIコマンド

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 随時（手動） |
| 実行時刻 | メンテナンス時間帯 |
| 実行曜日 | 不定 |
| 実行日 | 不定 |
| トリガー | CLIコマンド: `python manage.py rebuild_thumbnails` |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| データベース接続 | InvenTreeデータベースに正常に接続できること |
| メディアストレージ | メディアファイルシステムにアクセス可能であること |
| 元画像存在 | 処理対象の元画像ファイルが存在すること |

### 実行可否判定

特別な実行可否判定はなく、コマンド実行時に即座に処理を開始する。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| なし | - | - | - | 本コマンドは入力パラメータを受け取らない |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| part_part | DB | 部品テーブル（imageフィールド） |
| company_company | DB | 企業テーブル（imageフィールド） |
| メディアファイル | File | 元画像ファイル |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| メディアファイル | File | 再生成されたサムネイル・プレビュー画像 |
| ログ | Log | 再生成処理のログ |

### 出力ファイル仕様

| 項目 | 内容 |
|-----|------|
| ファイル名 | 元画像に基づいた自動命名 |
| 出力先 | Django MEDIAディレクトリ |
| 形式 | 元画像と同じ形式 |

## 処理フロー

### 処理シーケンス

```
1. 部品サムネイル再構築開始
   └─ logger.info('Rebuilding Part thumbnails')
2. 画像が設定されているPartを全件取得
   └─ Part.objects.exclude(image=None)
3. 各部品に対してサムネイル再構築を試行
   └─ rebuild_thumbnail(part)
4. rebuild_thumbnail処理
   └─ 画像とサムネイル、プレビューのパスを取得
   └─ 全てのパスが存在する場合はスキップ
   └─ 欠落がある場合は render_variations(replace=False) を実行
5. 企業サムネイル再構築開始
   └─ logger.info('Rebuilding Company thumbnails')
6. 画像が設定されているCompanyを全件取得
   └─ Company.objects.exclude(image=None)
7. 各企業に対してサムネイル再構築を試行
   └─ rebuild_thumbnail(company)
```

### フローチャート

```mermaid
flowchart TD
    A[コマンド開始] --> B[Rebuilding Part thumbnails ログ出力]
    B --> C[画像ありのPartを取得]
    C --> D{次のPartあり?}
    D -->|Yes| E[rebuild_thumbnail実行]
    D -->|No| F[Rebuilding Company thumbnails ログ出力]
    E --> G{DB/画像エラー?}
    G -->|Yes| H[エラーログ出力・ループ終了]
    G -->|No| D
    F --> I[画像ありのCompanyを取得]
    I --> J{次のCompanyあり?}
    J -->|Yes| K[rebuild_thumbnail実行]
    J -->|No| L[コマンド終了]
    K --> M{DB/画像エラー?}
    M -->|Yes| N[エラーログ出力・ループ終了]
    M -->|No| J
    H --> F
    N --> L
```

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

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

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 部品取得 | part_part | SELECT | image != NULL の部品を取得 |
| 企業取得 | company_company | SELECT | image != NULL の企業を取得 |

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

#### part_part

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | image | IS NOT NULL | 画像が設定されている部品のみ |

#### company_company

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | image | IS NOT NULL | 画像が設定されている企業のみ |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | FileNotFoundError | 元画像ファイルが存在しない | 警告ログ出力、次のレコードへ継続 |
| - | UnidentifiedImageError | 画像ファイルが不正 | 警告ログ出力、次のレコードへ継続 |
| - | OperationalError | データベース読み取りエラー | エラーログ出力、ループ終了 |
| - | ProgrammingError | データベース読み取りエラー | エラーログ出力、ループ終了 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（各画像は1回のみ試行） |
| リトライ間隔 | なし |
| リトライ対象エラー | なし（エラー時は次のレコードへ継続） |

### 障害時対応

個別画像の処理に失敗しても、他の画像の処理は継続される。ただし、OperationalErrorやProgrammingErrorが発生した場合は、データベース接続の問題として現在のループを終了する。

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | なし（データベース更新なし） |
| コミットタイミング | なし |
| ロールバック条件 | なし |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 数百〜数千件の画像 |
| 目標処理時間 | 画像数に依存（数分〜数十分） |
| メモリ使用量上限 | 画像処理時に一時的にメモリを使用 |

## 排他制御

排他制御は特に実装されていない。実行中に画像が変更されても、個別の画像処理には影響しない。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 開始ログ | Part処理開始時 | "Rebuilding Part thumbnails" |
| 開始ログ | Company処理開始時 | "Rebuilding Company thumbnails" |
| 情報ログ | サムネイル生成時 | "Generating thumbnail image for '{image}'" |
| 警告ログ | ファイル欠落時 | "Warning: Image file '{image}' is missing" |
| 警告ログ | 不正画像時 | "Warning: Image file '{image}' is not a valid image" |
| エラーログ | DBエラー時 | "ERROR: Database read error." |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| 処理時間 | 画像数に依存 | システム管理者 |
| エラー件数 | 多数の場合 | システム管理者 |

## 備考

- 本コマンドはDjango管理コマンド（BaseCommand）として実装されている
- 実行方法: `python manage.py rebuild_thumbnails`
- `render_variations(replace=False)` により、既存のサムネイルは上書きされない
- PILライブラリを使用した画像処理
- 全てのパス（元画像、サムネイル、プレビュー）が存在する場合は処理をスキップ
- structlogを使用したログ出力
- データインポート後に実行することを推奨
