From b7b5ce3943500a00d4fbccb723ea0ac41a1a0bf5 Mon Sep 17 00:00:00 2001 From: akira Date: Fri, 10 Apr 2026 13:14:07 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20TODO=E7=AE=A1=E7=90=86=E6=A9=9F?= =?UTF-8?q?=E8=83=BD=E3=81=AE=E3=83=9E=E3=82=B9=E3=82=BF=E3=83=BC=E3=83=89?= =?UTF-8?q?=E3=82=AD=E3=83=A5=E3=83=A1=E3=83=B3=E3=83=88=E3=82=92=E4=BD=9C?= =?UTF-8?q?=E6=88=90=E3=81=97=E4=BB=95=E6=A7=98=E6=9B=B8=E6=A1=88=E3=82=92?= =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 論点1-5の決定を仕様書案に反映 - document/19_マスタードキュメント_TODO管理編.md を新規作成 - CLAUDE.md のマスタードキュメント一覧に TODO管理を追加 --- CLAUDE.md | 1 + .../19_マスタードキュメント_TODO管理編.md | 367 ++++++++++++++++++ 改善案/TODO管理機能仕様書案.md | 54 +-- 3 files changed, 398 insertions(+), 24 deletions(-) create mode 100644 document/19_マスタードキュメント_TODO管理編.md diff --git a/CLAUDE.md b/CLAUDE.md index 52dffd0..3c023f4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -109,6 +109,7 @@ ssh keinafarm-claude 'cd /home/keinasystem/keinasystem_t02 && \ | 運搬計画 | `document/14_マスタードキュメント_分配計画編.md` | | 田植え計画 | `document/16_マスタードキュメント_田植え計画編.md` | | 農薬散布管理 | `document/18_マスタードキュメント_農薬散布管理編.md` | +| TODO管理 | `document/19_マスタードキュメント_TODO管理編.md` | | データモデル全体 | `document/03_データ仕様書.md` | --- diff --git a/document/19_マスタードキュメント_TODO管理編.md b/document/19_マスタードキュメント_TODO管理編.md new file mode 100644 index 0000000..ae56240 --- /dev/null +++ b/document/19_マスタードキュメント_TODO管理編.md @@ -0,0 +1,367 @@ +# マスタードキュメント:TODO管理機能 + +> **作成**: 2026-04-10 +> **最終更新**: 2026-04-10 +> **対象機能**: TODO管理(作業指示・優先順位管理・実績連携導線) +> **実装状況**: 設計完了・実装前 +> **対象 Issue**: `akira/keinasystem#17` + +--- + +## 概要 + +繁忙期に「どれから手を付けるか」を管理するための TODO 機能。 +計画(施肥・田植え・運搬など)と実績の間に位置する「作業指示」レイヤー。 + +### 機能スコープ(IN / OUT) + +| IN(MVP対象) | OUT(対象外) | +|---|---| +| TODO の作成・編集・削除 | 期日通知・リマインダー | +| ステータス管理(todo / doing / done / canceled) | 複数ユーザー割り当て | +| 優先順位管理(ドラッグ&ドロップ / 矢印移動) | コメント・添付ファイル | +| 圃場単位の対象紐づけ | 工数見積・実績時間記録 | +| 計画との紐づけ(施肥・田植え・運搬) | 完全な汎用ワークフローエンジン化 | +| 計画画面からの TODO 生成 | 実績アプリ未実装領域の詳細実績入力 UI | +| 完了時の実績入力画面への導線生成 | | +| 完了済み・キャンセル済みの表示切り替え | | + +### TODO の位置づけ + +``` +計画(年間設計情報) + ↓ 生成 +TODO(実際に動く作業単位) + ↓ 完了 +実績(完了した事実) +``` + +--- + +## データモデル + +### Todo(本体) + +| フィールド | 型 | 必須 | 説明 | +|---|---|---|---| +| id | bigint | ✓ | PK | +| year | integer | ✓ | 年度 | +| title | varchar(200) | ✓ | タイトル | +| description | text | | 説明 | +| status | enum | ✓ | `todo / doing / done / canceled` | +| priority | integer | ✓ | 小さいほど上位(1000刻み) | +| due_date | date | | 期日 | +| work_type | enum | ✓ | 作業種別(下記参照) | +| should_link_record | boolean | ✓ | 完了時に実績連携導線を有効にするか | +| completed_at | datetime | | 完了日時(差し戻し後も保持) | +| canceled_at | datetime | | キャンセル日時 | +| created_at | datetime | ✓ | | +| updated_at | datetime | ✓ | | + +#### ステータス遷移 + +- `todo` → `doing` → `done`(complete/ 専用エンドポイント経由) +- `done` → `todo / doing`(差し戻し許可。completed_at は履歴として保持) +- `canceled` への遷移は任意のタイミングで可 + +#### 作業種別(work_type) + +MVP で採用する種別: + +| 値 | 意味 | +|---|---| +| `general` | 一般(どれにも当てはまらない作業) | +| `fertilization` | 施肥 | +| `rice_transplant` | 田植え | +| `delivery` | 運搬 | +| `levee_work` | 畔塗 | + +将来追加(農薬散布管理アプリ実装時): + +| 値 | 意味 | +|---|---| +| `pesticide` | 防除 | + +#### 並び順 + +- 基本は FILO(新規作成時は最上位へ) +- 初回作成時:最上位 TODO の `priority - 1000` を割り当て +- 一覧表示:`priority` 昇順 +- 並び替え後:表示対象全体を 1000, 2000, 3000... と再採番して保存 +- 完了・キャンセル済みも `priority` を保持 + +### TodoTargetField(対象圃場) + +| フィールド | 型 | 必須 | 説明 | +|---|---|---|---| +| id | bigint | ✓ | PK | +| todo | FK(Todo) | ✓ | CASCADE | +| field | FK(fields.Field) | ✓ | PROTECT | +| field_name_snapshot | varchar(100) | ✓ | 保存時点の圃場名 | +| group_name_snapshot | varchar(50) | | 保存時点の group_name | +| created_at | datetime | ✓ | | + +- `unique_together = ['todo', 'field']` +- 圃場グループは独立モデル化しない(`Field.group_name` を参照するのみ) +- 計画に含まれる圃場の一部だけを対象にすることを許可する + +### TodoCrop(分類補助:作物) + +| フィールド | 型 | 必須 | 説明 | +|---|---|---|---| +| id | bigint | ✓ | PK | +| todo | FK(Todo) | ✓ | CASCADE | +| crop | FK(plans.Crop) | ✓ | PROTECT | +| created_at | datetime | ✓ | | + +- `unique_together = ['todo', 'crop']` + +### TodoVariety(分類補助:品種) + +| フィールド | 型 | 必須 | 説明 | +|---|---|---|---| +| id | bigint | ✓ | PK | +| todo | FK(Todo) | ✓ | CASCADE | +| variety | FK(plans.Variety) | ✓ | PROTECT | +| created_at | datetime | ✓ | | + +- `unique_together = ['todo', 'variety']` +- 圃場が 0 件でも Crop / Variety だけの紐づけは許可(圃場未確定の準備作業など) + +### TodoPlanLink(計画との紐づけ) + +| フィールド | 型 | 必須 | 説明 | +|---|---|---|---| +| id | bigint | ✓ | PK | +| todo | FK(Todo) | ✓ | CASCADE | +| plan_type | enum | ✓ | `fertilization / rice_transplant / delivery` | +| fertilization_plan | FK(fertilizer.FertilizationPlan) | | | +| rice_transplant_plan | FK(plans.RiceTransplantPlan) | | | +| delivery_plan | FK(分配計画モデル) | | | +| created_at | datetime | ✓ | | + +- 1 行に 1 種別のリンクのみ保持 +- `plan_type` に応じて対応 FK だけを埋める +- `levee_work` は MVP では「計画リンクなしで持てる work_type」として扱う +- 作付け計画(Plan)は TODO 生成元としては対象外 + +### TodoCompletionLink(完了時の実績連携索引) + +| フィールド | 型 | 必須 | 説明 | +|---|---|---|---| +| id | bigint | ✓ | PK | +| todo | FK(Todo) | ✓ | | +| record_type | enum | ✓ | 実績種別 | +| work_record | FK(workrecords.WorkRecord) | | 共通索引 | +| spreading_session | FK(fertilizer.SpreadingSession) | | 施肥実績 | +| created_at | datetime | ✓ | | + +- `todo` は OneToOne ではなく FK(1 TODO から複数実績への分割を許容) +- 実績アプリが未実装の種別は空でよい + +--- + +## API 仕様 + +### エンドポイント一覧 + +| メソッド | パス | 説明 | +|---|---|---| +| GET | `/api/todos/` | 一覧取得 | +| POST | `/api/todos/` | 作成 | +| GET | `/api/todos/{id}/` | 詳細取得 | +| PATCH | `/api/todos/{id}/` | 更新(status=done への変更は不可) | +| DELETE | `/api/todos/{id}/` | 削除 | +| PATCH | `/api/todos/reorder/` | 並び替え | +| POST | `/api/todos/from-plan/` | 計画から TODO 生成 | +| POST | `/api/todos/{id}/complete/` | 完了処理(実績連携導線を返す) | + +### 重要な設計ルール + +**完了処理の一本化** +- `PATCH` での `status=done` 変更はバックエンドが拒否する +- 完了は必ず `POST /api/todos/{id}/complete/` を通る +- 理由:実績連携導線の生成を確実にするため。AI 実装者がセッションをまたいで実装する際のブレを防ぐ + +**差し戻し時の挙動** +- `done → todo/doing` は許可 +- `TodoCompletionLink` が存在する場合は、差し戻しを許可しつつ API レスポンスに警告と各実績レコードへの直リンクを返す +- 実績レコード自体の削除は行わない(各実績アプリ側の責務) + +**削除時の挙動** +- `TodoCompletionLink` が存在する TODO を削除しようとした場合、警告と各実績レコードへの直リンクを返す +- ユーザーが確認した上で削除を実行した場合は物理削除を許可する +- `TodoCompletionLink` は TODO と一緒に削除(CASCADE) +- 実績レコード自体は削除しない + +### 一覧 GET `/api/todos/` + +主なクエリパラメータ: + +| パラメータ | デフォルト | 説明 | +|---|---|---| +| `status` | `todo,doing` | カンマ区切りで複数指定可 | +| `include_closed` | `false` | true で完了・キャンセルも含む | +| `work_type` | - | 作業種別フィルター | +| `due` | - | `overdue / today / upcoming` | +| `year` | - | 年度フィルター | + +### 作成 POST `/api/todos/` + +```json +{ + "title": "西田エリアの追肥", + "description": "週内に先行実施", + "status": "todo", + "year": 2026, + "due_date": "2026-04-12", + "work_type": "fertilization", + "should_link_record": true, + "field_ids": [12, 18, 21], + "crop_ids": [1], + "variety_ids": [4], + "plan_links": [ + {"plan_type": "fertilization", "plan_id": 8} + ] +} +``` + +`plan_links` の変換:API 入力は `plan_type + plan_id` の組で受け、Serializer で対応 FK へ変換する。 + +### 並び替え PATCH `/api/todos/reorder/` + +```json +{ + "items": [ + {"id": 31, "priority": 1000}, + {"id": 27, "priority": 2000}, + {"id": 42, "priority": 3000} + ] +} +``` + +### 計画から TODO 生成 POST `/api/todos/from-plan/` + +```json +{ + "plan_type": "fertilization", + "plan_id": 8, + "title": "2026春肥の散布", + "field_ids": [12, 18], + "due_date": "2026-04-15", + "should_link_record": true +} +``` + +- `field_ids` 未指定時は計画内の全圃場を初期対象にする +- `work_type` は `plan_type` から自動補完する + +### 完了処理 POST `/api/todos/{id}/complete/` + +- `status=done` にする +- `should_link_record=true` かつ対応実績アプリがある場合、関連画面へ遷移するための情報を返す +- MVP では実績レコードの自動生成は行わず、導線情報の返却にとどめる + +--- + +## バリデーション + +- `done` 遷移時に `completed_at` を自動設定 +- `canceled` 遷移時に `canceled_at` を自動設定 +- `PATCH` で `status=done` を指定した場合は 400 エラーを返す +- `field_ids` が計画外圃場を含む場合は `plan_links` が 1 件以上あるときのみエラーにする +- `should_link_record=true` でも対応実績アプリが無い場合は保存を許可する +- `TodoTargetField.field` は `PROTECT`(過去 TODO の対象圃場履歴を保全するため) + +--- + +## UI 仕様 + +### 一覧画面 `/todos` + +- デフォルト表示:todo / doing を priority 昇順で表示 +- 完了済み・キャンセル済みはフィルターで表示切り替え +- 期限超過は赤系で強調、当日期限も強調表示 +- ドラッグ&ドロップで並び替え(難しければ矢印ボタンで代替) + +表示カラム:タイトル / ステータス / 期日 / 作業種別 / 対象圃場数 / 紐づき計画 + +### 詳細画面 `/todos/{id}` + +表示・編集:タイトル / 説明 / ステータス / 期日 / 作業種別 / 実績連携フラグ / 対象圃場 / 分類作物・品種 / 計画リンク + +下部表示:実績連携先 / 完了日時 / 更新日時 + +### 作成導線 + +1. TODO 一覧から新規作成 +2. 計画詳細または一覧から TODO 生成(施肥・田植え・運搬の各計画画面) + +--- + +## 実装ファイル構成 + +### Backend + +``` +apps/todos/ +├── models.py # Todo, TodoTargetField, TodoCrop, TodoVariety, TodoPlanLink, TodoCompletionLink +├── admin.py +├── serializers.py +├── views.py +├── urls.py +└── migrations/ +``` + +- `keinasystem/settings.py` に `apps.todos` を追加 +- `keinasystem/urls.py` に `/api/todos/` を追加 + +### Frontend + +``` +frontend/src/app/todos/ +├── page.tsx # 一覧 +├── [id]/page.tsx # 詳細 +└── new/page.tsx # 作成 +``` + +### 実装順 + +1. モデル・admin・migration +2. TODO CRUD API(一覧・詳細・作成・更新・削除) +3. TODO 一覧・詳細 UI +4. 並び替え API と UI +5. 計画から TODO 生成(from-plan API + 各計画画面への導線) +6. 完了処理 API と実績連携導線 UI + +--- + +## 実績連携の考え方 + +### 施肥 + +`施肥計画 → 施肥TODO → 施肥実績`(SpreadingSession)の流れ。 +完了時は `SpreadingSession` 作成画面への導線を返す。対象圃場は `TodoTargetField` を初期値として渡す。 + +### 田植え + +田植え実績アプリは今後実装予定。MVP では: +- `rice_transplant` 種別の TODO を持てる +- 完了時は「完了済みだが実績アプリ未接続」の状態も許容する +- 将来の田植え実績導入時に `TodoCompletionLink` を拡張する + +### 実績アプリが無い作業 + +`general` など、実績アプリに紐づかない TODO は `status=done` のみで完了とする。 + +--- + +## 未決定(実装時に判断) + +以下は MVP 着手後に実装者が判断しながら決めてよい事項。 + +| 事項 | 方針 | +|---|---| +| 複数計画リンクの初回 UI | 内部構造は複数可。UI はまず 1 件中心で実装し、必要なら拡張する | +| 並び替え対象の範囲 | フィルター中(todo/doing のみ)を再採番対象とするのが自然 | +| 施肥完了時に渡す初期値の粒度 | SpreadingSession 作成画面の実装時に具体的な受け渡し仕様を決める | diff --git a/改善案/TODO管理機能仕様書案.md b/改善案/TODO管理機能仕様書案.md index cae85df..b575017 100644 --- a/改善案/TODO管理機能仕様書案.md +++ b/改善案/TODO管理機能仕様書案.md @@ -186,20 +186,22 @@ TODO 本体。 作業種別は「計画に対応するもの」と「計画に対応しないもの」の両方を含める。 -初期案: +初期採用(MVP): - `general`: 一般 - `fertilization`: 施肥 - `rice_transplant`: 田植え - `delivery`: 運搬 - `levee_work`: 畔塗 -- `pesticide`: 防除 -- `other_recorded`: 計画非紐づき実績系 + +将来追加(アプリ実装時): + +- `pesticide`: 防除(農薬散布管理アプリ実装時に追加) 補足: -- 実装時点で将来の全計画種別を確定できない場合は、MVP では現行アプリに対応する種別を先行定義する - `general` はどれにも当てはまらない作業用に必須 +- 現行アプリに対応する種別のみで始め、新しい計画機能追加時に `work_type` を拡張する ### 7.2 TodoTargetField @@ -386,7 +388,7 @@ TODO と既存計画との紐づけ。 - タイトル - 説明 -- ステータス +- ステータス(`todo` / `doing` / `canceled` のみ。`done` への変更は不可) - 期日 - 作業種別 - 実績連携フラグ @@ -394,14 +396,18 @@ TODO と既存計画との紐づけ。 - 分類 - 計画リンク +**注意**: `status=done` への変更は `PATCH` では受け付けない。完了は必ず `POST /api/todos/{id}/complete/` を使うこと。理由は、完了時に実績連携導線の生成が必要なため、入口を一本化して実装のブレを防ぐ。 + ### 8.5 削除 - `DELETE /api/todos/{id}/` -ルール案: +ルール: -- 連携済み実績がある TODO は物理削除ではなく制限をかける案を優先 -- MVP ではまず `done` かつ実績連携済み TODO の削除可否を要確認とする +- `TodoCompletionLink` が存在する TODO を削除しようとした場合、警告と各実績レコードへの直リンクを返す +- ユーザーが確認した上で削除を実行した場合は物理削除を許可する +- `TodoCompletionLink` は TODO と一緒に削除する(CASCADE) +- 実績レコード自体は削除しない(各実績アプリ側の責務) ### 8.6 並び替え @@ -581,6 +587,8 @@ MVP では少なくとも以下の 2 導線を持つ。 - `canceled` に遷移したら `canceled_at` を自動設定する - `done` から `todo` または `doing` への差し戻しは MVP では許可する - 差し戻し時も `completed_at` はクリアせず履歴値として保持する +- 差し戻し時に `TodoCompletionLink` が存在する場合は、差し戻し自体は許可しつつ、API レスポンスに警告と各実績レコードへの直リンクを返す +- フロントはその警告を表示し、ユーザーが実績を削除したい場合は直リンクから遷移できるようにする(実績レコード自体の削除は TODO 側では行わない) - `plan_links` に紐づく計画の年度と TODO の利用年度が必要なら将来追加する - `field_ids` が計画外圃場を含む場合は、`plan_links` が 1 件以上ある場合のみエラーにする - 複数 `plan_links` がある場合は、それぞれの計画に対して対象圃場整合性を検証する @@ -645,27 +653,25 @@ MVP では少なくとも以下の 2 導線を持つ。 ## 14. 未確定事項 -### 14.1 work_type enum の最終一覧 +### 14.1 work_type enum の初回実装範囲(確定) -今回の回答で方針は見えたが、初回実装でどこまで列挙するかは確定していない。 +MVP は現行アプリ対応の5種別のみで開始する。 -候補: +- `general`: 一般 +- `fertilization`: 施肥 +- `rice_transplant`: 田植え +- `delivery`: 運搬 +- `levee_work`: 畔塗 -- 一般 -- 施肥 -- 田植え -- 運搬 -- 畔塗 -- 防除 -- 計画非紐づき実績系 +`pesticide`(防除)は農薬散布管理アプリ実装時に追加する。 -### 14.2 完了時の自動生成レベル +### 14.2 完了時の実績連携レベル(確定) -MVP で以下のどこまでやるかは実装前に決める。 +MVP は **B. 実績入力画面への導線生成** を採用する。 -- A. 完了ステータス変更のみ -- B. 実績入力画面への導線生成 -- C. TODO 情報を使った実績レコード仮生成 +- A. 完了ステータス変更のみ → 採用しない +- **B. 実績入力画面への導線生成 → 採用** +- C. TODO 情報を使った実績レコード仮生成 → 後続検討 ### 14.3 削除ポリシー @@ -700,7 +706,7 @@ MVP では以下を前提とする。 - TODO は `year` を持つ - 対象管理は `TodoTargetField` を正とする -- `work_type` は `general / fertilization / rice_transplant / delivery / levee_work / pesticide` を初期採用する +- `work_type` は `general / fertilization / rice_transplant / delivery / levee_work` を初期採用する(`pesticide` は農薬散布管理アプリ実装時に追加) - 計画リンクは明示 FK 方式で開始する - 実績連携フラグ名は `should_link_record` を採用する - 完了時はまず「実績入力画面への導線生成」を採用し、自動実績作成は後続検討とする