power-automate · git:20260907.7f55761 · 2026-09-07 · sha256 968c442d1294b990
power-automate git:20260907.7f55761A
Immutable. This exact content is served forever at /api/v1/blob/968c442d1294b990.
---
name: power-automate
description: "Power Automate クラウドフローを Flow agent MCP SERVER(FlowAgent)で開発することを優先する。MCP が使えない場合は Dataverse Web API(workflow テーブル)でソリューション対応で作成・デプロイする。接続参照パターンで API 有効化を100%成功させる。"
category: automation
triggers:
- "Power Automate"
- "フロー作成"
- "クラウドフロー"
- "FlowAgent"
- "Flow agent MCP"
- "MCP SERVER"
- "接続参照"
- "Connection Reference"
- "workflow"
- "トリガー"
- "アクション"
- "フローデプロイ"
- "フロー有効化"
- "メール通知"
---
# Power Automate クラウドフロー構築スキル
クラウドフロー開発は **Flow agent MCP SERVER(FlowAgent)を第一選択**とする。
MCP が利用できない環境では Dataverse Web API(workflow テーブル)経由のフォールバックを使う。
## 推奨: Flow agent MCP SERVER を使う(第一選択)
**FlowAgent MCP SERVER** を使うと、VS Code の GitHub Copilot Chat(エージェントモード)からフローを自然言語で構築・編集・デバッグできる。
| 比較項目 | Flow agent MCP(推奨) | Dataverse Web API(フォールバック) |
|---|---|---|
| フロー作成 | 自然言語で指示するだけ | Python スクリプトを手書き |
| 編集 | アクション単位のサージカル編集 | 定義 JSON を全置換 |
| デバッグ | 失敗ランを自律診断 | ログを手動確認 |
| 接続解決 | 自動検索・自動紐づけ | PowerApps API + 手動確認 |
| セットアップ | スクリプト 1 本で完結 | Python 環境 + 複数スコープのトークン |
> ★ FlowAgent MCP サーバー本体(`server/mcp.mjs`)は Claude Code / GitHub Copilot CLI 用の
> プラグインマーケットプレイス(`microsoft/power-platform-skills`)で配布されているが、
> **VS Code の GitHub Copilot Chat は `/plugin marketplace add` コマンドや Claude 形式の
> `.mcp.json`(`mcpServers` キー)を解釈できない**。VS Code は独自の MCP クライアントを持ち、
> ワークスペース直下の `.vscode/mcp.json`(`servers` キー + `type: "stdio"`)を読む。
> そのため本スキルでは `microsoft/power-platform-skills` リポジトリを git スパースチェックアウトで
> 直接取得し、VS Code 形式で登録する(プラグインマーケットプレイスは経由しない)。
### 1. 前提
- Node.js 20+(FlowAgent v3.0.0 以降は MCP SDK v2 のため Node.js 18 では起動できない)
- git(`microsoft/power-platform-skills` の `plugins/power-automate` を取得するために使用)
- Azure CLI(`az login` — MCP サーバー自身の認証に必要。`auth_helper.py` とは別の資格情報ストア)
### 2. 認証 + .vscode/mcp.json 生成(auth_helper を使用)
`.env` に `DATAVERSE_URL` / `SOLUTION_NAME` を設定してからスクリプトを実行する。
スクリプトが行うこと:
| 処理 | 内容 |
|---|---|
| Node.js 確認 | 20+ でなければ中断 |
| az login 確認 | `az account list` で対象テナントの既存キャッシュを確認 → あれば `az account set` のみ(対話不要)。無い場合のみ案内を表示 |
| auth_helper 認証 | Dataverse / Flow API トークンを取得・キャッシュ(Python スクリプト用) |
| プラグイン取得 | `microsoft/power-platform-skills` を git スパースチェックアウトで `~/.power-platform-skills` に取得(マシン全体で共有・自動更新) |
| .vscode/mcp.json 生成 | 既存エントリを保持しつつ FlowAgent を追記(VS Code 形式) |
```bash
python .github/skills/power-automate/scripts/setup_flow_mcp.py
```
内容確認だけしたい場合:
```bash
python .github/skills/power-automate/scripts/setup_flow_mcp.py --dry-run
```
> `.vscode/mcp.json` は環境依存パスを含むためコミットしない(`.vscode/*` は標準 `.gitignore` で除外済み)。
### 3. VS Code に認識させる
1. コマンドパレット → `MCP: List Servers` で `FlowAgent` が表示されるか確認(表示されない場合はウィンドウをリロード)
2. `FlowAgent` を Start
3. GitHub Copilot Chat(エージェントモード)で自然言語で指示する
### 4. フローを開発する
| 指示例 | 動作 |
|---|---|
| 「承認フローを作って。申請レコード作成時に承認者へメール送信」 | `build-flow` スキルがフローを自律生成・デプロイ |
| 「先ほどのフローが失敗した原因を教えて」 | `diagnose-flow` スキルが失敗ランを深掘り診断 |
| 「このフローのメール本文を変更して」 | `edit-flow` スキルがアクション単位で編集 |
### 5. ソリューションへの追加・有効化
MCP で作成したフローをソリューションに追加するには `manage-flows` スキルで
`solutionUniqueName` を指定するか、以下のスクリプトで補完する。
**第 1 引数にフロー ID を直接渡す**(`--workflow-id` のようなオプション形式ではない)。
```bash
python .github/skills/power-automate/scripts/add_flow_to_solution.py <flow-id>
```
ソリューションに追加した直後の `publish_flow`(有効化)が
`CannotStartUnpublishedSolutionFlow` で失敗することがある。この場合の原因切り分けと
解消手順、および `run_flow` によるテスト実行時の制約は
[references/flow-agent-mcp.md](references/flow-agent-mcp.md) の該当節を参照。
詳細な設定・トラブルシュートは [references/flow-agent-mcp.md](references/flow-agent-mcp.md) を参照。
コネクター接続は [接続作成標準](references/connection-creation.md) に従う。
Power Apps API で Connected 接続を先に検索し、存在しない場合だけ VS Code 統合ブラウザで
接続パラメーターを自動入力する。ユーザー操作は OAuth のアカウント選択・同意に限定し、
Connected 確認後の接続参照・フロー作成・有効化・テストは API で行う。
OAuth 完了後は子ページを自動で閉じる。自動クローズできない場合は Connected を API で確認してから、
その画面を閉じてよいことをユーザーへ明示する。
`HTTP with Microsoft Entra ID` の内部 API、要求本文、権限の実測値は
[非公開接続 API の実測結果](references/http-entra-connection-private-api.md) を参照する。
---
## API アプローチ(Flow agent MCP が使えない場合)
以下は MCP サーバーが利用できない環境向けの **フォールバック手順**。
Python スクリプトで Dataverse Web API を直接操作する。
定義を送信する前に `scripts/validate_flow_definition.py` の
`assert_base64_content_contract()` を必ず実行する。JSON の `contentBase64` に実行時の本文を渡す場合は
`@base64(...)` で明示的にエンコードし、コネクタ出力型の違いによる実行時失敗をデプロイ前に止める。
Dataverse アクションを含む場合は、参照列をメタデータ API で取得し、
`assert_required_dataverse_columns()` で列の存在を確認してから既存フローを変更する。
Lookup を `@odata.bind` で書き込む場合は `ManyToOneRelationships` から
`ReferencingEntityNavigationPropertyName` を取得し、`require_navigation_property()` で検証する。
Lookup属性の論理名や表示名からナビゲーションプロパティ名を推測しない。
## 核心原則: 接続参照(Connection Reference)が有効化成功の鍵
```
重要な既知制約(2026-05 検証済み)
フロー有効化で AzureResourceManagerRequestFailed が出る根本原因:
→ 接続参照なしで接続 ID を直接埋め込んだ場合、authenticatedUserObjectId が不足する
解決策: 接続参照テーブルに正しい接続を紐づけてから、フロー定義で参照する
→ 100% API 有効化に成功する
❌ 旧パターン(接続 ID 直接指定 → 有効化失敗のリスクあり):
"connectionReferences": {
"shared_commondataserviceforapps": {
"connectionName": "some-connection-id",
"source": "Embedded",
...
}
}
✅ 新パターン(接続参照経由 → 100% 有効化成功):
"connectionReferences": {
"shared_commondataserviceforapps": {
"runtimeSource": "embedded",
"connection": {
"connectionReferenceLogicalName": "prefix_connref_logical_name"
},
"api": {"name": "shared_commondataserviceforapps"}
}
}
```
## 前提: 設計フェーズ完了後にデプロイに入る(必須)
**フローをデプロイする前に、フロー設計をユーザーに提示し承認を得ていること。**
設計提示時に含める内容:
| 項目 | 内容 |
| -------------- | ------------------------------------------------------------------ |
| フロー名 | フローの名前と目的 |
| トリガー | 何をきっかけに実行するか(レコード変更時 / スケジュール / 手動等) |
| アクション一覧 | 条件分岐・メール送信・Teams 通知・データ更新等 |
| 必要な接続 | 使用するコネクタ(Dataverse, Office 365 Outlook, Teams 等) |
| 通知先・本文 | メールの宛先・件名・本文の概要 |
```
フロー: 設計提示 → ユーザー承認 → デプロイスクリプト実行
```
## 大前提: 一つのソリューション内に開発
Dataverse テーブル・Code Apps・Power Automate フロー・Copilot Studio エージェントは **すべて同一のソリューション内** に含める。
```
SOLUTION_NAME=ProjectName ← .env で定義。全フェーズで同じ値を使用
PUBLISHER_PREFIX=prefix ← ソリューション発行者の prefix
```
- フロー作成時は `MSCRM.SolutionUniqueName` ヘッダー必須
- 接続参照もソリューション内に作成(`MSCRM.SolutionUniqueName` ヘッダー)
> **認証**: Python スクリプトの認証は `standard` スキルの `auth_helper.py` を使用。
> `from auth_helper import get_token, get_session, api_get, api_post, api_patch, api_delete, retry_metadata, DATAVERSE_URL` で利用する。
- ソリューション外のフローは「マイフロー」に入り、ALM 管理できない
## 必須要件
### 認証スコープが異なる【必須】
```
Flow API: https://service.flow.microsoft.com/.default ← 環境 ID 解決・/start
PowerApps API: https://service.powerapps.com/.default ← 接続検索用
Graph API: https://graph.microsoft.com/.default ← ユーザー情報用
Dataverse API: https://{org}.crm7.dynamics.com/.default ← workflow テーブル操作・接続参照作成
```
### 接続は Connected 状態で環境内に必要
```
1. Power Apps API で Connected 接続を自動検索する
2. 見つからない場合だけ、VS Code 統合ブラウザで接続を仮作成する
3. ユーザーは OAuth のアカウント選択・同意だけを行う
4. Connected を API で検証し、接続 ID を接続参照へ設定する
```
`auth_helper` の既定クライアントには `Connectivity.Connections.Write` がないため、
新規接続の仮作成はメーカーポータル自身の認証済み API 呼び出しを利用する。
Microsoft Dataverse も OAuth 接続では同意フローを使用する。詳細は
[接続作成標準](references/connection-creation.md) を参照する。
### f-string と式の二重ブレース問題
```python
# ❌ f-string 内の Power Automate 式({} エスケープが複雑でバグの原因)
body = f"@{{triggerOutputs()?['body/{PREFIX}_name']}}"
# ✅ f-string を使わない部分は通常文字列で構築
body_template = "@{triggerOutputs()?['body/{prefix}_name']}"
body = body_template.replace("{prefix}", PREFIX)
# ✅ または変数だけ f-string で、式部分は連結
body = f"<td>@{{triggerOutputs()?['body/{PREFIX}_name']}}</td>"
# ↑ 正しく動くが読みにくい。1箇所だけならOK、複数箇所は避ける
```
### べき等デプロイパターン
```python
# 既存フロー検索 → 無効化 → 削除 → 再作成
existing = api_get(f"workflows?$filter=name eq '{FLOW_NAME}' and category eq 5&$select=workflowid,statecode")
for f in existing.get("value", []):
wf_id = f["workflowid"]
if f["statecode"] == 1: # Active → Draft
api_patch(f"workflows({wf_id})", {"statecode": 0, "statuscode": 1})
time.sleep(2)
api_delete(f"workflows({wf_id})")
time.sleep(3)
# → 新規作成へ進む
```
### Dataverse Webhook トリガーのフローは /start 必須(★ 検証済み教訓)
```
❌ statecode=1 だけで終わる
→ Dataverse Create/Update トリガー(webhook 型)で webhook 登録が完了せず発火しない
✅ statecode=1 + statuscode=2 の後に /start を明示的に呼ぶ:
POST .../providers/Microsoft.ProcessSimple/environments/{env-id}/flows/{workflow-id}/start?api-version=2016-11-01
(Flow API スコープ: https://service.flow.microsoft.com/.default)
```
### GrantAccess / RevokeAccess は PerformUnboundAction で呼ぶ(★ 検証済み教訓)
```
❌ PerformBoundAction + GrantAccess / RevokeAccess
→ "Bound action 'GrantAccess' is not found" (BadRequest)
✅ PerformUnboundAction + actionName + Target パラメータ
→ Draft 作成・有効化に成功(2026-05-02 検証済み)
補足:
- @odata.type をそのまま書くと式として解釈されるため @@odata.type でエスケープが必要
- connectionReferences は runtimeSource: "embedded" + connectionReferenceLogicalName で渡す
- payload(Target / PrincipalAccess / Revokee)は Compose アクションに分離すると
Power Automate UI での編集性が上がる
```
### AI Builder アクションは API で Draft 作成・有効化ともに可能
```
検証結果(operationId: aibuilderpredict_customprompt):
✅ フロー作成(Draft) — AI Builder アクション含む定義の POST は成功
✅ フロー有効化(Activate) — statecode=1 の PATCH も成功
推奨パターン:
✅ aibuilderpredict_customprompt を使用(PerformBoundAction は不可)
✅ connectionReferences に AI Builder 用 Dataverse 接続参照を別キーで登録
CN_DV_AI = "shared_commondataserviceforapps_1"
✅ runtimeSource: "embedded" + connectionReferenceLogicalName でソリューション対応
✅ parameters: recordId(AI Model ID), item/requestv2/... で入力を渡す
✅ AI 出力パス: body/responsev2/predictionOutput/text
NG パターン:
❌ PerformBoundAction / PerformUnboundAction + msdyn_PredictByReference
→ InvalidOpenApiFlow で作成自体が失敗する
```
### Teams PostMessageToConversation の注意
```
★ チャネル投稿(Channel):
❌ body/subject パラメータを指定しない
→ PostMessageToConversation の operationSchema に body/subject は存在しない
→ 指定するとフロー有効化時に InvalidOpenApiFlow (0x80060467) が発生
→ エラーメッセージに具体的なパラメータ名が出ないため原因特定が困難
✅ 使用可能なパラメータ:
poster, location, body/recipient/groupId, body/recipient/channelId, body/messageBody
★ 1:1 チャット(Chat with Flow bot):
✅ location は "Chat with Flow bot"
✅ body/recipient にメールアドレス(文字列)を指定
✅ host.connection キーを使用(connectionName ではない)
❌ body/recipient/to は存在しない → ExtraParameter で InvalidOpenApiFlow
❌ Dataverse workflows テーブルへの直接 INSERT → 接続認証不良で Runtime エラー
✅ デプロイは Flow API 経由を推奨
詳細は trigger-action-patterns.md の
「Teams 1:1 チャット投稿 — Chat with Flow bot」セクション参照
```
### Power Apps V2 トリガー・応答のパラメータ形式(★ 重要)
```
Power Automate UI で手動追加したパラメータと API でデプロイしたパラメータは
形式が異なるとフローが正しく動作しない。必ず UI 形式に合わせる。
★ 正しい形式(トリガー・応答共通):
✅ "x-ms-content-hint": "TEXT"
✅ "x-ms-dynamically-added": true
❌ 間違った形式(API デプロイ時にありがちなミス):
❌ "x-ms-powerflows-param-ispartial": false
❌ "isPartial": false
応答(Response)固有:
✅ schema に "additionalProperties": {} を含める(UI が自動付与)
✅ title と body のキー名を一致させる
詳細: references/trigger-action-patterns.md の
「Power Apps V2 トリガー」「PowerApp 応答アクション」セクションを参照
```
### PowerApps API 接続検索のタイムアウト対策
PowerApps API(`api.powerapps.com`)での接続検索は 504 GatewayTimeout が頻発する。
```python
# ✅ リトライ + timeout=120 パターン
for attempt in range(3):
try:
r = requests.get(
f"https://api.powerapps.com/providers/Microsoft.PowerApps"
f"/apis/{connector}/connections",
headers={"Authorization": f"Bearer {token}"},
params={"api-version": "2016-11-01", "$filter": f"environment eq '{env_id}'"},
timeout=120,
)
except requests.exceptions.Timeout:
wait = 15 * (attempt + 1)
time.sleep(wait)
continue
if r.status_code == 504:
wait = 15 * (attempt + 1)
time.sleep(wait)
continue
if r.ok:
# Connected 状態の接続を抽出
break
```
```
❌ タイムアウトで即座にエラー終了 → 一時的な問題で不必要に失敗
✅ 3 回リトライ(累進的 wait: 15s → 30s → 45s)
✅ timeout=120 を明示的に設定(デフォルトは無限待ち)
```
### Dataverse File 列へのファイルアップロード(★ 検証済み教訓)
```
❌ operationId: "UploadFile"
→ Dataverse コネクタに存在しない operationId
→ WorkflowOperationInputsApiOperationNotFound エラー
✅ operationId: "UpdateEntityFileImageFieldContent"
→ Dataverse コネクタの正式な File/Image 列更新オペレーション
→ Draft 作成・有効化ともに成功(2026-04-27 検証済み)
```
### 環境 ID の解決(Flow API / PowerApps API で必要)
```python
def resolve_environment_id() -> str:
"""Flow API で DATAVERSE_URL → 環境 ID を解決"""
token = get_token(scope="https://service.flow.microsoft.com/.default")
r = requests.get(
"https://api.flow.microsoft.com/providers/Microsoft.ProcessSimple/environments"
"?api-version=2016-11-01",
headers={"Authorization": f"Bearer {token}"},
timeout=60,
)
r.raise_for_status()
dv_url = DATAVERSE_URL.rstrip("/")
for env in r.json().get("value", []):
instance_url = (
env.get("properties", {})
.get("linkedEnvironmentMetadata", {})
.get("instanceUrl", "")
or ""
).rstrip("/")
if instance_url == dv_url:
return env["name"] # ← 環境 ID
raise RuntimeError(f"環境が見つかりません: {dv_url}")
```
```
✅ Flow API スコープ(https://service.flow.microsoft.com/.default)でトークン取得
✅ instanceUrl の末尾スラッシュを rstrip("/") で統一して比較
✅ 環境 ID は env["name"] フィールド(properties.displayName ではない)
❌ 環境 ID を .env にハードコード → 環境が変わると動かない
```
## 構築手順(5ステップ — この順序で100%有効化成功)
### Step 1: 環境 ID 解決 + 接続検索
```python
# 環境 ID を DATAVERSE_URL から逆引き
env_id = resolve_environment_id()
# PowerApps API で接続を検索(リトライ付き)
connection_id = find_connection(env_id, "shared_commondataserviceforapps")
```
### Step 2: 接続参照の作成(★ 有効化成功の核心)
```python
def ensure_connection_reference(logical_name: str, display_name: str, connector_id: str, connection_id: str):
"""接続参照をべき等で作成。既存なら接続の紐づけを更新。"""
existing = api_get(
f"connectionreferences?$filter=connectionreferencelogicalname eq '{logical_name}'"
"&$select=connectionreferenceid,connectionid"
)
if existing.get("value"):
ref = existing["value"][0]
if ref.get("connectionid") != connection_id:
api_patch(f"connectionreferences({ref['connectionreferenceid']})", {"connectionid": connection_id})
return
body = {
"connectionreferencelogicalname": logical_name,
"connectionreferencedisplayname": display_name,
"connectorid": f"/providers/Microsoft.PowerApps/apis/{connector_id}",
"connectionid": connection_id,
}
retry_metadata(
lambda: api_post("connectionreferences", body, solution=SOLUTION_NAME),
f"接続参照: {logical_name}",
)
# ── 使用例 ──
CONNREF_DATAVERSE = f"{PREFIX}_sharedcommondataserviceforapps"
CONNREF_OUTLOOK = f"{PREFIX}_sharedoffice365"
ensure_connection_reference(CONNREF_DATAVERSE, "Dataverse", "shared_commondataserviceforapps", dv_conn_id)
ensure_connection_reference(CONNREF_OUTLOOK, "Office 365 Outlook", "shared_office365", outlook_conn_id)
```
```
★ なぜこれが重要か:
接続参照に正しい接続 ID が紐づいていれば、フロー有効化時に
authenticatedUserObjectId が解決され、AzureResourceManagerRequestFailed は発生しない。
接続参照なしの旧パターンでは、接続の認証情報が不足して有効化が失敗していた。
```
### Step 3: フロー定義の構築
```python
# フロー定義(Logic Apps スキーマ形式)
definition = {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"$authentication": {"defaultValue": {}, "type": "SecureObject"},
"$connections": {"defaultValue": {}, "type": "Object"},
},
"triggers": { ... },
"actions": { ... },
}
# ★ 接続参照を参照する connectionReferences(有効化成功の鍵)
clientdata = {
"properties": {
"definition": definition,
"connectionReferences": {
"shared_commondataserviceforapps": {
"runtimeSource": "embedded",
"connection": {
"connectionReferenceLogicalName": CONNREF_DATAVERSE,
},
"api": {"name": "shared_commondataserviceforapps"},
},
"shared_office365": {
"runtimeSource": "embedded",
"connection": {
"connectionReferenceLogicalName": CONNREF_OUTLOOK,
},
"api": {"name": "shared_office365"},
},
},
},
"schemaVersion": "1.0.0.0",
}
```
```
★ connectionReferences のキー名は定義内の host.connectionName と一致させる:
triggers/actions の host.connectionName = "shared_commondataserviceforapps"
→ connectionReferences の key も "shared_commondataserviceforapps"
★ AI Builder 用に同じコネクタの別キーが必要な場合:
host.connectionName = "shared_commondataserviceforapps_1"
→ connectionReferences に "shared_commondataserviceforapps_1" を追加
→ 同じ接続参照を参照してもよい
```
### Step 4: workflow テーブルに Draft 作成
```python
workflow_body = {
"name": FLOW_DISPLAY_NAME,
"type": 1,
"category": 5, # 5 = Cloud Flow
"statecode": 0, # 0 = Draft
"statuscode": 1, # 1 = Draft
"primaryentity": "none",
"clientdata": json.dumps(clientdata, ensure_ascii=False),
"description": "フローの説明",
}
# MSCRM.SolutionUniqueName ヘッダーでソリューション内に作成
wf_id = api_post("workflows", workflow_body, solution=SOLUTION_NAME)
```
### Step 5: 有効化 + Webhook 登録
```python
# ★ Draft → Activated(接続参照が正しければ100%成功)
time.sleep(3) # 作成直後は少し待つ
api_patch(f"workflows({wf_id})", {"statecode": 1, "statuscode": 2})
# ★ Dataverse Webhook トリガーの場合のみ /start を呼ぶ(Webhook 登録)
time.sleep(3)
token = get_token(scope="https://service.flow.microsoft.com/.default")
try:
r = requests.post(
f"https://api.flow.microsoft.com/providers/Microsoft.ProcessSimple"
f"/environments/{env_id}/flows/{wf_id}/start?api-version=2016-11-01",
headers={"Authorization": f"Bearer {token}"},
timeout=60,
)
r.raise_for_status()
print(" ✓ Webhook /start 登録")
except Exception as e:
print(f" ⚠ /start 登録失敗(フローは有効化済み。手動で Turn On すれば Webhook 登録される): {e}")
```
```
★ /start が必要なトリガー(Webhook 型):
- SubscribeWebhookTrigger(Dataverse レコード変更)
- OnNewFile(SharePoint Notification 型)
★ /start が不要なトリガー:
- GetOnNewFileItems(SharePoint Polling 型)
- Recurrence(スケジュール)
- PowerAppV2(Code Apps からの手動呼び出し)
```
### デバッグ JSON 出力(失敗時のフォールバック)
有効化が失敗した場合のデバッグ JSON 出力・手動有効化フォールバックは
[references/troubleshooting.md](references/troubleshooting.md#有効化失敗時のデバッグ-json-出力フォールバック) を参照。
## 通知デザイン(デフォルト適用 — ユーザー指定不要)
メール通知・Teams 通知が含まれるフローでは、[通知デザインテンプレート](references/notification-templates.md) を**デフォルトで適用する**。
```
★ ユーザーから特別な指定がなくても以下のデザインが自動適用される:
- メール: カード型テーブルレイアウト(600px幅、ゼブラストライプ、色付きヘッダーライン)
- Teams: シンプルテーブル + h3 見出し + hr 区切り
- variant 自動判定: 通知目的に応じて青/紫/緑/橙/赤を自動選択
★ 検証済み(2026-05-21 Outlook メール受信確認):
- テーブルレイアウト + インラインスタイル → Outlook/Gmail で崩れない
- ゼブラストライプ(#ffffff / #f9fafb 交互)→ 視認性向上
- border-bottom で色付きヘッダー → グラデーション不要で目立つ
❌ グラデーション背景(メールクライアントで描画されない)
❌ flexbox / grid(メールクライアント非対応)
❌ <style> タグ(Gmail で除去される)
```
## 代表的パターン
詳細なトリガー・アクションパターン(SharePoint、Dataverse、Teams、AI Builder、OneDrive PDF 変換等)は [トリガー・アクションパターンリファレンス](references/trigger-action-patterns.md) を参照。
## .env 必須項目
全パラメータの定義(取得元コメント付き)は [references/.env.example](references/.env.example) を参照。
実値はリポジトリルートの `.env` に置く(`.gitignore` 済み)。
```env
DATAVERSE_URL=https://{org}.crm.dynamics.com/
SOLUTION_NAME=SolutionName
PUBLISHER_PREFIX=prefix
# 接続 ID はハードコードしない。deploy_flow.py が PowerApps API で自動検索する
```
## よくあるエラーと解決策
エラー→原因→解決策の一覧(`AzureResourceManagerRequestFailed` / `InvalidOpenApiFlow` /
504 GatewayTimeout / 接続エラー 等)は [references/troubleshooting.md](references/troubleshooting.md#よくあるエラーと解決策) を参照。