{"id":51223669,"url":"https://github.com/yasunorioi/rotation-planner","last_synced_at":"2026-06-28T09:03:31.532Z","repository":{"id":335707140,"uuid":"1144946872","full_name":"yasunorioi/rotation-planner","owner":"yasunorioi","description":null,"archived":false,"fork":false,"pushed_at":"2026-05-18T09:20:29.000Z","size":9591,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-18T10:31:19.801Z","etag":null,"topics":["agriculture","agritech","constraint-programming","cp-sat","crop-rotation","farming","fastapi","hokkaido","optimization","or-tools","react","sqlite"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yasunorioi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY_AUDIT.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-29T08:29:10.000Z","updated_at":"2026-05-18T09:20:34.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/yasunorioi/rotation-planner","commit_stats":null,"previous_names":["yasunorioi/rotation-planner"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/yasunorioi/rotation-planner","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yasunorioi%2Frotation-planner","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yasunorioi%2Frotation-planner/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yasunorioi%2Frotation-planner/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yasunorioi%2Frotation-planner/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yasunorioi","download_url":"https://codeload.github.com/yasunorioi/rotation-planner/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yasunorioi%2Frotation-planner/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34882752,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-28T02:00:05.809Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agriculture","agritech","constraint-programming","cp-sat","crop-rotation","farming","fastapi","hokkaido","optimization","or-tools","react","sqlite"],"created_at":"2026-06-28T09:03:30.988Z","updated_at":"2026-06-28T09:03:31.522Z","avatar_url":"https://github.com/yasunorioi.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 農業管理アプリ（Rotation Planner）\n\n北海道畑作農家向けの統合農業管理アプリケーション。\nほ場管理・輪作計画・農薬発注・防除記録を一元管理し、OR-Toolsによる最適化で科学的な輪作計画を自動生成する。\n\n## アーキテクチャ\n\n```mermaid\nflowchart TD\n\nsubgraph group_group_backend[\"Backend API\"]\n  node_node_api_main[\"API entrypoint\u003cbr/\u003eFastAPI app\u003cbr/\u003e[main.py]\"]\n  node_node_api_routers[\"API routers\u003cbr/\u003eHTTP routes\"]\n  node_node_api_deps[\"Dependencies\u003cbr/\u003eDI/auth glue\u003cbr/\u003e[deps.py]\"]\nend\n\nsubgraph group_group_domain[\"Domain Core\"]\n  node_node_common[(\"Shared core\u003cbr/\u003edomain kernel\")]\n  node_node_field{{\"Fields \u0026 GIS\u003cbr/\u003espatial subsystem\"}}\n  node_node_optimizer{{\"Rotation planner\u003cbr/\u003eCP-SAT optimizer\"}}\n  node_node_crop_history[\"Crop history\u003cbr/\u003ehistory module\"]\n  node_node_pesticide{{\"Pesticide ops\u003cbr/\u003ecalculation/export\"}}\n  node_node_pesticide_record{{\"Spray records\u003cbr/\u003erecording/export\"}}\n  node_node_famic[\"FAMIC import\u003cbr/\u003ebatch ingest\"]\nend\n\nsubgraph group_group_frontend[\"Frontend UI\"]\n  node_node_front_app[\"React app\u003cbr/\u003eSPA shell\"]\n  node_node_front_pages[\"Pages\u003cbr/\u003escreen layer\"]\n  node_node_front_components[\"Shared UI\u003cbr/\u003ecomponents\"]\n  node_node_front_state[\"Client state\u003cbr/\u003estores\"]\n  node_node_front_lib[\"Client logic\"]\nend\n\nsubgraph group_group_data_ops[\"Data \u0026 Ops\"]\n  node_node_db[(\"SQLite schema\u003cbr/\u003eschema/data\u003cbr/\u003e[db_schema.sql]\")]\n  node_node_data[(\"Live data\u003cbr/\u003eruntime data\")]\n  node_node_scripts[\"Ops scripts\u003cbr/\u003emaintenance\"]\n  node_node_tests[\"Test suite\u003cbr/\u003everification\"]\nend\n\nnode_node_api_main --\u003e|\"registers\"| node_node_api_routers\nnode_node_api_main --\u003e|\"injects\"| node_node_api_deps\nnode_node_api_routers --\u003e|\"calls\"| node_node_common\nnode_node_api_routers --\u003e|\"field APIs\"| node_node_field\nnode_node_api_routers --\u003e|\"plan APIs\"| node_node_optimizer\nnode_node_api_routers --\u003e|\"pesticide APIs\"| node_node_pesticide\nnode_node_api_routers --\u003e|\"record APIs\"| node_node_pesticide_record\nnode_node_api_routers --\u003e|\"import APIs\"| node_node_famic\nnode_node_front_app --\u003e|\"routes to\"| node_node_front_pages\nnode_node_front_app --\u003e|\"uses\"| node_node_front_components\nnode_node_front_app --\u003e|\"stores\"| node_node_front_state\nnode_node_front_app --\u003e|\"fetches\"| node_node_front_lib\nnode_node_front_lib --\u003e|\"HTTP calls\"| node_node_api_main\nnode_node_common --\u003e|\"persists to\"| node_node_db\nnode_node_field --\u003e|\"stores\"| node_node_db\nnode_node_field --\u003e|\"reads caches\"| node_node_data\nnode_node_optimizer --\u003e|\"loads models\"| node_node_common\nnode_node_optimizer --\u003e|\"updates\"| node_node_crop_history\nnode_node_pesticide --\u003e|\"uses\"| node_node_common\nnode_node_pesticide --\u003e|\"reads/writes\"| node_node_db\nnode_node_pesticide_record --\u003e|\"persists\"| node_node_db\nnode_node_famic --\u003e|\"imports into\"| node_node_db\nnode_node_scripts --\u003e|\"migrates\"| node_node_db\nnode_node_tests -.-\u003e|\"covers\"| node_node_api_main\nnode_node_tests -.-\u003e|\"covers\"| node_node_optimizer\nnode_node_tests -.-\u003e|\"covers\"| node_node_field\nnode_node_tests -.-\u003e|\"covers\"| node_node_front_app\n\nclick node_node_api_main \"https://github.com/yasunorioi/rotation-planner/blob/main/api/main.py\"\nclick node_node_api_routers \"https://github.com/yasunorioi/rotation-planner/tree/main/api/routers\"\nclick node_node_api_deps \"https://github.com/yasunorioi/rotation-planner/blob/main/api/deps.py\"\nclick node_node_common \"https://github.com/yasunorioi/rotation-planner/tree/main/rotation_planner/common\"\nclick node_node_field \"https://github.com/yasunorioi/rotation-planner/tree/main/rotation_planner/field\"\nclick node_node_optimizer \"https://github.com/yasunorioi/rotation-planner/tree/main/rotation_planner/app\"\nclick node_node_crop_history \"https://github.com/yasunorioi/rotation-planner/tree/main/rotation_planner/crop_history\"\nclick node_node_pesticide \"https://github.com/yasunorioi/rotation-planner/tree/main/rotation_planner/pesticide\"\nclick node_node_pesticide_record \"https://github.com/yasunorioi/rotation-planner/tree/main/rotation_planner/pesticide_record\"\nclick node_node_famic \"https://github.com/yasunorioi/rotation-planner/tree/main/rotation_planner/famic\"\nclick node_node_front_app \"https://github.com/yasunorioi/rotation-planner/tree/main/frontend/app/src\"\nclick node_node_front_pages \"https://github.com/yasunorioi/rotation-planner/tree/main/frontend/app/src/pages\"\nclick node_node_front_components \"https://github.com/yasunorioi/rotation-planner/tree/main/frontend/app/src/components\"\nclick node_node_front_state \"https://github.com/yasunorioi/rotation-planner/tree/main/frontend/app/src/store\"\nclick node_node_front_lib \"https://github.com/yasunorioi/rotation-planner/tree/main/frontend/app/src/lib\"\nclick node_node_db \"https://github.com/yasunorioi/rotation-planner/blob/main/db_schema.sql\"\nclick node_node_data \"https://github.com/yasunorioi/rotation-planner/tree/main/data\"\nclick node_node_scripts \"https://github.com/yasunorioi/rotation-planner/tree/main/scripts\"\nclick node_node_tests \"https://github.com/yasunorioi/rotation-planner/tree/main/tests\"\n\nclassDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a\nclassDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554\nclassDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f\nclassDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d\nclassDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337\nclassDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81\nclassDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a\nclass node_node_api_main,node_node_api_routers,node_node_api_deps toneBlue\nclass node_node_common,node_node_field,node_node_optimizer,node_node_crop_history,node_node_pesticide,node_node_pesticide_record,node_node_famic toneAmber\nclass node_node_front_app,node_node_front_pages,node_node_front_components,node_node_front_state,node_node_front_lib toneMint\nclass node_node_db,node_node_data,node_node_scripts,node_node_tests toneRose\n```\n\n## 主な機能\n\n| 機能 | 説明 |\n|------|------|\n| 🌱 作物設定 | 作付する作物を選択・カスタム作物追加 |\n| 🗺️ ほ場登録 | 地図上でほ場を登録（筆ポリゴン対応・KML/KMZインポート） |\n| 🗺️ ほ場一覧 | 年度別作物をマトリックス形式で表示・編集 |\n| 🌾 作付けポリゴン管理 | 同一ほ場内の作物別ポリゴン登録・前年コピー・KMLインポート |\n| 🌾 水田ポリゴン管理 | 水田ポリゴン登録・畑地化フラグ管理・KMLインポート |\n| 📊 地目別集計 | 作物×地目（畑/畑地化済/水田）クロス集計・畑地化年度別面積集計 |\n| 🌾 輪作計画 | OR-Tools CP-SATソルバーによる最適な輪作計画自動生成・PDF出力 |\n| 💊 農薬発注 | 輪作計画から年間の農薬必要量を算出・PDF出力 |\n| 💊 FAMIC農薬インポーター | 農薬検査所（FAMIC）公式XLSデータの一括取込 |\n| 🧪 防除記録 | 農薬散布記録の管理・画像解析によるラベル読取 |\n| 📥 データ管理 | CSV一括インポート/エクスポート・テンプレート提供 |\n| ⚙️ 管理 | ユーザー管理・バックアップ・筆ポリゴンアップロード |\n\n## 技術スタック\n\n| 種別 | 技術 |\n|------|------|\n| フロントエンド | React 18+ (Vite) |\n| バックエンド | FastAPI + Uvicorn |\n| 認証 | JWT（PyJWT） |\n| 言語 | Python 3.11+ |\n| DB | SQLite（22テーブル） |\n| 最適化 | Google OR-Tools CP-SAT ソルバー |\n| 地理空間 | Shapely 2.0+ / Pyproj 3.0+ / Leaflet.js |\n| PDF出力 | ReportLab 4.0+ |\n| データ処理 | Pandas 2.0+ / NumPy 1.24+ |\n| E2Eテスト | Playwright |\n\n## クイックスタート\n\n```bash\ngit clone https://github.com/yasunorioi/rotation-planner.git\ncd rotation-planner\npython3 -m venv venv\nsource venv/bin/activate\npip install -r requirements.txt\npip install -r api/requirements.txt\n\n# フロントエンド依存インストール\ncd frontend/app \u0026\u0026 npm install \u0026\u0026 cd ../..\n\n# DB初期化\npython3 -c \"from rotation_planner.common.db import init_db; init_db()\"\n\n# 開発サーバー起動（API + React）\nbash start-dev.sh\n# → API:   http://localhost:8000\n# → React: http://localhost:5173\n```\n\n### 初期ユーザー\n\n| ユーザー名 | パスワード | ロール |\n|-----------|-----------|--------|\n| admin | admin123 | 管理者 |\n| ja_staff | ja123 | JA職員 |\n| farmer_demo | demo123 | 農家（デモ用） |\n\n\u003e ⚠️ **本番環境では必ず初期パスワードを変更してください**\n\n## ユーザーロール\n\n| ロール | 権限 |\n|--------|------|\n| admin | 全機能 + ユーザー管理 + システム設定 |\n| ja_staff | 全機能 + 農家一覧 + 防除マスタ管理 + 農薬集約発注 |\n| farmer | 基本機能（作物設定〜農薬発注） |\n\n## 機能詳細\n\n### 🌱 作物設定\n\n- マスタから作付する作物を選択\n- カスタム作物の追加（例: ブロッコリー（2作目））\n- 選択した作物がほ場登録や輪作計画で使用可能に\n- **自動保存**: チェックボックス変更時に即座にDB保存\n\n### 🗺️ ほ場登録\n\n- OpenStreetMap + Leaflet.jsによる地図表示（Leaflet.drawプラグインでポリゴン描画）\n- WGS84楕円体による正確な測地面積計算（Shapely + Pyproj）\n- ほ場登録時に作付年度・作物を同時設定可能\n\n#### 対応インポート形式\n\n| 形式 | 説明 |\n|------|------|\n| KML/KMZ | Google Earth形式。Placemark/Polygon、Placemark/LineStringに対応 |\n| CSV | テンプレートによる一括登録 |\n| 筆ポリゴン | 農水省公開データ（GeoJSON形式、手動ダウンロード） |\n\n#### 筆ポリゴン連携\n\n農林水産省「筆ポリゴンデータ」（https://open.fude.maff.go.jp/）から農地区画情報を取り込み可能。\n\n- バウンディングボックス指定で該当範囲の筆ポリゴンを検索\n- 地方公共団体コードによる逆ジオコーディング（北海道全市町村対応）\n- GeoJSONファイルの `data/fude_cache/` へのローカルキャッシュ\n\n\u003e **注意**: 筆ポリゴンデータの利用には農水省の利用規約への同意が必要。自動ダウンロードは非対応のため、手動で `data/fude_cache/` にGeoJSONファイルを配置する。\n\n### 🗺️ ほ場一覧\n\n- ほ場×年度のマトリックス形式で作物を表示・編集\n- 令和年度形式（R5〜R9など）で年度範囲を指定\n- ほ場情報（ID、名前、地区、面積、禁止フラグ）のインライン編集\n- 輪作計画結果の微調整が可能\n\n### 🌾 作付けポリゴン管理\n\n同一ほ場内で複数の作物が混在する場合に、作物別の区画を管理する機能。\n\n- **年度別ポリゴン登録**: ほ場ごとに年度・作物を指定してポリゴンを描画\n- **KML/KMZインポート**: Google Earth等で作成した区画図を取込\n- **前年コピー**: 前年の作付けポリゴンを今年度にコピー\n- **面積自動計算**: 測地面積（ha）を自動算出\n- 対応テーブル: `crop_polygons`（field_id, year, crop_name, geometry, area_ha）\n\n### 🌾 輪作計画\n\n#### 最適化エンジン\n\n2つのソルバーを搭載:\n\n| ソルバー | 特徴 |\n|---------|------|\n| OR-Tools CP-SAT（デフォルト） | Google制約プログラミングソルバー。厳密解を探索 |\n| ヒューリスティック（フォールバック） | 貪欲法 + ローカルサーチ。高速だが近似解 |\n\n#### 制約設定\n\n**ハード制約（必ず満たす）:**\n\n| 制約 | 説明 | 設定場所 |\n|------|------|---------|\n| 連作禁止 | 同一作物の連続作付を禁止 | 固定（常に有効） |\n| 禁止遷移（固定） | てんさい→秋小麦（作期重複）、春小麦→秋小麦（病害対策） | 固定 |\n| 禁止遷移（ユーザー定義） | 任意の作物ペアの遷移を禁止 | `forbidden_transitions` |\n| 作付間隔 | 作物ごとの最小間隔年数（例: てんさい・馬鈴薯は4年） | `min_gap_years` |\n| てんさい禁止フラグ | `beet_forbidden=1` のほ場でてんさい・馬鈴薯を禁止 | ほ場登録時に設定 |\n\n**ソフト制約（ペナルティ付き最適化）:**\n\n| 制約 | 説明 | 設定場所 |\n|------|------|---------|\n| 面積上限 | 作物ごとの年間最大ha数 | `cap_ha` |\n| 面積下限 | 作物ごとの年間最小ha数 | `min_ha` |\n| ほ場数制限 | 作物ごとの最小・最大ほ場数 | `min_fields` / `max_fields` |\n| 優先遷移 | 望ましい作物遷移にボーナス（例: てんさい→大豆:10） | `preferred_transitions` |\n| 主作物安定 | 主要作物の年間面積変動を抑制 | `main_crops` |\n| 地区まとめ | 同一地区に同一作物を集約 | UI チェックボックス |\n| 隣接筆同一科制約 | 隣接ほ場での同一科作物を抑制（空間演算で隣接判定） | UI チェックボックス（PRO機能） |\n\n#### 不明年の取扱モード\n\n| モード | 動作 |\n|--------|------|\n| ignore（推奨） | 不明年は制約なしとして扱う |\n| safe | 不明年はワーストケース（全禁止作物の可能性あり）として扱う |\n\n#### 推論モード\n\n- 作付履歴の不明年を制約ベースの推論で自動補完\n- 推論された履歴は `is_inferred=1` フラグで区別\n\n#### ボトルネック分析\n\n- 各制約を個別に緩和して改善ポテンシャルを分析\n- どの制約が最適化の品質を最も制限しているかを特定\n\n#### 出力\n\n- **PDF/CSV出力**: 計画をダウンロード\n- **作付履歴に保存**: 生成した計画を直接作付履歴に反映\n\n### 💊 農薬発注\n\n- 輪作計画から対象年の農薬必要量を自動計算\n- 月別詳細スケジュール表示\n- 在庫控除: `inventory` テーブルの手持ち在庫を差し引き\n- **DB保存**: 発注リストを名前を付けて保存（`order_templates` テーブル）\n- **PDF出力**: 印刷用フォーマットでダウンロード\n- **保存済み一覧**: 過去の発注リストを読み込み/削除\n\n#### JA職員向け集約機能\n\n- JA管内の全農家の農薬発注を集約\n- 農薬名ごとの合計数量を算出\n- 農家別内訳の確認\n- 一括発注CSVのエクスポート\n\n### 💊 FAMIC農薬インポーター\n\n農薬検査所（FAMIC）が公開する農薬登録情報XLSファイルをDBに一括取込する機能。\n\n- **データソース**: https://www.acis.famic.go.jp/ddownload/index.htm\n- **依存ライブラリ**: `xlrd`（XLS読み込み）\n\n| インポート関数 | 対象ファイル | 取込先テーブル |\n|---------------|-------------|---------------|\n| `import_famic_basic()` | 登録基本部.xls | `pesticide_registry`（登録番号、名称、製造者、有効成分、剤型） |\n| `import_famic_usage()` | 登録適用部一/二.xls | `pesticide_usage`（作物名、適用病害虫、希釈倍数、使用時期、使用回数） |\n\n- インポート履歴は `famic_import_log` テーブルに記録\n- `get_import_stats()` で現在のインポート状況を確認可能\n\n### 🧪 防除記録\n\n- ほ場ごとの農薬散布記録管理\n- 散布日、農薬名、希釈倍率、散布量を記録\n- 履歴の編集・削除\n- CSV/PDFエクスポート（農薬取締法準拠フォーマット）\n\n#### 画像解析機能\n\n- 農薬ラベルの画像から情報を抽出（`image_analyzer.py`）\n- Tesseract OCR + OpenCV による前処理\n- 農薬名、登録番号、有効成分、希釈倍率を自動認識\n\n### 🌾 水田・畑地化管理\n\n- **水田ポリゴン登録**: 地図上で水田境界を描画・登録（KML/KMZインポート対応）\n- **畑地化フラグ管理**: 水田ポリゴンごとに畑地化フラグ（`is_converted`）と開始年度を設定\n- **データソース**: `maff`（農水省筆ポリゴン）/ `kml`（Google Earth）/ `manual`（手動描画）\n- **地目自動判定**: 作付けポリゴンと水田ポリゴンの空間演算（Shapely）で地目を自動分類\n  - **畑**: 作付けポリゴンのうち水田ポリゴンに重ならない部分\n  - **畑地化済**: 畑地化フラグ（`is_converted=true`）の水田ポリゴンと重なる部分\n  - **水田**: 畑地化フラグ（`is_converted=false`）の水田ポリゴンと重なる部分\n- **地目×作物クロス集計**: 作物を行、地目を列としたクロス集計表を生成\n- **畑地化開始年度別面積集計**: 畑地化の開始年度別に面積を集計（補助金申請用）\n\n#### データフロー\n\n```\n1. 水田ポリゴン登録（paddy_crud.py）\n2. 作付けポリゴン登録（crop_polygon_crud.py）\n3. 空間演算で地目判定（spatial.py）\n4. 集計処理（aggregation.py → aggregation_service.py）\n5. React画面で表示（Fields.jsx / Dashboard.jsx）\n```\n\n### 📥 データ管理\n\n- ほ場データのCSVインポート/エクスポート\n- 作付履歴のCSVインポート/エクスポート\n- 防除マスタのCSVインポート/エクスポート\n- バリデーション機能（空欄チェック、未登録作物チェック）\n- **テンプレート提供**: ほ場・制約・在庫・輪作計画のCSVテンプレートをダウンロード可能\n- **DBバックアップ**: SQLiteデータベースのダンプ\n\n### ⚙️ 管理（admin専用）\n\n- ユーザー管理（追加/削除/パスワードリセット/ロール変更）\n- システム情報表示\n- データバックアップ\n- 筆ポリゴンアップロード\n- デバッグモード切り替え\n\n## サーバーデプロイ（VPS）\n\n### 手動インストール\n\n```bash\ngit clone https://github.com/yasunorioi/rotation-planner.git\ncd rotation-planner\n\n# Python環境\npython3 -m venv venv\nsource venv/bin/activate\npip install -r requirements.txt\npip install -r api/requirements.txt\n\n# フロントエンドビルド\ncd frontend/app \u0026\u0026 npm install \u0026\u0026 npm run build \u0026\u0026 cd ../..\n\n# DB初期化\npython3 -c \"from rotation_planner.common.db import init_db; init_db()\"\n\n# API起動\nuvicorn api.main:app --host 0.0.0.0 --port 8000\n```\n\n### 動作確認済み環境\n\n- Debian 12 / Ubuntu 22.04\n- Python 3.11+\n- Node.js 18+\n- メモリ 512MB以上\n\n### systemdサービス設定\n\n```bash\nsudo tee /etc/systemd/system/rotation-planner.service \u003c\u003c 'EOF'\n[Unit]\nDescription=Rotation Planner FastAPI\nAfter=network.target\n\n[Service]\nType=simple\nUser=webapp\nWorkingDirectory=/var/www/rotation-planner/app\nExecStart=/var/www/rotation-planner/app/venv/bin/uvicorn api.main:app --host 127.0.0.1 --port 8000\nRestart=always\nRestartSec=3\n\n[Install]\nWantedBy=multi-user.target\nEOF\n\nsudo systemctl daemon-reload\nsudo systemctl enable rotation-planner\nsudo systemctl start rotation-planner\n```\n\n### nginx設定\n\n```bash\nsudo tee /etc/nginx/sites-available/rotation-planner \u003c\u003c 'EOF'\nserver {\n    listen 80;\n    server_name YOUR_DOMAIN_OR_IP;\n\n    # React静的ファイル\n    root /var/www/rotation-planner/app/frontend/app/dist;\n    index index.html;\n\n    location / {\n        try_files $uri $uri/ /index.html;\n    }\n\n    # FastAPI\n    location /api/ {\n        proxy_pass http://127.0.0.1:8000;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n}\nEOF\n\nsudo ln -sf /etc/nginx/sites-available/rotation-planner /etc/nginx/sites-enabled/\nsudo rm -f /etc/nginx/sites-enabled/default\nsudo nginx -t \u0026\u0026 sudo systemctl restart nginx\n```\n\n## 運用コマンド\n\n```bash\n# サービス状態確認\nsudo systemctl status rotation-planner\n\n# ログ確認\nsudo journalctl -u rotation-planner -f\n\n# 再起動\nsudo systemctl restart rotation-planner\n```\n\n## ファイル構成\n\n```\nrotation-planner/\n├── api/                               # FastAPI バックエンド\n│   ├── main.py                        # アプリエントリポイント\n│   ├── deps.py                        # 依存性注入（DB, 認証）\n│   ├── requirements.txt               # API依存ライブラリ\n│   ├── routers/                       # APIルーター\n│   │   ├── admin.py                   # 管理機能API\n│   │   ├── auth.py                    # 認証API（JWT）\n│   │   ├── crops.py                   # 作物API\n│   │   ├── dashboard.py               # ダッシュボードAPI\n│   │   ├── fields.py                  # ほ場API\n│   │   ├── gis.py                     # GIS/ポリゴンAPI\n│   │   ├── pesticides.py              # 農薬API\n│   │   └── plans.py                   # 輪作計画API\n│   └── inventory_api.py               # 在庫API\n│\n├── frontend/                          # React フロントエンド\n│   └── app/\n│       └── src/\n│           ├── pages/                 # ページコンポーネント\n│           │   ├── Login.jsx\n│           │   ├── Dashboard.jsx\n│           │   ├── Fields.jsx\n│           │   ├── FieldRegister.jsx\n│           │   ├── CropSettings.jsx\n│           │   ├── DataManagement.jsx\n│           │   ├── JAAggregation.jsx\n│           │   └── PesticideMasters.jsx\n│           ├── components/            # 共通コンポーネント\n│           └── store/                 # 状態管理\n│\n├── rotation_planner/                  # コアロジックパッケージ\n│   ├── field/                         # ほ場管理・ポリゴン・集計\n│   │   ├── crud.py                    # ほ場CRUD操作\n│   │   ├── map.py                     # Leaflet.js地図統合\n│   │   ├── kml_parser.py             # KML/KMZパーサー\n│   │   ├── fude_polygon.py           # 筆ポリゴン連携\n│   │   ├── crop_polygon_crud.py      # 作付けポリゴンCRUD\n│   │   ├── paddy_crud.py             # 水田ポリゴンCRUD\n│   │   ├── spatial.py                # 空間演算（測地面積計算・隣接判定）\n│   │   ├── aggregation.py            # 集計ロジック（作物×地目）\n│   │   └── aggregation_service.py    # 集計サービス（補助金計算）\n│   │\n│   ├── app/                           # 輪作計画（制約・最適化）\n│   │   ├── constraints.py            # 制約定義・パース・テーブル管理\n│   │   ├── optimizer.py              # OR-Tools CP-SAT / ヒューリスティック最適化\n│   │   └── utils.py                   # ヘルパー関数（Field, CSV生成等）\n│   │\n│   ├── pesticide/                     # 農薬発注\n│   │   ├── calculator.py             # 農薬必要量計算\n│   │   ├── master.py                  # 防除マスタリポジトリ\n│   │   ├── rotation.py               # 輪作計画連携\n│   │   ├── csv_io.py                 # CSV入出力\n│   │   └── pdf_export.py             # PDF出力（ReportLab）\n│   │\n│   ├── pesticide_record/             # 防除記録\n│   │   ├── export.py                 # CSV/PDFエクスポート\n│   │   └── image_analyzer.py         # 農薬ラベル画像解析（OCR）\n│   │\n│   ├── famic/                         # FAMIC農薬データインポーター\n│   │   └── importer.py               # XLS→DB取込（基本部・適用部）\n│   │\n│   └── common/                        # 共通モジュール\n│       ├── db.py                      # DB接続ユーティリティ\n│       ├── db_access.py              # リポジトリパターン（全テーブルのCRUD）\n│       ├── auth.py                    # 認証・認可（BCryptハッシュ, RBAC, JWT）\n│       ├── models.py                  # データモデル（User, Field等）\n│       ├── exceptions.py             # カスタム例外クラス\n│       ├── validation.py             # 入力バリデーション\n│       ├── export.py                 # CSV/PDFエクスポート共通\n│       ├── file_utils.py             # ファイル操作ユーティリティ\n│       └── year_utils.py             # 和暦（令和）⇔西暦変換\n│\n├── tests/                             # テストスイート（529件）\n│   ├── conftest.py                    # Pytest設定・フィクスチャ\n│   ├── test_optimizer_unit.py         # 最適化ロジック\n│   ├── test_constraints_unit.py       # 制約パース\n│   ├── ... (38ファイル)\n│   └── e2e/                           # Playwright E2Eテスト\n│       ├── test_fields.py\n│       ├── test_auth.py\n│       └── ... (6ファイル)\n│\n├── scripts/                           # ユーティリティスクリプト\n│   ├── backup_db.py                  # DBバックアップ\n│   ├── sync_users_to_db.py           # ユーザー同期\n│   └── migrate_*.sql                 # マイグレーションSQL\n│\n├── data/                              # データディレクトリ\n│   ├── rotation_planner.db           # SQLiteデータベース\n│   ├── settings.json                 # システム設定\n│   ├── famic/                        # FAMICデータ（XLS）\n│   └── fude_cache/                   # 筆ポリゴンキャッシュ\n│\n├── db_schema.sql                      # DBスキーマ定義（22テーブル）\n├── requirements.txt                   # Python依存ライブラリ\n└── start-dev.sh                       # 開発サーバー起動スクリプト\n```\n\n## データベーステーブル\n\nSQLiteデータベースに22テーブルを定義（`db_schema.sql`）。\n\n| # | テーブル | 説明 |\n|---|----------|------|\n| 1 | organizations | 組織（JA、個人農家グループ） |\n| 2 | users | ユーザー（username, password_hash, role, org_id） |\n| 3 | fields | ほ場（field_code, district, area_ha, beet_forbidden, coordinates_json） |\n| 4 | crop_history | 作付履歴（field_id, year, crop, is_inferred） |\n| 5 | rotation_plans | 輪作計画（user_id, name, start_year, end_year, constraints_json） |\n| 6 | plan_details | 輪作計画詳細（plan_id, field_id, year, crop） |\n| 7 | pesticide_masters | 防除マスタ（org_id, crop, pesticide_name, dilution_rate） |\n| 8 | user_constraints | ユーザー輪作制約（constraints_json, forbidden_transitions等） |\n| 9 | order_templates | 発注テンプレート（user_id, name, type, items_json） |\n| 10 | inventory | 在庫（user_id, pesticide_name, amount, unit） |\n| 11 | inventory_transactions | 在庫トランザクション履歴 |\n| 12 | inventory_csv_operations | 在庫CSV操作履歴 |\n| 13 | paddy_polygons | 水田ポリゴン（field_id, geometry, is_converted, source） |\n| 14 | crop_polygons | 作付けポリゴン（field_id, year, crop_name, geometry, area_ha） |\n| 15 | crop_master | 作物マスタ（作物名、科分類、輪作間隔等） |\n| 16 | user_crops | ユーザー作物選択（user_id, crop_name） |\n| 17 | pesticide_registry | FAMIC農薬登録基本情報（登録番号、名称、製造者、有効成分） |\n| 18 | pesticide_usage | FAMIC農薬適用情報（作物名、適用病害虫、希釈倍数） |\n| 19 | pesticide_records | 防除記録（ほ場ごとの農薬散布実績） |\n| 20 | famic_import_log | FAMICインポート履歴 |\n| 21 | pesticide_orders | 農薬発注レコード |\n| 22 | （マイグレーション追加分） | migrate_pesticide_v2.sql 等 |\n\n## 依存ライブラリ\n\n### バックエンド（requirements.txt）\n\n```\npandas\u003e=2.0.0          # データ操作\nnumpy\u003e=1.24.0          # 数値計算\nortools\u003e=9.0           # 制約最適化ソルバー（CP-SAT）\nshapely\u003e=2.0.0         # 地理空間ジオメトリ演算\npyproj\u003e=3.0.0          # 座標投影（WGS84→平面座標）\nrequests\u003e=2.28.0       # HTTP通信（筆ポリゴン取得等）\nreportlab\u003e=4.0.0       # PDF生成\npython-multipart\u003e=0.0.6\n```\n\n### API（api/requirements.txt）\n\n```\nfastapi\u003e=0.109.0       # REST APIフレームワーク\nuvicorn[standard]\u003e=0.27.0\npyjwt\u003e=2.8.0           # JWT認証\nxlrd\u003e=2.0.0            # FAMICインポーター（XLS読み込み）\n```\n\n## テスト\n\n```bash\nsource venv/bin/activate\n\n# 全テスト実行（529件）\npytest tests/ -v\n\n# 特定ファイルのみ\npytest tests/test_optimizer_unit.py -v\n\n# パターンマッチ\npytest tests/ -k \"optimizer\" -v\n\n# カバレッジ付き\npytest tests/ --cov=rotation_planner --cov-report=term-missing\n\n# E2Eテスト（Playwright）\npytest tests/e2e/ -v\n```\n\n### テスト分類\n\n| 分類 | ファイル数 | 対象 |\n|------|----------|------|\n| ユニットテスト | 15 | 制約パース、最適化ロジック、農薬計算、空間演算、バリデーション等 |\n| リポジトリテスト | 10 | DB操作（ほ場、作付履歴、計画、ユーザー、制約、防除マスタ等） |\n| 統合テスト | 7 | 農薬発注ワークフロー、防除記録、GIS、在庫、エクスポート等 |\n| セキュリティテスト | 2 | 認証、SQLインジェクション・XSS防止 |\n| E2Eテスト | 6 | Playwright ブラウザテスト |\n| その他 | 4 | CSV、隣接判定、作物科分類等 |\n\n## セキュリティ\n\n本番環境では以下を必ず実施してください：\n\n1. **adminパスワードを変更する**（初期値: admin123）\n2. **テストユーザーを削除する**（farmer_demo, ja_staff）\n3. **HTTPS化する**（certbot使用）\n4. **JWT_SECRET_KEY を環境変数で設定する**\n\n### セキュリティ対策\n\n- BCryptパスワードハッシュ\n- パラメタライズドクエリ（SQLインジェクション防止）\n- HTMLエスケープ（XSS防止）\n- ロールベースアクセス制御（RBAC）\n- JWTベース認証（PyJWT）\n\n## ライセンス\n\nMIT License\n\n## データ出典\n\n- 筆ポリゴン: 農林水産省「筆ポリゴンデータ」（https://open.fude.maff.go.jp/）\n- 農薬登録情報: 農薬検査所（FAMIC）（https://www.acis.famic.go.jp/ddownload/index.htm）\n- 地図: OpenStreetMap contributors\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyasunorioi%2Frotation-planner","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyasunorioi%2Frotation-planner","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyasunorioi%2Frotation-planner/lists"}