# 画面設計書 8-ワークフロー画面

## 概要

本ドキュメントは、Decap CMS のワークフロー画面（Workflow）の画面設計書である。Editorial Workflow有効時にカンバンボード形式で未公開エントリのステータスを管理する画面の仕様を定義する。

### 本画面の処理概要

**業務上の目的・背景**：コンテンツの公開プロセスを管理するために、ドラフト(Draft)・レビュー待ち(In Review)・公開準備完了(Ready)の3段階のステータスでエントリを管理する。カンバンボード形式でエントリカードを視覚的に配置し、ドラッグ&ドロップによるステータス変更を可能にする。これにより、複数のコンテンツ制作者・編集者間のワークフローを効率化する。

**画面へのアクセス方法**：ヘッダーの「Workflow」リンクからアクセスする。URLは`/workflow`。config.ymlで`publish_mode: editorial_workflow`が設定されている場合のみ利用可能。

**主要な操作・処理内容**：
1. 未公開エントリを3カラム（Draft / In Review / Ready）のカンバンボードで一覧表示する
2. エントリカードをドラッグ&ドロップしてステータスを変更する
3. エントリカードをクリックしてエントリ編集画面に遷移する
4. エントリカードから直接公開操作を行う
5. エントリカードから未公開エントリを削除する
6. 「New Post」ドロップダウンからコレクションを選択して新規エントリを作成する

**画面遷移**：
- 遷移元：コレクション一覧画面（ヘッダーWorkflowリンク）、エントリ編集画面（ヘッダーWorkflowリンク）
- 遷移先：エントリ編集画面（エントリカードクリック）、エントリ新規作成画面（New Postドロップダウン）、コレクション一覧画面（ヘッダーContentリンク）、メディアライブラリ画面（ヘッダーMediaボタン）

**権限による表示制御**：`publish_mode`が`editorial_workflow`でない場合はこの画面自体が表示されない（ルーティングにも追加されない）。Open Authoring時はReady(Pending Publish)カラムが非表示になり、2カラムレイアウトになる（WorkflowList.js 行190-191）。コレクション設定の`publish`フラグにより公開ボタンの表示が制御される。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 17 | ワークフロー管理 | 主機能 | ドラフト・レビュー待ち・公開待ちの3カラムカンバンボードによるエントリステータス管理 |
| 19 | エントリ公開 | 補助機能 | ワークフローボードからの直接公開処理 |
| 21 | 未公開エントリ削除 | 補助機能 | ワークフローボードからの未公開エントリ削除 |
| 74 | ドラッグ&ドロップ | 補助機能 | エントリカードのドラッグ&ドロップによるステータス変更 |
| 73 | ヘッダー | 補助機能 | ヘッダーのワークフローリンクからの遷移 |
| 8 | エントリ作成・編集 | 遷移先機能 | New Postドロップダウンからの新規エントリ作成画面への遷移 |

## 画面種別

一覧（カンバンボード）

## URL/ルーティング

| パス | 説明 |
|------|------|
| `/workflow` | ワークフロー画面。publish_mode=editorial_workflowの場合のみルート追加 |

## 入出力項目

### 入力項目

入力フォームなし。操作はカードのドラッグ&ドロップとボタンクリック。

## 表示項目

| 項目名 | 表示条件 | 説明 |
|--------|---------|------|
| ヘッダー | 常時 | 通常のヘッダーナビゲーション |
| ワークフロー見出し | 常時 | 「Editorial Workflow」見出し |
| 説明文 | 常時 | レビュー待ち数と公開準備完了数のサマリー |
| New Postドロップダウン | 常時 | create=trueのコレクション一覧からの新規エントリ作成 |
| Draftカラム | 常時 | ドラフトステータスのエントリカード一覧 |
| In Reviewカラム | 常時 | レビュー待ちステータスのエントリカード一覧 |
| Readyカラム | !isOpenAuthoring | 公開準備完了ステータスのエントリカード一覧 |
| エントリカード | 各カラム内 | コレクション名、エントリタイトル、最終更新者、更新日時、本文プレビュー |
| カード内公開ボタン | ownStatus === status.last() && !isPersisting && allowPublish | エントリの直接公開 |
| カード内削除ボタン | 各カード | エントリの削除 |
| ローディング | isFetching=true | 読み込み中のLoaderコンポーネント |

## イベント仕様

### 1-ドラッグ&ドロップによるステータス変更

1. エントリカードをDragSourceとしてドラッグ開始（WorkflowList.js 行229-234）
2. 対象カラムのDropTargetにドロップ（WorkflowList.js 行177-208）
3. `handleChangeStatus(newStatus, dragProps)`が呼ばれる（WorkflowList.js 行147-152）
4. `updateUnpublishedEntryStatus(collection, slug, oldStatus, newStatus)`アクションをdispatch

### 2-エントリカードクリック

1. WorkflowCardのeditLinkをクリック
2. `collections/{collectionName}/entries/{slug}?ref=workflow`に遷移（WorkflowList.js 行216）
3. エントリ編集画面が表示される（戻るリンクはワークフロー画面に設定）

### 3-カード内公開ボタン押下

1. WorkflowCardのonPublishをクリック
2. `requestPublish(collection, slug, ownStatus)`が呼ばれる（WorkflowList.js 行160-168）
3. ステータスがPENDING_PUBLISHでない場合、アラートで拒否
4. 確認ダイアログ後、`publishUnpublishedEntry(collection, slug)`をdispatch

### 4-カード内削除ボタン押下

1. WorkflowCardのonDeleteをクリック
2. `requestDelete(collection, slug, ownStatus)`が呼ばれる（WorkflowList.js 行154-158）
3. 確認ダイアログ後、`deleteUnpublishedEntry(collection, slug, ownStatus)`をdispatch

### 5-New Postドロップダウンでコレクション選択

1. Dropdownからコレクションを選択（Workflow.js 行110-119）
2. `createNewEntry(collectionName)`を実行
3. `/collections/{collectionName}/new`に遷移

### 6-コンポーネントマウント時

1. componentDidMount（Workflow.js 行69-77）で`loadUnpublishedEntries(collections)`を呼び出す
2. 全コレクションの未公開エントリを読み込む

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ステータス変更 | Redux State (editorialWorkflow) / Gitメタデータ | UPDATE | 未公開エントリのステータスを更新 |
| 公開 | Gitリポジトリ / Redux State | UPDATE/DELETE | ブランチをメインブランチにマージ、ワークフローから削除 |
| 削除 | Gitリポジトリ / Redux State | DELETE | 未公開エントリのブランチを削除 |

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

#### Redux State: editorialWorkflow

| 操作 | 項目（キー） | 更新値・取得条件 | 備考 |
|-----|-------------|-----------------|------|
| UPDATE | entries[].status | 'draft' / 'pending_review' / 'pending_publish' | ステータス変更時 |
| DELETE | entries[] | 公開/削除されたエントリを除去 | 公開・削除時 |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|--------------|---------|
| workflow.workflow.loading | 情報 | 読み込み中表示 | isFetching=true |
| workflow.workflow.workflowHeading | 情報 | 「Editorial Workflow」見出し | 常時 |
| workflow.workflow.newPost | 情報 | 「New Post」ドロップダウンボタン | 常時 |
| workflow.workflow.description | 情報 | レビュー待ち数と公開準備完了数のサマリー | 常時 |
| workflow.workflowList.draftHeader | 情報 | 「Drafts」カラムヘッダー | 常時 |
| workflow.workflowList.inReviewHeader | 情報 | 「In Review」カラムヘッダー | 常時 |
| workflow.workflowList.readyHeader | 情報 | 「Ready」カラムヘッダー | !isOpenAuthoring |
| workflow.workflowList.currentEntries | 情報 | カラム内エントリ数表示 | 常時 |
| workflow.workflowList.onDeleteEntry | 確認 | 削除確認ダイアログ | 削除ボタン押下時 |
| workflow.workflowList.onPublishingNotReadyEntry | 警告 | 公開準備未完了アラート | Ready以外のステータスで公開試行時 |
| workflow.workflowList.onPublishEntry | 確認 | 公開確認ダイアログ | 公開ボタン押下時 |

## 例外処理

| 例外条件 | 処理内容 | 画面表示 |
|---------|---------|---------|
| Editorial Workflowが無効 | render内でnullを返す | 画面表示なし（Workflow.js 行92） |
| 未公開エントリ読み込み中 | Loaderコンポーネント表示 | 「Loading...」ローダー |
| Ready以外のステータスで公開試行 | window.alertで拒否 | アラートダイアログ |

## 備考

- ワークフロー画面はconfig.ymlの`publish_mode: editorial_workflow`が設定されている場合のみ利用可能（App.js 行213）。
- ドラッグ&ドロップはHTML5DragDrop HOCとDragSource/DropTargetコンポーネントで実装される（WorkflowList.js 行272）。
- DNDNamespace 'cms-workflow'により、ワークフロー画面のカード以外のドラッグ要素との干渉を防止（WorkflowList.js 行118）。
- Open Authoring時は2カラムレイアウト（Draft + In Review）になり、Readyカラムは非表示（WorkflowList.js 行20-25, 190-191）。
- エントリカードの編集リンクには`?ref=workflow`が付加され、エディタの戻るリンクがワークフロー画面に設定される（WorkflowList.js 行216）。
- 日時表示にはdayjsライブラリが使用される（WorkflowList.js 行213）。

---

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

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

### 推奨読解順序

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

未公開エントリのRedux state構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Workflow.js | `packages/decap-cms-core/src/components/Workflow/Workflow.js` | mapStateToProps（行142-162）でのunpublishedEntriesの構造。OrderedMapでstatus別にエントリを管理 |

**読解のコツ**: `status.reduce((acc, currStatus) => ...)`でstatus別のOrderedMapを構築するパターンに注目（行156-159）。

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

App.jsのルーティングとWorkflowの初期化を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | App.js | `packages/decap-cms-core/src/components/App/App.js` | 行213のhasWorkflow判定によるルート追加 |
| 2-2 | Workflow.js | `packages/decap-cms-core/src/components/Workflow/Workflow.js` | componentDidMount（行69-77）のloadUnpublishedEntries呼び出し |

#### Step 3: WorkflowListのカンバンボードを理解する

ドラッグ&ドロップとステータス変更の実装を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | WorkflowList.js | `packages/decap-cms-core/src/components/Workflow/WorkflowList.js` | renderColumns（行171-261）のDropTarget/DragSourceによるDnD実装 |

**主要処理フロー**:
- **行171-208**: カラム描画。DropTargetでドロップイベントを処理
- **行210-261**: エントリカード描画。DragSourceでドラッグ元を設定
- **行147-152**: handleChangeStatusでステータス変更

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

```
App.js (Route: /workflow)
    |
    +-- Workflow (connect + translate)
            |
            +-- componentDidMount
            |       +-- loadUnpublishedEntries(collections)
            |
            +-- WorkflowTop
            |       +-- WorkflowHeading
            |       +-- New Post Dropdown -> createNewEntry
            |       +-- WorkflowDescription
            |
            +-- WorkflowList (HTML5DragDrop HOC)
                    |
                    +-- DropTarget (各カラム)
                    |       +-- ColumnHeader (Draft / In Review / Ready)
                    |       +-- ColumnCount
                    |       +-- DragSource (各エントリカード)
                    |               +-- WorkflowCard
                    |                       +-- editLink -> /collections/:name/entries/:slug?ref=workflow
                    |                       +-- onDelete -> requestDelete -> deleteUnpublishedEntry
                    |                       +-- onPublish -> requestPublish -> publishUnpublishedEntry
                    |
                    +-- handleChangeStatus -> updateUnpublishedEntryStatus
```

### データフロー図

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

ページアクセス       ──▶  loadUnpublishedEntries             ──▶  Redux State
                         |                                       (editorialWorkflow)
                         +-- backend.unpublishedEntries()

ドラッグ&ドロップ    ──▶  updateUnpublishedEntryStatus       ──▶  Redux State更新
(newStatus)              |                                       カラム間移動
                         +-- backend.updateUnpublishedEntryStatus()

公開ボタン          ──▶  publishUnpublishedEntry             ──▶  Gitリポジトリ (マージ)
                         |                                       Redux State削除
                         +-- backend.publishUnpublishedEntry()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Workflow.js | `packages/decap-cms-core/src/components/Workflow/Workflow.js` | ソース | ワークフロー画面のメインコンテナ |
| WorkflowList.js | `packages/decap-cms-core/src/components/Workflow/WorkflowList.js` | ソース | カンバンボードのカラム・カード描画 |
| WorkflowCard.js | `packages/decap-cms-core/src/components/Workflow/WorkflowCard.js` | ソース | エントリカードコンポーネント |
| editorialWorkflow.js | `packages/decap-cms-core/src/actions/editorialWorkflow.js` | ソース | ワークフロー関連のReduxアクション |
| publishModes.js | `packages/decap-cms-core/src/constants/publishModes.js` | ソース | ステータス定数定義 |
| App.js | `packages/decap-cms-core/src/components/App/App.js` | ソース | ルーティング定義 |
