Power Platform のテナント / 環境ガバナンスを確認・設定する管理スキル。開発着手前の環境チェック(既定環境ではないか・マネージド環境・Dataverse / Code Apps / MCP の有効化・セキュリティ ロール・管理 API アクセス)と DLP 事前チェックを非対話スクリプトで実行し、必要ならマネージド環境設定・カスタムコネクタの DLP 分類・ACP(Advanced connector policies)の許可コネクタを dry-run 付きで変更する。Microsoft 第一者サービスだけを許可する ACP 推奨プロファイルの適用と、クラシック DLP から ACP への移行も支援する。クラシック DLP と ACP は既定の混成モードで併用され、より制限の厳しい方が適用されるため両方を確認する。オプションとして、既定環境 / 個人開発者環境 / 市民開発者環境 / AI CoE セントラル / AI CoE 内製開発の 5 グループからなるテナント全体の環境戦略を、読み取り専用スキャン → 移行プラン(admin-migration-plan.md)→ レビュー → 適用の順で策定・実行する。設定は環境グループのルールで行うのを原則とし、グループ ルールに無い項目(既定環境ルーティング・Dataverse for Teams 禁止・Dataverse 検索・グループへの割り当て・Copilot クレジット配分)だけをテナント設定・環境個別設定・Dataverse の組織設定で補う。IP 制限・テナント分離・監査ログ・ライセンス配分などの管理設定は references にまとめる。
power-pages
Power Pages Code Site (SPA) の開発・ビルド・デプロイ。pac pages upload-code-site でサイト作成からデプロイまで完結する。
含まれるファイル(200)
- SKILL.md39.8 KB
- references/.env.example3.7 KB
- references/access-scope-design.md9.3 KB
- references/account-link-admin-app.md3.9 KB
- references/account-link-request-flow.md7.0 KB
- references/auth-authz.md53.9 KB
- references/authentication.md35.4 KB
- references/dataverse-client.md30.7 KB
- references/design-pattern.md7.6 KB
- references/design-templates.md13.3 KB
- references/enhanced-data-model-permissions.md18.6 KB
- references/legacy-checklist.md3.8 KB
- references/operations-and-pitfalls.md8.7 KB
- references/previews/amber-orange.html6.0 KB
- references/previews/blue-navy.html6.0 KB
- references/previews/emerald-teal.html6.0 KB
- references/previews/indigo-violet.html6.2 KB
- references/previews/rose-pink.html6.0 KB
- references/troubleshooting.md8.3 KB
- references/upstream-alignment.md2.6 KB
- reviews/pre-deploy-review.md6.2 KB
- reviews/pre-design-review.md5.6 KB
- samples/portal/.powerpages-site-backup/.portalconfig/English.portallanguage.yml128 B
- samples/portal/.powerpages-site-backup/content-snippets/footer/en-US/Footer.contentsnippet.value.html66 B
- samples/portal/.powerpages-site-backup/content-snippets/footer/en-US/Footer.contentsnippet.yml154 B
- samples/portal/.powerpages-site-backup/content-snippets/header-search-tooltip/en-US/Header-Search-ToolTip.contentsnippet.value.html6 B
- samples/portal/.powerpages-site-backup/content-snippets/header-search-tooltip/en-US/Header-Search-ToolTip.contentsnippet.yml168 B
- samples/portal/.powerpages-site-backup/content-snippets/header-toggle-navigation/en-US/Header-Toggle-Navigation.contentsnippet.value.html17 B
- samples/portal/.powerpages-site-backup/content-snippets/header-toggle-navigation/en-US/Header-Toggle-Navigation.contentsnippet.yml190 B
- samples/portal/.powerpages-site-backup/content-snippets/logo-alt-text/en-US/Logo-alt-text.contentsnippet.value.html17 B
- samples/portal/.powerpages-site-backup/content-snippets/logo-alt-text/en-US/Logo-alt-text.contentsnippet.yml168 B
- samples/portal/.powerpages-site-backup/content-snippets/logo-url/en-US/Logo-URL.contentsnippet.value.html15 B
- samples/portal/.powerpages-site-backup/content-snippets/logo-url/en-US/Logo-URL.contentsnippet.yml158 B
- samples/portal/.powerpages-site-backup/content-snippets/mobile-header/en-US/Mobile-Header.contentsnippet.value.html177 B
- samples/portal/.powerpages-site-backup/content-snippets/mobile-header/en-US/Mobile-Header.contentsnippet.yml168 B
- samples/portal/.powerpages-site-backup/content-snippets/search-noresults/en-US/Search-NoResults.contentsnippet.value.html17 B
- samples/portal/.powerpages-site-backup/content-snippets/search-noresults/en-US/Search-NoResults.contentsnippet.yml159 B
- samples/portal/.powerpages-site-backup/content-snippets/search-resultscount/en-US/Search-ResultsCount.contentsnippet.value.html88 B
- samples/portal/.powerpages-site-backup/content-snippets/search-resultscount/en-US/Search-ResultsCount.contentsnippet.yml165 B
- samples/portal/.powerpages-site-backup/content-snippets/search-resultstitle/en-US/Search-ResultsTitle.contentsnippet.value.html34 B
- samples/portal/.powerpages-site-backup/content-snippets/search-resultstitle/en-US/Search-ResultsTitle.contentsnippet.yml165 B
- samples/portal/.powerpages-site-backup/content-snippets/search-title/en-US/Search-Title.contentsnippet.value.html19 B
- samples/portal/.powerpages-site-backup/content-snippets/search-title/en-US/Search-Title.contentsnippet.yml150 B
- samples/portal/.powerpages-site-backup/content-snippets/site-name/en-US/Site-name.contentsnippet.value.html12 B
- samples/portal/.powerpages-site-backup/content-snippets/site-name/en-US/Site-name.contentsnippet.yml160 B
- samples/portal/.powerpages-site-backup/page-templates/Access-Denied.pagetemplate.yml172 B
- samples/portal/.powerpages-site-backup/page-templates/Default-studio-template.pagetemplate.yml240 B
- samples/portal/.powerpages-site-backup/page-templates/Profile.pagetemplate.yml161 B
- samples/portal/.powerpages-site-backup/page-templates/Search.pagetemplate.yml211 B
- samples/portal/.powerpages-site-backup/publishing-states/Draft.publishingstate.yml103 B
- samples/portal/.powerpages-site-backup/publishing-states/Published.publishingstate.yml105 B
- samples/portal/.powerpages-site-backup/site-languages/English.websitelanguage.yml185 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-LoginThrottling-IpAddressTimeoutTimeSpan.sitesetting.yml369 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-LoginThrottling-MaxAttemptsTimeLimitTimeSpan.sitesetting.yml359 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-LoginThrottling-MaxInvaildAttemptsFromIPAddress.sitesetting.yml421 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-LoginTrackingEnabled.sitesetting.yml284 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-OpenAuth-Facebook-AppId.sitesetting.yml86 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-OpenAuth-Facebook-AppSecret.sitesetting.yml90 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-OpenAuth-LinkedIn-ConsumerKey.sitesetting.yml92 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-OpenAuth-LinkedIn-ConsumerSecret.sitesetting.yml95 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-OpenAuth-Microsoft-ClientId.sitesetting.yml90 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-OpenAuth-Microsoft-ClientSecret.sitesetting.yml94 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-OpenAuth-Twitter-ConsumerKey.sitesetting.yml91 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-OpenAuth-Twitter-ConsumerSecret.sitesetting.yml94 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-OpenIdConnect-AzureAD-Caption.sitesetting.yml118 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-OpenIdConnect-AzureAD-RebrandDisclaimerEnabled.sitesetting.yml122 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-Registration-AzureADLoginEnabled.sitesetting.yml214 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-Registration-DenyMinors.sitesetting.yml180 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-Registration-DenyMinorsWithoutParentalConsent.sitesetting.yml227 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-Registration-EmailConfirmationEnabled.sitesetting.yml112 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-Registration-Enabled.sitesetting.yml95 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-Registration-ExternalLoginEnabled.sitesetting.yml108 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-Registration-InvitationEnabled.sitesetting.yml105 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-Registration-LocalLoginDeprecated.sitesetting.yml282 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-Registration-LocalLoginEnabled.sitesetting.yml105 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-Registration-LoginButtonAuthenticationType.sitesetting.yml105 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-Registration-OpenRegistrationEnabled.sitesetting.yml111 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-Registration-ProfileRedirectEnabled.sitesetting.yml253 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-Registration-TermsAgreementEnabled.sitesetting.yml332 B
- samples/portal/.powerpages-site-backup/site-settings/Authentication-Registration-TermsPublicationDate.sitesetting.yml500 B
- samples/portal/.powerpages-site-backup/site-settings/CodeSite-Enabled.sitesetting.yml86 B
- samples/portal/.powerpages-site-backup/site-settings/CustomerSupport-DisplayAllUserActivitiesOnTimeline.sitesetting.yml202 B
- samples/portal/.powerpages-site-backup/site-settings/Footer-OutputCache-Enabled.sitesetting.yml153 B
- samples/portal/.powerpages-site-backup/site-settings/Header-OutputCache-Enabled.sitesetting.yml153 B
- samples/portal/.powerpages-site-backup/site-settings/Header-ShowAllProfileNavigationLinks.sitesetting.yml97 B
- samples/portal/.powerpages-site-backup/site-settings/HTTP-X-Frame-Options.sitesetting.yml86 B
- samples/portal/.powerpages-site-backup/site-settings/KnowledgeManagement-DisplayNotes.sitesetting.yml183 B
- samples/portal/.powerpages-site-backup/site-settings/KnowledgeManagement-NotesFilter.sitesetting.yml230 B
- samples/portal/.powerpages-site-backup/site-settings/MultiLanguage-DisplayLanguageCodeInURL.sitesetting.yml193 B
- samples/portal/.powerpages-site-backup/site-settings/MultiLanguage-MaximumDepthToClone.sitesetting.yml318 B
- samples/portal/.powerpages-site-backup/site-settings/OnlineDomains.sitesetting.yml103 B
- samples/portal/.powerpages-site-backup/site-settings/Profile-Enabled.sitesetting.yml75 B
- samples/portal/.powerpages-site-backup/site-settings/Profile-ForceSignUp.sitesetting.yml80 B
- samples/portal/.powerpages-site-backup/site-settings/Profile-ShowMarketingOptionsPanel.sitesetting.yml93 B
- samples/portal/.powerpages-site-backup/site-settings/Search-Enabled.sitesetting.yml74 B
- samples/portal/.powerpages-site-backup/site-settings/Search-FacetedView.sitesetting.yml145 B
- samples/portal/.powerpages-site-backup/site-settings/search-filters.sitesetting.yml482 B
- samples/portal/.powerpages-site-backup/site-settings/Search-IndexNotesAttachments.sitesetting.yml89 B
- samples/portal/.powerpages-site-backup/site-settings/Search-IndexQueryName.sitesetting.yml90 B
- samples/portal/.powerpages-site-backup/site-settings/search-query.sitesetting.yml578 B
- samples/portal/.powerpages-site-backup/site-settings/Search-RecordTypeFacetsEntities.sitesetting.yml210 B
- samples/portal/.powerpages-site-backup/site-settings/Site-BootstrapV5Enabled.sitesetting.yml83 B
- samples/portal/.powerpages-site-backup/site-settings/ThemeFeature.sitesetting.yml161 B
- samples/portal/.powerpages-site-backup/sitemarkers/Access-Denied.sitemarker.yml106 B
- samples/portal/.powerpages-site-backup/sitemarkers/Home.sitemarker.yml97 B
- samples/portal/.powerpages-site-backup/sitemarkers/Page-Not-Found.sitemarker.yml107 B
- samples/portal/.powerpages-site-backup/sitemarkers/Profile.sitemarker.yml100 B
- samples/portal/.powerpages-site-backup/sitemarkers/Search.sitemarker.yml99 B
- samples/portal/.powerpages-site-backup/web-files/bootstrap.min.css/bootstrap.min.css190.3 KB
- samples/portal/.powerpages-site-backup/web-files/bootstrap.min.css/bootstrap.min.css.webfile.yml478 B
- samples/portal/.powerpages-site-backup/web-files/cat-pc.png/Cat-PC.png10.5 KB
- samples/portal/.powerpages-site-backup/web-files/cat-pc.png/Cat-PC.png.webfile.yml444 B
- samples/portal/.powerpages-site-backup/web-files/index-BtOg51P5.js/index-BtOg51P5.js374.9 KB
- samples/portal/.powerpages-site-backup/web-files/index-BtOg51P5.js/index-BtOg51P5.js.webfile.yml508 B
- samples/portal/.powerpages-site-backup/web-files/index-CoAiucoc.css/index-CoAiucoc.css51.3 KB
- samples/portal/.powerpages-site-backup/web-files/index-CoAiucoc.css/index-CoAiucoc.css.webfile.yml497 B
- samples/portal/.powerpages-site-backup/web-files/index.html/index.html842 B
- samples/portal/.powerpages-site-backup/web-files/index.html/index.html.webfile.yml474 B
- samples/portal/.powerpages-site-backup/web-files/logo-sm-64.png/Logo-sm-64.png2.8 KB
- samples/portal/.powerpages-site-backup/web-files/logo-sm-64.png/Logo-sm-64.png.webfile.yml456 B
- samples/portal/.powerpages-site-backup/web-files/portalbasictheme.css/portalbasictheme.css26.2 KB
- samples/portal/.powerpages-site-backup/web-files/portalbasictheme.css/portalbasictheme.css.webfile.yml489 B
- samples/portal/.powerpages-site-backup/web-files/theme.css/theme.css29.8 KB
- samples/portal/.powerpages-site-backup/web-files/theme.css/theme.css.webfile.yml455 B
- samples/portal/.powerpages-site-backup/web-pages/access-denied/Access-Denied.webpage.copy.html0 B
- samples/portal/.powerpages-site-backup/web-pages/access-denied/Access-Denied.webpage.custom_css.css0 B
- samples/portal/.powerpages-site-backup/web-pages/access-denied/Access-Denied.webpage.custom_javascript.js0 B
- samples/portal/.powerpages-site-backup/web-pages/access-denied/Access-Denied.webpage.summary.html0 B
- samples/portal/.powerpages-site-backup/web-pages/access-denied/Access-Denied.webpage.yml381 B
- samples/portal/.powerpages-site-backup/web-pages/access-denied/content-pages/en-US/Access-Denied.webpage.copy.html1.1 KB
- samples/portal/.powerpages-site-backup/web-pages/access-denied/content-pages/en-US/Access-Denied.webpage.custom_css.css0 B
- samples/portal/.powerpages-site-backup/web-pages/access-denied/content-pages/en-US/Access-Denied.webpage.custom_javascript.js0 B
- samples/portal/.powerpages-site-backup/web-pages/access-denied/content-pages/en-US/Access-Denied.webpage.summary.html0 B
- samples/portal/.powerpages-site-backup/web-pages/access-denied/content-pages/en-US/Access-Denied.webpage.yml490 B
- samples/portal/.powerpages-site-backup/web-pages/assets/assets.webpage.copy.html0 B
- samples/portal/.powerpages-site-backup/web-pages/assets/assets.webpage.custom_css.css0 B
- samples/portal/.powerpages-site-backup/web-pages/assets/assets.webpage.custom_javascript.js0 B
- samples/portal/.powerpages-site-backup/web-pages/assets/assets.webpage.summary.html0 B
- samples/portal/.powerpages-site-backup/web-pages/assets/assets.webpage.yml425 B
- samples/portal/.powerpages-site-backup/web-pages/assets/content-pages/en-US/assets.webpage.copy.html0 B
- samples/portal/.powerpages-site-backup/web-pages/assets/content-pages/en-US/assets.webpage.custom_css.css0 B
- samples/portal/.powerpages-site-backup/web-pages/assets/content-pages/en-US/assets.webpage.custom_javascript.js0 B
- samples/portal/.powerpages-site-backup/web-pages/assets/content-pages/en-US/assets.webpage.summary.html0 B
- samples/portal/.powerpages-site-backup/web-pages/assets/content-pages/en-US/assets.webpage.yml534 B
- samples/portal/.powerpages-site-backup/web-pages/home/content-pages/en-US/Home.webpage.copy.html842 B
- samples/portal/.powerpages-site-backup/web-pages/home/content-pages/en-US/Home.webpage.custom_css.css0 B
- samples/portal/.powerpages-site-backup/web-pages/home/content-pages/en-US/Home.webpage.custom_javascript.js0 B
- samples/portal/.powerpages-site-backup/web-pages/home/content-pages/en-US/Home.webpage.summary.html76 B
- samples/portal/.powerpages-site-backup/web-pages/home/content-pages/en-US/Home.webpage.yml474 B
- samples/portal/.powerpages-site-backup/web-pages/home/Home.webpage.copy.html374 B
- samples/portal/.powerpages-site-backup/web-pages/home/Home.webpage.custom_css.css0 B
- samples/portal/.powerpages-site-backup/web-pages/home/Home.webpage.custom_javascript.js0 B
- samples/portal/.powerpages-site-backup/web-pages/home/Home.webpage.summary.html0 B
- samples/portal/.powerpages-site-backup/web-pages/home/Home.webpage.yml394 B
- samples/portal/.powerpages-site-backup/web-pages/page-not-found/content-pages/en-US/Page-Not-Found.webpage.copy.html1.1 KB
- samples/portal/.powerpages-site-backup/web-pages/page-not-found/content-pages/en-US/Page-Not-Found.webpage.custom_css.css0 B
- samples/portal/.powerpages-site-backup/web-pages/page-not-found/content-pages/en-US/Page-Not-Found.webpage.custom_javascript.js0 B
- samples/portal/.powerpages-site-backup/web-pages/page-not-found/content-pages/en-US/Page-Not-Found.webpage.summary.html0 B
- samples/portal/.powerpages-site-backup/web-pages/page-not-found/content-pages/en-US/Page-Not-Found.webpage.yml492 B
- samples/portal/.powerpages-site-backup/web-pages/page-not-found/Page-Not-Found.webpage.copy.html0 B
- samples/portal/.powerpages-site-backup/web-pages/page-not-found/Page-Not-Found.webpage.custom_css.css0 B
- samples/portal/.powerpages-site-backup/web-pages/page-not-found/Page-Not-Found.webpage.custom_javascript.js0 B
- samples/portal/.powerpages-site-backup/web-pages/page-not-found/Page-Not-Found.webpage.summary.html0 B
- samples/portal/.powerpages-site-backup/web-pages/page-not-found/Page-Not-Found.webpage.yml383 B
- samples/portal/.powerpages-site-backup/web-pages/profile/content-pages/en-US/Profile.webpage.copy.html478 B
- samples/portal/.powerpages-site-backup/web-pages/profile/content-pages/en-US/Profile.webpage.custom_css.css0 B
- samples/portal/.powerpages-site-backup/web-pages/profile/content-pages/en-US/Profile.webpage.custom_javascript.js0 B
- samples/portal/.powerpages-site-backup/web-pages/profile/content-pages/en-US/Profile.webpage.summary.html0 B
- samples/portal/.powerpages-site-backup/web-pages/profile/content-pages/en-US/Profile.webpage.yml494 B
- samples/portal/.powerpages-site-backup/web-pages/profile/Profile.webpage.copy.html0 B
- samples/portal/.powerpages-site-backup/web-pages/profile/Profile.webpage.custom_css.css0 B
- samples/portal/.powerpages-site-backup/web-pages/profile/Profile.webpage.custom_javascript.js0 B
- samples/portal/.powerpages-site-backup/web-pages/profile/Profile.webpage.summary.html0 B
- samples/portal/.powerpages-site-backup/web-pages/profile/Profile.webpage.yml385 B
- samples/portal/.powerpages-site-backup/web-pages/search/content-pages/en-US/Search.webpage.copy.html0 B
- samples/portal/.powerpages-site-backup/web-pages/search/content-pages/en-US/Search.webpage.custom_css.css0 B
- samples/portal/.powerpages-site-backup/web-pages/search/content-pages/en-US/Search.webpage.custom_javascript.js0 B
- samples/portal/.powerpages-site-backup/web-pages/search/content-pages/en-US/Search.webpage.summary.html0 B
- samples/portal/.powerpages-site-backup/web-pages/search/content-pages/en-US/Search.webpage.yml477 B
- samples/portal/.powerpages-site-backup/web-pages/search/Search.webpage.copy.html0 B
- samples/portal/.powerpages-site-backup/web-pages/search/Search.webpage.custom_css.css0 B
- samples/portal/.powerpages-site-backup/web-pages/search/Search.webpage.custom_javascript.js0 B
- samples/portal/.powerpages-site-backup/web-pages/search/Search.webpage.summary.html0 B
- samples/portal/.powerpages-site-backup/web-pages/search/Search.webpage.yml368 B
- samples/portal/.powerpages-site-backup/web-roles/Administrators.webrole.yml118 B
- samples/portal/.powerpages-site-backup/web-roles/Anonymous-Users.webrole.yml118 B
- samples/portal/.powerpages-site-backup/web-roles/Authenticated-Users.webrole.yml122 B
- samples/portal/.powerpages-site-backup/web-templates/breadcrumbs/Breadcrumbs.webtemplate.source.html387 B
- samples/portal/.powerpages-site-backup/web-templates/breadcrumbs/Breadcrumbs.webtemplate.yml59 B
- samples/portal/.powerpages-site-backup/web-templates/default-studio-template/Default-studio-template.webtemplate.source.html220 B
- samples/portal/.powerpages-site-backup/web-templates/default-studio-template/Default-studio-template.webtemplate.yml71 B
- samples/portal/.powerpages-site-backup/web-templates/footer/Footer.webtemplate.source.html6 B
- samples/portal/.powerpages-site-backup/web-templates/footer/Footer.webtemplate.yml54 B
- samples/portal/.powerpages-site-backup/web-templates/header/Header.webtemplate.source.html6 B
- samples/portal/.powerpages-site-backup/web-templates/header/Header.webtemplate.yml54 B
- samples/portal/.powerpages-site-backup/web-templates/languages-dropdown/Languages-Dropdown.webtemplate.source.html361 B
- samples/portal/.powerpages-site-backup/web-templates/languages-dropdown/Languages-Dropdown.webtemplate.yml66 B
- samples/portal/.powerpages-site-backup/web-templates/layout-2-column-wide-left/Layout-2-Column-Wide-Left.webtemplate.source.html553 B
- samples/portal/.powerpages-site-backup/web-templates/layout-2-column-wide-left/Layout-2-Column-Wide-Left.webtemplate.yml73 B
- samples/portal/.powerpages-site-backup/web-templates/page-copy/Page-Copy.webtemplate.source.html89 B
SKILL.md(原文)
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Power Pages Code Site (SPA) 開発・デプロイスキル
公式リファレンス: Power Pages でシングルページ アプリケーションを作成して展開する | Microsoft Learn 新スキル参照: microsoft/power-platform-skills - power-pages
サブリファレンス(必要に応じて参照)
| リファレンス | 内容 |
|---|---|
| upstream 優先構成ガイド | microsoft/power-platform-skills 基準での責務分離・実行順序・刷新方針 |
| Dataverse クライアント実装 | powerPagesFetch/powerPagesFetchResponse・WebApiErrorCode・OData ヘルパー・ページネーション・サービスレイヤーパターン・Code Apps との対比 |
| 認証実装 | SSO・サインアウト・ログインボタン・認証ガード・UI フローの実コード一式・サーバー側 IdP/サイト設定・Code Apps との対比 |
| 認証・認可・テーブル権限(詳細) | EDM 2.0 Code Site の認証/認可/テーブル権限・Web API 共有クライアント・SSO+プロフィール編集・Web ロール管理・テーブル Web API 有効化・site-settings 永続化 |
| Enhanced Data Model テーブル権限 | EDM 2.0 のテーブル権限設定・3 レイヤー権限・N:N バグ・ワークアラウンド |
| 運用と落とし穴 | ビルド・デプロイ・サイト再起動・よくあるエラーと解決策 |
| トラブルシューティング | エラーコード早見表・デバッグ用 Site Settings・既知の無害な警告 |
| レガシー参照用チェックリスト | 旧構成の参照用チェックリスト |
| デザインシステム | UI コンポーネント・テーマ・レイアウトの指針 |
| デザインテンプレート集 | 5 種類の配色テンプレート定義。設計時に提案→選択→適用 |
| アクセススコープ設計(Self / Account) | Self / Account の比較・scope 値・権限マトリクス・管理者への依頼テンプレート・セキュリティ根拠 |
| 紐づけ依頼メールフロー | 未紐づけユーザーから管理者への依頼テーブル設計・Power Automate フロー定義 |
| 管理者用紐づけ画面 | contact ↔ account を管理者が割り当てる Code Apps 画面の仕様(実装は code-apps/templates/account-link-admin) |
Dataverse 接続と認証の実装方法はこのファイルで概要を説明し、完全なサンプルコードは上記 References にまとめている。
刷新版の構成原則(upstream 優先)
このスキルは microsoft/power-platform-skills/plugins/power-pages の以下 4 スキルを優先参照して構成する。
| 領域 | upstream スキル | このスキル内の着地 |
|---|---|---|
| 認証・認可 | setup-auth | references/authentication.md |
| Web ロール | create-webroles | references/enhanced-data-model-permissions.md |
| Dataverse CRUD | integrate-webapi | references/dataverse-client.md |
| 権限監査 | audit-permissions | reviews/* + scripts/review_pre_deploy.py |
標準実行順序(刷新後)
- デプロイ基盤準備(
.powerpages-site作成) - Web ロール整備
- 認証導線(SSO/ログイン/ログアウト)整備
- Dataverse Web API CRUD 実装
- 権限監査(ロール・テーブル権限整合)
⚠️ デプロイ後の必須ステップ:
pac pages upload-code-siteでテーブル権限 YAML をデプロイしても、 type=18 の content JSON 内adx_entitypermission_webroleが空のまま残り、Web ロール紐付けが効かない。デプロイ直後にpython scripts/setup_permissions.pyを実行して content のadx_entitypermission_webroleを書き込み、review_pre_deploy.pyの チェック 3.7 が ✅ になることを確認する(さもないと管理者を含む全ユーザーが 403)。詳細は教訓 14。
詳細な責務分離と判断基準は upstream 優先構成ガイド を正本として扱う。
microsoft/power-platform-skills 比較(認証・認可 vs Dataverse CRUD)
| 観点 | ユーザー認証・Webロール認可 | Dataverse Web API 連携 CRUD |
|---|---|---|
| 上流スキル | setup-auth + create-webroles | integrate-webapi |
| 主目的 | ログイン/ログアウト、認証状態判定、ロールベース UI 制御 | /_api 経由の読み書き(powerPagesFetch/powerPagesFetchResponse、OData ヘルパー) |
| 主な成果物 | authService.ts(AUTH_PROVIDERS 配列)・use-auth.ts・ログイン UI・Web ロール YAML(.powerpages-site/web-roles/) | powerPagesApi.ts、テーブル別 service/hooks、CRUD 画面 |
| サーバー側必須設定 | IdP site settings、Web ロール、テーブル権限へのロール紐付け | テーブル権限(type=18 + adx_entitypermission_webrole)、必要時のみ Webapi 設定 |
| 失敗時の代表症状 | ログインループ、/profile 強制遷移、未認証判定ミス | 401(90040107) / 403 / 404(9004010C, 9004010D) |
| 依存関係 | 先に認証導線を整える(ユーザー実体: contact) | 認証済みセッション Cookie 前提で CRUD を実行 |
推奨適用順:
setup-authで認証導線を整備create-webrolesでロールを確定integrate-webapiで CRUD 実装audit-permissionsで権限妥当性を最終監査
核心原則
pac pages upload-code-siteがサイト作成とデプロイの両方を行う — API でサイトを事前作成する必要はない- 初回は Inactive Sites に作成される → PP API (
2022-03-01-preview) でactivate_site.pyを使ってアクティブ化 - デプロイは upload-code-site → relink → restart の3ステップ —
upload-code-siteは既存テーブル権限の Web ロール紐付けを消すため、毎回scripts/relink_table_permissions.py(または統合のscripts/deploy_site.py)で再付与する(教訓 15)。npm run deploy(build && upload-code-site だけ)で終わらせない - Post-Upload Fix は不要 —
upload-code-siteが header/footer/page を正しく構成する .powerpages-site/は upload-code-site が自動管理する — ただしsite-settings/YAML は手動追加して永続化できる(下記参照)adx_websiteレコードは絶対に削除しない — EDM 2.0 でもランタイムが起動時に参照する- 環境のクリーンアップ時は PP API のサイト一覧と照合してから削除する — 誤削除で 500 エラー
credentials: "same-origin"を使う —"include"ではない(same-site Cookie 認証)- powerpagecomponent type=18 には
powerpagesitelanguageidが必須 — 未設定だと 404 になる - 報告者・作成者は Contact Lookup で追跡する — Power Pages では
createdbyはアプリケーションユーザーになるため使えない。ログインユーザーの Contact 情報を自動取得し入力不要にする(教訓 19) - デザイン系の変更は必ず
npm run dev(localhost)で見た目を確認してから本番デプロイする — 本番デプロイ → ブラウザ確認 → 再デプロイのループは 1 サイクルあたり数十秒〜数分かかり非効率。レイアウト・配色・レスポンシブ崩れは localhost で先に潰し、本番デプロイは最終確認のみに留める(教訓 20)。ただし Power Pages 本体のテーマ CSS(Bootstrap 既定の見出し色など)はローカルには存在せず本番でのみ衝突しうるため、色指定は見出し要素に明示的なcolorを必ず設定し、デプロイ後の最終確認も省略しない(詳細は トラブルシューティング) - 取引先企業(
account)配下の「業務テーブル」は Account スコープ(756150002)で権限を切る — 全件公開になるグローバルアクセスで逃げない。子テーブル権限(accountrelationship+ create)を作り、POST 時に account Lookup を@odata.bindする。readは通るのにcreateだけ 403 になる典型パターンの原因(教訓 21) accountテーブル自身に Account スコープを設定してはいけない — Web API が 500(9004010A)を返し、会社名の参照も子レコードの bind も一切できなくなる。正解は Contact スコープ(756150001)+contact_customer_accounts。これで「自分のparentcustomeridが指す 1 件」だけが返る(実機検証済み)- Lookup バインドには参照する側・される側「両方」の 追加(Append)と 追加先(AppendTo)が要る — 片側だけでは 403。
You don't have permission to associate or disassociate table X to Yが出たら、まず不足している側の権限を疑う(実機で 4 通りの真理値表を検証済み) - account Lookup を省いた POST は 403 ではなく 201 で通ってしまう — できるのは誰にも見えない孤立レコード。テーブル権限では防げないため、クライアント側で account 未取得なら作成 UI を出さない+サーバー側(フロー等)で
nullを検知する二段構えにする(実機検証済み)
ワークフロー
初回:
npm run build
→ pac pages upload-code-site ← Inactive Sites に作成
→ py portal/scripts/activate_site.py ← PP API でアクティブ化 (api-version=2022-03-01-preview)
→ py portal/scripts/setup_contact_webapi.py
→ py .github/skills/power-pages/scripts/setup_inquiry_reporter.py ← 報告者 Contact Lookup (教訓 19)
→ py .github/skills/power-pages/scripts/relink_table_permissions.py ← ★ロール再付与+再起動
2回目以降(推奨: 統合スクリプトで一括実行):
py .github/skills/power-pages/scripts/deploy_site.py
(ビルド → upload-code-site → ★relink → 検証 → 再起動 を 1 コマンドで実行)
2回目以降(手動の場合):
npm run build → pac pages upload-code-site
→ py .github/skills/power-pages/scripts/relink_table_permissions.py ← ★必須(省くと 403)
Account アクセスを採用する場合(初回デプロイ後に 1 回だけ・実機検証済みの順序):
py .github/skills/power-pages/scripts/setup_access_scope.py --scope account
→ py .github/skills/power-pages/scripts/setup_account_link_request.py
→ py .github/skills/power-pages/scripts/deploy_flow_account_link_request.py
→ 管理者用 Code App をデプロイ(code-apps/templates/account-link-admin)
→ py .github/skills/power-pages/scripts/setup_access_scope.py --scope account --verify-only
⚠️
PAGES_SITE_NAMEを.envに必ず設定する。未設定だと最終更新のサイトが暗黙で選ばれ、 別サイトに権限を書き込む事故が起きる。
⚠️
npm run build && pac pages upload-code-siteだけで終わらせると、既存テーブル権限の Web ロール紐付けが消えて全件 403 になる(教訓 15)。relink_table_permissions.pyを 毎回実行するか、deploy_site.pyで一括実行すること。両スクリプトともハードコードなし・ すべて.env管理(DATAVERSE_URL/ENV_ID/PAGES_WEBSITE_ID/PP_SUBDOMAIN/RELINK_WEBROLE_NAMES/PORTAL_DIR)。
アクティベーション詳細
初回の pac pages upload-code-site はサイトを Inactive Sites に作成する。
アクティブ化は Power Platform API (api-version=2022-03-01-preview) で行う。
POST https://api.powerplatform.com/powerpages/environments/{ENV_ID}/websites?api-version=2022-03-01-preview
Body:
{
"name": "<PAGES_SITE_NAME>",
"subdomain": "<PAGES_SUBDOMAIN>",
"templateName": "DefaultPortalTemplate",
"dataverseOrganizationId": "<org_id>",
"selectedBaseLanguage": 1033,
"websiteRecordId": "<powerpagesiteid>" ← pac pages upload-code-site が作った ID
}
Response: 202 Accepted + Operation-Location ヘッダー
→ Operation-Location を 10 秒間隔でポーリング
→ OperationComplete = 成功、OperationFailed = 失敗
| パラメータ | 取得方法 |
|---|---|
ENV_ID | .env |
PAGES_SITE_NAME | .env / powerpages.config.json の siteName |
PAGES_SUBDOMAIN | .env / ユーザー指定 |
dataverseOrganizationId | GET /api/data/v9.2/organizations?$select=organizationid |
websiteRecordId | GET /api/data/v9.2/powerpagesites から name で検索 |
⚠️ API バージョン注意: 2022-03-01-preview を使用すること。2024-10-01 ではアクティベーションが正しく動作しない。
前提条件・事前確認(会話の最初に 1 回だけ)
作業開始前に、standard の共通契約に加え、 1 回の AskUserQuestion で次をまとめて確認する。
| # | 質問 | 合格条件 |
|---|---|---|
| 1 | 対象環境、サイト名、subdomain、サイト種別は何か | 新規 / 更新、公開 URL、開発・テスト・本番の対象が確定している |
| 2 | Power Pages のライセンス / capacity は利用可能か | 認証ユーザー / 匿名ユーザーの想定数と課金方式を確認している |
| 3 | 認証方式とアクセス scope は何か | anonymous / authenticated、Self / Account、IdP、Web role、table permission を承認済みである |
| 4 | サイトと Dataverse を変更する担当者は誰か | Code Site の upload、site settings、Web role、table permission を変更できる担当者を記録している |
| 5 | 公開データとセキュリティ検証は何か | 公開列、PII、未認証時の期待値、403 / 200 のテスト担当者を確定している |
| 6 | デプロイ後の relink / restart を実施できるか | deploy_site.py または upload → relink → restart の一連を実行することで合意している |
環境全体の System Administrator を既定にせず、サイト管理と対象 Dataverse 構成に必要な
権限を持つ担当者を使用する。認証、scope、Web role、table permission のいずれかが未確定なら
外部公開へ進まない。
| ツール | バージョン | 用途 |
|---|---|---|
pac (Power Platform CLI) | 1.44+ | サイト作成・アップロード |
node + npm | 18+ | SPA ビルド |
| Python 3 | 3.10+ | デプロイスクリプト(任意) |
pac CLI 注意: サブコマンドは
pac pages(例:pac pages list,pac pages upload-code-site)。pac power-pagesは無効。pac pages helpでコマンド一覧を確認できる。
.env パラメータ
DATAVERSE_URL=https://{org}.crm.dynamics.com/
ENV_ID= # Power Platform 環境 ID
PAGES_SITE_NAME= # サイト名 (powerpages.config.json の siteName と一致)
PAGES_SUBDOMAIN= # サブドメイン (例: myportal → myportal.powerappsportals.com)
# Account アクセススコープを使う場合(Step 4)
ACCESS_SCOPE=account # self | account
ACCOUNT_CHILD_TABLES= # 論理名:リレーションスキーマ名 のカンマ区切り
ACCOUNT_LINK_REQUEST_TABLE= # 紐づけ依頼テーブルの論理名
ACCOUNT_LINK_REQUEST_RELATIONSHIP= # contact との 1:N スキーマ名
ACCOUNT_LINK_ADMIN_RECIPIENT= # 依頼通知メールの宛先(配布リスト推奨)
プロジェクト構造(公式準拠 / upstream 推奨)
portal/
├── src/
│ ├── App.tsx ← ルート (HashRouter + Routes)
│ ├── main.tsx ← エントリポイント
│ ├── index.css ← Tailwind CSS
│ ├── components/
│ │ ├── site-layout.tsx ← ヘッダー・ナビ・プロフィールドロップダウン
│ │ ├── require-auth.tsx ← 認証ガードコンポーネント
│ │ ├── mode-toggle.tsx ← ダーク/ライト切替
│ │ └── ui/ ← shadcn/ui コンポーネント
│ ├── hooks/
│ │ └── use-auth.ts ← SSO 認証フック
│ ├── shared/
│ │ ├── powerPagesApi.ts ← ★ Web API 共有クライアント (powerPagesFetch/buildODataUrl 等)
│ │ └── services/
│ │ └── <table>Service.ts ← テーブルごとの CRUD サービス
│ ├── types/
│ │ └── <table>.ts ← エンティティ型・ドメイン型・マッパー
│ ├── lib/
│ │ └── utils.ts ← cn() ユーティリティ
│ ├── config.ts ← サイト名・ロゴ等のブランディング設定(.env の VITE_* を集約)
│ └── pages/
│ ├── home.tsx ← ランディングページ
│ └── profile.tsx ← プロフィール編集 (★ powerPagesApi.ts を使用)
├── dist-site/ ← ビルド出力 (compiledPath)
├── .powerpages-site/ ← upload-code-site が管理 + site-settings YAML 手動追加可
│ └── site-settings/ ← Webapi/* 設定を YAML で永続化
├── .env.example ← ★ ブランディング等の VITE_* 変数サンプル(コピーして .env を作成)
├── powerpages.config.json ← CLI 設定ファイル (必須)
├── package.json
├── vite.config.ts
└── scripts/
├── deploy.py ← デプロイスクリプト (Build→Upload→Restart)
├── activate_site.py ← PP API サイトアクティベーション
├── setup_auth.py ← Entra ID SSO 認証設定 (Site Settings + Liquid 注入)
└── setup_contact_webapi.py ← Contact Web API 有効化 (EDM 2.0 対応)
サイト名・ロゴのブランディング設定(.env / src/config.ts)
デプロイごとに変わるブランディング値はコードに直書きせず、ビルド時の環境変数で差し替える。
テンプレートの .env.example を .env にコピーして値を編集する(.env は .gitignore 済み)。
cp .env.example .env # 値を編集してから npm run build
| 変数 | 用途 | 既定値 |
|---|---|---|
VITE_SITE_NAME | サイト/ブランド表示名(ヘッダーロゴ・フッター・ブラウザタブのタイトル) | Power Pages |
VITE_SITE_LOGO_MARK | ヘッダーロゴのマーク(1〜2 文字の頭文字) | P |
- すべて
VITE_プレフィックス必須(Vite はこの接頭辞の変数のみクライアントへ公開)。 - 値は
src/config.ts(SITE_NAME/SITE_LOGO_MARK)に集約し、未設定時は既定値へフォールバック。 - バンドルに同梱されブラウザに露出するため、秘密情報は置かない。
home.tsx/site-layout.tsxは@/configを import して参照、main.tsxがdocument.titleを設定。
powerpages.config.json(必須)
{
"siteName": "MySite",
"compiledPath": "dist-site",
"defaultLandingPage": "index.html"
}
bundleFilePatterns(オプション)
pac pages upload-code-site は古いバンドルファイルを自動クリーンアップする。
デフォルトパターン: main.*.js, main.*.css, vendor.*.js, index-*.js, index-*.css 等 10 種。
Vite のデフォルト出力(index-{hash}.js)はカバーされるが、カスタムの命名規則を使う場合は明示指定する:
{
"siteName": "MySite",
"compiledPath": "dist-site",
"defaultLandingPage": "index.html",
"bundleFilePatterns": ["app.*.js", "app.*.css", "style.*.css"]
}
テンプレートとサンプルの使い分け
| フォルダ | 種別 | 内容 | 使いどころ |
|---|---|---|---|
| templates/corporate-lp/ | プロジェクト雛形 | React + TypeScript + Vite + shadcn/ui。認証導線・/profile・Dataverse クライアント込み | 新規開発の既定の出発点。コピーして中身を差し替える |
| templates/minimal-code-site/ | プロジェクト雛形 | ビルド不要の素の HTML/CSS/JS 1 セット | upload-code-site → アクティブ化 → 再起動の配線だけを疎通確認したいとき |
| templates/access-scope/ | 部分テンプレート(コード片) | 取引先企業の読み取り専用表示と紐づけ依頼ボタン | 既存アプリに機能として追加する(雛形ではない) |
| samples/portal/ | 参照用サンプル | 動作済みサイトの実体(.powerpages-site の web-templates / page-templates を含む) | 実装の答え合わせ・生成物の構造確認。コピー元にはしない |
templates/= コピーして使うもの、samples/= 読んで参考にするもの。 プロジェクト雛形は共通スキャフォルダーで生成し、部分テンプレートは空のステージング先へ 生成してから該当ファイルだけを既存のsrc/hooks/やsrc/components/に配置する。
テンプレートから開始する
生成計画を確認し、問題がなければ --dry-run を外して実行する。
# React + TypeScript + Vite の既定プロジェクト
python .github/skills/update-skills/scripts/scaffold_from_template.py `
--template .github/skills/power-pages/templates/corporate-lp `
--target portal --var PAGES_SITE_NAME="My Site" --dry-run
# 配線確認用の最小 Code Site
python .github/skills/update-skills/scripts/scaffold_from_template.py `
--template .github/skills/power-pages/templates/minimal-code-site `
--target portal-smoke --var PAGES_SITE_NAME="My Smoke Site" --dry-run
# Account アクセス用アドオン(空のステージング先へ生成する)
python .github/skills/update-skills/scripts/scaffold_from_template.py `
--template .github/skills/power-pages/templates/access-scope `
--target .scaffold/access-scope --dry-run
access-scopeを既存プロジェクト直下へ--forceで生成しない。生成後に必要な2ファイルを ホストプロジェクトへ統合する。
Step 1: SPA 開発
Vite 設定(必須制約)
// vite.config.ts
export default defineConfig({
base: "./", // 相対パス(必須)
build: {
outDir: "dist-site", // powerpages.config.json と一致
rollupOptions: {
output: { inlineDynamicImports: true }, // 単一バンドル(推奨)
},
},
});
| 制約 | 理由 |
|---|---|
base: "./" | Power Pages のパス構造に対応 |
inlineDynamicImports: true | コード分割するとロード順問題が発生 |
| Hash ルーティング必須 | History API モードは直接 URL アクセスで 404 |
| 静的 SPA のみ | SSR / ISR 非対応 |
package.json scripts
{
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"upload": "pac pages upload-code-site --rootPath . --compiledPath ./dist",
"deploy": "py ../.github/skills/power-pages/scripts/deploy_site.py"
}
}
★ ローカル確認を先に行う(デザイン変更時は必須)
レイアウト・配色・レスポンシブ対応など見た目に関わる変更は、本番デプロイ前に必ず npm run dev で確認する。
cd portal
npm run dev # http://localhost:5173 などで起動
# ブラウザで表示・配色・レスポンシブを確認してから次のコミット/デプロイへ進む
| 確認できること | 確認できないこと(デプロイ後に要再確認) |
|---|---|
| コンポーネント構造・レイアウト崩れ・レスポンシブ | Power Pages 本体のテーマ CSS との衝突(例: Bootstrap 既定の見出し色が明示指定のない <h1> 等に強制適用される) |
| 自前 CSS の配色・グラデーション・アニメーション | 認証リダイレクト・Web ロール・テーブル権限まわりの挙動 |
| コンポーネント間の状態遷移・フォームバリデーション | Power Pages ランタイムが注入する外部スクリプト/スタイルとの相互作用 |
教訓 20:
<h1>等の見出し要素は、親要素にcolor: #fffを設定していても Power Pages 本体のテーマ CSS(h1への既定色指定)に上書きされることがある(継承より明示指定が常に優先されるため)。見出し要素には必ず明示的にcolorを指定し、ローカル確認だけで満足せず本番デプロイ後にも目視確認する。
Step 2: 初回デプロイ
2-A: JavaScript ファイルのアップロード許可
環境で .js がブロックされている場合:
- Power Platform 管理センター → 環境選択
- 設定 → プライバシー + セキュリティ
- ブロックされた添付ファイルから
jsを削除
2-B: ビルド & アップロード
cd portal
npm run build
pac pages upload-code-site --rootPath .
2-C: サイトのアクティブ化(PP API 経由)
py portal/scripts/activate_site.py
スクリプトが以下を自動実行:
- PP API でサイトが既にアクティブか確認
- Dataverse から Organization ID と Website Record ID を取得
- パラメータ確認後、PP API に POST
- Operation-Location をポーリングして完了待ち(最大 5 分)
カスタムサブドメインを指定する場合:
py portal/scripts/activate_site.py --subdomain my-portal
2-D: Contact Web API 有効化(★初回必須)
py portal/scripts/setup_contact_webapi.py
2-E: サイト再起動
py .github/skills/standard/scripts/_restart.py
アクティブ化後、URL にアクセスできるまで 60〜90秒 かかる。
Step 3: 再デプロイ(2回目以降)
推奨: 統合スクリプトで一括実行(再現性が高い)
cd portal
py ../.github/skills/power-pages/scripts/deploy_site.py
# ビルド → upload-code-site → ★ロール再付与 → 検証 → 再起動 を 1 コマンドで実行する。
# upload-code-site が消す Web ロール紐付けを毎回必ず再付与するため、relink 忘れによる
# 全件 403 事故(教訓 15)を構造的に防ぐ。ハードコードなし・すべて .env 管理。
手動で段階実行する場合
cd portal
npm run build
pac pages upload-code-site --rootPath . --compiledPath ./dist
# ★ upload-code-site は既存 type=18 の content.adx_entitypermission_webrole を消すため、
# デプロイのたびに全テーブル権限の Web ロールを再付与する(教訓 15)。これを省くと 403。
py ../.github/skills/power-pages/scripts/relink_table_permissions.py
# → relink スクリプトが PAGES_WEBSITE_ID(推奨)または PP_SUBDOMAIN 設定時に自動で再起動する
# (未設定の場合は手動再起動)
/profile(contact Self)を使う場合は、初回のみsetup_contact_self.pyで contact 権限とWebapi/contact/enabled|fieldsを作成しておく(教訓 16):py ../.github/skills/power-pages/scripts/setup_contact_self.py
取引先企業(
account)配下のレコードを扱う場合や、参照可能範囲を Self / Account から 選ぶ場合は Step 4 を実行する(教訓 21)。
Step 4: アクセススコープを決めてテーブル権限を構成する(Self / Account)
サインインユーザーが誰のデータを見られるかを確定し、そのスコープで権限・UI・運用を揃える。 背景と根拠は アクセススコープ設計。
4-A: AskUserQuestion でスコープを確定する(実装前に必須)
テーブル権限を作る前に必ず質問する。 ここを飛ばすと権限・UI・運用を同時にやり直すことになる。
| # | 質問 | 選択肢 |
|---|---|---|
| 1 | サインインユーザーの参照可能範囲は? | Self アクセス(本人のレコードだけ)/ Account アクセス(所属する取引先企業配下) |
| 2 | (Account のときのみ)管理者が contact ↔ 取引先企業を紐づける Code Apps 管理画面をどう用意しますか? | テンプレートから作成する(既定) / 作成しない(モデル駆動型アプリで運用) |
- Self アクセス — 本人の
contactと本人が作成したレコードのみ。BtoC・個人利用向け。 - Account アクセス —
contactに紐づく 取引先企業(account)配下を同僚と共有。BtoB ポータル向け。
回答を .env の ACCESS_SCOPE(self / account)と ADMIN_LINK_APP(true / false)に記録し、
以降の分岐に使う。迷っている場合の既定は Self(後から Account を足せるが、逆は利用者影響が大きい)。
Account を選んだら紐づけ手段は必須。
contact.parentcustomeridが空のままではどのデータも見えないため、 質問 2 は「作る/作らない」ではなく「Code Apps 管理画面か、モデル駆動型アプリ運用か」の選択である。 既定は templates/account-link-admin からの作成(ADMIN_LINK_APP=true)。
4-B: リレーションスキーマ名を控える
権限に指定するのはリレーションのスキーマ名であり、表示名でも Lookup 列名でもない。
cd portal
python ../.github/skills/power-pages/scripts/setup_access_scope.py --list-relationships
4-C: Self アクセスを構成する
python ../.github/skills/power-pages/scripts/setup_access_scope.py --scope self
contact:scope=756150004(Self)read/write、appendto=true- 業務テーブル:
scope=756150001(Contact)+contactrelationship、read/write/create - 各テーブルに
Webapi/{table}/enabled=trueとWebapi/{table}/fields
4-D: Account アクセスを構成する
サインイン時に作られた contact に関連付いている account を
参照できるが編集・削除はできない権限セットにする。
# .env の ACCOUNT_CHILD_TABLES(論理名:リレーションスキーマ名 のカンマ区切り)を使う
python ../.github/skills/power-pages/scripts/setup_access_scope.py --scope account
| # | テーブル | scope | リレーション | read | write | create | delete | append | appendto |
|---|---|---|---|---|---|---|---|---|---|
| 1 | account | Contact(756150001) | contact_customer_accounts | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ |
| 2 | 業務テーブル | Account(756150002) | accountrelationship | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
| 3 | contact | Self(756150004) | なし | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ |
- #1 に Account スコープを使わない。
accountテーブル自身を Account スコープにすると Web API が 500(9004010A)を返し、参照も bind もできなくなる(実機検証済み)。 Contact スコープ +contact_customer_accounts(account 1:N contact =parentcustomerid)にすれば 自社 1 件だけが返る。verify()は旧構成が残っていたら NG を出す。 - #1 の
write/deleteは必ずfalse。スクリプトは送信直前に検証し、trueなら中止する。 append/appendtoは編集権限ではない。Lookup バインドには 参照する側とされる側の両方でappendとappendtoが必要で、片側だけだと 403 になる。- Web ロールは既定で Authenticated Users。専用ロールにする場合は
ACCESS_SCOPE_WEBROLE_NAMEを設定する (存在しなければ作成されるが、contact への割り当ては別途必要)。 - グローバルアクセス(
756150000)で代用しない。全社の取引先企業が全ユーザーに見えてしまう。 - account Lookup を省いた POST は 201 で通る(403 にならない)。できるのは誰にも見えない 孤立レコードなので、クライアント側で account 未取得なら作成 UI を出さないこと。
4-E: 取引先企業をプロファイル画面に読み取り専用で表示する
/profile に会社情報を表示専用で出す(入力欄にしない)。
const me = await powerPagesFetch<{ _parentcustomerid_value: string | null }>(
`/_api/contacts(${user.contactId})?$select=_parentcustomerid_value`
);
const accountId = me._parentcustomerid_value; // null = 未紐づけ
実装は templates/access-scope/ の use-account-access.ts /
AccountProfileSection.tsx を src/hooks/・src/components/ に配置する。
なぜユーザーに選ばせないのか: 取引先企業を自由に選べると、他社を選ぶだけで 他社データにアクセスできてしまう(権限昇格)。紐づけはアプリ管理者だけが行う。
Webapi/contact/fieldsにparentcustomeridを含めない運用にすると PATCH 自体が拒否され二重に安全。
4-F: 未紐づけユーザー向けの「管理者に紐づけを依頼」を構成する
-
依頼テーブル
{prefix}_accountlinkrequestを作成する(dataverse スキル、 列定義は 紐づけ依頼メールフロー)。 -
依頼テーブルの権限と Web API を作成する(作成と自分の依頼の参照だけを許可)。
python ../.github/skills/power-pages/scripts/setup_account_link_request.py -
依頼メール送信フローをデプロイする。
python ../.github/skills/power-pages/scripts/deploy_flow_account_link_request.py接続参照の作成 → フロー作成 → 有効化 → Webhook 登録(
/start)までを自動で行う。 事前に Dataverse と Office 365 Outlook の接続を make.powerautomate.com で作っておく(API では作れない)。 トリガーは Dataverse「行が追加されたとき」、アクションは Office 365 Outlook「メールの送信」。 宛先は.envのACCOUNT_LINK_ADMIN_RECIPIENT。 -
プロファイル画面のボタンから依頼レコードを POST する(テンプレート実装済み)。
HTTP トリガーのフローを直接呼ばない。匿名で叩ける URL は踏み台になる。 認証済みセッションで Dataverse にレコードを作り、サーバー側のフローで送信する。
4-G: 管理者用 Code Apps 画面を構築する(Account アクセスでは必須)
アドオンテンプレート code-apps/templates/account-link-admin を使う。
code-apps スキルで generic-base から scaffold し、テンプレートの src/ を重ねて
ルート(/account-link)とナビ項目を追加するだけで動く。データソースは
shared_commondataserviceforapps を 1 回追加すれば contacts / accounts /
{prefix}_accountlinkrequests をすべて扱える。
画面仕様・更新処理・監査の考え方は 管理者用紐づけ画面 に従う。 「作成しない」を選んだ場合は、モデル駆動型アプリの取引先担当者フォームで 取引先企業を設定する運用手順を README に記載する(紐づけ手段そのものは省略できない)。
4-H: 検証する
python ../.github/skills/power-pages/scripts/setup_access_scope.py --scope account --verify-only
- 4-A の AskUserQuestion を実施し、
.envのACCESS_SCOPEに記録した -
account権限は Contact スコープ +contact_customer_accountsで read のみ(write/deleteがfalse) -
account/ 業務テーブル /contactのすべてにappendとappendtoがある - 業務テーブル権限に
accountrelationship(スキーマ名)とcreate=trueがある - すべての type=18 に Web ロールが content JSON と N:N association の両方で紐付いている
-
Webapi/{table}/enabled|fieldsがアクセスする全テーブルにある - プロファイル画面で取引先企業が読み取り専用で表示される
- 未紐づけユーザーに依頼ボタンが出て、押すとメールが届く
-
upload-code-siteの後にrelink_table_permissions.pyを実行した(省くと全件 403)
再起動の反映には 60〜90 秒かかる。確認は InPrivate ウィンドウで行う。 異常系は トラブルシューティング を参照。
レビュースキル(品質ゲート)
Power Pages の品質を標準的に維持するための 設計前レビュー と デプロイ前レビュー を提供する。
| レビュー | タイミング | ドキュメント | スクリプト |
|---|---|---|---|
| 設計前レビュー | テーブル設計完了後、SPA 実装開始前 | reviews/pre-design-review.md | scripts/review_pre_design.py |
| デプロイ前レビュー | npm run build 後、pac pages upload-code-site 前 | reviews/pre-deploy-review.md | scripts/review_pre_deploy.py |
呼び出し方
# 設計前レビュー(ローカル静的チェックのみ、Dataverse 接続不要)
cd portal
python ../.github/skills/power-pages/scripts/review_pre_design.py
# デプロイ前レビュー(ビルド出力 + Dataverse API チェック)
cd portal
python ../.github/skills/power-pages/scripts/review_pre_deploy.py
# CI/CD でリモートチェックをスキップする場合
SKIP_REMOTE=1 python ../.github/skills/power-pages/scripts/review_pre_deploy.py
標準フロー: 設計前レビュー → 実装 →
npm run devでローカル確認(デザイン変更時は必須・教訓 20) → ビルド → デプロイ前レビュー → デプロイ → 本番での目視確認
レビュー
まだレビューはありません。使ってみた感想をお寄せください。
同じリポジトリのスキル
概要と使いどころ
Copilot Studio 新 UI の Agent flows / Workflows を構築・公開・検証する。Dataverse レコード作成/更新トリガーから既存の発行済み Copilot Studio v2 を Agent ノードで呼ぶ標準経路、Code Apps との非同期要求/結果連携、および手動 Start + inline Agent の API ライフサイクル検証を扱う。
株主総会の想定問答を、IR 抜粋(決算短信・説明資料・招集通知など)を根拠に下書きし、利用者の確認後に Dataverse の想定問答テーブルへ「下書き」として登録するスキル。 Use when ユーザーが「配当について想定問答を作って」「この論点の想定問答を 3 件追加して」「招集通知から想定問答を作って」「想定問答を登録して」と依頼したとき。 Dataverse MCP コネクタ(describe / read_query / search_data / create_record / update_record)を使用する。削除・テーブル変更のツールは使わない。
株主総会の想定問答を点検し、根拠の IR 抜粋に無い数値・存在しない根拠 ID・回答者や注意事項の抜け・趣旨の重複・下書きのまま残っているものを一覧にするスキル(書き込みはしない)。 Use when ユーザーが「想定問答を点検して」「根拠の無い数値が無いか確認して」「下書きの想定問答を一覧にして」と依頼したとき。 Dataverse MCP コネクタ(describe / read_query / search_data)を使用する。書き込み・削除のツールは使わない。
株主総会の質疑応答のリハーサル台本(議長・株主・回答役員の読み上げ原稿)を、承認済みの想定問答から作り、Dataverse のリハーサル台本テーブルへ登録するスキル。 Use when ユーザーが「リハーサルの台本を作って」「QA-001〜QA-010 で読み上げ原稿を作って」「番号を言わない株主も入れた台本を作って」と依頼したとき。 Dataverse MCP コネクタ(describe / read_query / search_data / create_record / update_record)を使用する。削除・テーブル変更のツールは使わない。
AI Builder の AI プロンプト(GPT Dynamic Prompt)を Dataverse API で作成し、Copilot Studio エージェントにツール(アクション)として追加する。Power Automate フローとの統合パターンも含む。