# 通知設計書 79-group_was_exported_email

## 概要

本ドキュメントは、グループのエクスポートが成功した際に送信されるメール通知 `group_was_exported_email` の設計仕様を定義する。

### 本通知の処理概要

本通知は、GitLabグループのエクスポート処理が正常に完了したことをユーザーに通知するメール機能を提供する。

**業務上の目的・背景**：グループのエクスポートは、グループとその設定を別のGitLabインスタンスに移行したり、バックアップを取得したりするための重要な機能である。エクスポート処理は非同期で実行され、完了までに時間がかかる可能性があるため、処理完了をユーザーに通知することで、ユーザーはエクスポートファイルのダウンロードやインポート作業を開始できる。

**通知の送信タイミング**：グループエクスポートサービス（`Groups::ImportExport::ExportService`）がエクスポート処理を正常に完了した直後に送信される。

**通知の受信者**：エクスポート処理を開始したユーザー（current_user）に送信される。ユーザーはグループに対する管理者権限（admin_group）を持っている必要がある。

**通知内容の概要**：エクスポートが正常に完了したこと、ダウンロードリンク、およびダウンロードリンクの有効期限（24時間）を含む成功通知メールである。

**期待されるアクション**：受信者は24時間以内にエクスポートファイルをダウンロードし、必要に応じて別のGitLabインスタンスへのインポートやバックアップ保存を行う。

## 通知種別

メール通知

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（deliver_later） |
| 優先度 | 中 |
| リトライ | Sidekiqのデフォルトリトライ機構に従う |

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

エクスポート処理を開始したユーザー（`current_user`パラメータ）の通知用メールアドレスに送信される。メールアドレスは `current_user.notification_email_for(group)` メソッドで決定される。

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | GitLabのデフォルト送信元アドレス |
| 送信元名称 | GitLab |
| 件名 | `[Group Name] Group was exported` |
| 形式 | HTML/テキスト |

### 本文テンプレート

```html
<p>
  Group {group_name} was exported successfully.
</p>

<p>
  The group export can be downloaded from:
  <a href="{download_export_url}" rel="nofollow" download>
    {group_full_name} export
  </a>
</p>

<p>
  The download link will expire in 24 hours.
</p>
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| なし | - | - | 添付ファイルなし（ダウンロードリンクを提供） |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| @group | 対象グループ | パラメータから取得 | Yes |
| @group.name | グループ名 | Group.name | Yes |
| @group.full_name | グループフルパス | Group.full_name | Yes |
| download_export_group_url | ダウンロードURL | URL helper | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| バックグラウンドジョブ | GroupExportWorker完了 | エクスポート処理が正常終了 | サービス内でnotify_successを呼び出し |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| ユーザーが通知不可 | notifiable?がfalseの場合（通知設定等） |
| エクスポート失敗 | エクスポート処理が失敗した場合（別の通知が送られる） |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ユーザーがグループエクスポートをリクエスト] --> B[GroupExportWorkerをキューに追加]
    B --> C[ワーカーがExportService.execute実行]
    C --> D[権限チェック]
    D --> E{権限あり?}
    E -->|No| F[エラー通知処理へ]
    E -->|Yes| G[既存エクスポートファイル削除]
    G --> H[エクスポート処理実行]
    H --> I{処理成功?}
    I -->|No| J[エラー通知処理へ]
    I -->|Yes| K[監査ログ記録]
    K --> L[NotificationService.group_was_exported呼び出し]
    L --> M{ユーザーが通知可能?}
    M -->|No| N[終了]
    M -->|Yes| O[成功通知メール送信]
    O --> P[終了]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| namespaces (groups) | グループ情報取得 | 名前、パス |
| users | ユーザー情報取得 | 通知先メールアドレス |
| import_export_uploads | エクスポートファイル情報 | ダウンロードURL生成用 |

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

#### namespaces

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | グループ識別 | パラメータで指定されたgroup_id |
| name | グループ名表示 | メール本文に使用 |
| path | グループパス | URLに使用 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| import_export_uploads | INSERT/UPDATE | エクスポートファイルの保存 |
| audit_events | INSERT | エクスポート操作の監査ログ |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 送信失敗 | SMTPサーバー接続エラー | Sidekiqによるリトライ |
| 宛先不正 | ユーザーのメールアドレスが無効 | エラーログ記録、送信スキップ |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | Sidekiqデフォルト |
| リトライ間隔 | 指数バックオフ |
| リトライ対象エラー | 一時的なネットワークエラー等 |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | GitLabのデフォルト設定に従う |
| 1日あたり上限 | GitLabのデフォルト設定に従う |

### 配信時間帯

特に制限なし。エクスポート完了時に即時送信される。

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

- ダウンロードリンクは24時間で有効期限切れになる
- ダウンロードリンクはエクスポートを実行したユーザーのみがアクセス可能
- エクスポートファイルにはグループの設定情報が含まれるため、リンクの取り扱いに注意が必要
- サイレント管理者エクスポート（silent_admin_exports_enabled）の場合、監査ログはスキップされる

## 備考

- エクスポートファイルは24時間で自動削除される
- エクスポート処理失敗時は別途 `group_was_not_exported_email` が送信される
- エクスポートにはグループの管理者権限が必要

---

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

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

### 推奨読解順序

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

まず、通知に必要なデータモデルを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | group.rb | `app/models/group.rb` | グループモデルの構造 |
| 1-2 | user.rb | `app/models/user.rb` | ユーザーモデル、notification_email_for メソッド |

**読解のコツ**: グループのname、full_name、path属性の違いを理解する。

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

エクスポート処理を行うサービスクラスを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | export_service.rb | `app/services/groups/import_export/export_service.rb` | エクスポートサービスの全体構造 |

**主要処理フロー**:
- **23-31行目**: executeメソッドで権限チェック、既存ファイル削除、エクスポート実行
- **53-63行目**: save!メソッドでエクスポーターの実行と通知
- **128-131行目**: notify_successメソッドでNotificationService呼び出し

#### Step 3: 通知サービスを理解する

通知の送信ロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | notification_service.rb | `app/services/notification_service.rb` | group_was_exportedメソッド（684-688行目） |

**主要処理フロー**:
- **684-688行目**: notifiable?チェック後、メーラーを呼び出す

#### Step 4: メーラーを理解する

実際のメール生成処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | groups.rb | `app/mailers/emails/groups.rb` | group_was_exported_emailメソッド（7-9行目） |
| 4-2 | groups.rb | `app/mailers/emails/groups.rb` | group_emailヘルパーメソッド（15-19行目） |

**主要処理フロー**:
- **7-9行目**: group_emailヘルパーを呼び出して「Group was exported」件名でメール送信
- **15-19行目**: @groupを設定し、mail_with_localeでメール送信

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | group_was_exported_email.html.haml | `app/views/notify/group_was_exported_email.html.haml` | HTML本文の構造 |

**テンプレート内容**:
- **1-2行目**: エクスポート成功メッセージ
- **4-7行目**: ダウンロードリンク
- **8-9行目**: 有効期限の説明

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

```
ユーザーリクエスト
    │
    └─ GroupExportWorker#perform
           │
           └─ Groups::ImportExport::ExportService#execute
                  │
                  ├─ validate_user_permissions
                  │
                  ├─ remove_existing_export!
                  │
                  ├─ save!
                  │      ├─ save_exporters (VersionSaver, TreeSaver)
                  │      ├─ file_saver.save
                  │      ├─ audit_export
                  │      └─ notify_success
                  │             │
                  │             └─ NotificationService#group_was_exported
                  │                    │
                  │                    └─ notifiable? チェック
                  │                           │
                  │                           └─ Notify#group_was_exported_email
                  │                                  └─ mail_with_locale
                  │
                  └─ remove_archive_tmp_dir
```

### データフロー図

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

group_id ──────────▶ ExportService ───────────────────▶ メール送信
current_user                   │
params                         ├─ VersionSaver
                               │      └─ バージョン情報保存
                               │
                               ├─ TreeSaver
                               │      └─ グループツリー保存
                               │
                               ├─ Saver
                               │      └─ アーカイブ作成
                               │
                               └─ NotificationService
                                      └─ メール送信
                                             ├─ グループ名
                                             ├─ ダウンロードURL
                                             └─ 有効期限案内
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| export_service.rb | `app/services/groups/import_export/export_service.rb` | ソース | エクスポート実行サービス |
| notification_service.rb | `app/services/notification_service.rb` | ソース | 通知送信サービス |
| groups.rb | `app/mailers/emails/groups.rb` | ソース | メール生成メーラー |
| group_was_exported_email.html.haml | `app/views/notify/group_was_exported_email.html.haml` | テンプレート | HTML本文テンプレート |
| group_export_worker.rb | `app/workers/group_export_worker.rb` | ソース | バックグラウンドジョブ |
