docs: Windmill通知ワークフロー マスタードキュメント追加
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
458
docs/shiraou/20_マスタードキュメント_Windmill通知ワークフロー編.md
Normal file
458
docs/shiraou/20_マスタードキュメント_Windmill通知ワークフロー編.md
Normal file
@@ -0,0 +1,458 @@
|
||||
# マスタードキュメント - Windmill通知ワークフロー編
|
||||
|
||||
> **最終更新**: 2026-02-21
|
||||
> **対象システム**: windmill.keinafarm.net(ワークスペース: admins)
|
||||
> **目的**: このドキュメントだけでWindmill通知ワークフローの全容を把握できること
|
||||
|
||||
---
|
||||
|
||||
## 目次
|
||||
|
||||
1. [機能概要](#1-機能概要)
|
||||
2. [フロー設計](#2-フロー設計)
|
||||
3. [変更履歴取得API仕様](#3-変更履歴取得api仕様)
|
||||
4. [LINE通知仕様](#4-line通知仕様)
|
||||
5. [Windmill設定仕様](#5-windmill設定仕様)
|
||||
6. [状態管理仕様](#6-状態管理仕様)
|
||||
7. [設計判断と制約](#7-設計判断と制約)
|
||||
8. [運用手順](#8-運用手順)
|
||||
9. [ソースファイル索引](#9-ソースファイル索引)
|
||||
10. [更新履歴](#更新履歴)
|
||||
|
||||
---
|
||||
|
||||
## 1. 機能概要
|
||||
|
||||
### 目的
|
||||
|
||||
`shiraou.keinafarm.net`(白皇集落営農組合 統合システム)で発生した予約・実績の変更を、LINE Messaging API 経由で管理者に通知する。
|
||||
|
||||
### ユーザーフロー
|
||||
|
||||
```
|
||||
統合システム上で予約・実績の変更が発生
|
||||
└→ Windmill が5分毎にポーリング
|
||||
└→ 変更があればLINEにプッシュ通知
|
||||
└→ 管理者がLINEで変更内容を確認
|
||||
```
|
||||
|
||||
### 通知される操作一覧
|
||||
|
||||
| 区分 | 操作 | 説明 |
|
||||
|------|------|------|
|
||||
| 予約 | `create` | 予約が作成された |
|
||||
| 予約 | `update` | 予約の日時・機械が変更された |
|
||||
| 予約 | `cancel` | 予約がキャンセルされた |
|
||||
| 実績 | `create` | 実績が登録された |
|
||||
| 実績 | `update` | 実績が修正された |
|
||||
| 実績 | `delete` | 実績が削除された |
|
||||
|
||||
---
|
||||
|
||||
## 2. フロー設計
|
||||
|
||||
### Windmillフロー情報
|
||||
|
||||
| 項目 | 値 |
|
||||
|------|-----|
|
||||
| パス | `f/shiraou/shiraou_notification` |
|
||||
| 概要 | 白皇集落営農 変更通知 |
|
||||
| ステップ数 | 1(単一Pythonスクリプト) |
|
||||
| スケジュール | `0 */5 * * * *`(5分毎、JST) |
|
||||
| スケジュールパス | `f/shiraou/shiraou_notification_every_5min` |
|
||||
|
||||
### 実行フロー(擬似コード)
|
||||
|
||||
```python
|
||||
# Step 1: シークレット・前回実行時刻を取得
|
||||
api_key = get_variable("u/admin/NOTIFICATION_API_KEY")
|
||||
line_token = get_variable("u/admin/LINE_CHANNEL_ACCESS_TOKEN")
|
||||
line_to = get_variable("u/admin/LINE_TO")
|
||||
last_checked = get_variable("u/admin/SHIRAOU_LAST_CHECKED_AT") # 空なら初回
|
||||
|
||||
since = last_checked or (now() - 10分)
|
||||
|
||||
# Step 2: 変更履歴を取得
|
||||
response = GET "https://shiraou.keinafarm.net/reservations/api/changes/?since={since}"
|
||||
headers: { "X-API-Key": api_key }
|
||||
|
||||
# Step 3: 変更があればLINE通知
|
||||
if response.reservations or response.usages:
|
||||
message = format_message(response)
|
||||
POST "https://api.line.me/v2/bot/message/push"
|
||||
body: { "to": line_to, "messages": [{"type": "text", "text": message}] }
|
||||
|
||||
# Step 4: 前回実行時刻を更新(正常完了時のみ)
|
||||
set_variable("u/admin/SHIRAOU_LAST_CHECKED_AT", response.checked_at)
|
||||
```
|
||||
|
||||
### エラー時の挙動
|
||||
|
||||
- API呼び出し失敗、LINE送信失敗のいずれでも例外が発生
|
||||
- 例外が発生した場合、`SHIRAOU_LAST_CHECKED_AT` は更新されない
|
||||
- 次回実行時に同じ `since` で再試行される(変更の取り漏れ防止)
|
||||
|
||||
---
|
||||
|
||||
## 3. 変更履歴取得API仕様
|
||||
|
||||
### エンドポイント
|
||||
|
||||
```
|
||||
GET https://shiraou.keinafarm.net/reservations/api/changes/
|
||||
```
|
||||
|
||||
### 認証
|
||||
|
||||
```
|
||||
X-API-Key: <NOTIFICATION_API_KEY>
|
||||
```
|
||||
|
||||
APIキーが不正な場合は `401 Unauthorized` が返る。
|
||||
|
||||
### クエリパラメータ
|
||||
|
||||
| パラメータ | 型 | 必須 | 説明 |
|
||||
|-----------|-----|------|------|
|
||||
| `since` | ISO8601文字列 | 必須 | この日時以降の変更を取得する |
|
||||
|
||||
**`since` の形式例**:
|
||||
- `2026-02-21T10:00:00+09:00`(タイムゾーン付き、推奨)
|
||||
- `2026-02-21T10:00:00`(ナイーブ、JSTとして扱われる)
|
||||
|
||||
### レスポンス(200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"checked_at": "2026-02-21T12:00:00+09:00",
|
||||
"since": "2026-02-21T10:00:00+09:00",
|
||||
"reservations": [
|
||||
{
|
||||
"operation": "create",
|
||||
"reservation_id": 123,
|
||||
"user_name": "田中太郎",
|
||||
"machine_name": "トラクター",
|
||||
"start_at": "2026-02-25T09:00:00+09:00",
|
||||
"end_at": "2026-02-25T12:00:00+09:00",
|
||||
"operated_at": "2026-02-21T11:30:00+09:00",
|
||||
"operator_name": "田中太郎",
|
||||
"reason": ""
|
||||
}
|
||||
],
|
||||
"usages": [
|
||||
{
|
||||
"operation": "update",
|
||||
"usage_id": 456,
|
||||
"user_name": "山田次郎",
|
||||
"machine_name": "コンバイン",
|
||||
"amount": 4.0,
|
||||
"unit": "時間",
|
||||
"start_at": "2026-02-20T08:00:00+09:00",
|
||||
"end_at": "2026-02-20T12:00:00+09:00",
|
||||
"operated_at": "2026-02-21T11:55:00+09:00",
|
||||
"operator_name": "管理者A",
|
||||
"reason": "記録ミスのため修正"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 変更なし時のレスポンス
|
||||
|
||||
```json
|
||||
{
|
||||
"checked_at": "2026-02-21T12:05:00+09:00",
|
||||
"since": "2026-02-21T12:00:00+09:00",
|
||||
"reservations": [],
|
||||
"usages": []
|
||||
}
|
||||
```
|
||||
|
||||
### エラーレスポンス
|
||||
|
||||
| ステータス | 原因 |
|
||||
|-----------|------|
|
||||
| `401 Unauthorized` | APIキーが不正または未設定 |
|
||||
| `400 Bad Request` | `since` パラメータが欠落または不正な日時形式 |
|
||||
|
||||
---
|
||||
|
||||
## 4. LINE通知仕様
|
||||
|
||||
### 使用API
|
||||
|
||||
LINE Messaging API - Push Message
|
||||
|
||||
```
|
||||
POST https://api.line.me/v2/bot/message/push
|
||||
Authorization: Bearer <LINE_CHANNEL_ACCESS_TOKEN>
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
### リクエストボディ
|
||||
|
||||
```json
|
||||
{
|
||||
"to": "<LINE_TO>",
|
||||
"messages": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<フォーマット済みメッセージ>"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### メッセージフォーマット
|
||||
|
||||
```
|
||||
📋 営農システム 変更通知
|
||||
|
||||
🟢 予約作成
|
||||
機械: トラクター
|
||||
利用者: 田中太郎
|
||||
日時: 2026-02-25 09:00 〜 2026-02-25 12:00
|
||||
|
||||
🔴 予約キャンセル
|
||||
機械: 田植機
|
||||
利用者: 佐藤花子
|
||||
日時: 2026-02-22 08:00 〜 2026-02-22 17:00
|
||||
|
||||
🔵 実績修正
|
||||
機械: コンバイン
|
||||
利用者: 山田次郎
|
||||
利用量: 4.0時間
|
||||
日: 2026-02-20
|
||||
理由: 記録ミスのため修正
|
||||
```
|
||||
|
||||
### アイコン規則
|
||||
|
||||
| アイコン | 意味 |
|
||||
|---------|------|
|
||||
| 🟢 | 作成(create / 予約作成 / 実績登録) |
|
||||
| 🔵 | 変更(update / 予約変更 / 実績修正) |
|
||||
| 🔴 | 削除・キャンセル(cancel / delete) |
|
||||
|
||||
### 通知先の種別
|
||||
|
||||
`LINE_TO` にはユーザーIDまたはグループIDを設定する。
|
||||
|
||||
| 種別 | ID形式 |
|
||||
|------|-------|
|
||||
| ユーザー | `U` で始まる文字列 |
|
||||
| グループ | `C` で始まる文字列 |
|
||||
|
||||
---
|
||||
|
||||
## 5. Windmill設定仕様
|
||||
|
||||
### Windmill Variables(シークレット)
|
||||
|
||||
以下の変数を Windmill UI(Variables ページ)で作成・管理する。
|
||||
|
||||
| 変数パス | Secret | 説明 | 取得元 |
|
||||
|---------|--------|------|-------|
|
||||
| `u/admin/NOTIFICATION_API_KEY` | ✅ | shiraou.keinafarm.net のAPIキー | Djangoサーバー側 `NOTIFICATION_API_KEY` 環境変数と同一値 |
|
||||
| `u/admin/LINE_CHANNEL_ACCESS_TOKEN` | ✅ | LINE Messaging API チャネルアクセストークン | LINE Developers Console |
|
||||
| `u/admin/LINE_TO` | ✅ | 通知先のLINEユーザーIDまたはグループID | LINE webhook / profile API |
|
||||
| `u/admin/SHIRAOU_LAST_CHECKED_AT` | ❌ | 前回確認時刻(ワークフローが自動更新) | ワークフローが自動管理(初期値: 空文字) |
|
||||
|
||||
### Django側の設定(shiraou.keinafarm.net)
|
||||
|
||||
`docker-compose.yml` に以下の環境変数を追加:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
- NOTIFICATION_API_KEY=<NOTIFICATION_API_KEYと同一の値>
|
||||
```
|
||||
|
||||
APIキー生成コマンド:
|
||||
```bash
|
||||
openssl rand -hex 32
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 状態管理仕様
|
||||
|
||||
### 状態変数: `SHIRAOU_LAST_CHECKED_AT`
|
||||
|
||||
| 項目 | 内容 |
|
||||
|------|------|
|
||||
| 格納場所 | Windmill Variable `u/admin/SHIRAOU_LAST_CHECKED_AT` |
|
||||
| 型 | ISO8601文字列(例: `2026-02-21T15:30:00+09:00`) |
|
||||
| 初期値 | 空文字(初回実行時は `現在時刻 - 10分` を使用) |
|
||||
| 更新タイミング | フロー正常完了時のみ、APIレスポンスの `checked_at` を保存 |
|
||||
| 参照タイミング | フロー実行開始時、`since` パラメータとして使用 |
|
||||
|
||||
### 重複通知防止の仕組み
|
||||
|
||||
```
|
||||
実行1: since=T0, checked_at=T1 → LAST_CHECKED_AT = T1
|
||||
実行2: since=T1, checked_at=T2 → T1以降の変更のみ取得
|
||||
```
|
||||
|
||||
- `since` に `checked_at`(APIが確認した時刻)を使うことで、変更の取りこぼしが発生しない
|
||||
- `since`(リクエストに渡した時刻)ではなく `checked_at`(サーバーが確認した時刻)を保存するのがポイント
|
||||
|
||||
### 旧実装との違い(トラブルシュート記録)
|
||||
|
||||
| | 旧実装 | 現実装 |
|
||||
|---|--------|--------|
|
||||
| 状態保存方法 | `wmill.get_state()` / `set_state()` | `wmill.get_variable()` / `set_variable()` |
|
||||
| 問題 | フローのインラインスクリプトでは実行をまたいで保存されない | - |
|
||||
| 症状 | 毎回 `since = 現在 - 10分` になり、毎回通知が飛ぶ | 正常動作 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 設計判断と制約
|
||||
|
||||
### 絶対に変えてはいけない制約
|
||||
|
||||
1. **`SHIRAOU_LAST_CHECKED_AT` には `checked_at` を保存すること**(`since` を保存しない)
|
||||
- `checked_at`: APIサーバーが「この時刻まで確認した」という保証付きの時刻
|
||||
- 同じ変更が2度通知されることを防ぐ
|
||||
|
||||
2. **状態更新は正常完了後のみ行うこと**
|
||||
- API呼び出し失敗・LINE送信失敗時は `SHIRAOU_LAST_CHECKED_AT` を更新しない
|
||||
- 次回実行で同じ範囲を再取得し、通知の取り漏れを防ぐ
|
||||
|
||||
3. **`wmill.get_state()` は使用しないこと**
|
||||
- Windmillのインラインフロースクリプトでは実行をまたいで保存されない
|
||||
- 状態管理は必ず Windmill Variable を使うこと
|
||||
|
||||
### 設計判断
|
||||
|
||||
| 判断 | 理由 |
|
||||
|------|------|
|
||||
| 単一ステップフロー | 状態管理を1か所に集約するため。`get_state()`/`set_state()` のスコープ問題を回避 |
|
||||
| SSL検証スキップ | shiraou.keinafarm.net が自己署名証明書の可能性があるため |
|
||||
| タイムアウト 30秒 | 農業用途で多少の応答遅延を許容しつつ、無限待機を防ぐ |
|
||||
| 5分ポーリング間隔 | 農業機械の予約用途では数分の遅延は許容範囲。リアルタイム不要 |
|
||||
|
||||
---
|
||||
|
||||
## 8. 運用手順
|
||||
|
||||
### フローを手動実行
|
||||
|
||||
```bash
|
||||
curl -sk -X POST \
|
||||
-H "Authorization: Bearer qLJ3VPZ61kTDiIwaUPUu1dXszGrsN1Dh" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{}' \
|
||||
"https://windmill.keinafarm.net/api/w/admins/jobs/run/f/f/shiraou/shiraou_notification"
|
||||
```
|
||||
|
||||
### 動作確認(curlで直接API呼び出し)
|
||||
|
||||
```bash
|
||||
# 変更なし確認
|
||||
curl -H "X-API-Key: <キー>" \
|
||||
"https://shiraou.keinafarm.net/reservations/api/changes/?since=2026-02-21T11:59:00%2B09:00"
|
||||
|
||||
# 広い範囲で変更取得(初期確認用)
|
||||
curl -H "X-API-Key: <キー>" \
|
||||
"https://shiraou.keinafarm.net/reservations/api/changes/?since=2026-01-01T00:00:00"
|
||||
```
|
||||
|
||||
### フローの更新デプロイ手順
|
||||
|
||||
```bash
|
||||
cd /path/to/windmill_workflow
|
||||
|
||||
# 1. flows/shiraou_notification.flow.json を編集
|
||||
|
||||
# 2. 既存フローを削除して再作成(PUTは405のため)
|
||||
curl -sk -X DELETE \
|
||||
-H "Authorization: Bearer qLJ3VPZ61kTDiIwaUPUu1dXszGrsN1Dh" \
|
||||
"https://windmill.keinafarm.net/api/w/admins/flows/delete/f/shiraou/shiraou_notification"
|
||||
|
||||
curl -sk -X POST \
|
||||
-H "Authorization: Bearer qLJ3VPZ61kTDiIwaUPUu1dXszGrsN1Dh" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @flows/shiraou_notification.flow.json \
|
||||
"https://windmill.keinafarm.net/api/w/admins/flows/create"
|
||||
|
||||
# 3. スケジュールは再作成不要(フローの削除・再作成でも維持される)
|
||||
```
|
||||
|
||||
### APIキーローテーション手順
|
||||
|
||||
1. Djangoサーバー側で新しいキーを生成: `openssl rand -hex 32`
|
||||
2. `docker-compose.yml` の `NOTIFICATION_API_KEY` を更新してデプロイ
|
||||
3. Windmill UI で `u/admin/NOTIFICATION_API_KEY` の値を同じ新しいキーに更新
|
||||
4. フローを手動実行して動作確認
|
||||
|
||||
### 過去のジョブ結果確認
|
||||
|
||||
```bash
|
||||
curl -sk -H "Authorization: Bearer qLJ3VPZ61kTDiIwaUPUu1dXszGrsN1Dh" \
|
||||
"https://windmill.keinafarm.net/api/w/admins/jobs/list?per_page=10&script_path_exact=f/shiraou/shiraou_notification&is_flow=true"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. ソースファイル索引
|
||||
|
||||
### フロー定義
|
||||
|
||||
| ファイル | 説明 |
|
||||
|---------|------|
|
||||
| [flows/shiraou_notification.flow.json](../../flows/shiraou_notification.flow.json) | フロー本体。単一Pythonステップでポーリング・通知・状態更新を実行 |
|
||||
|
||||
**フロー構造**:
|
||||
```json
|
||||
{
|
||||
"path": "f/shiraou/shiraou_notification",
|
||||
"value": {
|
||||
"modules": [
|
||||
{
|
||||
"id": "a",
|
||||
"value": {
|
||||
"type": "rawscript",
|
||||
"language": "python3",
|
||||
"content": "..."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ヘルパースクリプト
|
||||
|
||||
| ファイル | 説明 |
|
||||
|---------|------|
|
||||
| [wm-api.sh](../../wm-api.sh) | Windmill REST API操作ヘルパー。フロー作成・スケジュール管理に使用 |
|
||||
|
||||
**主要コマンド**:
|
||||
```
|
||||
create-flow <file> JSONファイルからフローを作成
|
||||
create-schedule <file> JSONファイルからスケジュールを作成
|
||||
flows フロー一覧取得
|
||||
schedules スケジュール一覧取得
|
||||
```
|
||||
|
||||
### ドキュメント
|
||||
|
||||
| ファイル | 説明 |
|
||||
|---------|------|
|
||||
| [docs/shiraou/19_windmill_通知ワークフロー連携仕様.md](19_windmill_通知ワークフロー連携仕様.md) | 仕様書。API仕様・メッセージフォーマットの原典 |
|
||||
| [docs/shiraou/20_マスタードキュメント_Windmill通知ワークフロー編.md](20_マスタードキュメント_Windmill通知ワークフロー編.md) | 本ドキュメント |
|
||||
|
||||
### エージェントワークフロー
|
||||
|
||||
| ファイル | 説明 |
|
||||
|---------|------|
|
||||
| [.agent/workflows/windmill-push.md](../../.agent/workflows/windmill-push.md) | Windmillへのpush手順。wmill CLIの制限とAPI代替の経緯を記録 |
|
||||
| [.agent/workflows/windmill-new-script.md](../../.agent/workflows/windmill-new-script.md) | 新規スクリプト作成手順 |
|
||||
|
||||
---
|
||||
|
||||
## 更新履歴
|
||||
|
||||
| 日付 | 変更内容 |
|
||||
|------|---------|
|
||||
| 2026-02-21 | 初版作成。フロー登録・スケジュール設定・状態管理バグ修正を含む |
|
||||
Reference in New Issue
Block a user