# 画面設計書 1-ログイン画面

## 概要

本ドキュメントは、Medusa Admin Dashboard のログイン画面の設計仕様を定義するものです。管理者がシステムにアクセスするための認証入口となる画面であり、セキュリティと利便性の両面を考慮した設計となっています。

### 本画面の処理概要

本画面は、Medusa Admin Dashboard への管理者認証を行うための公開画面です。ユーザーはメールアドレスとパスワードを入力してシステムにログインし、認証成功後はダッシュボードのメイン画面（注文一覧）へ遷移します。

**業務上の目的・背景**：ECサイトの管理業務を行うためには、適切な権限を持つ管理者のみがシステムにアクセスできる必要があります。本画面は、不正アクセスを防止しつつ、正規の管理者がスムーズにシステムへログインできるようにするためのゲートウェイとして機能します。セキュリティを担保しながらも、ユーザビリティを損なわないシンプルなデザインを採用しています。

**画面へのアクセス方法**：
- ブラウザで管理画面のURL `/login` に直接アクセス
- 認証が必要なページにアクセスした際に自動リダイレクト
- ログアウト後のリダイレクト先

**主要な操作・処理内容**：
1. メールアドレスの入力 - 登録済みの管理者メールアドレスを入力
2. パスワードの入力 - アカウントに紐づくパスワードを入力
3. ログインボタン押下 - 認証処理を実行し、成功時にダッシュボードへ遷移
4. パスワードリセットリンク押下 - パスワードを忘れた場合にリセット画面へ遷移
5. Cloud認証ログイン - Medusa Cloud認証が有効な場合、外部認証プロバイダーを使用したログインが可能

**画面遷移**：
- 遷移元：パスワードリセット画面（リセット完了後）、招待画面（アカウント設定完了後）、認証切れ画面
- 遷移先：ホーム画面（→注文一覧へリダイレクト）、パスワードリセット画面

**権限による表示制御**：本画面は認証不要の公開画面のため、権限による表示制御はありません。ただし、既にログイン済みのユーザーがアクセスした場合は、自動的にダッシュボードへリダイレクトされます。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 59 | 認証ID管理 | 主機能 | 管理者のログイン認証処理 |
| 60 | プロバイダー認証 | 補助機能 | 外部認証プロバイダーによるログイン |
| 61 | 認証検証 | 補助機能 | ログイントークンの検証 |

## 画面種別

認証画面（ログイン）

## URL/ルーティング

`/login`

## 入出力項目

| 項目名 | 項目ID | データ型 | 必須 | 最小桁 | 最大桁 | 入力形式 | 説明 |
|--------|--------|----------|------|--------|--------|----------|------|
| メールアドレス | email | string | 必須 | - | - | Email形式 | ログインに使用するメールアドレス |
| パスワード | password | string | 必須 | 1 | - | パスワード | ログインに使用するパスワード |

## 表示項目

| 項目名 | 表示位置 | データソース | 説明 |
|--------|----------|--------------|------|
| ロゴ/アバター | 画面上部中央 | 静的 | Medusaのロゴまたはアバターボックス |
| タイトル | ロゴ下 | i18n (login.title) | ログイン画面のタイトル |
| ヒントテキスト | タイトル下 | i18n (login.hint) | ログインの説明文 |
| メールアドレス入力欄 | フォーム内 | ユーザー入力 | メールアドレスの入力フィールド |
| パスワード入力欄 | フォーム内 | ユーザー入力 | パスワードの入力フィールド（マスク表示） |
| ログインボタン | フォーム下 | i18n (actions.continueWithEmail) | メールでログインするボタン |
| Cloud認証ボタン | ログインボタン下 | i18n (auth.login.cloud) | Medusa Cloud認証ボタン（有効時のみ表示） |
| パスワードリセットリンク | 画面下部 | i18n (login.forgotPassword) | パスワードリセット画面へのリンク |
| バリデーションエラー | フォーム下 | 動的 | 入力値のバリデーションエラー |
| サーバーエラー | フォーム下 | 動的 | 認証失敗時のエラーメッセージ |

## イベント仕様

### 1-ログインボタン押下

**トリガー**: 「メールでログイン」ボタンのクリック（type="submit"）

**処理フロー**:
1. フォームの入力値（email, password）を取得
2. Zod スキーマによるバリデーション実行
   - email: 有効なメールアドレス形式であること
   - password: 空でないこと
3. バリデーション成功時、`useSignInWithEmailPass` フックを呼び出し
4. SDK経由で認証API（`sdk.auth.login("user", "emailpass", payload)`）を実行
5. 認証成功時：
   - `location.state.from.pathname` または `/orders` へ遷移
6. 認証失敗時：
   - 401エラー: emailフィールドにエラーメッセージを表示
   - その他エラー: サーバーエラーとしてアラートを表示

**遷移先**: ホーム画面（/orders へリダイレクト）

### 2-パスワードリセットリンク押下

**トリガー**: 「パスワードをお忘れですか？」リンクのクリック

**処理フロー**:
1. React Router の Link コンポーネントによるページ遷移

**遷移先**: パスワードリセット画面（/reset-password）

### 3-Cloud認証ログインボタン押下

**トリガー**: Cloud認証ボタンのクリック（cloudAuth.enabled が true の場合のみ表示）

**処理フロー**:
1. `sdk.auth.login("user", "cloud", { callback_url: ... })` を呼び出し
2. レスポンスに `location` が含まれる場合、外部認証プロバイダーへリダイレクト
3. 認証完了後、コールバックURLへ戻り、トークン処理を実行
4. ユーザーが存在しない場合は自動作成
5. 認証完了後、ルート画面へ遷移

**遷移先**: 外部認証プロバイダー → ホーム画面

### 4-拡張ウィジェット表示

**トリガー**: 画面レンダリング時

**処理フロー**:
1. `useExtension().getWidgets("login.before")` で前置ウィジェットを取得・表示
2. `useExtension().getWidgets("login.after")` で後置ウィジェットを取得・表示

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ログインボタン押下 | auth_identity | SELECT | 認証情報の検証 |
| ログインボタン押下 | user | SELECT | ユーザー情報の取得 |
| Cloud認証（新規ユーザー） | user | INSERT | 新規ユーザーの作成 |
| Cloud認証（新規ユーザー） | auth_identity | INSERT | 認証情報の作成 |

### テーブル別更新項目詳細

#### auth_identity

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | entity_id | email一致条件で検索 | ログイン認証時 |
| SELECT | provider_id | "emailpass" | 認証プロバイダーの特定 |

#### user

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id | auth_identity.actor_id | ユーザー情報の取得 |
| INSERT | email | Cloud認証時のメール | Cloud認証での新規作成時 |
| INSERT | created_at | 現在日時 | Cloud認証での新規作成時 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|----------|
| email.invalid | エラー | 有効なメールアドレスを入力してください | メールアドレス形式が不正な場合 |
| auth.401 | エラー | 認証に失敗しました（APIからのメッセージ） | メールアドレスまたはパスワードが間違っている場合 |
| auth.serverError | エラー | サーバーエラーが発生しました | サーバー側でエラーが発生した場合 |
| auth.login.authenticationFailed | エラー | 認証に失敗しました | Cloud認証が失敗した場合 |

## 例外処理

| 例外条件 | 処理内容 | ユーザーへの表示 |
|---------|---------|-----------------|
| 認証失敗（401） | emailフィールドにエラーを設定 | フィールド下にエラーメッセージを表示 |
| サーバーエラー | rootエラーとしてアラートを表示 | 画面上部に dismissible なエラーアラートを表示 |
| ネットワークエラー | エラーメッセージを表示 | サーバーエラーとして処理 |
| Cloud認証コールバック失敗 | /login へリダイレクト | トースト通知でエラーを表示 |

## 備考

- 本画面は認証不要の公開画面です
- Medusa Cloud認証が有効な場合、追加のログインオプションが表示されます
- 認証成功後のリダイレクト先は、元々アクセスしようとしていた画面（`location.state.from`）があればそこへ、なければ `/orders` へ遷移します
- 拡張機能により、ログインフォームの前後にカスタムウィジェットを追加可能です

---

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

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

### 推奨読解順序

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

まず、ログインフォームで使用されるバリデーションスキーマとデータ型を理解します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | login.tsx | `packages/admin/dashboard/src/routes/login/login.tsx` | 15-18行目: LoginSchema（Zodスキーマ）でemail/password の型定義を確認 |

**読解のコツ**: Zodスキーマは `z.object()` でオブジェクト構造を定義し、`z.string().email()` などのメソッドチェーンでバリデーションルールを設定します。

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

処理の起点となるログインコンポーネントを確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/admin/dashboard/src/routes/login/index.ts` | Loginコンポーネントのエクスポート確認 |
| 2-2 | login.tsx | `packages/admin/dashboard/src/routes/login/login.tsx` | 20-67行目: Loginコンポーネントの全体構造 |

**主要処理フロー**:
1. **21-24行目**: useTranslation, useLocation, useNavigate, useExtensionフックの初期化
2. **26行目**: リダイレクト先の決定（location.state?.from?.pathname または "/orders"）
3. **28-34行目**: react-hook-formによるフォーム初期化
4. **36行目**: useSignInWithEmailPassミューテーションフックの取得
5. **38-67行目**: handleSubmit関数でログイン処理を実行

#### Step 3: 認証APIフックを理解する

認証処理を行うカスタムフックの実装を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | auth.tsx | `packages/admin/dashboard/src/hooks/api/auth.tsx` | 6-23行目: useSignInWithEmailPassフックの実装 |

**主要処理フロー**:
- **17行目**: `sdk.auth.login("user", "emailpass", payload)` でバックエンドAPIを呼び出し
- **18-20行目**: 成功時のコールバック処理

#### Step 4: Cloud認証コンポーネントを理解する

Medusa Cloud認証のオプション機能を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | cloud-auth-login.tsx | `packages/admin/dashboard/src/routes/login/components/cloud-auth-login.tsx` | Cloud認証の全体フロー |

**主要処理フロー**:
- **15-76行目**: CloudAuthLoginコンポーネント - Cloud認証が有効な場合のUI表示
- **78-113行目**: useHandleLogin - ログイン開始処理
- **115-166行目**: useAuthCallback - 認証コールバック処理

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

```
Login (login.tsx)
    │
    ├─ useSignInWithEmailPass (hooks/api/auth.tsx)
    │      └─ sdk.auth.login (lib/client)
    │           └─ Backend Auth API
    │
    ├─ CloudAuthLogin (components/cloud-auth-login.tsx)
    │      ├─ useHandleLogin
    │      │      └─ sdk.auth.login("user", "cloud", ...)
    │      │
    │      └─ useAuthCallback
    │             ├─ sdk.auth.callback
    │             ├─ useCreateCloudAuthUser
    │             └─ sdk.auth.refresh
    │
    └─ useExtension (providers/extension-provider)
           └─ getWidgets("login.before" / "login.after")
```

### データフロー図

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

メールアドレス ─┐
               ├──▶ LoginSchema (Zod)
パスワード ────┘     バリデーション
                          │
                          ▼
                   useSignInWithEmailPass
                          │
                          ▼
                   sdk.auth.login
                          │
                          ▼
                   [成功] ───▶ navigate(from) ───▶ ダッシュボード
                          │
                   [失敗] ───▶ form.setError ───▶ エラー表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| login.tsx | `packages/admin/dashboard/src/routes/login/login.tsx` | ソース | ログイン画面のメインコンポーネント |
| index.ts | `packages/admin/dashboard/src/routes/login/index.ts` | ソース | エクスポート定義 |
| cloud-auth-login.tsx | `packages/admin/dashboard/src/routes/login/components/cloud-auth-login.tsx` | ソース | Cloud認証コンポーネント |
| auth.tsx | `packages/admin/dashboard/src/hooks/api/auth.tsx` | ソース | 認証関連APIフック |
| form.tsx | `packages/admin/dashboard/src/components/common/form/index.tsx` | ソース | フォームコンポーネント |
| avatar-box.tsx | `packages/admin/dashboard/src/components/common/logo-box/avatar-box.tsx` | ソース | アバターボックスコンポーネント |
| is-fetch-error.ts | `packages/admin/dashboard/src/lib/is-fetch-error.ts` | ソース | FetchErrorの型ガード |
| extension-provider.tsx | `packages/admin/dashboard/src/providers/extension-provider/index.tsx` | ソース | 拡張機能プロバイダー |
