# 機能設計書 1-アプリケーション初期化

## 概要

本ドキュメントは、Decap CMSアプリケーションのブートストラップ処理（初期化処理）の機能設計を記載する。CMSの起動時にReduxストアの初期化、設定ファイルの読み込み、バックエンドの解決、Reactアプリケーションのマウントを行う一連の処理を定義する。

### 本機能の処理概要

本機能は、Decap CMSアプリケーションが最初にブラウザ上で起動される際に実行されるブートストラップ処理である。HTMLページに埋め込まれたスクリプトから`init()`関数が呼び出されると、内部で`bootstrap()`関数が実行され、CMSアプリケーション全体の初期化が行われる。

**業務上の目的・背景**：Decap CMSはヘッドレスCMSとして、静的サイトジェネレータと連携してコンテンツ管理を行うツールである。ユーザーがCMS管理画面にアクセスした際に、設定ファイル（config.yml）の読み込み、Reduxストアの構築、認証状態の確認、Reactコンポーネントツリーのレンダリングまでを一貫して実行する必要がある。この初期化処理が正しく完了しないと、CMS全体が利用不可能となるため、最も基盤的かつ重要な機能である。

**機能の利用シーン**：ユーザーがブラウザでCMS管理画面のURL（例: `/admin/`）にアクセスした際に自動的に実行される。また、手動設定（JavaScript API経由）でCMSを初期化する場合にも利用される。

**主要な処理内容**：
1. バージョン番号のコンソールログ出力
2. DOMルート要素の取得または作成（`nc-root` IDのdiv要素）
3. Reduxストアへの設定読み込みアクション（`loadConfig`）のディスパッチ
4. 設定読み込み完了後のユーザー認証処理（`authenticateUser`）の実行
5. グローバルスタイルの適用（`GlobalStyles`）
6. React-Reduxの`Provider`によるストア接続
7. ローカライズ対応（`I18n`コンポーネント）
8. React Router（ハッシュベース）によるルーティング設定
9. `ReactDOM.createRoot`によるアプリケーションのレンダリング

**関連システム・外部連携**：設定ファイル（config.yml）のHTTP取得、ローカルプロキシサーバーの自動検出（`detectProxyServer`）、各種Gitバックエンド（GitHub, GitLab, Bitbucket等）との接続準備。

**権限による制御**：初期化処理自体には権限制御はないが、初期化完了後に認証処理が実行され、認証済みユーザーのみがCMS機能にアクセスできるようになる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 10 | エラー画面（設定エラー） | 結果表示画面 | アプリケーション初期化時の設定ファイル読み込み失敗をトリガーとしたエラー画面表示 |
| 12 | ローディング画面 | 結果表示画面 | CMSアプリケーションの初期化中にLoaderコンポーネントを表示。config.isFetchingがtrueの間表示 |

## 機能種別

初期化処理（アプリケーションブートストラップ）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| opts | Object | No | bootstrap関数のオプションオブジェクト | - |
| opts.config | Partial<CmsConfig> | No | 手動設定オブジェクト。config.ymlとマージされる | validateConfigで検証 |

### 入力データソース

- HTMLページ内の`<link rel="cms-config-url">`要素（設定ファイルURLのカスタマイズ）
- config.ymlファイル（HTTP GETで取得）
- `window.CMS_CONFIG`グローバル変数（事前設定済みの場合）
- `window.CMS_ENV`グローバル変数（環境別設定の切り替え）
- JavaScript API経由の手動設定オブジェクト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Reactアプリケーション | ReactElement | `nc-root` DOM要素にマウントされたCMSアプリケーション |
| Reduxストア | Store<State> | 初期化済みのアプリケーション状態 |
| コンソールログ | string | バージョン情報（`decap-cms-core {version}`） |

### 出力先

- ブラウザDOM（`nc-root` ID のdiv要素配下）
- ブラウザコンソール（バージョン情報）
- Reduxストア（設定情報、認証状態）

## 処理フロー

### 処理シーケンス

```
1. bootstrap(opts)が呼び出される
   └─ オプションからconfigを取得
2. バージョン番号のコンソールログ出力
   └─ DECAP_CMS_CORE_VERSIONが文字列の場合のみ出力
3. DOMルート要素の取得/作成
   └─ getRoot()で既存の`nc-root`要素を探索、なければ新規作成してbodyに追加
4. store.dispatch(loadConfig(config, onLoad))
   └─ 設定ファイルの非同期読み込みを開始
   └─ onLoadコールバック: authenticateUser()をディスパッチ
5. Rootコンポーネントの定義
   └─ GlobalStyles + Provider + ConnectedTranslatedApp
6. createRoot(getRoot()).render(<Root />)
   └─ Reactアプリケーションのレンダリング
```

### フローチャート

```mermaid
flowchart TD
    A[bootstrap関数呼び出し] --> B{DECAP_CMS_CORE_VERSION<br/>が文字列か?}
    B -->|Yes| C[バージョンをコンソール出力]
    B -->|No| D[スキップ]
    C --> E[getRoot: DOMルート要素取得]
    D --> E
    E --> F{nc-rootが<br/>存在するか?}
    F -->|Yes| G[既存要素を返す]
    F -->|No| H[新規div作成してbodyに追加]
    G --> I[loadConfigをディスパッチ]
    H --> I
    I --> J[設定読み込み開始]
    J --> K{読み込み成功?}
    K -->|Yes| L[authenticateUserをディスパッチ]
    K -->|No| M[configFailedをディスパッチ]
    L --> N[Rootコンポーネント定義]
    M --> N
    N --> O[createRoot.render実行]
    O --> P[アプリケーション表示]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 手動設定のマージ | 手動設定（opts.config）はconfig.ymlの内容とdeepmergeされ、競合時は手動設定が優先される | 手動設定が提供された場合 |
| BR-02 | グローバル設定の即時返却 | window.CMS_CONFIGが存在する場合はファイル読み込みをスキップし即座にconfigLoadedを返す | window.CMS_CONFIGが設定済みの場合 |
| BR-03 | ルート要素の再利用 | 既存の`nc-root`要素がある場合は新規作成せず再利用する | DOM上にnc-rootが存在する場合 |
| BR-04 | 設定読み込み後の認証 | 設定の読み込みが完了した後にのみ認証処理が実行される | loadConfigのonLoadコールバック |

### 計算ロジック

特になし。

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

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

本機能はクライアントサイド処理のため、直接的なデータベース操作はない。状態管理はReduxストア（インメモリ）で行われる。

| 操作 | 対象ストア | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 設定読み込み | config | UPDATE | CONFIG_REQUEST -> CONFIG_SUCCESS/CONFIG_FAILURE |
| 認証確認 | auth | UPDATE | AUTH_REQUEST -> AUTH_SUCCESS/AUTH_FAILURE |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| CONFIG_FAILURE | 設定読み込みエラー | config.ymlの取得失敗（404, ネットワークエラー等） | エラー画面（configError）を表示し、チェック方法を案内 |
| CONFIG_FAILURE | バリデーションエラー | config.ymlの内容が不正（validateConfigで検出） | エラー画面にバリデーションエラー詳細を表示 |
| AUTH_FAILURE | 認証エラー | キャッシュされたトークンの検証失敗 | ログイン画面にフォールバック |

### リトライ仕様

設定ファイルの読み込みに対するリトライ機構は実装されていない。ユーザーによるページリロードで再試行となる。

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

クライアントサイド処理のためトランザクション管理は不要。Reduxのdispatchによる状態遷移は同期的に処理される（非同期アクションはthunkミドルウェアで制御）。

## パフォーマンス要件

- config.ymlの読み込みはHTTP GETリクエスト1回で完了すること
- ローカルプロキシサーバーの検出はタイムアウト付きで実行されること
- 初期化中はLoaderコンポーネントが表示され、ユーザーに待機状態を伝えること

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

- config.ymlの取得は`credentials: 'same-origin'`で実行され、クロスオリジンリクエストでの認証情報漏洩を防止
- 認証トークンのキャッシュ検証は初期化の一部として実行される
- `window.CMS_CONFIG`によるグローバル設定は、ページ内スクリプトからのみアクセス可能

## 備考

- Decap CMSはReact 18の`createRoot` APIを使用している
- ルーティングはハッシュベース（`createHashHistory`）で実装されている
- ポリフィル（`./lib/polyfill`）が最初にインポートされ、ブラウザ互換性が確保される
- `what-input`ライブラリがインポートされ、入力デバイス（マウス/キーボード/タッチ）の検出が行われる

---

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

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

### 推奨読解順序

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

まず、アプリケーション状態の型定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | redux/index.ts | `packages/decap-cms-core/src/redux/index.ts` | Reduxストアの構成（thunkミドルウェア、waitUntilActionミドルウェア、DevTools） |
| 1-2 | config.ts (reducer) | `packages/decap-cms-core/src/reducers/config.ts` | 設定状態の型（CmsConfig）、デフォルト状態（isFetching: true） |
| 1-3 | auth.ts (reducer) | `packages/decap-cms-core/src/reducers/auth.ts` | 認証状態の型（Auth: isFetching, user, error） |

**読解のコツ**: Reduxストアは`createStore`で作成され、`thunkMiddleware`と`waitUntilAction`の2つのミドルウェアが適用されている。`composeWithDevTools`によりRedux DevToolsでの状態監視が可能。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | bootstrap.js | `packages/decap-cms-core/src/bootstrap.js` | アプリケーション初期化のメインロジック |

**主要処理フロー**:
1. **1行目**: ポリフィルのインポート（最初に実行される）
2. **21行目**: ROOT_ID定数の定義（`nc-root`）
3. **23-33行目**: TranslatedAppコンポーネント（I18n + ErrorBoundary + Router + App）
4. **35-37行目**: mapDispatchToProps（locale, configをReduxストアから取得）
5. **41行目**: bootstrap関数の定義（オプションからconfigを取得）
6. **47-49行目**: バージョン番号のコンソール出力
7. **54-70行目**: getRoot関数（DOM要素の取得/作成）
8. **77-81行目**: loadConfigのディスパッチとonLoadコールバック内でのauthenticateUser
9. **86-95行目**: Rootコンポーネントの定義（GlobalStyles + Provider + ConnectedTranslatedApp）
10. **100-101行目**: createRootによるレンダリング

#### Step 3: 設定読み込み処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | config.ts (actions) | `packages/decap-cms-core/src/actions/config.ts` | loadConfig関数の実装 |

**主要処理フロー**:
- **523-526行目**: `window.CMS_CONFIG`が存在する場合の即時返却
- **527-558行目**: 非同期設定読み込み（getConfigYaml -> deepmerge -> validateConfig -> handleLocalBackend -> normalizeConfig -> applyDefaults）
- **62-73行目**: getConfigUrl（`<link rel="cms-config-url">`からURL取得、デフォルトは`config.yml`）
- **403-421行目**: getConfigYaml（HTTPフェッチとYAMLパース）
- **388-401行目**: parseConfig（YAMLパースと環境別設定のマージ）

#### Step 4: 認証処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | auth.ts (actions) | `packages/decap-cms-core/src/actions/auth.ts` | authenticateUser関数の実装 |

**主要処理フロー**:
- **56-77行目**: authenticateUser（キャッシュされたトークンの検証、Open Authoringモードの判定）

#### Step 5: Appコンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | App.js | `packages/decap-cms-core/src/components/App/App.js` | メインAppコンポーネントの状態分岐ロジック |

**主要処理フロー**:
- **161-163行目**: config === nullの場合はnull返却
- **165-167行目**: config.errorの場合はconfigError画面表示
- **169-171行目**: config.isFetchingの場合はLoader表示
- **173-175行目**: user == nullの場合は認証画面表示
- **180-258行目**: 認証済みの場合はメインUI（Header + Router + MediaLibrary）を表示

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

```
bootstrap(opts)
    |
    +-- store.dispatch(loadConfig(config, onLoad))
    |       |
    |       +-- configLoading()
    |       +-- getConfigUrl()
    |       +-- getConfigYaml(configUrl)
    |       |       +-- fetch(file)
    |       |       +-- parseConfig(text)
    |       +-- deepmerge(configYaml, manualConfig)
    |       +-- validateConfig(mergedConfig)
    |       +-- handleLocalBackend(mergedConfig)
    |       |       +-- detectProxyServer(local_backend)
    |       +-- normalizeConfig(config)
    |       +-- applyDefaults(config)
    |       +-- configLoaded(config)
    |       +-- onLoad()
    |               +-- store.dispatch(authenticateUser())
    |                       +-- currentBackend(config)
    |                       +-- backend.currentUser()
    |                       +-- authenticate(user) / doneAuthenticating()
    |
    +-- Root()
    |       +-- GlobalStyles
    |       +-- Provider(store)
    |               +-- ConnectedTranslatedApp
    |                       +-- I18n(locale, messages)
    |                       +-- ErrorBoundary
    |                       +-- Router(history)
    |                               +-- App
    |
    +-- createRoot(getRoot()).render(<Root />)
```

### データフロー図

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

config.yml (HTTP GET) ---------> parseConfig() ----+
                                                    |
opts.config (JS API) ----------> deepmerge() ------+---> validateConfig()
                                                    |         |
window.CMS_CONFIG ----+                             |    normalizeConfig()
                      |                             |         |
<link> 要素 ---------+-> getConfigUrl()             |    applyDefaults()
                                                    |         |
                                                    +---> configLoaded() --> Reduxストア(config)
                                                                                   |
                                                                            authenticateUser()
                                                                                   |
                                                                            Reduxストア(auth)
                                                                                   |
                                                                            App.render()
                                                                                   |
                                                                            ブラウザDOM(nc-root)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| bootstrap.js | `packages/decap-cms-core/src/bootstrap.js` | ソース | アプリケーション初期化のメインエントリーポイント |
| index.ts (redux) | `packages/decap-cms-core/src/redux/index.ts` | ソース | Reduxストアの作成と設定 |
| config.ts (actions) | `packages/decap-cms-core/src/actions/config.ts` | ソース | 設定読み込みアクション |
| auth.ts (actions) | `packages/decap-cms-core/src/actions/auth.ts` | ソース | 認証アクション |
| config.ts (reducer) | `packages/decap-cms-core/src/reducers/config.ts` | ソース | 設定状態のリデューサー |
| auth.ts (reducer) | `packages/decap-cms-core/src/reducers/auth.ts` | ソース | 認証状態のリデューサー |
| history.ts | `packages/decap-cms-core/src/routing/history.ts` | ソース | ハッシュベースルーティングのhistoryオブジェクト |
| App.js | `packages/decap-cms-core/src/components/App/App.js` | ソース | メインAppコンポーネント（状態分岐とルーティング） |
| phrases.ts | `packages/decap-cms-core/src/lib/phrases.ts` | ソース | ローカライズフレーズの取得 |
| EditorWidgets | `packages/decap-cms-core/src/components/EditorWidgets/` | ソース | エディタウィジェットの登録（副作用インポート） |
| mediaLibrary.ts | `packages/decap-cms-core/src/mediaLibrary.ts` | ソース | メディアライブラリの初期化（副作用インポート） |
