# 機能設計書 87-公開カード閲覧

## 概要

本ドキュメントは、Fizzyアプリケーションにおける「公開カード閲覧」機能の設計仕様を定義する。外部に公開されたボード内のカード詳細を認証なしで閲覧できる機能である。

### 本機能の処理概要

公開カード閲覧機能は、公開設定されたボード内の公開済みカードの詳細情報を、ログインしていない外部ユーザーでも閲覧できるようにする機能である。カードのタイトル、説明、ステップ（チェックリスト）、タグ、カラム情報などを表示する。

**業務上の目的・背景**：公開ボードの各カード（タスクや課題）の詳細を外部ユーザーに共有するための機能である。プロジェクトのロードマップや課題の詳細を外部ステークホルダーや顧客に公開することで、透明性の高いプロジェクト管理が可能になる。

**機能の利用シーン**：外部ユーザーが公開ボードからカードをクリックして詳細を確認する。例えば、機能リクエストの詳細確認、バグレポートの状況確認、リリース予定の確認などに使用される。

**主要な処理内容**：
1. 公開キーとカード番号からカードを特定
2. アカウントがキャンセル済みでないことを確認
3. カードの詳細情報（タイトル、説明、ステップ、タグ等）を表示
4. 画像がある場合は表示
5. OGP（Open Graph Protocol）メタタグを設定

**関連システム・外部連携**：なし

**権限による制御**：認証不要。ただし、公開設定されたボードの公開済みカードのみアクセス可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 72 | 公開カード詳細画面 | 主画面 | カードの詳細情報を表示 |
| 67 | 公開ボード詳細画面 | 参照画面 | カード一覧から遷移元 |

## 機能種別

参照・表示 / 公開API

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| board_id | String | Yes | 公開キー（publication.key） | URLパラメータ |
| id | Integer | Yes | カード番号 | URLパラメータ |

### 入力データソース

URLパラメータ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| card.title | String | カードタイトル |
| card.description | RichText | カード説明文 |
| card.steps | Array | ステップ（チェックリスト）一覧 |
| card.tags | Array | タグ一覧 |
| card.column | Column | 所属カラム |
| card.image | Attachment | カード画像 |
| card.board | Board | 所属ボード |

### 出力先

HTML画面表示（publicレイアウト）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ GET /public/boards/:board_id/cards/:id
2. 公開キーからボード取得
   └─ Board.find_by_published_key(params[:board_id])
3. カード取得
   └─ @board.cards.published.find_by!(number: params[:id])
4. アクセス可否チェック
   └─ アカウントがキャンセル済みでないことを確認
5. キャッシュ設定
   └─ 30秒間のパブリックキャッシュを設定
6. ビューレンダリング
   └─ publicレイアウトでカード詳細を表示
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[公開キーからボード取得]
    B --> C{ボード存在?}
    C -->|No| D[404 Not Found]
    C -->|Yes| E[カード番号でカード取得]
    E --> F{カード存在かつ公開済み?}
    F -->|No| G[404 Not Found]
    F -->|Yes| H{アカウントキャンセル済み?}
    H -->|Yes| I[404 Not Found]
    H -->|No| J[キャッシュ設定]
    J --> K[OGPメタタグ設定]
    K --> L[カード詳細レンダリング]
    L --> M[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-87-01 | 公開カードのみ | 公開済み（published）ステータスのカードのみ表示可能 | 常時 |
| BR-87-02 | カード番号アクセス | カードIDではなくカード番号でアクセス | 常時 |
| BR-87-03 | キャッシュ設定 | 30秒間のパブリックキャッシュを設定 | 常時 |
| BR-87-04 | 画像プレビュー | カードに画像がある場合はOGPで画像を使用 | 画像添付時 |

### 計算ロジック

該当なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ボード取得 | board_publications | SELECT | 公開キーでボードを特定 |
| カード取得 | cards | SELECT | カード番号で公開済みカードを取得 |
| ステップ取得 | steps | SELECT | カードのステップ一覧を取得 |
| タグ取得 | taggings, tags | SELECT | カードのタグ一覧を取得 |

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

#### cards

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | 全カラム | board_id = @board.id AND number = params[:id] AND status = 'published' | 公開済みのみ |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 404 | NotFound | 公開キーが存在しない | エラーページ表示 |
| 404 | NotFound | カード番号が存在しないまたは未公開 | エラーページ表示 |
| 404 | NotFound | アカウントがキャンセル済み | エラーページ表示 |

### リトライ仕様

該当なし

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

参照のみのためトランザクション制御なし

## パフォーマンス要件

- レスポンス時間: 500ms以内
- キャッシュ: 30秒間のパブリックキャッシュ（CDN等で利用可能）

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

- 公開キーは推測困難なランダム文字列
- 公開済み（published）ステータスのカードのみ表示
- 下書き（drafted）カードは表示されない
- キャンセル済みアカウントのカードは非表示

## 備考

OGPメタタグにより、SNSでカードURLを共有した際にカードタイトル、説明文、画像がプレビュー表示される。画像がない場合はデフォルトのアプリアイコンが使用される。

---

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

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

### 推奨読解順序

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

公開カードの取得条件を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | card.rb | `app/models/card.rb` | Cardモデルのステータス定義 |
| 1-2 | base_controller.rb | `app/controllers/public/base_controller.rb` | カード取得の条件 |

**読解のコツ**: `@board.cards.published.find_by!(number: params[:id])`で公開済みカードのみをカード番号で検索する。

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

Public::CardsControllerの処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | cards_controller.rb | `app/controllers/public/cards_controller.rb` | showアクションの処理 |
| 2-2 | base_controller.rb | `app/controllers/public/base_controller.rb` | set_cardメソッド |

**主要処理フロー**:
1. **14-15行目（base_controller）**: `set_card` - カード取得条件
2. **2-3行目（cards_controller）**: `show` - ビューレンダリング

#### Step 3: ビューテンプレートを理解する

公開カード画面の表示内容を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | show.html.erb | `app/views/public/cards/show.html.erb` | メイン画面の構造 |
| 3-2 | _content.html.erb | `app/views/public/cards/show/_content.html.erb` | コンテンツパーシャル |
| 3-3 | _steps.html.erb | `app/views/public/cards/show/_steps.html.erb` | ステップ一覧パーシャル |

**主要処理フロー**:
- **4-13行目**: OGPメタタグの設定（画像含む）
- **24-41行目**: カード本体の表示
- **31行目**: コンテンツパーシャル呼び出し
- **36行目**: ステップパーシャル呼び出し

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

```
Public::CardsController#show
    │
    ├─ Public::BaseController#set_board
    │      └─ Board.find_by_published_key(params[:board_id])
    │
    ├─ Public::BaseController#set_card
    │      └─ @board.cards.published.find_by!(number: params[:id])
    │
    ├─ Public::BaseController#ensure_board_accessible
    │      └─ raise RoutingError if @board&.account&.cancelled?
    │
    └─ Public::BaseController#set_public_cache_expiration
           └─ expires_in 30.seconds, public: true
```

### データフロー図

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

URLパラメータ ───▶ Public::CardsController ───▶ HTML画面
  - board_id             │
  - id (カード番号)       │
                         ▼
                   board_publications ───▶ ボード特定
                         │
                         ▼
                   cards ───▶ カード取得
                         │    （公開済みのみ）
                         │
                         ├─▶ steps ───▶ ステップ一覧
                         │
                         ├─▶ taggings/tags ───▶ タグ一覧
                         │
                         └─▶ active_storage ───▶ 画像
                         │
                         ▼
                   publicレイアウト ───▶ OGPメタタグ付きHTML
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| cards_controller.rb | `app/controllers/public/cards_controller.rb` | ソース | 公開カードコントローラー |
| base_controller.rb | `app/controllers/public/base_controller.rb` | ソース | 公開ページ基底コントローラー |
| show.html.erb | `app/views/public/cards/show.html.erb` | テンプレート | 公開カード画面 |
| _content.html.erb | `app/views/public/cards/show/_content.html.erb` | テンプレート | コンテンツパーシャル |
| _steps.html.erb | `app/views/public/cards/show/_steps.html.erb` | テンプレート | ステップ一覧パーシャル |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義（206行目） |
