# 機能設計書 69-購読者管理

## 概要

本ドキュメントは、QuickerSite CMSの管理画面におけるニュースレター購読者管理機能の設計を定義する。

### 本機能の処理概要

購読者管理機能は、ニュースレターの購読者（メールリスト登録者）を一覧表示し、購読者情報の編集・削除・一括解除などの管理操作を提供する機能である。

**業務上の目的・背景**：ニュースレター配信において、購読者（メールアドレス登録者）の管理は重要な業務である。購読者の検索、有効/無効状態の確認、個別編集、一括削除、一括配信解除など、多様な管理操作が必要とされる。本機能は、メールリスト（カテゴリ）ごとに購読者を管理し、効率的な購読者管理を実現する。

**機能の利用シーン**：
- 購読者の一覧表示と検索
- 特定購読者の情報編集（名前、メールアドレス、有効状態）
- 購読者の個別削除または一括削除
- メールアドレスリストによる一括配信解除
- 購読者名の一括Proper Case変換
- カテゴリ（メールリスト）ごとのフィルタリング
- 有効/無効状態によるフィルタリング

**主要な処理内容**：
1. カテゴリごとの購読者一覧取得と表示
2. 名前・メールアドレスによる検索機能
3. 有効/無効状態によるフィルタリング
4. 選択した購読者の一括削除
5. メールアドレスリストによる一括配信解除
6. 購読者名のProper Case（先頭大文字）一括変換
7. 個別購読者の編集・削除

**関連システム・外部連携**：特になし（CMS内部機能）

**権限による制御**：セカンドアドミン権限のbNewsletterフラグによりアクセス制御される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 69a | 購読者一覧 | 主画面 | 購読者の一覧表示・検索・一括操作 |
| 69b | 購読者編集 | 詳細画面 | 個別購読者の編集・削除 |
| 67 | ニュースレター一覧 | 参照画面 | Newsletter homeリンク |
| 70 | 購読者インポート | 遷移先画面 | インポート画面への遷移 |

## 機能種別

データ一覧表示 / CRUD操作 / 一括処理

## 入力仕様

### 入力パラメータ（購読者一覧画面）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| iCategoryID | String (暗号化) | No | フィルタ対象カテゴリID | decrypt後にconvertGetal |
| sName | String | No | 名前検索キーワード | cleanup処理、最大50文字 |
| sEmail | String | No | メール検索キーワード | cleanup処理、最大50文字 |
| bActive | String | No | 有効状態フィルタ（""/i/b） | ""=有効のみ、i=無効のみ、b=両方 |
| deleteID | Array | No | 削除対象購読者ID配列 | 複数選択チェックボックス |
| unsubscribers | Text | No | 一括解除メールアドレスリスト | 改行区切り |
| pcase | String | No | Proper Case実行フラグ | "1"で実行 |

### 入力パラメータ（購読者編集画面）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| iSubscriptionID | String (暗号化) | Yes | 購読者ID | decrypt後にconvertGetal |
| sName | String | No | 購読者名 | 最大50文字 |
| sEmail | String | Yes | メールアドレス | メール形式検証、最大50文字 |
| bActive | Boolean | No | 有効フラグ | true/false |
| btnaction | String | Yes | アクション（保存/削除） | l("save")、l("delete") |

### 入力データソース

- データベーステーブル: tblNewsletterCategorySubscriber
- データベーステーブル: tblNewsletterCategory（カテゴリ情報）
- データベーステーブル: tblNewsletterLog（削除時の関連データ）
- セッション: 顧客ID（cId）

## 出力仕様

### 出力データ（購読者一覧画面）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| counter | Integer | 検索条件に合致する購読者総数 |
| sName | String | 購読者名 |
| sEmail | String | メールアドレス |
| bActive | Boolean | 有効/無効状態 |
| iCategoryID | Integer | カテゴリID |
| 編集リンク | HTML | 編集画面へのリンク |
| 削除チェックボックス | HTML | 一括削除用チェックボックス |

### 出力データ（購読者編集画面）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| sName | String | 購読者名 |
| sEmail | String | メールアドレス |
| bActive | Boolean | 有効状態 |
| カテゴリ名 | String | 所属カテゴリ名 |
| sKey | String | 配信解除用キー |
| dAdded | Date | 登録日 |

### 出力先

HTML画面（管理画面内）、データベース

## 処理フロー

### 処理シーケンス（購読者一覧画面）

```
1. アクセス権限チェック
   └─ secondAdmin.bNewsletter権限の確認
2. 検索条件の取得
   └─ sName、sEmail、bActive、iCategoryIDの取得
3. 一括削除処理
   └─ deleteID配列がある場合、選択された購読者を削除
   └─ tblNewsletterLog、tblNewsletterCategorySubscriberから削除
4. 購読者数のカウント
   └─ 検索条件に合致するレコード数を取得
5. Proper Case処理
   └─ pcase=1の場合、全購読者名をProper Caseに変換
6. 一括配信解除処理
   └─ unsubscribersがある場合、リストのメールをbActive=falseに更新
7. 購読者一覧の取得と表示
   └─ 最大2500件まで表示
8. 一括解除フォームの表示
   └─ カテゴリが選択されている場合のみ表示
```

### 処理シーケンス（購読者編集画面）

```
1. アクセス権限チェック
   └─ secondAdmin.bNewsletter権限の確認
2. 購読者データの読み込み
   └─ iSubscriptionIDで既存レコードを取得
   └─ レコードが存在しない場合は一覧画面へリダイレクト
3. 保存アクション処理
   └─ メール形式検証
   └─ 検証OK時はレコード更新、一覧画面へリダイレクト
4. 削除アクション処理
   └─ tblNewsletterLog、tblNewsletterCategorySubscriberから削除
   └─ 一覧画面へリダイレクト
5. 画面表示
   └─ 編集フォーム表示
```

### フローチャート（購読者一覧画面）

```mermaid
flowchart TD
    A[開始] --> B{bNewsletter権限あり?}
    B -->|No| C[アクセス拒否]
    B -->|Yes| D[検索条件取得]
    D --> E{deleteID配列あり?}
    E -->|Yes| F[選択購読者を削除]
    F --> G[購読者数カウント]
    E -->|No| G
    G --> H{pcase=1?}
    H -->|Yes| I[Proper Case変換実行]
    I --> J[一括解除処理]
    H -->|No| J
    J --> K{unsubscribersあり?}
    K -->|Yes| L[メールリストを無効化]
    L --> M[購読者一覧取得]
    K -->|No| M
    M --> N[一覧表示（最大2500件）]
    N --> O[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 権限チェック | セカンドアドミンはbNewsletter権限が必要 | 全アクセス時 |
| BR-002 | 顧客分離 | 自顧客の購読者のみ表示・操作可能 | 全操作時 |
| BR-003 | 表示上限 | 一覧表示は最大2500件まで | 一覧表示時 |
| BR-004 | メール形式検証 | 購読者編集時はメールアドレス形式をチェック | 保存時 |
| BR-005 | 関連データ削除 | 購読者削除時はtblNewsletterLogも削除 | 削除時 |
| BR-006 | デフォルトフィルタ | 初期状態では有効な購読者のみ表示 | 一覧表示時 |
| BR-007 | 単一カテゴリ自動選択 | カテゴリが1件のみの場合は自動選択 | 一覧表示時 |

### 計算ロジック

- Proper Case変換: 名前の先頭文字を大文字、残りを小文字に変換

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 一覧表示 | tblNewsletterCategorySubscriber | SELECT | 条件付き取得 |
| カウント | tblNewsletterCategorySubscriber | SELECT COUNT | 件数取得 |
| 個別編集 | tblNewsletterCategorySubscriber | UPDATE | レコード更新 |
| 個別削除 | tblNewsletterCategorySubscriber | DELETE | レコード削除 |
| 関連削除 | tblNewsletterLog | DELETE | 配信ログ削除 |
| 一括削除 | tblNewsletterCategorySubscriber | DELETE | 複数レコード削除 |
| 一括解除 | tblNewsletterCategorySubscriber | UPDATE | bActive=false |
| Proper Case | tblNewsletterCategorySubscriber | UPDATE | sName更新 |

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

#### tblNewsletterCategorySubscriber

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | iCategoryID、bActive、iCustomerID、sName LIKE、sEmail LIKE | sNameでソート |
| UPDATE | sEmail、sName、bActive | 入力値 | 個別編集 |
| UPDATE | bActive | false | 一括解除 |
| UPDATE | sName | PCase(sName) | Proper Case |
| DELETE | - | iId、iCustomerID条件 | 個別・一括削除 |

#### tblNewsletterLog

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | - | iSubscriberID条件 | 購読者削除時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 権限エラー | bNewsletter権限なし | アクセス拒否 |
| err_email | メール形式エラー | 不正なメールアドレス | エラーメッセージ表示 |
| - | データなし | 購読者レコードなし | 一覧画面へリダイレクト |
| - | 表示上限警告 | 2500件超過 | JavaScript警告表示 |

### リトライ仕様

メール形式エラー時は画面再表示、ユーザーによる再入力を促す

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

ADOのデフォルトトランザクション（自動コミット）を使用。一括削除は個別にDELETE実行。

## パフォーマンス要件

- 一覧表示: 3秒以内（2500件まで）
- 個別編集: 1秒以内
- 一括削除: 5秒以内
- Proper Case: 10秒以内（全件更新）

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

- セカンドアドミン権限によるアクセス制御
- IDパラメータの暗号化（encrypt/decrypt関数）
- SQLインジェクション対策（cleanup関数、replace関数によるエスケープ）
- JavaScript確認ダイアログによる誤操作防止
- フォーム入力値のquotRep関数によるエスケープ
- 顧客IDによるデータ分離

## 備考

- 一覧表示は最大2500件の制限があり、超過時はJavaScript警告を表示
- 検索機能により特定の購読者を絞り込み可能
- Proper Case機能は名前の表記を統一するための便利機能
- 一括解除機能は改行区切りのメールアドレスリストで処理
- カテゴリが1件のみの場合は自動的に選択される

---

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

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

### 推奨読解順序

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

まず、購読者のデータモデルを理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | newsletterSubscriber.asp | `asp/includes/newsletterSubscriber.asp` | cls_newsletterSubscriberクラスの構造（2-3行目） |
| 1-2 | newsletterCategory.asp | `asp/includes/newsletterCategory.asp` | cls_newsletterCategoryクラス、カテゴリ構造 |

**読解のコツ**: 購読者データはtblNewsletterCategorySubscriberテーブルに格納され、カテゴリ（メールリスト）に紐づく。

#### Step 2: 一覧画面のエントリーポイントを理解する

購読者一覧画面の処理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | bs_newsletterSubscribers.asp | `asp/bs_newsletterSubscribers.asp` | 一覧表示のメイン処理（1-136行目） |

**主要処理フロー**:
1. **4行目**: セキュリティチェック（logon.hasaccess secondAdmin.bNewsletter）
2. **14-24行目**: 検索条件・カテゴリID取得、単一カテゴリ自動選択
3. **27-35行目**: 一括削除処理（deleteID配列のループ）
4. **36-44行目**: bActiveフィルタSQL構築
5. **46-55行目**: 購読者数カウント
6. **56-67行目**: Proper Case処理
7. **68-75行目**: 一覧取得SQL構築
8. **78-95行目**: 一括解除処理（unsubscribers）
9. **104-117行目**: 一覧表示ループ（最大2500件）

#### Step 3: 編集画面のエントリーポイントを理解する

個別購読者編集画面の処理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | bs_newsletterSubscriber.asp | `asp/bs_newsletterSubscriber.asp` | 編集画面のメイン処理（1-28行目） |

**主要処理フロー**:
1. **4行目**: セキュリティチェック
2. **7-9行目**: 購読者データ読み込み、存在チェック
3. **11-23行目**: 保存処理（メール形式検証、UPDATE）
4. **24-27行目**: 削除処理（tblNewsletterLog、tblNewsletterCategorySubscriber）
5. **28行目**: 編集フォームHTML

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

```
bs_newsletterSubscribers.asp（一覧画面）
    │
    ├─ bs_security.asp
    │      └─ logon.hasaccess (権限チェック)
    │
    ├─ customer.NewsletterCategories
    │      └─ カテゴリ一覧取得
    │
    ├─ 一括削除処理
    │      └─ DELETE tblNewsletterLog
    │      └─ DELETE tblNewsletterCategorySubscriber
    │
    ├─ Proper Case処理
    │      └─ UPDATE tblNewsletterCategorySubscriber (sName)
    │
    └─ 一括解除処理
           └─ UPDATE tblNewsletterCategorySubscriber (bActive=false)

bs_newsletterSubscriber.asp（編集画面）
    │
    ├─ bs_security.asp
    │      └─ logon.hasaccess (権限チェック)
    │
    ├─ 購読者データ読み込み
    │      └─ SELECT tblNewsletterCategorySubscriber
    │
    ├─ 保存処理
    │      └─ checkEmailSyntax() (メール形式検証)
    │      └─ UPDATE tblNewsletterCategorySubscriber
    │
    └─ 削除処理
           └─ DELETE tblNewsletterLog
           └─ DELETE tblNewsletterCategorySubscriber
```

### データフロー図

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

検索条件 ───────▶ bs_newsletterSubscribers.asp ───▶ HTML一覧画面
(sName,sEmail,          │
bActive,iCategoryID)    │
                        ▼
deleteID配列 ───▶ DELETE処理 ───▶ tblNewsletterCategorySubscriber
                        │              tblNewsletterLog
                        ▼
unsubscribers ───▶ UPDATE処理 ───▶ bActive=false

フォーム入力 ───▶ bs_newsletterSubscriber.asp ───▶ 一覧画面（リダイレクト）
                        │
                        ▼
               checkEmailSyntax() ───▶ UPDATE/DELETE
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| bs_newsletterSubscribers.asp | `asp/bs_newsletterSubscribers.asp` | ソース | 購読者一覧画面のメイン処理 |
| bs_newsletterSubscriber.asp | `asp/bs_newsletterSubscriber.asp` | ソース | 購読者編集画面のメイン処理 |
| newsletterSubscriber.asp | `asp/includes/newsletterSubscriber.asp` | ソース | cls_newsletterSubscriberクラス定義 |
| newsletterCategory.asp | `asp/includes/newsletterCategory.asp` | ソース | cls_newsletterCategoryクラス定義 |
| customer.asp | `asp/includes/customer.asp` | ソース | NewsletterCategoriesプロパティ |
| bs_security.asp | `asp/bs_security.asp` | ソース | 権限チェック処理 |
| header.asp | `asp/includes/header.asp` | テンプレート | HTMLヘッダー |
| footer.asp | `asp/includes/footer.asp` | テンプレート | HTMLフッター |
