# 通知設計書 118-import_work_items_csv_email

## 概要

本ドキュメントは、GitLabにおけるWork Item CSVインポート結果通知（import_work_items_csv_email）の設計仕様を記述する。

### 本通知の処理概要

Work Item CSVインポート結果通知は、CSVファイルからWork Itemを一括インポートした結果を、インポートを実行したユーザーに対して通知するメールを送信する。

**業務上の目的・背景**：プロジェクト管理においてWork Item（Issue、Task、Epicなど）を大量に作成する際、CSVファイルによる一括インポートは効率的な方法である。本通知により、インポート処理の結果（成功件数、エラー件数、エラー詳細）をユーザーに報告し、必要な修正や再インポートを促す。

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

**通知の受信者**：インポートを実行したユーザーに送信される。

**通知内容の概要**：インポート成功件数、エラー発生行、エラー種別（タイプエラー、パースエラー、その他エラー）の詳細を通知する。

**期待されるアクション**：受信者はインポート結果を確認し、エラーがある場合はCSVファイルを修正して再インポートを行う。

## 通知種別

メール

## 送信仕様

### 基本情報

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

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

インポートを実行したユーザーのnotification_email_for(project.group)に送信される。

## 通知テンプレート

### メール通知の場合

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

### 本文テンプレート

```
Here are the results for your CSV import for {project_name} ({project_url}).

(成功件数 > 0 の場合)
{success_count} work item(s) successfully imported.

(成功件数 = 0 の場合)
No work items have been imported.

(パースエラーの場合)
Error parsing CSV file. Please make sure it has the correct format: a delimited text file that uses a comma to separate values.

(タイプエラーがある場合)
Some values in the "type" column could not be matched with supported work item types:

(空のタイプの場合)
Line(s) {lines}: Work item type is empty.

(存在しないタイプの場合)
Line(s) {lines}: Work item type cannot be found or is not supported.

(許可されていないタイプの場合)
Line(s) {lines}: Work item type is not available. Please check your license and permissions.

(その他エラーがある場合)
Errors found on line(s): {error_lines}. Please check that these lines have the following fields: {required_headers}.

(エラーがある場合)
Please fix the lines with errors and try the CSV import again.
```

### 添付ファイル

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

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| @user | インポート実行ユーザー | User.find(user_id) | Yes |
| @project | 対象プロジェクト | Project.find(project_id) | Yes |
| @results | インポート結果ハッシュ | サービスから渡される | Yes |
| success_lines | 成功件数 | @results[:success] | Yes |
| type_errors | タイプエラー情報 | @results[:type_errors] | No |
| error_lines | エラー行一覧 | @results[:error_lines] | No |
| parse_error | パースエラーフラグ | @results[:parse_error] | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| サービス呼び出し | email_results_to_user | 常に送信 | ImportCsvService完了後に送信 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| なし | インポート結果に関わらず常に通知が送信される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[CSVインポート開始] --> B[ImportCsvService実行]
    B --> C[各行の処理]
    C --> D[結果の集計]
    D --> E[email_results_to_user呼び出し]
    E --> F[Notify.import_work_items_csv_email.deliver_later]
    F --> G[終了]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| projects | 対象プロジェクト情報取得 | |
| users | インポート実行ユーザー情報取得 | |
| work_item_types | 利用可能なワークアイテムタイプ確認 | |

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

#### projects

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | プロジェクト特定 | Project.find(project_id) |
| name | プロジェクト名表示 | |
| full_name | プロジェクトフルパス | |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| issues/work_items | INSERT | CSVからのWork Item作成（サービス側で実施） |

## エラー処理

### エラーケース一覧

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

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

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

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

- CSVインポートは適切な権限（import_work_items）を持つユーザーのみ実行可能
- エラーメッセージには行番号のみを表示し、CSVの内容自体は含めない

## 備考

- required_headersはWorkItems::ImportCsvService.required_headersから取得される
- タイプエラーは複数種類（blank、missing、disallowed）に分類される

---

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

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

### 推奨読解順序

#### Step 1: サービス層を理解する

インポート処理のサービスと結果構造を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | import_csv_service.rb | `app/services/work_items/import_csv_service.rb` | email_results_to_user、results構造、type_errors |

**読解のコツ**: resultsハッシュの構造（:success、:type_errors、:error_lines、:parse_error）に注目

**主要処理フロー**:
1. **30-32行目**: email_results_to_userでメール送信
2. **17-21行目**: type_errorsの初期化（blank、missing、disallowed）
3. **63-85行目**: preprocess!でタイプエラーの検出

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | work_items.rb | `app/mailers/emails/work_items.rb` | import_work_items_csv_emailメソッド |

**主要処理フロー**:
- **5-13行目**: ユーザー、プロジェクト、結果の取得とメール送信

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | import_work_items_csv_email.text.erb | `app/views/notify/import_work_items_csv_email.text.erb` | 各種エラーの条件分岐 |

**主要処理フロー**:
- **1行目**: プロジェクト情報表示
- **3-13行目**: 成功件数とパースエラー処理
- **15-35行目**: タイプエラー処理（blank、missing、disallowed）
- **37-43行目**: その他エラー処理
- **45-47行目**: エラー時の再インポート案内

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

```
WorkItems::ImportCsvService#execute
    │
    ├─ preprocess!
    │      └─ type_errorsの収集
    │
    ├─ 各行の処理
    │      └─ create_object
    │
    └─ email_results_to_user
           │
           └─ Notify.import_work_items_csv_email.deliver_later
                  │
                  ├─ User.find
                  ├─ Project.find
                  │
                  └─ email_with_layout
```

### データフロー図

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

CSVファイル ──────────────────▶ ImportCsvService
                                      │
                                      ├─ preprocess! ─────────▶ type_errors
                                      │
                                      ├─ 各行処理 ────────────▶ success count
                                      │                        error_lines
                                      │
                                      └─ email_results_to_user
                                             │
user_id ──────────────────────┬────────────▼
project_id ───────────────────┤ Notify.import_work_items_csv_email ──▶ メール送信
results ──────────────────────┤
    ├─ :success ──────────────┤
    ├─ :type_errors ──────────┤
    │      ├─ :blank ─────────┤
    │      ├─ :missing ───────┤
    │      └─ :disallowed ────┤
    ├─ :error_lines ──────────┤
    └─ :parse_error ──────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| import_csv_service.rb | `app/services/work_items/import_csv_service.rb` | ソース | CSVインポートサービス |
| work_items.rb | `app/mailers/emails/work_items.rb` | ソース | メーラーメソッド定義 |
| import_work_items_csv_email.text.erb | `app/views/notify/import_work_items_csv_email.text.erb` | テンプレート | メール本文テンプレート |
| base_service.rb | `app/services/issuable/import_csv/base_service.rb` | ソース | CSVインポートの基底クラス |
