# 機能設計書 63-GDPRリクエスト一覧

## 概要

本ドキュメントは、GDPRリクエスト一覧機能の設計仕様を定義する。GDPR（General Data Protection Regulation：EU一般データ保護規則）に基づくデータリクエストの一覧を表示し、ユーザーが自身のプライバシー権を行使するための機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：GDPRはEU域内のユーザーに対して、自身の個人データに関する権利（アクセス権、訂正権、削除権など）を保証している。ECサイトはこれらの権利に対応する必要があり、本機能はユーザーが過去に申請したGDPRリクエストの状況を確認できるようにする。

**機能の利用シーン**：
- ユーザーが過去に申請したデータリクエストの状況を確認したい場合
- データ削除や更新リクエストのステータス（処理中、完了、取消済み等）を追跡したい場合
- 新規リクエストの作成、既存リクエストの取消、データのエクスポートを行いたい場合

**主要な処理内容**：
1. 画面初期化時にGraphQL APIを呼び出し、GDPRリクエスト一覧を取得
2. リクエスト一覧をカード形式で表示（ID、ステータス、タイプ、メッセージ、日付）
3. 検索機能でリクエストIDによる絞り込み
4. 新規リクエスト作成、取消、PDF/HTMLエクスポートへのアクセスを提供

**関連システム・外部連携**：
- Bagisto GraphQL API（GDPRリクエスト一覧取得）
- url_launcher（HTMLエクスポート用外部ブラウザ起動）

**権限による制御**：ログイン済みユーザーのみアクセス可能。自身のリクエストのみ表示。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 33 | GDPRリクエスト画面 | 主画面 | GDPRデータリクエスト一覧表示 |

## 機能種別

データ取得・表示処理（READ操作）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| customerId | int | Yes（自動取得） | ログインユーザーのID | appStoragePrefから取得 |
| searchId | int | No | 検索対象のリクエストID | 数値のみ許可 |

### 入力データソース

- 自動取得: appStoragePref.getCustomerId()
- ユーザー入力: 検索バーからのリクエストID入力

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | String | リクエストID |
| customerId | String | 顧客ID |
| email | String | 顧客メールアドレス |
| status | String | リクエストステータス（pending/revoked等） |
| type | String | リクエストタイプ（DELETE/UPDATE） |
| message | String | リクエストメッセージ |
| revokedAt | String | 取消日時（取消済みの場合） |
| createdAt | String | 作成日時 |
| updatedAt | String | 更新日時 |

### 出力先

- GdprScreen画面にカード形式でリクエスト一覧表示

## 処理フロー

### 処理シーケンス

```
1. 画面初期化（initState）
   └─ GdprBlocにFetchGdprRequestsListを発行
   └─ appStoragePrefからcustomerEmailを取得
2. GdprBlocでイベント処理
   └─ GdprRepositoryのfetchGdprRequestsメソッドを呼び出し
3. APIクライアント呼び出し
   └─ GraphQL経由でgdprRequests queryを実行
4. レスポンス処理
   └─ GdprRequestModelにデシリアライズ
5. 状態更新
   └─ FetchGdprRequestsState.successを発行
6. UI更新
   └─ BlocConsumerで状態を監視し、リスト表示を更新
7. 各リクエストをCardウィジェットで表示
   └─ ID、ステータス、タイプ、メッセージ、日付を表示
```

### フローチャート

```mermaid
flowchart TD
    A[画面初期化] --> B[FetchGdprRequestsList発行]
    B --> C[GdprLoadingState]
    C --> D[GdprBloc.mapEventToState]
    D --> E[GdprRepository.fetchGdprRequests]
    E --> F[ApiClient.getGdprRequests]
    F --> G{API成功?}
    G -->|Yes| H[GdprRequestModel生成]
    G -->|No| I[FetchGdprRequestsState.fail]
    H --> J[FetchGdprRequestsState.success]
    J --> K[gdprRequestsリスト更新]
    K --> L[ListView.builderで一覧表示]
    I --> M[エラーメッセージ表示]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-63-01 | 認証必須 | ログイン済みユーザーのみアクセス可能 | 常時 |
| BR-63-02 | 自己データのみ | ユーザーは自身のリクエストのみ閲覧可能 | 常時 |
| BR-63-03 | 検索はID指定 | 検索機能はリクエストIDの完全一致のみ対応 | 検索時 |
| BR-63-04 | 空検索時全件表示 | 検索バーが空の場合は全件取得 | 検索時 |

### 計算ロジック

該当なし

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

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

本機能はGraphQL APIを通じてバックエンドのデータを読み取るのみで、クライアント側でのデータベース操作は行わない。

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| リクエスト一覧取得 | gdpr_requests（バックエンド） | SELECT | ログインユーザーのGDPRリクエスト一覧を取得 |

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

#### gdpr_requests（バックエンド）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | WHERE customer_id = ログインユーザーID | ページネーション対応 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | API通信エラー | ネットワーク接続失敗 | FetchGdprRequestsState.fail発行 |
| - | 認証エラー | 未ログイン状態でアクセス | ログイン画面へリダイレクト |
| - | 検索エラー | 無効なID形式で検索 | 「有効な数値IDを入力してください」SnackBar表示 |
| - | 検索結果なし | 該当IDのリクエストが存在しない | 空のリスト表示 |

### リトライ仕様

自動リトライは実装されていない。ユーザーは画面を再読み込みする必要がある。

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

読み取り専用のため、トランザクション制御は不要。

## パフォーマンス要件

- リクエスト一覧取得: 3秒以内
- ページネーション対応でデータ量増加時もパフォーマンス維持

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

- 認証必須（ログインユーザーのみ）
- 自身のデータのみアクセス可能（customerId制約）
- GDPRコンプライアンス対応機能

## 備考

- ステータス表示は大文字変換して表示
- REVOKED（取消済み）ステータスの場合、取消ボタンはグレーアウト

---

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

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

### 推奨読解順序

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

GDPRリクエストのデータ構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | gdpr_request_model.dart | `lib/data_model/gdpr_models/gdpr_request_model.dart` | GdprRequestModel、Datum、PaginatorInfoクラスの構造 |

**読解のコツ**:
- `@JsonSerializable()`アノテーションでJSONシリアライズを自動生成
- `data`リストに各リクエスト情報を格納
- **32-70行目**: Datumクラスでid、customerId、email、status、type、message、createdAt等を保持
- **72-97行目**: PaginatorInfoでページネーション情報を保持

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

処理の起点となる画面ファイルを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | gdpr_screen.dart | `lib/screens/gdpr/view/gdpr_screen.dart` | GdprScreenウィジェット、initStateでのイベント発行 |

**主要処理フロー**:
1. **20-23行目**: 状態変数（gdprBloc、customerEmail、gdprRequests）の定義
2. **26-31行目**: initStateでGdprBlocを取得し、FetchGdprRequestsListを発行
3. **48-129行目**: BlocConsumerでGdprStateを監視し、各状態に応じた処理
4. **50-64行目**: FetchGdprRequestsStateでリスト更新
5. **165-207行目**: 検索バーでID検索、空の場合は全件取得
6. **213-289行目**: ListView.builderでリクエスト一覧をカード表示

#### Step 3: イベント・状態管理を理解する

BLoCパターンによる状態管理の仕組みを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | gdpr_event.dart | `lib/screens/gdpr/bloc/gdpr_event.dart` | FetchGdprRequestsList、GdprSearchRequestの定義 |
| 3-2 | gdpr_state.dart | `lib/screens/gdpr/bloc/gdpr_state.dart` | GdprStatus列挙型、FetchGdprRequestsStateの定義 |
| 3-3 | gdpr_bloc.dart | `lib/screens/gdpr/bloc/gdpr_bloc.dart` | イベントからAPIを呼び出し、状態を発行する処理 |

**主要処理フロー**:
- **gdpr_event.dart 10行目**: FetchGdprRequestsListイベント（パラメータなし）
- **gdpr_event.dart 34-40行目**: GdprSearchRequestでIDを指定して検索
- **gdpr_state.dart 31-49行目**: FetchGdprRequestsStateでrequestsまたはerrorを保持
- **gdpr_bloc.dart 29-37行目**: FetchGdprRequestsListの処理でfetchGdprRequestsを呼び出し

#### Step 4: リポジトリ層を理解する

API呼び出しの抽象化層を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | gdpr_repository.dart | `lib/screens/gdpr/bloc/gdpr_repository.dart` | GdprRequestRepositoryインターフェースと実装 |

**主要処理フロー**:
- **7-8行目**: fetchGdprRequestsメソッド定義
- **17-27行目**: GdprRequestRepoでApiClient().getGdprRequests()を呼び出し

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

```
GdprScreen (gdpr_screen.dart)
    │
    ├─ initState
    │      └─ GdprBloc.add(FetchGdprRequestsList)
    │
    └─ BlocConsumer<GdprBloc, GdprState>
           │
           GdprBloc (gdpr_bloc.dart)
               │
               └─ mapEventToState
                      │
                      ├─ FetchGdprRequestsList
                      │      └─ GdprRepository.fetchGdprRequests
                      │              └─ ApiClient.getGdprRequests
                      │
                      └─ GdprSearchRequest
                             └─ GdprRepository.gdprSearchRequest
                                     └─ ApiClient.gdprSearchRequest
```

### データフロー図

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

customerId ───────▶ FetchGdprRequestsList ───────▶ GdprBloc
(自動取得)                                              │
                                                        ▼
                                               GdprRepository.fetchGdprRequests
                                                        │
                                                        ▼
                                               ApiClient.getGdprRequests
                                                        │
                                                        ▼
                                               GraphQL API (gdprRequests)
                                                        │
                                                        ▼
                                               GdprRequestModel ───▶ FetchGdprRequestsState
                                                                            │
                                                                            ▼
                                               gdprRequestsリスト更新 ───▶ Card一覧表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| gdpr_screen.dart | `lib/screens/gdpr/view/gdpr_screen.dart` | ソース | GDPRリクエスト一覧画面 |
| gdpr_bloc.dart | `lib/screens/gdpr/bloc/gdpr_bloc.dart` | ソース | 状態管理BLoC |
| gdpr_event.dart | `lib/screens/gdpr/bloc/gdpr_event.dart` | ソース | イベント定義 |
| gdpr_state.dart | `lib/screens/gdpr/bloc/gdpr_state.dart` | ソース | 状態定義 |
| gdpr_repository.dart | `lib/screens/gdpr/bloc/gdpr_repository.dart` | ソース | API呼び出しリポジトリ |
| gdpr_request_model.dart | `lib/data_model/gdpr_models/gdpr_request_model.dart` | ソース | リクエスト一覧データモデル |
| gdpr_request_search_model.dart | `lib/data_model/gdpr_models/gdpr_request_search_model.dart` | ソース | 検索結果データモデル |
| create_request.dart | `lib/screens/gdpr/view/widget/create_request.dart` | ソース | 新規リクエスト作成ダイアログ |
| api_client.dart | `lib/services/api_client.dart` | ソース | GraphQL APIクライアント |
| mutation_query.dart | `lib/services/mutation_query.dart` | ソース | GraphQLクエリ定義 |
