# 機能設計書 139-Notion認可

## 概要

本ドキュメントは、Chatwootシステムにおける「Notion認可」機能の設計仕様を記載する。本機能は、Notion統合を設定するためのOAuth 2.0認証フローを実装する。

### 本機能の処理概要

Notion認可機能は、Notionワークスペースとの統合を可能にする認証基盤を提供する。OAuth 2.0を使用してNotionワークスペースへのアクセス権限を取得し、Chatwootから直接Notionデータベースにアクセスできるようになる。これはチャネル連携ではなく、統合（Integration/Hook）として機能する。

**業務上の目的・背景**：
Notionは、ドキュメント管理、プロジェクト管理、ナレッジベースとして広く使用されている。Chatwootとの統合により、会話情報をNotionに記録したり、Notionのデータベースを参照しながら顧客対応を行うことが可能になる。これにより、チームの知識共有とワークフローの効率化を実現する。

**機能の利用シーン**：
- NotionワークスペースをChatwootと連携する場合
- 会話情報をNotionデータベースに自動記録する場合
- カスタマーサポート時にNotionのナレッジベースを参照する場合

**主要な処理内容**：
1. Notion OAuth 2.0認可URL生成とユーザーリダイレクト
2. 認可コードからアクセストークンへの変換
3. ワークスペース情報の取得
4. 統合Hook（integrations/hook）の作成
5. Notion設定画面へのリダイレクト

**関連システム・外部連携**：
- Notion API
- oauth2 gem（OAuth 2.0クライアント）
- Integrations Hook（統合管理）

**権限による制御**：
- Notion認可を実行するにはAdministrator権限が必要
- 統合完了後の設定変更もAdministrator権限が必要

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 70 | Notion連携画面 | 主画面 | Notion認可フローの開始・設定 |

## 機能種別

OAuth認証 / 外部API連携 / 統合設定

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| code | String | Yes | Notion認可コード | 有効な認可コード |
| state | String | Yes | CSRF対策用state（Signed Global ID） | 有効期限15分以内 |

### 入力データソース

- Notion OAuth認証コールバック
- 管理画面からの認可開始リクエスト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| redirect_url | String | Notion認可画面へのリダイレクトURL |
| hook | Object | 作成された統合Hook情報 |

### 出力先

- データベース（integrations_hooks テーブル）
- 管理画面へのリダイレクト
- API レスポンス（JSON形式）

## 処理フロー

### 処理シーケンス

```
1. 認可開始リクエスト（AuthorizationsController#create）
   └─ 管理者権限チェック
   └─ stateパラメータ生成（Signed Global ID、有効期限15分）
   └─ Notion OAuth認可URL生成

2. Notionログイン・権限承認
   └─ ユーザーがNotionでログイン
   └─ ワークスペースへのアクセス権限を承認
   └─ 認可コードを発行してコールバック

3. コールバック処理（CallbacksController#show）
   └─ stateパラメータ検証
   └─ 認可コードでトークン交換
   └─ Basic認証でトークン取得

4. Hook作成
   └─ access_tokenを保存
   └─ ワークスペース情報を設定に保存
   └─ app_id: 'notion'で統合Hook作成

5. リダイレクト
   └─ Notion統合設定画面へ
```

### フローチャート

```mermaid
flowchart TD
    A[開始: Notion連携開始] --> B[管理者権限チェック]
    B --> C{権限あり?}
    C -->|No| D[403エラー]
    C -->|Yes| E[state生成]
    E --> F[Notion認可URL生成]
    F --> G[JSONレスポンス返却]
    G --> H[フロントエンドがリダイレクト]
    H --> I[Notionログイン画面]
    I --> J{認証成功?}
    J -->|No| K[エラーリダイレクト]
    J -->|Yes| L[コールバック受信]
    L --> M[state検証]
    M --> N{検証OK?}
    N -->|No| K
    N -->|Yes| O[トークン交換]
    O --> P[Hook作成]
    P --> Q[設定保存]
    Q --> R[リダイレクト]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-139-01 | 管理者権限必須 | Notion認可はAdministrator権限が必要 | 認可開始時 |
| BR-139-02 | state有効期限 | stateパラメータは15分間有効 | コールバック時 |
| BR-139-03 | Basic認証 | トークン交換にはBasic認証を使用 | トークン交換時 |
| BR-139-04 | app_id固定 | 統合Hookのapp_idは'notion'固定 | Hook作成時 |
| BR-139-05 | owner=user | owner=userでユーザー認可を指定 | 認可リクエスト時 |

### 計算ロジック

特になし。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| Hook作成 | integrations_hooks | INSERT | 新規Notion統合Hook作成 |

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

#### integrations_hooks

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | access_token | parsed_body['access_token'] | Notionアクセストークン |
| INSERT | status | 'enabled' | 有効状態 |
| INSERT | app_id | 'notion' | アプリケーション識別子 |
| INSERT | settings | workspace情報等 | JSON形式の設定 |

settings内容:
- token_type: parsed_body['token_type']
- workspace_name: parsed_body['workspace_name']
- workspace_id: parsed_body['workspace_id']
- workspace_icon: parsed_body['workspace_icon']
- bot_id: parsed_body['bot_id']
- owner: parsed_body['owner']

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 403 | Forbidden | Administrator権限なし | 管理者でログインし直す |
| 400 | Bad Request | stateパラメータなし | 再度認可フローを開始 |
| 422 | Unprocessable Entity | state期限切れまたは無効 | 再度認可フローを開始 |
| 500 | Internal Server Error | トークン交換失敗 | Notionの状態確認、再試行 |

### リトライ仕様

- トークン交換失敗時、例外をキャプチャしてルートへリダイレクト

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

- Hook作成は単一のsave!操作

## パフォーマンス要件

- Notion OAuth API呼び出しは外部依存のため、タイムアウトを適切に設定
- 認可URLの生成は即座に完了

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

- Signed Global IDによるCSRF対策（state パラメータ）
- NOTION_CLIENT_IDとNOTION_CLIENT_SECRETは環境変数/GlobalConfigServiceで管理
- アクセストークンは暗号化して保存
- Basic認証スキーム使用

## 備考

- Notionはチャネルではなく統合（Integration）として実装
- Integrations Hookモデルを使用
- ワークスペース情報をsettingsに保存

---

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

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

### 推奨読解順序

#### Step 1: Notion認証共通機能を理解する

Notion OAuth設定の共通処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | notion_concern.rb | `app/controllers/concerns/notion_concern.rb` | notion_clientの初期化 |

**主要処理フロー**:
- **4-14行目**: notion_client - OAuth2::Clientの初期化
  - NOTION_CLIENT_IDとNOTION_CLIENT_SECRETをGlobalConfigServiceから取得
  - site: api.notion.com
  - authorize_url: api.notion.com/v1/oauth/authorize
  - token_url: api.notion.com/v1/oauth/token
  - auth_scheme: :basic_auth（Basic認証使用）
- **18-20行目**: scope - 空文字（Notionは認可時にスコープ指定不要）

#### Step 2: 認可開始処理を理解する

認可URL生成のコントローラーを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | authorizations_controller.rb | `app/controllers/api/v1/accounts/notion/authorizations_controller.rb` | 認可URL生成 |

**主要処理フロー**:
- **4-21行目**: create アクション
  - notion_client.auth_code.authorize_url
  - redirect_uri: {base_url}/notion/callback
  - response_type: code
  - owner: user（ユーザー認可）
  - state: Signed Global ID
  - client_id: NOTION_CLIENT_ID

#### Step 3: コールバック処理を理解する

認可コールバックの処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | callbacks_controller.rb | `app/controllers/notion/callbacks_controller.rb` | Notionコールバック処理 |
| 3-2 | oauth_callback_controller.rb | `app/controllers/oauth_callback_controller.rb` | 共通コールバック基底クラス |

**主要処理フロー**:
- NotionCallbacksController:
  - **6-8行目**: provider_name - 'notion'を返す
  - **10-12行目**: oauth_client - NotionConcernのnotion_clientを使用
  - **14-31行目**: handle_response - Hook作成とリダイレクト
  - **33-35行目**: notion_redirect_uri - Notion設定画面URL

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

```
Api::V1::Accounts::Notion::AuthorizationsController#create
    |
    +-- check_authorization (from OauthAuthorizationController)
    |       |
    |       +-- Current.account_user.administrator?
    |
    +-- notion_client.auth_code.authorize_url
    |       |
    |       +-- NotionConcern#notion_client
    |       |       |
    |       |       +-- OAuth2::Client.new(client_id, client_secret)
    |       |       +-- auth_scheme: :basic_auth
    |       |
    |       +-- state (from OauthAuthorizationController)
    |               |
    |               +-- Current.account.to_sgid(expires_in: 15.minutes)
    |
    +-- render json: { success: true, url: redirect_url }

Notion::CallbacksController#show
    |
    +-- oauth_client.auth_code.get_token(code, redirect_uri)
    |       |
    |       +-- notion_client (Basic認証でトークン交換)
    |
    +-- handle_response (Notion固有オーバーライド)
            |
            +-- account.hooks.new
            |       |
            |       +-- access_token: parsed_body['access_token']
            |       +-- status: 'enabled'
            |       +-- app_id: 'notion'
            |       +-- settings: { workspace情報 }
            |
            +-- hook.save!
            |
            +-- redirect_to notion_redirect_uri
```

### データフロー図

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

管理者リクエスト      --> AuthorizationsController#create --> 認可URL
(認可開始)               |                                  |
                         +-- notion_client.authorize_url    +-- { success, url }
                         +-- state生成

Notion OAuth         --> CallbacksController#show        --> 統合Hook
(code, state)            |                                  |
                         +-- get_token(code)                +-- Integrations::Hook
                         +-- handle_response                +-- settings (workspace情報)
                         +-- hook.save!
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| notion_concern.rb | `app/controllers/concerns/notion_concern.rb` | Concern | Notion OAuth設定 |
| authorizations_controller.rb | `app/controllers/api/v1/accounts/notion/authorizations_controller.rb` | コントローラー | 認可URL生成 |
| callbacks_controller.rb | `app/controllers/notion/callbacks_controller.rb` | コントローラー | Notionコールバック |
| oauth_authorization_controller.rb | `app/controllers/api/v1/accounts/oauth_authorization_controller.rb` | コントローラー | OAuth認可基底クラス |
| oauth_callback_controller.rb | `app/controllers/oauth_callback_controller.rb` | コントローラー | 共通コールバック基底クラス |
| hook.rb | `app/models/integrations/hook.rb` | モデル | 統合Hookのデータモデル |
