# 画面設計書 3-OpenIDコールバック画面

## 概要

本ドキュメントは、Actual Budget アプリケーションのOpenID認証コールバック画面の設計仕様を記述したものである。

### 本画面の処理概要

OpenIDコールバック画面は、OpenIDプロバイダーでの認証完了後にリダイレクトされる中継画面である。この画面はUIを持たず、URLパラメータからトークンを取得してサーバーに設定し、認証を完了させる処理のみを行う。

**業務上の目的・背景**：OpenID Connect認証フローでは、ユーザーがOpenIDプロバイダー（Google、Azure AD等）で認証を完了した後、アプリケーションにリダイレクトされる。このコールバック画面は、認証プロバイダーから受け取った認証トークンを処理し、アプリケーションのセッションを確立するために必要である。OAuth 2.0/OpenID Connectの標準的な認可コードフローの一部として機能する。

**画面へのアクセス方法**：以下の条件でこの画面に遷移する：
- OpenIDプロバイダーでの認証完了後の自動リダイレクト
- `/openid-cb?token=xxx` URLへのリダイレクト（OpenIDプロバイダーから）

**主要な操作・処理内容**：
1. URLクエリパラメータから `token` を取得
2. `subscribe-set-token` APIを呼び出してトークンを設定
3. `loggedIn` アクションをdispatchして認証状態を更新
4. 自動的に予算ファイル選択画面に遷移（Redux状態更新により）

**画面遷移**：
- 遷移元：OpenIDプロバイダーからのリダイレクト（ログイン画面経由）
- 遷移先：予算ファイル選択画面（`/`）（自動遷移）

**権限による表示制御**：この画面は認証処理専用であり、表示コンテンツはない。トークンが無効な場合はエラー画面に遷移する可能性がある。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 48 | OpenID認証 | 主機能 | OpenID認証コールバック処理・トークン取得 |

## 画面種別

リダイレクト専用（処理画面）

## URL/ルーティング

`/openid-cb`

## 入出力項目

| 項目名 | 項目ID | 入出力 | 必須 | データ型 | 最大長 | 備考 |
|--------|--------|--------|------|----------|--------|------|
| トークン | token | 入力（URLパラメータ） | 必須 | string | - | OpenIDプロバイダーから受け取った認証トークン |

## 表示項目

| 項目名 | 表示内容 | 備考 |
|--------|----------|------|
| - | - | UIなし（処理のみ） |

## イベント仕様

### 1-コンポーネントマウント時（自動実行）

1. `window.location.search` からURLクエリパラメータを解析
2. `token` パラメータを取得
3. `subscribe-set-token` APIを呼び出し、トークンをサーバーに送信
4. API成功時：`loggedIn` アクションをdispatchして認証状態を更新
5. Redux状態の変更により、ManagementAppが予算ファイル選択画面にルーティング

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| トークン設定 | sessions（サーバー側） | INSERT/UPDATE | セッショントークンを保存 |

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

#### sessions（サーバー側）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | token | OpenIDプロバイダーから受け取ったトークン | 認証トークンまたはセッションID |
| INSERT/UPDATE | user_id | トークンから抽出したユーザーID | マルチユーザー時 |
| INSERT/UPDATE | expires_at | トークンの有効期限 | トークンから抽出または計算 |

## メッセージ仕様

| メッセージID | メッセージ内容 | 種別 | 表示条件 |
|-------------|---------------|------|----------|
| - | - | - | この画面にはメッセージ表示なし |

## 例外処理

| 例外ケース | 処理内容 |
|------------|----------|
| トークンが存在しない | エラー状態となり、リダイレクトが失敗する可能性 |
| トークンが無効 | サーバー側でエラーとなり、認証が完了しない |
| API通信失敗 | ネットワークエラーとなり、認証が完了しない |

## 備考

- この画面は視覚的なUIを持たない（`return null`）
- 処理は `useEffect` 内で自動的に実行される
- OpenID認証フローの最終ステップとして機能する
- Electron環境では、組み込みOAuthサーバーがこのコールバックを処理する場合がある

---

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

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

### 推奨読解順序

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

トークン設定APIのインターフェースを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | handlers.d.ts | `loot-core/types/handlers.d.ts` | subscribe-set-token APIの型定義 |

**読解のコツ**: APIの入力パラメータ（tokenフィールド）と戻り値の型を確認する

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

メインコンポーネントの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | OpenIdCallback.ts | `packages/desktop-client/src/components/manager/subscribe/OpenIdCallback.ts` | メインコンポーネントの実装 |

**主要処理フロー**:
1. **8行目**: OpenIdCallback関数コンポーネントの定義
2. **9行目**: useDispatch hookでRedux dispatchを取得
3. **10-14行目**: useEffect内でトークン処理
4. **11行目**: URLSearchParamsでトークン取得
5. **12行目**: subscribe-set-token API呼び出し
6. **13行目**: loggedIn アクションdispatch
7. **16行目**: nullを返却（UIなし）

#### Step 3: ルーティングを理解する

画面遷移の流れを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ManagementApp.tsx | `packages/desktop-client/src/components/manager/ManagementApp.tsx` | ルーティング定義 |

**主要処理フロー**:
- **193行目**: `/openid-cb` ルートの定義

#### Step 4: 認証状態管理を理解する

ログイン完了後の状態遷移を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | usersSlice.ts | `packages/desktop-client/src/users/usersSlice.ts` | loggedIn アクションの実装 |

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

```
OpenIdCallback (OpenIdCallback.ts)
    │
    └─ useEffect (マウント時自動実行)
           │
           ├─ URLSearchParams(window.location.search)
           │      └─ token パラメータ取得
           │
           ├─ send('subscribe-set-token', { token })
           │      └─ [サーバー: トークン検証・セッション作成]
           │
           └─ dispatch(loggedIn())
                  └─ Redux state 更新
                         └─ ManagementApp が状態変化を検知
                                └─ 予算ファイル選択画面へルーティング
```

### データフロー図

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

OpenIDプロバイダー
       │
       ▼
リダイレクト ────────────▶ /openid-cb?token=xxx
       │
       ▼
URLSearchParams ─────────▶ token 取得
       │
       ▼
send('subscribe-set-token') ───▶ [サーバー: セッション作成]
       │
       ▼
dispatch(loggedIn()) ────────▶ Redux state.user.data 更新
       │
       ▼
ManagementApp ───────────────▶ userData存在を検知
       │
       ▼
Route '/' ───────────────────▶ 予算ファイル選択画面
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| OpenIdCallback.ts | `packages/desktop-client/src/components/manager/subscribe/OpenIdCallback.ts` | ソース | メインコンポーネント |
| ManagementApp.tsx | `packages/desktop-client/src/components/manager/ManagementApp.tsx` | ソース | ルーティング定義 |
| usersSlice.ts | `packages/desktop-client/src/users/usersSlice.ts` | ソース | loggedIn アクション |
| fetch.ts | `loot-core/platform/client/fetch.ts` | ソース | API通信ユーティリティ |
| Login.tsx | `packages/desktop-client/src/components/manager/subscribe/Login.tsx` | ソース | OpenID認証開始（遷移元） |
