# 機能設計書 170-CSAT公開API

## 概要

本ドキュメントは、Chatwootの顧客満足度調査（CSAT）公開API機能の設計を記載する。この機能はエンドユーザー（顧客）がCSATサーベイを表示・回答するためのAPIを提供する。

### 本機能の処理概要

CSAT公開API機能は、顧客満足度調査の結果を送信するための公開APIを提供する。顧客は会話終了後にメールリンク等から直接CSATサーベイにアクセスし、フィードバックを送信することができる。

**業務上の目的・背景**：顧客満足度を測定し、サポート品質の改善に活用するため、認証なしでCSATサーベイに回答できる公開APIが必要である。これにより、顧客はログインや複雑な認証プロセスなしに、簡単にフィードバックを提供できる。

**機能の利用シーン**：
- メールで送信されたCSATサーベイリンクをクリックして回答する場面
- 会話終了後の満足度評価を送信する場面
- フィードバックメッセージを追加で記入する場面

**主要な処理内容**：
1. CSATサーベイ情報の取得（show）
2. CSATサーベイ回答の送信（update）

**関連システム・外部連携**：
- 会話（Conversation）のUUID識別
- メッセージ（Message）のcontent_type=input_csat

**権限による制御**：
- 会話UUIDによるアクセス
- 14日以内の回答期限制限

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | CSATサーベイ画面（外部リンク） | 主画面 | CSATサーベイの表示・回答 |

## 機能種別

CRUD操作（Read/Update）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| id | String | Yes | 会話のUUID | 有効なUUID形式 |
| message.submitted_values | Array | No（update時はYes） | 回答値 | - |
| message.submitted_values[].name | String | No | 項目名 | - |
| message.submitted_values[].title | String | No | 項目タイトル | - |
| message.submitted_values[].value | String | No | 項目値 | - |
| message.submitted_values[].csat_survey_response.feedback_message | String | No | フィードバックメッセージ | - |
| message.submitted_values[].csat_survey_response.rating | Integer | No | 評価（1-5等） | - |

### 入力データソース

- 外部リンク（メール等）からのHTTPリクエスト

## 出力仕様

### 出力データ（show）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | Integer | メッセージID |
| content_type | String | コンテンツタイプ（input_csat） |
| content_attributes | Object | コンテンツ属性 |
| submitted_values | Array | 回答済みの値 |
| created_at | Integer | 作成日時 |

### 出力先

- JSON形式のHTTPレスポンス

## 処理フロー

### 処理シーケンス

```
1. CSATサーベイ取得（show）
   └─ 会話UUIDで会話取得
   └─ content_type=input_csatのメッセージ取得
   └─ サーベイ情報を返却

2. CSATサーベイ回答（update）
   └─ 会話UUIDで会話取得
   └─ content_type=input_csatのメッセージ取得
   └─ 14日以内かチェック
   └─ 回答をsubmitted_valuesに保存
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B[会話UUID検証]
    B --> C{会話存在?}
    C -->|No| D[404 Not Found]
    C -->|Yes| E[input_csatメッセージ取得]
    E --> F{アクション判定}
    F -->|show| G[サーベイ情報返却]
    F -->|update| H{14日以内?}
    H -->|No| I[422 期限切れエラー]
    H -->|Yes| J[回答保存]
    J --> K[成功レスポンス]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-170-01 | 回答期限 | 作成から14日以内のみ回答可能 | update時 |
| BR-170-02 | 会話UUID識別 | display_idではなくUUIDで会話を特定 | 全リクエスト |
| BR-170-03 | input_csat限定 | content_type=input_csatのメッセージのみ対象 | 全リクエスト |

### 計算ロジック

**回答期限チェック**:
```ruby
days_since_creation = (Time.zone.now.to_date - @message.created_at.to_date).to_i
locked = days_since_creation > 14
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| show | conversations | SELECT | 会話取得 |
| show | messages | SELECT | input_csatメッセージ取得 |
| update | messages | UPDATE | submitted_values更新 |

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

#### conversations

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | - | uuid = params[:id] | UUID条件 |

#### messages

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | - | conversation_id = @conversation.id | 会話条件 |
| SELECT | - | content_type = 'input_csat' | CSATメッセージ条件 |
| UPDATE | submitted_values | パラメータ値 | 回答内容 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 404 | Not Found | 会話が見つからない | 正しいUUIDを使用 |
| 404 | Not Found | input_csatメッセージがない | サーベイ設定を確認 |
| 422 | Unprocessable Entity | 14日超過 | 期限内に回答 |

### リトライ仕様

特になし（同期処理のため）

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

単一レコードの更新のため暗黙的トランザクション

## パフォーマンス要件

- レスポンス時間: 200ms以内

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

- 会話UUIDによる間接的なアクセス制御（推測困難）
- 14日間の回答期限によるデータ鮮度保証
- 認証不要だがUUIDを知っている必要がある

## 備考

- 会話のUUIDはメールリンク等で配布される
- 1つの会話に対して1つのinput_csatメッセージのみ
- 評価とフィードバックメッセージは任意
- 回答後の再回答も14日以内であれば可能

---

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

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

### 推奨読解順序

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

CSATに関連するデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | conversation.rb | `app/models/conversation.rb` | 会話モデル、UUID |
| 1-2 | message.rb | `app/models/message.rb` | content_type=input_csat、submitted_values |

**読解のコツ**: 会話のdisplay_idとuuidの違いを理解すること。公開APIではuuidを使用してセキュリティを確保している。

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

処理の起点となるコントローラーを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | csat_survey_controller.rb | `app/controllers/public/api/v1/csat_survey_controller.rb` | CSAT公開APIの実装 |

**主要処理フロー**:
1. **3行目**: before_action :set_conversation（会話取得）
2. **4行目**: before_action :set_message（CSATメッセージ取得）
3. **6行目**: show処理（ビューに委譲）
4. **8-11行目**: update処理（期限チェックと更新）
5. **15-19行目**: set_conversation（UUID検索）
6. **21-23行目**: set_message（input_csat検索）
7. **25-27行目**: message_update_params（許可パラメータ）
8. **29-31行目**: check_csat_locked（14日チェック）

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

```
Public::Api::V1::CsatSurveyController
    │
    ├─ PublicController (基底)
    │      └─ skip_before_action :verify_authenticity_token
    │
    ├─ set_conversation
    │      └─ Conversation.find_by!(uuid: params[:id])
    │
    ├─ set_message
    │      └─ @conversation.messages.find_by!(content_type: 'input_csat')
    │
    └─ check_csat_locked
           └─ (Time.zone.now.to_date - @message.created_at.to_date).to_i > 14
```

### データフロー図

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

uuid (会話UUID) ──────▶ set_conversation ─────────────────▶ @conversation
                              │
                        set_message ──────────────────────▶ @message
                              │                              (content_type=input_csat)
submitted_values ─────▶ check_csat_locked ────────────────▶ 期限判定
                              │
                        @message.update! ─────────────────▶ データベース更新
                              │
                        JSON Response ────────────────────▶ クライアント
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| csat_survey_controller.rb | `app/controllers/public/api/v1/csat_survey_controller.rb` | ソース | CSAT公開APIのメインコントローラー |
| public_controller.rb | `app/controllers/public_controller.rb` | ソース | 公開APIの基底コントローラー |
| conversation.rb | `app/models/conversation.rb` | ソース | 会話モデル |
| message.rb | `app/models/message.rb` | ソース | メッセージモデル |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義（528行目） |
