# 通知設計書 114-csv_placeholder_reassignment_failed

## 概要

本ドキュメントは、GitLabにおけるCSVプレースホルダー再割り当て失敗通知（csv_placeholder_reassignment_failed）の設計仕様を記述する。

### 本通知の処理概要

CSVプレースホルダー再割り当て失敗通知は、CSVファイルによるプレースホルダーユーザーの一括再割り当て処理自体が失敗した際に、管理者に対してエラーを知らせるメール通知を送信する。

**業務上の目的・背景**：CSVによる一括再割り当て処理は、CSVファイルの形式不正、アップロードファイルの消失、サービス内部エラーなどにより失敗する可能性がある。本通知により、処理失敗を管理者に即座に報告し、問題の調査と再試行を促す。

**通知の送信タイミング**：AssignmentFromCsvWorkerでのCSV処理が失敗した時点、またはリトライ回数を使い果たした時点で、非同期で送信される。

**通知の受信者**：CSVアップロードを実行したユーザー（グループオーナー/管理者）に送信される。

**通知内容の概要**：処理が失敗したこと、およびCSVファイルの再アップロードを促すメッセージを送信する。

**期待されるアクション**：受信者はCSVファイルの形式を確認し、修正後に再度アップロードを試みる。問題が解決しない場合は、手動での再割り当てを検討する。

## 通知種別

メール

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（deliver_later） |
| 優先度 | 通常 |
| リトライ | Sidekiqデフォルト設定に従う |

### 送信先決定ロジック

CSVアップロードを実行したユーザー（current_user）のnotification_email_or_defaultに送信される。

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | GitLabインスタンス設定に従う |
| 送信元名称 | GitLab |
| 件名 | `{group_name} | Bulk reassignment failed` |
| 形式 | テキスト |

### 本文テンプレート

```
Bulk reassignment failed

Unable to process the CSV file for {group_name} to reassign placeholders. Try to upload the file again.

View placeholders: {group_members_url}
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| なし | - | - | 添付ファイルはない |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| @group | 対象グループ | Group.find(group_id) | Yes |
| @title | メールタイトル | 固定値「Bulk reassignment failed」 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| バックグラウンドジョブ | AssignmentFromCsvWorker失敗 | BulkReassignFromCsvServiceが失敗した場合 | CSV処理失敗時に送信 |
| バックグラウンドジョブ | sidekiq_retries_exhausted | Workerのリトライ回数を使い果たした場合 | perform_failure経由で送信 |
| バックグラウンドジョブ | Uploadが見つからない | upload_idに該当するUploadが存在しない場合 | upload消失時に送信 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| BulkReassignFromCsvServiceが成功 | 成功時は別の通知（bulk_import_csv_user_mapping）が送信される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[AssignmentFromCsvWorker起動] --> B{Upload存在?}
    B -->|No| C[send_failure_email]
    B -->|Yes| D[BulkReassignFromCsvService実行]
    D --> E{処理結果}
    E -->|成功| F[send_results_email]
    E -->|失敗| G[perform_failure呼び出し]
    G --> C
    C --> H[Notify.csv_placeholder_reassignment_failed.deliver_later]
    H --> I[終了]
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| groups | 対象グループ情報取得 | |
| users | 送信先ユーザー情報取得 | |
| uploads | CSVファイル参照 | 存在確認のみ |

### テーブル別参照項目詳細

#### groups

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | グループ特定 | Group.find(group_id) |
| name | グループ名表示 | |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| uploads | DELETE | 失敗時にclear_uploadでUploadを削除 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| グループ未存在 | Group.find_by_idで見つからない | ログ出力のみ |
| ユーザー未存在 | User.find_by_idで見つからない | ログ出力のみ |
| メール送信失敗 | SMTPエラー等 | Sidekiqのリトライに委ねる |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | Sidekiqデフォルト設定 |
| リトライ間隔 | Sidekiqデフォルト設定 |
| リトライ対象エラー | メール送信に関連するエラー |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | システム設定に従う |
| 1日あたり上限 | システム設定に従う |

### 配信時間帯

制限なし（24時間送信可能）

## セキュリティ考慮事項

- エラーメッセージには具体的なエラー詳細を含めず、一般的なメッセージのみ表示
- グループメンバーページへのリンクは適切な権限チェックがサーバー側で行われる

## 備考

- 本通知はCSV処理自体の失敗を報告するもので、個々の行の再割り当て失敗とは異なる
- 失敗時はアップロードされたCSVファイルが削除される

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: Workerの失敗ハンドリングを理解する

処理の起点と失敗時の挙動を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | assignment_from_csv_worker.rb | `app/workers/import/user_mapping/assignment_from_csv_worker.rb` | perform_failure、sidekiq_retries_exhausted |

**読解のコツ**: sidekiq_retries_exhaustedコールバックとperform_failureメソッドの関係に注目

**主要処理フロー**:
1. **12-14行目**: sidekiq_retries_exhaustedでperform_failureが呼ばれる
2. **20-25行目**: Uploadが見つからない場合にsend_failure_email
3. **37-39行目**: サービス失敗時にperform_failure呼び出し
4. **42-49行目**: perform_failureでsend_failure_emailを呼び出し

#### Step 2: メーラー実装を理解する

メール本文生成ロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | imports.rb | `app/mailers/emails/imports.rb` | csv_placeholder_reassignment_failedメソッド（87-96行目） |

**主要処理フロー**:
- **87-96行目**: シンプルな実装でグループ取得とメール送信

#### Step 3: テンプレートを理解する

メール本文テンプレートを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | csv_placeholder_reassignment_failed.text.erb | `app/views/notify/csv_placeholder_reassignment_failed.text.erb` | シンプルな本文 |

**主要処理フロー**:
- **1-5行目**: タイトル、説明文、リンクのみのシンプル構成

### プログラム呼び出し階層図

```
AssignmentFromCsvWorker#perform
    │
    ├─ Upload.find_by_id
    │      └─ (nil時) send_failure_email ──▶ Notify.csv_placeholder_reassignment_failed
    │
    └─ BulkReassignFromCsvService#execute
           │
           └─ (失敗時) perform_failure
                  │
                  ├─ send_failure_email
                  │      └─ Notify.csv_placeholder_reassignment_failed.deliver_later
                  │
                  └─ clear_upload
                         └─ upload.destroy!

sidekiq_retries_exhausted
    │
    └─ perform_failure (同上)
```

### データフロー図

```
[入力]                          [処理]                                    [出力]

CSVファイル（Upload） ────────▶ AssignmentFromCsvWorker
                                      │
                                      ▼
                               BulkReassignFromCsvService
                                      │
                               (失敗/例外)
                                      │
current_user_id ──────────────┬──────▼
group_id ─────────────────────┤ Notify.csv_placeholder_reassignment_failed ▶ メール送信
                              │                                              │
                              │                                              ▼
                              └──────────────────────────────────────▶ Upload削除
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| assignment_from_csv_worker.rb | `app/workers/import/user_mapping/assignment_from_csv_worker.rb` | ソース | CSV処理Worker、失敗ハンドリング |
| imports.rb | `app/mailers/emails/imports.rb` | ソース | メーラーメソッド定義 |
| csv_placeholder_reassignment_failed.text.erb | `app/views/notify/csv_placeholder_reassignment_failed.text.erb` | テンプレート | メール本文テンプレート |
| notify_preview.rb | `app/mailers/previews/notify_preview.rb` | プレビュー | メールプレビュー用 |
