# 通知設計書 11-エクスポート完了メール

## 概要

本ドキュメントは、Fizzyアプリケーションにおけるエクスポート完了メール通知の設計仕様を定義する。データエクスポート処理が完了した際に、エクスポートを要求したユーザーに対してダウンロードリンクを含む通知メールを送信する機能について記載する。

### 本通知の処理概要

本通知は、ユーザーがリクエストしたデータエクスポート（アカウントエクスポートまたはユーザーデータエクスポート）がバックグラウンドジョブで処理完了した際に自動送信されるメール通知である。

**業務上の目的・背景**：データエクスポートは大量のデータをZIPファイルに圧縮する処理であり、リクエスト即時には完了しない。ユーザーが画面を離れても確実にエクスポート完了を知らせ、スムーズにダウンロードできるようにするため、メール通知が必要となる。また、GDPR等のデータポータビリティ要件への対応として、ユーザーが自身のデータを取得できることを保証する重要な機能である。

**通知の送信タイミング**：DataExportJobがエクスポート処理を完了し、Exportモデルのstatusがcompletedになったタイミングで送信される。具体的には、Export#buildメソッド内でmark_completedが呼ばれた直後に、ExportMailer.completed(self).deliver_laterが実行される。

**通知の受信者**：エクスポートを要求したユーザー（export.user）のメールアドレス（user.identity.email_address）に送信される。エクスポートには2種類あり、アカウント全体のエクスポート（Account::Export）とユーザー個人データのエクスポート（User::DataExport）がある。いずれの場合もエクスポートを作成したユーザーに送信される。

**通知内容の概要**：メール本文には、エクスポートが完了した旨のメッセージと、ダウンロードリンクが含まれる。ダウンロードリンクはエクスポートの種類によって異なるURL（アカウントエクスポートの場合はaccount_export_url、ユーザーデータエクスポートの場合はuser_data_export_url）が生成される。

**期待されるアクション**：ユーザーはメール内のダウンロードリンクをクリックし、エクスポートされたZIPファイルをダウンロードする。エクスポートファイルは24時間後に自動削除されるため、速やかなダウンロードが推奨される。

## 通知種別

メール通知

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（deliver_later） |
| 優先度 | 中（backendキュー） |
| リトライ | Active Jobのデフォルト設定に従う |

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

エクスポートを要求したユーザー（export.user）のIdentityに紐づくメールアドレスに送信される。送信先は`@user.identity.email_address`で決定される。

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | 環境変数MAILER_FROM_ADDRESSまたはデフォルト値 |
| 送信元名称 | Fizzy |
| 件名 | Your Fizzy data export is ready for download |
| 形式 | HTML/テキスト（マルチパート） |

### 本文テンプレート

#### HTML版

```html
<h1 class="title">Download your Fizzy data</h1>
<p class="subtitle">Your Fizzy data export has finished processing and is ready to download.</p>

<p><a href="{{download_url}}">Download your data</a></p>

<p class="footer">Need help? <a href="mailto:support@fizzy.do">Send us an email</a>.</p>
```

#### テキスト版

```
Your Fizzy data export has finished processing and is ready to download.

Download your data: {{download_url}}
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| なし | - | - | エクスポートデータは添付せず、ダウンロードリンクを提供 |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| @export | エクスポートオブジェクト | Export / Account::Export / User::DataExport | Yes |
| @user | エクスポート要求ユーザー | export.user | Yes |
| export_download_url | ダウンロードURL | export_mailer.rb#export_download_url | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| バッチ | DataExportJobの完了 | エクスポート処理が正常完了 | Export#build内でmark_completed後に送信 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| エクスポート処理失敗 | statusがfailedの場合は送信されない |
| ActiveJob::DeserializationError | ジョブ実行時にデシリアライズエラーが発生した場合はジョブ自体が破棄される |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ユーザーがエクスポート要求] --> B[Export作成 status=pending]
    B --> C[DataExportJob.perform_later]
    C --> D[Export#build実行]
    D --> E[ZIPファイル生成]
    E --> F[mark_completed status=completed]
    F --> G[ExportMailer.completed.deliver_later]
    G --> H[メール送信キューに追加]
    H --> I[メール送信実行]
    I --> J{送信結果}
    J -->|成功| K[送信完了]
    J -->|失敗| L[リトライ/エラー処理]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| exports | エクスポート情報取得 | STIでAccount::ExportまたはUser::DataExportとして利用 |
| users | エクスポート要求ユーザー情報 | export.userで取得 |
| identities | メールアドレス取得 | user.identityで取得 |

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

#### exports

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | エクスポート識別 | 引数で渡される |
| user_id | ユーザー特定 | belongs_to関連 |
| account_id | アカウント特定 | belongs_to関連 |
| type | エクスポート種別判定 | STI識別用 |
| status | 状態確認 | completed時のみ送信 |

#### users

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | ユーザー識別 | export.user |
| identity_id | Identity取得 | belongs_to関連 |

#### identities

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| email_address | 送信先メールアドレス | user.identity |

### 更新テーブル一覧

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

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 送信失敗 | SMTPエラー等 | Active Jobによるリトライ |
| デシリアライズエラー | エクスポートレコード削除後にジョブ実行 | ジョブ破棄（discard_on設定） |
| 宛先不正 | メールアドレス形式不正 | 送信エラーとしてログ記録 |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 特に制限なし |
| 1日あたり上限 | 特に制限なし |

### 配信時間帯

特に制限なし（エクスポート完了時に即座に送信）

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

- ダウンロードURLにはアカウントスラグが含まれ、認証されたユーザーのみがアクセス可能
- Export#accessible_to?メソッドにより、エクスポート作成者のみがダウンロード可能
- エクスポートファイルは24時間後に自動削除される（Export.cleanup）
- メールアドレスはIdentityテーブルで管理され、ユーザー認証済みのアドレスのみ使用

## 備考

- アカウントエクスポートとユーザーデータエクスポートで同じメーラーを使用するが、ダウンロードURLが異なる
- エクスポートファイル名はエクスポート種別により異なる（fizzy-account-{account_id}-export-{id}.zip または fizzy-user-data-export-{id}.zip）

---

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

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

### 推奨読解順序

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

まず、エクスポート機能で使用されるモデルの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | export.rb | `app/models/export.rb` | エクスポートの基底クラス。status管理、build処理、メール送信トリガーを理解 |
| 1-2 | account/export.rb | `app/models/account/export.rb` | アカウントエクスポートの具体実装。filenameとpopulate_zipを確認 |
| 1-3 | user/data_export.rb | `app/models/user/data_export.rb` | ユーザーデータエクスポートの具体実装 |

**読解のコツ**: RailsのSTI（Single Table Inheritance）パターンを使用している。基底クラスExportの処理フローを先に理解し、その後サブクラスの差分を確認する。

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

エクスポート処理の起点となるジョブを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | data_export_job.rb | `app/jobs/data_export_job.rb` | バックグラウンドジョブの起点。export.buildを呼び出す |

**主要処理フロー**:
1. **行7**: `export.build` - Exportモデルのbuildメソッドを呼び出し

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

メール送信処理の実装を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | export_mailer.rb | `app/mailers/export_mailer.rb` | メーラークラス。completedメソッドとexport_download_urlヘルパーを確認 |
| 3-2 | application_mailer.rb | `app/mailers/application_mailer.rb` | 基底メーラー。送信元アドレス設定を確認 |

**主要処理フロー**:
- **行4-9（export_mailer.rb）**: completedメソッドでエクスポートとユーザー情報を設定し、メール送信
- **行12-18（export_mailer.rb）**: export_download_urlでエクスポート種別に応じたURL生成

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | completed.html.erb | `app/views/mailers/export_mailer/completed.html.erb` | HTML版テンプレート |
| 4-2 | completed.text.erb | `app/views/mailers/export_mailer/completed.text.erb` | テキスト版テンプレート |

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

```
ユーザー操作（エクスポート要求）
    │
    ├─ Export.create! / Account::Export.create! / User::DataExport.create!
    │      └─ export.build_later
    │              └─ DataExportJob.perform_later(export)
    │
    └─ [非同期] DataExportJob#perform
           └─ export.build
                  ├─ processing!
                  ├─ ZipFile.create_for
                  │      └─ populate_zip (サブクラス実装)
                  ├─ mark_completed
                  │      └─ update!(status: :completed)
                  └─ ExportMailer.completed(self).deliver_later
                         └─ [非同期] メール送信
```

### データフロー図

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

Export(pending)  ───▶ DataExportJob
                           │
                           ▼
                      Export#build
                           │
                           ├─▶ ZIPファイル生成
                           │
                           ▼
                      mark_completed ───▶ Export(completed)
                           │
                           ▼
                      ExportMailer
                           │
                           ▼
                      完了メール ───▶ ユーザーのメールボックス
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| export.rb | `app/models/export.rb` | ソース | エクスポート基底モデル |
| account/export.rb | `app/models/account/export.rb` | ソース | アカウントエクスポートモデル |
| user/data_export.rb | `app/models/user/data_export.rb` | ソース | ユーザーデータエクスポートモデル |
| data_export_job.rb | `app/jobs/data_export_job.rb` | ソース | エクスポートジョブ |
| export_mailer.rb | `app/mailers/export_mailer.rb` | ソース | エクスポートメーラー |
| application_mailer.rb | `app/mailers/application_mailer.rb` | ソース | 基底メーラー |
| completed.html.erb | `app/views/mailers/export_mailer/completed.html.erb` | テンプレート | HTML版メール本文 |
| completed.text.erb | `app/views/mailers/export_mailer/completed.text.erb` | テンプレート | テキスト版メール本文 |
| export_mailer_test.rb | `test/mailers/export_mailer_test.rb` | テスト | メーラーテスト |
