# 機能設計書 109-ブログ記事管理

## 概要

本ドキュメントは、ブログプラグイン(blogs)におけるブログ記事管理機能の設計仕様を定義する。

### 本機能の処理概要

ブログ記事の作成・編集・削除・公開を行い、コンテンツマーケティングやナレッジ共有のための記事管理機能を提供する。

**業務上の目的・背景**：企業サイトやポータルサイトにおいて、ブログ記事を管理・公開することで、情報発信やSEO対策、顧客エンゲージメントの向上を実現する。

**機能の利用シーン**：
- コンテンツ担当者がブログ記事を作成・編集する
- 記事をカテゴリやタグで分類する
- SEOメタ情報を設定する
- 記事を公開/非公開にする

**主要な処理内容**：
1. ブログ記事の作成・編集・削除・表示
2. カテゴリへの紐付け
3. タグの設定（複数選択）
4. バナー画像のアップロード
5. SEOメタ情報の設定（タイトル/キーワード/説明）
6. 公開状態の管理
7. 自動スラッグ生成

**関連システム・外部連携**：Category、Tag、User（author/creator）と連携。

**権限による制御**：SoftDeletes対応。削除済み記事の復元・完全削除が可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| SCR-POST-001 | ListPosts | 一覧画面 | ブログ記事一覧表示・検索・フィルタ |
| SCR-POST-002 | CreatePost | 作成画面 | 新規記事作成 |
| SCR-POST-003 | EditPost | 編集画面 | 記事編集 |
| SCR-POST-004 | ViewPost | 詳細画面 | 記事詳細表示 |

## 機能種別

CRUD操作 / コンテンツ管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| title | string | Yes | 記事タイトル | 最大255文字 |
| slug | string | Yes | スラッグ（URLパス） | 最大255文字、ユニーク、自動生成（disabled） |
| sub_title | text | No | サブタイトル | - |
| content | text | Yes | 本文（リッチテキスト） | 必須 |
| image | file | No | バナー画像 | 画像ファイル |
| meta_title | string | No | メタタイトル | 最大255文字 |
| meta_keywords | string | No | メタキーワード | 最大255文字 |
| meta_description | text | No | メタ説明文 | - |
| category_id | integer | Yes | カテゴリID | categoriesテーブルに存在するID |
| tags | array | No | タグID配列 | tagsテーブルに存在するID |

### 入力データソース

画面フォーム入力、Postモデル

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | integer | 記事ID |
| title | string | 記事タイトル |
| slug | string | スラッグ |
| sub_title | string | サブタイトル |
| content | text | 本文 |
| image | string | バナー画像パス |
| author.name | string | 著者名 |
| category.name | string | カテゴリ名 |
| tags.name | array | タグ名一覧 |
| is_published | boolean | 公開フラグ |
| published_at | datetime | 公開日時 |
| creator.name | string | 作成者名 |
| created_at | datetime | 作成日時 |
| updated_at | datetime | 更新日時 |

### 出力先

Filamentテーブル画面、Infolist詳細画面、データベース(blogs_posts)

## 処理フロー

### 処理シーケンス

```
1. ブログ記事一覧表示
   └─ 公開状態、著者、カテゴリ、タグでフィルタ可能
2. ブログ記事作成
   └─ タイトル入力 → スラッグ自動生成 → フォーム入力 → DBへ保存
3. ブログ記事編集
   └─ 既存データ取得 → フォーム表示 → 更新保存
4. ブログ記事削除
   └─ ソフトデリート(SoftDeletes)
5. ブログ記事復元
   └─ deleted_atをnullに設定
6. ブログ記事完全削除
   └─ 物理削除
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[記事一覧表示]
    B --> C{操作選択}
    C -->|作成| D[作成フォーム表示]
    C -->|編集| E[編集フォーム表示]
    C -->|詳細| F[詳細画面表示]
    C -->|削除| G[ソフトデリート]
    C -->|復元| H[restore処理]
    C -->|完全削除| I[物理削除]
    D --> J[タイトル入力]
    J --> K[スラッグ自動生成]
    K --> L[その他入力]
    L --> M[入力バリデーション]
    E --> M
    M -->|OK| N[DB保存]
    M -->|NG| O[エラー表示]
    G --> P[成功通知]
    H --> P
    I --> P
    N --> P
    O --> C
    P --> B
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-109-01 | スラッグ自動生成 | タイトル入力時（作成時のみ）にスラッグを自動生成 | 作成時、onBlur |
| BR-109-02 | スラッグ編集不可 | スラッグフィールドはdisabled（編集不可） | フォーム表示時 |
| BR-109-03 | スラッグ一意性 | スラッグは同テーブル内でユニーク | 保存時 |
| BR-109-04 | 削除済みカテゴリ表示 | カテゴリ選択時に削除済みカテゴリも表示（選択不可） | フォーム表示時 |
| BR-109-05 | ソフトデリート | 削除は論理削除（deleted_at設定） | 削除時 |
| BR-109-06 | 削除済み操作制限 | 削除済み記事は表示/編集不可（復元/完全削除のみ） | 一覧操作時 |

### 計算ロジック

スラッグ自動生成:
```php
// 作成時のみ
if ($operation === 'create') {
    $set('slug', Str::slug($state));
}
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 一覧表示 | blogs_posts | SELECT | 公開状態/著者/カテゴリ/タグでフィルタ可能 |
| 作成 | blogs_posts | INSERT | 新規記事登録 |
| 作成 | blogs_post_tag | INSERT | タグ関連付け |
| 編集 | blogs_posts | UPDATE | 記事情報更新 |
| 削除 | blogs_posts | UPDATE | deleted_atをセット(ソフトデリート) |
| 復元 | blogs_posts | UPDATE | deleted_atをnullに |
| 完全削除 | blogs_posts | DELETE | 物理削除 |

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

#### blogs_posts

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | title | ユーザー入力値 | 必須 |
| INSERT | slug | Str::slug(title) | 自動生成 |
| INSERT | sub_title | ユーザー入力値 | 任意 |
| INSERT | content | ユーザー入力値 | 必須 |
| INSERT | image | アップロードパス | 任意 |
| INSERT | meta_title | ユーザー入力値 | 任意 |
| INSERT | meta_keywords | ユーザー入力値 | 任意 |
| INSERT | meta_description | ユーザー入力値 | 任意 |
| INSERT | category_id | 選択値 | 必須 |
| INSERT | author_id | Auth::id() | 自動設定 |
| INSERT | creator_id | Auth::id() | 自動設定 |
| UPDATE | deleted_at | now() | ソフトデリート時 |
| UPDATE | deleted_at | null | 復元時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| E-109-01 | バリデーションエラー | 必須項目未入力 | エラーメッセージ表示 |
| E-109-02 | ユニーク制約エラー | スラッグ重複 | エラーメッセージ表示 |

### リトライ仕様

特になし(画面操作による再実行)

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

ブログ記事の作成・編集・削除はFilamentのデフォルトトランザクション制御に従う。

## パフォーマンス要件

- 一覧表示: 2秒以内
- 作成/編集/削除: 1秒以内
- 画像アップロード: 5秒以内

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

- 認証済みユーザーのみアクセス可能
- 画像アップロードはimage()バリデーション

## 備考

- PostResourceはwebsite/posts URLに配置
- サブナビゲーション（Top位置）でView/Edit間の移動
- SoftDeletes対応
- reorderableColumns対応
- グループ化機能（カテゴリ/著者/作成日）対応
- フィルタ機能（公開状態/著者/作成者/カテゴリ/タグ）
- RichEditorで本文編集
- FileUploadでバナー画像管理
