# 通知設計書 12-インポート完了メール

## 概要

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

### 本通知の処理概要

本通知は、ユーザーがアップロードしたエクスポートZIPファイルからのデータインポート処理がバックグラウンドジョブで正常に完了した際に自動送信されるメール通知である。

**業務上の目的・背景**：データインポートは、別のFizzyアカウントからエクスポートしたデータを新しいアカウントに取り込む機能である。この処理は大量のデータを扱うため時間がかかり、ユーザーが画面を離れても確実に完了を通知する必要がある。また、インポートしたアカウントへのアクセスURLを提供することで、ユーザーがスムーズに作業を再開できるようにする。

**通知の送信タイミング**：Account::DataImportJobがインポート処理を完了し、Account::Importモデルのstatusがcompletedになったタイミングで送信される。具体的には、Account::Import#processメソッド内でmark_completedが呼ばれ、その中でImportMailer.completed(identity, account).deliver_laterが実行される。

**通知の受信者**：インポートを要求したユーザーのIdentityに紐づくメールアドレスに送信される。インポートを開始したユーザーは必ずしも既存のユーザーではなく、新規アカウント作成時にインポートを行う場合もあるため、UserではなくIdentityを直接参照する。

**通知内容の概要**：メール本文には、インポートが完了した旨のメッセージ、インポート先アカウントの名前、およびアカウントへのアクセスURLが含まれる。

**期待されるアクション**：ユーザーはメール内のリンクをクリックし、インポートしたアカウントにアクセスして作業を開始する。インポートされたボードやカードなどのデータを確認し、必要に応じて設定を調整する。

## 通知種別

メール通知

## 送信仕様

### 基本情報

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

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

インポートを要求したユーザーのIdentityに紐づくメールアドレスに送信される。送信先は引数として渡される`identity.email_address`で決定される。

## 通知テンプレート

### メール通知の場合

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

### 本文テンプレート

#### HTML版

```html
<p class="subtitle">Your import of {{account_name}} is complete!</p>

<p><a href="{{account_url}}">Go to your account</a></p>

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

#### テキスト版

```
Your import of {{account_name}} is complete!

Here's the URL: {{account_url}}
```

### 添付ファイル

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

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| @account | インポート先アカウント | 引数account | Yes |
| @account.name | アカウント名 | accounts.name | Yes |
| @account.slug | アカウントスラグ | Account#slug | Yes |
| landing_url | アカウントトップページURL | routes | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| バッチ | Account::DataImportJobの完了 | インポート処理が正常完了 | Account::Import#mark_completed内で送信 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| インポート処理失敗 | statusがfailedの場合は別のメール（失敗通知）が送信される |
| ConflictError | 既存アカウントとの競合時は失敗通知 |
| IntegrityError | データ整合性エラー時は失敗通知 |
| InvalidFileError | 無効なZIPファイル時は失敗通知 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ユーザーがインポートファイルをアップロード] --> B[Account::Import作成 status=pending]
    B --> C[Account::DataImportJob.perform_later]
    C --> D[import.check実行]
    D --> E{チェック結果}
    E -->|OK| F[import.process実行]
    E -->|NG| G[mark_as_failed]
    F --> H[データインポート処理]
    H --> I[add_importer_to_all_access_boards]
    I --> J[reconcile処理]
    J --> K[mark_completed status=completed]
    K --> L[ImportMailer.completed.deliver_later]
    L --> M[メール送信キューに追加]
    M --> N[メール送信実行]
    G --> O[ImportMailer.failed.deliver_later]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| account_imports | インポート情報取得 | ステータス管理 |
| accounts | インポート先アカウント情報 | 名前、スラグ取得 |
| identities | メールアドレス取得 | 送信先決定 |

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

#### accounts

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| id | アカウント識別 | 引数で渡される |
| name | アカウント名表示 | メール本文で使用 |
| external_account_id | スラグ生成 | Account#slug |

#### identities

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| email_address | 送信先メールアドレス | 引数で渡される |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| account_imports | UPDATE | status, completed_at更新 |

#### account_imports更新

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| UPDATE | status | completed | 完了ステータス |
| UPDATE | completed_at | Time.current | 完了日時 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 送信失敗 | SMTPエラー等 | Active Jobによるリトライ |
| 宛先不正 | メールアドレス形式不正 | 送信エラーとしてログ記録 |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

特に制限なし（インポート完了時に即座に送信）

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

- アカウントURLにはアカウントスラグが含まれ、認証されたユーザーのみがアクセス可能
- インポート完了後、インポーターは自動的にall_accessボードへのアクセス権限が付与される
- 失敗したインポートは7日後に自動削除される（Account::Import.cleanup）
- メールアドレスはIdentityテーブルで管理され、認証済みのアドレスのみ使用

## 備考

- インポート元のZIPファイルは、処理完了後24時間で削除される（completed_atから24時間後）
- 失敗したインポートの場合、関連するアカウントも自動削除される（Account::Import#cleanup）
- インポート処理はActiveJob::Continuableを使用して、中断・再開に対応している

---

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

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

### 推奨読解順序

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | account/import.rb | `app/models/account/import.rb` | インポートモデル。status管理、check/process処理、メール送信トリガーを理解 |

**読解のコツ**: enumで定義されたstatus（pending, processing, completed, failed）とfailure_reason（conflict, invalid_export）の遷移を理解する。mark_completedメソッド（行72-75）がメール送信のトリガーポイント。

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

インポート処理の起点となるジョブを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | account/data_import_job.rb | `app/jobs/account/data_import_job.rb` | バックグラウンドジョブの起点。ActiveJob::Continuableを使用したステップ処理 |

**主要処理フロー**:
1. **行8-11**: `step :check` - インポートデータの整合性チェック
2. **行14-17**: `step :process` - 実際のインポート処理

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | import_mailer.rb | `app/mailers/import_mailer.rb` | メーラークラス。completedメソッドとfailedメソッドを確認 |

**主要処理フロー**:
- **行2-5（import_mailer.rb）**: completedメソッドでidentityとaccountを受け取り、メール送信

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

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

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

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

```
ユーザー操作（インポートファイルアップロード）
    │
    ├─ Account::Import.create!
    │      └─ import.process_later
    │              └─ Account::DataImportJob.perform_later(import)
    │
    └─ [非同期] Account::DataImportJob#perform
           ├─ step :check
           │      └─ import.check
           │             └─ ZIPファイル検証
           │
           └─ step :process
                  └─ import.process
                         ├─ データインポート
                         ├─ add_importer_to_all_access_boards
                         ├─ reconcile_cards_count
                         ├─ reconcile_account_storage
                         └─ mark_completed
                                └─ ImportMailer.completed(identity, account).deliver_later
                                       └─ [非同期] メール送信
```

### データフロー図

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

ZIPファイル ───▶ Account::Import(pending)
                       │
                       ▼
               Account::DataImportJob
                       │
                       ├─▶ check (検証)
                       │
                       ├─▶ process (インポート)
                       │
                       ▼
               mark_completed ───▶ Account::Import(completed)
                       │
                       ▼
               ImportMailer.completed
                       │
                       ▼
               完了メール ───▶ ユーザーのメールボックス
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| account/import.rb | `app/models/account/import.rb` | ソース | インポートモデル |
| account/data_import_job.rb | `app/jobs/account/data_import_job.rb` | ソース | インポートジョブ |
| import_mailer.rb | `app/mailers/import_mailer.rb` | ソース | インポートメーラー |
| application_mailer.rb | `app/mailers/application_mailer.rb` | ソース | 基底メーラー |
| completed.html.erb | `app/views/mailers/import_mailer/completed.html.erb` | テンプレート | HTML版メール本文 |
| completed.text.erb | `app/views/mailers/import_mailer/completed.text.erb` | テンプレート | テキスト版メール本文 |
| import_mailer_test.rb | `test/mailers/import_mailer_test.rb` | テスト | メーラーテスト |
