# 機能設計書 2-アクティビティフィルタリング

## 概要

本ドキュメントは、Fat Free CRMシステムにおけるアクティビティフィルタリング機能の設計を定義する。この機能は、ダッシュボード画面に表示されるアクティビティ履歴を、アセット種別・イベント種別・ユーザー・期間の条件でフィルタリングする。

### 本機能の処理概要

アクティビティフィルタリング機能は、ダッシュボードのアクティビティセクションに表示されるデータを絞り込むための機能である。ユーザーは複数のフィルタ条件を組み合わせて、必要な情報のみを効率的に確認できる。

**業務上の目的・背景**：CRMシステムでは多数のアクティビティが発生するため、全てを確認することは現実的ではない。営業マネージャーは特定のチームメンバーの活動を確認したい場合があり、営業担当者は特定の種類のエンティティに関する変更のみを追跡したい場合がある。本機能により、これらのニーズに応えることが可能となる。

**機能の利用シーン**：
- マネージャーが特定の営業担当者の過去1週間の活動を確認する場面
- 営業担当者が取引先に関する更新のみを追跡する場面
- 新規作成されたリードのみを確認したい場面
- 過去1か月間の全体的なCRM活動を概観する場面

**主要な処理内容**：
1. フィルタリングオプション画面の表示（optionsアクション）
2. ユーザー設定（Preference）の更新（redrawアクション）
3. フィルタ条件に基づくアクティビティの再取得
4. AJAX通信による部分的な画面更新

**関連システム・外部連携**：本機能は外部システムとの連携はなく、内部データベースとユーザー設定の操作のみで構成される。

**権限による制御**：フィルタリング結果は、ユーザーのアクセス権限に基づいて表示される。アクセス権限のないエンティティは、フィルタ条件に合致してもvisible_toメソッドにより除外される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 6 | ホーム画面（ダッシュボード） | 主画面 | アセット種別・イベント種別・ユーザー・期間でフィルタリング |

## 機能種別

データ表示・フィルタリング（READ操作 + Preference UPDATE）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| asset | String | No | アセット種別（all/tasks/campaigns/leads/accounts/contacts/opportunities/comments/emails） | ASSETS定数で定義された値のみ許可 |
| event | String | No | イベント種別（all_events/create/view/update/destroy） | EVENTS定数で定義された値のみ許可 |
| user | String | No | ユーザー指定（all_users/ユーザー名/メールアドレス） | 存在するユーザーであること |
| duration | String | No | 期間（one_hour/one_day/two_days/one_week/two_weeks/one_month） | DURATION定数で定義された値のみ許可 |
| cancel | String | No | キャンセルフラグ（true/false） | - |

### 入力データソース

- ユーザー入力（フォーム選択）
- セッション情報（current_user）
- ユーザー設定（current_user.pref）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| @asset | String | 選択されたアセット種別 |
| @action | String | 選択されたイベント種別 |
| @user | String | 選択されたユーザー |
| @duration | String | 選択された期間 |
| @all_users | ActiveRecord::Relation<User> | ユーザー一覧（optionsアクション用） |
| @activities | Array<Version> | フィルタリングされたアクティビティ一覧 |

### 出力先

- HTML部分更新（AJAX）
- ユーザー設定（Preference）への保存

## 処理フロー

### 処理シーケンス

```
【optionsアクション】
1. cancelパラメータの確認
   └─ trueの場合は何もしない
2. 現在のユーザー設定から各フィルタ値を取得
   └─ activity_asset, activity_event, activity_user, activity_duration
3. 全ユーザー一覧の取得
   └─ User.order("first_name, last_name")
4. options.js.hamlのレンダリング

【redrawアクション】
1. 各パラメータの存在確認と設定保存
   └─ params[:asset] → current_user.pref[:activity_asset]
   └─ params[:event] → current_user.pref[:activity_event]
   └─ params[:user] → current_user.pref[:activity_user]
   └─ params[:duration] → current_user.pref[:activity_duration]
2. get_activitiesでフィルタリングされたアクティビティ取得
3. index.jsのレンダリング（AJAX応答）
```

### フローチャート

```mermaid
flowchart TD
    A[optionsリクエスト] --> B{cancel=true?}
    B -->|Yes| C[何もしない]
    B -->|No| D[現在の設定を取得]
    D --> E[ユーザー一覧取得]
    E --> F[options画面表示]

    G[redrawリクエスト] --> H[パラメータを設定に保存]
    H --> I[get_activities実行]
    I --> J[Version.latest取得]
    J --> K[visible_toフィルタ]
    K --> L[index.js返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | デフォルトアセット | 未設定時は"all"（全アセット） | activity_assetがnil |
| BR-002 | デフォルトイベント | 未設定時は"all_events"（全イベント） | activity_eventがnil |
| BR-003 | デフォルトユーザー | 未設定時は"all_users"（全ユーザー） | activity_userがnil |
| BR-004 | デフォルト期間 | 未設定時は"two_days"（2日間） | activity_durationがnil |
| BR-005 | ユーザー検索 | メールアドレス形式または名前で検索 | activity_userが"all_users"以外 |

### 計算ロジック

**期間の変換ロジック**：
```ruby
# "two_weeks" => 2.weeks
words = duration.split("_")  # ["two", "weeks"]
%w[zero one two].index(words.first).send(words.last)
# => 2.weeks
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ユーザー一覧取得 | users | SELECT | フィルタ選択肢用のユーザー一覧 |
| 設定保存 | preferences | UPDATE | ユーザーのフィルタ設定を保存 |
| アクティビティ取得 | versions | SELECT | フィルタ条件に基づくアクティビティ |

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

#### users

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, first_name, last_name, email | ORDER BY first_name, last_name | optionsアクション |

#### preferences

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | value (JSON) | activity_asset, activity_event, activity_user, activity_duration | シリアライズされたハッシュ |

#### versions

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | * | item_type, event, whodunnit, created_at >= (now - duration) | latestスコープ |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 401 | 認証エラー | 未ログイン状態でアクセス | ログイン画面へリダイレクト |
| - | ユーザー不存在 | 指定ユーザーが存在しない | nilを返し、全ユーザー表示にフォールバック |

### リトライ仕様

本機能ではリトライ処理は実装されていない。

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

Preferenceの更新は単一レコードの更新であり、明示的なトランザクション制御は不要。

## パフォーマンス要件

- AJAX応答時間: 1秒以内を目標
- ユーザー一覧はキャッシュ可能

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

- 認証: Deviseによるユーザー認証が必須
- 認可: visible_toによるアクセス権限フィルタリング
- ユーザー検索: SQLインジェクション対策済み（ActiveRecordのwhere使用）

## 備考

- フィルタ設定はユーザーごとに永続化される
- ブラウザリロード後も設定は維持される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | version.rb | `app/models/polymorphic/version.rb` | ASSETS, EVENTS, DURATION定数の定義 |
| 1-2 | preference.rb | `app/models/users/preference.rb` | ユーザー設定の保存形式 |

**読解のコツ**: Versionクラスの定数定義（11-13行目）がフィルタの選択肢を定義している。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | routes.rb | `config/routes.rb` | /home/optionsと/home/redrawルート |
| 2-2 | home_controller.rb | `app/controllers/home_controller.rb` | options, redrawアクション |

**主要処理フロー**:
1. **25-33行目**: optionsアクション - フィルタ設定画面の表示
2. **37-47行目**: redrawアクション - フィルタ適用とアクティビティ再取得

#### Step 3: フィルタリングロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | home_controller.rb | `app/controllers/home_controller.rb` | activity_asset, activity_event, activity_user, activity_durationメソッド |

**主要処理フロー**:
- **112-119行目**: activity_asset - アセット種別の変換
- **122-129行目**: activity_event - イベント種別の変換
- **135-148行目**: activity_user - ユーザーIDの解決
- **161-167行目**: activity_duration - 期間の変換

#### Step 4: ビュー層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | options.js.haml | `app/views/home/options.js.haml` | オプション画面のJS |
| 4-2 | _options.html.haml | `app/views/home/_options.html.haml` | フィルタフォーム |
| 4-3 | _assets_menu.html.haml | `app/views/home/_assets_menu.html.haml` | アセット選択メニュー |
| 4-4 | _events_menu.html.haml | `app/views/home/_events_menu.html.haml` | イベント選択メニュー |
| 4-5 | _users_menu.html.haml | `app/views/home/_users_menu.html.haml` | ユーザー選択メニュー |
| 4-6 | _duration_menu.html.haml | `app/views/home/_duration_menu.html.haml` | 期間選択メニュー |

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

```
HomeController#options
    │
    ├─ current_user.pref[:activity_asset]
    ├─ current_user.pref[:activity_event]
    ├─ current_user.pref[:activity_user]
    ├─ current_user.pref[:activity_duration]
    └─ User.order("first_name, last_name")

HomeController#redraw
    │
    ├─ current_user.pref[:activity_asset] = params[:asset]
    ├─ current_user.pref[:activity_event] = params[:event]
    ├─ current_user.pref[:activity_user] = params[:user]
    ├─ current_user.pref[:activity_duration] = params[:duration]
    │
    └─ get_activities
           ├─ activity_asset
           ├─ activity_event
           ├─ activity_user
           ├─ activity_duration
           └─ Version.latest().visible_to()
```

### データフロー図

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

フォーム入力 ───▶ HomeController#redraw ───▶ Preference保存
(asset,event,         │                      @activities更新
 user,duration)       │                          │
                      ▼                          ▼
              get_activities()            index.js.haml
                      │                          │
                      ▼                          ▼
              Version.latest()            AJAX画面更新
              visible_to()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| home_controller.rb | `app/controllers/home_controller.rb` | ソース | メインコントローラー |
| version.rb | `app/models/polymorphic/version.rb` | ソース | フィルタ定数・取得ロジック |
| preference.rb | `app/models/users/preference.rb` | ソース | ユーザー設定モデル |
| options.js.haml | `app/views/home/options.js.haml` | テンプレート | オプション画面JS |
| _options.html.haml | `app/views/home/_options.html.haml` | テンプレート | フィルタフォーム |
| _assets_menu.html.haml | `app/views/home/_assets_menu.html.haml` | テンプレート | アセット選択 |
| _events_menu.html.haml | `app/views/home/_events_menu.html.haml` | テンプレート | イベント選択 |
| _users_menu.html.haml | `app/views/home/_users_menu.html.haml` | テンプレート | ユーザー選択 |
| _duration_menu.html.haml | `app/views/home/_duration_menu.html.haml` | テンプレート | 期間選択 |
| index.js.haml | `app/views/home/index.js.haml` | テンプレート | AJAX応答 |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義 |
