# バッチ設計書 3-購読者一括インポート

## 概要

本ドキュメントは、QuickerSiteシステムにおける購読者一括インポートバッチの設計仕様を記載する。ニュースレター購読者をCSV形式で一括インポートする処理の仕様を定義する。

### 本バッチの処理概要

このバッチは、ニュースレター購読者リストにメールアドレスと名前のペアを一括でインポートする処理である。名前・メールアドレスのペア形式、またはメールアドレスのみの形式に対応している。また、テキストからメールアドレスを自動抽出する機能も提供している。

**業務上の目的・背景**：既存の顧客リストや外部ソースから取得したメールアドレスリストを、QuickerSiteのニュースレター購読者として一括登録するために必要なバッチ処理である。手作業で一件ずつ登録することは非効率であり、CSVやテキスト形式での一括インポートにより運用効率を向上させる。また、任意のテキストからメールアドレスを自動抽出する機能により、様々なデータソースからのインポートを容易にしている。

**バッチの実行タイミング**：管理者が管理画面から手動で実行する。新規購読者リストの入手時や、外部システムからの移行時に随時実行される。

**主要な処理内容**：
1. インポートデータの形式選択（名前,メール or メールのみ）
2. インポート先カテゴリの選択
3. テキストデータを改行で分割してループ処理
4. メールアドレスの構文チェック
5. 既存購読者との重複チェック
6. 新規購読者レコードの作成・保存
7. インポート結果のカウント表示

**前後の処理との関連**：前提としてニュースレターカテゴリの作成（bs_newsletterCategoryEdit.asp）が完了している必要がある。インポート後は購読者一覧（bs_newsletterSubscribers.asp）で確認可能。

**影響範囲**：tblNewsletterCategorySubscriberテーブルに影響。インポート後は当該カテゴリへのニュースレター配信対象となる。

## バッチ種別

データインポート

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 随時（手動実行） |
| 実行時刻 | 管理者操作時 |
| 実行曜日 | 該当なし |
| 実行日 | 該当なし |
| トリガー | 手動（管理画面から実行） |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| カテゴリ存在 | インポート先のニュースレターカテゴリが作成されていること |
| customer.bCanImportSubscribers | 購読者インポート権限が有効であること |
| secondAdmin.bNewsletter | ニュースレター管理権限を持つ管理者がログインしていること |

### 実行可否判定

- インポート先カテゴリが1つ以上選択されていること
- インポートデータが入力されていること

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| pairs | String（テキストエリア） | Yes | - | インポートデータ（改行区切り） |
| cat | String（複数選択可） | Yes | - | インポート先カテゴリID |
| importType | String | No | 1 | インポート形式（0:名前,メール、1:メールのみ） |
| bimportinactive | Boolean | No | false | 非アクティブとしてインポート |
| btnaction | String | Yes | - | 実行アクション（Import/Extract valid email addresses） |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| テキスト入力 | テキストエリア | 改行区切りの購読者データ |
| tblNewsletterCategory | DB | インポート先カテゴリ情報 |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| tblNewsletterCategorySubscriber | DB | 購読者レコード |

### 出力ファイル仕様

ファイル出力なし

| 項目 | 内容 |
|-----|------|
| ファイル名 | 該当なし |
| 出力先 | 該当なし |
| 文字コード | 該当なし |
| 区切り文字 | 該当なし |

## 処理フロー

### 処理シーケンス

```
1. 権限チェック
   └─ customer.bCanImportSubscribers、secondAdmin.bNewsletter
2. パラメータ検証
   └─ カテゴリ選択必須チェック
3. インポートデータ分割
   └─ vbcrlfで改行分割
4. カテゴリループ
   └─ 選択された各カテゴリに対してインポート
5. データループ
   └─ 各行に対して以下を実行
6. 形式に応じたパース
   └─ 名前,メール or メールのみ
7. メールアドレス検証
   └─ checkEmailSyntaxで構文チェック
8. 重複チェック
   └─ 同一カテゴリ・メールアドレスの既存レコード確認
9. レコード作成
   └─ 新規購読者レコードの挿入
10. 結果表示
    └─ インポート件数の表示
```

### フローチャート

```mermaid
flowchart TD
    A[バッチ開始] --> B[権限チェック]
    B --> C{権限あり?}
    C -->|なし| D[リダイレクト]
    C -->|あり| E[パラメータ取得]
    E --> F{カテゴリ選択あり?}
    F -->|なし| G[エラーメッセージ]
    F -->|あり| H[インポートデータ分割]
    H --> I[カテゴリループ開始]
    I --> J[データループ開始]
    J --> K{形式判定}
    K -->|0| L[名前,メール分割]
    K -->|1| M[メールのみ取得]
    L --> N{メール構文OK?}
    M --> N
    N -->|NG| O[スキップ]
    N -->|OK| P{重複チェック}
    P -->|重複あり| O
    P -->|新規| Q[レコード作成]
    Q --> R[カウンター増加]
    R --> O
    O --> S{次のデータあり?}
    S -->|あり| J
    S -->|なし| T{次のカテゴリあり?}
    T -->|あり| I
    T -->|なし| U[結果表示]
    U --> V[バッチ終了]
```

## データベース操作仕様

### 操作別データベース影響一覧

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 重複チェック | tblNewsletterCategorySubscriber | SELECT | 同一カテゴリ・メールアドレスの存在確認 |
| 購読者作成 | tblNewsletterCategorySubscriber | INSERT | 新規購読者レコードの作成 |

### テーブル別操作詳細

#### tblNewsletterCategorySubscriber

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | - | iCategoryID=指定カテゴリ AND sEmail=入力メールアドレス | 重複チェック |
| INSERT | sName | 入力された名前（形式0の場合） | 空文字の場合あり |
| INSERT | sEmail | 入力されたメールアドレス（小文字変換済み） | lcase()で変換 |
| INSERT | sKey | generatePassword×3 | 購読解除キー |
| INSERT | iCategoryID | 選択されたカテゴリID | - |
| INSERT | iCustomerID | cId | 顧客ID |
| INSERT | bActive | true/false | bimportinactiveの逆値 |
| INSERT | dAdded | date() | インポート日 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| err_mandatory | 必須エラー | カテゴリ未選択 | エラーメッセージ表示 |
| - | 構文エラー | 無効なメールアドレス | スキップして次のレコードへ |
| - | 解析エラー | カンマ区切りの分割失敗 | On Error Resume Nextで継続 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 該当なし |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

### 障害時対応

- エラー発生時：On Error Resume Nextでエラーをクリアし、次のレコードへ処理を継続
- 部分的なインポート成功の場合は成功件数のみ表示

## トランザクション仕様

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | レコード単位 |
| コミットタイミング | 各レコード挿入時に自動コミット |
| ロールバック条件 | 明示的なトランザクション管理なし |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 数百〜数千件 |
| 目標処理時間 | 同期処理のため画面応答時間内 |
| メモリ使用量上限 | arrPairs配列のサイズに依存 |

## 排他制御

- 重複チェックにより、同一カテゴリ内での同一メールアドレスの重複登録を防止
- 同時実行の明示的な排他制御なし

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 開始ログ | 該当なし | 明示的な開始ログなし |
| 進捗ログ | 該当なし | 明示的な進捗ログなし |
| 終了ログ | インポート完了時 | インポート件数（sCounter） |
| エラーログ | 該当なし | 明示的なエラーログなし |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| 処理時間 | 該当なし | 該当なし |
| エラー件数 | 該当なし | 該当なし |

## 備考

- メールアドレス抽出機能（Extract valid email addresses）はprivatebotクラスのquickSearchメソッドで実装
- メールアドレスは小文字に変換して保存（lcase()）
- sKeyはgeneratePassword×3で生成され、購読解除URLのパラメータとして使用
- 同一インポートで複数カテゴリを選択した場合、各カテゴリに同じ購読者が登録される
- bimportinactive=trueの場合、非アクティブ状態でインポートされ、配信対象外となる
