# 機能設計書 61-ノート管理

## 概要

本ドキュメントは、Chatwootにおける連絡先（Contact）に対するノート（メモ）管理機能の設計を記述する。エージェントが連絡先に関する情報を内部メモとして記録・管理するための機能である。

### 本機能の処理概要

連絡先ノート管理機能は、エージェントが顧客（連絡先）に関する重要な情報や覚書を記録・参照するための機能を提供する。

**業務上の目的・背景**：カスタマーサポート業務において、顧客との過去のやり取りや特記事項を記録し、チーム内で情報共有することは極めて重要である。この機能により、エージェント間の引き継ぎや顧客対応の質を向上させることができる。顧客の特性、過去のクレーム履歴、VIP顧客であることの注記など、会話には表示されない内部情報を管理できる。

**機能の利用シーン**：
- 顧客との初回対応時に、顧客の特性や要望を記録する場合
- 他のエージェントへの引き継ぎ事項を記載する場合
- 顧客の過去の問い合わせパターンや傾向を記録する場合
- VIP顧客や特別対応が必要な顧客を識別するためのメモを残す場合

**主要な処理内容**：
1. ノートの作成（Create）：連絡先に紐づくノートを新規作成
2. ノートの一覧取得（Index）：連絡先に紐づく全ノートを作成日時の降順で取得
3. ノートの詳細表示（Show）：特定のノートの詳細情報を取得
4. ノートの更新（Update）：既存ノートの内容を編集
5. ノートの削除（Destroy）：不要なノートを削除

**関連システム・外部連携**：特定の外部システムとの連携はなし。内部的にはユーザー（エージェント）情報と連携し、ノート作成者を記録する。

**権限による制御**：連絡先へのアクセス権限を持つエージェントのみがノートの操作が可能。アカウント単位でのアクセス制御が適用される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 24 | 連絡先編集画面 | 主画面 | 連絡先メモの追加・編集・削除 |

## 機能種別

CRUD操作（Create/Read/Update/Delete）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| contact_id | Integer | Yes | 対象連絡先ID | URLパラメータ、存在確認 |
| note[content] | Text | Yes | ノートの内容 | presence: true |
| id | Integer | No | ノートID（更新・削除時） | 存在確認、所属確認 |

### 入力データソース

- 画面入力：連絡先編集画面からの入力
- URLパラメータ：contact_id、note_id

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | Integer | ノートID |
| content | Text | ノート内容 |
| account_id | Integer | アカウントID |
| contact_id | Integer | 連絡先ID |
| user | Object | 作成者情報（エージェント情報） |
| created_at | Integer | 作成日時（Unix timestamp） |
| updated_at | Integer | 更新日時（Unix timestamp） |

### 出力先

- API レスポンス（JSON形式）
- フロントエンド連絡先詳細画面

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ API エンドポイントで受信（/api/v1/accounts/:account_id/contacts/:contact_id/notes）

2. 認証・認可チェック
   └─ BaseController で Current.account, Current.user を設定
   └─ 連絡先の存在確認と所属確認

3. アクション実行
   └─ index: 全ノート取得（作成日時降順、ユーザー情報を含む）
   └─ show: 特定ノート取得
   └─ create: 新規ノート作成（content, contact_id, user_id を設定）
   └─ update: ノート内容更新
   └─ destroy: ノート削除

4. レスポンス生成
   └─ JBuilder テンプレートでJSON形式に整形
   └─ ユーザー情報を含めて返却
```

### フローチャート

```mermaid
flowchart TD
    A[APIリクエスト受信] --> B{認証済み?}
    B -->|No| C[401 Unauthorized]
    B -->|Yes| D{連絡先存在?}
    D -->|No| E[404 Not Found]
    D -->|Yes| F{アクション判定}
    F -->|index| G[全ノート取得]
    F -->|show| H[特定ノート取得]
    F -->|create| I[バリデーション]
    F -->|update| J[ノート存在確認]
    F -->|destroy| K[ノート存在確認]
    I -->|OK| L[ノート作成]
    I -->|NG| M[422 Validation Error]
    J --> N[ノート更新]
    K --> O[ノート削除]
    G --> P[JSONレスポンス]
    H --> P
    L --> P
    N --> P
    O --> Q[200 OK]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | アカウント自動設定 | ノート作成時、account_id は contact の account_id から自動設定 | ノート作成時 |
| BR-02 | 作成者自動設定 | ノート作成時、user_id は Current.user.id が自動設定される | ノート作成時 |
| BR-03 | ソート順序 | ノート一覧は作成日時の降順（最新順）で取得 | index アクション |
| BR-04 | 所属確認 | ノートは対象の連絡先に所属しているもののみ操作可能 | 全アクション |

### 計算ロジック

特に計算ロジックはなし。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| index | notes | SELECT | 連絡先に紐づく全ノートを取得 |
| show | notes | SELECT | 特定のノートを取得 |
| create | notes | INSERT | 新規ノートを作成 |
| update | notes | UPDATE | ノート内容を更新 |
| destroy | notes | DELETE | ノートを削除 |

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

#### notes

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | content | リクエストパラメータの値 | 必須 |
| INSERT | contact_id | URLパラメータの値 | 自動設定 |
| INSERT | user_id | Current.user.id | 自動設定 |
| INSERT | account_id | contact.account_id | before_validation で自動設定 |
| UPDATE | content | リクエストパラメータの値 | |
| SELECT | - | contact_id = :contact_id | 連絡先IDで絞り込み |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | Unauthorized | 認証トークンが無効または期限切れ | 再認証を促す |
| 404 | Not Found | 連絡先またはノートが存在しない | 正しいIDを指定 |
| 422 | Unprocessable Entity | content が空の場合 | content を入力 |

### リトライ仕様

特にリトライ仕様はなし。通常のHTTPリクエストとして処理。

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

- create, update, destroy はそれぞれ単一レコード操作のため、暗黙的なトランザクション管理
- ActiveRecord の save!, update!, destroy! を使用し、失敗時は例外が発生

## パフォーマンス要件

- インデックス: contact_id, account_id, user_id にインデックス設定済み
- 一覧取得時はユーザー情報を includes で事前読み込み

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

- アカウント単位でのアクセス制御（Current.account.contacts でスコープ）
- 連絡先の所属確認を BaseController で実施
- Strong Parameters による入力パラメータの制限（content のみ許可）

## 備考

- ノートは連絡先が削除された場合、dependent: :destroy_async により非同期で削除される
- user_id は optional であり、ユーザーが削除された場合もノートは残る

---

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

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

### 推奨読解順序

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

まず、ノートのデータモデルを理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | note.rb | `app/models/note.rb` | ノートのスキーマ定義、バリデーション、リレーション |

**読解のコツ**: ファイル冒頭のコメントに Schema Information が記載されている。これを見ることでテーブル構造を即座に把握できる。

**主要処理フロー**:
- **19-36行目**: Note モデルのクラス定義
- **20行目**: `before_validation :ensure_account_id` - account_id の自動設定フック
- **21-23行目**: バリデーション定義（content, account_id, contact_id は必須）
- **25-27行目**: belongs_to によるリレーション定義
- **29行目**: `scope :latest` - 作成日時降順のスコープ
- **33-35行目**: `ensure_account_id` - contact から account_id を自動設定

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

APIコントローラーが処理の起点となる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | notes_controller.rb | `app/controllers/api/v1/accounts/contacts/notes_controller.rb` | 全CRUDアクションの実装 |

**主要処理フロー**:
- **1行目**: BaseController を継承し、認証・連絡先確認を継承
- **2行目**: `before_action :note` - show, update, destroy 前にノート取得
- **4-6行目**: `index` - 全ノート取得（latest スコープ + includes(:user)）
- **10-12行目**: `create` - ノート作成（note_params でパラメータ整形）
- **14-16行目**: `update` - ノート更新
- **18-21行目**: `destroy` - ノート削除
- **29-31行目**: `note_params` - Strong Parameters（content のみ許可、contact_id と user_id を追加）

#### Step 3: ベースコントローラーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | base_controller.rb | `app/controllers/api/v1/accounts/contacts/base_controller.rb` | 連絡先の事前取得処理 |

**主要処理フロー**:
- **2行目**: `before_action :ensure_contact` - 全アクション前に連絡先取得
- **6-8行目**: `ensure_contact` - Current.account から連絡先を取得（アカウントスコープ）

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | index.json.jbuilder | `app/views/api/v1/accounts/contacts/notes/index.json.jbuilder` | 一覧レスポンス形式 |
| 4-2 | _note.json.jbuilder | `app/views/api/v1/models/_note.json.jbuilder` | ノート詳細のJSON形式 |

**主要処理フロー**:
- **index.json.jbuilder 1-3行目**: 配列形式で全ノートを出力
- **_note.json.jbuilder 1-11行目**: id, content, account_id, contact_id, user（条件付き）, created_at, updated_at を出力

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

```
Api::V1::Accounts::Contacts::NotesController
    │
    ├─ Api::V1::Accounts::Contacts::BaseController (親クラス)
    │      └─ ensure_contact (before_action)
    │             └─ Current.account.contacts.find(params[:contact_id])
    │
    ├─ index アクション
    │      └─ @contact.notes.latest.includes(:user)
    │             └─ Note.latest scope
    │
    ├─ create アクション
    │      └─ @contact.notes.create!(note_params)
    │             └─ Note#ensure_account_id (before_validation)
    │
    └─ JBuilder テンプレート
           └─ api/v1/models/_note.json.jbuilder
                  └─ api/v1/models/_agent.json.jbuilder (ユーザー情報)
```

### データフロー図

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

contact_id (URL) ───▶ BaseController#ensure_contact ───▶ @contact
                              │
note[content] ─────▶ NotesController#create ────────────▶ notes テーブル
 (POST body)                  │                           (INSERT)
                              │
                      Note#ensure_account_id
                              │
                      (account_id 自動設定)
                              │
                              ▼
                      JBuilder テンプレート ────────────▶ JSON レスポンス
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| note.rb | `app/models/note.rb` | モデル | ノートのデータモデル定義 |
| notes_controller.rb | `app/controllers/api/v1/accounts/contacts/notes_controller.rb` | コントローラー | ノートCRUD APIエンドポイント |
| base_controller.rb | `app/controllers/api/v1/accounts/contacts/base_controller.rb` | コントローラー | 連絡先関連APIの共通処理 |
| index.json.jbuilder | `app/views/api/v1/accounts/contacts/notes/index.json.jbuilder` | ビュー | 一覧レスポンステンプレート |
| create.json.jbuilder | `app/views/api/v1/accounts/contacts/notes/create.json.jbuilder` | ビュー | 作成レスポンステンプレート |
| _note.json.jbuilder | `app/views/api/v1/models/_note.json.jbuilder` | ビュー | ノート詳細パーシャル |
| contact.rb | `app/models/contact.rb` | モデル | 連絡先モデル（has_many :notes） |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義 |
