From 6e99164e3f65513f784a4b8b623a24ed05392b98 Mon Sep 17 00:00:00 2001 From: Akira Date: Sat, 28 Feb 2026 14:05:32 +0900 Subject: [PATCH] =?UTF-8?q?Trilium=E3=81=AB=E8=A8=98=E9=8C=B2=E3=81=97?= =?UTF-8?q?=E3=81=BE=E3=81=97=E3=81=9F=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ドキュメント整備が全て完了しました。今回のセッションで行った作業のまとめ: 実装した機能 Windmill フロー f/weather/weather_sync(毎朝6時 Asia/Tokyo)の作成・本番稼働 /weather フロントエンドページ(年別集計 / 期間指定の2モード) Recharts 3.7.0 による月別・日次グラフ(気温折れ線、降水量棒+日照折れ線 2軸) 整備したドキュメント ドキュメント 内容 CLAUDE.md weather 画面追加・Windmill フロー・マスタードキュメントリンク document/12_マスタードキュメント_気象データ編.md 気象機能の完全リファレンス(新規作成) MEMORY.md Windmill API パターン・Recharts TypeScript パターン Trilium マスタードキュメント フロントエンド2モード・Recharts・document/12_ 参照追加 --- CLAUDE.md | 16 +- .../12_マスタードキュメント_気象データ編.md | 241 ++++++++++++++++++ 2 files changed, 252 insertions(+), 5 deletions(-) create mode 100644 document/12_マスタードキュメント_気象データ編.md diff --git a/CLAUDE.md b/CLAUDE.md index f93a84a..7ffa4f7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -93,6 +93,7 @@ keinasystem_t02/ │ ├── feedback/[token]/ # フィードバックページ(認証不要) │ ├── history/ # メール処理履歴 │ └── rules/ # 送信者ルール管理 + ├── weather/ # 気象データ画面(年別集計・期間指定・グラフ) └── settings/ └── password/ # パスワード変更 ``` @@ -280,10 +281,12 @@ WeatherRecord (日次気象記録) - `GET /api/weather/gdd/?start_date=&base_temp=&end_date=` 有効積算温度(GDD) - `GET /api/weather/similarity/?year=` 類似年分析(月別パターン比較) - 管理コマンド: `python manage.py fetch_weather [--full] [--start-date] [--end-date]` - - Windmill フロー: `u/admin/weather_sync.flow`(ローカル作成済み、本番デプロイ要) + - Windmill フロー: `f/weather/weather_sync`(本番稼働中、毎朝6時 Asia/Tokyo) - `Crop.base_temp`(GDD計算の基準温度、default=0.0℃)をCropモデルに追加 - **初回データ投入**: `docker compose exec backend python manage.py fetch_weather --full` + - フロントエンド `/weather` 画面(年別集計・期間指定 モード、グラフは Recharts) - **将来計画**: 開花・収穫予測(品種ごとの目標GDD設定 → 到達日予測) + - マスタードキュメント: `document/12_マスタードキュメント_気象データ編.md` ### 🚧 既知の課題・技術的負債 @@ -340,9 +343,11 @@ Phase 2 のタスクに進む段階。 ```bash # ⚠️ --env-file .env.production を必ず付けること(省略するとSECRET_KEYが空でbackendが起動しない) -ssh keinafarm-claude 'cd /home/akira/keinasystem_t02 && \ - docker compose -f docker-compose.prod.yml --env-file .env.production build && \ - docker compose -f docker-compose.prod.yml --env-file .env.production up -d' +# ⚠️ 本番ファイルは keinasystem ユーザー所有。git pull は sudo -u keinasystem で実行 +ssh keinafarm-claude 'sudo -u keinasystem git -C /home/keinasystem/keinasystem_t02 pull origin main && \ + cd /home/keinasystem/keinasystem_t02 && \ + sudo -u keinasystem docker compose -f docker-compose.prod.yml --env-file .env.production build && \ + sudo -u keinasystem docker compose -f docker-compose.prod.yml --env-file .env.production up -d' ``` ### マイグレーションエラー @@ -381,6 +386,7 @@ docker-compose exec backend python manage.py migrate - **圃場管理機能**: `document/10_マスタードキュメント_圃場管理編.md` - **メール通知機能**: `document/11_マスタードキュメント_メール通知関連編.md` +- **気象データ機能**: `document/12_マスタードキュメント_気象データ編.md` ### 設計ドキュメント(プロジェクト横断) @@ -405,7 +411,7 @@ docker-compose exec backend python manage.py migrate ## 📝 更新履歴 -- 2026-02-28: 気象データ基盤を実装。`apps/weather` Django app(WeatherRecord, GDD API, 類似年分析API)、Windmill フロー `u/admin/weather_sync.flow`、管理コマンド `fetch_weather`。`Crop.base_temp` 追加(GDD基準温度)。初回データ投入は `fetch_weather --full` +- 2026-02-28: 気象データ機能を実装・本番稼働。`apps/weather`(WeatherRecord, 5 API)、Windmill `f/weather/weather_sync`(毎朝6時)、フロントエンド `/weather`(年別集計・期間指定・Rechartsグラフ)。`Crop.base_temp` 追加。デプロイコマンドの本番パス修正(/home/keinasystem/)。マスタードキュメント `document/12_マスタードキュメント_気象データ編.md` 追加 - 2026-02-25: CLAUDE.md更新。パスワード変更機能追記。メールフィルタリング機能を本番稼働済みに更新。マスタードキュメント `document/11_マスタードキュメント_メール通知関連編.md` リンク追加。デプロイコマンド(`--env-file .env.production` 必須)をトラブルシューティングに追加 - 2026-02-22: メールフィルタリング機能を実装。`apps/mail` Django app、Windmill向けAPI(APIキー認証)、フィードバックページ、ルール管理ページを追加。仕様書: `document/メールフィルタ/mail_filter_spec.md` - 2026-02-21: マスタードキュメント体系を導入。`document/10_マスタードキュメント_圃場管理編.md` を追加。セッション推奨フローにマスタードキュメント参照を追加 diff --git a/document/12_マスタードキュメント_気象データ編.md b/document/12_マスタードキュメント_気象データ編.md new file mode 100644 index 0000000..74f6654 --- /dev/null +++ b/document/12_マスタードキュメント_気象データ編.md @@ -0,0 +1,241 @@ +# 気象データ機能 マスタードキュメント + +> **最終更新**: 2026-02-28 +> **状態**: 本番稼働中 + +--- + +## 概要 + +Open-Meteo archive API から窪川の気象データを日次取得し、PostgreSQL に蓄積する。 +農業における積算温度計算・類似年分析・作期の気象振り返りを目的とする。 + +- **観測地点**: 窪川 (lat=33.213, lon=133.133) +- **データソース**: [Open-Meteo Archive API](https://archive-api.open-meteo.com/v1/archive)(無料) +- **蓄積期間**: 2016-01-01 〜 前日(毎朝自動更新) +- **Django アプリ**: `backend/apps/weather/` + +--- + +## データモデル + +### WeatherRecord (`apps/weather/models.py`) + +| フィールド | 型 | 説明 | +|---|---|---| +| date | DateField (unique) | 日付 | +| temp_mean | FloatField nullable | 平均気温 (℃) | +| temp_max | FloatField nullable | 最高気温 (℃) | +| temp_min | FloatField nullable | 最低気温 (℃) | +| sunshine_h | FloatField nullable | 日照時間 (h) | +| precip_mm | FloatField nullable | 降水量 (mm) | +| wind_max | FloatField nullable | 最大風速 (m/s) | +| pressure_min | FloatField nullable | 最低気圧 (hPa) | + +**Crop.base_temp** (`apps/plans/models.py` に追加): +- FloatField, default=0.0 +- GDD(有効積算温度)計算の基準温度 + +--- + +## API エンドポイント (`/api/weather/`) + +### POST `/api/weather/sync/` +- **認証**: X-API-Key(MAIL_API_KEY 設定値、Windmill と共用) +- **用途**: Windmill から日次データを受け取り upsert +- **リクエスト**: 単一オブジェクトまたはリスト +- **レスポンス**: `{"saved": N}` or `{"saved": N, "errors": [...]}` + +```json +[ + { + "date": "2026-02-27", + "temp_mean": 8.5, "temp_max": 14.2, "temp_min": 3.1, + "sunshine_h": 6.3, "precip_mm": 0.0, + "wind_max": 4.2, "pressure_min": 1008.0 + } +] +``` + +--- + +### GET `/api/weather/records/` +- **認証**: JWT +- **クエリパラメータ**: + - `?year=2025` — 年指定 + - `?start=2025-05-01&end=2025-09-30` — 日付範囲指定 +- **レスポンス**: WeatherRecord の配列(date 昇順) + +--- + +### GET `/api/weather/summary/?year=2025` +- **認証**: JWT +- **レスポンス**: + +```json +{ + "year": 2025, + "monthly": [ + { + "month": 1, + "temp_mean_avg": 5.2, "temp_max_avg": 10.1, "temp_min_avg": 0.8, + "precip_total": 45.0, "sunshine_total": 98.3, "wind_max": 9.5, + "hot_days": 0, "cold_days": 8, "rainy_days": 12 + }, + ... + ], + "annual": { + "temp_mean_avg": 16.1, "precip_total": 2310.0, "sunshine_total": 1850.5, + "hot_days": 12, "cold_days": 25 + } +} +``` + +- **hot_days**: 最高気温 ≥ 35℃ の日数 +- **cold_days**: 最低気温 < 0℃ の日数 +- **rainy_days**: 降水量 ≥ 1.0mm の日数 + +--- + +### GET `/api/weather/gdd/` +- **認証**: JWT +- **用途**: 播種日〜現在の有効積算温度(Growing Degree Days)を計算 +- **クエリパラメータ**: + - `?start_date=2025-05-15` (必須) — 起算日 + - `?base_temp=10` (省略時=0) — 基準温度 ℃ + - `?end_date=2025-09-30` (省略時=昨日) +- **レスポンス**: + +```json +{ + "start_date": "2025-05-15", + "end_date": "2025-09-30", + "base_temp": 10.0, + "total_gdd": 1342.5, + "records": [ + {"date": "2025-05-15", "temp_mean": 18.2, "daily_gdd": 8.2, "cumulative_gdd": 8.2}, + ... + ] +} +``` + +- **日積算温度** = max(0, 平均気温 - 基準温度) + +--- + +### GET `/api/weather/similarity/?year=2026` +- **認証**: JWT +- **用途**: 今年 1/1〜昨日 の気象パターンと過去年を比較し、類似年 Top3 を返す +- **アルゴリズム**: (平均気温, 総降水量, 総日照時間) の正規化ユークリッド距離 +- **レスポンス**: + +```json +{ + "target_year": 2026, + "comparison_period": "1/1〜2/27", + "target_features": {"mean_temp": 7.3, "total_precip": 185.0, "total_sunshine": 240.5}, + "similar_years": [ + { + "year": 2020, "distance": 0.312, + "features": {...}, + "monthly": [...] + } + ] +} +``` + +--- + +## 管理コマンド + +```bash +# 全期間取得(初回のみ) +docker compose exec backend python manage.py fetch_weather --full + +# 差分取得(最終レコード翌日〜昨日) +docker compose exec backend python manage.py fetch_weather + +# 任意期間 +docker compose exec backend python manage.py fetch_weather --start-date 2025-01-01 --end-date 2025-12-31 +``` + +**仕様**: +- 年単位で Open-Meteo API を呼び出し(API 制限回避のため分割) +- upsert: 既存データを上書き更新 +- `--full`: 2016-01-01 から昨日まで(初回投入用) + +--- + +## Windmill フロー + +| 項目 | 値 | +|---|---| +| パス | `f/weather/weather_sync` | +| スケジュール | `0 0 6 * * *`(毎朝 6:00 Asia/Tokyo) | +| スクリプト | `windmill/u/admin/weather_sync.flow/a.inline_script.py` | +| 状態 | ✅ 本番稼働中(windmill.keinafarm.net) | + +**使用 Windmill Variables**: + +| 変数名 | 内容 | +|---|---| +| `u/admin/KEINASYSTEM_API_KEY` | API キー(メール機能と共用) | +| `u/admin/KEINASYSTEM_API_URL` | `https://keinafarm.net` | + +--- + +## フロントエンド画面 (`/weather`) + +### 年別集計モード(デフォルト) + +- 年セレクタ (2016〜現在) +- **年間サマリーカード**: 平均気温 / 年間降水量 / 年間日照時間 / 猛暑日数・冬日数 +- **グラフタブ**: 月別気温折れ線(最高・平均・最低)、月別降水量棒 + 日照時間折れ線(2軸) +- **月別サマリータブ**: 12ヶ月のテーブル +- **直近14日タブ**: 日次データテーブル(Windmill 同期確認用) + +### 期間指定モード + +- 開始日・終了日の date input + 「表示」ボタン +- **期間集計カード**: 期間の平均気温 / 総降水量 / 総日照時間 / 猛暑日・冬日 +- **グラフタブ**: 日次気温折れ線 + 日次降水量棒+日照折れ線 + - X軸ラベル自動間引き(30日以内→3日おき、3ヶ月→週1、半年→2週、1年超→月1) + - 60日以内はドット表示あり +- **一覧タブ**: 日次データテーブル(スクロール対応) + +**使用ライブラリ**: Recharts 3.7.x(`frontend/package.json` に登録済み) + +--- + +## ファイル索引 + +| ファイル | 役割 | +|---|---| +| `backend/apps/weather/models.py` | WeatherRecord モデル | +| `backend/apps/weather/views.py` | 5つのAPIビュー | +| `backend/apps/weather/urls.py` | URL設定 | +| `backend/apps/weather/serializers.py` | Serializer | +| `backend/apps/weather/admin.py` | 管理画面登録 | +| `backend/apps/weather/migrations/0001_initial.py` | 初回マイグレーション | +| `backend/apps/weather/management/commands/fetch_weather.py` | 管理コマンド | +| `backend/apps/plans/migrations/0004_crop_base_temp.py` | Crop.base_temp 追加 | +| `frontend/src/app/weather/page.tsx` | 気象画面(400行) | +| `windmill/u/admin/weather_sync.flow/a.inline_script.py` | Windmill Python スクリプト | +| `windmill/u/admin/weather_sync.flow/flow.yaml` | Windmill フロー定義 | + +--- + +## 将来計画(Phase 2 以降) + +1. **GDD 到達日予測**: `Crop.base_temp` を使い、播種日から目標GDDに達する日を予測 +2. **類似年ベースの収穫予測**: 類似年の収穫時期を参考に今年の予測を表示 +3. **作付け計画との連携**: 作期ごとの気象サマリーを圃場詳細に表示 +4. **気象アラート**: 猛暑・長雨・強風などの異常気象を検知して通知 + +--- + +## 注意事項 + +- Open-Meteo archive API は**前日まで**のデータしか取得できない(リアルタイム不可) +- `pressure_min` は `surface_pressure_min`(地表気圧)。海面更正気圧とは異なる +- Open-Meteo の `sunshine_duration` は秒単位 → `sunshine_h` = 秒 ÷ 3600 で変換