# 機能設計書 21-未公開エントリ削除

## 概要

本ドキュメントは、Decap CMSのエディトリアルワークフローにおける未公開エントリ（ブランチ）の削除機能について、処理フロー・入出力仕様・データ操作・エラー処理を詳細に記述した機能設計書である。

### 本機能の処理概要

エディトリアルワークフローで管理されている未公開状態のエントリ（Draft / Pending Review / Pending Publish）を削除する機能である。バックエンドのGitリポジトリ上に作成された対応ブランチおよびプルリクエストを削除し、Redux状態から該当エントリ情報を除去する。

**業務上の目的・背景**：エディトリアルワークフローでは、エントリは編集ブランチ上で管理される。不要になった下書きやレビュー中のエントリを削除することで、リポジトリのブランチの肥大化を防ぎ、ワークフローボードの整理を可能にする。誤って作成したエントリや、不採用となったコンテンツの破棄に使用される。

**機能の利用シーン**：
- エントリ編集画面のツールバーから未公開エントリの削除ボタンを押下した場合
- ワークフロー画面（カンバンボード）から未公開エントリを削除する場合
- 不要な下書きエントリをクリーンアップする場合

**主要な処理内容**：
1. `deleteUnpublishedEntry`アクションが呼び出され、バックエンドの`deleteUnpublishedEntry`メソッドを実行
2. バックエンド側でGitリポジトリのブランチ及びプルリクエストを削除
3. 成功時、Redux状態（editorialWorkflowリデューサー）から該当エントリ情報を削除
4. 成功・失敗に応じたトースト通知をユーザーに表示

**関連システム・外部連携**：GitHub / GitLab / Bitbucket / Git Gateway等のGitバックエンドAPIを経由してブランチ・PR削除を実行する。

**権限による制御**：Open Authoringモードの場合、フォーク上のブランチに対する削除権限が必要。通常モードでは、リポジトリへの書き込み権限を持つ認証済みユーザーのみ実行可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 6 | エントリ編集画面 | 主画面 | 未公開エントリの削除処理。deleteUnpublishedEntryアクションを実行 |
| 8 | ワークフロー画面 | 主画面 | ワークフローボードからの未公開エントリ削除。deleteUnpublishedEntryアクションの実行 |

## 機能種別

CRUD操作（Delete）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| collection | string | Yes | コレクション名 | 存在するコレクション名であること |
| slug | string | Yes | エントリのスラッグ | 未公開エントリとして存在すること |

### 入力データソース

- Redux状態の`editorialWorkflow.entities`から該当エントリ情報を参照
- ユーザーのUI操作（エントリ編集画面の削除ボタン、ワークフロー画面の削除操作）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| type | string | Reduxアクションタイプ（UNPUBLISHED_ENTRY_DELETE_REQUEST / SUCCESS / FAILURE） |
| payload.collection | string | 対象コレクション名 |
| payload.slug | string | 対象エントリスラッグ |

### 出力先

- Redux Store: `editorialWorkflow.entities`から該当エントリを削除
- Git バックエンド: 対応するブランチ・PRの削除
- UI: トースト通知（成功 / 失敗メッセージ）

## 処理フロー

### 処理シーケンス

```
1. deleteUnpublishedEntry(collection, slug)が呼び出される
   └─ エントリ編集画面またはワークフロー画面からのユーザー操作
2. Redux Stateからconfigを取得し、currentBackendを取得
   └─ getState().configを使用してバックエンドインスタンスを取得
3. UNPUBLISHED_ENTRY_DELETE_REQUESTアクションをディスパッチ
   └─ リデューサー側では特に状態変更なし（現在の実装ではDELETE_REQUESTのcaseは未定義）
4. backend.deleteUnpublishedEntry(collection, slug)を呼び出す
   └─ バックエンドAPIを通じてブランチ・PRを削除
5a. 成功時:
   └─ 'ui.toast.onDeleteUnpublishedChanges'の成功通知をディスパッチ
   └─ UNPUBLISHED_ENTRY_DELETE_SUCCESSアクションをディスパッチ
   └─ リデューサーがentitiesから`${collection}.${slug}`キーのエントリを削除
5b. 失敗時:
   └─ 'ui.toast.onDeleteUnpublishedChanges'のエラー通知をディスパッチ
   └─ UNPUBLISHED_ENTRY_DELETE_FAILUREアクションをディスパッチ
```

### フローチャート

```mermaid
flowchart TD
    A[deleteUnpublishedEntry呼び出し] --> B[currentBackend取得]
    B --> C[DELETE_REQUESTディスパッチ]
    C --> D[backend.deleteUnpublishedEntry実行]
    D --> E{成功?}
    E -->|Yes| F[成功通知ディスパッチ]
    F --> G[DELETE_SUCCESSディスパッチ]
    G --> H[entities から該当エントリ削除]
    E -->|No| I[エラー通知ディスパッチ]
    I --> J[DELETE_FAILUREディスパッチ]
    H --> K[終了]
    J --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-21-01 | 未公開エントリのみ削除可能 | エディトリアルワークフローで管理されている未公開状態のエントリのみが削除対象となる | エディトリアルワークフローが有効な場合 |
| BR-21-02 | ブランチとPRの同時削除 | バックエンドAPIを通じて、対応するGitブランチとプルリクエストが同時に削除される | Git系バックエンド使用時 |
| BR-21-03 | 削除の非可逆性 | 一度削除された未公開エントリは復元できない | 常時 |

### 計算ロジック

特になし。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 未公開エントリ削除 | Redux Store: editorialWorkflow.entities | DELETE | `${collection}.${slug}`キーのエントリを削除 |
| Gitブランチ削除 | Git Repository | DELETE | 対応するブランチを削除 |
| PR削除 | Git Provider API | DELETE | 対応するプルリクエストを閉じる/削除 |

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

#### Redux Store: editorialWorkflow

| 操作 | 項目（キー） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | entities[`${collection}.${slug}`] | キーごと削除 | UNPUBLISHED_ENTRY_DELETE_SUCCESS時に実行 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | バックエンドAPIエラー | Git APIの通信失敗・認証エラー | エラートースト通知を表示、DELETE_FAILUREアクションをディスパッチ |
| - | ブランチ未存在 | 既に削除済みのブランチに対する削除操作 | バックエンドのエラーハンドリングに依存 |

### リトライ仕様

自動リトライは実装されていない。ユーザーが再度削除操作を実行する必要がある。

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

Redux Store上の削除操作は、バックエンドAPIの成功レスポンスを受けてから実行される。バックエンドAPI実行中にUIがブロックされることはないが、リクエスト中はDELETE_REQUESTアクションがディスパッチされる。Git操作自体はアトミックではなく、ブランチ削除とPR削除が個別に実行されるため、部分的な失敗が発生する可能性がある。

## パフォーマンス要件

特別なパフォーマンス要件は定義されていない。Git APIへの削除リクエストのレスポンス時間に依存する。

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

- 認証済みユーザーのみが削除操作を実行可能
- Git APIのトークン認証を通じてアクセス制御が行われる
- Open Authoringモードでは、自分のフォーク上のブランチのみ削除可能

## 備考

- 削除前の確認ダイアログはUI側（エディタツールバーやワークフロー画面）で実装される
- 削除成功後、エントリ編集画面にいる場合はコレクション一覧画面にリダイレクトされる（UI側の処理）
- Redux Storeの`editorialWorkflow`リデューサーでは`UNPUBLISHED_ENTRY_DELETE_REQUEST`と`UNPUBLISHED_ENTRY_DELETE_FAILURE`に対するcaseハンドラが明示的に実装されていない点に注意

---

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

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

### 推奨読解順序

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

Redux Storeにおけるエディトリアルワークフローの状態構造と、アクション定数を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | editorialWorkflow.ts (reducer) | `packages/decap-cms-core/src/reducers/editorialWorkflow.ts` | エディトリアルワークフロー状態の構造。entitiesマップのキー構造（`${collection}.${slug}`） |
| 1-2 | publishModes.ts | `packages/decap-cms-core/src/constants/publishModes.ts` | ワークフローステータス定数（Draft, Pending Review, Pending Publish） |

**読解のコツ**: Redux + Immutable.jsパターン。状態はImmutable.jsのMapで管理され、`getIn`/`setIn`/`deleteIn`でネストされたパスにアクセスする。

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

削除処理のthunkアクションクリエーターを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | editorialWorkflow.ts (actions) | `packages/decap-cms-core/src/actions/editorialWorkflow.ts` | `deleteUnpublishedEntry`関数（452-480行目）が本機能のエントリーポイント |

**主要処理フロー**:
1. **452行目**: `deleteUnpublishedEntry`関数定義。collection（string）とslug（string）を受け取る
2. **454行目**: `getState()`でRedux Stateを取得
3. **455行目**: `currentBackend(state.config)`でバックエンドインスタンスを取得
4. **456行目**: `unpublishedEntryDeleteRequest`アクションをディスパッチ
5. **457-458行目**: `backend.deleteUnpublishedEntry(collection, slug)`を呼び出し
6. **459-467行目**: 成功時の処理（通知 + DELETE_SUCCESSディスパッチ）
7. **469-478行目**: 失敗時の処理（エラー通知 + DELETE_FAILUREディスパッチ）

#### Step 3: アクションクリエーターを理解する

内部で使用されるシンプルアクションクリエーターを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | editorialWorkflow.ts (actions) | `packages/decap-cms-core/src/actions/editorialWorkflow.ts` | `unpublishedEntryDeleteRequest`（215-220行目）、`unpublishedEntryDeleted`（222-227行目）、`unpublishedEntryDeleteError`（229-234行目）の3つのアクションクリエーター |

#### Step 4: リデューサーでの状態更新を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | editorialWorkflow.ts (reducer) | `packages/decap-cms-core/src/reducers/editorialWorkflow.ts` | **135-136行目**: `UNPUBLISHED_ENTRY_DELETE_SUCCESS`ケースでentitiesから該当エントリを削除 |

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

```
deleteUnpublishedEntry(collection, slug)          [actions/editorialWorkflow.ts:452]
    |
    +-- currentBackend(state.config)               [backend.ts]
    |
    +-- dispatch(unpublishedEntryDeleteRequest)     [actions/editorialWorkflow.ts:215]
    |
    +-- backend.deleteUnpublishedEntry(collection, slug)  [各バックエンド実装]
    |
    +-- [成功時]
    |   +-- dispatch(addNotification({success}))   [actions/notifications.ts]
    |   +-- dispatch(unpublishedEntryDeleted)       [actions/editorialWorkflow.ts:222]
    |       +-- reducer: entities.deleteIn          [reducers/editorialWorkflow.ts:135]
    |
    +-- [失敗時]
        +-- dispatch(addNotification({error}))     [actions/notifications.ts]
        +-- dispatch(unpublishedEntryDeleteError)   [actions/editorialWorkflow.ts:229]
```

### データフロー図

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

ユーザー操作          dispatch(deleteUnpublishedEntry)     Redux Store更新
(collection, slug)        |                               (entitiesから削除)
        |                 v
        +---------> currentBackend取得                     Git API
                      |                                   (ブランチ/PR削除)
                      v
                  DELETE_REQUEST dispatch                   UI通知
                      |                                   (トースト表示)
                      v
                  backend.deleteUnpublishedEntry
                      |
                      v
                  成功/失敗 -> 通知 + SUCCESS/FAILURE
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| editorialWorkflow.ts | `packages/decap-cms-core/src/actions/editorialWorkflow.ts` | ソース | 削除アクションの定義（deleteUnpublishedEntry） |
| editorialWorkflow.ts | `packages/decap-cms-core/src/reducers/editorialWorkflow.ts` | ソース | Redux状態の更新（DELETE_SUCCESS時のentities削除） |
| notifications.ts | `packages/decap-cms-core/src/actions/notifications.ts` | ソース | トースト通知アクション |
| backend.ts | `packages/decap-cms-core/src/backend.ts` | ソース | バックエンドインスタンスの取得（currentBackend） |
| EditorToolbar.js | `packages/decap-cms-core/src/components/Editor/EditorToolbar.js` | ソース | エントリ編集画面からの削除トリガー |
