关于 footprint-workflows
Footprint Workflows 是用于在 Footprint 中编写和修改 Datex Studio footprint-workflow 配置的技能。它指导开发者将低代码 TypeScript 逻辑绑定到平台定义的扩展点,并在功能分支上验证和发布。
主要功能
- 01将工作流绑定到平台定义的扩展点
- 02通过元数据发现扩展点参数
- 03编写低代码 TypeScript 工作流主体
- 04使用 `dxs` 验证并写入配置
适用场景
- 01在 Footprint 处理扩展点实现自定义逻辑
- 02编辑工作流时保留配置内容和 GUID
- 03推送配置前检查工作流结构
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ datex/ skills --skill footprint-workflows安装后在 Claude Code 中输入/footprint-workflows确认已加载。
附带文件references/footprint-workflows.md
详细介绍
Footprint 工作流
在分支上编写或修改 Datex Studio footprint 工作流(configurationTypeId: 23)——这是一种低代码 TypeScript 实现,Footprint 平台会在其处理流程中的指定扩展点调用它(例如,在实体状态提交之前、装箱时、规划分配时、推荐位置时,等等)。它是旧版 XAML「Datex Workflow」活动的现代替代方案。平台负责扩展点、GUID 以及输入/输出契约;你负责实现主体。
参考资料
- ../datex-studio-shared/branch-setup.md — 分支/连接选择(各技能通用)
- references/footprint-workflows.md — 权威参考:主体结构、扩展点绑定与 workflowsMetadata 发现、固定参数契约、各扩展点的字段说明、扩展点目录、代码模式、CLI 生命周期、预检清单
- ../datex-studio-shared/configuration-roundtrip.md —
get -O envelope → jq .json → upsert -D往返流程,以及该流程可避免的静默清空问题 - ../datex-studio-conventions/file-format.md —
configurationTypeId表、代码字符串编辑规则、带 outParams 的return;规则 - ../datex-studio-conventions/naming-conventions.md — 优先使用
_workflow后缀;后端类型不受显示名称规则约束 - ../datex-studio-conventions/universal-checklist.md — 每个组件都必须通过的通用检查
- ../datex-studio-runtime/calling-conventions.md — 执行层级规则;工作流在 action 层运行(通过
$flows调用操作、读取fpds、不使用$db、不调用函数) - ../datex-studio-shared/flow-code-patterns.md —
$utils.isDefined、日期默认值及其他 flow 代码惯用写法 - ../action-creator/references/actions.md — 操作是工作流主体调用的调度目标;运行在同一 Footprint 服务层级
- ../datasource-creator/references/datasources.md — 工作流读取的
fpds_*footprint 数据源(action 层)
依赖项
requirements-gathering技能 — 如果当前上下文中尚无需求简报,则调用该技能来生成需求简报(包括使用哪个扩展点、自定义行为是什么、要调度到什么目标,以及使用哪个包)。action-creator技能 — 调用该技能来编写工作流主体要调度到的包操作。工作流节点应保持为轻量调度器;实际逻辑放在操作中(同一 Footprint 服务层级)。function-creator技能 — 当将调度逻辑封装在操作后的函数中更合适时,调用该技能(工作流不能直接调用函数)。datasource-creator技能 — 当工作流通过fpds_*footprint 数据源读取配置/状态时,调用该技能。type-definition-creator技能 — 当调度目标需要包接口/枚举时,调用该技能(FootPrintWorkflow.*输入/结果类型由平台管理,应从contexts读取,而非自行编写)。impact-analysis技能 — 修改其他代码依赖的工作流之前,或重命名工作流调度到的操作/数据源之前,调用该技能;应追踪$flows.<Package>.<action>调用位置,而不是搜索内联代码。
CLI 生命周期
工作流编写通过 dxs configuration 完成——这是适用于所有平台配置类型的通用 CRUD 基元。没有 dxs workflow 子命令,也不支持字段级补丁;你需要构建(或获取并提取)完整的 JSON 正文,编辑后再将完整内容推送回去。CLI 类型标识符为 footprintworkflow(小写,与 ConfigurationEndpoints.normalize_type 的输出一致),映射到 configurationTypeId: 23。PublishedMain 配置的 readonly: true——请在功能分支上编写。
新建工作流——从元数据 API 中发现插槽,并分配一个新的 GUID(如果是要替换旧工作流,则复用其 GUID——参见步骤 2):
# 1. Discover the slot: id (= workflowDefinitionId), name, exact inParams/outParams
dxs api GET "/footPrintApiConnections/byName/<connectionName>/workflowsMetadata?applicationId=<branchId>" --raw -O meta.json
jq '.workflowsMetadataJson.workflowDefinitions[] | select(.name=="Cartonization")' meta.json
# 2. Generate a fresh workflowGUID for this new config (new capability; you point callers at it).
# Superseding a legacy workflow on this slot? Reuse ITS GUID instead so existing callers keep working.
python3 -c "import uuid; print(uuid.uuid4())"
# 3. Build body.json: apiSettingName + workflowDefinitionId/Name (step 1) + your fresh GUID,
# the slot's inParams/outParams verbatim, configurationTypeId:23, id:0, your referenceName/title/description/code
# 4. (Optional) read Input/result field shapes — contexts OR meta.json `types`
dxs configuration contexts footprintworkflow -b <branchId> -D body.json
# 5. Validate, THEN upsert — these are two steps, not one. Validate exits 1 when it finds
# errors (read validation_errors, fix body.json, re-run); do not run the upsert on exit 1.
dxs configuration validate footprintworkflow -b <branchId> -D body.json
dxs configuration upsert footprintworkflow -b <branchId> -D body.json
编辑现有工作流(往返流程——绝不能跳过 jq 提取):
dxs configuration get footprintworkflow <configId> -b <branchId> -O envelope.json
jq .json envelope.json > body.json # EXTRACT THE INNER BODY (round-trip footgun guard)
# ... edit nodes[0].stepConfig.executeCodeConfig.code ...
dxs configuration validate footprintworkflow -b <branchId> -D body.json # exit 1 = errors found; fix, do not push
dxs configuration upsert footprintworkflow -b <branchId> -D body.json
往返规则(至关重要)
绝不能将 envelope.json 直接传入 dxs configuration upsert——这会静默破坏配置内容(信封包含 id/jsonString/version/…,而 upsert -D 不接受这些字段)。务必先运行 jq .json envelope.json > body.json。信封还包含 application.applicationDefinition 中的 Azure 应用注册机密——jq .json 提取会将其丢弃;绝不要提交 envelope.json。参见 ../datex-studio-shared/configuration-roundtrip.md。
工作流
[Phase 1: Setup + Requirements]
Follow branch-setup.md for branch/connection selection (feature branch — main is readonly)
|
[requirements brief in context?]
YES -> use it NO -> invoke `requirements-gathering`
|
[Phase 2: Identify the platform slot]
Pick the extension point (Cartonization, Entity Status Change (Before Commit),
Allocation Strategy, Recommend* , Barcode Parser, ...). Consult
references/footprint-workflows.md -> Extension-Point Catalog.
If nothing in the platform *calls* the slot -> a workflow config is inert; stop.
|
[Phase 3: Bind to the slot]
Pull the workflowsMetadata API for the connection/branch -> copy the slot's
id (=workflowDefinitionId), name, and inParams/outParams VERBATIM. Never
invent the id/name. workflowGUID is NOT in the metadata — it is the code callers
pass: generate fresh for a NEW workflow, preserve it on edits, and reuse the
legacy GUID when shipping a drop-in replacement for an existing workflow.
|
[Phase 4: Author the body]
Build body.json:
- Slot binding (Phase 3): apiSettingName + workflowDefinitionId/Name +
your workflowGUID + configurationTypeId:23 + start:"step1"
- Fixed param contract: single Input: FootPrintWorkflow.<Slot>InputBaseWL;
out-params exactly as the slot dictates (or [] for before-commit mutation)
- Single ExecuteCodeActivity node; code is a THIN DISPATCHER to package
actions ($flows.<Pkg>.<action>) and fpds reads; map results into
$flow.outParams; action-tier rules (no $db, no functions)
- id:0, accessModifier:public, description <=100 chars, vars/events null
|
[Phase 5: Discover types + validate]
dxs configuration contexts footprintworkflow -b <branchId> -D body.json
-> confirm $types.FootPrintWorkflow.<X>InputBaseWL + result fields you use
dxs configuration validate footprintworkflow -b <branchId> -D body.json
|
[Phase 6: Push]
CREATE -> dxs configuration upsert footprintworkflow -b <branchId> -D body.json
MODIFY -> get -O envelope -> jq .json -> edit -> upsert (round-trip)
|
[Phase 7: Verify (optional)]
Exercise the slot in the running platform; confirm the workflow is invoked and
the result/mutation lands. Re-fetch (jq .json) and diff against body.json.
|
[invoke `post-edit-verification`; then `component-validator`]
阶段详情
阶段 1:设置 + 需求
- 遵循 ../datex-studio-shared/branch-setup.md。绝不要假定分支 ID——请与用户确认。在功能分支上编写;PublishedMain 工作流配置的
readonly: true。 - 检查上下文中是否有需求简报。简报应说明:使用哪个平台插槽、自定义行为、要分派到哪些软件包操作/数据源,以及目标软件包。若没有简报 → 调用
requirements-gathering。
阶段 2:确定平台插槽
只有 Footprint 平台调用相应插槽时,footprint-workflow 才会运行。请查阅 references/footprint-workflows.md → 用途与适用场景 和扩展点目录。如果所需行为不是由某个已命名的工作流插槽触发,那么此处使用的组件类型就不对——需要的是普通操作/函数/数据源。如果签名应由你来设计,那就应使用函数/操作,而不是工作流。
阶段 3:绑定到插槽
插槽绑定包含两个相互独立的部分:
- 插槽标识 + 签名(来自平台)。 获取 Footprint 连接和分支对应的 workflowsMetadata API:
将插槽的dxs api GET "/footPrintApiConnections/byName/<connectionName>/workflowsMetadata?applicationId=<branchId>" --raw -O meta.json jq '.workflowsMetadataJson.workflowDefinitions[] | {id, name, inParams, outParams}' meta.jsonid复制到workflowDefinitionId,将name复制到workflowDefinitionName,并逐字复制其inParams/outParams。<connectionName>是实际的 Footprint 连接(例如DSV),不是apiSettingName的值。根据分支的 Footprint 设置来设置apiSettingName。绝不要自行编造 id/name。 workflowGUID(调用方传入的代码)。 元数据中不包含它,因此目录中没有任何内容规定该值——但调用方会使用它:该值会以ProcessingStrategyWorkflowCode/AllocationStrategyWorkflowId的形式传到服务器,用于选择运行该插槽的哪个实现。对于真正的新工作流,生成一个新的 v4 UUID(python3 -c "import uuid; print(uuid.uuid4())"),然后让调用方指向它;编辑时保留现有 GUID,不作更改(jq .json往返会保留它);如果配置是现有实现的直接替代品,且调用方不得更改,则复用旧 GUID。编辑时绝不要重新生成。
第 4 阶段:编写主体
根据 references/footprint-workflows.md → Minimal Valid Skeleton 构建 body.json。要点:
- 文件基础信息遵循下方的预检清单和通用清单:
configurationTypeId: 23、id: 0、description不超过 100 个字符、设置accessModifier,包与功能相匹配。 - 参数契约由平台规定,而非由你决定。 单个
Input入参,类型为FootPrintWorkflow.<Slot>InputBaseWL;出参严格按槽位要求设置(单个对象、集合,或用于提交前修改的[])。不要重命名Input、添加参数或更改出参形状。 - 单个
ExecuteCodeActivity节点。start: "step1"、节点id: "step1"、decisionConfig: null。虽然可以使用多节点图,但此库中没有使用——除非有明确理由,否则只用一个步骤。 - 代码是精简的分发器。 将
$flow.inParams.Input转换为$flows.<Package>.<action>调用和fpds读取;将结果映射到$flow.outParams.<Name>。操作层级规则:不使用$db,不直接调用函数,使用fpds(而非云端-datasource.json)。声明了outParams的槽位使用return $flow.outParams;,不要只写return;。参见 references/footprint-workflows.md → Code Patterns。 vars/events/fromBaseConfiguration保持为null。
第 5 阶段:发现类型并验证
dxs configuration contexts footprintworkflow -b <branchId> -D body.json
dxs configuration validate footprintworkflow -b <branchId> -D body.json
contexts 会返回 $types.FootPrintWorkflow.* IntelliSense 类型界面;其 flowContext 会将你声明的签名回显为类型化的 IFlow,可用于快速检查 $flow.inParams.Input / $flow.outParams.* 是否解析为该槽位的类型。确认你引用的每个字段都存在(不要自行编写平台类型)。根据需要使用以下三种类型发现来源(参见 references → Discovering the type surface):
FootPrintWorkflow.*平台类型(Input/ 结果形状)——使用contexts,或使用workflowsMetadataAPI 的types数组(结构化 JSON,更易查询)。- 分发代码使用的
$types.<Package>.*包类型(例如$types.Utilities.e_awi_scopes.Cartonization)——使用dxs configuration nomenclature -b <branchId>(可使用--package/--kind enum/--search进行筛选;枚举成员列于constantValues中)。
validate 可以捕获结构性错误和必填字段错误,但无法发现错误的槽位绑定(workflowDefinitionId / 名称)、与槽位不匹配的签名或违反操作层级规则的问题——请逐项检查预检清单。
第 6 阶段:推送
# New
dxs configuration upsert footprintworkflow -b <branchId> -D body.json
# Modify-existing (round-trip — never skip the jq extract)
dxs configuration get footprintworkflow <configId> -b <branchId> -O envelope.json
jq .json envelope.json > body.json
# ... edit ...
dxs configuration upsert footprintworkflow -b <branchId> -D body.json
第 7 阶段:验证(可选)
在运行中的平台上测试该槽位——触发实体状态变更 / 箱盒化 / 分配 / 库位推荐,并确认工作流已调用,且结果或提交前修改按预期生效。如果应用不可用,则重新获取配置(使用 jq .json 提取),并与 body.json 比较差异,以确认推送已生效。
上线前检查清单
请完整查看 references/footprint-workflows.md → 上线前检查清单。快速版:
configurationTypeId: 23;常用后缀为-footprintWorkflow.json。- 槽位绑定真实有效 — 从 workflowsMetadata 目录中复制
workflowDefinitionId+workflowDefinitionName;apiSettingName与分支的 Footprint 设置一致。 workflowGUID正确 — 使用新的 v4 UUID(新建工作流,调用方改为指向新工作流)、保留原有值(编辑),或使用旧工作流的 GUID(有意进行直接替换)。编辑时绝不重新生成。- 参数契约与槽位一致 — 单个
Input,类型与槽位的输入类型一致(通常为FootPrintWorkflow.<Slot>InputBaseWL);输出参数严格遵循槽位定义(或为[])。 description不超过 100 个字符且非空; 设置accessModifier;全新配置使用id: 0。- 单个
ExecuteCodeActivity节点;start指向其id;vars/events/fromBaseConfiguration为null。 - 代码符合 Action 层规范 —
$flows.<Pkg>.<action>(不使用函数或$db)、使用fpds读取、$types.FootPrintWorkflow.*、$utils.isDefined;声明了outParams时 →return $flow.outParams;。 - 根据
contexts或元数据中的types验证类型。 - 针对该分支完成验证。
常见错误
| 错误 | 修复方法 |
|---|---|
臆造或混用 workflowDefinitionId / workflowDefinitionName | 从 workflowsMetadata API 获取槽位的 id/name 和 inParams/outParams,并原样复制。id 和 name 错误或混用时,验证虽能通过,但不会正确绑定。 |
编辑时重新生成 workflowGUID,或从不相关的配置中克隆一个 GUID | 调用方通过 GUID 选择此工作流(它不属于槽位绑定)。新建工作流时使用新的 v4 UUID(python3 -c "import uuid; print(uuid.uuid4())");编辑时保持原值不变。只有一种情况可以复制 GUID——直接替换拥有该 GUID 的工作流。 |
重命名 Input、添加输入参数,或更改输出参数结构 | 签名由槽位定义。保持单个 Input: FootPrintWorkflow.<Slot>InputBaseWL,并使用槽位规定的精确输出参数(或 [])。不匹配时验证虽能通过,但调用会失败。 |
手动编写 Input/结果的接口 | 使用 dxs configuration contexts footprintworkflow -D body.json 读取真实结构;引用 $types.FootPrintWorkflow.*。 |
在工作流中调用函数或使用 $db | Action 层规范:通过 $flows.<Pkg>.<action> 调用操作;将函数/$db 逻辑封装在操作后面;使用 fpds,不要使用云数据源。 |
在声明了 outParams 的槽位中使用裸 return; | 使用 return $flow.outParams; — 裸 return; 会破坏生成的正文;Validate 检测不到,但 Preview 可以发现。 |
将 get -O envelope.json 的输出直接传给 upsert -D | 先运行 jq .json envelope.json > body.json — 信封会覆盖内容并携带密钥。 |
对压缩后的 code 字符串直接查找替换 | 使用 Python json.load/json.dump 编辑;使用 \r\n 拼接;绝不要调整周围的 JSON 结构。 |
| 在节点中内联复杂业务逻辑 | 让节点只负责轻量调度到包操作;这样既符合库中的模式,也便于维护。 |
| 基于 PublishedMain 编写 | Main 的 readonly: true。请在已确认的功能分支上编写(绝不要猜测 id)。 |
编辑后,调用 post-edit-verification,以发现描述、JSON 或架构违规。最终审查时,调用 component-validator。