# 通知設計書 113-bulk_import_csv_user_mapping

## 概要

本ドキュメントは、GitLabにおけるCSVによるユーザーマッピング結果通知（bulk_import_csv_user_mapping）の設計仕様を記述する。

### 本通知の処理概要

CSVによるユーザーマッピング結果通知は、インポート後のプレースホルダーユーザーを実際のGitLabユーザーに一括で再割り当てするCSVアップロード処理の完了後に、処理結果を管理者に通知するメールを送信する。

**業務上の目的・背景**：大規模なプロジェクト移行では、多数のプレースホルダーユーザーが作成される。これらを手動で1件ずつ再割り当てするのは非効率であるため、CSVファイルによる一括再割り当て機能が提供されている。本通知により、一括処理の結果（成功件数、失敗件数、スキップ件数）を管理者に報告し、必要に応じてエラー対応を促す。

**通知の送信タイミング**：AssignmentFromCsvWorkerでのCSV処理が完了した時点で、非同期で送信される。

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

**通知内容の概要**：再割り当て処理の成功件数、失敗件数、スキップ件数を通知する。失敗がある場合は失敗詳細のCSVファイルが添付される。

**期待されるアクション**：受信者は結果を確認し、失敗した再割り当てについては添付CSVを参照して原因を特定し、修正後に再度CSVアップロードを行うか、手動で再割り当てを実施する。

## 通知種別

メール

## 送信仕様

### 基本情報

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

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

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

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | GitLabインスタンス設定に従う |
| 送信元名称 | GitLab |
| 件名（成功時） | `{group_name} | Placeholder reassignments completed successfully` |
| 件名（エラー時） | `{group_name} | Placeholder reassignments completed with errors` |
| 形式 | テキスト |

### 本文テンプレート

```
(エラーまたはスキップがある場合)
Placeholder reassignments completed with errors / Placeholder reassignments completed successfully

Items assigned to placeholder users have been reassigned to users in {group_name} according to the uploaded CSV file.

(エラーなしかつスキップなしの場合)
All items assigned to placeholder users have been reassigned to users in {group_name} according to the uploaded CSV file.

- {success_count} placeholder user(s) have been matched to user(s).
(エラーがある場合)
- {failed_count} placeholder user(s) have not been matched to user(s).
(スキップがある場合)
- {skipped_count} placeholder user(s) have been skipped.

(エラーがある場合)
A CSV file with a list of placeholder reassignment errors is attached to this email.

Review results: {group_members_url}
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| reassignment_failures_{date}.csv | CSV | failed_count > 0 | 再割り当て失敗の詳細一覧 |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| @group | 対象グループ | Group.find(group_id) | Yes |
| @success_count | 成功件数 | パラメータ | Yes |
| @failed_count | 失敗件数 | パラメータ（デフォルト0） | No |
| @skipped_count | スキップ件数 | パラメータ（デフォルト0） | No |
| @has_errors | エラーありフラグ | failed_count > 0 | Yes |
| @title | メールタイトル | エラー有無で分岐 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| バックグラウンドジョブ | AssignmentFromCsvWorker完了 | BulkReassignFromCsvServiceが成功した場合 | CSV処理完了後に送信 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| BulkReassignFromCsvServiceが失敗 | 処理自体が失敗した場合は別の通知（csv_placeholder_reassignment_failed）が送信される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[CSVアップロード] --> B[AssignmentFromCsvWorker起動]
    B --> C[BulkReassignFromCsvService実行]
    C --> D{処理結果}
    D -->|成功| E[send_results_email]
    D -->|失敗| F[send_failure_email]
    E --> G[統計情報取得]
    G --> H{エラーあり?}
    H -->|Yes| I[失敗CSVを添付]
    H -->|No| J[添付なし]
    I --> K[Notify.bulk_import_csv_user_mapping.deliver_later]
    J --> K
    K --> L[終了]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| groups | 対象グループ情報取得 | |
| users | 送信先ユーザー情報取得 | |
| import_source_users | 再割り当て対象の情報 | BulkReassignFromCsvService内で参照 |

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

#### groups

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

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| なし | - | 本通知処理自体ではDB更新は行わない |

## エラー処理

### エラーケース一覧

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

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

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

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

- 添付CSVにはユーザー情報が含まれる可能性があるため、送信先は処理実行者に限定
- グループメンバーページへのリンクはtab=placeholdersパラメータ付きで、適切な権限チェックがサーバー側で行われる

## 備考

- スキップされるケース：既に再割り当て済み、または再割り当て不要と判断されたプレースホルダー
- エラーがある場合、リンクURLにstatus=failedパラメータが追加され、失敗したもののみフィルタリング表示される

---

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

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

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、通知で使用されるデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | import_source_user.rb | `app/models/import/source_user.rb` | プレースホルダーユーザーの状態、再割り当て関連 |

**読解のコツ**: STATUSESの定義とスコープに注目

#### Step 2: Workerを理解する

処理の起点となるWorkerを確認する。

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

**主要処理フロー**:
1. **16-39行目**: performでCSV処理サービス呼び出しと結果判定
2. **55-68行目**: send_results_emailで統計情報を取得しメール送信

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

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

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

**主要処理フロー**:
- **55-85行目**: 各種カウント取得、タイトル分岐、添付ファイル処理

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

メール本文テンプレートの条件分岐を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | bulk_import_csv_user_mapping.text.erb | `app/views/notify/bulk_import_csv_user_mapping.text.erb` | 条件分岐によるメッセージ出し分け |

**主要処理フロー**:
- **3-7行目**: エラー/スキップ有無による本文分岐
- **9-15行目**: 各種カウント表示
- **17-22行目**: 添付ファイル説明とリンクURL

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

```
AssignmentFromCsvWorker#perform
    │
    ├─ UserFinder.new.find_by_id
    ├─ Group.find_by_id
    ├─ Upload.find_by_id
    │
    └─ BulkReassignFromCsvService#execute
           │
           ├─ (成功時) send_results_email
           │      │
           │      └─ Notify.bulk_import_csv_user_mapping.deliver_later
           │             │
           │             ├─ User.find
           │             ├─ Group.find
           │             ├─ タイトル決定（エラー有無）
           │             ├─ 添付ファイル作成（エラー時）
           │             │
           │             └─ email_with_layout
           │
           └─ (失敗時) send_failure_email
                  └─ Notify.csv_placeholder_reassignment_failed
```

### データフロー図

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

CSVファイル ─────────────────▶ BulkReassignFromCsvService
                                      │
                                      ▼
                               結果集計
                                      │
current_user_id ──────────────┬──────▼
group_id ─────────────────────┤ Notify.bulk_import_csv_user_mapping ───▶ メール送信
success_count ────────────────┤                                         │
failed_count ─────────────────┤                                         ├─ 添付CSV（エラー時）
skipped_count ────────────────┤                                         │
failures_csv_data ────────────┘                                         │
                                                                        ▼
                                                                   グループメンバーページ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| assignment_from_csv_worker.rb | `app/workers/import/user_mapping/assignment_from_csv_worker.rb` | ソース | CSV処理Worker |
| imports.rb | `app/mailers/emails/imports.rb` | ソース | メーラーメソッド定義 |
| bulk_import_csv_user_mapping.text.erb | `app/views/notify/bulk_import_csv_user_mapping.text.erb` | テンプレート | メール本文テンプレート |
| bulk_reassign_from_csv_service.rb | `app/services/import/source_users/bulk_reassign_from_csv_service.rb` | ソース | CSVによる一括再割り当てサービス |
| imports_spec.rb | `spec/mailers/emails/imports_spec.rb` | テスト | メーラーのテスト仕様 |
