# 機能設計書 3-サインアップ

## 概要

本ドキュメントは、ECモバイルアプリケーションにおけるサインアップ（新規ユーザー登録）機能の設計仕様を定義する。メールアドレス、名前、パスワードを入力して新規アカウントを作成し、登録完了後は自動的にログイン状態となる。

### 本機能の処理概要

**業務上の目的・背景**：ECサイトにおいて、新規顧客を獲得しリピート購入を促進するためには、ユーザーアカウントの作成が不可欠である。本機能は、新規ユーザーが簡単にアカウントを作成できるインターフェースを提供し、登録完了後は即座にサービスを利用開始できるようにする。

**機能の利用シーン**：初めてアプリを利用するユーザーがサインイン画面から「アカウント作成」ボタンをタップした際に利用される。また、ゲストとして商品閲覧後、購入手続きに進む際にアカウント作成を促される場合にも利用される。

**主要な処理内容**：
1. ユーザー情報（名、姓、メール、パスワード、確認パスワード）の入力
2. 入力値のバリデーション（必須チェック、メール形式、パスワード一致等）
3. ニュースレター購読オプションの選択
4. 利用規約同意チェック
5. GraphQL APIを通じた新規ユーザー登録リクエスト
6. 登録成功時のアクセストークン取得とローカル保存
7. ホーム画面への自動遷移

**関連システム・外部連携**：Bagisto（Laravel製ECプラットフォーム）のGraphQL APIと連携し、customerSignUp mutationを呼び出す。FCMデバイストークンも登録時に送信される。

**権限による制御**：本機能は未ログインユーザーが利用可能。登録完了後は顧客権限でアプリ内機能にアクセスできるようになる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 5 | サインアップ画面 | 主画面 | ユーザー情報入力、アカウント作成ボタン押下 |
| 2 | ホーム画面 | 遷移先画面 | サインアップ成功後の遷移先 |
| 4 | サインイン画面 | 参照画面 | サインアップ画面への遷移元 |

## 機能種別

データ登録 / バリデーション / API連携 / 認証処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| firstName | String | Yes | ユーザーの名 | 空でないこと |
| lastName | String | Yes | ユーザーの姓 | 空でないこと |
| email | String | Yes | メールアドレス | 空でないこと、有効なメール形式 |
| password | String | Yes | パスワード | 空でないこと、6文字以上 |
| passwordConfirmation | String | Yes | 確認パスワード | 空でないこと、6文字以上、passwordと一致 |
| subscribedToNewsLetter | bool | No | ニュースレター購読フラグ | デフォルトfalse |
| agreement | bool | Yes | 利用規約同意フラグ | trueであること |
| deviceToken | String | No | FCMデバイストークン | GlobalData.fcmTokenから自動取得 |
| deviceName | String | No | デバイス名 | GlobalData.deviceNameから自動取得 |

### 入力データソース

- 画面入力：SignUpScreen上のTextEditingControllerから取得
- チェックボックス：NewsLetterCheckboxウィジェットから取得

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| success | bool | 登録成功フラグ |
| message | String | 処理結果メッセージ |
| accessToken | String | API認証用アクセストークン |
| tokenType | String | トークン種別（Bearer等） |
| expiresIn | int | トークン有効期限（秒） |
| customer.id | String | 顧客ID |
| customer.name | String | 顧客フルネーム |
| customer.email | String | 顧客メールアドレス |
| customer.apiToken | String | APIトークン |
| customer.token | String | 顧客トークン |

### 出力先

- SharedPreferences：顧客情報（ログイン状態、名前、メール、トークン、ID）
- 画面遷移：成功時はホーム画面へ遷移

## 処理フロー

### 処理シーケンス

```
1. ユーザーが必要情報を入力
   └─ 各TextEditingControllerで値を保持

2. 利用規約同意チェック
   └─ agreementがfalseの場合、エラー表示

3. アカウント作成ボタン押下
   └─ _signUpFormKey.currentState!.validate()でバリデーション実行

4. バリデーション成功時、ローディングダイアログ表示
   └─ showDialog()で表示

5. FetchSignUpEventをSignUpBlocへ送信
   └─ signUpBloc?.add(FetchSignUpEvent(...))

6. SignUpBlocがSignUpRepositoryを通じてAPI呼び出し
   └─ repository!.callSignUpApi(...)

7. ApiClientがGraphQL mutationを実行
   └─ mutation.customerRegister(...)

8. レスポンス処理
   └─ 成功: FetchSignUpState.success発行
   └─ 失敗: FetchSignUpState.fail発行

9. 成功時、1秒後にユーザー情報を保存
   └─ _updateSharedPreferences()

10. ホーム画面へ遷移
    └─ Navigator.of(context).pushNamedAndRemoveUntil(home, ...)
```

### フローチャート

```mermaid
flowchart TD
    A[サインアップ画面表示] --> B[ユーザー情報入力]
    B --> C{利用規約同意?}
    C -->|No| D[エラーメッセージ表示]
    D --> B
    C -->|Yes| E{バリデーション}
    E -->|失敗| F[入力エラー表示]
    F --> B
    E -->|成功| G[ローディング表示]
    G --> H[GraphQL API呼び出し]
    H --> I{登録結果}
    I -->|失敗| J[エラー通知表示]
    J --> K[ダイアログ閉じる]
    K --> B
    I -->|成功| L[ユーザー情報保存]
    L --> M[成功通知表示]
    M --> N[ホーム画面へ遷移]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | メール形式検証 | 入力されたメールアドレスは有効な形式である必要がある | メールアドレス入力時 |
| BR-002 | パスワード長検証 | パスワードは6文字以上である必要がある | パスワード入力時 |
| BR-003 | パスワード一致検証 | パスワードと確認パスワードは一致する必要がある | 確認パスワード入力時 |
| BR-004 | 利用規約同意必須 | 利用規約に同意しないとアカウント作成不可 | アカウント作成ボタン押下時 |
| BR-005 | 登録後自動ログイン | アカウント登録成功後は自動的にログイン状態となる | 登録成功時 |
| BR-006 | 登録成功時の自動遷移 | 登録成功後1秒待機してからホーム画面へ遷移 | 登録成功時 |

### 計算ロジック

本機能に計算ロジックは存在しない。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| アカウント作成 | customers | INSERT | 新規顧客レコード作成 |
| トークン生成 | oauth_access_tokens | INSERT | アクセストークンの生成・保存 |
| ニュースレター登録 | subscribers | INSERT | ニュースレター購読者登録（オプション） |

※上記はバックエンド側（Bagisto）での操作。モバイルアプリ側ではSharedPreferencesへの書き込みのみ。

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

#### SharedPreferences（ローカルストレージ）

| 操作 | 項目（キー名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| WRITE | customerLoggedIn | true | ログイン状態フラグ |
| WRITE | customerName | SignInModel.data.name | 顧客名 |
| WRITE | customerEmail | SignInModel.data.email | 顧客メール |
| WRITE | customerToken | "${tokenType} ${token}" | 認証トークン |
| WRITE | customerId | SignInModel.data.id | 顧客ID |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | バリデーションエラー | 名が空 | 入力フォームにエラーメッセージ表示 |
| - | バリデーションエラー | 姓が空 | 入力フォームにエラーメッセージ表示 |
| - | バリデーションエラー | メールアドレスが空または不正形式 | 入力フォームにエラーメッセージ表示 |
| - | バリデーションエラー | パスワードが空または6文字未満 | 入力フォームにエラーメッセージ表示 |
| - | バリデーションエラー | パスワードと確認パスワードが不一致 | 入力フォームにエラーメッセージ表示 |
| - | 同意エラー | 利用規約未同意 | チェックボックス下にエラーメッセージ表示 |
| - | 登録エラー | メールアドレス重複 | ShowMessage.errorNotificationでエラー表示 |
| - | ネットワークエラー | API通信失敗 | ShowMessage.errorNotificationでエラー表示 |

### リトライ仕様

本機能にリトライ処理は実装されていない。ユーザーは手動で再度サインアップを試行する必要がある。

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

モバイルアプリ側ではトランザクション管理は行わない。バックエンド側でアカウント作成とトークン生成が一連の処理として実行される。

## パフォーマンス要件

- API応答時間：3秒以内（ローディングダイアログ表示中）
- ネットワークタイムアウト：graphql_flutterのデフォルト設定に準拠

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

- パスワードはGraphQL mutation内で平文送信されるが、HTTPS通信により暗号化される
- パスワードはバックエンド側でハッシュ化して保存される
- アクセストークンはSharedPreferencesに保存（暗号化なし）
- パスワード表示/非表示の切り替えUIを提供してショルダーハッキング対策

## 備考

- 本機能はサインイン機能と同じSignInModelをレスポンスモデルとして使用
- ニュースレター購読はオプション（デフォルトOFF）
- 利用規約同意は必須

---

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

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

### 推奨読解順序

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

サインイン機能と同じデータモデルを使用。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | signin_model.dart | `lib/data_model/sign_in_model/signin_model.dart` | SignInModelクラスでサインアップのレスポンス構造も同様に処理 |

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | sign_up.dart | `lib/screens/sign_up/view/sign_up.dart` | UI構築とユーザー操作のハンドリング |

**主要処理フロー**:
1. **31-44行目**: TextEditingController定義と状態変数
2. **47-51行目**: initStateでBlocの取得
3. **70-99行目**: BlocConsumerによる状態監視とUI更新
4. **122-305行目**: サインアップフォームUI構築
5. **308-357行目**: アカウント作成ボタン押下時の処理（_onPressCreateAccount）
6. **360-367行目**: SharedPreferences更新処理

#### Step 3: ウィジェットを理解する

ニュースレターチェックボックスウィジェットを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | news_letter_checkbox.dart | `lib/screens/sign_up/widgets/news_letter_checkbox.dart` | チェックボックスUIとコールバック処理 |

#### Step 4: ビジネスロジックを理解する

Blocでのイベント処理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | sign_up_bloc.dart | `lib/screens/sign_up/bloc/sign_up_bloc.dart` | FetchSignUpEvent処理とState発行 |
| 4-2 | sign_up_event.dart | `lib/screens/sign_up/bloc/sign_up_event.dart` | イベント定義 |
| 4-3 | sign_up_state.dart | `lib/screens/sign_up/bloc/sign_up_state.dart` | 状態定義 |

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | sign_up_repository.dart | `lib/screens/sign_up/bloc/sign_up_repository.dart` | callSignUpApiメソッドでApiClientを呼び出し |

#### Step 6: API通信層を理解する

GraphQL通信の実装を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | api_client.dart | `lib/services/api_client.dart` | getSignUpDataメソッド（670-697行目）でmutationを実行 |
| 6-2 | mutation_query.dart | `lib/services/mutation_query.dart` | customerRegisterメソッド（918-955行目）でGraphQL mutation文字列を生成 |

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

```
SignUpScreen (View)
    │
    ├─ NewsLetterCheckbox (Widget)
    │
    ├─ SignUpBloc (Business Logic)
    │      │
    │      └─ SignUpRepositoryImp (Repository)
    │             │
    │             └─ ApiClient (API Layer)
    │                    │
    │                    └─ GraphQlApiCalling (GraphQL Client)
    │                           │
    │                           └─ MutationsData.customerRegister() (Query Builder)
    │
    └─ appStoragePref (Local Storage)
           └─ SharedPreferences
```

### データフロー図

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

firstName, lastName,
email, password,     ───▶ SignUpScreen
confirmPassword,           │
newsLetter, agreement      ▼
                    FetchSignUpEvent ───▶ SignUpBloc
                                          │
                                          ▼
                                  SignUpRepository
                                          │
                                          ▼
                                      ApiClient ───▶ GraphQL API
                                          │
                                          ▼
                                   SignInModel
                                          │
                                          ▼
                  FetchSignUpState.success ───▶ SignUpScreen
                                               │
                                               ▼
                                        appStoragePref ───▶ SharedPreferences
                                               │
                                               ▼
                                        Navigator.pushNamedAndRemoveUntil(home)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| sign_up.dart | `lib/screens/sign_up/view/sign_up.dart` | ソース | サインアップ画面UI |
| sign_up_bloc.dart | `lib/screens/sign_up/bloc/sign_up_bloc.dart` | ソース | 状態管理Bloc |
| sign_up_event.dart | `lib/screens/sign_up/bloc/sign_up_event.dart` | ソース | イベント定義 |
| sign_up_state.dart | `lib/screens/sign_up/bloc/sign_up_state.dart` | ソース | 状態定義 |
| sign_up_repository.dart | `lib/screens/sign_up/bloc/sign_up_repository.dart` | ソース | リポジトリ層 |
| news_letter_checkbox.dart | `lib/screens/sign_up/widgets/news_letter_checkbox.dart` | ソース | ニュースレターチェックボックス |
| signin_model.dart | `lib/data_model/sign_in_model/signin_model.dart` | ソース | データモデル |
| api_client.dart | `lib/services/api_client.dart` | ソース | API通信クライアント |
| mutation_query.dart | `lib/services/mutation_query.dart` | ソース | GraphQLクエリ定義 |
| index.dart | `lib/screens/sign_up/utils/index.dart` | ソース | エクスポート集約 |
