integration-capability-analysis

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Integration capability analysis

集成能力分析

Factorial's integrations framework is organised by domain — payroll and finance today — and each domain defines a set of capabilities, each with a direction and the Factorial endpoints behind it. This skill takes one external system's specification and works out, capability by capability, which vendor endpoints implement it and how every field maps between the two APIs.
The output is an integration mapping document. It serves two readers at once: whoever decides whether the integration is worth building, and whoever then builds it. The first needs the verdicts; the second needs the endpoint sequence and the field mapping. Both depend on the same rule — cite or downgrade: a mapping row, an endpoint or a verdict that cannot be pointed at in the vendor's specification does not go in the document as fact.
Factorial 的集成框架按领域组织——目前包括薪资和财务——每个领域定义一组能力,每项能力都有数据传输方向以及与其对应的 Factorial endpoint。此 skill 接收一个外部系统的规范,并逐项确定哪些供应商 endpoint 可以实现各项能力,以及两个 API 之间的每个字段应如何映射。
输出是一份集成映射文档。它同时面向两类读者:决定集成是否值得构建的人,以及随后负责实施集成的人。前者需要各项判定,后者需要 endpoint 调用顺序和字段映射。二者都依赖同一条规则——有依据,否则降级:如果映射行、endpoint 或判定无法在供应商规范中找到依据,就不能将其作为事实写入文档。

The catalogue is the public documentation

能力目录以公开文档为准

The capabilities are defined in Factorial's API documentation, one page per domain:
Read the page for the domain in scope at the start of every analysis. Each one lists the domain's capabilities, the direction of each, what it covers, and links to the Factorial endpoints involved. Those pages are the source of truth: analyse every capability they list, use the direction they state, and take Factorial field names from the endpoint references they link to. Do not work from memory of what a payroll or finance integration usually contains — the real lists differ from the intuitive ones, and a mapping built against the wrong capability set looks exactly as convincing as a correct one.
The URLs are versioned. Use the version the requester names, otherwise the one above, and record which version you used in the document's header, since field names and capabilities can change between versions.
If a page can't be fetched, stop and say so rather than improvising the capability list.
能力定义在 Factorial 的 API 文档中,每个领域各有一页:
每次分析开始时,都要阅读目标领域的文档页面。每一页都会列出该领域的能力、各项能力的方向、覆盖范围,以及相关 Factorial endpoint 的链接。这些页面是事实来源:必须分析其中列出的每一项能力,采用其中指定的数据方向,并从所链接的 endpoint 参考文档中获取 Factorial 字段名称。不要凭记忆判断薪资或财务集成通常包含哪些内容——实际能力列表可能与直觉不同,而基于错误能力列表生成的映射,看起来会与正确映射一样有说服力。
这些 URL 包含版本号。使用请求方指定的版本;如果未指定,则使用上述版本,并在文档头部记录所使用的版本,因为字段名称和能力可能随版本发生变化。
如果无法获取某个页面,应停止并说明情况,而不是自行推测能力列表。

Step 1 — Classify the domain

第 1 步——确定领域

Decide which domain the vendor belongs to: a payroll engine is payroll; an accounting system or ERP is finance. Some systems span both — an ERP with a payroll module — in which case analyse each domain and produce one document per domain. If the system fits neither, say so and stop; forcing it into a domain produces a mapping nobody can use.
State the classification and the reason in one line at the top of the document. Don't block on the requester to confirm it; if it was a judgement call, say so and carry on.
判断供应商属于哪个领域:薪资引擎归入薪资;会计系统或 ERP 归入财务。某些系统同时涵盖两个领域,例如包含薪资模块的 ERP——此时应分别分析各个领域,并为每个领域分别生成一份文档。如果系统不属于任何领域,应说明并停止;强行将其归入某个领域只会产生无人能够使用的映射。
在文档顶部用一行说明分类结果及理由。不要等待请求方确认;即使这是一项主观判断,也应说明并继续执行。

Step 2 — Load the domain's capabilities

第 2 步——加载领域能力

From the domain page, build the working list: every capability, its direction, and the Factorial endpoints it links to. Then follow those endpoint links for the fields — you cannot map what you have not read. Read them per capability as you reach it rather than all upfront; the domain pages link to many endpoints and most of them serve only one capability.
Also carry forward anything the page says that constrains the whole domain: ordering or setup sequences (which records must exist before others can be created), identifiers Factorial requires on writes (such as an
external_id
on records posted into Factorial), and incremental-sync parameters. These shape the endpoint sequence in the document, not just individual rows.
根据领域页面建立工作清单:列出每项能力、其数据方向,以及它所链接的 Factorial endpoint。然后访问这些 endpoint 链接以获取字段信息——未读取的内容无法映射。不要一次性读取所有 endpoint,而应在分析到某项能力时再读取其相关内容,因为领域页面会链接大量 endpoint,其中大多数只服务于一项能力。
同时记录页面中所有会影响整个领域的约束:顺序或设置流程(例如必须先存在哪些记录,才能创建其他记录)、Factorial 在写入时要求的标识符(例如写入 Factorial 的记录需要包含
external_id
),以及增量同步参数。这些内容会影响文档中的 endpoint 调用顺序,而不只是单个映射行。

Step 3 — Inventory the vendor specification

第 3 步——盘点供应商规范

Build a factual inventory before mapping anything. Going capability-first means looking for the endpoint you expect and finding something adjacent to it.
For an API specification — OpenAPI/Swagger, a developer portal, a PDF guide — record one row per operation: method, path, what it does, request and response fields with their required flags, and where each came from (
operationId
, section, page). Those references become the citations.
Read the field documentation and the examples, both. Descriptions tell you what a field means; examples frequently tell you what it actually takes — the date format, the real enum values, how a nested object is shaped, which fields are populated together, a field that appears in the example but was never documented in the schema. Examples often complete behaviour the schema leaves open, so use them. Where an example contradicts the schema, report the contradiction rather than silently picking one.
In a schema, slow down for
allOf
composition (the real
required
list is the union of all branches) and for a
$ref
pointing back at its own ancestor (a relationship modelled as a nested object instead of an id — usually unusable, and worth a spec-quality note).
For a file specification, the same inventory in file terms: each record type or layout stands in for an endpoint, each column for a field — with mandatory flags, types, lengths, code lists, the key linking records across files, delivery mechanism, and any acknowledgement or error file.
开始映射之前,先建立基于事实的规范清单。按能力推进时,很容易只找到预期 endpoint 的相邻操作。
对于 API 规范——OpenAPI/Swagger、开发者门户或 PDF 指南——每个 operation 记录一行:method、path、用途、请求与响应字段及其必填标记,以及每项信息的来源(
operationId
、章节或页码)。这些来源将成为引用依据。
字段文档和示例都要阅读。 描述说明字段的含义;示例通常展示字段实际接受的内容,例如日期格式、真实的 enum 值、嵌套对象的结构、哪些字段会同时被填充,以及仅在示例中出现、但未在 schema 中记录的字段。示例经常补充 schema 未定义的行为,因此必须使用示例。如果示例与 schema 存在冲突,应报告该矛盾,而不是擅自选择其中一个。
在 schema 中,要特别留意
allOf
组合(真正的
required
列表是所有分支的并集),以及指回自身祖先节点的
$ref
(通常表示将关系建模为嵌套对象而非 id,这类设计往往无法使用,并值得在规范质量说明中指出)。
对于文件规范,使用文件维度建立同样的清单:每种记录类型或布局对应一个 endpoint,每一列对应一个字段,并记录必填标记、类型、长度、代码列表、跨文件关联记录的键、交付机制,以及任何确认文件或错误文件。

Whole-document checks

全文检查

These are claims about what the specification does not contain, and they decide capabilities as often as its contents do. Verify each against the whole file rather than an impression — count or
grep
when the file is long.
  • Operations by method — how many
    GET
    ,
    POST
    ,
    PUT
    ,
    PATCH
    ,
    DELETE
    .
  • Auth actually applied (a root or per-operation
    security
    block), not merely declared under
    securitySchemes
    .
  • Whether any operation declares an error response.
  • Operations that return no body — a create that returns nothing gives us no id to store.
  • Pagination (
    page
    ,
    limit
    ,
    offset
    ,
    cursor
    ) and incremental filters (
    updated_since
    ,
    modified_since
    ,
    since
    ) on list endpoints.
  • Rate limits —
    429
    ,
    Retry-After
    ,
    X-RateLimit-*
    , a documented quota.
  • Every
    enum
    , since each one is a code list to map.
  • deprecated: true
    on an endpoint a capability depends on.
Report what they return, including nothing: "no list endpoint supports incremental filtering" is a finding, not a blank.
以下内容描述的是规范中不包含什么,它们与规范所包含的内容同样会影响能力判定。必须针对完整文件进行验证,而不能仅凭印象;文件较长时应进行计数或
grep
。
  • 按 method 统计 operation——
    GET
    、
    POST
    、
    PUT
    、
    PATCH
    、
    DELETE
    各有多少。
  • 实际应用了哪些认证(根级别或 operation 级别的
    security
    块),而不是仅在
    securitySchemes
    中声明。
  • 是否有 operation 声明错误响应。
  • 哪些 operation 不返回响应体——如果创建操作不返回任何内容,就无法获得需要保存的 id。
  • 列表 endpoint 是否支持分页(
    page
    、
    limit
    、
    offset
    、
    cursor
    )和增量筛选(
    updated_since
    、
    modified_since
    、
    since
    )。
  • 速率限制——
    429
    、
    Retry-After
    、
    X-RateLimit-*
    或有文档说明的配额。
  • 每一个
    enum
    ,因为每个 enum 都是需要映射的代码列表。
  • 某项能力所依赖的 endpoint 是否标记了
    deprecated: true
    。
必须报告检查结果,包括“没有任何结果”的情况。例如,“没有列表 endpoint 支持增量筛选”是一项发现,而不是空白项。

Step 4 — Match each capability

第 4 步——匹配每项能力

Direction decides what to look for on the vendor side:
Outbound — Factorial is the source. We read from Factorial's endpoints and write into the vendor, so the vendor needs write endpoints (
POST
to create,
PUT
/
PATCH
to update) that accept what the Factorial read endpoints return.
Inbound — the vendor is the source. We read from the vendor and write into Factorial, so the vendor needs read endpoints (
GET
, ideally paginated and filterable by modification date) that return what Factorial's write endpoints require.
A rich read API contributes nothing to an outbound capability, and a rich write API nothing to an inbound one. That mismatch is the most common way a vendor that looks well covered turns out not to be.
For each capability, identify the vendor endpoints that implement it and put them in the order an implementation calls them — including the supporting calls that make the main one possible: resolving a legal entity or cost-centre id before a create, reading back the vendor's identifier after it, looking up a code list. Then check the fields, not just the endpoints: a
POST /employees
exists in almost every HR API, and whether it can carry a Factorial new hire is decided entirely by its fields.
数据方向决定应在供应商侧寻找什么:
Outbound——Factorial 是数据源。我们从 Factorial 的 endpoint 读取数据,并写入供应商,因此供应商需要能够接收 Factorial 读取 endpoint 所返回数据的写入 endpoint(使用
POST
创建,使用
PUT
/
PATCH
更新)。
Inbound——供应商是数据源。我们从供应商读取数据并写入 Factorial,因此供应商需要返回 Factorial 写入 endpoint 所要求数据的读取 endpoint(使用
GET
,最好支持分页并可按修改日期筛选)。
读取 API 再丰富,也无法支持 outbound 能力;写入 API 再丰富,也无法支持 inbound 能力。许多看似覆盖充分的供应商,最常见的问题正是出在这种方向不匹配上。
对于每项能力,确定实现它的供应商 endpoint,并按照实际实施时的调用顺序排列,包括使主要操作得以执行的支持性调用:例如在创建前解析法人实体或成本中心 id、创建后读取供应商生成的标识符,以及查询代码列表。随后还要检查字段,而不只是 endpoint:几乎每个 HR API 都有
POST /employees
,但它能否承载 Factorial 的新员工数据,完全取决于其字段。

Step 5 — Map the fields

第 5 步——映射字段

This is the core of the document. For each capability, map every field that carries data between the two systems, in the direction the data flows.
For each row record: the source field and the destination field, as full paths (
GET /employees → birth_on
;
POST /workers → person.date_of_birth
); whether the destination requires it; the transformation, if any; and the evidence — the schema, the documentation text, or an example.
Transformations are where integrations actually break, so be specific about them:
  • Formats — dates, timestamps and time zones, decimal separators, currency as code or symbol, amounts in major or minor units.
  • Code lists — map values, not just fields. Give the value-to-value table when both sides publish their enums; when the vendor's list is configured per customer, say that the mapping is a per-customer configuration.
  • Structure — one field split into several (a full address into street, number, postcode), several joined into one, a flat field that becomes a nested object, a list that must be flattened.
  • Units — hours versus percentage for working time, monthly versus annual salary, days versus hours for absences.
  • Identifiers — which side's id is stored where, and how a record is matched on the next sync.
Then list the two kinds of gap, separately, because they mean different things:
  • Vendor-required fields with no Factorial source. These block the capability or force a default or a manual step. Each one needs a named resolution: a constant, a per-customer configuration value, a derivation, or a gap.
  • Factorial data with no vendor destination. Usually just data the vendor doesn't hold; worth listing so nobody assumes it is synced.
Never invent a vendor field to complete a row. An unmapped row is a finding; a plausible field name that isn't in the spec is a defect in the document.
这是文档的核心。对于每项能力,按照数据实际流动的方向,映射两个系统之间传输数据的每一个字段。
每一行都应记录:源字段和目标字段,并使用完整路径(
GET /employees → birth_on
;
POST /workers → person.date_of_birth
);目标字段是否必填;如需转换则说明转换方式;以及证据来源——schema、文档文本或示例。
转换通常是集成真正失败的地方,因此必须具体说明:
  • 格式——日期、时间戳和时区,小数分隔符,货币采用代码还是符号,以及金额使用主要单位还是最小单位。
  • 代码列表——不仅要映射字段,还要映射值。如果双方都发布了 enum,应提供值对值的映射表;如果供应商的列表按客户配置,应说明该映射需要按客户进行配置。
  • 结构——一个字段拆分为多个字段,例如完整地址拆分为街道、门牌号和邮编;多个字段合并为一个字段;扁平字段转换为嵌套对象;列表需要扁平化。
  • 单位——工时使用小时还是百分比,薪资使用月薪还是年薪,缺勤使用天还是小时。
  • 标识符——存储哪一侧的 id,以及下一次同步时如何匹配记录。
然后分别列出两类缺口,因为它们含义不同:
  • 供应商要求但 Factorial 没有来源的字段。 这些字段会阻止能力实现,或迫使系统使用默认值或人工步骤。每个字段都需要给出明确的解决方式:常量、按客户配置的值、推导逻辑,或确认其为缺口。
  • Factorial 有数据但供应商没有目标字段。 这通常只是供应商不保存的数据,但仍应列出,以免有人误以为这些数据会被同步。
绝不能为了让映射行完整而虚构供应商字段。未映射的行属于发现;使用一个看似合理但规范中不存在的字段名,则属于文档缺陷。

Step 6 — Classify

第 6 步——作出判定

Three verdicts per capability.
Fully supported — the vendor exposes every operation the capability needs in the right direction, every field the destination requires has a source, and the record can be identified again on the next sync. Reachable only when the specification is explicit about all of it.
Partially supported — the operations exist but something needed does not: destination-required fields with no source, no update or correction path, no way to match records on the next sync, no effective dating where the data is time-dependent, a code list with no published values. Every partial verdict states the limitation and a viability judgement — shippable as-is or needs the gap closed first, and what closing it takes.
Not supported — the specification doesn't cover it: the operation or entity is absent, the spec is silent, or the only route is manual work in the vendor's UI. Absence and silence land in the same place because the consequence is the same — we can only build against what is documented. Note in the capability section whether the spec rules it out or is merely silent, since silence is a question for the vendor that could change the verdict.
The line between the last two: a missing field makes a capability partial; a missing operation or entity makes it not supported. Silence about one detail inside a capability that otherwise works — whether re-sending replaces or accumulates, say — is partial, with the detail named as the limitation.
每项能力有三种判定结果。
完全支持——供应商以正确方向提供了该能力所需的每个 operation,目标要求的每个字段都有数据来源,并且下次同步时能够再次识别该记录。只有当规范对所有这些内容都有明确说明时,才能作出此判定。
部分支持——operation 存在,但某些必要内容缺失,例如目标必填字段没有来源、缺少更新或更正路径、无法在下次同步时匹配记录、时间相关数据缺少有效期机制,或代码列表没有公开值。每个部分支持判定都必须说明其限制,并给出可行性判断——可按现状交付或需要先弥补缺口——以及弥补缺口所需的工作。
不支持——规范未覆盖该能力:operation 或实体不存在、规范对此未作说明,或者只能通过供应商 UI 手动完成。缺失和沉默都会得到相同结果,因为其后果相同——只能基于已有文档进行构建。在能力章节中,应注明规范是明确排除了该能力,还是仅保持沉默,因为沉默可能需要供应商进一步说明,而回答可能改变判定结果。
后两者的分界是:缺少字段会使能力成为部分支持;缺少 operation 或实体会使其不受支持。如果某项能力整体可行,但其中一个细节未被说明,例如重复发送是覆盖还是累加,则判定为部分支持,并明确指出该限制。

Step 7 — Write the document

第 7 步——编写文档

Follow
assets/report-template.md
. Fill every section; write "none" rather than dropping one, so a reader can tell "nothing to report" from "not analysed".
The capability summary comes first, because it is what the decision-maker reads. Then one section per capability — every capability the domain page lists, including the unsupported ones, so it is visible that each was assessed. Each section carries the endpoint sequence, the field mapping, the gaps and the verdict. The field mapping is the part an engineer will build from, so it must be complete for the fields in scope and exact about paths and transforms.
Close with the vendor questions, ordered by how much each answer would change the plan, merging any a single conversation would settle.
Save as
<vendor>-<domain>-integration-mapping.md
.
遵循
assets/report-template.md
。填写每一个章节;即使没有内容也应写“none”,以便读者区分“没有需要报告的内容”和“未进行分析”。
首先编写能力摘要,因为决策者会首先阅读它。然后为每项能力分别编写一个章节——包括领域页面列出的所有能力,即使该能力不受支持也应列出,以表明每项能力都已评估。每个章节都应包含 endpoint 调用顺序、字段映射、缺口和判定。字段映射是工程师实施集成时将直接依据的部分,因此必须完整覆盖相关字段,并准确说明路径和转换方式。
最后列出供应商问题,按照每个答案对计划的改变程度排序,并将一次沟通即可解决的相关问题合并在一起。
保存为
<vendor>-<domain>-integration-mapping.md
。

Failure modes

常见失败模式

  • Working from memory instead of the domain page. The real capability lists are longer and sometimes counter-intuitive — directions included. Read the page every time.
  • Endpoint match without field match. An endpoint with the right name and the wrong fields is a partial at best.
  • Ignoring examples. Formats, enum values and undocumented fields often live only there.
  • Inventing fields. Only map fields that appear in the vendor's specification.
  • Mapping fields but not values. Two
    status
    fields with different enums are not mapped until their values are.
  • Asserting absence from an impression. "There is no update endpoint" swings a verdict. Count or grep, then say it.
  • 凭记忆工作,而不是阅读领域页面。 实际能力列表更长,有时也违反直觉——数据方向亦是如此。每次都必须阅读页面。
  • 只匹配 endpoint,不匹配字段。 endpoint 名称正确但字段错误,最多只能判定为部分支持。
  • 忽略示例。 格式、enum 值和未记录字段经常只存在于示例中。
  • 虚构字段。 只能映射供应商规范中明确出现的字段。
  • 只映射字段,不映射值。 两个具有不同 enum 的
    status
    字段,在值尚未映射之前不能视为完成映射。
  • 凭印象断言内容不存在。 “没有更新 endpoint”这类结论会直接影响判定。必须先计数或执行
    grep
    ,然后再作出陈述。