بنقرة واحدة
dataverse
Dataverse テーブル設計・構築・デモデータ投入・セキュリティロール作成。ソリューション作成からテーブル・リレーション・ローカライズ・権限設定まで Python スクリプトで一括構築する。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Dataverse テーブル設計・構築・デモデータ投入・セキュリティロール作成。ソリューション作成からテーブル・リレーション・ローカライズ・権限設定まで Python スクリプトで一括構築する。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Power Platform 包括開発標準。共通認証(auth_helper.py)・.env パラメータ・ソリューション運用など全スキル共通の開発基盤を提供する。アイコン生成・HTML メールは横断参照用の共有ユーティリティとして保持。
Copilot Studio の「全く新しいアーキテクチャ」(cliagent テンプレート)エージェントを Dataverse Web API だけで完全自動構築する。UI 手動作成不要。Bot 作成・Instructions/モデル/メモリ設定・フラット Python スキル添付・アイコン登録・公開までスクリプトで完結。MCP サーバー(Dataverse / Work IQ 等)のツール追加は Copilot Studio UI での手動作業とする。
Azure 上のリファレンスアーキテクチャを選定し、テナントのセキュリティガバナンスに準拠した構成で構築・デプロイ・検証する。組織ポリシー(公衆ネットワークアクセス禁止・共有キー禁止・MFA 必須等)の下でも動作する構成を、Private Link / Managed Identity / VNet 統合を用いて実装する。
Power Apps Code Apps(コードファースト)の初期化・Dataverse 接続・UI 設計・開発・デプロイ。TypeScript + React + Tailwind CSS で開発する。CSP 構成・メール送信パターンも含む。
Power Pages Code Site (SPA) の開発・ビルド・デプロイ。pac pages upload-code-site でサイト作成からデプロイまで完結する。
Power Platform ソリューションの全体アーキテクチャを設計する。Copilot Studio / Power Automate / Code Apps / Power Pages / AI Builder の使い分け判断、コンポーネント選定、統合パターンを決定する。
| name | dataverse |
| description | Dataverse テーブル設計・構築・デモデータ投入・セキュリティロール作成。ソリューション作成からテーブル・リレーション・ローカライズ・権限設定まで Python スクリプトで一括構築する。 |
| category | data |
| triggers | ["Dataverse テーブル作成","テーブル設計","スキーマ設計","Lookup","Choice","リレーション","デモデータ","ソリューション","パブリッシャー","プレフィックス","setup_dataverse","セキュリティロール","Security Role","権限設定","ロール作成","AddPrivilegesRole","ReplacePrivilegesRole","PrivilegeDepth","アクセス制御","RBAC","ロール権限","テーブル権限"] |
Dataverse のソリューション・テーブル・リレーション・ローカライズ・デモデータ・セキュリティロールを Python スクリプト で一括構築する。
| リファレンス | 内容 |
|---|---|
| Dataverse 統合ガイド | CRUD・Lookup・Choice・システム列・標準テーブル再利用ガイド・トラブルシューティング |
| セキュリティロール | カスタムセキュリティロールの作成・権限設定パターン |
| セキュリティロールデプロイリファレンス | セキュリティロールのデプロイ手順詳細 |
| セキュリティロールトラブルシューティング | セキュリティロール関連のトラブルシューティング |
このスキルの位置づけ: アーキテクチャ設計(
architecture)で Dataverse 利用が確定した後、テーブル設計→構築を担当する。Code Apps / Generative Pages / Power Automate / Copilot Studio のいずれを使う場合でも、データ層はこのスキルで構築する。
認証ヘルパーは standard スキルに同梱(.github/skills/standard/scripts/auth_helper.py)。
各スキルの Python スクリプトは sys.path に ../../standard/scripts を追加して import するため、コピー不要。
2 層キャッシュ(AuthenticationRecord + MSAL OS 資格情報ストア)によりデバイスコード認証は初回のみ。
コピー元: .github/skills/standard/scripts/auth_helper.py
| 関数 | 戻り値 | 説明 |
|---|---|---|
api_get(path) | dict | GET。パス文字列のみ(api_get("url", {"$filter": ...}) は 不可。クエリパラメータは URL に直接埋め込む) |
api_post(path, body, solution=) | str | None | POST。作成レコードの ID を返す。solution=SOLUTION_NAME でソリューションヘッダー付与 |
api_patch(path, body) | None | PATCH |
api_delete(path) | None | DELETE |
api_request(path, body, method="PUT") | None | PUT + MSCRM.MergeLabels: true ヘッダー自動付与。ローカライズ用 |
retry_metadata(fn, desc, max=5) | any | None | メタデータロック(0x80040237)・重複(already exists)検出リトライ。既存スキップ対応 |
get_token(scope=) | str | アクセストークン。省略時は {DATAVERSE_URL}/.default |
flow_api_call(method, path, body) | dict | Flow Management API 用。自動的に service.flow.microsoft.com スコープで認証 |
重要:
api_get()はdictを直接返す。.json()を呼ぶとエラー。
DATAVERSE_URL=https://{org}.crm7.dynamics.com/
TENANT_ID={your-tenant-id}
SOLUTION_NAME={YourSolutionName}
PUBLISHER_PREFIX={prefix}
SOLUTION_DISPLAY_NAME={日本語表示名} # ソリューション作成後に自動保存される
pip install azure-identity requests python-dotenv
テーブル設計に入る前に、必ず既存パブリッシャーを環境から確認する。
from auth_helper import api_get
# 既存パブリッシャー一覧を取得
pubs = api_get("publishers?$filter=customizationprefix ne 'none'&$select=friendlyname,uniquename,customizationprefix&$orderby=friendlyname")
for p in pubs.get("value", []):
print(f" {p['customizationprefix']} — {p['friendlyname']} ({p['uniquename']})")
ユーザーに提示する内容:
ユーザーの承認を得てから .env の PUBLISHER_PREFIX を確定し、環境スキャンに進む。
新規テーブルを設計する前に、必ず既存環境を API でスキャンし、再利用できる資産を棚卸しする。 いきなり新規テーブルを作らず、標準テーブル・他ソリューションのカスタムテーブルを最大限再利用する。
# 標準テーブル(account/contact/product/systemuser 等)+全カスタムテーブルを走査し、再利用レポートを出力
python -u .github/skills/dataverse/scripts/scan_environment.py --out spec/dataverse-scan.md
# 特定テーブルの列詳細も見たいとき
python -u .github/skills/dataverse/scripts/scan_environment.py --tables account,contact,product
レポートをもとにユーザーに提示し、再利用 vs 新規を合意する:
systemuser Lookup + ownerid/createdby/modifiedby システム列を使う。account(企業)/ contact(個人)を再利用。顧客参照は customer 型 Lookup(account/contact ポリモーフィック)。product / pricelevel / uom を再利用。製品マスタを新規作成しない。詳細な再利用判断は Dataverse 統合ガイド — 標準テーブル再利用ガイド を参照。
# ソリューション名の重複チェック
existing_sol = api_get(f"solutions?$filter=uniquename eq '{SOLUTION_NAME}'&$select=solutionid,friendlyname")
# テーブルスキーマ名の重複チェック
# ⚠️ 環境によっては EntityDefinitions への $filter=startswith(...) が 501 Not Implemented になる。
# $select のみで全件取得し、プレフィックス一致は Python 側でフィルタする(詳細は Dataverse 統合ガイド参照)。
all_tables = api_get("EntityDefinitions?$select=LogicalName,SchemaName,DisplayName")
existing_tables = [t for t in all_tables["value"] if t["LogicalName"].startswith(f"{PREFIX}_")]
衝突がある場合はユーザーに報告し、名前を変更してから設計を確定する。
設計書を作成してユーザーに提示する。以下をすべて含める:
| 項目 | 内容 |
|---|---|
| 再利用テーブル一覧 | Step 1 スキャン結果から、再利用する標準/既存テーブルを明記 |
| テーブル一覧 | 新規のみ。マスタ → 主 → 従属の順に記載 |
| 列定義 | 英語スキーマ名、型、必須、Choice 値(100000000 始まり) |
| 全 Lookup リレーション | 漏れなく明記(既存テーブルへの Lookup・customer 型を含む) |
| ローカライズ計画 | テーブル名・列名・Choice オプションの日本語名 |
| デモデータ計画 | 全テーブルに対して(従属テーブル含む) |
Code Apps 案件: スキーマ承認後すぐに Code Apps サブエージェントを起動する(並行実行)
architectureスキルで Code Apps が確定している場合、ユーザーがスキーマを承認したタイミングでcode-appsスキルをサブエージェントとして起動し、Dataverse 構築(Step 4)と並行して Code Apps 開発(scaffold → deploy → add-data-source)を進める。
- このエージェント(dataverse): Step 4 を
--skip-localizeで実行(テーブル構築のみ)- サブエージェント(code-apps): scaffold →
pac code init→npm run deploy→pac code add-data-source(全テーブル)- このエージェント(dataverse): Code Apps 側の
add-data-source完了を待たずに--localize-onlyを実行して完了Dataverse 構築が先に終わっても Code Apps サブエージェントは独立して継続する。
同梱の setup_dataverse.py をプロジェクト用にカスタマイズして実行する。
必ず
python -u(unbuffered)で実行する: テーブル作成・Lookup 作成・ローカライズは 数分〜十数分かかるため、標準の出力バッファリング下では「止まって見える」ことがある。-uを付けて Step ごとの進捗(=== Step 2: テーブル作成 ===など)を確実にリアルタイム 表示させる。スクリプト側でもsys.stdout.reconfigure(line_buffering=True)を有効化済み。
テーブルが複数ある場合は並行作成(環境の混雑度に応じて並行数を調整):
setup_dataverse.pyの Step 2 では、TABLESに 2 つ以上のテーブルが定義されている場合、ThreadPoolExecutor(デフォルト最大 3 並行)で全テーブルを並行作成する。⚠️ Dataverse のメタデータロックはテナント全体で共有されるため、既存カスタムテーブルが 大量にある(100 件超)環境や、同一環境で他セッションが並行してメタデータ操作をしている環境では 並行数が高いほど競合が増える。実測では 10 テーブルを 5 並行で作成したところ 7 テーブルが
max retries (5) exceededで失敗し、並行数を 2 に落として再実行したところ全て成功した。 失敗が多発する場合はcreate_tables()のThreadPoolExecutor(max_workers=...)を 2 まで 下げて再実行する。スクリプトはべき等(成功済みテーブル・列はalready exists, skippingで自動スキップ)なので、同じコマンドを再実行するだけで失敗分だけがリトライされ、安全に復旧する。Lookup(Step 3)は全テーブルと列が揃ってから作成するので、このスクリプトでの呼び出し順は 変わらない(
create_tables()が全スレッドの完了を待ってから return する)。
Code Apps を使う場合はローカライズを2段階に分ける:
pac code add-data-sourceは日本語 DisplayName だとFailed to sanitize stringで失敗することがある。ローカライズ→英語に一時 戻す→再ローカライズという無駄な往復を避けるため、構築時点ではローカライズせず英語のままadd-data-sourceを先に済ませ、その後にローカライズする。python -u setup_dataverse.py --skip-localize # テーブル構築のみ(英語のまま) # ここで code-apps サブエージェント側の add-data-source を全テーブルに実行(build-reference.md Step 4) python -u setup_dataverse.py --localize-only # ローカライズ・デモデータ投入Code Apps を使わない(Generative Page / モデル駆動型アプリのみ等)場合は、従来どおり フラグなしで一括実行して問題ない(
python -uは常に付ける)。
| ルール | 理由 |
|---|---|
| 設計前に環境スキャン(Step 1)を必ず実行 | 既存テーブルと重複作成して二重管理になる事故を防ぐ。scan_environment.py で棚卸し |
| ユーザー参照は systemuser + システム列 | カスタムユーザーテーブルを作らない。ownerid/createdby/modifiedby を活用 |
| 顧客は account/contact を再利用 | 標準テーブルを使う。顧客 Lookup は customer 型(account/contact ポリモーフィック) |
| 製品は product/pricelevel/uom を再利用 | 製品マスタを新規作成しない |
| スキーマ名は英語のみ | 日本語スキーマ名は npx power-apps add-data-source で失敗する |
| ユーザー参照は SystemUser テーブル | カスタムユーザーテーブルを作らない |
作成者・報告者は createdby システム列を利用 | カスタム ReportedBy Lookup は不要 |
⚠️ Power Pages 例外: Power Pages では Web API 経由のレコード作成時に
createdbyがアプリケーションユーザー(サービスアカウント)になるため、createdbyで報告者を追跡できない。Power Pages 向けテーブルでは Contact テーブルへの Lookup 列で報告者を追跡する設計が必須。詳細は power-pages スキルの教訓 19 を参照。 | Choice 値は100000000始まり | 0, 1, 2... はカスタム Choice では使用不可 | | マスタテーブルは要件から網羅的に洗い出す | カテゴリ・場所・設備等、ユーザーが言及した分類はすべてマスタ化 | | 全 Lookup リレーションシップを設計書に明記 | 漏れると Lookup が機能しない | | デモデータは全テーブル(従属テーブル含む)に計画 | コメント等の従属テーブルにもデモデータを用意 | | Instructions のテーブル名は単数形の論理名 | Power Apps MCP / Dataverse MCP は LogicalName でアクセス。複数形(EntitySetName)や表示名は不可 |
| ルール | 理由 |
|---|---|
retry_metadata() を使う | auth_helper.py 組み込みのリトライ。メタデータロック(0x80040237)・重複(already exists)を自動ハンドリング |
テーブル作成間に time.sleep(10)、列追加間に time.sleep(5) | メタデータロックの 予防策。retry_metadata はリアクティブ(発生後リトライ)だが、プロアクティブに待機する方が結果的に速い(リトライ回数が減る) |
| リレーション作成順: マスタ → 主 → 従属 → Lookup | 依存テーブルが存在しないとリレーション作成失敗 |
| 既存テーブルでもカラム欠落を補完 | テーブルは既存でも、前回失敗したカラムが欠けている場合がある。個別にカラム存在チェックして不足分を追加 |
api_post() に solution=SOLUTION_NAME を渡す | ソリューションヘッダー付与。テーブル・列・Lookup すべてに |
テーブル作成後に PublishAllXml | テーブルのメタデータを公開しないとローカライズが失敗する場合がある |
PublishAllXml は 429 レート制限に備える | 大量メタデータ操作後に 429 が頻発。時間を置いてスクリプト再実行で回復。べき等設計必須 |
ローカライズは api_request() で PUT | MSCRM.MergeLabels: true ヘッダーが自動付与される |
ローカライズ後に再度 PublishAllXml | ローカライズの反映に公開が必要 |
ソリューション含有は AddSolutionComponent で検証 | MSCRM.SolutionName ヘッダーだけに依存しない |
| EntitySetName は API で取得 | 複数形の推測は誤る場合がある(例: equipmentcategorys vs em_equipmentcategories) |
ソリューション表示名を .env に自動保存 | _save_env_value("SOLUTION_DISPLAY_NAME", name) で永続化。他スクリプトから参照可能 |
| メタデータロックで最大リトライ超過時は再実行 | retry_metadata() の max retries (5) を超えた列は、スクリプト再実行時に「既存。スキップ」で回復 |
| 失敗が多発する環境では並行数を下げる | 既存カスタムテーブルが多い環境では max_workers を 5→2〜3 に下げると失敗率が大幅に下がる(実測) |
| 429 レート制限は時間を置いて再実行 | PublishAllXml・EntityDefinitions PUT で 429 が頻発。べき等設計でスクリプト再実行で回復 |
| ルール | 理由 |
|---|---|
RelationshipDefinitions への POST で Lookup 作成 | 1:N リレーション(Lookup)は RelationshipDefinitions エンティティセットへ OneToManyRelationshipMetadata を POST する。CreateOneToMany バインドアクションは環境/Web API バージョンによって 404 Not Found になるため使わない |
| Lookup 作成前に属性存在チェック必須 | api_get("EntityDefinitions(LogicalName='{from}')/Attributes(LogicalName='{col}')") で存在確認。存在すればスキップ。retry_metadata の "already exists" 検出だけに頼らない |
LOOKUPS 形式: from_table, column_logical, display, to_table | シンプルな 4 キー構造。SchemaName は {from_table}_{column_logical} で自動生成 |
@odata.bind にはナビゲーションプロパティ名(NavProp名)を使う | 列の論理名ではない。大文字/小文字が区別される |
NavProp 名は ManyToOneRelationships で動的取得 | ReferencingEntityNavigationPropertyName を確認する |
| NavProp 名を推測しない | get_navprop(from_logical, to_logical) ヘルパーで取得 |
Lookup は NavProp@odata.bind で設定 | /{EntitySetName}({id}) の形式 |
| Lookup リレーション作成はべき等設計 | 属性存在チェック → 存在すればスキップ → 未存在なら RelationshipDefinitions へ POST → retry_metadata で二重保護 |
| ルール | 理由 |
|---|---|
| テーブル表示名は PUT + MetadataId | PATCH では反映されないケースがある |
api_request() を使う | MSCRM.MergeLabels: true ヘッダーが自動付与される |
列の PUT には @odata.type が必要 | AttributeType に応じた OData 型を指定(Lookup → LookupAttributeMetadata 等) |
Choice オプションは UpdateOptionValue アクション | api_post("UpdateOptionValue", {...}) で各オプションの日本語ラベルを更新 |
テーブルにカスタムアイコンを設定する場合は standard スキルの アイコン作成リファレンス を参照。
SVG WebResource 作成 → IconVectorName の PUT 設定パターンが記載されている。
| ルール | 理由 |
|---|---|
| NavProp 名を API から動的取得 | get_navprop() ヘルパーを使う |
| EntitySetName を API から動的取得 | get_entity_set_name() ヘルパーを使う |
| 既存データのべき等チェック | 主キー名で検索し、既存ならスキップ |
api_post() の戻り値は ID 文字列 | r.headers["OData-EntityId"] ではなく、直接 ID が返る |
## テーブル設計書
### テーブル一覧
| # | テーブル (論理名) | 種別 | 説明 |
|---|---|---|---|
| 1 | **{prefix}_mastera** | マスタ | ... |
| 2 | **{prefix}_mainentity** | 主テーブル | ... |
| 3 | **{prefix}_childentity** | 従属 | ... |
### 列定義: {prefix}_mainentity
| 列 (論理名) | 表示名 | 型 | 必須 | 備考 |
|---|---|---|---|---|
| {prefix}_name | Name / 名前 | String(200) | Yes | 主列 |
| {prefix}_status | Status / ステータス | Picklist | No | 100000000=New, 100000001=Active |
| {prefix}_masteraid | MasterA / マスタA | Lookup→mastera | No | |
### Lookup リレーション
| From (referencing) | → To (referenced) | lookup_attr | 表示名 |
|---|---|---|---|
| mainentity | mastera | {prefix}_masteraid | マスタA |
| mainentity | systemuser | {prefix}_assigneeid | 担当者 |
| childentity | mainentity | {prefix}_mainentityid | メイン |
### Choice 値
| フィールド | 値 |
|---|---|
| mainentity.status | 100000000=New, 100000001=Active, 100000002=Closed |
### ローカライズ
| 対象 | 日本語名 |
|---|---|
| mastera テーブル | マスタA / マスタA |
| mainentity テーブル | メインエンティティ / メインエンティティ一覧 |
| mainentity.name | 名前 |
| mainentity.status | ステータス |
| mainentity.status=100000000 | 新規 |
| mainentity.status=100000001 | アクティブ |
### デモデータ計画
| テーブル | 件数 | 概要 |
|---|---|---|
| MasterA | 5件 | ... |
| MainEntity | 10件 | 各ステータスを網羅 |
| ChildEntity | 8件 | 主要レコードにコメント |
| スクリプト | 用途 |
|---|---|
| scan_environment.py | 設計前の環境スキャン。標準/既存カスタムテーブルを棚卸しし、再利用推奨レポートを出力(Step 1) |
| setup_dataverse.py | テーブル・Lookup・ローカライズ・デモデータの一括構築(Step 4) |
カスタマイズ箇所:
TABLES — テーブル定義(論理名・列定義)LOOKUPS — リレーション定義LOCALIZE_TABLES / LOCALIZE_COLUMNS / LOCALIZE_OPTIONS — 日本語化定義create_demo_data() — デモデータ投入ロジック実行ステップ:
retry_metadata + 既存カラム補完)PublishAllXml)api_request PUT + MergeLabels + UpdateOptionValue)AddSolutionComponent)Code Apps 案件では
--skip-localizeで 1〜4 のみ実行 →add-data-source→--localize-onlyで 5〜9 を実行する(詳細は Step 4)。
| スキル | 関係 |
|---|---|
standard | 共通認証(auth_helper.py)・.env パラメータ・retry_metadata |
architecture | アーキテクチャ判断後にこのスキルへ |
code-apps | テーブル構築後に Code Apps 開発 |
generative-page | テーブル構築後に Generative Page 開発 |
model-driven-app | テーブル構築後にモデル駆動型アプリ作成 |
security-role | テーブル構築後にセキュリティロール設定 |