DFC Bridge 交付契约
DFC Bridge 契约记录图层名称和 Figma 属性无法完整表达的决定:数据、响应式转换、交互结果和交付证据。它将源设计与实现、QA 连接起来,不依赖某一种目标平台。
本页供集成开发或结构化交付使用。准备第一份设计页面时,请先读设计师快速起步。下文先说明一起传递的数据,再说明它们如何关联设计元素,以及如何验证这些关联。外层结构和 JSON Schema 在 1.0 之前可能变化,因此每次交换都要固定 contractVersion、methodologyVersion 和 rulesVersion。
两种互补的表达方式
标题为“两种互补的表达方式”的章节图层名称用于浏览和定位,不应成为存放所有信息的数据库。
简短的图层标签
标题为“简短的图层标签”的章节设计师用少量标签表达浏览设计时就需要看见的意图:
catalog [page=catalog] [route=/catalog] [bp=1200] [view=default] products [section=product-results] product-grid [collection=products] product-card-oak-chair [item=product] filter [action=state:filters-open]标签标识页面、变体、区块、链接和动作、目标、字段、集合、视觉策略、溢出及明确的例外。数据模型、状态图、动效时间线、无障碍测试计划和交付历史则不放进标签。
结构化 bridge 元数据
标题为“结构化 bridge 元数据”的章节详细信息统一放在 bridge 对象中,并引用设计中的稳定标识。它可以保存在 Figma 插件数据、随附的 JSON 文件或适配器传输数据中,但必须随设计一起交付,并作为整体接受验证。
Figma/source metadata + short DFC Bridge anchors + structured bridge metadata ↓ one transferable contract已有结构化字段能表达的信息,不要再创建新的图层标签。
外层结构与核心字段
标题为“外层结构与核心字段”的章节完整数据以 bridge 为根对象。核心内容包括:
| 字段 | 用途 |
|---|---|
contractVersion |
结构化数据格式的版本。 |
methodologyVersion |
准备交付时采用的 DFC Bridge 版本。 |
rulesVersion |
验证所用的规则目录版本。 |
source |
来源工具、文件/页面、不可变修订版本和采集上下文。 |
context |
声明的交付范围、适用的产品/页面上下文、包含的变化轴及外部依赖。 |
identity |
角色、模板、设计实例、运行时数据与目标实现之间的对应关系。 |
structure |
各响应式/数据上下文中的逻辑树。Figma 的原生节点类型、布局模式、定位和资源边界仍属于源证据,与逻辑树一起验证。 |
| 契约模块 | 按适用范围包含 data、responsive、interaction、motion、accessibility、capabilities 和 lifecycle。 |
openQuestions |
未决问题及其负责人、范围、是否阻塞、复查时点和备用方案。 |
exceptions |
明确的源设计/契约例外,以及影响和补偿措施。 |
只有范围证明某模块不适用,才能省略它。缺少模块不能表示“没有人检查”。
用映射区分不同标识
标题为“用映射区分不同标识”的章节一个名称不能同时可靠地表示交付中的所有身份。DFC Bridge 区分五个维度:
| 维度 | 回答的问题 | 示例 |
|---|---|---|
role |
元素承担什么逻辑作用? | 数据项 / 商品 |
template |
哪个可复用定义拥有其形态和行为? | product-card |
designInstance |
这是设计及其上下文中的哪个具体实例? | product-card-oak-chair |
runtimeData |
通过什么记录键规则或样例绑定运行时内容? | 集合 products,键字段 sku |
target |
哪个实现实体对应此元素? | Web 组件 ProductCard |
bridgeKey 用于连接契约引用,不会把这些维度合并成一个。[item=product] 表示可重复的角色或类型,不是唯一设计实例或运行时记录 ID。product-card-3 这样的顺序名称可以临时标识设计样例,但不能成为运行时记录键。排序、筛选、分页、实时更新,以及看起来相同的不同记录,都需要稳定的业务键。
交互目标与实现映射也不同:交互反应引用模态窗口、状态、表单、路由或元素的 bridgeKey;identity.elements[].target 则把元素映射到实现代码或另一目标平台。
模块组合示例
标题为“模块组合示例”的章节把本例当作模块关系图,而不是可原样复制的完整项目。部分引用对象的完整定义未包含在此片段中。实际交付只包含适用模块,保留同样的命名空间结构,并验证所有引用。仓库中的完整可执行示例位于 validator/examples/bridge-contract.valid.json。
{ "bridge": { "contractVersion": "0.2.0", "methodologyVersion": "0.11.7", "rulesVersion": "0.5.0", "source": { "tool": "figma", "fileKey": "example-file-key", "pageId": "12:4", "pageName": "Catalog", "versionId": "figma-version-2026-08-13T10:20Z", "capturedAt": "2026-08-13T10:25:00Z" }, "context": { "transferId": "catalog-default", "page": "catalog", "route": "/catalog", "view": "default", "axes": { "locale": "en-US", "theme": "light" }, "contextIds": ["catalog-1200", "catalog-360"] }, "identity": { "elements": [{ "bridgeKey": "product-card-oak-chair", "role": { "kind": "data-item", "semantics": "product" }, "template": { "templateKey": "product-card", "sourceComponentId": "55:8", "sourceComponentName": "UI Kit / Product Card" }, "designInstance": { "designInstanceKey": "product-card-oak-chair", "sourceNodes": [ { "contextId": "catalog-1200", "nodeId": "401:72", "layerPath": ["Catalog / 1200", "product-grid", "product-card-oak-chair"] }, { "contextId": "catalog-360", "nodeId": "509:21", "layerPath": ["Catalog / 360", "product-grid", "product-card-oak-chair"] } ] }, "runtimeData": { "collection": "products", "keyField": "sku", "fixtureKey": "oak-chair", "runtimeDataKey": "sku:CHAIR-OAK-01" }, "target": { "platform": "web", "kind": "component", "targetKey": "ProductCard", "locator": "src/catalog/ProductCard" } }] }, "structure": { "contexts": [ { "id": "catalog-1200", "rootIdentity": "catalog", "tree": { "product-results": ["product-grid", "filter-button"] } }, { "id": "catalog-360", "rootIdentity": "catalog", "tree": { "product-results": ["product-grid", "filter-button"] } } ] }, "data": { "displays": [{ "displayId": "product-grid", "purpose": "Browse products matching the active catalog query", "source": { "owner": "catalog-service", "dataset": "products", "refresh": "request" }, "dimensions": [{ "key": "sku", "type": "string" }], "measures": [{ "key": "price", "type": "decimal", "currency": "USD" }], "format": { "locale": "user", "currencyDisplay": "symbol" }, "states": ["loading", "empty", "error", "partial", "stale"] }] }, "responsive": { "defaultPolicy": "same-tree", "contexts": [ { "id": "catalog-1200", "driver": "viewport", "width": 1200 }, { "id": "catalog-360", "driver": "viewport", "width": 360 } ], "transformations": [{ "id": "comparison-table-to-disclosures", "fromContext": "comparison-wide", "toContext": "comparison-narrow", "when": { "driver": "container", "container": "comparison-panel", "condition": "max-width: 480px" }, "mappings": [{ "source": ["comparison-table"], "target": ["comparison-disclosures"], "semantics": "same-records-and-fields" }], "preserves": ["content", "actions", "field-relationships", "selection", "accessible-names"], "readingOrder": ["comparison-heading", "comparison-disclosures"], "focusOrder": ["comparison-disclosure-trigger:*"], "stateTransfer": "preserve-selection-and-open-record", "history": "no-new-entry" }] }, "interaction": { "stateMachines": [{ "id": "catalog-filter", "initial": "idle", "states": ["idle", "pending", "results", "empty", "failure"], "transitions": [{ "id": "apply-filter", "from": ["idle", "results", "empty", "failure"], "event": { "type": "submit", "source": "catalog-filter-form" }, "pending": { "to": "pending", "duplicateEvent": "replace-with-latest" }, "outcomes": { "success": { "to": "results", "focus": "results-heading", "announce": "Results updated" }, "empty": { "to": "empty", "focus": "results-heading" }, "failure": { "to": "failure", "focus": "filter-error", "retry": "preserve-values" } }, "history": "replace-query" }] }] }, "motion": { "sequences": [] }, "capabilities": { "profiles": [{ "id": "mobile-low-bandwidth", "target": { "platform": "web", "runtime": "browser" }, "essentialExperience": ["product-name-and-price", "filter-and-open-product"], "supports": ["responsive-images", "offline-cache"], "unsupported": [{ "capability": "scroll-timeline", "fallback": "static-scenes", "owner": "storefront" }], "assets": [{ "element": "product-image", "width": 960, "height": 960, "formats": ["avif", "webp", "jpeg"], "quality": "product-detail-visible", "artDirection": "square-crop-with-subject-safe-area", "loading": { "priority": "results-dependent", "poster": null, "strategy": "lazy-outside-first-window" } }], "data": { "expectedItems": 48, "maximumItems": 10000, "virtualizeAfter": 200, "strategy": "server-pagination" }, "conditions": ["low-bandwidth", "offline", "data-saver", "low-power"], "budgets": [{ "metric": "initial-results-payload", "limit": 250, "unit": "KiB", "owner": "storefront", "measureAt": "release-qa" }] }] }, "accessibility": { "profile": { "standard": "WCAG", "version": "2.2", "level": "AA" }, "elements": [{ "element": "product-grid", "name": "Catalog results", "readingOrder": ["results-heading", "active-filters", "product-grid", "pagination"], "testIds": ["catalog-results-keyboard", "catalog-results-reflow"] }] }, "lifecycle": { "transferId": "catalog-default", "contractRevision": "7", "sourceRevision": "figma-version-2026-08-13T10:20Z", "targetRevision": "build-1842", "status": "qa", "owners": { "design": "catalog-design", "contract": "design-systems", "implementation": "storefront", "qa": "quality" }, "requirements": ["REQ-CATALOG-017", "REQ-CATALOG-021"], "evidence": { "tests": ["catalog-grid-default", "catalog-grid-keyboard"] }, "deviations": [] }, "openQuestions": [{ "id": "OPEN-CATALOG-003", "scope": ["catalog", "offline"], "question": "May users open a product from stale cached results?", "owner": "catalog-product", "blocking": true, "due": "2026-08-18", "reviewAt": "contract-gate", "fallback": "Show cached results read-only and disable product navigation", "status": "open" }], "exceptions": [] }}图层标签仍是人可以直接看到的定位依据;结构化数据补充无法放进名称的关系和决定。
默认保持同一棵树,结构变化需要声明
标题为“默认保持同一棵树,结构变化需要声明”的章节responsive.defaultPolicy 为 same-tree。几何、Auto Layout 方向、换行、同一逻辑父级内的顺序,以及已声明的可见性变化,不需要结构映射。
树结构或呈现方式发生变化时,必须用 responsive.transformations[] 记录。记录包括源和结果标识、视口/容器条件、字段/场景/动作映射、保留的语义、阅读与焦点顺序、状态传递和历史行为。没有对应转换记录的差异属于契约偏移。
原生布局仍然需要源证据
标题为“原生布局仍然需要源证据”的章节bridge.structure 不重复保存 Figma 的原生 layoutMode、节点类型和定位字段。源验证器直接读取这些字段并应用规则目录:
- 页面根始终使用原生 Auto Layout,不能标记为
[asset]; - 由画框构建的区块根与
Page Sections源根使用 Auto Layout,除非该区块本身确实是整体交付的视觉资源; - 支持 Auto Layout 且至少包含两个可见、有意义的内容流子节点的普通容器使用 Auto Layout;
GROUP只允许位于真正不透明的[asset]子树内;- 基础图形、叶节点几何与已放置的
INSTANCE内部不作为内容流容器检查; [decor]只标识具体的、具有明确意图的绝对定位视觉节点,不构成结构检查豁免。
Page Check 将放置的 INSTANCE 视为原子对象,不会为了区块布局规则继续解析其源组件;应单独检查可编辑源根。资源根仍是逻辑树中的一个标识,也是父级 Auto Layout 中的一项。附带原因的手动布局例外可以记录结构偏差,但不会改变源证据,也不会把失败的 Page Check 变成通过。
在现有产品中限定选中区块的范围
标题为“在现有产品中限定选中区块的范围”的章节团队可以先对一个新区块采用 DFC Bridge,不必同时迁移周围的产品。边界是明确选中的源根节点,并具有稳定的区块标识:
checkout-summary [section=checkout-summary]不要把区块伪装成页面。[page]、[bp]、[view] 和 [route] 仍是页面根标签,不能只为启动验证而添加。Check selected section(检查选中区块) 只遍历规范化后的选中根节点及其后代。结果取决于所选对象:
- 可编辑的
FRAME或COMPONENT接受完整的本地源检查。GROUP仍是阻塞性的结构问题。 - 如果选中的区块根节点本身是
INSTANCE,只能检查其边界,结果为 Partial。 - 普通后代
INSTANCE被视为可信的原子边界。本次遍历不检查其内部,因此它不会降低 Ready。 [section=id] [asset]位于选中的根节点本身时,可形成有效的整体视觉资源边界,内部布局检查不适用。- 如果区块位于另一个非页面根的
[asset]祖先之下,范围无效,结果为 Blocked;检查不能穿过这条继承的资源边界。
页面根上的非法 [asset] 不会隐藏内部结构。Page Check 会单独报告该根的问题,后代仍可检查。单独的 [decor] 也不会停止遍历。
结构化范围记录选中了什么,以及什么仍在范围之外。以下是非独立片段,应放入完整的 bridge 外层结构:
{ "context": { "project": "Legacy storefront section adoption", "scope": { "kind": "section", "rootIdentity": "checkout-summary", "boundary": "selected-subtree", "assetBoundary": "none", "hostCompliance": "legacy-out-of-scope", "selectionMode": "explicit-variants", "contextIds": ["summary-container-360", "summary-container-1200"], "readinessClaim": "section-source-only" }, "externalDependencies": [{ "id": "checkout-route-dependency", "kind": "route", "reference": "/checkout", "status": "deferred", "owner": "storefront-platform", "reviewAt": "host integration gate" }] }, "responsive": { "defaultPolicy": "same-tree", "contexts": [ { "id": "summary-container-360", "driver": "container", "width": 360, "label": "Container 360", "labelSource": "inferred-from-selected-root-width" }, { "id": "summary-container-1200", "driver": "container", "width": 1200, "label": "Container 1200", "labelSource": "inferred-from-selected-root-width" } ] }}范围字段的含义如下:
- 对于可编辑或原子源根,
assetBoundary为none。只有选中的区块根本身带有[asset]时,才为selected-root-opaque。祖先资源边界不能构成有效的区块范围契约。 single-root表示只请求了一个上下文。无需编造未请求的变体,也可以达到源就绪。explicit-variants表示用户明确选中了两个或更多具有相同[section]标识的根进行比较。验证器不能自行寻找旧文件中的相邻对象并扩大范围。- 工具根据选中根或容器宽度推导上下文名称时,应记录
labelSource: inferred-from-selected-root-width,不能把推导结果当作作者明确表达的意图。
区分本地证据与外部依赖:
- 在选中根内部找到的动作目标属于本地目标。
- 完整且有效的
http:、https:、mailto:或tel:地址,在区块源范围内视为作者已明确给出,不会导致 Partial。地址在运行时是否可用不属于源检查范围。 - 不完整或格式错误的外部地址属于阻塞性的
interaction.href-invalid问题,而不是 Deferred。 - 需要到选中根之外查找的内部路由/锚点、模态窗口/状态/表单/重置目标、组件和数据,既不能判为缺失,也不能视为已验证。应关联外部契约,或在
externalDependencies中记录为待确认/未验证,再由独立的文件或产品集成检查确认。
完整可执行示例见 bridge-section-contract.valid.json。
成功的区块契约只表示 选中区块的源设计在声明的上下文中就绪。它不证明周围的旧页面、路由、完整响应式版本、端到端流程、实现或产品已就绪,也不代表符合 WCAG。
明确记录未知项,不留下未跟踪的问题
标题为“明确记录未知项,不留下未跟踪的问题”的章节DFC Bridge 不承诺所有决定都已确定,而是要求所有相关未知项都有记录。
unknown、unsupported、TBD 等状态只有记录到 openQuestions[] 才有效。记录包含:
- 稳定 ID 和准确范围;
- 未决问题或不支持的能力;
- 负责人;
- 是否阻塞;
- 截止日期或明确的复查阶段;
- 未解决时的安全备用方案;
- 当前状态,以及解决后的决定链接。
如果备用方案不安全、不满足无障碍需求、有误导性或会破坏数据,该问题就是阻塞项,受影响范围不能通过对应验收。只存在于口头讨论、聊天、孤立任务或个人记忆中的问题,仍是 DFC Bridge 的盲点。
目标能力与性能约束
标题为“目标能力与性能约束”的章节契约不能假设所有目标平台都有相同的编解码器、输入方式、布局能力、内存、网络和电力条件。capabilities.profiles[] 声明目标平台与运行环境、降级时必须保留的核心体验、支持与不支持的能力,以及每项不支持需求对应的已测试备用方案。
- 媒体和资源:声明原始尺寸、可接受的格式与质量、构图和裁剪安全区、加载优先级、封面/预览,以及预加载或延迟加载策略。
- 数据:声明预期和最大数据量,以及分页、流式加载或虚拟化的阈值。
- 适用条件:覆盖低带宽、离线、省流量、低功耗、减少动效和 API 缺失等情况。
设计负责声明必要内容、媒体、顺序和任务结果。实现负责可测量的性能预算、交付策略、测量手段和证据。尚未确定的能力或预算应成为有负责人、有安全备用方案的未决问题,不能从某张漂亮的设计图中推断。
来源优先级与继承
标题为“来源优先级与继承”的章节每项事实有一个负责来源:
- 目标平台的安全、隐私和原生语义约束所有其他来源;
- 已批准的产品和内容决定定义含义;
- 结构化 DFC Bridge 契约定义源工具无法表达的意图;
- Figma/源元数据定义设计中的结构、组件、几何和样式;
- 已固定版本的组件/系统契约提供继承行为;
- 明确批准的例外或偏差记录剩余差异。
不要把组件状态机复制到每个实例。引用已固定版本的模板,只声明实例专属内容、覆盖项和上下文。
契约验证器应检查:
- 数据模式及固定的版本字段;
- 范围内
bridgeKey、设计实例、需求、问题、例外和偏差 ID 的唯一性; - 标识、树、数据显示、转换、反应、动效、无障碍与测试之间的引用有效性;
- 源节点和上下文是否存在;
- 运行时记录映射是否误用了样例的顺序索引;
- 是否保持同一逻辑树,或存在覆盖差异的适用转换;
- 能力配置是否按需包含资源/媒体、数据量、降级、不支持功能的备用方案,以及有负责人的预算;
- 状态机可达性与动作目标;
- 必需的数据状态和无障碍配置;
- 未决问题的负责人、范围、阻塞状态、复查时点和备用方案;
- 临时例外/偏差的复查或到期日期,以及证据。
JSON 格式有效不等于产品契约有效。确定性模式检查、源设计检查和人工语义评审互为补充。
1.0 之前的兼容性
标题为“1.0 之前的兼容性”的章节- 生成方必须明确输出
contractVersion。 - 使用方必须拒绝不支持的主要数据结构,并报告未知字段,不得默默丢弃必要含义。
- 新增扩展字段应保留命名空间并附有说明。
- 迁移必须保留稳定标识和需求链接。
- 契约修订一旦用于已接受的实现/QA 执行,就不可修改;变更应创建新修订。