# 機能設計書 2-ログアウト

## 概要

本ドキュメントは、Shopware 6 Storefrontにおける顧客ログアウト機能の設計仕様を記述する。ログイン中の顧客がセッションを終了し、ログアウトするための機能である。

### 本機能の処理概要

**業務上の目的・背景**：ECサイトにおいて、顧客がセッションを安全に終了することはセキュリティ上重要である。共有端末での利用時や、個人情報保護の観点から、顧客が能動的にログアウトできる機能は必須である。また、ゲスト注文完了後の自動ログアウトにも使用される。

**機能の利用シーン**：顧客がショッピングを終了し、アカウントからログアウトしたい場合に使用される。また、別のアカウントでログインし直したい場合や、セキュリティ上の理由でセッションを終了したい場合にも利用される。

**主要な処理内容**：
1. 現在のログイン状態を確認
2. システム設定に基づいてカートおよびセッションコンテキストを削除または置換
3. 新しい匿名セッショントークンを発行
4. CustomerLogoutEventを発行
5. 成功メッセージを表示してログインページへリダイレクト

**関連システム・外部連携**：特になし

**権限による制御**：ログイン中の顧客（ゲストを含む）のみがログアウト機能を使用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 11 | 注文完了ページ | 補助機能 | ゲスト注文時の自動ログアウト処理 |

## 機能種別

セッション管理 / 認証終了処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| - | - | - | 特別なパラメータは不要 | - |

### 入力データソース

- 現在のセッションコンテキスト（SalesChannelContext）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| token | string | 新しい匿名セッショントークン |
| flashMessage | string | ログアウト成功メッセージ |

### 出力先

- セッション（新しいコンテキストトークン）
- 画面（フラッシュメッセージ）
- HTTPレスポンス（リダイレクト）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ AuthController::logout がGETリクエストを受け取る

2. ログイン状態チェック
   └─ 顧客がログインしていない場合はログインページへリダイレクト

3. ログアウトルート呼び出し
   └─ LogoutRoute::logout を実行

4. セッション処理判定
   └─ shouldDelete()で削除するか置換するかを判定
   └─ 条件: invalidateSessionOnLogOut設定 または ゲストユーザー

5. カートとコンテキストの処理
   └─ 削除の場合: カート削除 + コンテキスト削除
   └─ 置換の場合: コンテキストを新しいトークンで置換

6. 新規コンテキスト取得
   └─ 32文字のランダムトークンで新しいコンテキストを生成

7. イベント発行
   └─ CustomerLogoutEvent をディスパッチ

8. レスポンス生成
   └─ 成功メッセージをフラッシュに追加
   └─ ログインページへリダイレクト
```

### フローチャート

```mermaid
flowchart TD
    A[ログアウト開始] --> B{顧客ログイン済み?}
    B -->|No| C[ログインページへリダイレクト]
    B -->|Yes| D[LogoutRoute::logout]
    D --> E{shouldDelete判定}
    E -->|invalidateSessionOnLogOut=true| F[カート削除]
    E -->|ゲストユーザー| F
    E -->|その他| G[コンテキスト置換]
    F --> H[コンテキスト削除]
    H --> I[新規コンテキスト生成]
    G --> I
    I --> J[CustomerLogoutEvent発行]
    J --> K[成功メッセージ追加]
    K --> L[ログインページへリダイレクト]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | セッション無効化設定 | core.loginRegistration.invalidateSessionOnLogOut=trueの場合はカートとコンテキストを完全削除 | ログアウト時 |
| BR-002 | ゲストログアウト | ゲストユーザーの場合は常にカートとコンテキストを削除 | ゲストログアウト時 |
| BR-003 | コンテキスト置換 | 削除条件を満たさない場合はコンテキストを新しいトークンで置換（顧客情報のみ削除） | 通常ログアウト時 |

### 計算ロジック

- 新規トークン生成: `Random::getAlphanumericString(32)`

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| コンテキスト削除 | sales_channel_api_context | DELETE | セッションコンテキストを削除 |
| コンテキスト置換 | sales_channel_api_context | UPDATE | トークンを新しい値に置換 |
| カート削除 | cart | DELETE | 顧客のカートを削除 |

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

#### sales_channel_api_context

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | - | token = 現在のトークン AND sales_channel_id | shouldDelete=trueの場合 |
| UPDATE | token | 新規ランダムトークン | shouldDelete=falseの場合 |

#### cart

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | - | token = 現在のトークン | shouldDelete=trueの場合 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ConstraintViolationException | バリデーションエラー発生時 | エラーパラメータ付きでログインページへリダイレクト |

### リトライ仕様

- リトライは不要（べき等性のある処理）

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

- カート削除とコンテキスト削除は個別のトランザクションで実行
- 一方が失敗しても他方は実行される

## パフォーマンス要件

- ログアウト処理全体で200ms以内のレスポンスを目標

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

- ログアウト後は新しいセッショントークンが発行されるため、旧トークンでのアクセスは不可
- ゲストユーザーのセッションデータは完全に削除される
- invalidateSessionOnLogOutを有効にすることで、よりセキュアな運用が可能

## 備考

- ログアウト成功時に CustomerLogoutEvent が発行され、拡張やログ記録に使用可能
- Store-APIのログアウトはPOSTメソッドだが、StorefrontではGETメソッドでアクセス可能

---

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

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

### 推奨読解順序

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

ログアウト処理に関連するコンテキストとイベントの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | SalesChannelContext.php | `src/Core/System/SalesChannel/SalesChannelContext.php` | getCustomer(), getToken()メソッドを確認 |
| 1-2 | CustomerLogoutEvent.php | `src/Core/Checkout/Customer/Event/CustomerLogoutEvent.php` | ログアウトイベントの構造 |

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

StorefrontのログアウトリクエストはAuthControllerで受け付けられる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AuthController.php | `src/Storefront/Controller/AuthController.php` | logout()メソッド（153-174行目） |

**主要処理フロー**:
1. **160-161行目**: 顧客がnullの場合はログインページへリダイレクト
2. **164-165行目**: LogoutRoute::logoutを呼び出し
3. **166行目**: 成功メッセージをフラッシュに追加
4. **169-170行目**: ConstraintViolationExceptionのキャッチ
5. **173行目**: ログインページへリダイレクト

#### Step 3: Store-APIルートを理解する

実際のログアウトロジックはLogoutRouteに実装されている。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | LogoutRoute.php | `src/Core/Checkout/Customer/SalesChannel/LogoutRoute.php` | logout()メソッド（54-77行目）、shouldDelete()メソッド（79-92行目） |

**主要処理フロー**:
- **57行目**: customerを変数に保存（イベント用）
- **58行目**: shouldDelete()で削除判定
- **59-60行目**: 削除の場合はカート削除とコンテキスト削除
- **62行目**: 置換の場合はcontextPersister.replace
- **66-71行目**: 新しいコンテキストを生成
- **73-74行目**: CustomerLogoutEventを発行

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

```
AuthController::logout (Storefront)
    │
    ├─ context.getCustomer() チェック
    │
    └─ LogoutRoute::logout (Store-API)
           │
           ├─ LogoutRoute::shouldDelete
           │      └─ SystemConfigService::get (invalidateSessionOnLogOut)
           │
           ├─ [shouldDelete=true]
           │      ├─ CartService::deleteCart
           │      └─ SalesChannelContextPersister::delete
           │
           ├─ [shouldDelete=false]
           │      └─ SalesChannelContextPersister::replace
           │
           ├─ SalesChannelContextService::get (新規コンテキスト)
           │
           └─ CustomerLogoutEvent (dispatch)
```

### データフロー図

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

現在のセッション ───▶ AuthController::logout
                           │
                           ▼
                     LogoutRoute::logout
                           │
                     ┌─────┴─────┐
                     ▼           ▼
              shouldDelete?  shouldDelete?
              (true)         (false)
                     │           │
                     ▼           ▼
              カート削除    コンテキスト置換
              コンテキスト削除
                     │           │
                     └─────┬─────┘
                           ▼
                     新規コンテキスト生成
                           │
                           ▼
                     CustomerLogoutEvent ───▶ [イベント発行]
                           │
                           ▼
                     ContextTokenResponse ───▶ [新しいトークン]
                           │
                           ▼
                     リダイレクト ───▶ [ログインページ]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AuthController.php | `src/Storefront/Controller/AuthController.php` | コントローラ | Storefrontのログアウトエンドポイント |
| LogoutRoute.php | `src/Core/Checkout/Customer/SalesChannel/LogoutRoute.php` | ルート | Store-APIのログアウトルート |
| AbstractLogoutRoute.php | `src/Core/Checkout/Customer/SalesChannel/AbstractLogoutRoute.php` | 抽象クラス | ログアウトルートの抽象定義 |
| SalesChannelContextPersister.php | `src/Core/System/SalesChannel/Context/SalesChannelContextPersister.php` | サービス | コンテキストの永続化管理 |
| CartService.php | `src/Core/Checkout/Cart/SalesChannel/CartService.php` | サービス | カート操作 |
| CustomerLogoutEvent.php | `src/Core/Checkout/Customer/Event/CustomerLogoutEvent.php` | イベント | ログアウトイベント |
| SystemConfigService.php | `src/Core/System/SystemConfig/SystemConfigService.php` | サービス | システム設定の取得 |
