From 2939487c4f656e9b836c9084d5fb37107cf278ae Mon Sep 17 00:00:00 2001 From: Kenichiro NOGI Date: Sat, 5 Sep 2026 10:57:20 +0900 Subject: [PATCH] =?UTF-8?q?=E5=81=A5=E5=BA=B7=E8=A8=BA=E6=96=AD=E7=AE=A1?= =?UTF-8?q?=E7=90=86LINEWORKS=E9=80=A3=E6=90=BA=E8=A8=AD=E8=A8=88=E3=82=92?= =?UTF-8?q?=E3=83=97=E3=83=AD=E3=82=BB=E3=82=B9=E6=A9=9F=E8=83=BD=E6=B5=81?= =?UTF-8?q?=E7=94=A8=E5=9E=8B=E3=81=AB=E5=85=A8=E9=9D=A2=E6=94=B9=E8=A8=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ヒアリングで判明した実際のフロー(日程通知→了承/変更→受診確認→ 結果受取り)がステータス駆動の対話型であり、単純な順次質問アンケート ではないと判明。LINE WORKS Bot APIに「トークを開いた」検知イベントが 存在しない制約も踏まえ、プッシュ型通知+フォールバック応答方式に変更。 フロー定義用の新規マスタは作らず、プリザンター標準のProcess機能 (現在の状況/変更後の状況/ツールチップ/入力検証タブ)をそのまま 定義source として使う設計に切り替えた。 Co-Authored-By: Claude Sonnet 5 --- ...healthcheck-lineworks-survey-n8n-design.md | 172 +++++++++--------- 1 file changed, 90 insertions(+), 82 deletions(-) diff --git a/NodeSrv/docs/superpowers/specs/2026-09-05-healthcheck-lineworks-survey-n8n-design.md b/NodeSrv/docs/superpowers/specs/2026-09-05-healthcheck-lineworks-survey-n8n-design.md index 0f91b9c4..60ff0761 100644 --- a/NodeSrv/docs/superpowers/specs/2026-09-05-healthcheck-lineworks-survey-n8n-design.md +++ b/NodeSrv/docs/superpowers/specs/2026-09-05-healthcheck-lineworks-survey-n8n-design.md @@ -1,120 +1,128 @@ -# 健康診断管理×LINEWORKSアンケート n8n化 設計書 +# 健康診断管理×LINEWORKS Bot連携 n8n化 設計書 - 作成日: 2026-09-05 -- 対象: プリザンター「健康診断管理」プロジェクト(SiteId 508971)へLINEWORKS Bot経由アンケート機能を実装 -- 位置付け: 既存Express実装(`OldCode/express/modules/lineworksSurvey.js`、仕様書`Pleasanter/LINEWORKSアンケート管理/docs/lineworks-survey-scheme.md`)と同等機能をn8nで新規構築。Expressの流用・移植ではなく作り直し +- 対象: プリザンター「健康診断管理」プロジェクト(SiteId 508971)へLINEWORKS Bot経由の対話型ステータス管理機能を実装 +- 位置付け: 既存Express実装(`OldCode/express/modules/lineworksSurvey.js`、仕様書`Pleasanter/LINEWORKSアンケート管理/docs/lineworks-survey-scheme.md`)とは別物としてn8nで新規構築。単純な順次質問アンケートではなく、**プリザンターのProcess機能をそのままフロー定義として使うステータス駆動型対話ボット** ## 1. 背景・既存Express実装との違い -Express版(ケアセブンプロジェクト向け)は以下の構成だった。 +Express版(ケアセブンプロジェクト向け)は「アンケート開始→設問を順番に送信→全問回答で1レコードcreate」という一方向の順次アンケートだった。今回の健康診断管理版は要件が異なる。 -- 「アンケート実行管理」を独立サイト(484186)として持ち、対象テーブル(例: 車両点検報告484182)へ回答を新規レコードcreateする -- Bot・対象者マスタも専用サイト(484184/484181)を新設 -- セッション状態はExpressプロセスのメモリ(`Map`)で保持 - -今回の健康診断管理版は要件が異なるため、以下の方針で作り直す。 - -- **アンケート実行管理を独立サイトにせず、508971自体に統合**(Process+列追加)。回答は新規レコードcreateではなく、発行元の508971レコード自体へupdateで書き戻す -- **Botマスタは新設せず、既存の「LINEWORKSアンケート管理」プロジェクトのSiteId 484184をそのまま参照** -- **対象者マスタは新設せず、プリザンター標準Usersのメールアドレスをそのまま LINEWORKS の宛先ID(userId)として使う**(LINEWORKS ID=メールアドレスという前提。484181のような変換用マスタは不要) -- **サーバー実装はExpressでなくn8n**。セッション状態はn8nプロセスのメモリではなく、n8n Data Table(新規テーブル `survey_sessions`)で保持する +- 508971は1レコード=1回の健診。フローは「日程通知→了承/変更→受診確認→結果受取り」のようにレコードのStatusを段階的に進める対話であり、設問の連続ではない +- LINE WORKS Bot APIの制約上、**「トークを開いた瞬間」を検知するイベントは存在しない**(コールバックイベントは`message`/`join`/`leave`/`joined`/`left`/`postback`のみ)。そのため「初期表示切替」は、①Statusが変わった瞬間にBotから能動的にメッセージを送る(プッシュ型)、②ユーザーが何か送信したら現在Statusの案内を返す(フォールバック)、の組み合わせで実現する +- アンケート実行管理・Bot・対象者マスタは新設せず、既存資産を流用する(後述) +- **フロー定義(Statusごとの案内文・選択肢・遷移先)を管理する専用マスタは新設しない。508971自体の`SiteSettings.Processes`(プロセス機能)をそのままフロー定義として使う** +- サーバー実装はExpressでなくn8n。会話の待機状態はn8nプロセスのメモリではなく、n8n Data Table(新規`bot_conversation_state`)で保持する n8n環境自体の詳細(URL・API・既存ワークフロー・過去の罠)は`NodeSrv/apps/n8n/docs/n8n-guide.md`参照。以下の設計はこのガイドの制約(コンテナメモリ768MB、Data Table操作の罠、Schedule Trigger運用方針等)を踏まえている。 -## 2. 全体アーキテクチャ +## 2. 前提とした既存資産の流用 -``` -プリザンター(508971 健康診断管理データ本体) - └ Process「アンケート発行」ボタン(flowIdごとに1つ) - │ クライアントスクリプト fetch - ▼ -n8n: W1「健診アンケート開始」(Webhook) - └ resultId取得 → ClassC(Users参照列)からPleasanterUserId解決 - └ POST api/users/get(View:{ApiGetMailAddresses:true})でメールアドレス取得 - → LINEWORKS userIdとしてそのまま使用 - └ 508971自身のColumnsからflowId該当設問を抽出 - └ n8n Data Table「survey_sessions」へセッション行Insert - └ 484184(LINEWORKS Bot)から該当BotId取得 → LINEWORKS Bot APIで第1問送信 - │ - ▼ -LINEWORKS トーク(Bot⇔対象者) - │ 回答 - ▼ -n8n: W2「健診アンケート回答受信」(Webhook, 署名検証) - └ targetId(=メール)でsurvey_sessions検索 → 型検証 → 回答蓄積 - └ 未完了 → 次設問送信 / セッション更新 - └ 完了 → 508971へupdate(Hashネスト)→ アンケート進捗列更新 → セッション削除 - -n8n: W3「健診アンケートタイムアウト監視」(Schedule Trigger、数分毎) - └ survey_sessions走査 → 期限切れセッションに終了通知 → 削除 -``` - -## 3. プリザンター側(508971)変更点 - -| 追加項目 | 内容 | +| 用途 | 流用元 | |---|---| -| 設問対象列 | アンケートで使う列の`ExtendedControlCss`に`survey survey-`トークンを付与。1列が複数flowに属してもよい(スペース区切りで複数トークン) | -| アンケート進捗列(新規、列名は実装時に採番) | アンケートの発行・回答状況を管理する専用列。既存業務Status(100申込中〜910対象外)とは別軸で持つ | -| Process「アンケート発行」 | flowIdごとに1つずつ追加。`OnClick`でn8n WebhookのW1へPOST(`resultId`・`flowId`を送信) | -| ClassC(Users参照、既存) | そのまま流用。ここからPleasanterUserIdを取得し、n8n側でメールアドレスを解決する | +| Bot | 既存「LINEWORKSアンケート管理」プロジェクトのSiteId 484184(LINEWORKS Bot管理)をそのまま参照。健康診断管理側にBotマスタは新設しない | +| 対象者解決 | プリザンター標準Usersのメールアドレスを、そのままLINEWORKS宛先ID(userId)として使う。LINE WORKS側からの受信時も`source.userId`=メールアドレスという前提で扱う(専用マッピングマスタは不要) | +| 対象レコード特定 | LINEWORKSから届いたメッセージの送信者メール→508971の中で、そのユーザーが紐づくレコードのうち**未完了(Status 900/910以外)の最新レコード**を対象とする。複数該当時の自動判定は行わず、実装上は「複数ヒット」を異常系として扱う | -新規アンケート(flowId)を追加する際の運用手順: -1. 該当列の`ExtendedControlCss`に`survey-<新flowId>`トークンを追記(既存列流用 or 新規列追加はflow内容次第で都度判断) -2. 508971にProcess「◯◯アンケート発行」を追加、`flowId`を固定値でn8n Webhookへ渡すよう設定 -3. n8n側の設問抽出ロジックは`ExtendedControlCss`のトークンでflowIdを判定するため、n8nワークフロー自体の改修は不要(列追加・Process追加のみで新flowを増やせる設計) +## 3. 全体アーキテクチャ -アンケート進捗列の具体的な値・遷移(業務Statusとの整合を取るか等)は、実際のアンケートフロー内容を設計する際に個別に確定する。本設計書では「既存業務Statusとは独立した列で管理する」という方針のみを定める。 +``` +[プリザンター508971] Statusが変わる契機は2種類 + (a) 担当者がProcessボタンを押す(例:①日程通知発行、日程確定時) + (b) Bot対話の結果としてProcessが実行される(例:②→③) -## 4. n8n側詳細 +(a)の場合 + ▼ +n8n: WP「Statusプッシュ通知」(Webhook, 508971クライアントスクリプトから起動) + └ resultId・processIdを受け取りレコード取得 + └ 該当Processの案内文(ツールチップ欄)をレコード値で置換 + └ 対象者メール解決 → LINEWORKS Bot APIで案内+選択肢を送信 + └ n8n Data Table「bot_conversation_state」に提示内容を記録 + ▼ +LINEWORKS トーク + │ ユーザー返信(ボタン押下/テキスト/ファイル) + ▼ +n8n: WA「LINEWORKS応答受信」(Webhook、唯一の受信口、署名検証) + └ 送信者メール解決 → 508971の対象レコード特定 + └ bot_conversation_stateの待機状態を見て回答を処理 + └ 該当Processを`ProcessId`指定でapi/items/updateへ実行 → Status遷移 + └ 遷移後の新Statusに紐づく次のProcess群を取得し、次の案内を送信(WPと共通ロジック) +``` -### Data Table「survey_sessions」(新規作成) +## 4. フロー定義: 508971のProcess機能をそのまま流用 + +新規マスタサイト・新規テーブルは作らない。プリザンター標準の「プロセス」設定画面(画面種別・現在の状況・変更後の状況・表示名・ツールチップ・入力検証タブ等)を、Bot対話の定義としてそのまま使う。 + +| Processの項目 | Bot連携での役割 | +|---|---| +| 現在の状況(CurrentStatus)/変更後の状況(ChangedStatus) | 既存のStatus遷移定義をそのまま使う | +| 表示名(DisplayName) | Botが提示する選択肢ボタンのラベル | +| ツールチップ | Bot案内文言。`{検査機関}` `{日程}`のようなプレースホルダーを書いておくと、n8nがレコードの実際の値に置換してから送信する | +| 入力検証タブの「項目」 | このProcess実行に追加入力を伴うかの判定に流用。列名プレフィックスで種別を判定する(`Date*`→日付入力を1往復挟む、`Attachments*`→ファイル受信を1往復挟む、項目なし→即実行) | +| ProcessId | n8nが`POST /api/items/{resultId}/update`に`ProcessId`パラメータとして渡して実行する。公式マニュアル記載の通り、APIからのプロセス実行では入力検証(プリザンター標準の検証機能)は適用されない点に注意 | + +新フローを追加する際の運用手順: +1. 508971のProcessを1つ追加(現在の状況・変更後の状況・表示名・ツールチップ文言を設定) +2. 追加入力が必要なら、入力検証タブの「項目」に対象列(`Date*`または`Attachments*`)を登録 +3. n8nワークフロー(WP/WA)は無改修。現在Statusに紐づくProcess一覧を都度`getsite`から動的に取得する設計のため、Process追加だけで新フローを反映できる + +## 5. n8n側詳細 + +### Data Table「bot_conversation_state」(新規) | 列 | 内容 | |---|---| -| sessionId | UUID | | resultId | 508971のResultId | -| flowId | アンケート種別識別子 | -| botId | 484184から取得したBotId | | targetEmail | 対象者メールアドレス(LINEWORKS userId) | -| currentIndex | 現在の設問番号 | -| answersJson | ここまでの回答(JSON文字列) | -| expiresAt | 現在設問のタイムアウト時刻 | -| startedAt | 開始日時(無応答タイムアウト判定用) | -| firstAnswerAt | 初回応答有無判定用 | +| currentStatus | 直近提示時点のStatus値 | +| pendingProcesses | 直近提示した選択肢一覧(`[{processId, label, validateColumn}]`のJSON文字列) | +| awaitInput | `none`(選択肢待ち)/`date`(日付入力待ち)/`file`(ファイル受信待ち) | +| awaitProcessId | 追加入力完了後に実行すべきProcessId(`awaitInput`が`date`/`file`の間のみ使用) | +| awaitColumn | 追加入力先の列名(例: `Date001`) | +| updatedAt | 最終更新日時 | -n8n-guide.md 7-1(Clear出力の握り潰し)・7-2(複数行が後続へそのまま渡ると行数分繰り返し実行される)の罠を踏まえ、1セッション=1行の読み書きに限定し、複数セッションを一括で展開・集約する処理は入れない。 +n8n-guide.md 7-1(Clear出力の握り潰し)・7-2(複数行が後続へそのまま渡ると行数分繰り返し実行される)の罠を踏まえ、1レコード=1行の読み書きに限定し、複数行を横断する集約処理は入れない。セッションタイムアウトの概念は持たない(ユーザーの都合のいいタイミングで返信されればよい性質のフローのため、待機状態は無期限に保持する)。 ### ワークフロー構成 -- **W1 開始**: Webhookトリガー(`X-API-Key`ヘッダー認証、508971のクライアントスクリプト専用) -- **W2 回答受信**: Webhookトリガー(LINEWORKS本体からの直接コールバック、`x-works-signature`をHMAC-SHA256検証。Express版`verifyWebhookSignature`と同等ロジック) -- **W3 タイムアウト監視**: Schedule Trigger(数分間隔)。n8n-guide.md 9章では「Schedule Trigger等の自動化は今回のスコープ外」としているが、**本機能ではセッションタイムアウト監視のために自動実行を解禁する**(今回の設計で追加する例外) +- **WP Statusプッシュ通知**: Webhookトリガー(`X-API-Key`ヘッダー認証、508971のクライアントスクリプト専用)。担当者がProcessボタンを押した時に起動 +- **WA LINEWORKS応答受信**: Webhookトリガー(LINE WORKS本体からの直接コールバック、`x-works-signature`をHMAC-SHA256検証)。唯一の受信口 +- タイムアウト監視ワークフローは持たない(3節参照) + +### WAの処理詳細 + +1. 署名検証 → 送信内容(テキスト/ボタン応答/ファイル)を判定 +2. 送信者メール解決 → 508971の対象レコード(未完了の最新1件)を特定 +3. `bot_conversation_state`から該当resultIdの待機状態を取得 +4. **待機状態なし、または`awaitInput=none`で回答が選択肢と不一致** → 現在Statusに紐づくProcess群を`getsite`から再取得し、案内を再送(フォールバック) +5. **`awaitInput=none`で回答が選択肢(DisplayName)と一致**: + - 対象列なし → 即座に`ProcessId`実行 → 新Statusの次Process群を取得 → 次の案内を送信 + - 対象列が`Date*` → `awaitInput=date`/`awaitProcessId`/`awaitColumn`を記録し、「日付を入力してください」を追加送信(Process実行は保留) + - 対象列が`Attachments*` → 同様に`awaitInput=file`で保留し、ファイル送信を促す +6. **`awaitInput=date`** → 受信テキストを日付として検証(Express版の和暦・月日省略対応ロジックを踏襲)→ `awaitColumn`をupdate → `awaitProcessId`を`ProcessId`実行 → 新Status提示 → 待機状態を`none`へ戻す +7. **`awaitInput=file`** → 受信がファイルでなければ再送要求。ファイルならLINEWORKS Bot APIでダウンロード → Pleasanter添付ファイルAPIで`awaitColumn`へアップロード → `awaitProcessId`を`ProcessId`実行 → 新Status提示 → 待機状態を`none`へ戻す ### 認証まわり -- LINEWORKS Bot APIメッセージ送信: 既存Credential「LINEWORKS Bot Private Key (v4)」(`Hw0qlEaGfLPnQWp1`)が流用できるか、実装時にBotIdとの対応関係を確認する -- 対象者メール解決: `POST api/users/get`(`View:{ApiGetMailAddresses:true}`、Offset+TotalCountページング)。org-master-sync③で実績のある実装パターンをそのまま使う - -## 5. 設問の型・検証ルール - -Express版(選択式/数値/自由記述の3種、日付は和暦・月日省略に対応)と同等の検証ロジックをn8n上(Codeノード)に再実装する。列名プレフィックスによる型判定(`Class*`→選択式 or 短文、`Num*`→数値、`Date*`→日付、`Description*`→長文)もExpress版を踏襲する。 +- LINEWORKS Bot APIメッセージ送信: 既存Credential「LINEWORKS Bot Private Key (v4)」(`Hw0qlEaGfLPnQWp1`)が流用できるか、BotIdとの対応関係を実装時に確認する +- 対象者メール解決: `POST api/users/get`(`View:{ApiGetMailAddresses:true}`)。org-master-sync③で実績のある実装パターンを流用 ## 6. エラーハンドリング・異常系 -- キャンセルキーワード(取消/キャンセル/終了等)受信 → セッション削除+508971のアンケート進捗列を「キャンセル」相当へ -- 必須設問での無回答・スキップ要求 → 再送(同じ設問を再送信) -- 型検証失敗(数値・日付フォーマット不正)→ エラーメッセージ+再送 -- セッション未検出(期限切れ後の回答等)→ 「アンケートが開始されていません」を返信 +- 対象レコードが複数ヒット(同一ユーザーの未完了レコードが2件以上)→ 自動判定せず、担当者確認が必要な異常系として扱う(Bot応答は保留し、通知等は今後の実装計画で検討) +- 選択肢に一致しない回答 → 選択肢を再提示(4節のフォールバックと同じ経路) +- 日付形式不正/ファイル未送信 → エラーメッセージ+再送、待機状態は維持 - LINEWORKS送信失敗・508971 update失敗 → n8n Execution History(Postgres保存)に残す。追加のログ実装はしない ## 7. 導入・検証方針 - n8n運用ルール(n8n-guide.md 9章)に従い、ワークフローの構築・編集自体は確認不要。**Webhook実行によるプリザンター書き込み・LINEWORKS送信を伴うテストは都度事前確認** -- 初回検証は1flow・1件のみで実施し、疎通確認後に複数flow展開へ進める +- 初回検証は1Process・1件のみで実施し、疎通確認後にフロー全体(①〜③)の通し検証に進める - 508971は本番の健診データそのものなので、検証は既存レコードを壊さない捨てレコードを用意して行う -## 8. 未確定事項(今後のflow設計時に個別確定) +## 8. 未確定事項(実装時に個別確定) -- アンケートflowの具体的な設問内容・対象列・flowId命名は本設計書のスコープ外。flow追加のたびに3章の運用手順に従って個別設計する -- アンケート進捗列の具体的な値・遷移 -- LINEWORKS Bot Private Key CredentialとBotIdの対応関係の実機確認 +- 具体的なProcess定義(①日程通知〜③検査結果受取りの各Process内容、Status値の追加・修正)は508971のStatus設計がまだ未完成のため、実装着手時に個別に設計する +- LINEWORKS Bot Private Key CredentialとBotId(484184側)の対応関係の実機確認 +- LINEWORKS Bot APIでのファイル受信(ダウンロードURL取得)とPleasanter添付ファイルAPIへのアップロードの具体的な実装方法 +- 今後フロー内容の詳細が追加判明する前提のため、4節の枠組み(Process流用)の汎用性を保ったまま個別Processを増やしていく