# 通知設計書 13-issues_csv_email

## 概要

本ドキュメントは、GitLabにおけるIssueのCSVエクスポート処理が完了した際に送信されるメール通知「issues_csv_email」の設計仕様を定義するものである。

### 本通知の処理概要

この通知は、ユーザーがIssueの一覧をCSV形式でエクスポートした際、処理完了後にCSVファイルを添付したメールを送信する機能である。

**業務上の目的・背景**：プロジェクト管理やレポーティングにおいて、Issue情報を外部ツール（Excel、BIツール等）で分析・加工したい場合がある。CSVエクスポート機能により、現在のIssue一覧を表形式でダウンロードできる。エクスポート処理は大量データの場合に時間がかかるため、非同期で処理し、完了後にメールで通知する仕組みとなっている。

**通知の送信タイミング**：CSVエクスポート処理が完了した直後に送信される。Issues::ExportCsvServiceのemailメソッドにより通知が発行される。なお、このメールはdeliver_now（同期送信）で送信される点が特徴的である。

**通知の受信者**：エクスポート操作を実行したユーザー本人のみが受信者となる。エクスポートはユーザーが明示的に開始する操作であり、その結果は操作者のみに通知される。

**通知内容の概要**：メールには、対象プロジェクト名、エクスポートされたIssue件数、サイズ制限によるトランケーション情報が含まれる。CSVファイルは添付ファイルとして送信される。

**期待されるアクション**：受信者は添付されたCSVファイルをダウンロードし、外部ツールで分析・加工を行う。トランケーションが発生した場合は、より狭い条件でフィルタリングして再エクスポートを検討する。

## 通知種別

メール通知

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（deliver_now） |
| 優先度 | 中 |
| リトライ | なし（同期送信のため） |

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

受信者はエクスポート操作を実行したユーザー本人のみ。`user.notification_email_for(@project.group)`により、プロジェクトのグループに対する通知用メールアドレスが使用される。

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | GitLabインスタンスのデフォルト送信元アドレス |
| 送信元名称 | GitLabインスタンス名 |
| 件名 | "{プロジェクト名} \| Exported issues" |
| 形式 | HTML/テキスト（マルチパート） |

### 本文テンプレート

**HTMLバージョン**
```html
Your CSV export of {count} issue(s) from project {project_link} has been added to this email as an attachment.

[トランケーションが発生した場合]
This attachment has been truncated to avoid exceeding the maximum allowed attachment size of {size_limit}. {written_count} of {count} issues have been included. Consider re-exporting with a narrower selection of issues.
```

**テキストバージョン**
```
Your CSV export of {count} issue(s) from project {project_name} ({project_url}) has been added to this email as an attachment.

[トランケーションが発生した場合]
This attachment has been truncated to avoid exceeding the maximum allowed attachment size of {size_limit}. {written_count} of {total_count} issues have been included. Consider re-exporting with a narrower selection of issues.
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| {project_path}_issues_{date}.csv | CSV | 常に添付 | エクスポートされたIssue一覧 |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| @project | 対象プロジェクト | ExportCsvService初期化時に設定 | Yes |
| @count | エクスポート対象の総Issue数 | export_status[:rows_expected] | Yes |
| @written_count | 実際にCSVに書き込まれたIssue数 | export_status[:rows_written] | Yes |
| @truncated | トランケーション発生フラグ | export_status[:truncated] | Yes |
| @size_limit | 最大添付ファイルサイズ（人間可読形式） | ExportCsv::BaseService::TARGET_FILESIZE | Yes |
| type | エクスポート種別（"issue"） | メソッド引数 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| バックグラウンドジョブ | CSVエクスポート処理完了 | エクスポート処理が正常に終了した場合 | ExportCsvWorkerからの呼び出し |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 特になし | エクスポート完了後は必ず結果通知が送信される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[CSVエクスポートリクエスト] --> B[ExportCsvWorker実行]
    B --> C[Issues::ExportCsvService初期化]
    C --> D[csv_data生成]
    D --> E[csv_builder.status取得]
    E --> F[emailメソッド呼び出し]
    F --> G[csv_emailメソッド実行]
    G --> H[添付ファイル設定]
    H --> I[email_with_layout]
    I --> J[deliver_now]
    J --> K[SMTP送信]
    K --> L[ユーザーメールボックスに配信]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| issues | エクスポート対象のIssue情報取得 | |
| users | ユーザー情報（作成者、担当者） | |
| projects | プロジェクト情報 | |
| namespaces | 名前空間情報 | |
| milestones | マイルストーン情報 | |
| labels | ラベル情報 | |
| timelogs | 作業時間情報 | |

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

#### issues

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | Issue識別子 | フィルタ条件に基づく |
| iid | プロジェクト内Issue番号 | CSV出力用 |
| title | タイトル | CSV出力用 |
| description | 説明 | CSV出力用 |
| state | 状態 | CSV出力用 |
| author_id | 作成者ID | CSV出力用 |
| confidential | 機密フラグ | CSV出力用 |
| due_date | 期限日 | CSV出力用 |
| created_at | 作成日時 | CSV出力用 |
| updated_at | 更新日時 | CSV出力用 |
| closed_at | クローズ日時 | CSV出力用 |
| time_estimate | 見積時間 | CSV出力用 |
| weight | 重み | CSV出力用 |

### 更新テーブル一覧

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

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 送信失敗 | SMTPサーバー接続失敗 | エクスポートジョブ全体の失敗として処理 |
| 添付ファイルサイズ超過 | CSVが最大サイズを超える | トランケーションが自動的に適用される |
| メモリ不足 | 大量のIssueエクスポート時 | バッチ処理により軽減 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし（同期送信） |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 特定のレート制限なし |
| 1日あたり上限 | 特定のレート制限なし |

### 配信時間帯

特定の時間帯制限なし（エクスポート完了後即時配信）

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

- エクスポート結果はエクスポート実行者本人のみに送信される
- CSVファイルにはIssueの詳細情報（機密Issue含む可能性）が含まれるため、メール傍受に注意が必要
- 機密Issueのエクスポート可否はエクスポート実行前の権限チェックで制御される
- 添付ファイルサイズはTARGET_FILESIZEで制限される

## 備考

- csv_emailメソッドはEmails::Sharedモジュールで共通化されており、issues_csv_emailはこれを呼び出すラッパー
- deliver_nowを使用しているため、エクスポートジョブのコンテキスト内で同期的に送信される
- 添付ファイル名は`{project_path}_issues_{date}.csv`形式でプロジェクトパスと日付を含む
- トランケーション時は実際に書き込まれた件数と期待された件数の両方が通知される

---

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

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

### 推奨読解順序

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

エクスポート結果のステータス構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | base_service.rb | `app/services/export_csv/base_service.rb` | export_statusの構造（:rows_expected, :rows_written, :truncated） |
| 1-2 | csv_builder.rb | `lib/gitlab/csv_builder.rb` | CSVビルダーの動作とステータス生成 |

**読解のコツ**: TARGET_FILESIZEがトランケーションの閾値となる。

#### Step 2: エントリーポイントを理解する

処理の起点となるExportCsvServiceを特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | export_csv_service.rb | `app/services/issues/export_csv_service.rb` | emailメソッド（14-16行目）でNotify.issues_csv_emailを呼び出し |

**主要処理フロー**:
1. **8-12行目**: コンストラクタでlabelsハッシュを初期化
2. **14-16行目**: `email(mail_to_user)` - メール送信メソッド
3. **15行目**: `Notify.issues_csv_email(mail_to_user, resource_parent, csv_data, csv_builder.status).deliver_now`

#### Step 3: メーラーモジュールを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | issues.rb | `app/mailers/emails/issues.rb` | issues_csv_emailメソッド（177-179行目） |
| 3-2 | shared.rb | `app/mailers/emails/shared.rb` | csv_emailメソッド（5-18行目）共通処理 |

**主要処理フロー**:
- **issues.rb 177-179行目**: `csv_email(user, project, csv_data, export_status, 'issues')` を呼び出し
- **shared.rb 5-18行目**: 添付ファイル設定、email_with_layout呼び出し

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | issues_csv_email.html.haml | `app/views/notify/issues_csv_email.html.haml` | パーシャル呼び出しのみ |
| 4-2 | _issuable_csv_export.html.haml | `app/views/notify/_issuable_csv_export.html.haml` | HTML形式の共通テンプレート |
| 4-3 | issues_csv_email.text.erb | `app/views/notify/issues_csv_email.text.erb` | パーシャル呼び出しのみ |
| 4-4 | _issuable_csv_export.text.erb | `app/views/notify/_issuable_csv_export.text.erb` | テキスト形式の共通テンプレート |

**主要処理フロー**:
- **html 1行目**: `render 'issuable_csv_export', type: :issue` でパーシャル呼び出し
- **パーシャル 5行目**: プロジェクトリンクとエクスポート完了メッセージ
- **パーシャル 6-8行目**: トランケーション時の警告メッセージ

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

```
[UI/API] CSVエクスポートリクエスト
    |
    └── ExportCsvWorker (Sidekiq)
            |
            └── Issues::ExportCsvService
                    |
                    ├── #initialize
                    |       └── labels_hash生成
                    |
                    ├── #csv_data (基底クラス)
                    |       └── CsvBuilder#render
                    |
                    └── #email(mail_to_user)
                            |
                            └── Notify.issues_csv_email
                                    |
                                    ├── csv_email (Emails::Shared)
                                    |       ├── attachments設定
                                    |       └── email_with_layout
                                    |
                                    └── deliver_now
                                            |
                                            └── SMTP送信
```

### データフロー図

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

Issue一覧           ──┐
                    ├──▶ ExportCsvService     ──▶ CSV生成
User               ──┤           │
                    │           ▼
Project            ──┤    csv_builder.status
                    │           │
                    │           ├── :rows_expected
                    │           ├── :rows_written
                    │           └── :truncated
                    │           │
                    │           ▼
                    └──▶ Notify.issues_csv_email
                                │
                                ├── 添付ファイル（CSV）
                                │
                                └──▶ ActionMailer::Base#mail
                                            │
                                            ▼
                                      SMTPサーバー ──▶ ユーザーメールボックス
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| export_csv_service.rb | `app/services/issues/export_csv_service.rb` | ソース | CSVエクスポートサービス |
| base_service.rb | `app/services/export_csv/base_service.rb` | ソース | エクスポートサービス基底クラス |
| issues.rb | `app/mailers/emails/issues.rb` | ソース | Issue関連メール生成モジュール |
| shared.rb | `app/mailers/emails/shared.rb` | ソース | 共通メール処理モジュール |
| issues_csv_email.html.haml | `app/views/notify/issues_csv_email.html.haml` | テンプレート | HTML形式メールテンプレート |
| issues_csv_email.text.erb | `app/views/notify/issues_csv_email.text.erb` | テンプレート | テキスト形式メールテンプレート |
| _issuable_csv_export.html.haml | `app/views/notify/_issuable_csv_export.html.haml` | テンプレート | 共通HTMLパーシャル |
| _issuable_csv_export.text.erb | `app/views/notify/_issuable_csv_export.text.erb` | テンプレート | 共通テキストパーシャル |
| csv_builder.rb | `lib/gitlab/csv_builder.rb` | ソース | CSVビルダーライブラリ |
