# バッチ設計書 18-theme.delete_files

## 概要

本ドキュメントは、Shopwareプラットフォームにおけるテーマファイル削除バッチの設計仕様を定義します。使用されていないテーマのコンパイル済みファイル（CSS、JavaScript等）をファイルシステムから削除し、ストレージを最適化します。

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

**業務上の目的・背景**：Shopwareのテーマシステムでは、テーマがコンパイルされるたびに新しいファイルセットが生成されます。テーマの変更、再コンパイル、テーマ切り替えなどにより、使用されなくなった古いテーマファイルがファイルシステムに残存します。これらのファイルは次第に蓄積し、ストレージ容量を圧迫します。本バッチは定期的に未使用のテーマファイルを検出・削除することで、ストレージの健全性を維持します。

**バッチの実行タイミング**：日次（86400秒間隔）でスケジュール実行されます。

**主要な処理内容**：
1. theme_sales_channelテーブルから現在使用中のテーマパスを取得
2. themeファイルシステムのディレクトリ一覧を取得
3. 使用中でないテーマディレクトリを特定
4. 24時間以上前に更新されたディレクトリのみを削除対象とする（キャッシュ済みレスポンス対応）
5. 対象ディレクトリを削除

**前後の処理との関連**：前提として、テーマがコンパイルされ、theme_sales_channelテーブルに現在の使用テーマが登録されている必要があります。テーマ変更やコンパイル処理の後続タスクとして位置づけられます。

**影響範囲**：themeファイルシステム上のディレクトリ削除を実行します。削除されたファイルは復元できませんが、テーマを再コンパイルすることで再生成可能です。

## バッチ種別

データクレンジング（ファイルクリーンアップ）

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 日次 |
| 実行時刻 | スケジュールタスクランナーに依存 |
| 実行曜日 | 毎日 |
| 実行日 | - |
| トリガー | cron（スケジュールタスク） |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| テーマファイルシステム | themeファイルシステムがアクセス可能であること |
| theme_sales_channel | テーマと販売チャネルのマッピングが存在すること |

### 実行可否判定

特別な実行条件チェックはありません。タスクは常に実行され、削除対象がない場合は何も処理しません。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| なし | - | - | - | 入力パラメータは不要 |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| theme_sales_channel | DB | テーマと販売チャネルのマッピング |
| themeファイルシステム | FileSystem | コンパイル済みテーマファイル |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| themeファイルシステム | FileSystem | ディレクトリ削除 |

### 出力ファイル仕様

ファイル出力はありません（削除処理のみ）。

## 処理フロー

### 処理シーケンス

```
1. 使用中テーマパス取得
   └─ theme_sales_channelからマッピング取得
   └─ themeIdとsalesChannelIdからパスを生成
2. ファイルシステムスキャン
   └─ themeディレクトリ配下のディレクトリ一覧取得
3. 削除対象フィルタリング
   └─ 使用中パスに含まれないディレクトリを抽出
   └─ 24時間以内に更新されたディレクトリを除外
4. ディレクトリ削除
   └─ 削除対象ディレクトリを順次削除
```

### フローチャート

```mermaid
flowchart TD
    A[バッチ開始] --> B[使用中テーマパス取得]
    B --> C[theme_sales_channelクエリ]
    C --> D[パス一覧生成]
    D --> E[themeディレクトリスキャン]
    E --> F[ディレクトリループ]
    F --> G{使用中パス?}
    G -->|Yes| H[スキップ]
    G -->|No| I[最終更新日時確認]
    I --> J{24時間以上前?}
    J -->|No| H
    J -->|Yes| K[ディレクトリ削除]
    K --> L{次のディレクトリ?}
    H --> L
    L -->|Yes| F
    L -->|No| M[バッチ終了]
```

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

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

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| マッピング取得 | theme_sales_channel | SELECT | 使用中テーマのマッピング取得 |

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

#### theme_sales_channel

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | sales_channel_id, theme_id | 全レコード | 現在使用中のテーママッピング |

#### 使用中パス生成SQL

```sql
SELECT LOWER(HEX(sales_channel_id)) AS salesChannelId,
       LOWER(HEX(theme_id)) AS themeId
FROM theme_sales_channel
```

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ファイルシステムエラー | IO エラー | ファイルシステムアクセス失敗 | 権限・接続確認 |
| 削除失敗 | IO エラー | ディレクトリ削除失敗 | ログ確認、手動削除 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 失敗時再スケジュール有効 |
| リトライ間隔 | 次回スケジュール実行時 |
| リトライ対象エラー | 全般的なエラー |

### 障害時対応

1. エラーログを確認し原因を特定
2. ファイルシステムの権限を確認
3. ディスク容量を確認
4. 手動でディレクトリを削除

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | なし（ファイル操作） |
| コミットタイミング | - |
| ロールバック条件 | - |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 数件〜数十件（未使用テーマディレクトリ数） |
| 目標処理時間 | 数秒〜数十秒 |
| メモリ使用量上限 | 通常のPHP制限に準拠 |
| 削除猶予期間 | 24時間 |

## 排他制御

特別な排他制御は実装されていません。ファイルシステム操作はディレクトリ単位で実行されます。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 開始ログ | タスク開始時 | タスク開始通知 |
| 進捗ログ | ディレクトリ削除時 | 削除パス |
| 終了ログ | タスク終了時 | 処理完了通知、削除件数 |
| エラーログ | エラー発生時 | エラー詳細、スタックトレース |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| 処理時間 | 300秒 | システム管理者 |
| エラー件数 | 1件以上 | システム管理者 |

## 備考

- 内部使用タスク（@internal）として定義されています
- 24時間以内に更新されたディレクトリは削除対象から除外されます（キャッシュ済みHTTPレスポンスが古いテーマファイルを参照している可能性があるため）
- themePathBuilderを使用してテーマパスを生成します（salesChannelIdとthemeIdの組み合わせ）
- ファイルシステム操作はLeague\Flysystem\FilesystemOperatorを使用します
- 空のディレクトリ（ファイルが存在しない）も削除対象となります
- ディレクトリ内の最初のファイルの更新日時を基準に削除判定を行います（仮想ディレクトリ対応）
- themeIdのみのパス（アセット用）とsalesChannelId+themeIdのパス（CSS/JS用）の両方が使用中パスとして保護されます
