# バッチ設計書 61-ActionMailbox::IncinerationJob

## 概要

本ドキュメントは、Action Mailboxフレームワークにおける`ActionMailbox::IncinerationJob`の設計仕様を記載します。このジョブは、処理済みのInboundEmail（受信メール）を設定された期間後に自動的に削除（焼却）する非同期バッチ処理です。

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

このバッチは、Action Mailboxで処理が完了した受信メールを、プライバシー保護とストレージ管理の観点から自動的にデータベースから削除します。

**業務上の目的・背景**：
メールシステムでは、受信したメールを処理後も永続的に保持し続けると、プライバシー上の懸念（個人情報の長期保持）やストレージコストの増大といった問題が発生します。IncinerationJobは、これらの課題を解決するために設計されており、GDPR等のデータ保護規制への準拠を支援し、システムのストレージ使用量を適切に管理します。「焼却（Incineration）」という名称は、メールデータを完全に削除することを意味しています。

**バッチの実行タイミング**：
InboundEmailのステータスが`processed`（delivered、failed、bounced のいずれか）に変更されたタイミングで、設定された待機時間（デフォルト30日）後に実行されるようスケジュールされます。具体的には、`after_update_commit`コールバックで`ActionMailbox::IncinerationJob.schedule`が呼び出され、ActiveJobの`set(wait:)`機能を使用して遅延実行されます。

**主要な処理内容**：
1. スケジュール時に指定されたInboundEmailの取得を試みる
2. InboundEmailが削除済みの場合はジョブを破棄（discard_on ActiveRecord::RecordNotFound）
3. InboundEmailの`incinerate`メソッドを呼び出し、Incinerationコマンドクラスを実行
4. 削除条件（処理済み かつ 待機期間経過）を満たす場合、レコードを完全削除（destroy!）

**前後の処理との関連**：
前提として、RoutingJobによってメールの処理が完了し、ステータスが`delivered`、`failed`、または`bounced`に更新されている必要があります。このステータス変更がIncinerationJobのスケジューリングをトリガーします。後続の処理はなく、本ジョブの完了をもってInboundEmailのライフサイクルは終了となります。

**影響範囲**：
- action_mailbox_inbound_emails テーブル（レコード削除）
- Active Storage（raw_emailとして添付されたメール本文のBlob削除）
- 関連する監査ログやメトリクス（削除イベントの記録）

## バッチ種別

データクレンジング / 定期削除処理

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | イベント駆動（随時） |
| 実行時刻 | N/A（スケジュール時刻から待機時間後） |
| 実行曜日 | N/A |
| 実行日 | N/A |
| トリガー | InboundEmailのステータスがprocessedに変更時、待機時間後に自動実行 |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| ActionMailbox.incinerate が true | 焼却機能が有効になっていること（デフォルト: true） |
| InboundEmailが存在する | 対象のInboundEmailレコードがデータベースに存在すること |
| InboundEmailが処理済み | ステータスがdelivered、failed、bouncedのいずれかであること |

### 実行可否判定

1. `ActionMailbox.incinerate`が`true`の場合のみスケジュールされる
2. ジョブ実行時にInboundEmailが存在しない場合、`discard_on ActiveRecord::RecordNotFound`によりジョブは破棄される
3. 実際の削除時には、Incinerationクラスで以下の条件を再確認：
   - `due?`: `updated_at`が`ActionMailbox.incinerate_after.ago.end_of_day`より前であること
   - `processed?`: ステータスがdelivered、failed、bouncedのいずれかであること

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| inbound_email | ActionMailbox::InboundEmail | Yes | - | 削除対象のInboundEmailインスタンス |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| action_mailbox_inbound_emails | DB | 削除対象のInboundEmailレコード |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| action_mailbox_inbound_emails | DB | レコード削除 |
| Active Storage Blobs | DB/Storage | 関連する添付ファイル（raw_email）の削除 |

### 出力ファイル仕様

ファイル出力はありません。

## 処理フロー

### 処理シーケンス

```
1. ジョブ実行開始
   └─ ActiveJobキューから取り出され、performメソッドが呼び出される
2. InboundEmail取得
   └─ 渡されたinbound_emailオブジェクトを参照
3. レコード存在チェック
   └─ ActiveRecord::RecordNotFoundの場合、ジョブを破棄
4. incinerate呼び出し
   └─ inbound_email.incinerateを実行
5. Incinerationコマンド実行
   └─ due?とprocessed?の条件を確認
6. 条件判定
   └─ 両条件を満たす場合のみ次のステップへ
7. レコード削除
   └─ destroy!でInboundEmailと関連データを完全削除
8. ジョブ完了
   └─ 正常終了
```

### フローチャート

```mermaid
flowchart TD
    A[ジョブ開始] --> B{InboundEmail存在?}
    B -->|なし| C[ジョブ破棄]
    B -->|あり| D[incinerate呼び出し]
    D --> E{処理済み?}
    E -->|No| F[スキップ]
    E -->|Yes| G{待機期間経過?}
    G -->|No| F
    G -->|Yes| H[destroy!実行]
    H --> I[関連Blob削除]
    I --> J[ジョブ完了]
    F --> J
    C --> K[終了]
    J --> K
```

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

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

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| レコード削除 | action_mailbox_inbound_emails | DELETE | 対象InboundEmailレコードの削除 |
| Blob削除 | active_storage_blobs | DELETE | 関連するraw_emailのBlob削除 |
| Attachment削除 | active_storage_attachments | DELETE | InboundEmailとBlobの関連削除 |

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

#### action_mailbox_inbound_emails

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | - | id = 対象InboundEmailのID | destroy!により完全削除 |

#### active_storage_attachments

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | - | record_type = 'ActionMailbox::InboundEmail', record_id = 対象ID, name = 'raw_email' | 依存関係により自動削除 |

#### active_storage_blobs

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | - | 関連するAttachmentのblob_id | PurgeJobにより非同期削除される場合あり |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ActiveRecord::RecordNotFound | InboundEmailが既に削除されている | discard_onにより自動破棄 |
| - | ActiveRecord::RecordNotDestroyed | 削除処理が失敗した場合 | 標準のActiveJobリトライに従う |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | ActiveJobのデフォルト設定に従う |
| リトライ間隔 | ActiveJobのデフォルト設定に従う |
| リトライ対象エラー | ActiveRecord::RecordNotFound以外のすべてのエラー |

### 障害時対応

1. `discard_on ActiveRecord::RecordNotFound`により、対象レコードが存在しない場合は自動的にジョブが破棄される
2. その他のエラーが発生した場合は、ActiveJobの標準リトライメカニズムに従ってリトライされる
3. 手動での対応が必要な場合は、対象のInboundEmailを特定し、`inbound_email.incinerate`を直接呼び出すか、ジョブを再キューイングする

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | 単一レコード単位 |
| コミットタイミング | destroy!完了時 |
| ロールバック条件 | destroy!が例外をraiseした場合 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 1ジョブあたり1件 |
| 目標処理時間 | 数秒以内 |
| メモリ使用量上限 | 通常のActiveJobプロセスの範囲内 |

## 排他制御

各InboundEmailに対して1つのIncinerationJobのみがスケジュールされます。`discard_on ActiveRecord::RecordNotFound`により、同じレコードに対する重複実行は自動的に処理されます。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 開始ログ | ジョブ開始時 | ActiveJobの標準ログ（ジョブクラス名、引数） |
| 進捗ログ | - | 特別な進捗ログなし |
| 終了ログ | ジョブ終了時 | ActiveJobの標準ログ（実行時間等） |
| エラーログ | エラー発生時 | 例外情報、スタックトレース |
| 破棄ログ | RecordNotFound時 | ActiveJobの破棄ログ |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| キュー滞留数 | アプリケーション依存 | 運用チーム |
| 失敗ジョブ数 | アプリケーション依存 | 運用チーム |

## 備考

- キュー名は`ActionMailbox.queues[:incineration]`で設定可能（デフォルト: `:action_mailbox_incineration`）
- 焼却待機時間は`config.action_mailbox.incinerate_after`で設定可能（デフォルト: 30日）
- 焼却機能自体は`config.action_mailbox.incinerate`で無効化可能（デフォルト: true）
- InboundEmailの削除時には、Active Storageに保存されたraw_email（メール本文）も削除される
