# 画面設計書 29-タスク新規作成フォーム

## 概要

本ドキュメントは、Fat Free CRMシステムにおけるタスク新規作成フォームの設計を記述する。新規タスクの登録、関連エンティティへの紐付け、期日設定などの機能を提供するモーダル/Ajax形式のフォームである。

### 本画面の処理概要

タスク新規作成フォームは、営業活動に伴うタスク（フォローアップ、提案書作成、顧客訪問等）を迅速に登録するためのフォームである。

**業務上の目的・背景**：営業担当者は日々発生するタスクを即座に登録し、期日管理を行う必要がある。本フォームにより、タスクの漏れ防止と効率的な業務管理を実現する。

**画面へのアクセス方法**：
- タスク一覧画面の「新規作成」ボタンをクリック
- ダッシュボードのタスクセクションから「新規作成」ボタンをクリック
- 各エンティティ詳細画面（取引先、連絡先、商談等）の「タスクを追加」リンクをクリック
- ナビゲーションバーの「+」メニューから選択

**主要な操作・処理内容**：
1. タスク名の入力
2. 期日の選択（ASAP/Today/Tomorrow/This Week/Next Week/Later/特定日時）
3. 担当者（割り当て先）の選択
4. カテゴリの選択
5. 関連エンティティの設定（自動または手動）
6. 背景情報の入力
7. タスクの保存

**画面遷移**：
- 遷移元：タスク一覧画面、ダッシュボード、各エンティティ詳細画面
- 遷移先（成功時）：タスク一覧画面（一覧からの場合）、遷移元エンティティ詳細画面

**権限による表示制御**：ログイン済みユーザーのみアクセス可能。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 36 | タスク作成 | 主機能 | 新規タスク情報入力、関連エンティティ紐付け、作成実行 |

## 画面種別

登録フォーム（モーダル/Ajax）

## URL/ルーティング

### 表示
- URL: `/tasks/new`
- HTTPメソッド: GET
- コントローラ: `TasksController#new`

### 登録実行
- URL: `/tasks`
- HTTPメソッド: POST
- コントローラ: `TasksController#create`

## 入出力項目

### 入力パラメータ（GET /tasks/new）

| パラメータ名 | 型 | 必須 | 説明 |
|-------------|-----|------|------|
| view | String | 任意 | 現在のビュー種別 |
| related | String | 任意 | 関連エンティティ（例: "contact_123"） |

### 入力パラメータ（POST /tasks）

| パラメータ名 | 型 | 必須 | 説明 |
|-------------|-----|------|------|
| task[name] | String | 必須 | タスク名 |
| task[user_id] | Integer | 必須 | 作成者ユーザーID |
| task[assigned_to] | Integer | 任意 | 担当者ユーザーID |
| task[bucket] | String | 任意 | 期日バケット |
| task[calendar] | String | 条件付き | 特定日時（bucketがspecific_timeの場合必須） |
| task[category] | String | 任意 | カテゴリ |
| task[asset_id] | Integer | 任意 | 関連エンティティID |
| task[asset_type] | String | 任意 | 関連エンティティ種別 |
| task[background_info] | String | 任意 | 背景情報 |
| view | String | 任意 | 現在のビュー種別 |

### 出力データ（インスタンス変数）

| 変数名 | 型 | 説明 |
|--------|-----|------|
| @task | Task | 新規タスクオブジェクト |
| @view | String | 現在のビュー種別 |
| @bucket | Array | 期日バケット選択肢 |
| @category | Array | カテゴリ選択肢 |
| @asset | Object | 関連エンティティ（relatedパラメータ指定時） |

## 表示項目

### 基本情報セクション

| 項目名 | フィールド名 | 入力形式 | 必須 | 説明 |
|--------|------------|---------|------|------|
| タスク名 | name | テキスト | 必須 | タスクの名称 |
| 期日 | bucket | 選択 | - | バケット選択またはカレンダー入力 |
| 特定日時 | calendar | 日時 | 条件付き | bucketがspecific_timeの場合 |
| 担当者 | assigned_to | 選択 | - | ユーザー選択（デフォルト: 自分） |
| カテゴリ | category | 選択 | - | タスクカテゴリ |
| 背景情報 | background_info | テキストエリア | - | 補足情報 |

### 期日バケット選択肢

| 選択肢 | 説明 |
|--------|------|
| Due ASAP | 至急（期日なし） |
| Due Today | 本日中 |
| Due Tomorrow | 明日中 |
| Due This Week | 今週中 |
| Due Next Week | 来週中 |
| Due Later | それ以降 |
| On Specific Date... | 特定日時を指定 |

## イベント仕様

### 1-作成ボタンクリック

- **トリガー**: 「タスクを作成」ボタンをクリック
- **処理**:
  1. フォームがAjaxでPOST送信される
  2. サーバー側でバリデーション実行
  3. 期日の計算（bucketに応じてdue_atを設定）
  4. タスクレコードの作成
  5. サイドバー更新（一覧からの場合）
- **成功時**: 一覧画面更新または関連エンティティ詳細画面更新
- **失敗時**: エラーメッセージ表示、フォーム再表示

### 2-キャンセルリンククリック

- **トリガー**: 「キャンセル」リンクをクリック
- **処理**: Ajax経由でフォームを閉じる
- **遷移先**: フォーム表示前の状態に戻る

### 3-期日バケット選択変更

- **トリガー**: バケットドロップダウンの選択変更
- **処理**:
  - 「On Specific Date...」選択時: カレンダー入力フィールドを表示
  - その他選択時: カレンダー入力フィールドを非表示
- **備考**: `crm.flip_calendar()`関数で切り替え

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| タスク作成 | tasks | INSERT | タスクレコード作成 |
| バージョン記録 | versions | INSERT | 作成履歴記録 |

### テーブル別更新項目詳細

#### tasks

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | user_id | current_user.id | 作成者 |
| INSERT | assigned_to | フォーム入力値 | 担当者（nilの場合は作成者） |
| INSERT | name | フォーム入力値 | タスク名 |
| INSERT | bucket | フォーム入力値 | 期日バケット |
| INSERT | due_at | bucketから計算 | 期日（set_due_dateで計算） |
| INSERT | category | フォーム入力値 | カテゴリ |
| INSERT | asset_id | フォーム入力値 | 関連エンティティID |
| INSERT | asset_type | フォーム入力値 | 関連エンティティ種別 |
| INSERT | background_info | フォーム入力値 | 背景情報 |
| INSERT | created_at | 現在日時 | 作成日時 |

## メッセージ仕様

| 種別 | メッセージキー | 表示条件 |
|------|---------------|---------|
| エラー | :missing_task_name | タスク名が未入力 |
| エラー | :invalid_date | 特定日時の形式不正 |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| 関連エンティティが見つからない | respond_to_related_not_foundでエラーレスポンス |
| バリデーションエラー | フォーム再表示（バリデーションメッセージは表示しない） |
| 日付解析エラー | :invalid_dateエラー追加 |

## 備考

- フォームはremote: trueでAjax送信される
- タスクのバリデーションメッセージは表示しない設計
- 期日はbucketから自動計算される
- specific_time選択時のカレンダーはSetting.task_calendar_with_timeで時刻入力可否が決まる
- 関連エンティティはポリモーフィック関連（asset_id, asset_type）

---

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

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

### 推奨読解順序

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

タスク作成時に関連するデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | task.rb | `app/models/polymorphic/task.rb` | バリデーション（116-120行目）、set_due_date（217-234行目） |

**読解のコツ**: `before_create :set_due_date`で期日が自動計算される点に注目。bucketの値に応じてdue_atが設定される。

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

コントローラーのnewとcreateアクションを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | tasks_controller.rb | `app/controllers/tasks_controller.rb` | newアクション（34-50行目）、createアクション（68-77行目） |

**主要処理フロー（new）**:
1. **35行目**: `@view = view` でビュー種別を取得
2. **36行目**: `@task = Task.new` で新規オブジェクト生成
3. **37行目**: `@bucket` でバケット選択肢を設定
4. **38行目**: `@category` でカテゴリ選択肢を設定
5. **40-46行目**: 関連エンティティの取得（relatedパラメータ処理）

**主要処理フロー（create）**:
1. **69-70行目**: @viewとTaskオブジェクト生成
2. **73行目**: @task.saveで保存
3. **74行目**: 成功時にサイドバー更新

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

フォームの構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | _new.html.haml | `app/views/tasks/_new.html.haml` | フォーム構造、hidden_field |
| 3-2 | _top_section.html.haml | `app/views/tasks/_top_section.html.haml` | 入力項目、crm.flip_calendar |

**主要処理フロー**:
- **4-6行目**: user_id, asset_id, asset_typeをhidden_fieldでセット
- **13行目**: bucketドロップダウンのonchangeでcrm.flip_calendar呼び出し

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

```
TasksController#new
    │
    ├─ @view = view
    │
    ├─ @task = Task.new
    │
    ├─ @bucket = Setting.unroll(:task_bucket)[1..-1] + [specific_time]
    │
    ├─ @category = Setting.unroll(:task_category)
    │
    ├─ 関連エンティティ取得（related param）
    │      └─ @asset = model.my.find_by_id(id)
    │
    └─ respond_with(@task)

TasksController#create
    │
    ├─ @view = view
    │
    ├─ @task = Task.new(task_params)
    │
    ├─ @task.save
    │      │
    │      ├─ before_create :set_due_date
    │      │      └─ bucketからdue_atを計算
    │      │
    │      └─ [tasks] INSERT
    │
    ├─ update_sidebar (called_from_index_page?)
    │
    └─ respond_with(@task)
```

### データフロー図

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

フォーム入力
    │
    ├── task[name] ──────▶ TasksController#create
    │                           │
    ├── task[bucket] ──────────┤
    │                           │
    ├── task[calendar] ────────┤
    │                           │
    ├── task[assigned_to] ─────┤
    │                           │
    └── task[asset_*] ─────────┤
                                │
                                ├──▶ set_due_date (before_create)
                                │         │
                                │         └──▶ bucketからdue_at計算
                                │
                                ├──▶ Task#save
                                │         │
                                │         └──▶ [tasks] INSERT
                                │
                                └────────────────────────▶ JS Response
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| task.rb | `app/models/polymorphic/task.rb` | モデル | タスクエンティティ、期日計算 |
| tasks_controller.rb | `app/controllers/tasks_controller.rb` | コントローラ | new/createアクション |
| _new.html.haml | `app/views/tasks/_new.html.haml` | テンプレート | 新規作成フォーム |
| _top_section.html.haml | `app/views/tasks/_top_section.html.haml` | テンプレート | 入力項目 |
| routes.rb | `config/routes.rb` | 設定 | ルーティング定義 |
