# 機能設計書 4-ユーザー認証

## 概要

本ドキュメントは、Decap CMSのユーザー認証機能の設計を記載する。ログイン、ログアウト、トークンキャッシュの検証、Open Authoringモードのサポートを含む認証フロー全体を管理する。

### 本機能の処理概要

本機能は、CMSユーザーの認証ライフサイクルを管理する。アプリケーション起動時のキャッシュトークン検証、ログインフォームからの認証実行、ログアウト処理、およびOpen Authoring（フォークベースの共同編集）モードの判定を行う。

**業務上の目的・背景**：Decap CMSはGitリポジトリをバックエンドとして使用するため、リポジトリへのアクセス権限をユーザー認証で制御する必要がある。各バックエンド（GitHub, GitLab, Bitbucket等）はそれぞれ異なる認証方式を持つが、本機能がその抽象化レイヤーとして機能し、統一的な認証インターフェースを提供する。

**機能の利用シーン**：CMSアプリケーション起動時の自動認証（トークンキャッシュ検証）、ログイン画面からの手動認証、セッション終了時のログアウト。

**主要な処理内容**：
1. `authenticateUser`: 起動時のキャッシュトークン検証。バックエンドの`currentUser()`を呼び出し、有効なユーザー情報があれば認証成功とする
2. `loginUser`: 資格情報（Credentials）によるログイン。バックエンドの`authenticate()`を呼び出す
3. `logoutUser`: ログアウト処理。バックエンドの`logout()`を呼び出し、認証状態と通知をクリアする
4. Open Authoringモードの判定: ユーザーの`useOpenAuthoring`フラグに基づくモード切替

**関連システム・外部連携**：各Gitバックエンド（GitHub, GitLab, Bitbucket, Git Gateway等）の認証API。

**権限による制御**：認証されたユーザーのみがCMS機能にアクセスできる。Open Authoringモードではフォークベースの制限付きアクセスが提供される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | ログイン画面 | 主画面 | メールアドレスとパスワードによるログイン処理。Netlify Identity経由またはgit-gateway経由での認証実行 |
| 2 | PKCE認証画面 | 主画面 | OAuth 2.0 PKCEフローによるログイン処理。外部プロバイダーへの認証リダイレクト |

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| credentials | Credentials | Yes（loginUser） | ログイン資格情報（バックエンド固有） | バックエンドの認証処理で検証 |

### 入力データソース

- ログインフォームのユーザー入力（メール、パスワード）
- OAuthリダイレクトのコールバックデータ（アクセストークン等）
- ブラウザのローカルストレージ/セッションストレージに保存されたキャッシュトークン

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| user | User | 認証されたユーザー情報（name, email, token等） |
| auth.isFetching | boolean | 認証処理中フラグ |
| auth.error | string | 認証エラーメッセージ |

### 出力先

- Reduxストア（auth状態スライス）
- 通知システム（認証エラー時のトーストメッセージ）

## 処理フロー

### 処理シーケンス

```
1. authenticateUser()（起動時）
   └─ AUTH_REQUESTをディスパッチ（isFetching: true）
   └─ currentBackend(config)でバックエンド取得
   └─ backend.currentUser()でキャッシュトークン検証
   └─ ユーザーが存在する場合:
       └─ useOpenAuthoringフラグチェック → USE_OPEN_AUTHORING
       └─ AUTH_SUCCESSをディスパッチ
   └─ ユーザーが存在しない場合:
       └─ AUTH_REQUEST_DONEをディスパッチ（ログイン画面表示）
   └─ エラーの場合:
       └─ AUTH_FAILUREをディスパッチ
       └─ logoutUser()を呼び出し

2. loginUser(credentials)（ログインフォーム送信時）
   └─ AUTH_REQUESTをディスパッチ
   └─ backend.authenticate(credentials)を呼び出し
   └─ 成功時: AUTH_SUCCESSをディスパッチ
   └─ 失敗時: エラー通知 + AUTH_FAILUREをディスパッチ

3. logoutUser()（ログアウト時）
   └─ backend.logout()を呼び出し
   └─ LOGOUTをディスパッチ
   └─ clearNotifications()をディスパッチ
```

### フローチャート

```mermaid
flowchart TD
    A[アプリ起動] --> B[authenticateUser]
    B --> C[AUTH_REQUEST dispatch]
    C --> D[backend.currentUser]
    D --> E{ユーザー存在?}
    E -->|Yes| F{useOpenAuthoring?}
    F -->|Yes| G[USE_OPEN_AUTHORING dispatch]
    F -->|No| H[AUTH_SUCCESS dispatch]
    G --> H
    E -->|No| I[AUTH_REQUEST_DONE dispatch]
    I --> J[ログイン画面表示]
    D --> K{エラー発生?}
    K -->|Yes| L[AUTH_FAILURE dispatch]
    L --> M[logoutUser呼び出し]
    J --> N[loginUser]
    N --> O[backend.authenticate]
    O --> P{成功?}
    P -->|Yes| Q[AUTH_SUCCESS dispatch]
    P -->|No| R[エラー通知 + AUTH_FAILURE]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | キャッシュトークン優先 | 起動時にキャッシュされたトークンが有効であれば自動ログインする | アプリケーション起動時 |
| BR-02 | Open Authoringモード | ユーザーのuseOpenAuthoringフラグがtrueの場合、USE_OPEN_AUTHORINGアクションをディスパッチ | ユーザー情報にuseOpenAuthoringが設定されている場合 |
| BR-03 | 認証エラー時の自動ログアウト | authenticateUserでエラーが発生した場合、自動的にlogoutUserを呼び出す | キャッシュトークン検証失敗時 |
| BR-04 | ログアウト時の通知クリア | ログアウト時に既存の通知をすべてクリアする | logoutUser実行時 |
| BR-05 | 認証エラー通知の自動消去 | ログインエラー通知は8秒後に自動消去される | loginUser失敗時 |

### 計算ロジック

特になし。

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

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

| 操作 | 対象ストア | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 認証開始 | auth | UPDATE | AUTH_REQUEST: isFetching=true |
| 認証成功 | auth | UPDATE | AUTH_SUCCESS: user=ユーザー情報 |
| 認証失敗 | auth | UPDATE | AUTH_FAILURE: error=エラーメッセージ |
| 認証完了 | auth | UPDATE | AUTH_REQUEST_DONE: isFetching=false |
| ログアウト | auth | UPDATE | LOGOUT: user=undefined, isFetching=false |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| AUTH_FAILURE | キャッシュトークン無効 | backend.currentUser()がエラーを返す | logoutUser()で状態クリア |
| AUTH_FAILURE | ログイン失敗 | backend.authenticate()がエラーを返す | エラートースト通知（'ui.toast.onFailToAuth'） |

### リトライ仕様

認証処理に対するリトライ機構は実装されていない。ユーザーによる再ログインが必要。

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

クライアントサイド処理のためトランザクション管理は不要。

## パフォーマンス要件

- キャッシュトークンの検証はバックエンドAPIへの単一リクエストで完了すること
- 認証エラー通知のdismissAfterは8000ms（8秒）

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

- トークンはブラウザのローカルストレージ/セッションストレージに保存される
- ログアウト時にバックエンドのlogout()が呼び出され、トークンが無効化される
- Open Authoringモードではフォークベースのアクセス制限が適用される
- 認証エラーの詳細メッセージはコンソールに出力されるが、ユーザーにはローカライズされたメッセージが表示される

## 備考

- 認証処理はバックエンド固有の実装に委譲される（Strategy パターン）
- 各バックエンドが独自のauthComponent()を提供し、ログイン画面のUIをカスタマイズできる
- AUTH_REQUEST_DONEアクションはauthenticateUserで有効なユーザーがいない場合にのみディスパッチされる

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | auth.ts (reducer) | `packages/decap-cms-core/src/reducers/auth.ts` | Auth型（isFetching, user, error）とデフォルト状態 |

**読解のコツ**: immerのproduceパターンで状態更新。AUTH_SUCCESSでuserを設定、LOGOUTでuserをundefinedに戻す。AUTH_REQUEST_DONEはisFetchingのみをfalseにする特殊なアクション。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | auth.ts (actions) | `packages/decap-cms-core/src/actions/auth.ts` | 認証アクションの全体像 |

**主要処理フロー**:
1. **9-14行目**: アクションタイプ定数の定義
2. **16-53行目**: 基本アクションクリエーター（authenticating, authenticate, authError, doneAuthenticating, useOpenAuthoring, logout）
3. **56-77行目**: authenticateUser - キャッシュトークン検証
4. **79-108行目**: loginUser - 資格情報によるログイン
5. **110-119行目**: logoutUser - ログアウト処理

#### Step 3: App.jsの認証分岐を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | App.js | `packages/decap-cms-core/src/components/App/App.js` | 認証状態に基づく画面分岐 |

**主要処理フロー**:
- **112-140行目**: authenticating() - バックエンドのauthComponent()を使用してログイン画面を描画
- **173-175行目**: user == nullの場合にauthenticating()を呼び出す

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

```
bootstrap.onLoad()
    |
    +-- authenticateUser()
            |
            +-- currentBackend(config)
            +-- authenticating()  [dispatch]
            +-- backend.currentUser()
                    |
                    +-- [成功] authenticate(user)  [dispatch]
                    |           +-- useOpenAuthoring()  [dispatch]  (条件付き)
                    |
                    +-- [ユーザーなし] doneAuthenticating()  [dispatch]
                    |
                    +-- [エラー] authError(error)  [dispatch]
                                +-- logoutUser()
                                        +-- backend.logout()
                                        +-- logout()  [dispatch]
                                        +-- clearNotifications()  [dispatch]

loginUser(credentials)
    |
    +-- currentBackend(config)
    +-- authenticating()  [dispatch]
    +-- backend.authenticate(credentials)
            |
            +-- [成功] authenticate(user)  [dispatch]
            |
            +-- [失敗] addNotification()  [dispatch]
                        +-- authError(error)  [dispatch]
```

### データフロー図

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

キャッシュトークン -------> backend.currentUser() -----> Reduxストア(auth.user)
(localStorage等)

ログインフォーム ---------> backend.authenticate() ----> Reduxストア(auth.user)
(credentials)                                           通知(エラー時)

ログアウト操作 ----------> backend.logout() -----------> Reduxストア(auth = default)
                                                         通知クリア
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| auth.ts (actions) | `packages/decap-cms-core/src/actions/auth.ts` | ソース | 認証アクション（authenticateUser, loginUser, logoutUser） |
| auth.ts (reducer) | `packages/decap-cms-core/src/reducers/auth.ts` | ソース | 認証状態のリデューサー |
| App.js | `packages/decap-cms-core/src/components/App/App.js` | ソース | 認証状態に基づく画面分岐 |
| notifications.ts | `packages/decap-cms-core/src/actions/notifications.ts` | ソース | 通知アクション（addNotification, clearNotifications） |
| backend.ts | `packages/decap-cms-core/src/backend.ts` | ソース | currentBackend関数、バックエンド抽象化レイヤー |
