add-server-logic

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese
Plugin check: Run
node "${CLAUDE_PLUGIN_ROOT}/scripts/check-version.js"
— if it outputs a message, show it to the user before proceeding.
插件检查:运行
node "${CLAUDE_PLUGIN_ROOT}/scripts/check-version.js"
— 如果脚本输出消息,请在继续操作前展示给用户。

Add Server Logic

添加Server Logic

Create and manage one or more Power Pages Server Logic files — server-side JavaScript that runs securely on the Power Pages runtime, hidden from the browser and protected by web roles and table permissions. Server Logic enables secure external API integrations, Dataverse operations, and custom business logic without exposing sensitive code or credentials to the client.
创建并管理一个或多个Power Pages Server Logic文件——这种服务器端JavaScript在Power Pages运行时环境中安全运行,对浏览器不可见,并受Web角色和表权限保护。Server Logic支持安全的外部API集成、Dataverse操作以及自定义业务逻辑,无需向客户端暴露敏感代码或凭据。

Core Principles

核心原则

  • Microsoft Learn is the source of truth: Always fetch the latest documentation before writing code. The Server Logic feature is in preview and the SDK may change — never rely on cached knowledge alone.
  • No browser APIs, no dependencies: Server Logic runs in a sandboxed server environment with ECMAScript 2023 support. There is no
    fetch
    ,
    XMLHttpRequest
    ,
    setTimeout
    , or any DOM API. No npm packages are available.
  • Five functions only: A server logic file can only export these top-level functions:
    get
    ,
    post
    ,
    put
    ,
    patch
    ,
    del
    . The name
    delete
    is a reserved word in JavaScript and cannot be used.
  • Always return a string: Every function must return a string. Use
    JSON.stringify()
    when returning objects or arrays.
  • Use TaskCreate/TaskUpdate: Track all progress throughout all phases — create the todo list upfront with all phases before starting any work.
Prerequisites:
  • An existing Power Pages code site created
  • The site must be deployed at least once (
    .powerpages-site
    folder must exist) — server logic files live inside
    .powerpages-site/server-logic/
    , so deployment is required before any server logic can be created
Initial request: $ARGUMENTS

  • Microsoft Learn为权威来源:编写代码前务必获取最新文档。Server Logic功能目前处于预览阶段,SDK可能会发生变化——切勿仅依赖缓存的知识。
  • 无浏览器API,无依赖项:Server Logic在支持ECMAScript 2023的沙箱服务器环境中运行。不存在
    fetch
    XMLHttpRequest
    setTimeout
    或任何DOM API,也无法使用npm包。
  • 仅支持五种函数:Server Logic文件只能导出以下顶级函数:
    get
    post
    put
    patch
    del
    delete
    是JavaScript的保留字,无法使用。
  • 始终返回字符串:每个函数必须返回字符串。返回对象或数组时请使用
    JSON.stringify()
  • 使用TaskCreate/TaskUpdate:在所有阶段全程跟踪进度——在开始任何工作前,提前创建包含所有阶段的待办事项列表。
前提条件:
  • 已创建现有的Power Pages代码站点
  • 站点必须至少部署过一次(必须存在
    .powerpages-site
    文件夹)——Server Logic文件存储在
    .powerpages-site/server-logic/
    目录下,因此在创建任何Server Logic前必须完成部署
初始请求: $ARGUMENTS

Workflow

工作流程

  1. Verify Site Exists — Locate the Power Pages project, explore existing patterns, and verify prerequisites
  2. Understand Requirements — Determine the user intent and whether the solution needs one or more server logic files
  3. Fetch Latest Documentation — Query Microsoft Learn for the most current Server Logic SDK reference
  4. Review Implementation Plan — Present the plan to the user and confirm before writing code
  5. Implement Server Logic — Create the approved
    .js
    and
    .serverlogic.yml
    files in
    .powerpages-site/server-logic/<name>/
  6. Configure Table Permissions(Conditional: only if Server.Connector.Dataverse is used) Set up table permissions for Dataverse tables accessed by the server logic
  7. Manage Secrets & Environment Variables(Conditional: only if the server logic requires secrets) Store sensitive values securely using Azure Key Vault (recommended) or direct environment variables in Dataverse
  8. Configure Site Settings — Set up ServerLogic site settings if needed
  9. Client-Side Integration — Help wire the server logic into the site's frontend code
  10. Verify & Test Guidance — Validate the code and provide testing instructions
  11. Review & Deploy — Present summary and offer deployment

  1. 验证站点存在 — 定位Power Pages项目,探索现有模式,并验证前提条件
  2. 理解需求 — 确定用户意图,判断解决方案是否需要一个或多个Server Logic文件
  3. 获取最新文档 — 查询Microsoft Learn获取最新的Server Logic SDK参考资料
  4. 审核实施计划 — 向用户展示计划并在编写代码前确认
  5. 实现Server Logic — 在
    .powerpages-site/server-logic/<name>/
    目录下创建经批准的
    .js
    .serverlogic.yml
    文件
  6. 配置表权限 — (条件性:仅当使用Server.Connector.Dataverse时)为Server Logic访问的Dataverse表设置表权限
  7. 管理密钥与环境变量 — (条件性:仅当Server Logic需要密钥时)使用Azure Key Vault(推荐)或Dataverse中的直接环境变量安全存储敏感值
  8. 配置站点设置 — 根据需要设置ServerLogic站点设置
  9. 客户端集成 — 帮助将Server Logic接入站点的前端代码
  10. 验证与测试指南 — 验证代码并提供测试说明
  11. 审核与部署 — 展示总结并提供部署选项

Phase 1: Verify Site Exists

阶段1:验证站点存在

Goal: Locate the Power Pages project root and confirm prerequisites
Actions:
  1. Create todo list with all 11 phases (see Progress Tracking table)
目标:定位Power Pages项目根目录并确认前提条件
操作
  1. 创建包含所有11个阶段的待办事项列表(参见进度跟踪表格)

1.1 Locate Project

1.1 定位项目

Look for
powerpages.config.json
in the current directory or immediate subdirectories
If not found: Tell the user to create a site first with
/create-site
.
在当前目录或直接子目录中查找
powerpages.config.json
文件
如果未找到:告知用户先使用
/create-site
创建站点。

1.2 Read Existing Config

1.2 读取现有配置

Read
powerpages.config.json
to get the site name and configuration:
读取
powerpages.config.json
以获取站点名称和配置信息:

1.3 Detect Framework

1.3 检测框架

Read
package.json
to determine the frontend framework (React, Vue, Angular, or Astro). This is needed for Phase 8 (client-side integration guidance). See
${CLAUDE_PLUGIN_ROOT}/references/framework-conventions.md
for the full framework detection mapping.
读取
package.json
以确定前端框架(React、Vue、Angular或Astro)。这是阶段8(客户端集成指南)所需的信息。请查看
${CLAUDE_PLUGIN_ROOT}/references/framework-conventions.md
获取完整的框架检测映射。

1.4 Explore Existing Server Logic and Frontend Code

1.4 探索现有Server Logic和前端代码

Use the Explore agent (via
Task
tool with
agent_type: "explore"
) to analyze the site for existing server logic patterns and frontend code that may call or need to call server logic endpoints.
Prompt for the Explore agent:
"Analyze this Power Pages code site for server logic context. Check:
  1. Does
    .powerpages-site/server-logic/
    exist? If yes, list all subdirectories and their .js files. Summarize what each server logic does (which functions it implements, what SDK features it uses). Also read the corresponding .serverlogic.yml files to check web role assignments.
  2. Search the frontend source code (
    src/**/*.{ts,tsx,js,jsx,vue,astro}
    ) for any existing calls to
    /_api/serverlogics/
    — these indicate server logic endpoints already being consumed.
  3. Look for CSRF token handling patterns (
    __RequestVerificationToken
    ,
    _layout/tokenhtml
    ) — these show how the site currently makes authenticated API calls.
  4. Check for any TODO/FIXME comments mentioning server logic, backend, or server-side processing.
  5. Look for hardcoded API URLs, mock data, or placeholder fetch calls that might need to be replaced with server logic calls.
  6. Check for any existing service layer or API utility files in
    src/shared/
    ,
    src/services/
    , or similar directories that could be reused for server logic integration.
  7. Read
    .powerpages-site/web-roles/*.webrole.yml
    files to list available web roles and their GUIDs — these are needed when creating the server logic metadata YAML.
  8. For each existing server logic, assess whether it can be reused or safely extended for the requested capability instead of creating a brand-new server logic file. Call out any strong reuse candidates and explain why. Report all findings so we can avoid duplicating work and match existing patterns."
From the Explore agent's findings, note:
  • Existing server logic files — what's already implemented, and which ones are candidates for reuse or extension
  • Frontend calling patterns — how the site makes API calls (match this pattern in Phase 9)
  • Existing service/utility files — reuse these when adding client-side integration
  • Gaps — frontend code that references server logic endpoints that don't exist yet
使用Explore代理(通过
Task
工具,设置
agent_type: "explore"
)分析站点,查找现有Server Logic模式以及可能调用或需要调用Server Logic端点的前端代码。
给Explore代理的提示:
"分析此Power Pages代码站点的Server Logic上下文。检查:
  1. 是否存在
    .powerpages-site/server-logic/
    ?如果存在,列出所有子目录及其.js文件。总结每个Server Logic的功能(实现了哪些函数、使用了哪些SDK功能)。同时读取对应的.serverlogic.yml文件以检查Web角色分配情况。
  2. 在前端源代码(
    src/**/*.{ts,tsx,js,jsx,vue,astro}
    )中搜索对
    /_api/serverlogics/
    的现有调用——这些调用表明Server Logic端点已在被使用。
  3. 查找CSRF令牌处理模式(
    __RequestVerificationToken
    _layout/tokenhtml
    )——这些模式展示了站点当前如何进行已认证的API调用。
  4. 查找提及Server Logic、后端或服务器端处理的任何TODO/FIXME注释。
  5. 查找可能需要替换为Server Logic调用的硬编码API URL、模拟数据或占位符fetch调用。
  6. 查找
    src/shared/
    src/services/
    或类似目录中可能可重用于Server Logic集成的现有服务层或API工具文件。
  7. 读取
    .powerpages-site/web-roles/*.webrole.yml
    文件以列出可用的Web角色及其GUID——这些信息在创建Server Logic元数据YAML时需要。
  8. 对于每个现有Server Logic,评估是否可以重用或安全扩展以实现所需功能,而非创建全新的Server Logic文件。指出强重用候选对象并说明原因。 报告所有发现,以避免重复工作并匹配现有模式。"
从Explore代理的发现中记录:
  • 现有Server Logic文件 — 已实现的内容,以及哪些是可重用或扩展的候选对象
  • 前端调用模式 — 站点如何进行API调用(在阶段9中匹配此模式)
  • 现有服务/工具文件 — 在添加客户端集成时重用这些文件
  • 缺口 — 引用不存在的Server Logic端点的前端代码

1.5 Check Deployment Status (Mandatory)

1.5 检查部署状态(必填)

Look for the
.powerpages-site
folder:
If not found: The site must be deployed before server logic can be created — server logic files live inside
.powerpages-site/server-logic/
. Tell the user:
"The
.powerpages-site
folder was not found. Server logic files are stored inside this folder, so the site must be deployed at least once before creating server logic. Would you like to deploy now?"
Use
AskUserQuestion
:
QuestionOptions
The
.powerpages-site
folder is required for server logic. Would you like to deploy the site now?
Yes, deploy now (Required), Cancel
If "Yes, deploy now": Invoke
/deploy-site
first, then continue to Phase 2.
If "Cancel": Stop the workflow — server logic cannot be created without
.powerpages-site
.
Output: Confirmed project root,
.powerpages-site
exists, existing server logic (if any), available web roles

查找
.powerpages-site
文件夹:
如果未找到:创建Server Logic前必须先部署站点——Server Logic文件存储在此文件夹内。告知用户:
"未找到
.powerpages-site
文件夹。Server Logic文件存储在此文件夹中,因此站点必须至少部署一次才能创建Server Logic。是否现在部署?"
使用
AskUserQuestion
问题选项
创建Server Logic需要
.powerpages-site
文件夹。是否现在部署站点?
是,立即部署(必填),取消
如果选择“是,立即部署”:先调用
/deploy-site
,然后继续阶段2。
如果选择“取消”:停止工作流程——没有
.powerpages-site
无法创建Server Logic。
输出:已确认项目根目录、
.powerpages-site
存在、现有Server Logic(如有)、可用Web角色

Phase 2: Understand Requirements

阶段2:理解需求

Goal: Determine the user intent, identify whether one or more server logic files are needed, and capture the required HTTP methods for each item
Actions:
目标:确定用户意图,判断是否需要一个或多个Server Logic文件,并记录每个文件所需的HTTP方法
操作

2.1 Analyze User Request

2.1 分析用户请求

From the user's request, determine:
  • Intent shape: Does the request map to a single server logic or multiple server logic?
  • Reuse opportunities: Can an existing server logic satisfy or be safely extended for part of the request?
  • Server logic inventory: For each required server logic, capture the purpose, suggested endpoint name, and whether it should be reused, extended, or created new
  • HTTP methods needed: Which of the 5 functions should be implemented for each server logic (
    get
    ,
    post
    ,
    put
    ,
    patch
    ,
    del
    )
Prefer reuse or safe extension of an existing server logic when it already matches the domain, security model, and lifecycle of the requested capability. Only create a new server logic when reuse would make the existing file confusing, over-broad, or unsafe.
Prefer multiple server logic files when the use case naturally separates into different responsibilities, security boundaries, or lifecycle concerns. Examples:
  • Separate read vs. write workflows with different web role requirements
  • Distinct integrations with different external systems or site settings
  • Independent business capabilities that would be harder to test or reason about if merged into one endpoint
从用户请求中确定:
  • 意图类型:请求对应单个还是多个Server Logic?
  • 重用机会:现有Server Logic是否能满足或安全扩展以实现部分请求?
  • Server Logic清单:对于每个所需的Server Logic,记录其用途、建议的端点名称,以及是否应重用、扩展或新建
  • 所需HTTP方法:每个Server Logic应实现哪5种函数中的哪些(
    get
    post
    put
    patch
    del
当现有Server Logic已匹配所需功能的领域、安全模型和生命周期时,优先重用或安全扩展。仅当重用会使现有文件变得混乱、过于宽泛或不安全时,才创建新的Server Logic。
当用例自然分为不同职责、安全边界或生命周期关注点时,优先使用多个Server Logic文件。例如:
  • 具有不同Web角色要求的独立读/写工作流
  • 与不同外部系统或站点设置的不同集成
  • 合并到一个端点会更难测试或推理的独立业务功能

2.1.1 Identify Validate-and-Execute Patterns

2.1.1 识别“验证并执行”模式

For each planned server logic item, determine whether it should validate-and-execute — meaning the server logic both validates a business rule AND performs the resulting Dataverse write, rather than just returning a validation result for the client to act on.
A server logic item should validate-and-execute when any of these are true:
ConditionExample
It enforces a state machine or lifecycleOrder status: Draft → Submitted → Approved
The write is conditional on a business rule that must be tamper-proof"Only allow bid submission before the deadline"
The operation spans multiple tables atomicallyAward a bid + reject all others + update event status
The write involves a computed or derived valueServer calculates a score and writes it
The client should not have direct write access to the fieldStatus fields with strict transition rules
For each validate-and-execute item, note:
  • Which Dataverse writes the server logic will perform (UpdateRecord, CreateRecord, etc.)
  • Which fields are being written — these fields should NOT be writable via Web API from the client
  • What the server logic returns to the client — typically a success/failure result with the before/after state, NOT a validation flag that the client acts on
Anti-pattern to avoid: A server logic item that only validates and returns
{ valid: true/false }
, expecting the client to make a separate Web API call to perform the write. This allows the client to skip validation and write directly.
对于每个计划的Server Logic项,确定是否应采用验证并执行模式——即Server Logic既验证业务规则又执行相应的Dataverse写入操作,而非仅返回验证结果供客户端操作。
当满足以下任一条件时,Server Logic项应采用验证并执行模式:
条件示例
强制执行状态机或生命周期订单状态:草稿 → 已提交 → 已批准
写入操作取决于必须防篡改的业务规则"仅允许在截止日期前提交投标"
操作跨多个表原子执行授予投标 + 拒绝所有其他投标 + 更新活动状态
写入操作涉及计算或派生值服务器计算分数并写入
客户端不应具有对字段的直接写入权限具有严格转换规则的状态字段
对于每个验证并执行项,记录:
  • Server Logic将执行的Dataverse写入操作(UpdateRecord、CreateRecord等)
  • 正在写入的字段 — 这些字段不应允许客户端通过Web API写入
  • Server Logic返回给客户端的内容 — 通常是包含前后状态的成功/失败结果,而非供客户端操作的验证标志
需避免的反模式:仅进行验证并返回
{ valid: true/false }
的Server Logic项,期望客户端进行单独的Web API调用以执行写入操作。这会允许客户端跳过验证直接写入。

2.1.2 Discover Dataverse Custom Actions

2.1.2 发现Dataverse自定义操作

If any planned server logic item involves Dataverse operations, check whether the user's Dataverse environment has existing custom actions (Custom APIs or Custom Process Actions) that could be leveraged instead of building logic from scratch.
Step 1 — Fetch custom actions:
powershell
node "${CLAUDE_PLUGIN_ROOT}/scripts/list-custom-actions.js" "<ENV_URL>"
The script outputs a JSON object with:
  • customApis
    — Modern Custom APIs with full request parameters and response properties
  • customProcessActions
    — Legacy Custom Process Actions (activated only)
  • total
    — Total count of both types combined
Each entry includes:
name
,
displayName
,
description
,
type
(
action
or
function
),
binding
(
unbound
,
entity
, or
entityCollection
),
boundEntity
, and
source
(
customApi
or
customProcessAction
). Custom APIs also include
requestParameters
and
responseProperties
arrays.
Step 2 — Present and ask the user:
If custom actions are found (
total > 0
), present a summary to the user grouped by binding type (unbound vs. entity-bound) and ask whether any should be used:
Use
AskUserQuestion
:
QuestionOptions
Your Dataverse environment has
<total>
custom action(s). Would you like to use any of these in your server logic instead of writing the logic from scratch?
Yes, let me choose which ones to use; No, build everything from scratch
Present the list clearly — for each action show: name, description, type (action/function), binding, and bound entity (if applicable). Group them as Unbound and Entity-bound for readability.
If the user says No, skip to Phase 2.2.
Step 3 — Map custom actions to server logic items:
If the user says Yes, for each server logic item being created, ask which custom action (if any) it should wrap:
Use
AskUserQuestion
for each server logic item:
QuestionContext
For the
<server-logic-name>
endpoint, which custom action should it use?
Present the list of custom actions with their names, descriptions, and binding types. Include "None — build from scratch" as an option.
Record the mapping for each server logic item. For items that wrap a custom action, note:
  • The custom action name (used in the
    InvokeCustomApi
    call)
  • Whether it's a function (
    GET
    ) or action (
    POST
    )
  • The binding type and bound entity (if applicable)
  • The request parameters and response properties (if available from Custom APIs)
This mapping will be used in Phase 5.3 when generating the server logic code, and will appear in the HTML plan (Phase 4) to indicate which items wrap existing custom actions.
如果任何计划的Server Logic项涉及Dataverse操作,请检查用户的Dataverse环境是否存在可利用的现有自定义操作(自定义API或自定义流程操作),而非从头构建逻辑。
步骤1 — 获取自定义操作:
powershell
node "${CLAUDE_PLUGIN_ROOT}/scripts/list-custom-actions.js" "<ENV_URL>"
脚本输出包含以下内容的JSON对象:
  • customApis
    — 具有完整请求参数和响应属性的现代自定义API
  • customProcessActions
    — 仅已激活的旧版自定义流程操作
  • total
    — 两种类型的总数
每个条目包含:
name
displayName
description
type
action
function
)、
binding
unbound
entity
entityCollection
)、
boundEntity
source
customApi
customProcessAction
)。自定义API还包含
requestParameters
responseProperties
数组。
步骤2 — 展示并询问用户:
如果找到自定义操作(
total > 0
),按绑定类型(非绑定与实体绑定)分组向用户展示摘要,并询问是否应使用其中任何操作:
使用
AskUserQuestion
问题选项
您的Dataverse环境有
<total>
个自定义操作。是否要在Server Logic中使用这些操作,而非从头编写逻辑?
是,让我选择要使用的操作;否,从头构建所有内容
清晰展示列表——每个操作显示名称、描述、类型(操作/函数)、绑定类型,以及绑定实体(如适用)。按非绑定实体绑定分组以提高可读性。
如果用户选择,跳至阶段2.2。
步骤3 — 将自定义操作映射到Server Logic项:
如果用户选择,对于每个正在创建的Server Logic项,询问应包装哪个自定义操作(如有):
对每个Server Logic项使用
AskUserQuestion
问题上下文
对于
<server-logic-name>
端点,应使用哪个自定义操作?
展示自定义操作列表及其名称、描述和绑定类型。包含**“无——从头构建”**作为选项。
记录每个Server Logic项的映射。对于包装自定义操作的项,记录:
  • 自定义操作名称(用于
    InvokeCustomApi
    调用)
  • 是函数(
    GET
    )还是操作(
    POST
  • 绑定类型和绑定实体(如适用)
  • 请求参数和响应属性(如果从自定义API获取)
此映射将在阶段5.3生成Server Logic代码时使用,并会出现在HTML计划(阶段4)中,以指示哪些项包装了现有自定义操作。

2.2 Identify SDK Features Needed

2.2 识别所需SDK功能

Based on each planned server logic item's purpose, identify which Server SDK features are required:
FeatureWhen to use
Server.Connector.HttpClient
Calling external REST APIs (NOT Dataverse)
Server.Connector.Dataverse
Reading/writing Dataverse records (CRUD +
InvokeCustomApi
for Dataverse Custom APIs)
Server.Context
Accessing request parameters, headers, body
Server.User
User-scoped operations, role checks
Server.Logger
Always — every function should log entry/exit and errors
Server.Sitesetting
Reading site setting configuration values
Server.EnvironmentVariable
Reading Dataverse environment variable values directly via
Server.EnvironmentVariable.get(name)
— an alternative to
Server.Sitesetting
for non-secret config
Server.Website
Accessing site metadata
根据每个计划的Server Logic项的用途,确定所需的Server SDK功能:
功能使用场景
Server.Connector.HttpClient
调用外部REST API(非Dataverse)
Server.Connector.Dataverse
读取/写入Dataverse记录(CRUD + 使用
InvokeCustomApi
调用Dataverse自定义API)
Server.Context
访问请求参数、标头、主体
Server.User
用户范围操作、角色检查
Server.Logger
始终使用——每个函数都应记录进入/退出和错误
Server.Sitesetting
读取站点设置配置值
Server.EnvironmentVariable
通过
Server.EnvironmentVariable.get(name)
直接读取Dataverse环境变量值——是
Server.Sitesetting
的替代方案,用于非机密配置
Server.Website
访问站点元数据

2.3 Identify Secret Values

2.3 识别密钥值

Determine whether any server logic item requires secret or sensitive configuration values that should not be hardcoded. Common examples:
ScenarioSecret needed
Calling an authenticated external APIAPI key, client secret, bearer token
Connecting to a third-party serviceConnection string, access token
OAuth2 client credentials flowClient ID + client secret
Webhook verificationSigning secret, shared key
For each identified secret, capture:
  • Secret name: A descriptive name (e.g.,
    ExchangeRateApiKey
    ,
    PaymentGatewaySecret
    )
  • Purpose: Why the secret is needed
  • Site setting name: The name the server logic will use with
    Server.Sitesetting.Get()
    (e.g.,
    ExternalApi/ExchangeRateApiKey
    )
  • Environment variable schema name: The Dataverse environment variable schema name (e.g.,
    cr5b4_ExchangeRateApiKey
    )
These values will be used in Phase 7 to create the environment variables and site settings.
确定是否有任何Server Logic项需要不应硬编码的机密或敏感配置值。常见示例:
场景需要的密钥
调用已认证的外部APIAPI密钥、客户端密钥、Bearer令牌
连接到第三方服务连接字符串、访问令牌
OAuth2客户端凭据流客户端ID + 客户端密钥
Webhook验证签名密钥、共享密钥
对于每个识别出的密钥,记录:
  • 密钥名称:描述性名称(例如
    ExchangeRateApiKey
    PaymentGatewaySecret
  • 用途:为何需要此密钥
  • 站点设置名称:Server Logic将与
    Server.Sitesetting.Get()
    一起使用的名称(例如
    ExternalApi/ExchangeRateApiKey
  • 环境变量架构名称:Dataverse环境变量架构名称(例如
    cr5b4_ExchangeRateApiKey
这些值将在阶段7用于创建环境变量和站点设置。

2.3.1 Key Vault Decision

2.3.1 Key Vault决策

If secrets were identified in Phase 2.3, ask the user now whether they want to use Azure Key Vault. This decision must happen before Phase 4 so the implementation plan can show the chosen secret management approach.
Use
AskUserQuestion
:
QuestionOptions
This server logic requires secret values (e.g., API keys, client secrets). Azure Key Vault is the recommended way to store secrets securely. Would you like to use Azure Key Vault?Yes, use Azure Key Vault (Recommended), No, store directly as environment variable
Record the user's choice — it will be shown in the HTML plan (Phase 4) and executed in Phase 7.
如果在阶段2.3中识别出密钥,请立即询问用户是否要使用Azure Key Vault。此决策必须在阶段4之前做出,以便实施计划可以显示所选的密钥管理方法。
使用
AskUserQuestion
问题选项
此Server Logic需要密钥值(例如API密钥、客户端密钥)。Azure Key Vault是安全存储密钥的推荐方式。是否要使用Azure Key Vault?是,使用Azure Key Vault(推荐);否,直接存储为环境变量
记录用户的选择——该选择将显示在HTML计划(阶段4)中,并在阶段7执行。

2.4 Confirm with User

2.4 与用户确认

If the requirements are ambiguous, use
AskUserQuestion
to clarify:
QuestionContext
What should this server logic solution do overall?If the purpose is unclear
Should this be one server logic or multiple server logic?If the request could reasonably be modeled either way
Which HTTP methods does each server logic need?If not specified — suggest based on the use case (e.g., read-only = GET, form processing = POST)
Does each server logic need to call external APIs, Dataverse, or both?Determines which connectors to use
What should each server logic be named?Suggest URL-friendly names based on the responsibilities
Does the server logic need any secret or sensitive values (API keys, client secrets, tokens)?If the server logic calls authenticated external APIs or services
Output: Clear understanding of the overall intent, the list of server logic items to reuse/extend/create, their HTTP methods, SDK features needed, and any secrets required

如果需求不明确,使用
AskUserQuestion
澄清:
问题上下文
此Server Logic解决方案总体应实现什么功能?如果用途不明确
应使用一个还是多个Server Logic?如果请求可以合理建模为两种方式
每个Server Logic需要哪些HTTP方法?如果未指定——根据用例建议(例如只读=GET,表单处理=POST)
每个Server Logic是否需要调用外部API、Dataverse或两者?确定要使用的连接器
每个Server Logic应命名为什么?根据职责建议URL友好的名称
Server Logic是否需要任何机密或敏感值(API密钥、客户端密钥、令牌)?如果Server Logic调用已认证的外部API或服务
输出:对总体意图、要重用/扩展/创建的Server Logic项列表、其HTTP方法、所需SDK功能以及任何所需密钥的清晰理解

Phase 3: Fetch Latest Documentation

阶段3:获取最新文档

Goal: Discover and read all current Server Logic documentation from Microsoft Learn before writing any code
This step is critical because Server Logic is a preview feature and the SDK surface may change. The documentation on Microsoft Learn is the authoritative source.
Actions:
目标:在编写任何代码之前,从Microsoft Learn发现并读取所有当前的Server Logic文档
此步骤至关重要,因为Server Logic是预览功能,SDK表面可能会变化。Microsoft Learn上的文档是权威来源。
操作

3.1 Follow the Documentation Reference

3.1 遵循文档参考

Use the reference document below as the source of truth for how to discover, classify, fetch, and reconcile Server Logic documentation:
Reference:
${CLAUDE_PLUGIN_ROOT}/skills/add-server-logic/references/server-logic-docs.md
Follow that reference to:
  • Search Microsoft Learn dynamically for all current Server Logic docs
  • Fetch the core reference pages and any relevant scenario-specific pages
  • Search for current code samples
  • Reconcile the discovered documentation with the known SDK baseline in the reference
使用以下参考文档作为发现、分类、获取和协调Server Logic文档的权威来源:
参考:
${CLAUDE_PLUGIN_ROOT}/skills/add-server-logic/references/server-logic-docs.md
遵循该参考文档以:
  • 动态搜索Microsoft Learn获取所有当前的Server Logic文档
  • 获取核心参考页面和任何相关的场景特定页面
  • 搜索当前代码示例
  • 将发现的文档与参考中的已知SDK基线进行协调

3.2 Extract Task-Specific Notes

3.2 提取任务特定注释

From the fetched docs, extract and note the items that matter for the current task:
  • All SDK method signatures, parameter types, and return types
  • Current supported HTTP methods and function signatures
  • Site settings and their defaults
  • Security model (web roles, table permissions, CSRF)
  • Client-side calling patterns and response format
  • Any new methods or breaking changes discovered in Microsoft Learn
Output: Up-to-date SDK reference verified against all relevant Microsoft Learn documentation pages

从获取的文档中提取并记录与当前任务相关的项:
  • 所有SDK方法签名、参数类型和返回类型
  • 当前支持的HTTP方法和函数签名
  • 站点设置及其默认值
  • 安全模型(Web角色、表权限、CSRF)
  • 客户端调用模式和响应格式
  • 在Microsoft Learn中发现的任何新方法或破坏性变更
输出:经所有相关Microsoft Learn文档页面验证的最新SDK参考

Phase 4: Review Implementation Plan

阶段4:审核实施计划

Goal: Present the implementation plan to the user and confirm before writing any code
Actions:
目标:向用户展示实施计划并在编写任何代码前确认
操作

4.1 Prepare the Plan Data

4.1 准备计划数据

Build the server logic plan data and render the HTML plan before asking for approval.
Reference:
${CLAUDE_PLUGIN_ROOT}/skills/add-server-logic/references/server-logic-plan-data-format.md
The rendered plan should summarize:
  • The number of server logic items being created or reused
  • Each endpoint name, API URL, and files to be created
  • The functions that will be implemented and what each one does
  • The SDK features, external services, and Dataverse tables involved for each item
  • The web roles, security constraints, and site settings that apply to each item
  • Any secrets or sensitive values that will be stored as environment variables (with or without Azure Key Vault). If the user chose Azure Key Vault in Phase 2.3.1, populate
    SECRETS_DATA
    with
    useKeyVault: true
    and the list of secrets — the HTML plan will render a Key Vault banner explaining the security benefits and show which secrets each server logic depends on. If no secrets are needed, set
    SECRETS_DATA
    to
    null
    .
  • The expected next steps after approval
构建Server Logic计划数据并在请求批准前渲染HTML计划。
参考:
${CLAUDE_PLUGIN_ROOT}/skills/add-server-logic/references/server-logic-plan-data-format.md
渲染的计划应总结:
  • 正在创建或重用的Server Logic项数量
  • 每个端点名称、API URL和要创建的文件
  • 将实现的函数及其功能
  • 每个项涉及的SDK功能、外部服务和Dataverse表
  • 适用于每个项的Web角色、安全约束和站点设置
  • 将存储为环境变量的任何机密或敏感值(带或不带Azure Key Vault)。如果用户在阶段2.3.1中选择了Azure Key Vault,请在
    SECRETS_DATA
    中填充
    useKeyVault: true
    和密钥列表——HTML计划将显示一个Key Vault横幅,解释安全优势并显示每个Server Logic依赖的密钥。如果不需要密钥,请将
    SECRETS_DATA
    设置为
    null
  • 批准后的预期下一步

4.2 Render the HTML Plan

4.2 渲染HTML计划

Generate the HTML plan file from the template and open it in the user's default browser before asking for approval.
When working inside a Power Pages project, write the plan to:
text
<PROJECT_ROOT>/docs/serverlogic-plan.html
Create the
docs/
folder if it does not already exist. Keep this HTML file inside the repository so it can be reviewed and committed with the rest of the server logic work.
Do not hand-author the HTML. Use the render script:
powershell
node "${CLAUDE_PLUGIN_ROOT}/scripts/render-serverlogic-plan.js" --output "<OUTPUT_PATH>" --data "<DATA_JSON_PATH>"
The render script refuses to overwrite existing files. Before calling it, check if the default output path (
<PROJECT_ROOT>/docs/serverlogic-plan.html
) already exists. If it does, choose a new descriptive filename based on context — e.g.,
serverlogic-plan-exchange-rate.html
,
serverlogic-plan-apr-2026.html
. Pass the chosen name via
--output
.
从模板生成HTML计划文件,并在请求批准前在用户的默认浏览器中打开。
在Power Pages项目中工作时,将计划写入:
text
<PROJECT_ROOT>/docs/serverlogic-plan.html
如果
docs/
文件夹不存在,请创建它。将此HTML文件保存在存储库中,以便与其余Server Logic工作一起审核和提交。
请勿手动编写HTML。使用渲染脚本:
powershell
node "${CLAUDE_PLUGIN_ROOT}/scripts/render-serverlogic-plan.js" --output "<OUTPUT_PATH>" --data "<DATA_JSON_PATH>"
渲染脚本会拒绝覆盖现有文件。调用前,请检查默认输出路径(
<PROJECT_ROOT>/docs/serverlogic-plan.html
)是否已存在。如果存在,请根据上下文选择新的描述性文件名——例如
serverlogic-plan-exchange-rate.html
serverlogic-plan-apr-2026.html
。通过
--output
传递所选名称。

4.3 Present Plan Summary

4.3 展示计划摘要

Do not present a second detailed plan in the CLI. The HTML file is the single detailed plan artifact.
In the CLI, give only a brief summary that points the user to the HTML plan open in the browser. Keep it to:
  • Total server logic count
  • Whether the plan is creating, updating, or reusing items
  • Whether web roles, table permissions, or site settings are involved
  • The actual output path returned by the render script
  • A note that the browser-opened HTML contains the full details
Do not restate the per-server-logic breakdown, rationale, role assignments, or function details inline in the CLI unless the user explicitly asks for a text version. Tell the user where the detailed HTML plan file was saved, that it has been opened in the browser for review, and that the repo copy of the plan will be committed with the implementation artifacts unless the user asks to discard it.
请勿在CLI中展示第二个详细计划。HTML文件是唯一的详细计划工件。
在CLI中,仅提供指向浏览器中打开的HTML计划的简要摘要。内容应包括:
  • Server Logic总数
  • 计划是创建、更新还是重用项
  • 是否涉及Web角色、表权限或站点设置
  • 渲染脚本返回的实际输出路径
  • 说明浏览器中打开的HTML包含完整详细信息
除非用户明确要求文本版本,否则请勿在CLI中重复每个Server Logic的细分、理由、角色分配或函数详细信息。告知用户详细HTML计划文件的保存位置,说明它已在浏览器中打开以供审核,并且除非用户要求丢弃,否则计划的存储库副本将与实施工件一起提交。

4.4 Confirm with User

4.4 与用户确认

Use
AskUserQuestion
:
QuestionOptions
Here's the implementation plan for this server logic work. Does it look correct?Approve and implement (Recommended), Request changes, Cancel
If "Request changes": Ask what needs to change, update the plan, and present again.
If "Cancel": Stop the workflow.
Output: User-approved implementation plan

使用
AskUserQuestion
问题选项
这是此Server Logic工作的实施计划。看起来是否正确?批准并实施(推荐),请求更改,取消
如果选择“请求更改”:询问需要更改的内容,更新计划并再次展示。
如果选择“取消”:停止工作流程。
输出:用户批准的实施计划

Phase 5: Implement Server Logic

阶段5:实现Server Logic

Goal: Create each approved server logic
.js
file and metadata YAML following the constraints verified in Phase 3
Actions:
目标:根据阶段3验证的约束,创建每个经批准的Server Logic
.js
文件和元数据YAML
操作

5.1 Create Server Logic Folder

5.1 创建Server Logic文件夹

For each approved server logic item:
  • If the approved plan says
    reuse
    : Do not create a new folder. Reuse the existing server logic as-is and only update the surrounding integration work if needed.
  • If the approved plan says
    update
    / extend
    : Reuse the existing folder and update the existing
    .js
    /
    .serverlogic.yml
    files rather than creating duplicates.
  • If the approved plan says
    create
    : Create the folder inside
    .powerpages-site/server-logic/
    (note: singular
    server-logic
    , no trailing 's'). Ensure the folder name matches that endpoint name exactly.
对于每个经批准的Server Logic项:
  • 如果经批准的计划要求
    reuse
    :不要创建新文件夹。按原样重用现有Server Logic,仅在需要时更新周围的集成工作。
  • 如果经批准的计划要求
    update
    /extend
    :重用现有文件夹并更新现有的
    .js
    /
    .serverlogic.yml
    文件,而非创建重复文件。
  • 如果经批准的计划要求
    create
    :在
    .powerpages-site/server-logic/
    目录下创建文件夹(注意:单数
    server-logic
    ,无尾随's')。确保文件夹名称与端点名称完全匹配。

5.2 Read or Create Web Roles

5.2 读取或创建Web角色

Use the Create Web Role skill to determine which web roles are required for the approved server logic plan and to create any missing roles before writing metadata.
Do not assume every server logic should get every available role. Instead, determine the minimum set of roles required for each server logic based on its purpose, security model, and the approved plan.
Example web role file content:
yaml
adx_anonymoususersrole: false
adx_authenticatedusersrole: true
description: Role for authenticated users
id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
name: Authenticated Users
In the skill workflow, explicitly invoke the Create Web Role skill when:
  • The site has no suitable existing web roles
  • The approved plan includes proposed roles that do not exist yet
  • The role assignments need to be refined before metadata can be created
After the Create Web Role skill completes, read the resulting web role YAML files and collect the
id
and
name
values needed for each server logic's metadata YAML.
使用Create Web Role技能确定经批准的Server Logic计划所需的Web角色,并在编写元数据前创建任何缺失的角色。
请勿假设每个Server Logic应获得所有可用角色。相反,根据每个Server Logic的用途、安全模型和经批准的计划确定所需的最小角色集。
示例Web角色文件内容:
yaml
adx_anonymoususersrole: false
adx_authenticatedusersrole: true
description: Role for authenticated users
id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
name: Authenticated Users
在技能工作流程中,在以下情况下显式调用Create Web Role技能:
  • 站点没有合适的现有Web角色
  • 经批准的计划包含尚未存在的提议角色
  • 在创建元数据前需要细化角色分配
Create Web Role技能完成后,读取生成的Web角色YAML文件并收集每个Server Logic元数据YAML所需的
id
name
值。

5.3 Create the Server Logic File

5.3 创建Server Logic文件

Repeat this step for each approved server logic item. Create or update
<PROJECT_ROOT>/.powerpages-site/server-logic/<name>/<name>.js
according to the approved plan status (
create
,
update
, or
reuse
) and follow these mandatory patterns:
对每个经批准的Server Logic项重复此步骤。根据经批准的计划状态(
create
update
reuse
)创建或更新
<PROJECT_ROOT>/.powerpages-site/server-logic/<name>/<name>.js
,并遵循以下强制模式:

Structure Rules

结构规则

  1. Only top-level functions: The file can only contain these 5 functions at the top level:
    get
    ,
    post
    ,
    put
    ,
    patch
    ,
    del
    . Only include the functions the user needs.
  2. Each function returns a string: Use
    JSON.stringify()
    for objects/arrays.
  3. Each function has try/catch: Every function must wrap its logic in a try/catch block.
  4. Each function logs: Use
    Server.Logger.Log()
    at entry and
    Server.Logger.Error()
    in catch blocks.
  5. No imports or requires: No
    import
    ,
    require
    , or external dependencies.
  6. No browser APIs: No
    fetch
    ,
    XMLHttpRequest
    ,
    setTimeout
    ,
    setInterval
    ,
    console.log
    , or DOM APIs.
  7. Async when needed: Mark functions as
    async
    only when they use
    await
    (HttpClient calls). Dataverse connector methods (
    Server.Connector.Dataverse.*
    ) are synchronous — do NOT use
    async
    /
    await
    with them.
  1. 仅顶级函数:文件只能包含以下5个顶级函数:
    get
    post
    put
    patch
    del
    。仅包含用户需要的函数。
  2. 每个函数返回字符串:对对象/数组使用
    JSON.stringify()
  3. 每个函数包含try/catch:每个函数必须将其逻辑包装在try/catch块中。
  4. 每个函数记录日志:在入口处使用
    Server.Logger.Log()
    ,在catch块中使用
    Server.Logger.Error()
  5. 无导入或依赖:无
    import
    require
    或外部依赖项。
  6. 无浏览器API:无
    fetch
    XMLHttpRequest
    setTimeout
    setInterval
    console.log
    或DOM API。
  7. 必要时使用Async:仅当函数使用
    await
    (HttpClient调用)时才标记为
    async
    。Dataverse连接器方法(
    Server.Connector.Dataverse.*
    )是同步的——请勿对其使用
    async
    /
    await

Code Template

代码模板

javascript
// Server Logic: <name>
// Purpose: <description>
// API URL: https://<site-url>/_api/serverlogics/<name>

function get() {
    try {
        Server.Logger.Log("<name> GET called");

        // Access query parameters
        // const id = Server.Context.QueryParameters["id"];

        // Your logic here...

        return JSON.stringify({
            status: "success",
            method: "GET",
            data: null // replace with actual data
        });
    } catch (err) {
        Server.Logger.Error("<name> GET failed: " + err.message);
        return JSON.stringify({
            status: "error",
            method: "GET",
            message: err.message
        });
    }
}
javascript
// Server Logic: <name>
// Purpose: <description>
// API URL: https://<site-url>/_api/serverlogics/<name>

function get() {
    try {
        Server.Logger.Log("<name> GET called");

        // Access query parameters
        // const id = Server.Context.QueryParameters["id"];

        // Your logic here...

        return JSON.stringify({
            status: "success",
            method: "GET",
            data: null // replace with actual data
        });
    } catch (err) {
        Server.Logger.Error("<name> GET failed: " + err.message);
        return JSON.stringify({
            status: "error",
            method: "GET",
            message: err.message
        });
    }
}

Validate-and-Execute Template

验证并执行模板

When a server logic item is identified as validate-and-execute (see Phase 2.1.1), use this pattern. The key difference: the server logic reads the current state, validates the business rule, AND writes the result to Dataverse — all in one call. The client never writes the protected field directly.
javascript
// Server Logic: <name>
// Purpose: Validate and execute <describe the operation>
// Pattern: Validate-and-execute — this endpoint both validates the business rule
//          and performs the Dataverse write. The client should NOT write <protected fields>
//          via Web API — all writes to those fields go through this endpoint.
// API URL: https://<site-url>/_api/serverlogics/<name>

function post() {
    try {
        Server.Logger.Log("<name> POST called");

        const body = JSON.parse(Server.Context.Body);
        const entityId = body.entityId;
        const targetStatus = body.targetStatus;

        // 1. Read the current record from Dataverse
        const current = Server.Connector.Dataverse.RetrieveRecord("<table-name>", entityId, "?$select=<status-field>");
        const currentStatus = current["<status-field>"];

        // 2. Validate the transition
        const allowedTransitions = {
            "Draft": ["Submitted"],
            "Submitted": ["Approved", "Rejected"],
            "Approved": ["Fulfilled"]
        };

        const allowed = allowedTransitions[currentStatus] || [];
        if (!allowed.includes(targetStatus)) {
            return JSON.stringify({
                status: "error",
                message: "Invalid transition: " + currentStatus + " → " + targetStatus + " is not allowed",
                currentStatus: currentStatus,
                targetStatus: targetStatus,
                allowedTargets: allowed
            });
        }

        // 3. Execute the write — server performs the Dataverse update
        const updateData = {};
        updateData["<status-field>"] = targetStatus;
        Server.Connector.Dataverse.UpdateRecord("<table-name>", entityId, JSON.stringify(updateData));

        Server.Logger.Log("<name> transition executed: " + currentStatus + " → " + targetStatus);

        // 4. Return the result — client receives confirmation, not a validation flag
        return JSON.stringify({
            status: "success",
            previousStatus: currentStatus,
            newStatus: targetStatus,
            entityId: entityId
        });
    } catch (err) {
        Server.Logger.Error("<name> POST failed: " + err.message);
        return JSON.stringify({
            status: "error",
            message: err.message
        });
    }
}
Key differences from the basic template:
  1. The server logic reads the current state from Dataverse (not trusting the client's view)
  2. It validates the business rule server-side
  3. It writes the result to Dataverse via
    Server.Connector.Dataverse.UpdateRecord
  4. It returns a success/failure result — NOT a
    { valid: true/false }
    flag for the client to act on
  5. The client calls this one endpoint — it does NOT make a separate Web API PATCH call
当Server Logic项被识别为验证并执行模式(参见阶段2.1.1)时,使用此模式。关键区别:Server Logic读取当前状态、验证业务规则,并将结果写入Dataverse——所有操作在一次调用中完成。客户端永远不会直接写入受保护的字段。
javascript
// Server Logic: <name>
// Purpose: Validate and execute <describe the operation>
// Pattern: Validate-and-execute — this endpoint both validates the business rule
//          and performs the Dataverse write. The client should NOT write <protected fields>
//          via Web API — all writes to those fields go through this endpoint.
// API URL: https://<site-url>/_api/serverlogics/<name>

function post() {
    try {
        Server.Logger.Log("<name> POST called");

        const body = JSON.parse(Server.Context.Body);
        const entityId = body.entityId;
        const targetStatus = body.targetStatus;

        // 1. Read the current record from Dataverse
        const current = Server.Connector.Dataverse.RetrieveRecord("<table-name>", entityId, "?$select=<status-field>");
        const currentStatus = current["<status-field>"];

        // 2. Validate the transition
        const allowedTransitions = {
            "Draft": ["Submitted"],
            "Submitted": ["Approved", "Rejected"],
            "Approved": ["Fulfilled"]
        };

        const allowed = allowedTransitions[currentStatus] || [];
        if (!allowed.includes(targetStatus)) {
            return JSON.stringify({
                status: "error",
                message: "Invalid transition: " + currentStatus + " → " + targetStatus + " is not allowed",
                currentStatus: currentStatus,
                targetStatus: targetStatus,
                allowedTargets: allowed
            });
        }

        // 3. Execute the write — server performs the Dataverse update
        const updateData = {};
        updateData["<status-field>"] = targetStatus;
        Server.Connector.Dataverse.UpdateRecord("<table-name>", entityId, JSON.stringify(updateData));

        Server.Logger.Log("<name> transition executed: " + currentStatus + " → " + targetStatus);

        // 4. Return the result — client receives confirmation, not a validation flag
        return JSON.stringify({
            status: "success",
            previousStatus: currentStatus,
            newStatus: targetStatus,
            entityId: entityId
        });
    } catch (err) {
        Server.Logger.Error("<name> POST failed: " + err.message);
        return JSON.stringify({
            status: "error",
            message: err.message
        });
    }
}
与基础模板的关键区别:
  1. Server Logic从Dataverse读取当前状态(不依赖客户端的视图)
  2. 它在服务器端验证业务规则
  3. 它通过
    Server.Connector.Dataverse.UpdateRecord
    将结果写入Dataverse
  4. 它返回成功/失败结果——而非供客户端操作的
    { valid: true/false }
    标志
  5. 客户端调用此一个端点——不进行单独的Web API PATCH调用

Custom Action Wrapping Template

自定义操作包装模板

When a server logic item wraps a Dataverse custom action (mapped in Phase 2.1.2), use this pattern with
Server.Connector.Dataverse.InvokeCustomApi
. The server logic acts as a portal-friendly wrapper, exposing the custom action through a
/_api/serverlogics/<name>
endpoint with proper web role authorization.
Unbound action:
javascript
// Server Logic: <name>
// Purpose: Wraps Dataverse custom action "<custom-action-name>" for portal consumption
// Custom Action: <custom-action-name> (unbound, action)
// API URL: https://<site-url>/_api/serverlogics/<name>

function post() {
    try {
        Server.Logger.Log("<name> POST called — invoking custom action <custom-action-name>");

        const body = JSON.parse(Server.Context.Body);

        // Build the request payload matching the custom action's input parameters
        const payload = JSON.stringify({
            // "<ParameterName>": body.<clientFieldName>
        });

        const result = Server.Connector.Dataverse.InvokeCustomApi(
            "POST",
            "<custom-action-name>",
            payload
        );

        Server.Logger.Log("<name> custom action completed successfully");

        return JSON.stringify({
            status: "success",
            data: result
        });
    } catch (err) {
        Server.Logger.Error("<name> POST failed: " + err.message);
        return JSON.stringify({
            status: "error",
            message: err.message
        });
    }
}
Entity-bound action:
javascript
function post() {
    try {
        Server.Logger.Log("<name> POST called — invoking bound action <custom-action-name>");

        const body = JSON.parse(Server.Context.Body);
        const entityId = body.entityId;

        const payload = JSON.stringify({
            // "<ParameterName>": body.<clientFieldName>
        });

        // Include the entity set and record ID, followed by the fully qualified action name
        const result = Server.Connector.Dataverse.InvokeCustomApi(
            "POST",
            "<entity-set-name>(" + entityId + ")/Microsoft.Dynamics.CRM.<custom-action-name>",
            payload
        );

        Server.Logger.Log("<name> bound action completed for entity " + entityId);

        return JSON.stringify({
            status: "success",
            data: result,
            entityId: entityId
        });
    } catch (err) {
        Server.Logger.Error("<name> POST failed: " + err.message);
        return JSON.stringify({
            status: "error",
            message: err.message
        });
    }
}
Unbound function (read-only, GET):
javascript
function get() {
    try {
        Server.Logger.Log("<name> GET called — invoking custom function <custom-function-name>");

        // Pass parameters as query string for functions
        const param1 = Server.Context.QueryParameters["param1"];
        const queryString = "<custom-function-name>(Param1='" + param1 + "')";

        const result = Server.Connector.Dataverse.InvokeCustomApi(
            "GET",
            queryString,
            null
        );

        Server.Logger.Log("<name> custom function completed successfully");

        return JSON.stringify({
            status: "success",
            data: result
        });
    } catch (err) {
        Server.Logger.Error("<name> GET failed: " + err.message);
        return JSON.stringify({
            status: "error",
            message: err.message
        });
    }
}
Key points:
  • Unbound actions: Use the action name as the URL, pass parameters as JSON body
  • Entity-bound actions: Include the entity set and record ID in the URL path, followed by
    Microsoft.Dynamics.CRM.<action-name>
  • Functions (GET): Use
    "GET"
    as the HTTP method and pass parameters inline in the URL using OData function call syntax
  • Actions (POST): Use
    "POST"
    as the HTTP method and pass parameters as JSON body payload
  • InvokeCustomApi
    is synchronous — do NOT use
    async
    /
    await
  • The server logic can add additional validation, transformation, or logging around the custom action call — it doesn't have to be a pass-through
  • When Custom API response properties are known (from Phase 2.1.2), map them to the response object for clarity
当Server Logic项包装Dataverse自定义操作(在阶段2.1.2中映射)时,使用此模式并结合
Server.Connector.Dataverse.InvokeCustomApi
。Server Logic作为门户友好的包装器,通过
/_api/serverlogics/<name>
端点暴露自定义操作,并具有适当的Web角色授权。
非绑定操作:
javascript
// Server Logic: <name>
// Purpose: Wraps Dataverse custom action "<custom-action-name>" for portal consumption
// Custom Action: <custom-action-name> (unbound, action)
// API URL: https://<site-url>/_api/serverlogics/<name>

function post() {
    try {
        Server.Logger.Log("<name> POST called — invoking custom action <custom-action-name>");

        const body = JSON.parse(Server.Context.Body);

        // Build the request payload matching the custom action's input parameters
        const payload = JSON.stringify({
            // "<ParameterName>": body.<clientFieldName>
        });

        const result = Server.Connector.Dataverse.InvokeCustomApi(
            "POST",
            "<custom-action-name>",
            payload
        );

        Server.Logger.Log("<name> custom action completed successfully");

        return JSON.stringify({
            status: "success",
            data: result
        });
    } catch (err) {
        Server.Logger.Error("<name> POST failed: " + err.message);
        return JSON.stringify({
            status: "error",
            message: err.message
        });
    }
}
实体绑定操作:
javascript
function post() {
    try {
        Server.Logger.Log("<name> POST called — invoking bound action <custom-action-name>");

        const body = JSON.parse(Server.Context.Body);
        const entityId = body.entityId;

        const payload = JSON.stringify({
            // "<ParameterName>": body.<clientFieldName>
        });

        // Include the entity set and record ID, followed by the fully qualified action name
        const result = Server.Connector.Dataverse.InvokeCustomApi(
            "POST",
            "<entity-set-name>(" + entityId + ")/Microsoft.Dynamics.CRM.<custom-action-name>",
            payload
        );

        Server.Logger.Log("<name> bound action completed for entity " + entityId);

        return JSON.stringify({
            status: "success",
            data: result,
            entityId: entityId
        });
    } catch (err) {
        Server.Logger.Error("<name> POST failed: " + err.message);
        return JSON.stringify({
            status: "error",
            message: err.message
        });
    }
}
非绑定函数(只读,GET):
javascript
function get() {
    try {
        Server.Logger.Log("<name> GET called — invoking custom function <custom-function-name>");

        // Pass parameters as query string for functions
        const param1 = Server.Context.QueryParameters["param1"];
        const queryString = "<custom-function-name>(Param1='" + param1 + "')";

        const result = Server.Connector.Dataverse.InvokeCustomApi(
            "GET",
            queryString,
            null
        );

        Server.Logger.Log("<name> custom function completed successfully");

        return JSON.stringify({
            status: "success",
            data: result
        });
    } catch (err) {
        Server.Logger.Error("<name> GET failed: " + err.message);
        return JSON.stringify({
            status: "error",
            message: err.message
        });
    }
}
关键点:
  • 非绑定操作:使用操作名称作为URL,将参数作为JSON主体传递
  • 实体绑定操作:在URL路径中包含实体集和记录ID,后跟
    Microsoft.Dynamics.CRM.<action-name>
  • 函数(GET):使用
    "GET"
    作为HTTP方法,并使用OData函数调用语法在URL中内联传递参数
  • 操作(POST):使用
    "POST"
    作为HTTP方法,并将参数作为JSON主体负载传递
  • InvokeCustomApi
    同步的——请勿使用
    async
    /
    await
  • Server Logic可以在自定义操作调用周围添加额外的验证、转换或日志记录——不必是直通式的
  • 当已知自定义API响应属性(来自阶段2.1.2)时,将其映射到响应对象以提高清晰度

Referencing Secrets in Code

在代码中引用密钥

When the server logic needs a secret value identified in Phase 2.3, never hardcode the value. Instead, read it at runtime from a site setting backed by an environment variable:
javascript
const apiKey = Server.Sitesetting.Get("ExternalApi/ExchangeRateApiKey");
Use the site setting name planned in Phase 2.3. The actual environment variable and site setting YAML will be created in Phase 7.
当Server Logic需要阶段2.3中识别的密钥值时,切勿硬编码值。相反,在运行时从环境变量支持的站点设置中读取:
javascript
const apiKey = Server.Sitesetting.Get("ExternalApi/ExchangeRateApiKey");
使用阶段2.3中计划的站点设置名称。实际的环境变量和站点设置YAML将在阶段7创建。

SDK Usage Guidance

SDK使用指南

Do not duplicate Microsoft Learn SDK usage patterns inline in this skill. Use the documentation fetched in Phase 3 as the source of truth for connector methods, signatures, and supported patterns, then apply only the task-specific notes that were captured in the approved plan.
请勿在此技能文件中重复Microsoft Learn SDK使用模式。使用阶段3中获取的文档作为连接器方法、签名和支持模式的权威来源,然后仅应用经批准计划中记录的任务特定注释。

5.4 Create the Metadata YAML

5.4 创建元数据YAML

For each approved server logic item where the plan status is
create
, generate the metadata file with the deterministic writer script instead of hand-authoring the YAML. The script generates the UUID, writes the fields in the correct order, and returns the created file path as JSON. Skip this step for
update
/
reuse
items
— the YAML already exists and should be updated manually if needed.
powershell
node "${CLAUDE_PLUGIN_ROOT}/skills/add-server-logic/scripts/create-serverlogic-metadata.js" --projectRoot "<PROJECT_ROOT>" --name "<name>" --displayName "<human-readable display name>" --description "<description of what this server logic does>" --webRoleIds "<uuid1,uuid2,uuid3>"
The generated
<PROJECT_ROOT>/.powerpages-site/server-logic/<name>/<name>.serverlogic.yml
file has this structure:
yaml
adx_serverlogic_adx_webrole:
  - <web-role-guid-1>
  - <web-role-guid-2>
  - <web-role-guid-3>
description: <description of what this server logic does>
display_name: <human-readable display name>
id: <generated-uuid>
name: <name>
Critical requirements:
  • id
    field is mandatory
    — The script generates a new UUID (v4). PAC CLI crashes with
    Expected Guid for primary key 'id'
    if this is missing.
  • adx_serverlogic_adx_webrole
    — Array of web role GUIDs from step 5.2. Include only the roles required for that server logic item.
  • name
    — Must match the folder name and
    .js
    file name (the URL-friendly name used in
    /_api/serverlogics/<name>
    ).
  • display_name
    — Human-readable name (e.g., "Exchange Rate API", "Order Processor").
  • Alphabetical field ordering — Fields must be sorted alphabetically:
    adx_serverlogic_adx_webrole
    ,
    description
    ,
    display_name
    ,
    id
    ,
    name
    .
对于每个计划状态为
create
的经批准Server Logic项,使用确定性写入脚本生成元数据文件,而非手动编写YAML。脚本生成UUID,按正确顺序写入字段,并以JSON格式返回创建的文件路径。跳过
update
/
reuse
项的此步骤
——YAML已存在,如有需要应手动更新。
powershell
node "${CLAUDE_PLUGIN_ROOT}/skills/add-server-logic/scripts/create-serverlogic-metadata.js" --projectRoot "<PROJECT_ROOT>" --name "<name>" --displayName "<human-readable display name>" --description "<description of what this server logic does>" --webRoleIds "<uuid1,uuid2,uuid3>"
生成的
<PROJECT_ROOT>/.powerpages-site/server-logic/<name>/<name>.serverlogic.yml
文件具有以下结构:
yaml
adx_serverlogic_adx_webrole:
  - <web-role-guid-1>
  - <web-role-guid-2>
  - <web-role-guid-3>
description: <description of what this server logic does>
display_name: <human-readable display name>
id: <generated-uuid>
name: <name>
关键要求:
  • id
    字段是必填项
    ——脚本生成新的UUID(v4)。如果缺少此字段,PAC CLI会崩溃并显示
    Expected Guid for primary key 'id'
  • adx_serverlogic_adx_webrole
    ——来自步骤5.2的Web角色GUID数组。仅包含该Server Logic项所需的角色。
  • name
    ——必须与文件夹名称和
    .js
    文件名匹配(
    /_api/serverlogics/<name>
    中使用的URL友好名称)。
  • display_name
    ——人类可读名称(例如“Exchange Rate API”、“Order Processor”)。
  • 字母顺序字段排序——字段必须按字母顺序排序:
    adx_serverlogic_adx_webrole
    description
    display_name
    id
    name

5.5 Validate the Code

5.5 验证代码

Before saving, verify the code against these constraints:
ConstraintCheck
Only allowed top-level functionsNo functions other than get, post, put, patch, del
Every function returns a stringAll code paths return a string (including catch blocks)
try/catch in every functionEvery function body is wrapped in try/catch
Server.Logger in every functionLog at entry, Error in catch
No external dependenciesNo
import
,
require
,
module.exports
No browser APIsNo
fetch
,
XMLHttpRequest
,
setTimeout
,
console.log
,
document
,
window
Async only when neededOnly functions using
await
are marked
async
ECMAScript 2023 compliantStandard JS features only (optional chaining, nullish coalescing, etc. are fine)
保存前,根据以下约束验证代码:
约束检查内容
仅允许顶级函数无get、post、put、patch、del之外的函数
每个函数返回字符串所有代码路径返回字符串(包括catch块)
每个函数包含try/catch每个函数体都包装在try/catch中
每个函数使用Server.Logger入口处记录日志,catch块中记录错误
无外部依赖
import
require
module.exports
无浏览器API
fetch
XMLHttpRequest
setTimeout
console.log
document
window
仅必要时使用Async仅使用
await
的函数标记为
async
符合ECMAScript 2023标准仅使用标准JS功能(可选链、空值合并等是允许的)

5.6 Git Commit

5.6 Git提交

After creating the approved server logic files, do a git commit for the server logic changes.
If the HTML plan was generated inside the project, include it in the same commit (use the actual output path from the render script's JSON response).
Output: Server logic
.js
and
.serverlogic.yml
files created, validated, and committed

创建经批准的Server Logic文件后,对Server Logic更改进行git提交。
如果HTML计划是在项目内生成的,请将其包含在同一提交中(使用渲染脚本JSON响应中的实际输出路径)。
输出:Server Logic
.js
.serverlogic.yml
文件已创建、验证并提交

Phase 6: Configure Table Permissions (Conditional)

阶段6:配置表权限(条件性)

Goal: Set up table permissions for Dataverse tables accessed by
Server.Connector.Dataverse
in the server logic code
This phase only runs when the server logic uses
Server.Connector.Dataverse
.
If the server logic only uses
Server.Connector.HttpClient
(external APIs) or doesn't access Dataverse at all, skip this phase entirely and proceed to Phase 7.
Server.Connector.Dataverse
does NOT bypass table permissions — it respects them. Without table permissions configured, the Dataverse connector silently returns 0 records instead of the actual data. This is a common source of confusion.
Actions:
目标:为Server Logic代码中
Server.Connector.Dataverse
访问的Dataverse表设置表权限
仅当Server Logic使用
Server.Connector.Dataverse
时运行此阶段
。如果Server Logic仅使用
Server.Connector.HttpClient
(外部API)或根本不访问Dataverse,请完全跳过此阶段并继续阶段7。
Server.Connector.Dataverse
不会绕过表权限——它会遵守权限。如果未配置表权限,Dataverse连接器会静默返回0条记录,而非实际数据。这是常见的混淆来源。
操作

6.1 Detect Dataverse Tables and Required Privileges

6.1 检测Dataverse表和所需权限

Parse the server logic
.js
file created in Phase 5 to identify which Dataverse tables are accessed and what CRUD operations are performed:
Dataverse SDK MethodRequired Table Permission
RetrieveMultipleRecords("tablename", ...)
Read
RetrieveRecord("tablename", ...)
Read
CreateRecord("tablename", ...)
Create
UpdateRecord("tablename", ...)
Write
DeleteRecord("tablename", ...)
Delete
Extract the entity set name (first argument) from each method call. Build a mapping:
Table (entity set name)ReadCreateWriteDelete
accounts
Yes
contacts
YesYes
解析阶段5中创建的Server Logic
.js
文件,识别访问的Dataverse表和执行的CRUD操作:
Dataverse SDK方法所需表权限
RetrieveMultipleRecords("tablename", ...)
读取
RetrieveRecord("tablename", ...)
读取
CreateRecord("tablename", ...)
创建
UpdateRecord("tablename", ...)
写入
DeleteRecord("tablename", ...)
删除
从每个方法调用中提取实体集名称(第一个参数)。构建映射:
表(实体集名称)读取创建写入删除
accounts
contacts

6.2 Use the Table Permissions Architect

6.2 使用表权限架构师

When any approved server logic item uses
Server.Connector.Dataverse
, invoke the
table-permissions-architect
agent at
${CLAUDE_PLUGIN_ROOT}/agents/table-permissions-architect.md
to determine and create the required table permissions.
Prompt:
"Analyze this Power Pages code site and propose table permissions for Dataverse tables accessed by the approved server logic plan. The following tables need permissions:
[list each table with required CRUD privileges from step 6.1, grouped by server logic item]
Context:
  • These permissions are needed because the server logic uses
    Server.Connector.Dataverse
    , which respects table permissions — without them, the connector silently returns 0 records.
  • The scope should typically be Global for server logic that fetches all records, unless the server logic filters by the current user (in which case use Contact scope).
  • The web roles assigned to these server logic items are: [list web role names and GUIDs from Phase 5.2]
  • Project root: [path]
Check for existing table permissions and web roles. If new web roles are needed, create them using the create-web-role.js script. Propose a plan, then after approval create the table permission YAML files using the deterministic scripts."
The agent will:
  1. Discover existing table permissions and web roles
  2. Create any missing web roles via
    create-web-role.js
    if needed
  3. Propose a table permissions plan (with HTML visualization)
  4. Present the plan via plan mode for user approval
  5. After approval, create table permission YAML files in
    .powerpages-site/table-permissions/
    using
    create-table-permission.js
当任何经批准的Server Logic项使用
Server.Connector.Dataverse
时,调用位于
${CLAUDE_PLUGIN_ROOT}/agents/table-permissions-architect.md
table-permissions-architect
代理,以确定并创建所需的表权限。
提示:
"分析此Power Pages代码站点,并为经批准的Server Logic计划访问的Dataverse表提出表权限建议。以下表需要权限:
[列出步骤6.1中每个表的所需CRUD权限,按Server Logic项分组]
上下文:
  • 需要这些权限是因为Server Logic使用
    Server.Connector.Dataverse
    ,它会遵守表权限——没有权限的话,连接器会静默返回0条记录。
  • 范围通常应为全局,适用于获取所有记录的Server Logic,除非Server Logic按当前用户过滤(在这种情况下使用联系人范围)。
  • 分配给这些Server Logic项的Web角色是:[列出阶段5.2中的Web角色名称和GUID]
  • 项目根目录:[路径]
检查现有表权限和Web角色。如果需要新的Web角色,请使用create-web-role.js脚本创建。提出计划,然后在批准后使用确定性脚本创建表权限YAML文件。"
代理将:
  1. 发现现有表权限和Web角色
  2. 如果需要,通过
    create-web-role.js
    创建任何缺失的Web角色
  3. 提出表权限计划(带HTML可视化)
  4. 通过计划模式向用户展示计划以获得批准
  5. 批准后,使用
    create-table-permission.js
    .powerpages-site/table-permissions/
    目录下创建表权限YAML文件

6.3 Git Commit

6.3 Git提交

After table permissions (and any new web roles) are created, do a git commit for the table permissions changes.
Output: Table permissions (and web roles if created) configured for all Dataverse tables accessed by the server logic

创建表权限(以及任何新Web角色)后,对表权限更改进行git提交。
输出:已为Server Logic访问的所有Dataverse表配置表权限(以及创建的Web角色,如果有)

Phase 7: Manage Secrets & Environment Variables

阶段7:管理密钥与环境变量

Goal: Securely store any secret values (API keys, client secrets, connection strings) required by the server logic as environment variables in Dataverse, optionally backed by Azure Key Vault
This phase only runs when the server logic requires secret or sensitive configuration values (identified in Phase 2.3). If no secrets are needed, skip this phase and proceed to Phase 8.
Actions:
目标:将Server Logic所需的任何密钥值(API密钥、客户端密钥、连接字符串)安全存储为Dataverse中的环境变量,可选由Azure Key Vault支持
仅当Server Logic需要机密或敏感配置值时运行此阶段(在阶段2.3中识别)。如果不需要密钥,请跳过此阶段并继续阶段8。
操作

7.1 Recall Key Vault Decision

7.1 回顾Key Vault决策

The user already chose whether to use Azure Key Vault in Phase 2.3.1 (before the plan was presented). Use that decision here — do not re-ask.
用户已在阶段2.3.1(展示计划前)选择是否使用Azure Key Vault。在此处使用该决策——请勿重新询问

7.2a Azure Key Vault Path

7.2a Azure Key Vault路径

If the user chose Azure Key Vault in Phase 2.3.1:
Step 1 — List available Key Vaults:
powershell
node "${CLAUDE_PLUGIN_ROOT}/scripts/list-azure-keyvaults.js"
The script outputs a JSON array of Key Vaults (
name
,
resourceGroup
,
location
) from the user's Azure subscription.
Step 2 — Select or create a Key Vault:
If Key Vaults were found, present the list and ask which one to use:
Use
AskUserQuestion
:
QuestionContext
Which Azure Key Vault would you like to use for storing secrets?Present the names from the script output
If no Key Vaults are found, ask the user how to proceed:
Use
AskUserQuestion
:
QuestionOptions
No Azure Key Vaults were found in your subscription. Would you like to create one, or fall back to storing secrets directly as environment variables?Create a new Key Vault (Recommended), Store directly as environment variable
If "Create a new Key Vault": Ask for a vault name, resource group, and location, then create it:
Use
AskUserQuestion
:
QuestionContext
What name, resource group, and Azure region would you like for the new Key Vault?Vault names must be 3-24 characters, globally unique, start with a letter, and contain only alphanumerics and hyphens. Suggest a name based on the project/site name.
powershell
node "${CLAUDE_PLUGIN_ROOT}/scripts/create-azure-keyvault.js" \
  --name "<vault-name>" \
  --resourceGroup "<resource-group>" \
  --location "<location>"
The script outputs a JSON object with
name
,
resourceGroup
, and
location
. Use the created vault for the remaining steps.
If "Store directly as environment variable": Skip the rest of Phase 7.2a and proceed to Phase 7.2b (direct environment variable path).
Step 3 — Provide instructions for storing each secret in Key Vault:
For each secret identified in Phase 2.3, give the user instructions to store the value themselves. Do not ask for the secret value — secret values must never pass through the conversation.
Present both methods (CLI and Azure Portal) so the user can choose whichever they prefer:
Option A — Azure CLI (recommended for automation):
Present the commands as a numbered list the user can copy and run. Use the stdin form so the secret value does not appear in process listings:
For each secret, run the following command (replacing <YOUR_SECRET_VALUE> with the actual value):

1. <secret-name>:
   printf '%s' '<YOUR_SECRET_VALUE>' | node "${CLAUDE_PLUGIN_ROOT}/scripts/store-keyvault-secret.js" \
     --vaultName "<selected-vault>" \
     --secretName "<secret-name>"
Tell the user each command outputs a JSON object with a
secretUri
and to share the output (which contains only the URI, not the secret) so the workflow can continue.
Option B — Azure Portal:
Provide these steps for each secret:
1. Go to the Azure Portal (https://portal.azure.com)
2. Search for "Key vaults" in the top search bar and select it
3. Select the Key Vault: <selected-vault>
4. In the left menu under "Objects", click "Secrets"
5. Click "+ Generate/Import" at the top
6. Fill in the fields:
   - Upload options: Manual
   - Name: <secret-name>
   - Secret value: paste your secret value here
   - Leave other fields as defaults
7. Click "Create"
8. After creation, click on the secret name, then click the current version
9. Copy the "Secret Identifier" URI and share it here so the workflow can continue
Tell the user the Secret Identifier URI looks like
https://<vault-name>.vault.azure.net/secrets/<secret-name>/<version>
and that this URI (not the secret value) is what should be shared back.
Step 4 — Create environment variable in Dataverse:
After the user shares the
secretUri
output from each command, create an environment variable definition in Dataverse that references the Key Vault secret. Use the
secret
type:
powershell
node "${CLAUDE_PLUGIN_ROOT}/scripts/create-environment-variable.js" "<ENV_URL>" \
  --schemaName "<prefix_SecretName>" \
  --displayName "<Secret Display Name>" \
  --type "secret" \
  --value "<secretUri-from-step-3>"
Step 5 — Create site setting for the environment variable:
For each environment variable, create a site setting YAML that maps to it:
powershell
node "${CLAUDE_PLUGIN_ROOT}/scripts/create-site-setting.js" \
  --projectRoot "<PROJECT_ROOT>" \
  --name "<SiteSetting/Name>" \
  --envVarSchema "<schemaName-from-step-4>"
This creates a site setting with
envvar_schema
and
source: 1
, which tells Power Pages to resolve the value from the Dataverse environment variable (backed by Key Vault).
如果用户在阶段2.3.1中选择了Azure Key Vault:
步骤1 — 列出可用的Key Vault:
powershell
node "${CLAUDE_PLUGIN_ROOT}/scripts/list-azure-keyvaults.js"
脚本输出用户Azure订阅中的Key Vault数组(
name
resourceGroup
location
)。
步骤2 — 选择或创建Key Vault:
如果找到Key Vault,展示列表并询问使用哪个:
使用
AskUserQuestion
问题上下文
您想使用哪个Azure Key Vault存储密钥?展示脚本输出中的名称
如果未找到Key Vault,询问用户如何继续:
使用
AskUserQuestion
问题选项
在您的订阅中未找到Azure Key Vault。您想创建一个,还是回退到直接将密钥存储为环境变量?创建新的Key Vault(推荐),直接存储为环境变量
如果选择“创建新的Key Vault”:询问Vault名称、资源组和位置,然后创建:
使用
AskUserQuestion
问题上下文
您希望新Key Vault使用什么名称、资源组和Azure区域?Vault名称必须为3-24个字符,全局唯一,以字母开头,仅包含字母数字和连字符。根据项目/站点名称建议一个名称。
powershell
node "${CLAUDE_PLUGIN_ROOT}/scripts/create-azure-keyvault.js" \
  --name "<vault-name>" \
  --resourceGroup "<resource-group>" \
  --location "<location>"
脚本输出包含
name
resourceGroup
location
的JSON对象。使用创建的Vault完成剩余步骤。
如果选择“直接存储为环境变量”:跳过阶段7.2a的其余部分,继续阶段7.2b(直接环境变量路径)。
步骤3 — 提供在Key Vault中存储每个密钥的说明:
对于阶段2.3中识别的每个密钥,向用户提供自行存储值的说明。请勿询问密钥值——密钥值绝不能通过对话传递。
同时提供两种方法(CLI和Azure门户),以便用户选择偏好的方法:
选项A — Azure CLI(推荐用于自动化):
将命令作为编号列表展示,用户可以复制并运行。使用stdin形式,使密钥值不会出现在进程列表中:
对于每个密钥,运行以下命令(将<YOUR_SECRET_VALUE>替换为实际值):

1. <secret-name>:
   printf '%s' '<YOUR_SECRET_VALUE>' | node "${CLAUDE_PLUGIN_ROOT}/scripts/store-keyvault-secret.js" \
     --vaultName "<selected-vault>" \
     --secretName "<secret-name>"
告知用户每个命令输出包含
secretUri
的JSON对象,并要求用户分享输出(仅包含URI,不包含密钥)以便工作流程继续。
选项B — Azure门户:
为每个密钥提供以下步骤:
1. 转到Azure门户(https://portal.azure.com)
2. 在顶部搜索栏中搜索“Key vaults”并选择
3. 选择Key Vault:<selected-vault>
4. 在左侧菜单的“对象”下,点击“Secrets”
5. 点击顶部的“+ 生成/导入”
6. 填写字段:
   - 上传选项:手动
   - 名称:<secret-name>
   - 密钥值:在此粘贴您的密钥值
   - 其他字段保留默认值
7. 点击“创建”
8. 创建后,点击密钥名称,然后点击当前版本
9. 复制“密钥标识符”URI并在此分享,以便工作流程继续
告知用户密钥标识符URI类似于
https://<vault-name>.vault.azure.net/secrets/<secret-name>/<version>
,并且应分享此URI(而非密钥值)。
步骤4 — 在Dataverse中创建环境变量:
用户分享每个命令的
secretUri
输出后,在Dataverse中创建引用Key Vault密钥的环境变量定义。使用
secret
类型:
powershell
node "${CLAUDE_PLUGIN_ROOT}/scripts/create-environment-variable.js" "<ENV_URL>" \
  --schemaName "<prefix_SecretName>" \
  --displayName "<Secret Display Name>" \
  --type "secret" \
  --value "<secretUri-from-step-3>"
步骤5 — 为环境变量创建站点设置:
对于每个环境变量,创建映射到它的站点设置YAML:
powershell
node "${CLAUDE_PLUGIN_ROOT}/scripts/create-site-setting.js" \
  --projectRoot "<PROJECT_ROOT>" \
  --name "<SiteSetting/Name>" \
  --envVarSchema "<schemaName-from-step-4>"
这会创建包含
envvar_schema
source: 1
的站点设置,告知Power Pages从Dataverse环境变量(由Key Vault支持)解析值。

7.2b Direct Environment Variable Path

7.2b 直接环境变量路径

If the user chose not to use Azure Key Vault:
Step 1 — Create environment variables with placeholder values:
For each secret identified in Phase 2.3, create the environment variable in Dataverse with a placeholder value:
powershell
node "${CLAUDE_PLUGIN_ROOT}/scripts/create-environment-variable.js" "<ENV_URL>" \
  --schemaName "<prefix_SecretName>" \
  --displayName "<Secret Display Name>" \
  --value "PLACEHOLDER_SET_ACTUAL_VALUE"
Step 2 — Create site setting for the environment variable:
powershell
node "${CLAUDE_PLUGIN_ROOT}/scripts/create-site-setting.js" \
  --projectRoot "<PROJECT_ROOT>" \
  --name "<SiteSetting/Name>" \
  --envVarSchema "<schemaName-from-step-1>"
Step 3 — Give the user steps to set the actual secret values:
Do not ask for secret values — they must never pass through the conversation. Instead, tell the user to update each placeholder with the real value using one of these approaches:
  1. Power Apps maker portal (make.powerapps.com) — Go to SolutionsDefault SolutionEnvironment variables → find the variable by display name → update the value
Present the list of environment variables that need updating (display name and schema name for each) so the user knows exactly which ones to set.
如果用户选择不使用Azure Key Vault:
步骤1 — 使用占位符值创建环境变量:
对于阶段2.3中识别的每个密钥,在Dataverse中使用占位符值创建环境变量:
powershell
node "${CLAUDE_PLUGIN_ROOT}/scripts/create-environment-variable.js" "<ENV_URL>" \
  --schemaName "<prefix_SecretName>" \
  --displayName "<Secret Display Name>" \
  --value "PLACEHOLDER_SET_ACTUAL_VALUE"
步骤2 — 为环境变量创建站点设置:
powershell
node "${CLAUDE_PLUGIN_ROOT}/scripts/create-site-setting.js" \
  --projectRoot "<PROJECT_ROOT>" \
  --name "<SiteSetting/Name>" \
  --envVarSchema "<schemaName-from-step-1>"
步骤3 — 向用户提供设置实际密钥值的步骤:
请勿询问密钥值——它们绝不能通过对话传递。相反,告知用户使用以下方法之一更新每个占位符为实际值:
  1. Power Apps制作者门户make.powerapps.com)——转到解决方案默认解决方案环境变量 → 按显示名称查找变量 → 更新值
展示需要更新的环境变量列表(每个变量的显示名称和架构名称),以便用户确切知道要设置哪些变量。

7.3 Verify Environment Variable Configuration

7.3 验证环境变量配置

After creating all environment variables and site settings:
  • Confirm each site setting YAML was created in
    .powerpages-site/site-settings/
  • Verify each YAML contains
    envvar_schema
    and
    source: 1
  • Confirm the server logic code references the correct site setting names via
    Server.Sitesetting.Get("<SiteSetting/Name>")
创建所有环境变量和站点设置后:
  • 确认每个站点设置YAML已在
    .powerpages-site/site-settings/
    目录下创建
  • 验证每个YAML包含
    envvar_schema
    source: 1
  • 确认Server Logic代码通过
    Server.Sitesetting.Get("<SiteSetting/Name>")
    引用正确的站点设置名称

7.4 Git Commit

7.4 Git提交

Do a git commit for the environment variable site setting changes.
Output: Environment variables created in Dataverse (with or without Azure Key Vault backing), site settings configured, server logic referencing correct setting names

对环境变量站点设置更改进行git提交。
输出:已在Dataverse中创建环境变量(带或不带Azure Key Vault支持),已配置站点设置,Server Logic引用正确的设置名称

Phase 8: Configure Site Settings

阶段8:配置站点设置

Goal: Set up site settings for the server logic feature
Actions:
目标:为Server Logic功能设置站点设置
操作

8.1 Configure Server Logic Site Settings

8.1 配置Server Logic站点设置

The
.powerpages-site
folder is guaranteed to exist at this point (verified in Phase 1.5).
The following site settings control server logic behavior. Only create settings that differ from defaults or are specifically needed:
SettingDescriptionDefaultWhen to configure
ServerLogic/Enabled
Enable/disable server logic feature
true
Only if explicitly disabled and needs re-enabling
ServerLogic/AllowedDomains
Restrict which external domains HttpClient can callAll domainsWhen the server logic calls external APIs and you want to restrict to specific domains for security
ServerLogic/TimeoutInSeconds
Maximum execution time
120
The platform caps this at 120 seconds — values above 120 are silently clamped. Only configure when you need to lower the timeout, not raise it.
ServerLogic/AllowNetworkingToAllDomains
Allow networking across domains
true
Set to
false
when restricting via AllowedDomains
Use the existing site setting creation script:
powershell
node "${CLAUDE_PLUGIN_ROOT}/scripts/create-site-setting.js" --projectRoot "<PROJECT_ROOT>" --name "ServerLogic/AllowedDomains" --value "api.example.com,api.other.com" --description "Restrict server logic external API calls to these domains"
此时
.powerpages-site
文件夹肯定存在(在阶段1.5中已验证)。
以下站点设置控制Server Logic行为。仅创建与默认值不同或特别需要的设置:
设置描述默认值配置场景
ServerLogic/Enabled
启用/禁用Server Logic功能
true
仅当明确禁用并需要重新启用时
ServerLogic/AllowedDomains
限制HttpClient可以调用的外部域所有域当Server Logic调用外部API并希望限制为特定域以提高安全性时
ServerLogic/TimeoutInSeconds
最大执行时间
120
平台将此值上限为120秒——超过120的值会被静默限制。仅在需要降低超时时配置,不要提高。
ServerLogic/AllowNetworkingToAllDomains
允许跨域联网
true
当通过AllowedDomains限制时设置为
false
使用现有的站点设置创建脚本:
powershell
node "${CLAUDE_PLUGIN_ROOT}/scripts/create-site-setting.js" --projectRoot "<PROJECT_ROOT>" --name "ServerLogic/AllowedDomains" --value "api.example.com,api.other.com" --description "Restrict server logic external API calls to these domains"

8.2 Git Commit

8.2 Git提交

If any settings were created:
Do a git commit for the site settings changes.
Output: Site settings configured and committed (or skipped if not needed/deployed)

如果创建了任何设置:
对站点设置更改进行git提交。
输出:已配置并提交站点设置(如果不需要/已部署则跳过)

Phase 9: Client-Side Integration

阶段9:客户端集成

Goal: Help the user call the server logic endpoints from their site's frontend code, matching existing patterns discovered in Phase 1
Server logic creates the backend — but without frontend code to call it, the endpoints are unused. This phase creates or updates frontend code to consume the server logic APIs, using the patterns and conventions already established in the codebase.
Actions:
目标:帮助用户从其站点的前端代码调用Server Logic端点,匹配阶段1中发现的现有模式
Server Logic创建后端——但如果没有前端代码调用,端点将无法使用。此阶段创建或更新前端代码以使用Server Logic API,使用代码库中已建立的模式和约定。
操作

9.1 Ask User About Integration Scope

9.1 询问用户集成范围

Use
AskUserQuestion
:
QuestionOptions
I've created the server logic backend. Would you like me to also fully integrate it into the frontend UI?Yes, fully integrate it into the UI (Recommended), No, I'll handle the frontend myself
If "No": Skip to Phase 10, but provide the API URL and a code snippet the user can copy.
使用
AskUserQuestion
问题选项
我已创建Server Logic后端。是否要将其完全集成到前端UI中?是,完全集成到UI中(推荐);否,我将自行处理前端
如果选择“否”:跳至阶段10,但提供API URL和用户可以复制的代码片段。

9.2 Follow the Frontend Integration Reference

9.2 遵循前端集成参考

Use the reference below for the frontend integration approach, examples, and framework-specific patterns:
Reference:
${CLAUDE_PLUGIN_ROOT}/skills/add-server-logic/references/frontend-integration-reference.md
Based on the Explore agent's findings from Phase 1.4 and the approved plan, choose the integration approach from that reference and apply it consistently across all server logic endpoints being wired into the frontend.
使用以下参考获取前端集成方法、示例和框架特定模式:
参考:
${CLAUDE_PLUGIN_ROOT}/skills/add-server-logic/references/frontend-integration-reference.md
根据阶段1.4中Explore代理的发现和经批准的计划,从该参考中选择集成方法,并一致应用于所有要接入前端的Server Logic端点。

9.3 Create or Update Frontend Integration

9.3 创建或更新前端集成

Following the reference:
  • Reuse the existing service layer or API utility when the site already has one
  • Create a lightweight CSRF-aware helper only when the site has no established API client pattern
  • Group multiple server logic endpoints into a coherent service module when that improves maintainability
  • Add framework-specific hooks/composables/services only when the codebase already follows that pattern
  • Fully integrate the server logic into the actual UI flow — do not stop at creating service/helper code
  • Update the relevant pages, components, forms, buttons, or user journeys so the new backend behavior is reachable from the interface
  • Replace placeholder data, mock handlers, or temporary actions when they are meant to be backed by the new server logic endpoints
  • Add or preserve loading, success, empty, and error states so the UI behaves like a finished feature
  • For validate-and-execute endpoints: The frontend must call the server logic endpoint for the protected operation (e.g., status transition) — it must NOT make a separate Web API PATCH for the same field. Ensure the UI for that operation (e.g., a "Submit" or "Approve" button) calls the server logic service function, not the Web API service
遵循参考:
  • 当站点已有服务层或API工具时重用现有服务层或API工具
  • 仅当站点没有已建立的API客户端模式时创建轻量级支持CSRF的助手
  • 当提高可维护性时,将多个Server Logic端点分组到连贯的服务模块中
  • 仅当代码库已遵循该模式时添加框架特定的钩子/组合式/服务
  • 将Server Logic完全集成到实际UI流程中——不要仅停留在创建服务/助手代码
  • 更新相关页面、组件、表单、按钮或用户旅程,使新的后端行为可从界面访问
  • 当占位符数据、模拟处理程序或临时操作旨在由新的Server Logic端点支持时,替换它们
  • 添加或保留加载、成功、空和错误状态,使UI表现为完整功能
  • 对于验证并执行端点:前端必须调用Server Logic端点以执行受保护的操作(例如状态转换)——不得对同一字段进行单独的Web API PATCH调用。确保该操作的UI(例如“提交”或“批准”按钮)调用Server Logic服务函数,而非Web API服务

9.4 Git Commit

9.4 Git提交

If frontend integration code was created:
Do a git commit for the frontend integration changes.
Output: Frontend service/hook created as needed, UI components/pages fully integrated, and changes committed

如果创建了前端集成代码:
对前端集成更改进行git提交。
输出:已根据需要创建前端服务/钩子,UI组件/页面已完全集成,更改已提交

Phase 10: Verify & Test Guidance

阶段10:验证与测试指南

Goal: Validate the code and provide the user with everything needed to test the server logic
Actions:
目标:验证代码并为用户提供测试Server Logic所需的一切
操作

10.1 Final Code Validation

10.1 最终代码验证

Re-read each created
.js
file and verify:
  • Only allowed top-level functions (get, post, put, patch, del)
  • Every function returns a string
  • try/catch in every function
  • Server.Logger calls in every function
  • No
    import
    ,
    require
    , or external dependencies
  • No browser APIs (
    fetch
    ,
    XMLHttpRequest
    ,
    setTimeout
    ,
    console.log
    ,
    document
    ,
    window
    )
  • Async only on functions that use await
  • Correct SDK method usage (verified against Phase 3 documentation)
  • HttpClient used only for external APIs (not Dataverse)
  • Dataverse connector used for Dataverse operations
Re-read each
.serverlogic.yml
file and verify:
  • id
    field exists and is a valid UUID
  • adx_serverlogic_adx_webrole
    array is non-empty (at least one web role)
  • name
    matches the folder name and
    .js
    file name
  • display_name
    and
    description
    are populated
  • Fields are alphabetically sorted
  • File names match: folder name,
    .js
    name,
    .serverlogic.yml
    name, and
    name
    field all use the same value
重新读取每个创建的
.js
文件并验证:
  • 仅允许顶级函数(get、post、put、patch、del)
  • 每个函数返回字符串
  • 每个函数包含try/catch
  • 每个函数使用Server.Logger调用
  • import
    require
    或外部依赖
  • 无浏览器API(
    fetch
    XMLHttpRequest
    setTimeout
    console.log
    document
    window
  • 仅使用await的函数标记为Async
  • 正确的SDK方法使用(已根据阶段3文档验证)
  • HttpClient仅用于外部API(非Dataverse)
  • Dataverse连接器用于Dataverse操作
重新读取每个
.serverlogic.yml
文件并验证:
  • id
    字段存在且是有效的UUID
  • adx_serverlogic_adx_webrole
    数组非空(至少一个Web角色)
  • name
    与文件夹名称和
    .js
    文件名匹配
  • display_name
    description
    已填充
  • 字段按字母顺序排序
  • 文件名匹配:文件夹名称、
    .js
    名称、
    .serverlogic.yml
    名称和
    name
    字段都使用相同的值

10.2 Provide API URL

10.2 提供API URL

Tell the user each endpoint URL:
https://<site-url>/_api/serverlogics/<server-logic-name>
告知用户每个端点的URL:
https://<site-url>/_api/serverlogics/<server-logic-name>

10.3 Test Guidance

10.3 测试指南

Provide testing instructions:
  1. Deploy the site first — The server logic must be deployed via
    /deploy-site
    before it can be called
  2. CSRF token required for non-GET requests — POST, PUT, PATCH, and DELETE calls to server logic endpoints require a CSRF token. Fetch the token from
    /_layout/tokenhtml
    and include it as
    __RequestVerificationToken
    header. GET requests are exempt from antiforgery validation — no token is needed for read-only calls.
  3. Authentication — Server logic respects the site's authentication. Calls from authenticated sessions use cookie-based auth automatically. Anonymous access depends on governance settings.
  4. Testing from browser console:
Use the frontend integration reference from Phase 9 for the exact calling pattern that matches the site's stack.
  1. Check diagnostics — Server.Logger output can be viewed in Power Pages design studio diagnostics
Output: Code validated, API URL provided, test guidance given

提供测试说明:
  1. 先部署站点 — Server Logic必须通过
    /deploy-site
    部署后才能调用
  2. 非GET请求需要CSRF令牌 — 对Server Logic端点的POST、PUT、PATCH和DELETE调用需要CSRF令牌。从
    /_layout/tokenhtml
    获取令牌并作为
    __RequestVerificationToken
    标头包含。GET请求豁免反伪造验证——只读调用不需要令牌。
  3. 身份验证 — Server Logic遵守站点的身份验证。来自已认证会话的调用自动使用基于Cookie的身份验证。匿名访问取决于治理设置。
  4. 从浏览器控制台测试
使用阶段9中的前端集成参考获取与站点堆栈匹配的确切调用模式。
  1. 检查诊断 — Server.Logger输出可在Power Pages设计工作室诊断中查看
输出:代码已验证,API URL已提供,测试指南已给出

Phase 11: Review & Deploy

阶段11:审核与部署

Goal: Present a summary of all work performed and offer deployment
Actions:
目标:展示所有执行工作的摘要并提供部署选项
操作

11.1 Record Skill Usage

11.1 记录技能使用情况

Reference:
${CLAUDE_PLUGIN_ROOT}/references/skill-tracking-reference.md
Follow the skill tracking instructions in the reference to record this skill's usage. Use
--skillName "AddServerLogic"
.
参考:
${CLAUDE_PLUGIN_ROOT}/references/skill-tracking-reference.md
遵循参考中的技能跟踪说明记录此技能的使用情况。使用
--skillName "AddServerLogic"

11.2 Present Summary

11.2 展示摘要

Present a summary of everything that was done:
StepStatusDetails
Server Logic JSCreatedList each created
.powerpages-site/server-logic/<name>/<name>.js
file
Server Logic YAMLCreatedList each created
.powerpages-site/server-logic/<name>/<name>.serverlogic.yml
file
HTML PlanCreated/UpdatedActual path from render script output
FunctionsImplementedSummarize methods implemented per server logic item
SDK Features UsedSummarize features used per server logic item
Table PermissionsCreated/Skipped
accounts
(Read),
contacts
(Read, Create), etc.
Secrets & Env VarsCreated/SkippedEnvironment variables (Key Vault-backed or direct), site settings with
envvar_schema
Site SettingsCreated/SkippedServerLogic/AllowedDomains, etc.
Client-Side ServiceCreated/SkippedList created or updated frontend service files
UI IntegrationCreated/SkippedPages, components, forms, or actions fully wired to the server logic endpoints
API URLList each
/_api/serverlogics/<name>
URL
展示已完成的所有工作的摘要:
步骤状态详细信息
Server Logic JS已创建列出每个已创建的
.powerpages-site/server-logic/<name>/<name>.js
文件
Server Logic YAML已创建列出每个已创建的
.powerpages-site/server-logic/<name>/<name>.serverlogic.yml
文件
HTML计划已创建/更新渲染脚本输出的实际路径
函数已实现总结每个Server Logic项实现的方法
使用的SDK功能总结每个Server Logic项使用的功能
表权限已创建/已跳过
accounts
(读取)、
contacts
(读取、创建)等
密钥与环境变量已创建/已跳过环境变量(Key Vault支持或直接存储)、带
envvar_schema
的站点设置
站点设置已创建/已跳过ServerLogic/AllowedDomains等
客户端服务已创建/已跳过列出已创建或更新的前端服务文件
UI集成已创建/已跳过已完全接入Server Logic端点的页面、组件、表单或操作
API URL列出每个
/_api/serverlogics/<name>
URL

11.3 Ask to Deploy

11.3 询问是否部署

Use
AskUserQuestion
:
QuestionOptions
The server logic work is ready. To make it live, the site needs to be deployed. Would you like to deploy now?Yes, deploy now (Recommended), No, I'll deploy later
If "Yes, deploy now": Invoke the
/deploy-site
skill to deploy the site.
After deployment succeeds, use
AskUserQuestion
:
QuestionOptions
The site has been deployed. Would you like me to run
/test-site
to validate it now?
Yes, run
/test-site
(Recommended), No, skip testing
If "Yes, run
/test-site
"
: Invoke the
/test-site
skill.
If "No, I'll deploy later": Acknowledge and remind:
"No problem! Remember to deploy your site using
/deploy-site
when you're ready. The server logic endpoints won't be accessible until the site is deployed."
使用
AskUserQuestion
问题选项
Server Logic工作已准备就绪。要使其生效,需要部署站点。是否现在部署?是,立即部署(推荐);否,我稍后部署
如果选择“是,立即部署”:调用
/deploy-site
技能部署站点。
部署成功后,使用
AskUserQuestion
问题选项
站点已部署。是否要运行
/test-site
立即验证?
是,运行
/test-site
(推荐);否,跳过测试
如果选择“是,运行
/test-site
:调用
/test-site
技能。
如果选择“否,我稍后部署”:确认并提醒:
"没问题!准备好后请使用
/deploy-site
部署站点。Server Logic端点在站点部署前无法访问。"

11.4 Post-Deploy Notes

11.4 部署后注意事项

After deployment (or if skipped), remind the user:
  • Test the endpoints: Call each
    /_api/serverlogics/<name>
    URL with the appropriate HTTP method (include CSRF token for non-GET requests)
  • Recommended full-site validation: After deployment, ask whether to run
    /test-site
    so the live site can be validated end to end
  • Check logs: Use Server.Logger output in Power Pages design studio diagnostics to debug issues
  • Table permissions: Table permissions were configured for Dataverse tables used by this server logic. If you add new Dataverse tables later, run the table permissions setup again — without permissions,
    Server.Connector.Dataverse
    silently returns 0 records
  • Timeout: Default execution timeout is 120 seconds — this is also the platform maximum (values above 120 are silently clamped)
  • Anonymous access: If the site's governance control disables anonymous access, anonymous users cannot invoke server logic that integrates with external systems
  • Preview feature: Server Logic is currently in preview — monitor Microsoft Learn for updates
  • Environment variables with placeholder values: If Phase 7 created environment variables with placeholder values, remind the user to update them with the actual secret values before testing. They can do this via:
    1. Power Platform admin centerEnvironments → select environment → Environment variables → find by display name → update value
    2. Power Apps maker portalSolutions → open solution → Environment variables → edit value
Output: Summary presented, deployment completed or deferred, post-deploy guidance provided

部署后(或如果跳过部署),提醒用户:
  • 测试端点:使用适当的HTTP方法调用每个
    /_api/serverlogics/<name>
    URL(非GET请求包含CSRF令牌)
  • 推荐全站点验证:部署后,询问是否运行
    /test-site
    以端到端验证实时站点
  • 检查日志:使用Power Pages设计工作室诊断中的Server.Logger输出调试问题
  • 表权限:已为此Server Logic使用的Dataverse表配置表权限。如果以后添加新的Dataverse表,请再次运行表权限设置——没有权限的话,
    Server.Connector.Dataverse
    会静默返回0条记录
  • 超时:默认执行超时为120秒——这也是平台最大值(超过120的值会被静默限制)
  • 匿名访问:如果站点的治理控制禁用匿名访问,匿名用户无法调用与外部系统集成的Server Logic
  • 预览功能:Server Logic目前处于预览阶段——请关注Microsoft Learn的更新
  • 带占位符值的环境变量:如果阶段7创建了带占位符值的环境变量,提醒用户在测试前更新为实际密钥值。他们可以通过以下方式操作:
    1. Power Platform管理中心环境 → 选择环境 → 环境变量 → 按显示名称查找 → 更新值
    2. Power Apps制作者门户解决方案 → 打开解决方案 → 环境变量 → 编辑值
输出:已展示摘要,已完成或推迟部署,已提供部署后指南

Important Notes

重要说明

Throughout All Phases

所有阶段通用

  • Use TaskCreate/TaskUpdate to track progress at every phase
  • Always fetch Microsoft Learn docs in Phase 3 before writing code — the docs are the source of truth
  • Ask for user confirmation at key decision points
  • Commit at milestones — after server logic code, table permissions (if any), secrets/environment variables (if any), site settings, and frontend integration (if any)
  • Validate thoroughly — server logic has strict constraints and violations cause runtime errors
  • 使用TaskCreate/TaskUpdate在每个阶段跟踪进度
  • 始终在阶段3获取Microsoft Learn文档后再编写代码——文档是权威来源
  • 在关键决策点征求用户确认
  • 在里程碑处提交——Server Logic代码后、表权限(如有)后、密钥/环境变量(如有)后、站点设置后、前端集成(如有)后
  • 彻底验证——Server Logic有严格的约束,违反会导致运行时错误

Key Decision Points (Wait for User)

关键决策点(等待用户)

  1. At Phase 1.5: Deploy now or cancel (if
    .powerpages-site
    missing — mandatory)
  2. At Phase 2.1.2: Use existing Dataverse custom actions or build from scratch (if custom actions found)
  3. At Phase 2: Confirm requirements (purpose, name, HTTP methods, secrets)
  4. At Phase 4: Approve implementation plan before writing code
  5. At Phase 6.2: Review and approve the
    table-permissions-architect
    plan (if Dataverse connector is used)
  6. At Phase 2.3.1: Choose Azure Key Vault or direct environment variable (if secrets needed)
  7. At Phase 7.2a Step 2: Create a new Key Vault or fall back to direct environment variable (if no vaults found)
  8. At Phase 9.1: Create frontend integration or skip
  9. At Phase 11.3: Deploy now or deploy later
  1. 在阶段1.5:立即部署或取消(如果缺少
    .powerpages-site
    ——必填)
  2. 在阶段2.1.2:使用现有Dataverse自定义操作或从头构建(如果找到自定义操作)
  3. 在阶段2:确认需求(用途、名称、HTTP方法、密钥)
  4. 在阶段4:编写代码前批准实施计划
  5. 在阶段6.2:审核并批准
    table-permissions-architect
    计划(如果使用Dataverse连接器)
  6. 在阶段2.3.1:选择Azure Key Vault或直接环境变量(如果需要密钥)
  7. 在阶段7.2a步骤2:创建新的Key Vault或回退到直接环境变量(如果未找到Vault)
  8. 在阶段9.1:创建前端集成或跳过
  9. 在阶段11.3:立即部署或稍后部署

SDK Pattern Source of Truth

SDK模式权威来源

Do not treat this skill file as the canonical SDK reference. The Phase 3 Microsoft Learn fetch is the source of truth for SDK usage patterns, supported methods, signatures, and connector behavior. Keep only task-specific decisions in the plan and implementation notes.
请勿将此技能文件视为规范SDK参考。阶段3中的Microsoft Learn获取是SDK使用模式、支持方法、签名和连接器行为的权威来源。仅在计划和实施说明中保留任务特定决策。

Progress Tracking

进度跟踪

Before starting Phase 1, create a task list with all phases using
TaskCreate
:
Task subjectactiveFormDescription
Verify site existsVerifying site prerequisitesLocate project root, detect framework, explore existing server logics and frontend patterns, verify .powerpages-site exists (mandatory)
Understand requirementsGathering requirementsDetermine user intent, whether one or more server logic files are needed, the methods/features for each item, discover Dataverse custom actions, and any secrets required
Fetch latest documentationFetching Microsoft Learn docsQuery Microsoft Learn for current Server Logic SDK reference and samples
Review implementation planReviewing plan with userPresent plan (server logic inventory, functions, SDK features, external APIs, secrets) and confirm before writing code
Implement server logicWriting server logic codeDetermine/create required web roles, create approved
.js
and
.serverlogic.yml
files, validate code
Configure table permissionsSetting up Dataverse table permissions(Conditional) Parse
.js
files for Dataverse tables, launch
table-permissions-architect
, create permission YAML files
Manage secrets and environment variablesConfiguring secrets and env vars(Conditional) Recommend Azure Key Vault, list vaults, store secrets, create environment variables in Dataverse, create site settings with envvar_schema
Configure site settingsConfiguring site settingsSet up ServerLogic/* site settings if needed
Client-side integrationWiring frontend to server logicFollow the frontend integration reference, create/update service files as needed, and fully wire the UI to the server logic endpoints
Verify and test guidanceValidating and providing test guidanceFinal validation, API URLs, CSRF token instructions, testing guide
Review and deployReviewing summary and deployingPresent summary, ask about deployment, provide post-deploy guidance
Mark each task
in_progress
when starting it and
completed
when done via
TaskUpdate
. Use
TaskList
between phase transitions and before the final summary to confirm there are no incomplete work items left.

Begin with Phase 1: Verify Site Exists
开始阶段1前,使用
TaskCreate
创建包含所有阶段的任务列表:
任务主题activeForm描述
验证站点存在Verifying site prerequisites定位项目根目录、检测框架、探索现有Server Logic和前端模式、验证.powerpages-site存在(必填)
理解需求Gathering requirements确定用户意图、是否需要一个或多个Server Logic文件、每个项的方法/功能、发现Dataverse自定义操作以及任何所需密钥
获取最新文档Fetching Microsoft Learn docs查询Microsoft Learn获取当前Server Logic SDK参考和示例
审核实施计划Reviewing plan with user展示计划(Server Logic清单、函数、SDK功能、外部API、密钥)并在编写代码前确认
实现Server LogicWriting server logic code确定/创建所需Web角色、创建经批准的.js和.serverlogic.yml文件、验证代码
配置表权限Setting up Dataverse table permissions(条件性)解析.js文件查找Dataverse表、启动table-permissions-architect、创建权限YAML文件
管理密钥与环境变量Configuring secrets and env vars(条件性)推荐Azure Key Vault、列出Vault、存储密钥、在Dataverse中创建环境变量、创建带envvar_schema的站点设置
配置站点设置Configuring site settings根据需要设置ServerLogic/*站点设置
客户端集成Wiring frontend to server logic遵循前端集成参考、根据需要创建/更新服务文件、并将UI完全接入Server Logic端点
验证与测试指南Validating and providing test guidance最终验证、API URL、CSRF令牌说明、测试指南
审核与部署Reviewing summary and deploying展示摘要、询问部署情况、提供部署后指南
开始每个任务时标记为
in_progress
,完成时通过
TaskUpdate
标记为
completed
。在阶段转换之间和最终摘要前使用
TaskList
确认没有未完成的工作项。

从阶段1:验证站点存在开始