# 画面設計書 4-サインイン画面

## 概要

本ドキュメントは、Bagisto eコマースモバイルアプリのサインイン画面に関する設計書です。ユーザー認証を行うための画面であり、メールアドレスとパスワードによる通常ログイン、ソーシャルログイン、生体認証（指紋認証）によるログインをサポートします。

### 本画面の処理概要

**業務上の目的・背景**：サインイン画面は、ユーザーがアプリケーションにログインするための認証画面です。eコマースアプリにおいて、カート内容の保持、注文履歴の確認、ウィッシュリスト機能などのパーソナライズされた機能を利用するために必要な認証プロセスを提供します。セキュアな認証を確保しつつ、指紋認証などの便利なログイン方法も提供することで、ユーザビリティを向上させています。

**画面へのアクセス方法**：
- ホーム画面からの遷移（未ログイン状態での操作時）
- ドロワーメニューの「サインイン」をタップ
- カート・ウィッシュリスト等の操作時の認証要求
- スプラッシュ画面から（未ログイン時）

**主要な操作・処理内容**：
1. メールアドレスの入力とバリデーション
2. パスワードの入力（表示/非表示切り替え可能）
3. サインインボタン押下によるログイン処理
4. パスワードを忘れた場合のリンクからパスワード再設定画面へ遷移
5. 新規アカウント作成リンクからサインアップ画面へ遷移
6. 指紋認証によるログイン（設定済みの場合）
7. ソーシャルログイン（外部サービス連携）

**画面遷移**：
- 遷移元：ホーム画面、スプラッシュ画面、各種認証要求画面
- 遷移先：ホーム画面（ログイン成功後）、サインアップ画面、パスワード再設定画面

**権限による表示制御**：
- 指紋認証エリア：過去に指紋認証を設定したユーザーのみ表示
- デモ用のメール・パスワードがデフォルト入力される（開発/デモ環境用）

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | サインイン | 主機能 | メールアドレスとパスワードによるユーザーログイン処理 |
| 2 | ソーシャルログイン | 補助機能 | 外部サービス（SNS等）を利用したログイン処理 |

## 画面種別

認証画面（ログイン）

## URL/ルーティング

- ルート名: `signIn`
- パス: `/signin`

## 入出力項目

| 項目名 | 入出力 | データ型 | 必須 | バリデーション | 説明 |
|--------|--------|----------|------|----------------|------|
| メールアドレス | 入力 | String | Yes | 必須、メール形式 | ログイン用メールアドレス |
| パスワード | 入力 | String | Yes | 必須、6文字以上 | ログイン用パスワード |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|----------|------|
| 画面タイトル | String | 「Sign in with Email」 |
| メールアドレス入力フィールド | TextField | メールアドレス入力欄 |
| パスワード入力フィールド | TextField | パスワード入力欄（マスク表示切り替え可能） |
| パスワード表示/非表示アイコン | IconButton | パスワードの表示状態を切り替え |
| パスワードを忘れた場合リンク | GestureDetector | パスワード再設定画面へのリンク |
| サインインボタン | MaterialButton | ログイン実行ボタン |
| アカウント作成ボタン | MaterialButton | サインアップ画面へのボタン |
| 指紋認証アニメーション | LottieBuilder | 指紋認証用のアニメーション（設定済みユーザーのみ） |
| ローディングダイアログ | Dialog | 処理中に表示されるダイアログ |

## イベント仕様

### 1-画面初期化イベント（initState）

**トリガー**: 画面がマウントされたタイミング

**処理フロー**:
1. `SignInBloc`をcontext.readで取得
2. デモ用のメール・パスワードをControllerにセット

### 2-サインインボタン押下イベント

**トリガー**: 「SIGN IN」ボタンタップ

**処理フロー**:
1. `_signInFormKey.currentState!.validate()`でフォームバリデーション
2. バリデーション成功時：
   - `showLoadingDialog()`でローディングダイアログ表示
   - `SignInBloc`に`FetchSignInEvent`を送信（email, password, fingerPrint: false）
3. API応答処理：
   - 成功時：
     - SharedPreferencesに認証情報を保存（ログイン状態、名前、メール、トークン、ID、画像）
     - 成功メッセージを表示
     - 3秒後にホーム画面へ遷移（pushNamedAndRemoveUntil）
   - 失敗時：
     - ダイアログを閉じる
     - エラーメッセージを表示

### 3-パスワードを忘れた場合リンクタップイベント

**トリガー**: 「Forget Password?」リンクタップ

**処理フロー**:
1. `Navigator.of(context).pushNamed(forgotPassword)`を実行
2. パスワード再設定画面に遷移

### 4-アカウント作成ボタン押下イベント

**トリガー**: 「CREATE AN ACCOUNT」ボタンタップ

**処理フロー**:
1. `Navigator.pushNamed(context, signUp, arguments: false)`を実行
2. サインアップ画面に遷移（arguments: falseはshopSlug追加なしを示す）

### 5-パスワード表示切り替えイベント

**トリガー**: パスワードフィールドのvisibilityアイコンタップ

**処理フロー**:
1. `setState()`で`showPassword`フラグを反転
2. パスワードフィールドの表示/非表示を切り替え

### 6-指紋認証イベント

**トリガー**: 指紋認証アニメーションエリアタップ

**処理フロー**:
1. `startAuthentication(false)`を呼び出し
2. `LocalAuthentication().authenticate()`で生体認証を実行
3. 認証成功時：
   - SharedPreferencesから保存済みのメール・パスワードを取得
   - `FetchSignInEvent`を送信（fingerPrint: true）
4. 認証失敗時：エラーメッセージを表示

### 7-指紋認証設定確認ダイアログ

**トリガー**: 初回ログイン成功時かつ指紋認証未設定かつデバイスサポート時

**処理フロー**:
1. `showFingerprintDialog()`でダイアログ表示
2. OK押下時：
   - `startAuthentication(true)`で認証実行
   - 成功時：メール・パスワードをSharedPreferencesに保存
3. キャンセル押下時：指紋認証をスキップしてホーム画面へ遷移

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| サインイン成功 | users (サーバー側) | SELECT | ユーザー認証情報の検証 |

### SharedPreferences更新項目

| 操作 | 項目 | 更新値 | 備考 |
|-----|------|--------|------|
| ログイン成功 | customerLoggedIn | true | ログイン状態フラグ |
| ログイン成功 | customerName | ユーザー名 | 表示用名前 |
| ログイン成功 | customerEmail | メールアドレス | ユーザーメール |
| ログイン成功 | customerToken | "tokenType token" | 認証トークン |
| ログイン成功 | customerId | ユーザーID | 数値ID |
| ログイン成功 | customerImage | 画像URL | プロフィール画像 |
| 指紋認証設定 | fingerPrintUser | メールアドレス | 指紋認証用保存メール |
| 指紋認証設定 | fingerPrintPassword | パスワード | 指紋認証用保存パスワード |

## メッセージ仕様

| メッセージID | メッセージ種別 | 表示条件 | メッセージ内容 |
|-------------|--------------|----------|--------------|
| MSG-001 | エラー | メール未入力 | 「Please fill Email」 |
| MSG-002 | エラー | メール形式不正 | 「Please enter valid email」 |
| MSG-003 | エラー | パスワード未入力 | 「Please fill Password」 |
| MSG-004 | エラー | パスワード6文字未満 | 「Password must be at least 6 characters」 |
| MSG-005 | 成功 | ログイン成功 | APIから返却されるメッセージ |
| MSG-006 | エラー | ログイン失敗 | graphqlErrorsまたはエラーメッセージ |
| MSG-007 | 情報 | 処理中 | 「Please wait...」 |
| MSG-008 | エラー | 指紋認証失敗 | 「Authentication failed」 |

## 例外処理

| 例外ケース | 処理内容 | ユーザーへの影響 |
|-----------|---------|----------------|
| ログインAPI失敗 | ダイアログを閉じ、エラーメッセージを表示 | ログインできない |
| ソーシャルログイン失敗 | ダイアログを閉じ、エラーメッセージを表示 | ログインできない |
| 指紋認証非対応デバイス | 指紋認証エリアを非表示 | 通常ログインのみ利用可能 |
| 指紋認証キャンセル | エラーメッセージを表示 | 再試行または通常ログインを選択 |

## 備考

- デモ環境では`demoEmail`と`demoPassword`がデフォルト入力される
- 認証トークンは「tokenType token」の形式で保存（Bearer token等）
- ログイン成功後3秒のディレイは成功メッセージを表示するため
- `local_auth`パッケージを使用して生体認証を実装

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | sign_in_model.dart | `lib/screens/sign_in/data_model/sign_in_model.dart` | ログインAPIレスポンスの構造 |

**読解のコツ**: SignInModelにはsuccess, message, data, token, tokenTypeなどのフィールドがある。dataにはユーザー情報が含まれる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | sign_in_screen.dart | `lib/screens/sign_in/view/sign_in_screen.dart` | サインイン画面のメインウィジェット |

**主要処理フロー**:
1. **39-43行目**: `initState()`でSignInBlocを取得
2. **46-59行目**: `build()`でScaffoldを構築
3. **68-126行目**: `_signInBloc()`でBlocConsumerを構築
4. **149-276行目**: `_form()`でログインフォームUI構築
5. **279-285行目**: `_onPressSignInButton()`でログイン処理実行
6. **326-344行目**: `checkFingerprint()`で指紋認証確認
7. **386-429行目**: `startAuthentication()`で指紋認証実行

#### Step 3: Blocレイヤーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | sign_in_bloc.dart | `lib/screens/sign_in/bloc/sign_in_bloc.dart` | 状態管理Bloc |
| 3-2 | sign_in_event.dart | `lib/screens/sign_in/bloc/sign_in_event.dart` | イベント定義 |
| 3-3 | sign_in_state.dart | `lib/screens/sign_in/bloc/sign_in_state.dart` | 状態定義 |

**主要処理フロー**:
- **24-37行目**: `FetchSignInEvent`でログインAPI呼び出し
- **38-57行目**: `SocialLoginEvent`でソーシャルログイン処理

#### Step 4: リポジトリレイヤーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | sign_in_repository.dart | `lib/screens/sign_in/bloc/sign_in_repository.dart` | API通信処理 |

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

```
SignInScreen (StatefulWidget)
    │
    ├─ initState()
    │      └─ SignInBloc (context.read)
    │
    ├─ build()
    │      └─ Scaffold
    │             ├─ AppBar(title: "Sign in with Email")
    │             └─ _signInBloc() → BlocConsumer<SignInBloc>
    │                    └─ buildUI() → _form()
    │                           ├─ TextField (email)
    │                           ├─ TextField (password)
    │                           ├─ GestureDetector ("Forget Password?")
    │                           │      └─ Navigator.pushNamed(forgotPassword)
    │                           ├─ MaterialButton ("SIGN IN")
    │                           │      └─ _onPressSignInButton()
    │                           │             ├─ validate()
    │                           │             ├─ showLoadingDialog()
    │                           │             └─ SignInBloc.add(FetchSignInEvent)
    │                           ├─ MaterialButton ("CREATE AN ACCOUNT")
    │                           │      └─ Navigator.pushNamed(signUp)
    │                           └─ LottieBuilder (fingerprint)
    │                                  └─ startAuthentication()
    │
    └─ SignInBloc
           ├─ FetchSignInEvent
           │      └─ repository.callSignInApi()
           │             └─ FetchSignInState (success/fail)
           │                    ├─ 成功: SharedPreferences更新 → home遷移
           │                    └─ 失敗: エラーメッセージ表示
           │
           └─ SocialLoginEvent
                  └─ repository.socialLogin()
                         └─ SocialLoginState (success/fail)
```

### データフロー図

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

email/password ─────────▶ FetchSignInEvent ─────────────▶ SignInBloc
                                │
                                ▼
                         repository.callSignInApi()
                                │
                                ▼
                         SignInModel (APIレスポンス)
                                │
                         ┌──────┴──────┐
                         ▼             ▼
                    success=true   success=false
                         │             │
                         ▼             ▼
              SharedPreferences更新    エラー表示
                         │
                         ▼
              checkFingerprint()
                         │
                 ┌───────┴───────┐
                 ▼               ▼
            指紋認証設定      スキップ
                 │               │
                 ▼               ▼
            ホーム画面へ     ホーム画面へ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| sign_in_screen.dart | `lib/screens/sign_in/view/sign_in_screen.dart` | ソース | サインイン画面のメインウィジェット |
| sign_in_bloc.dart | `lib/screens/sign_in/bloc/sign_in_bloc.dart` | ソース | 状態管理Bloc |
| sign_in_event.dart | `lib/screens/sign_in/bloc/sign_in_event.dart` | ソース | イベント定義 |
| sign_in_state.dart | `lib/screens/sign_in/bloc/sign_in_state.dart` | ソース | 状態定義 |
| sign_in_repository.dart | `lib/screens/sign_in/bloc/sign_in_repository.dart` | ソース | API通信処理 |
| sign_in_model.dart | `lib/screens/sign_in/data_model/sign_in_model.dart` | ソース | ログインレスポンスモデル |
| index.dart | `lib/screens/sign_in/utils/index.dart` | ソース | エクスポート集約 |
| server_configuration.dart | `lib/utils/server_configuration.dart` | 設定 | デモ用認証情報等 |
| route_constants.dart | `lib/utils/route_constants.dart` | ソース | ルーティング定数 |
