add-server-logic
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePlugin check: Run— if it outputs a message, show it to the user before proceeding.node "${CLAUDE_PLUGIN_ROOT}/scripts/check-version.js"
插件检查:运行— 如果脚本输出消息,请在继续操作前展示给用户。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, or any DOM API. No npm packages are available.setTimeout - Five functions only: A server logic file can only export these top-level functions: ,
get,post,put,patch. The namedelis a reserved word in JavaScript and cannot be used.delete - Always return a string: Every function must return a string. Use when returning objects or arrays.
JSON.stringify() - 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 (
folder must exist) — server logic files live inside.powerpages-site, so deployment is required before any server logic can be created.powerpages-site/server-logic/
Initial request: $ARGUMENTS
- Microsoft Learn为权威来源:编写代码前务必获取最新文档。Server Logic功能目前处于预览阶段,SDK可能会发生变化——切勿仅依赖缓存的知识。
- 无浏览器API,无依赖项:Server Logic在支持ECMAScript 2023的沙箱服务器环境中运行。不存在、
fetch、XMLHttpRequest或任何DOM API,也无法使用npm包。setTimeout - 仅支持五种函数:Server Logic文件只能导出以下顶级函数:、
get、post、put、patch。del是JavaScript的保留字,无法使用。delete - 始终返回字符串:每个函数必须返回字符串。返回对象或数组时请使用。
JSON.stringify() - 使用TaskCreate/TaskUpdate:在所有阶段全程跟踪进度——在开始任何工作前,提前创建包含所有阶段的待办事项列表。
前提条件:
- 已创建现有的Power Pages代码站点
- 站点必须至少部署过一次(必须存在
文件夹)——Server Logic文件存储在.powerpages-site目录下,因此在创建任何Server Logic前必须完成部署.powerpages-site/server-logic/
初始请求: $ARGUMENTS
Workflow
工作流程
- Verify Site Exists — Locate the Power Pages project, explore existing patterns, and verify prerequisites
- Understand Requirements — Determine the user intent and whether the solution needs one or more server logic files
- Fetch Latest Documentation — Query Microsoft Learn for the most current Server Logic SDK reference
- Review Implementation Plan — Present the plan to the user and confirm before writing code
- Implement Server Logic — Create the approved and
.jsfiles in.serverlogic.yml.powerpages-site/server-logic/<name>/ - Configure Table Permissions — (Conditional: only if Server.Connector.Dataverse is used) Set up table permissions for Dataverse tables accessed by the server logic
- 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
- Configure Site Settings — Set up ServerLogic site settings if needed
- Client-Side Integration — Help wire the server logic into the site's frontend code
- Verify & Test Guidance — Validate the code and provide testing instructions
- Review & Deploy — Present summary and offer deployment
- 验证站点存在 — 定位Power Pages项目,探索现有模式,并验证前提条件
- 理解需求 — 确定用户意图,判断解决方案是否需要一个或多个Server Logic文件
- 获取最新文档 — 查询Microsoft Learn获取最新的Server Logic SDK参考资料
- 审核实施计划 — 向用户展示计划并在编写代码前确认
- 实现Server Logic — 在目录下创建经批准的
.powerpages-site/server-logic/<name>/和.js文件.serverlogic.yml - 配置表权限 — (条件性:仅当使用Server.Connector.Dataverse时)为Server Logic访问的Dataverse表设置表权限
- 管理密钥与环境变量 — (条件性:仅当Server Logic需要密钥时)使用Azure Key Vault(推荐)或Dataverse中的直接环境变量安全存储敏感值
- 配置站点设置 — 根据需要设置ServerLogic站点设置
- 客户端集成 — 帮助将Server Logic接入站点的前端代码
- 验证与测试指南 — 验证代码并提供测试说明
- 审核与部署 — 展示总结并提供部署选项
Phase 1: Verify Site Exists
阶段1:验证站点存在
Goal: Locate the Power Pages project root and confirm prerequisites
Actions:
- Create todo list with all 11 phases (see Progress Tracking table)
1.1 Locate Project
1.1 定位项目
Look for in the current directory or immediate subdirectories
powerpages.config.jsonIf not found: Tell the user to create a site first with .
/create-site在当前目录或直接子目录中查找文件
powerpages.config.json如果未找到:告知用户先使用创建站点。
/create-site1.2 Read Existing Config
1.2 读取现有配置
Read to get the site name and configuration:
powerpages.config.json读取以获取站点名称和配置信息:
powerpages.config.json1.3 Detect Framework
1.3 检测框架
Read to determine the frontend framework (React, Vue, Angular, or Astro). This is needed for Phase 8 (client-side integration guidance). See for the full framework detection mapping.
package.json${CLAUDE_PLUGIN_ROOT}/references/framework-conventions.md读取以确定前端框架(React、Vue、Angular或Astro)。这是阶段8(客户端集成指南)所需的信息。请查看获取完整的框架检测映射。
package.json${CLAUDE_PLUGIN_ROOT}/references/framework-conventions.md1.4 Explore Existing Server Logic and Frontend Code
1.4 探索现有Server Logic和前端代码
Use the Explore agent (via tool with ) to analyze the site for existing server logic patterns and frontend code that may call or need to call server logic endpoints.
Taskagent_type: "explore"Prompt for the Explore agent:
"Analyze this Power Pages code site for server logic context. Check:
- Does
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..powerpages-site/server-logic/- Search the frontend source code (
) for any existing calls tosrc/**/*.{ts,tsx,js,jsx,vue,astro}— these indicate server logic endpoints already being consumed./_api/serverlogics/- Look for CSRF token handling patterns (
,__RequestVerificationToken) — these show how the site currently makes authenticated API calls._layout/tokenhtml- Check for any TODO/FIXME comments mentioning server logic, backend, or server-side processing.
- Look for hardcoded API URLs, mock data, or placeholder fetch calls that might need to be replaced with server logic calls.
- Check for any existing service layer or API utility files in
,src/shared/, or similar directories that could be reused for server logic integration.src/services/- Read
files to list available web roles and their GUIDs — these are needed when creating the server logic metadata YAML..powerpages-site/web-roles/*.webrole.yml- 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代理(通过工具,设置)分析站点,查找现有Server Logic模式以及可能调用或需要调用Server Logic端点的前端代码。
Taskagent_type: "explore"给Explore代理的提示:
"分析此Power Pages代码站点的Server Logic上下文。检查:
- 是否存在
?如果存在,列出所有子目录及其.js文件。总结每个Server Logic的功能(实现了哪些函数、使用了哪些SDK功能)。同时读取对应的.serverlogic.yml文件以检查Web角色分配情况。.powerpages-site/server-logic/- 在前端源代码(
)中搜索对src/**/*.{ts,tsx,js,jsx,vue,astro}的现有调用——这些调用表明Server Logic端点已在被使用。/_api/serverlogics/- 查找CSRF令牌处理模式(
、__RequestVerificationToken)——这些模式展示了站点当前如何进行已认证的API调用。_layout/tokenhtml- 查找提及Server Logic、后端或服务器端处理的任何TODO/FIXME注释。
- 查找可能需要替换为Server Logic调用的硬编码API URL、模拟数据或占位符fetch调用。
- 查找
、src/shared/或类似目录中可能可重用于Server Logic集成的现有服务层或API工具文件。src/services/- 读取
文件以列出可用的Web角色及其GUID——这些信息在创建Server Logic元数据YAML时需要。.powerpages-site/web-roles/*.webrole.yml- 对于每个现有Server Logic,评估是否可以重用或安全扩展以实现所需功能,而非创建全新的Server Logic文件。指出强重用候选对象并说明原因。 报告所有发现,以避免重复工作并匹配现有模式。"
从Explore代理的发现中记录:
- 现有Server Logic文件 — 已实现的内容,以及哪些是可重用或扩展的候选对象
- 前端调用模式 — 站点如何进行API调用(在阶段9中匹配此模式)
- 现有服务/工具文件 — 在添加客户端集成时重用这些文件
- 缺口 — 引用不存在的Server Logic端点的前端代码
1.5 Check Deployment Status (Mandatory)
1.5 检查部署状态(必填)
Look for the folder:
.powerpages-siteIf not found: The site must be deployed before server logic can be created — server logic files live inside . Tell the user:
.powerpages-site/server-logic/"Thefolder 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?".powerpages-site
Use :
AskUserQuestion| Question | Options |
|---|---|
The | Yes, deploy now (Required), Cancel |
If "Yes, deploy now": Invoke first, then continue to Phase 2.
/deploy-siteIf "Cancel": Stop the workflow — server logic cannot be created without .
.powerpages-siteOutput: Confirmed project root, exists, existing server logic (if any), available web roles
.powerpages-site查找文件夹:
.powerpages-site如果未找到:创建Server Logic前必须先部署站点——Server Logic文件存储在此文件夹内。告知用户:
"未找到文件夹。Server Logic文件存储在此文件夹中,因此站点必须至少部署一次才能创建Server Logic。是否现在部署?".powerpages-site
使用:
AskUserQuestion| 问题 | 选项 |
|---|---|
创建Server Logic需要 | 是,立即部署(必填),取消 |
如果选择“是,立即部署”:先调用,然后继续阶段2。
/deploy-site如果选择“取消”:停止工作流程——没有无法创建Server Logic。
.powerpages-site输出:已确认项目根目录、存在、现有Server Logic(如有)、可用Web角色
.powerpages-sitePhase 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:
| Condition | Example |
|---|---|
| It enforces a state machine or lifecycle | Order 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 atomically | Award a bid + reject all others + update event status |
| The write involves a computed or derived value | Server calculates a score and writes it |
| The client should not have direct write access to the field | Status 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 , expecting the client to make a separate Web API call to perform the write. This allows the client to skip validation and write directly.
{ valid: true/false }对于每个计划的Server Logic项,确定是否应采用验证并执行模式——即Server Logic既验证业务规则又执行相应的Dataverse写入操作,而非仅返回验证结果供客户端操作。
当满足以下任一条件时,Server Logic项应采用验证并执行模式:
| 条件 | 示例 |
|---|---|
| 强制执行状态机或生命周期 | 订单状态:草稿 → 已提交 → 已批准 |
| 写入操作取决于必须防篡改的业务规则 | "仅允许在截止日期前提交投标" |
| 操作跨多个表原子执行 | 授予投标 + 拒绝所有其他投标 + 更新活动状态 |
| 写入操作涉及计算或派生值 | 服务器计算分数并写入 |
| 客户端不应具有对字段的直接写入权限 | 具有严格转换规则的状态字段 |
对于每个验证并执行项,记录:
- Server Logic将执行的Dataverse写入操作(UpdateRecord、CreateRecord等)
- 正在写入的字段 — 这些字段不应允许客户端通过Web API写入
- Server Logic返回给客户端的内容 — 通常是包含前后状态的成功/失败结果,而非供客户端操作的验证标志
需避免的反模式:仅进行验证并返回的Server Logic项,期望客户端进行单独的Web API调用以执行写入操作。这会允许客户端跳过验证直接写入。
{ valid: true/false }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:
- — Modern Custom APIs with full request parameters and response properties
customApis - — Legacy Custom Process Actions (activated only)
customProcessActions - — Total count of both types combined
total
Each entry includes: , , , ( or ), (, , or ), , and ( or ). Custom APIs also include and arrays.
namedisplayNamedescriptiontypeactionfunctionbindingunboundentityentityCollectionboundEntitysourcecustomApicustomProcessActionrequestParametersresponsePropertiesStep 2 — Present and ask the user:
If custom actions are found (), present a summary to the user grouped by binding type (unbound vs. entity-bound) and ask whether any should be used:
total > 0Use :
AskUserQuestion| Question | Options |
|---|---|
Your Dataverse environment has | 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 for each server logic item:
AskUserQuestion| Question | Context |
|---|---|
For the | 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 call)
InvokeCustomApi - Whether it's a function () or action (
GET)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对象:
- — 具有完整请求参数和响应属性的现代自定义API
customApis - — 仅已激活的旧版自定义流程操作
customProcessActions - — 两种类型的总数
total
每个条目包含:、、、(或)、(、或)、和(或)。自定义API还包含和数组。
namedisplayNamedescriptiontypeactionfunctionbindingunboundentityentityCollectionboundEntitysourcecustomApicustomProcessActionrequestParametersresponseProperties步骤2 — 展示并询问用户:
如果找到自定义操作(),按绑定类型(非绑定与实体绑定)分组向用户展示摘要,并询问是否应使用其中任何操作:
total > 0使用:
AskUserQuestion| 问题 | 选项 |
|---|---|
您的Dataverse环境有 | 是,让我选择要使用的操作;否,从头构建所有内容 |
清晰展示列表——每个操作显示名称、描述、类型(操作/函数)、绑定类型,以及绑定实体(如适用)。按非绑定和实体绑定分组以提高可读性。
如果用户选择否,跳至阶段2.2。
步骤3 — 将自定义操作映射到Server Logic项:
如果用户选择是,对于每个正在创建的Server Logic项,询问应包装哪个自定义操作(如有):
对每个Server Logic项使用:
AskUserQuestion| 问题 | 上下文 |
|---|---|
对于 | 展示自定义操作列表及其名称、描述和绑定类型。包含**“无——从头构建”**作为选项。 |
记录每个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:
| Feature | When to use |
|---|---|
| Calling external REST APIs (NOT Dataverse) |
| Reading/writing Dataverse records (CRUD + |
| Accessing request parameters, headers, body |
| User-scoped operations, role checks |
| Always — every function should log entry/exit and errors |
| Reading site setting configuration values |
| Reading Dataverse environment variable values directly via |
| Accessing site metadata |
根据每个计划的Server Logic项的用途,确定所需的Server SDK功能:
| 功能 | 使用场景 |
|---|---|
| 调用外部REST API(非Dataverse) |
| 读取/写入Dataverse记录(CRUD + 使用 |
| 访问请求参数、标头、主体 |
| 用户范围操作、角色检查 |
| 始终使用——每个函数都应记录进入/退出和错误 |
| 读取站点设置配置值 |
| 通过 |
| 访问站点元数据 |
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:
| Scenario | Secret needed |
|---|---|
| Calling an authenticated external API | API key, client secret, bearer token |
| Connecting to a third-party service | Connection string, access token |
| OAuth2 client credentials flow | Client ID + client secret |
| Webhook verification | Signing 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 (e.g.,
Server.Sitesetting.Get())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项需要不应硬编码的机密或敏感配置值。常见示例:
| 场景 | 需要的密钥 |
|---|---|
| 调用已认证的外部API | API密钥、客户端密钥、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| Question | Options |
|---|---|
| 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 to clarify:
AskUserQuestion| Question | Context |
|---|---|
| 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 with
SECRETS_DATAand 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, setuseKeyVault: truetoSECRETS_DATA.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和密钥列表——HTML计划将显示一个Key Vault横幅,解释安全优势并显示每个Server Logic依赖的密钥。如果不需要密钥,请将useKeyVault: true设置为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.htmlCreate the 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.
docs/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 () already exists. If it does, choose a new descriptive filename based on context — e.g., , . Pass the chosen name via .
<PROJECT_ROOT>/docs/serverlogic-plan.htmlserverlogic-plan-exchange-rate.htmlserverlogic-plan-apr-2026.html--output从模板生成HTML计划文件,并在请求批准前在用户的默认浏览器中打开。
在Power Pages项目中工作时,将计划写入:
text
<PROJECT_ROOT>/docs/serverlogic-plan.html如果文件夹不存在,请创建它。将此HTML文件保存在存储库中,以便与其余Server Logic工作一起审核和提交。
docs/请勿手动编写HTML。使用渲染脚本:
powershell
node "${CLAUDE_PLUGIN_ROOT}/scripts/render-serverlogic-plan.js" --output "<OUTPUT_PATH>" --data "<DATA_JSON_PATH>"渲染脚本会拒绝覆盖现有文件。调用前,请检查默认输出路径()是否已存在。如果存在,请根据上下文选择新的描述性文件名——例如、。通过传递所选名称。
<PROJECT_ROOT>/docs/serverlogic-plan.htmlserverlogic-plan-exchange-rate.htmlserverlogic-plan-apr-2026.html--output4.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| Question | Options |
|---|---|
| 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 file and metadata YAML following the constraints verified in Phase 3
.jsActions:
目标:根据阶段3验证的约束,创建每个经批准的Server Logic 文件和元数据YAML
.js操作:
5.1 Create Server Logic Folder
5.1 创建Server Logic文件夹
For each approved server logic item:
- If the approved plan says : Do not create a new folder. Reuse the existing server logic as-is and only update the surrounding integration work if needed.
reuse - If the approved plan says / extend: Reuse the existing folder and update the existing
update/.jsfiles rather than creating duplicates..serverlogic.yml - If the approved plan says : Create the folder inside
create(note: singular.powerpages-site/server-logic/, no trailing 's'). Ensure the folder name matches that endpoint name exactly.server-logic
对于每个经批准的Server Logic项:
- 如果经批准的计划要求:不要创建新文件夹。按原样重用现有Server Logic,仅在需要时更新周围的集成工作。
reuse - 如果经批准的计划要求/extend:重用现有文件夹并更新现有的
update/.js文件,而非创建重复文件。.serverlogic.yml - 如果经批准的计划要求:在
create目录下创建文件夹(注意:单数.powerpages-site/server-logic/,无尾随's')。确保文件夹名称与端点名称完全匹配。server-logic
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 UsersIn 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 and values needed for each server logic's metadata YAML.
idname使用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所需的和值。
idname5.3 Create the Server Logic File
5.3 创建Server Logic文件
Repeat this step for each approved server logic item. Create or update according to the approved plan status (, , or ) and follow these mandatory patterns:
<PROJECT_ROOT>/.powerpages-site/server-logic/<name>/<name>.jscreateupdatereuse对每个经批准的Server Logic项重复此步骤。根据经批准的计划状态(、或)创建或更新,并遵循以下强制模式:
createupdatereuse<PROJECT_ROOT>/.powerpages-site/server-logic/<name>/<name>.jsStructure Rules
结构规则
- Only top-level functions: The file can only contain these 5 functions at the top level: ,
get,post,put,patch. Only include the functions the user needs.del - Each function returns a string: Use for objects/arrays.
JSON.stringify() - Each function has try/catch: Every function must wrap its logic in a try/catch block.
- Each function logs: Use at entry and
Server.Logger.Log()in catch blocks.Server.Logger.Error() - No imports or requires: No ,
import, or external dependencies.require - No browser APIs: No ,
fetch,XMLHttpRequest,setTimeout,setInterval, or DOM APIs.console.log - Async when needed: Mark functions as only when they use
async(HttpClient calls). Dataverse connector methods (await) are synchronous — do NOT useServer.Connector.Dataverse.*/asyncwith them.await
- 仅顶级函数:文件只能包含以下5个顶级函数:、
get、post、put、patch。仅包含用户需要的函数。del - 每个函数返回字符串:对对象/数组使用。
JSON.stringify() - 每个函数包含try/catch:每个函数必须将其逻辑包装在try/catch块中。
- 每个函数记录日志:在入口处使用,在catch块中使用
Server.Logger.Log()。Server.Logger.Error() - 无导入或依赖:无、
import或外部依赖项。require - 无浏览器API:无、
fetch、XMLHttpRequest、setTimeout、setInterval或DOM API。console.log - 必要时使用Async:仅当函数使用(HttpClient调用)时才标记为
await。Dataverse连接器方法(async)是同步的——请勿对其使用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:
- The server logic reads the current state from Dataverse (not trusting the client's view)
- It validates the business rule server-side
- It writes the result to Dataverse via
Server.Connector.Dataverse.UpdateRecord - It returns a success/failure result — NOT a flag for the client to act on
{ valid: true/false } - 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
});
}
}与基础模板的关键区别:
- Server Logic从Dataverse读取当前状态(不依赖客户端的视图)
- 它在服务器端验证业务规则
- 它通过将结果写入Dataverse
Server.Connector.Dataverse.UpdateRecord - 它返回成功/失败结果——而非供客户端操作的标志
{ valid: true/false } - 客户端调用此一个端点——不进行单独的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 . The server logic acts as a portal-friendly wrapper, exposing the custom action through a endpoint with proper web role authorization.
Server.Connector.Dataverse.InvokeCustomApi/_api/serverlogics/<name>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 as the HTTP method and pass parameters inline in the URL using OData function call syntax
"GET" - Actions (POST): Use as the HTTP method and pass parameters as JSON body payload
"POST" - is synchronous — do NOT use
InvokeCustomApi/asyncawait - 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 Logic作为门户友好的包装器,通过端点暴露自定义操作,并具有适当的Web角色授权。
Server.Connector.Dataverse.InvokeCustomApi/_api/serverlogics/<name>非绑定操作:
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):使用作为HTTP方法,并使用OData函数调用语法在URL中内联传递参数
"GET" - 操作(POST):使用作为HTTP方法,并将参数作为JSON主体负载传递
"POST" - 是同步的——请勿使用
InvokeCustomApi/asyncawait - 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 , 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 / items — the YAML already exists and should be updated manually if needed.
createupdatereusepowershell
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 file has this structure:
<PROJECT_ROOT>/.powerpages-site/server-logic/<name>/<name>.serverlogic.ymlyaml
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:
- field is mandatory — The script generates a new UUID (v4). PAC CLI crashes with
idif this is missing.Expected Guid for primary key 'id' - — Array of web role GUIDs from step 5.2. Include only the roles required for that server logic item.
adx_serverlogic_adx_webrole - — Must match the folder name and
namefile name (the URL-friendly name used in.js)./_api/serverlogics/<name> - — Human-readable name (e.g., "Exchange Rate API", "Order Processor").
display_name - Alphabetical field ordering — Fields must be sorted alphabetically: ,
adx_serverlogic_adx_webrole,description,display_name,id.name
对于每个计划状态为的经批准Server Logic项,使用确定性写入脚本生成元数据文件,而非手动编写YAML。脚本生成UUID,按正确顺序写入字段,并以JSON格式返回创建的文件路径。跳过/项的此步骤——YAML已存在,如有需要应手动更新。
createupdatereusepowershell
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.ymlyaml
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>关键要求:
- 字段是必填项——脚本生成新的UUID(v4)。如果缺少此字段,PAC CLI会崩溃并显示
id。Expected Guid for primary key 'id' - ——来自步骤5.2的Web角色GUID数组。仅包含该Server Logic项所需的角色。
adx_serverlogic_adx_webrole - ——必须与文件夹名称和
name文件名匹配(.js中使用的URL友好名称)。/_api/serverlogics/<name> - ——人类可读名称(例如“Exchange Rate API”、“Order Processor”)。
display_name - 字母顺序字段排序——字段必须按字母顺序排序:、
adx_serverlogic_adx_webrole、description、display_name、id。name
5.5 Validate the Code
5.5 验证代码
Before saving, verify the code against these constraints:
| Constraint | Check |
|---|---|
| Only allowed top-level functions | No functions other than get, post, put, patch, del |
| Every function returns a string | All code paths return a string (including catch blocks) |
| try/catch in every function | Every function body is wrapped in try/catch |
| Server.Logger in every function | Log at entry, Error in catch |
| No external dependencies | No |
| No browser APIs | No |
| Async only when needed | Only functions using |
| ECMAScript 2023 compliant | Standard JS features only (optional chaining, nullish coalescing, etc. are fine) |
保存前,根据以下约束验证代码:
| 约束 | 检查内容 |
|---|---|
| 仅允许顶级函数 | 无get、post、put、patch、del之外的函数 |
| 每个函数返回字符串 | 所有代码路径返回字符串(包括catch块) |
| 每个函数包含try/catch | 每个函数体都包装在try/catch中 |
| 每个函数使用Server.Logger | 入口处记录日志,catch块中记录错误 |
| 无外部依赖 | 无 |
| 无浏览器API | 无 |
| 仅必要时使用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 and files created, validated, and committed
.js.serverlogic.yml创建经批准的Server Logic文件后,对Server Logic更改进行git提交。
如果HTML计划是在项目内生成的,请将其包含在同一提交中(使用渲染脚本JSON响应中的实际输出路径)。
输出:Server Logic 和文件已创建、验证并提交
.js.serverlogic.ymlPhase 6: Configure Table Permissions (Conditional)
阶段6:配置表权限(条件性)
Goal: Set up table permissions for Dataverse tables accessed by in the server logic code
Server.Connector.DataverseThis phase only runs when the server logic uses . If the server logic only uses (external APIs) or doesn't access Dataverse at all, skip this phase entirely and proceed to Phase 7.
Server.Connector.DataverseServer.Connector.HttpClientServer.Connector.DataverseActions:
目标:为Server Logic代码中访问的Dataverse表设置表权限
Server.Connector.Dataverse仅当Server Logic使用时运行此阶段。如果Server Logic仅使用(外部API)或根本不访问Dataverse,请完全跳过此阶段并继续阶段7。
Server.Connector.DataverseServer.Connector.HttpClientServer.Connector.Dataverse操作:
6.1 Detect Dataverse Tables and Required Privileges
6.1 检测Dataverse表和所需权限
Parse the server logic file created in Phase 5 to identify which Dataverse tables are accessed and what CRUD operations are performed:
.js| Dataverse SDK Method | Required Table Permission |
|---|---|
| Read |
| Read |
| Create |
| Write |
| Delete |
Extract the entity set name (first argument) from each method call. Build a mapping:
| Table (entity set name) | Read | Create | Write | Delete |
|---|---|---|---|---|
| Yes | — | — | — |
| Yes | Yes | — | — |
解析阶段5中创建的Server Logic 文件,识别访问的Dataverse表和执行的CRUD操作:
.js| Dataverse SDK方法 | 所需表权限 |
|---|---|
| 读取 |
| 读取 |
| 创建 |
| 写入 |
| 删除 |
从每个方法调用中提取实体集名称(第一个参数)。构建映射:
| 表(实体集名称) | 读取 | 创建 | 写入 | 删除 |
|---|---|---|---|---|
| 是 | — | — | — |
| 是 | 是 | — | — |
6.2 Use the Table Permissions Architect
6.2 使用表权限架构师
When any approved server logic item uses , invoke the agent at to determine and create the required table permissions.
Server.Connector.Dataversetable-permissions-architect${CLAUDE_PLUGIN_ROOT}/agents/table-permissions-architect.mdPrompt:
"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
, which respects table permissions — without them, the connector silently returns 0 records.Server.Connector.Dataverse- 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:
- Discover existing table permissions and web roles
- Create any missing web roles via if needed
create-web-role.js - Propose a table permissions plan (with HTML visualization)
- Present the plan via plan mode for user approval
- After approval, create table permission YAML files in using
.powerpages-site/table-permissions/create-table-permission.js
当任何经批准的Server Logic项使用时,调用位于的代理,以确定并创建所需的表权限。
Server.Connector.Dataverse${CLAUDE_PLUGIN_ROOT}/agents/table-permissions-architect.mdtable-permissions-architect提示:
"分析此Power Pages代码站点,并为经批准的Server Logic计划访问的Dataverse表提出表权限建议。以下表需要权限:[列出步骤6.1中每个表的所需CRUD权限,按Server Logic项分组]上下文:
- 需要这些权限是因为Server Logic使用
,它会遵守表权限——没有权限的话,连接器会静默返回0条记录。Server.Connector.Dataverse- 范围通常应为全局,适用于获取所有记录的Server Logic,除非Server Logic按当前用户过滤(在这种情况下使用联系人范围)。
- 分配给这些Server Logic项的Web角色是:[列出阶段5.2中的Web角色名称和GUID]
- 项目根目录:[路径]
检查现有表权限和Web角色。如果需要新的Web角色,请使用create-web-role.js脚本创建。提出计划,然后在批准后使用确定性脚本创建表权限YAML文件。"
代理将:
- 发现现有表权限和Web角色
- 如果需要,通过创建任何缺失的Web角色
create-web-role.js - 提出表权限计划(带HTML可视化)
- 通过计划模式向用户展示计划以获得批准
- 批准后,使用在
create-table-permission.js目录下创建表权限YAML文件.powerpages-site/table-permissions/
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 (, , ) from the user's Azure subscription.
nameresourceGrouplocationStep 2 — Select or create a Key Vault:
If Key Vaults were found, present the list and ask which one to use:
Use :
AskUserQuestion| Question | Context |
|---|---|
| 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| Question | Options |
|---|---|
| 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| Question | Context |
|---|---|
| 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 , , and . Use the created vault for the remaining steps.
nameresourceGrouplocationIf "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 and to share the output (which contains only the URI, not the secret) so the workflow can continue.
secretUriOption 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 continueTell the user the Secret Identifier URI looks like and that this URI (not the secret value) is what should be shared back.
https://<vault-name>.vault.azure.net/secrets/<secret-name>/<version>Step 4 — Create environment variable in Dataverse:
After the user shares the output from each command, create an environment variable definition in Dataverse that references the Key Vault secret. Use the type:
secretUrisecretpowershell
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 and , which tells Power Pages to resolve the value from the Dataverse environment variable (backed by Key Vault).
envvar_schemasource: 1如果用户在阶段2.3.1中选择了Azure Key Vault:
步骤1 — 列出可用的Key Vault:
powershell
node "${CLAUDE_PLUGIN_ROOT}/scripts/list-azure-keyvaults.js"脚本输出用户Azure订阅中的Key Vault数组(、、)。
nameresourceGrouplocation步骤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>"脚本输出包含、和的JSON对象。使用创建的Vault完成剩余步骤。
nameresourceGrouplocation如果选择“直接存储为环境变量”:跳过阶段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>"告知用户每个命令输出包含的JSON对象,并要求用户分享输出(仅包含URI,不包含密钥)以便工作流程继续。
secretUri选项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类似于,并且应分享此URI(而非密钥值)。
https://<vault-name>.vault.azure.net/secrets/<secret-name>/<version>步骤4 — 在Dataverse中创建环境变量:
用户分享每个命令的输出后,在Dataverse中创建引用Key Vault密钥的环境变量定义。使用类型:
secretUrisecretpowershell
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>"这会创建包含和的站点设置,告知Power Pages从Dataverse环境变量(由Key Vault支持)解析值。
envvar_schemasource: 17.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:
- Power Apps maker portal (make.powerapps.com) — Go to Solutions → Default Solution → Environment 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 — 向用户提供设置实际密钥值的步骤:
请勿询问密钥值——它们绝不能通过对话传递。相反,告知用户使用以下方法之一更新每个占位符为实际值:
- 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 and
envvar_schemasource: 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_schemasource: 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 folder is guaranteed to exist at this point (verified in Phase 1.5).
.powerpages-siteThe following site settings control server logic behavior. Only create settings that differ from defaults or are specifically needed:
| Setting | Description | Default | When to configure |
|---|---|---|---|
| Enable/disable server logic feature | | Only if explicitly disabled and needs re-enabling |
| Restrict which external domains HttpClient can call | All domains | When the server logic calls external APIs and you want to restrict to specific domains for security |
| Maximum execution time | | 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. |
| Allow networking across domains | | Set to |
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"此时文件夹肯定存在(在阶段1.5中已验证)。
.powerpages-site以下站点设置控制Server Logic行为。仅创建与默认值不同或特别需要的设置:
| 设置 | 描述 | 默认值 | 配置场景 |
|---|---|---|---|
| 启用/禁用Server Logic功能 | | 仅当明确禁用并需要重新启用时 |
| 限制HttpClient可以调用的外部域 | 所有域 | 当Server Logic调用外部API并希望限制为特定域以提高安全性时 |
| 最大执行时间 | | 平台将此值上限为120秒——超过120的值会被静默限制。仅在需要降低超时时配置,不要提高。 |
| 允许跨域联网 | | 当通过AllowedDomains限制时设置为 |
使用现有的站点设置创建脚本:
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| Question | Options |
|---|---|
| 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 file and verify:
.js- 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, or external dependenciesrequire - 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 file and verify:
.serverlogic.yml- field exists and is a valid UUID
id - array is non-empty (at least one web role)
adx_serverlogic_adx_webrole - matches the folder name and
namefile name.js - and
display_nameare populateddescription - Fields are alphabetically sorted
- File names match: folder name, name,
.jsname, and.serverlogic.ymlfield all use the same valuename
重新读取每个创建的文件并验证:
.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- 字段存在且是有效的UUID
id - 数组非空(至少一个Web角色)
adx_serverlogic_adx_webrole - 与文件夹名称和
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:
- Deploy the site first — The server logic must be deployed via before it can be called
/deploy-site - 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 and include it as
/_layout/tokenhtmlheader. GET requests are exempt from antiforgery validation — no token is needed for read-only calls.__RequestVerificationToken - Authentication — Server logic respects the site's authentication. Calls from authenticated sessions use cookie-based auth automatically. Anonymous access depends on governance settings.
- Testing from browser console:
Use the frontend integration reference from Phase 9 for the exact calling pattern that matches the site's stack.
- Check diagnostics — Server.Logger output can be viewed in Power Pages design studio diagnostics
Output: Code validated, API URL provided, test guidance given
提供测试说明:
- 先部署站点 — Server Logic必须通过部署后才能调用
/deploy-site - 非GET请求需要CSRF令牌 — 对Server Logic端点的POST、PUT、PATCH和DELETE调用需要CSRF令牌。从获取令牌并作为
/_layout/tokenhtml标头包含。GET请求豁免反伪造验证——只读调用不需要令牌。__RequestVerificationToken - 身份验证 — Server Logic遵守站点的身份验证。来自已认证会话的调用自动使用基于Cookie的身份验证。匿名访问取决于治理设置。
- 从浏览器控制台测试:
使用阶段9中的前端集成参考获取与站点堆栈匹配的确切调用模式。
- 检查诊断 — 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:
| Step | Status | Details |
|---|---|---|
| Server Logic JS | Created | List each created |
| Server Logic YAML | Created | List each created |
| HTML Plan | Created/Updated | Actual path from render script output |
| Functions | Implemented | Summarize methods implemented per server logic item |
| SDK Features Used | — | Summarize features used per server logic item |
| Table Permissions | Created/Skipped | |
| Secrets & Env Vars | Created/Skipped | Environment variables (Key Vault-backed or direct), site settings with |
| Site Settings | Created/Skipped | ServerLogic/AllowedDomains, etc. |
| Client-Side Service | Created/Skipped | List created or updated frontend service files |
| UI Integration | Created/Skipped | Pages, components, forms, or actions fully wired to the server logic endpoints |
| API URL | — | List each |
展示已完成的所有工作的摘要:
| 步骤 | 状态 | 详细信息 |
|---|---|---|
| Server Logic JS | 已创建 | 列出每个已创建的 |
| Server Logic YAML | 已创建 | 列出每个已创建的 |
| HTML计划 | 已创建/更新 | 渲染脚本输出的实际路径 |
| 函数 | 已实现 | 总结每个Server Logic项实现的方法 |
| 使用的SDK功能 | — | 总结每个Server Logic项使用的功能 |
| 表权限 | 已创建/已跳过 | |
| 密钥与环境变量 | 已创建/已跳过 | 环境变量(Key Vault支持或直接存储)、带 |
| 站点设置 | 已创建/已跳过 | ServerLogic/AllowedDomains等 |
| 客户端服务 | 已创建/已跳过 | 列出已创建或更新的前端服务文件 |
| UI集成 | 已创建/已跳过 | 已完全接入Server Logic端点的页面、组件、表单或操作 |
| API URL | — | 列出每个 |
11.3 Ask to Deploy
11.3 询问是否部署
Use :
AskUserQuestion| Question | Options |
|---|---|
| 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 skill to deploy the site.
/deploy-siteAfter deployment succeeds, use :
AskUserQuestion| Question | Options |
|---|---|
The site has been deployed. Would you like me to run | Yes, run |
If "Yes, run ": Invoke the skill.
/test-site/test-siteIf "No, I'll deploy later": Acknowledge and remind:
"No problem! Remember to deploy your site usingwhen you're ready. The server logic endpoints won't be accessible until the site is deployed."/deploy-site
使用:
AskUserQuestion| 问题 | 选项 |
|---|---|
| Server Logic工作已准备就绪。要使其生效,需要部署站点。是否现在部署? | 是,立即部署(推荐);否,我稍后部署 |
如果选择“是,立即部署”:调用技能部署站点。
/deploy-site部署成功后,使用:
AskUserQuestion| 问题 | 选项 |
|---|---|
站点已部署。是否要运行 | 是,运行 |
如果选择“是,运行”:调用技能。
/test-site/test-site如果选择“否,我稍后部署”:确认并提醒:
"没问题!准备好后请使用部署站点。Server Logic端点在站点部署前无法访问。"/deploy-site
11.4 Post-Deploy Notes
11.4 部署后注意事项
After deployment (or if skipped), remind the user:
- Test the endpoints: Call each URL with the appropriate HTTP method (include CSRF token for non-GET requests)
/_api/serverlogics/<name> - Recommended full-site validation: After deployment, ask whether to run so the live site can be validated end to end
/test-site - 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, silently returns 0 records
Server.Connector.Dataverse - 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:
- Power Platform admin center — Environments → select environment → Environment variables → find by display name → update value
- Power Apps maker portal — Solutions → open solution → Environment variables → edit value
Output: Summary presented, deployment completed or deferred, post-deploy guidance provided
部署后(或如果跳过部署),提醒用户:
- 测试端点:使用适当的HTTP方法调用每个URL(非GET请求包含CSRF令牌)
/_api/serverlogics/<name> - 推荐全站点验证:部署后,询问是否运行以端到端验证实时站点
/test-site - 检查日志:使用Power Pages设计工作室诊断中的Server.Logger输出调试问题
- 表权限:已为此Server Logic使用的Dataverse表配置表权限。如果以后添加新的Dataverse表,请再次运行表权限设置——没有权限的话,会静默返回0条记录
Server.Connector.Dataverse - 超时:默认执行超时为120秒——这也是平台最大值(超过120的值会被静默限制)
- 匿名访问:如果站点的治理控制禁用匿名访问,匿名用户无法调用与外部系统集成的Server Logic
- 预览功能:Server Logic目前处于预览阶段——请关注Microsoft Learn的更新
- 带占位符值的环境变量:如果阶段7创建了带占位符值的环境变量,提醒用户在测试前更新为实际密钥值。他们可以通过以下方式操作:
- Power Platform管理中心 — 环境 → 选择环境 → 环境变量 → 按显示名称查找 → 更新值
- 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)
关键决策点(等待用户)
- At Phase 1.5: Deploy now or cancel (if missing — mandatory)
.powerpages-site - At Phase 2.1.2: Use existing Dataverse custom actions or build from scratch (if custom actions found)
- At Phase 2: Confirm requirements (purpose, name, HTTP methods, secrets)
- At Phase 4: Approve implementation plan before writing code
- At Phase 6.2: Review and approve the plan (if Dataverse connector is used)
table-permissions-architect - At Phase 2.3.1: Choose Azure Key Vault or direct environment variable (if secrets needed)
- At Phase 7.2a Step 2: Create a new Key Vault or fall back to direct environment variable (if no vaults found)
- At Phase 9.1: Create frontend integration or skip
- At Phase 11.3: Deploy now or deploy later
- 在阶段1.5:立即部署或取消(如果缺少——必填)
.powerpages-site - 在阶段2.1.2:使用现有Dataverse自定义操作或从头构建(如果找到自定义操作)
- 在阶段2:确认需求(用途、名称、HTTP方法、密钥)
- 在阶段4:编写代码前批准实施计划
- 在阶段6.2:审核并批准计划(如果使用Dataverse连接器)
table-permissions-architect - 在阶段2.3.1:选择Azure Key Vault或直接环境变量(如果需要密钥)
- 在阶段7.2a步骤2:创建新的Key Vault或回退到直接环境变量(如果未找到Vault)
- 在阶段9.1:创建前端集成或跳过
- 在阶段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 subject | activeForm | Description |
|---|---|---|
| Verify site exists | Verifying site prerequisites | Locate project root, detect framework, explore existing server logics and frontend patterns, verify .powerpages-site exists (mandatory) |
| Understand requirements | Gathering requirements | Determine 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 documentation | Fetching Microsoft Learn docs | Query Microsoft Learn for current Server Logic SDK reference and samples |
| Review implementation plan | Reviewing plan with user | Present plan (server logic inventory, functions, SDK features, external APIs, secrets) and confirm before writing code |
| Implement server logic | Writing server logic code | Determine/create required web roles, create approved |
| Configure table permissions | Setting up Dataverse table permissions | (Conditional) Parse |
| Manage secrets and environment variables | Configuring 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 settings | Configuring site settings | Set up ServerLogic/* site settings if needed |
| Client-side integration | Wiring frontend to server logic | Follow the frontend integration reference, create/update service files as needed, and fully wire the UI to the server logic endpoints |
| Verify and test guidance | Validating and providing test guidance | Final validation, API URLs, CSRF token instructions, testing guide |
| Review and deploy | Reviewing summary and deploying | Present summary, ask about deployment, provide post-deploy guidance |
Mark each task when starting it and when done via . Use between phase transitions and before the final summary to confirm there are no incomplete work items left.
in_progresscompletedTaskUpdateTaskListBegin 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 Logic | Writing 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_progressTaskUpdatecompletedTaskList从阶段1:验证站点存在开始