# バッチ設計書 9-Internal::DeleteAccountsJob

## 概要

本ドキュメントは、Chatwootアプリケーションにおける`Internal::DeleteAccountsJob`バッチの設計仕様を記載したものである。

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

このバッチは、削除マークが付けられ、削除期限が過ぎたアカウントを物理削除するジョブである。GDPR等のプライバシー規制に準拠したアカウント削除フローの一部として機能する。

**業務上の目的・背景**：Chatwootでは、ユーザーがアカウント削除をリクエストすると、即座に削除するのではなく、`marked_for_deletion_at`という属性に削除予定日時を設定する（通常7日後）。この猶予期間により、誤操作による削除の取り消しが可能となる。このバッチは、猶予期間が過ぎたアカウントを実際に削除することで、データ保護規制（GDPR等）への準拠を支援する。

**バッチの実行タイミング**：日次で01:00 UTCに実行される。深夜のトラフィック最小時間帯に実行される。

**主要な処理内容**：
1. `marked_for_deletion_at`が設定されているアカウントを検索
2. 削除期限（`marked_for_deletion_at`）が現在時刻以前のアカウントを特定
3. 各対象アカウントに対してAccountDeletionServiceを呼び出し
4. AccountDeletionServiceが孤立ユーザーのソフト削除、コンプライアンス通知、DeleteObjectJobのキューイングを実施

**前後の処理との関連**：Enterprise版でユーザーがアカウント削除をリクエスト（`mark_for_deletion`）した後、7日後にこのバッチが実行され、AccountDeletionServiceとDeleteObjectJobを通じてアカウントと関連データが削除される。

**影響範囲**：accounts、users、その他アカウントに関連するすべてのテーブル

## バッチ種別

アカウント管理 / データ削除

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 日次 |
| 実行時刻 | 01:00 UTC |
| 実行曜日 | 毎日 |
| 実行日 | - |
| トリガー | cron（sidekiq-cron） |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| なし | 特別な前提条件なく常に実行される |

### 実行可否判定

常に実行される。削除対象アカウントが存在しない場合は、処理をスキップして正常終了する。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| なし | - | - | - | 本バッチは引数を取らない |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| accounts | DB | `custom_attributes->>'marked_for_deletion_at'`がNOT NULLのアカウント |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| Sidekiqキュー | ジョブ | DeleteObjectJobをキューイング |
| ログ | テキスト | 削除対象アカウントの情報 |
| メール | 通知 | コンプライアンス通知メール |

### 出力ファイル仕様

ファイル出力なし

## 処理フロー

### 処理シーケンス

```
1. 削除候補アカウントの検索
   └─ Account.where("custom_attributes->>'marked_for_deletion_at' IS NOT NULL")
2. 削除期限チェック
   └─ 各アカウントのmarked_for_deletion_atをパース
   └─ Time.current以前のものを削除対象として選択
3. 各対象アカウントの削除処理
   └─ AccountDeletionService.new(account: account).perform
   └─ 孤立ユーザーのソフト削除（メールに"-deleted.com"を付加）
   └─ コンプライアンス通知メールの送信
   └─ DeleteObjectJob.perform_later(account)でバックグラウンド削除
```

### フローチャート

```mermaid
flowchart TD
    A[バッチ開始] --> B[marked_for_deletion_atがあるアカウント検索]
    B --> C{対象アカウントあり?}
    C -->|No| D[処理終了]
    C -->|Yes| E[各アカウントをループ処理]
    E --> F{削除期限過ぎた?}
    F -->|No| G[スキップ]
    F -->|Yes| H[AccountDeletionService呼び出し]
    H --> I[孤立ユーザーをソフト削除]
    I --> J[コンプライアンス通知メール送信]
    J --> K[DeleteObjectJobをキューイング]
    K --> L{次のアカウントあり?}
    G --> L
    L -->|Yes| E
    L -->|No| D
```

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

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

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 削除対象検索 | accounts | SELECT | marked_for_deletion_atがあるアカウント検索 |
| ユーザーソフト削除 | users | UPDATE | 孤立ユーザーのメールに"-deleted.com"を付加 |
| アカウント削除 | accounts, 関連テーブル | DELETE | DeleteObjectJob経由で削除 |

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

#### accounts

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, name, custom_attributes | custom_attributes->>'marked_for_deletion_at' IS NOT NULL | JSON属性の検索 |

#### users

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | email | email = original_email + '-deleted.com' | 他アカウントに所属していないユーザーのみ |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | JSON::ParserError | marked_for_deletion_atの日時パースエラー | スキップして次のアカウントを処理 |
| - | StandardError | 予期しないエラー | Sidekiqリトライ機構に委譲 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | Sidekiqのデフォルト設定に依存 |
| リトライ間隔 | Sidekiqのデフォルト設定に依存 |
| リトライ対象エラー | ジョブ実行時の例外全般 |

### 障害時対応

本ジョブが失敗した場合、翌日の定期実行で再度処理される。削除期限を過ぎたアカウントは次回実行時にも削除対象となるため、一時的な失敗は問題にならない。

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | AccountDeletionService内の個別処理ごと |
| コミットタイミング | ユーザーソフト削除時、DeleteObjectJob投入時 |
| ロールバック条件 | 個別処理内での例外発生時 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 数件/日（削除リクエストは稀） |
| 目標処理時間 | 数秒〜数分 |
| メモリ使用量上限 | 最小限 |

## 排他制御

同時実行の制御は特になし。日次1回のみの実行であり、通常は競合しない。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 情報ログ | 削除開始時 | `Deleting account {id} - {name} that was marked for deletion` |
| 情報ログ | ユーザーソフト削除時 | `Soft deleted user {id} with email {email}` |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| ジョブ失敗 | 連続失敗 | Sidekiq監視 |
| 削除件数 | 異常に多い場合 | 運用監視（任意） |

## 備考

- Enterprise版の機能で、`mark_for_deletion`メソッドにより7日後の削除予定日が設定される
- 孤立ユーザー（削除対象アカウントにのみ所属）は、メールアドレスに"-deleted.com"を付加してソフト削除される
- AccountComplianceMailerによりコンプライアンス通知メールが送信される
- 実際のアカウントと関連データの削除はDeleteObjectJobで非同期実行される
- `deletion_period_expired?`メソッドで`marked_for_deletion_at`が現在時刻以前かをチェック
- scheduled_jobsキューを使用
