# マスタードキュメント - 圃場管理編 > **最終更新**: 2026-02-20 > **対象バージョン**: Phase 1 (MVP) 完了時点 > **目的**: このドキュメントだけで圃場管理機能の全容を把握できること --- ## 目次 1. [機能概要](#1-機能概要) 2. [データモデル](#2-データモデル) 3. [API仕様](#3-api仕様) 4. [画面仕様](#4-画面仕様) 5. [インポート仕様](#5-インポート仕様) 6. [エクスポート仕様](#6-エクスポート仕様) 7. [対応表(E-2)機能](#7-対応表e-2機能) 8. [PDF帳票との関係](#8-pdf帳票との関係) 9. [作付け計画との関係](#9-作付け計画との関係) 10. [設計判断と制約](#10-設計判断と制約) 11. [ソースファイル索引](#11-ソースファイル索引) --- ## 1. 機能概要 ### 圃場管理機能とは 農業生産者が所有・管理する農地(圃場)の情報を管理する機能。本システムでは以下の3種類のデータを扱う。 | データ種別 | 説明 | レコード数 | ソース | |---|---|---|---| | **実圃場(Field)** | 農家が実際に管理している農地 | 39筆 | 吉田農地台帳.ods | | **共済マスタ(OfficialKyosaiField)** | 水稲共済細目書の区画 | 31区画 | 水稲共済細目用.ods | | **中山間マスタ(OfficialChusankanField)** | 中山間交付金の区画 | 71区画 | 中山間.ods | ### 3つのデータの関係 ``` 実圃場 (39筆) ├── M:N ─── 共済マスタ (31区画) ※1つの実圃場が複数の共済区画に対応可 └── M:N ─── 中山間マスタ (71区画) ※1つの実圃場が複数の中山間区画に対応可 ``` **M:N (多対多) 関係にした理由**: 当初は1:1を想定したが、実運用データで「1つの実圃場が複数の申請区画にまたがる」ケースが判明したため。 ### ユーザーフロー 1. **初回セットアップ**: データ取込画面から3つのODSファイルをインポート 2. **日常管理**: 圃場一覧で圃場情報の確認、圃場詳細で共済/中山間との紐付け確認・編集 3. **年次作業**: 作付け計画画面で年度ごとの作付けを設定 4. **申請書作成**: 帳票出力画面でPDFを生成・ダウンロード --- ## 2. データモデル ### 2.1 Field(実圃場) **テーブル名**: `fields_field` **ソース**: `backend/apps/fields/models.py:48-78` | フィールド名 | 型 | 制約 | 説明 | |---|---|---|---| | id | BigAutoField | PK | 自動採番 | | name | CharField(100) | NOT NULL | 圃場名(例: 「田んぼA」)| | address | CharField(255) | NOT NULL | 住所 | | area_tan | DecimalField(6,4) | NOT NULL | 面積(反)※表示用 | | area_m2 | IntegerField | NOT NULL | 面積(m2)※計算用 | | owner_name | CharField(100) | NOT NULL | 地主名 | | group_name | CharField(50) | NULL可 | グループ名(エリア・用途分け用) | | display_order | IntegerField | default=0 | 表示順(カスタム並び替え用) | | raw_kyosai_k_num | CharField(20) | NULL可 | インポート時の共済耕地番号(raw値) | | raw_kyosai_s_num | CharField(20) | NULL可 | インポート時の共済分筆番号(raw値) | | raw_chusankan_id | CharField(20) | NULL可 | インポート時の中山間ID(raw値、カンマ区切り複数可) | | location | PointField | NULL可 | 位置情報(Phase 1未使用) | **M:N関係(中間テーブル)**: - `fields_field_kyosai_fields` → OfficialKyosaiField との紐付け - `fields_field_chusankan_fields` → OfficialChusankanField との紐付け **面積の変換ルール**: `area_m2 = area_tan × 1000`(1反 = 1000m2 で統一) ### 2.2 OfficialKyosaiField(共済マスタ) **テーブル名**: `fields_officialkyosaifield` **ソース**: `backend/apps/fields/models.py:5-18` | フィールド名 | 型 | 制約 | 説明 | |---|---|---|---| | id | BigAutoField | PK | 自動採番 | | k_num | CharField(20) | UNIQUE(k_num, s_num) | 耕地番号 | | s_num | CharField(20) | UNIQUE(k_num, s_num) | 分筆番号(枝番) | | address | CharField(255) | NOT NULL | 住所(地名地番) | | kanji_name | CharField(100) | NOT NULL | 漢字地名 | | area | IntegerField | default=0 | 本地面積(m2)| **ユニーク制約**: `(k_num, s_num)` の組み合わせで一意 ### 2.3 OfficialChusankanField(中山間マスタ) **テーブル名**: `fields_officialchusankanfield` **ソース**: `backend/apps/fields/models.py:21-45` | フィールド名 | 型 | 制約 | 説明 | |---|---|---|---| | id | BigAutoField | PK | 自動採番 | | c_id | CharField(20) | UNIQUE | 中山間ID | | chusankan_flag | CharField(10) | NULL可 | 中山間フラグ | | oaza | CharField(100) | NOT NULL | 大字 | | aza | CharField(100) | NOT NULL | 字 | | chiban | CharField(50) | NOT NULL | 地番 | | branch_num | CharField(20) | NULL可 | 枝番 | | land_type | CharField(20) | NULL可 | 地目 | | area | IntegerField | default=0 | 農地面積(m2) | | planting_area | IntegerField | NULL可 | 植栽面積(m2) | | original_crop | CharField(100) | NULL可 | 作付け品目 | | manager | CharField(100) | NULL可 | 協定管理者 | | owner | CharField(100) | NULL可 | 所有者 | | slope | CharField(20) | NULL可 | 傾斜度 | | base_amount | IntegerField | NULL可 | 基本金額 | | steep_slope_addition | IntegerField | NULL可 | 超急傾斜加算額 | | smart_agri_addition | IntegerField | NULL可 | スマート農業加算額 | | payment_amount | IntegerField | NULL可 | 交付金額 | **ユニーク制約**: `c_id` で一意 ### 2.4 関連モデル(作付け計画系) **Crop(作物マスタ)** - `backend/apps/plans/models.py:5-13` | フィールド名 | 型 | 制約 | 説明 | |---|---|---|---| | id | BigAutoField | PK | 自動採番 | | name | CharField(100) | UNIQUE | 作物名(米、トウモロコシ等) | **Variety(品種マスタ)** - `backend/apps/plans/models.py:16-26` | フィールド名 | 型 | 制約 | 説明 | |---|---|---|---| | id | BigAutoField | PK | 自動採番 | | crop | FK(Crop) | CASCADE | 親の作物 | | name | CharField(100) | UNIQUE(crop, name) | 品種名 | **Plan(作付け計画)** - `backend/apps/plans/models.py:29-43` | フィールド名 | 型 | 制約 | 説明 | |---|---|---|---| | id | BigAutoField | PK | 自動採番 | | field | FK(Field) | CASCADE | 対象圃場 | | year | IntegerField | UNIQUE(field, year) | 作付年度 | | crop | FK(Crop) | CASCADE | 作物 | | variety | FK(Variety) | SET_NULL, NULL可 | 品種 | | notes | TextField | NULL可 | 備考 | ### 2.5 ER図(テキスト形式) ``` ┌──────────────────┐ M:N ┌──────────────────────┐ │ Field │──────────────│ OfficialKyosaiField │ │ (39筆) │ │ (31区画) │ │ │ M:N ├──────────────────────┤ │ id │──────────────│ OfficialChusankanField│ │ name │ │ (71区画) │ │ address │ └──────────────────────┘ │ area_tan │ │ area_m2 │ 1:N │ owner_name │──────────────┐ │ group_name │ │ │ display_order │ ┌─────────┴─────┐ └──────────────────┘ │ Plan │ │ (年度×圃場) │ │ │ │ field (FK) │ │ year │ N:1 ┌────────┐ │ crop (FK) │─────────────│ Crop │ │ variety (FK) │ N:1 ├────────┤ └───────────────┘─────────────│Variety │ └────────┘ ``` --- ## 3. API仕様 ### 3.1 圃場 CRUD **ベースURL**: `/api/fields/` **ViewSet**: `FieldViewSet` (`backend/apps/fields/views.py:18-27`) **認証**: JWT Bearer トークン必須 | メソッド | エンドポイント | 説明 | リクエスト/レスポンス | |---|---|---|---| | GET | `/api/fields/` | 圃場一覧取得 | → `Field[]`(group_name, display_order, id順) | | GET | `/api/fields/{id}/` | 圃場詳細取得 | → `Field`(kyosai_fields, chusankan_fieldsをネスト含む) | | POST | `/api/fields/` | 圃場新規作成 | ← `{name, address, area_tan, area_m2, owner_name}` | | PUT | `/api/fields/{id}/` | 圃場全体更新 | ← 全フィールド | | PATCH | `/api/fields/{id}/` | 圃場部分更新 | ← 変更フィールドのみ | | DELETE | `/api/fields/{id}/` | 圃場削除 | → 204 No Content | **レスポンス例(GET /api/fields/{id}/)**: ```json { "id": 1, "name": "田んぼA", "address": "○○市△△町123", "area_tan": "1.2000", "area_m2": 1200, "owner_name": "吉田太郎", "group_name": "上エリア", "display_order": 1, "kyosai_fields": [ { "id": 5, "k_num": "12", "s_num": "1", "address": "○○ 123", "kanji_name": "上田", "area": 1200, "linked_field_names": ["田んぼA"] } ], "chusankan_fields": [ { "id": 10, "c_id": "42", "chusankan_flag": "○", "oaza": "△△", "aza": "□□", "chiban": "123", "branch_num": null, "land_type": "田", "area": 1200, "planting_area": 1100, "original_crop": "米", "manager": "吉田太郎", "owner": "吉田太郎", "slope": "1/20", "base_amount": 21000, "steep_slope_addition": null, "smart_agri_addition": null, "payment_amount": 21000, "linked_field_names": ["田んぼA"] } ] } ``` **ソート**: デフォルトは `group_name ASC NULLS FIRST, display_order ASC, id ASC` クエリパラメータ `ordering=area_tan` 等で変更可能。 ### 3.2 共済/中山間マスタ(読み取り専用) | メソッド | エンドポイント | 説明 | |---|---|---| | GET | `/api/kyosai-fields/` | 共済マスタ一覧(k_num, s_num順) | | GET | `/api/kyosai-fields/{id}/` | 共済マスタ詳細 | | GET | `/api/chusankan-fields/` | 中山間マスタ一覧(c_id順) | | GET | `/api/chusankan-fields/{id}/` | 中山間マスタ詳細 | **ViewSet**: `OfficialKyosaiFieldViewSet`, `OfficialChusankanFieldViewSet` (`backend/apps/fields/views.py:30-39`) **ルーティング**: `backend/keinasystem/urls.py:23-25` の `master_router` で登録 各レスポンスに `linked_field_names: string[]` が含まれ、紐付いている実圃場の名前を返す。 ### 3.3 M:N紐付け操作 **ソース**: `backend/apps/fields/views.py:42-77` | メソッド | エンドポイント | 説明 | |---|---|---| | POST | `/api/fields/{field_id}/kyosai-links/` | 共済リンク追加 | | DELETE | `/api/fields/{field_id}/kyosai-links/{kyosai_id}/` | 共済リンク削除 | | POST | `/api/fields/{field_id}/chusankan-links/` | 中山間リンク追加 | | DELETE | `/api/fields/{field_id}/chusankan-links/{chusankan_id}/` | 中山間リンク削除 | **リンク追加リクエスト例**: ```json // POST /api/fields/1/kyosai-links/ { "kyosai_field_ids": [5, 8] } // POST /api/fields/1/chusankan-links/ { "chusankan_field_ids": [10, 15, 20] } ``` ### 3.4 作付け計画関連API **ベースURL**: `/api/plans/` **ViewSet**: `PlanViewSet` (`backend/apps/plans/views.py:20-132`) | メソッド | エンドポイント | 説明 | |---|---|---| | GET | `/api/plans/?year=2026` | 年度指定で計画一覧取得 | | POST | `/api/plans/` | 計画新規作成 | | PATCH | `/api/plans/{id}/` | 計画更新 | | DELETE | `/api/plans/{id}/` | 計画削除 | | GET | `/api/plans/summary/?year=2026` | 年度別集計 | | POST | `/api/plans/copy_from_previous_year/` | 前年度コピー | | POST | `/api/plans/bulk_update/` | 一括更新 | | GET | `/api/plans/get_crops_with_varieties/` | 作物+品種一覧 | **集計レスポンス例 (GET /api/plans/summary/?year=2026)**: ```json { "year": 2026, "total_fields": 39, "assigned_fields": 35, "unassigned_fields": 4, "total_plans": 35, "total_area": 25.5, "by_crop": [ { "crop": "米", "count": 20, "area": 15.3 }, { "crop": "トウモロコシ", "count": 8, "area": 5.2 } ] } ``` **前年度コピー リクエスト**: ```json // POST /api/plans/copy_from_previous_year/ { "from_year": 2025, "to_year": 2026 } ``` **一括更新 リクエスト**: ```json // POST /api/plans/bulk_update/ { "field_ids": [1, 3, 5], "year": 2026, "crop": 2, "variety": 4 } ``` ### 3.5 作物・品種マスタAPI | メソッド | エンドポイント | 説明 | |---|---|---| | GET | `/api/plans/crops/` | 作物一覧 | | POST | `/api/plans/crops/` | 作物追加 | | GET | `/api/plans/varieties/` | 品種一覧 | | POST | `/api/plans/varieties/` | 品種追加 | | DELETE | `/api/plans/varieties/{id}/` | 品種削除 | --- ## 4. 画面仕様 ### 4.1 圃場一覧画面 **URL**: `/fields` **ソース**: `frontend/src/app/fields/page.tsx` **機能**: - 全圃場をカード形式で一覧表示 - グループ名でフィルタ(ドロップダウン) - 各カードに: 圃場名、住所、面積(反)、地主名、共済紐付け数、中山間紐付け数 - 「新規作成」ボタン → `/fields/new` に遷移 - カードクリック → `/fields/{id}` に遷移 **データ取得**: `GET /api/fields/` → 全圃場をフロントで表示 **グループフィルタのロジック**: 全圃場の `group_name` からユニーク値を抽出し、ドロップダウンで選択。「すべて」選択時は全件表示。 ### 4.2 圃場詳細画面 **URL**: `/fields/{id}` **ソース**: `frontend/src/app/fields/[id]/page.tsx` **機能**: - 圃場の全情報を表示(名前、住所、面積、地主、グループ) - インライン編集(各フィールドの編集ボタンでトグル) - **共済マスタ紐付けセクション**: 紐付いている共済区画の一覧表示 + 紐付け追加/削除 - **中山間マスタ紐付けセクション**: 紐付いている中山間区画の一覧表示 + 紐付け追加/削除 - 紐付け追加はモーダル(`LinkModal`コンポーネント)で実施 - 圃場削除ボタン(確認ダイアログ付き) **紐付け追加モーダル(LinkModal)**: - ソース: `frontend/src/components/LinkModal.tsx` - 未紐付けのマスタ区画を一覧表示 - チェックボックスで複数選択 → 一括追加 - 既に他の圃場に紐付いている区画も表示(紐付け先圃場名を表示) **データフロー**: ``` 圃場詳細表示: GET /api/fields/{id}/ 紐付け候補取得: GET /api/kyosai-fields/ または /api/chusankan-fields/ 紐付け追加: POST /api/fields/{id}/kyosai-links/ or /chusankan-links/ 紐付け削除: DELETE /api/fields/{id}/kyosai-links/{kyosai_id}/ 圃場更新: PATCH /api/fields/{id}/ 圃場削除: DELETE /api/fields/{id}/ ``` ### 4.3 圃場新規作成画面 **URL**: `/fields/new` **ソース**: `frontend/src/app/fields/new/page.tsx` **入力フィールド**: - 圃場名(必須) - 住所(必須) - 面積・反(必須)→ 入力時に自動でm2計算 - 地主名(必須) - グループ名(任意) **バリデーション**: フロント側で必須チェック。面積は数値チェック。 ### 4.4 ダッシュボード画面 **URL**: `/dashboard` **ソース**: `frontend/src/app/dashboard/page.tsx` 圃場管理に関連する表示: - **全圃場数** / **作付け済み圃場数** / **未割当圃場数** のサマリーカード - 作物別集計テーブル(面積・筆数) - クイックアクセスボタン(作付け計画、圃場管理、帳票出力、データ取込) ### 4.5 作付け計画画面 **URL**: `/allocation` **ソース**: `frontend/src/app/allocation/page.tsx` 圃場管理に関連する機能: - 全圃場を表形式で表示(圃場名、面積、作物、品種、備考) - **グループ名**: インライン編集(datalistで既存グループから選択 or 自由入力) - **表示順**: カスタム順モードで↑↓ボタンで変更(PATCH /api/fields/{id}/ で保存) - **ソート**: カスタム順 / グループ順 / 作付け順 - **検索・フィルタ**: 圃場名・住所テキスト検索、作物フィルタ、未割当のみ表示 - **チェックボックス一括操作**: 複数圃場を選択して作物・品種を一括設定 - **年度管理**: localStorageで年度保持、過去年度は参照モード(amber色表示) --- ## 5. インポート仕様 ### 5.1 インポート画面 **URL**: `/import` **ソース**: `frontend/src/app/import/page.tsx` 3種類のODSファイルをインポートする画面。**インポート順序が重要**: ``` 1. 共済マスタ (水稲共済細目用.ods) ← 先にインポート 2. 中山間マスタ (中山間.ods) ← 先にインポート 3. 実圃場 (吉田農地台帳.ods) ← 最後(M:N紐付けのため) ``` ### 5.2 共済マスタインポート **エンドポイント**: `POST /api/fields/import/kyosai/` **ソース**: `backend/apps/fields/views.py:80-139` **ODSカラム → DBフィールド マッピング**: | ODSカラム名 | DBフィールド | 変換処理 | |---|---|---| | 耕地番号 | k_num | strip() | | 分筆番号 | s_num | strip() | | 地名 地番 | address | strip() | | 漢字地名 | kanji_name | strip() | | 本地面積 (m2) ※スペース有無両対応 | area | `float(値) × 100`(アール→m2変換) | **重要**: ODSファイルの面積値は**アール(a)単位**。m2への変換で `×100` している。 **upsertロジック**: `(k_num, s_num)` でマッチングし、`update_or_create`。 ### 5.3 中山間マスタインポート **エンドポイント**: `POST /api/fields/import/chusankan/` **ソース**: `backend/apps/fields/views.py:232-304` **ODSカラム → DBフィールド マッピング**: | ODSカラム名 | DBフィールド | 変換処理 | |---|---|---| | ID | c_id | strip() | | 中山間 | chusankan_flag | safe_str() | | 大字 | oaza | safe_str() | | 字 | aza | safe_str() | | 地番 | chiban | safe_str() | | 枝番 | branch_num | safe_str() or None | | 地目 | land_type | safe_str() or None | | 農地面積 | area | safe_int() | | 植栽面積 | planting_area | safe_int() | | 作付け品目 | original_crop | safe_str() or None | | 協定管理者 | manager | safe_str() or None | | 所有者 | owner | safe_str() or None | | 傾斜度 | slope | safe_str() or None | | 基本金額 | base_amount | safe_int() | | 超急傾斜加算額 | steep_slope_addition | safe_int() | | スマート農業加算額 | smart_agri_addition | safe_int() | | 交付金額 | payment_amount | safe_int() | **スキップ条件**: c_idが空、または数字を含まない行はスキップ。 **upsertロジック**: `c_id` でマッチングし、`update_or_create`。 ### 5.4 実圃場インポート **エンドポイント**: `POST /api/fields/import/yoshida/` **ソース**: `backend/apps/fields/views.py:142-229` **ODSカラム → DBフィールド マッピング**: | ODSカラム名 | DBフィールド | 変換処理 | |---|---|---| | 名称 | name | strip() | | 住所 | address | strip() | | 面積(反) | area_tan, area_m2 | area_m2 = area_tan × 1000 | | 地主 | owner_name | strip() | | 細目_耕地番号 | raw_kyosai_k_num | clean_int_str() | | 細目_分筆番号 | raw_kyosai_s_num | clean_int_str() | | 中山間_ID | raw_chusankan_id | clean_int_str(), カンマ区切り対応 | **upsertロジック**: `name` でマッチングし、`update_or_create`。 **M:N紐付け処理(インポート時に自動実行)**: 1. `raw_kyosai_k_num` と `raw_kyosai_s_num` の両方がある場合 → 共済マスタの `(k_num, s_num)` で検索 → `field.kyosai_fields.add()` 2. `raw_chusankan_id` がある場合 → カンマ区切りで分割 → 各IDで中山間マスタを検索 → `field.chusankan_fields.add()` **clean_int_str()関数**: NaN/空文字 → None、末尾 `.0` を除去。 --- ## 6. エクスポート仕様 **エンドポイント**: `GET /api/fields/export/zip/` **ソース**: `backend/apps/fields/views.py:307-380` 全データをCSV形式でZIPアーカイブとしてエクスポート。 **含まれるCSVファイル**: | ファイル名 | 内容 | カラム | |---|---|---| | fields.csv | 実圃場 | id, name, address, area_tan, area_m2, owner_name, group_name, display_order | | kyosai_fields.csv | 共済マスタ | id, k_num, s_num, address, kanji_name, area | | chusankan_fields.csv | 中山間マスタ | id, c_id, chusankan_flag, oaza, aza, chiban, branch_num, land_type, area, planting_area, original_crop, manager, owner, slope, base_amount, steep_slope_addition, smart_agri_addition, payment_amount | | plans.csv | 作付け計画 | id, field_id, field_name, year, crop_id, crop_name, variety_id, variety_name, notes | | crops_varieties.csv | 作物・品種 | crop_id, crop_name, variety_id, variety_name | | field_links.csv | M:N紐付け | field_id, field_name, link_type(kyosai/chusankan), linked_id | --- ## 7. 対応表(E-2)機能 圃場詳細画面における共済/中山間マスタとの紐付け管理機能。 ### 紐付け追加フロー 1. 圃場詳細画面で「共済区画を追加」or「中山間区画を追加」ボタンをクリック 2. `LinkModal` が開く 3. 全マスタ区画が一覧表示される(既に紐付いている区画にはチェック済み表示) 4. 各区画に `linked_field_names` が表示され、どの実圃場に紐付いているか確認可能 5. チェックボックスで選択 → 「追加」ボタンで `POST /api/fields/{id}/kyosai-links/` or `/chusankan-links/` ### 紐付け削除フロー 1. 圃場詳細画面の紐付きリストで「×」ボタンをクリック 2. 確認ダイアログ 3. `DELETE /api/fields/{id}/kyosai-links/{kyosai_id}/` or `/chusankan-links/{chusankan_id}/` --- ## 8. PDF帳票との関係 圃場データは PDF帳票生成で以下のように使用される。 ### 8.1 水稲共済細目書 PDF **エンドポイント**: `GET /api/reports/kyosai/{year}/` **ソース**: `backend/apps/reports/views.py:38-66` **データ集約ロジック**: ``` 共済マスタ区画ごとにループ: 1. 共済区画に紐づく実圃場群を取得 (kyosai.fields.all()) 2. 各実圃場の当年度Planから作物・品種を集約 3. 行データとして出力 ``` ### 8.2 中山間交付金申請書 PDF **エンドポイント**: `GET /api/reports/chusankan/{year}/` **ソース**: `backend/apps/reports/views.py:69-105` **データ集約ロジック**: ``` 中山間マスタ区画ごとにループ: 1. 中山間区画に紐づく実圃場群を取得 (ch.fields.all()) 2. 各実圃場の当年度Planから作物・品種を集約 3. 所在地 = 大字 + 字 + 地番 (+ 枝番) 4. 行データとして出力 ``` **共通の集約関数**: `_get_plan_info(related_fields, year)` (`backend/apps/reports/views.py:8-35`) --- ## 9. 作付け計画との関係 ### Plan → Field の関係 - `Plan.field` は `Field` への FK(CASCADE) - `unique_together = ['field', 'year']` により、1つの圃場に年度あたり1つの計画のみ - Field削除時、関連するPlanも全て削除される(CASCADE) ### 作付け計画画面での圃場操作 作付け計画画面(`/allocation`)では以下の圃場関連操作が可能: | 操作 | API呼び出し | 説明 | |---|---|---| | グループ名変更 | `PATCH /api/fields/{id}/` | `{ "group_name": "上エリア" }` | | 表示順変更 | `PATCH /api/fields/{id}/` | `{ "display_order": 5 }` | --- ## 10. 設計判断と制約 ### 10.1 絶対に変えてはいけない制約 1. **Field ↔ OfficialKyosaiField は M:N** — 決してFKに変更しない 2. **Field ↔ OfficialChusankanField は M:N** — 決してFKに変更しない 3. **Plan の (field, year) ユニーク制約** — 1圃場1年度1計画 4. **共済マスタの (k_num, s_num) ユニーク制約** 5. **中山間マスタの c_id ユニーク制約** ### 10.2 面積の扱い | 用途 | 単位 | フィールド | |---|---|---| | DB保存 | m2 (整数) | `area_m2` | | 画面表示 | 反 (小数) | `area_tan` | | 変換式 | 1反 = 1000m2 | 実際は991.736m2だが1000で統一 | | 共済ODS | アール(a) | インポート時に `×100` でm2変換 | ### 10.3 年度管理の設計方針 - **作付け計画画面**: `localStorage` で選択年度を保持(セッション跨ぎで記憶) - **過去年度**: 参照モード(amber色表示、「現在年度に戻る」ボタン) - **ダッシュボード/帳票**: 常に `new Date().getFullYear()` をデフォルト - **Phase 2**: グローバル作業年度の導入予定 ### 10.4 認証 - JWT認証(`rest_framework_simplejwt`) - アクセストークン: 24時間有効 - リフレッシュトークン: 7日間有効 - フロントエンド: `localStorage` にトークン保存、`axios` interceptorで自動付与・リフレッシュ - API設定: `DEFAULT_PERMISSION_CLASSES = IsAuthenticated` --- ## 11. ソースファイル索引 ### バックエンド | ファイル | 行数 | 内容 | |---|---|---| | `backend/apps/fields/models.py` | 79行 | Field, OfficialKyosaiField, OfficialChusankanField モデル定義 | | `backend/apps/fields/views.py` | 381行 | ViewSet、インポート3種、エクスポート、M:Nリンク操作 | | `backend/apps/fields/serializers.py` | 37行 | FieldSerializer(ネストあり)、マスタSerializer | | `backend/apps/fields/urls.py` | 18行 | ルーティング定義 | | `backend/apps/plans/models.py` | 44行 | Crop, Variety, Plan モデル定義 | | `backend/apps/plans/views.py` | 133行 | PlanViewSet(CRUD、summary、copy、bulk_update) | | `backend/apps/plans/serializers.py` | 37行 | Plan, Crop, Variety シリアライザ | | `backend/apps/plans/urls.py` | 13行 | ルーティング定義 | | `backend/apps/reports/views.py` | 106行 | PDF生成(共済・中山間) | | `backend/apps/reports/urls.py` | 7行 | ルーティング定義 | | `backend/keinasystem/urls.py` | 35行 | ルートURL設定(マスタルーター含む) | | `backend/keinasystem/settings.py` | 151行 | Django設定(DB, JWT, CORS等) | ### フロントエンド | ファイル | 内容 | |---|---| | `frontend/src/app/fields/page.tsx` | 圃場一覧画面 | | `frontend/src/app/fields/[id]/page.tsx` | 圃場詳細画面(M:N紐付け管理含む) | | `frontend/src/app/fields/new/page.tsx` | 圃場新規作成画面 | | `frontend/src/app/allocation/page.tsx` | 作付け計画画面(圃場グループ・順序操作含む) | | `frontend/src/app/dashboard/page.tsx` | ダッシュボード(圃場数サマリー) | | `frontend/src/app/import/page.tsx` | データ取込画面(3種インポート) | | `frontend/src/app/reports/page.tsx` | 帳票出力画面 | | `frontend/src/components/Navbar.tsx` | ナビゲーションバー | | `frontend/src/components/LinkModal.tsx` | M:N紐付け追加モーダル | | `frontend/src/lib/api.ts` | Axiosインスタンス、JWT認証インターセプター | | `frontend/src/types/index.ts` | TypeScript型定義(Field, Plan, Crop, Variety等) | ### TypeScript型定義 ```typescript // frontend/src/types/index.ts interface Field { id: number; name: string; address: string; area_tan: string; // DecimalFieldはstring型で来る area_m2: number; owner_name: string; group_name: string | null; display_order: number; kyosai_fields: OfficialKyosaiField[]; chusankan_fields: OfficialChusankanField[]; } interface OfficialKyosaiField { id: number; k_num: string; s_num: string; address: string; kanji_name: string; area: number; linked_field_names?: string[]; } interface OfficialChusankanField { id: number; c_id: string; oaza: string; aza: string; chiban: string; area: number; payment_amount: number | null; linked_field_names?: string[]; } interface Plan { id: number; field: number; field_name: string; year: number; crop: number; crop_name: string; variety: number; variety_name: string; notes: string | null; } interface Crop { id: number; name: string; varieties: Variety[]; } interface Variety { id: number; crop: number; name: string; } ``` --- ## 更新履歴 - 2026-02-20: 初版作成(Phase 1 MVP完了時点の全機能を網羅)