معماری چندکسب‌وکاری، تجاری و تجارت الکترونیک · فصل ۷ — Connector، Order، Packing، Barcode، Carrier و Notification · 268

Shopify Integration

Design a bounded Shopify connector that pins API/version assumptions, maps external IDs into a canonical internal contract, verifies event/request provenance, records idempotency and replay evidence, and preserves UNKNOWN/RETRY/HOLD states instead of treating vendor delivery as proof of internal completion. می‌تواند «Shopify Integration» را برای یک workflow محدود با state/contract/approval و verification مناسب طراحی کند.

Shopify Integration — fa-IR

Lesson summary

Design a bounded Shopify connector that pins API/version assumptions, maps external IDs into a canonical internal contract, verifies event/request provenance, records idempotency and replay evidence, and preserves UNKNOWN/RETRY/HOLD states instead of treating vendor delivery as proof of internal completion.

می‌تواند «Shopify Integration» را برای یک workflow محدود با state/contract/approval و verification مناسب طراحی کند.

This lesson produces

می‌تواند «Shopify Integration» را برای یک workflow محدود با state/contract/approval و verification مناسب طراحی کند.

Who it is for

Foundation

Use a field map, one worked scenario and explicit state vocabulary before independent construction.

Repair

Identify the failed evidence dimension, use the smallest mutated fixture and rerun only the affected gate.

Experienced

Compress definitions; require trade-off defense, counterexample analysis and changed-context transfer.

Prerequisites

When “GraphQL succeeded” still does not mean “the integration is correct”

Imagine a Shopify order webhook is retried after a timeout while an inventory mutation has already been sent but its response is lost. If the connector only records “HTTP succeeded” or “the webhook was valid,” critical questions remain unanswered: Which API version actually handled the request? Were the required scopes present? Which canonical identity does the Shopify GID map to? Is this delivery a duplicate or a distinct event? Is the mutation retry the same intent or a new operation? And after a lost response, what actually happened in Shopify?

The lesson output is Shopify Connector Contract and Event Ledger v1. The goal is not to build a generic Shopify client. The goal is to make every observation and mutation reconstructable before it can influence local state.

COM-027 ownership boundary

COM-027 owns Shopify-specific integration evidence: shop identity, GraphQL Admin surface, API version, access scopes, external GID mapping, webhook verification/deduplication, mutation idempotency, retry state and reconciliation. COM-029 owns provider-agnostic connector architecture and COM-028 owns WooCommerce-specific integration.

Three red lines:

  1. Shopify object != canonical local object
  2. valid HMAC != business completion
  3. successful response != permission to invent a new retry identity

Mental model: Shop → Version/Scopes → External identity → Event authenticity → Dedupe → Mapping → Mutation identity → Retry/Reconcile → Local promotion

Auditable flow:

shop_ref → GraphQL Admin + requested/observed version + scopes → external_order_id/GID → webhook topic + webhook/event ID + HMAC + digest → dedupe/order check → schema_mapping_version → mutation + idempotency key + attempt → response/retry state → reconciliation_cursor → canonical_order_id → evidence_ref

Each gate solves a different problem. HMAC does not repair mapping; idempotency does not repair missing scopes; and GraphQL success alone does not close uncertainty after a timeout.

Keep FACT, INFERENCE and DESIGN separate

FACT: Shopify currently documents the GraphQL Admin API as the admin app/integration surface. On 15 September 2026, 2026-07 is the latest stable version and 2026-10 is a release candidate.

FACT: Shopify versioned APIs release quarterly. If an inaccessible version is requested, Shopify can fall forward to the oldest accessible stable version, while X-Shopify-API-Version reports the version that actually fulfilled the request.

FACT: Shopify webhook deliveries include HMAC, X-Shopify-Webhook-Id, X-Shopify-Event-Id, API version and trigger timestamp metadata. Delivery ordering is not guaranteed and duplicate delivery can occur.

FACT: Shopify's documented idempotency behavior applies only to mutations that support it. Retries of the same intended operation reuse the same key, distinct operations need distinct keys, and the documented key retention window is 24 hours.

INFERENCE: Because API version, event delivery and mutation retry can drift independently, their evidence should be stored separately so transport success cannot silently become business truth.

DESIGN: MAKNOW gates local promotion on mapping/version, event identity, retry identity and reconciliation. That policy is local design, not a Shopify mandate for every app.

The 23-dimension Shopify contract

casedecisionapi_versionaccess_scope_setschema_mapping_versionevent_id_or_dedupe_keyauthenticity_checkidempotency_keyretry_stateevidence_ref
baselineACCEPT_CONNECTOR2026-07read_orders write_inventorymap-v7wh-1001VERIFIEDidem-1001CLOSEDevidence://COM-027/baseline
scope_missingHOLD_ACCESS_SCOPE2026-07read_ordersmap-v7wh-1002VERIFIEDidem-1002BLOCKEDevidence://COM-027/scope
duplicateHOLD_EVENT_DEDUPE2026-07read_orders write_inventorymap-v7wh-dup-1VERIFIEDidem-1003DUPLICATE_EFFECT_DETECTEDevidence://COM-027/dup
version_transferHOLD_MAPPING_VERSION2026-10read_orders write_inventorymap-v7wh-1004VERIFIEDidem-1004PENDING_MAPPINGevidence://COM-027/version-transfer

Gate 1 — Identify the shop and connector explicitly

connector_id and shop_domain_or_tenant_ref must be unambiguous. “Shopify production” is not sufficient audit identity. Real secrets or access tokens never belong in the learner artifact.

Gate 2 — Pin API surface and version

api_surface is GRAPHQL_ADMIN for this lesson. api_version is part of the contract, not an incidental URL setting. The current baseline requires a production target marked STABLE_SUPPORTED; a release candidate is useful for migration testing, not the production baseline here.

Gate 3 — Compare requested and observed version

If a retired version falls forward, the request can still succeed while the effective schema contract differs from what the caller requested. Record the actual response version. A mismatch produces HOLD_API_VERSION until mapping assumptions are rechecked.

Gate 4 — Separate access scope from authentication

A valid session/token proves authentication, not that the required query or mutation scopes are available. access_scope_set must satisfy the operation. Missing scope yields HOLD_ACCESS_SCOPE.

Gate 5 — Never treat Shopify GID as canonical identity

external_order_id and external_gid are Shopify identities. canonical_order_id is produced through a versioned mapping. Downstream logic should not couple itself to vendor ID shapes.

Gate 6 — Revalidate mapping when schema meaning changes

schema_mapping_version records which field contract the adapter understands. API version changes, deprecation or semantic drift invalidate the previous success assumption until mapping is reviewed and, when needed, bumped.

Gate 7 — Verify webhook HMAC against the raw body

authenticity_check must verify the delivered raw body. Parsing or transforming before verification can destroy the evidence. Invalid or unknown HMAC yields HOLD_AUTHENTICITY.

Gate 8 — Keep delivery identity separate from business meaning

event_id_or_dedupe_key records delivery identity. Receiving the same X-Shopify-Webhook-Id twice must not produce a second side effect. X-Shopify-Event-Id can strengthen correlation across deliveries from one merchant action, but does not replace business mapping.

Gate 9 — Do not assume webhook ordering

Shopify does not guarantee ordering. A late old update must not regress canonical state merely because it arrived later. Preserve timestamp/version evidence and evaluate progression explicitly.

Gate 10 — Use vendor idempotency only where supported

A string called “idempotency key” is not enough. First establish that the mutation supports Shopify's documented idempotency behavior. Otherwise keep a local stable operation identity and dedupe path.

Gate 11 — Same intent retry, same key

A timeout retry of the same operation reuses the same key. Generating a new UUID for every attempt defeats duplicate protection. Conversely, distinct operations require distinct keys even if variables look similar.

Gate 12 — Lost response after send means UNKNOWN, not definite failure

If the request left the process but the response was lost, response_state=UNKNOWN_AFTER_SEND. Blind retry before reconciliation can duplicate work. Idempotency helps, but the outcome still needs bounded reconciliation.

Gate 13 — Cached response is not the business oracle

Shopify documents that a retried idempotent operation can receive a cached response and that reconstructed response data can reflect current database state. Transport safety therefore does not replace domain evidence.

Gate 14 — Missing decisive evidence fails closed

Unknown version, scopes, mapping, HMAC, event identity, idempotency or reconciliation yields a typed HOLD/UNKNOWN state rather than optimistic acceptance.

Worked examples

1. Stable baseline → ACCEPT_CONNECTOR

The shop is explicit, GraphQL Admin is pinned to stable 2026-07, requested and observed versions match, scopes are sufficient, GID mapping is versioned, webhook HMAC is verified, delivery is deduplicated, and mutation/retry/reconciliation evidence is closed.

2. Required scope removed → HOLD_ACCESS_SCOPE

The session is valid but the operation lacks required authorization. Authentication does not prove authorization.

3. Invalid HMAC → HOLD_AUTHENTICITY

A plausible order-shaped payload is still unusable for promotion before authenticity is verified.

4. Same webhook creates a second side effect → HOLD_EVENT_DEDUPE

Duplicate delivery must be idempotent. Double fulfillment or adjustment is connector failure even if both HTTP deliveries succeeded.

5. Timeout retry uses a new key → HOLD_IDEMPOTENCY

The intent is the same but the key changed, so the provider cannot recognize it as the same protected operation.

6. Retired requested version falls forward → HOLD_API_VERSION

HTTP success is insufficient. Requested/observed mismatch means schema assumptions must be revalidated.

7. Transfer: version changes and a mapped field is deprecated → HOLD_MAPPING_VERSION

Even when the new version is stable, the previous mapping is not the oracle. Revalidate or bump it.

8. Response is lost after send → HOLD_RECONCILIATION

Do not issue definite success or failure until query/ledger evidence closes the operation outcome.

Common failure modes

  • using an implicit “latest” instead of a pinned version;
  • ignoring X-Shopify-API-Version and fall-forward;
  • treating a valid token as sufficient scope;
  • leaking Shopify GID shape into the local identity model;
  • keeping an old mapping after version/schema change;
  • verifying HMAC after the request body has been transformed;
  • applying the same X-Shopify-Webhook-Id twice;
  • trusting arrival order;
  • attaching idempotency semantics to a mutation that does not support them;
  • generating a new key for the same-intent retry;
  • reusing one key for distinct operations;
  • turning post-send timeout into definite failure;
  • equating a provider response with business completion;
  • copying a baseline result into transfer without recomputation.

Alternatives and trade-offs

Webhook-only: low latency, but duplicate/out-of-order/missed deliveries and versioned payloads remain operational concerns. It is insufficient for unresolved outcomes by itself.

GraphQL polling-only: gives controlled snapshots but increases latency and API usage. Useful for reconciliation, not necessarily the only ingestion path.

Webhook + bounded GraphQL reconciliation: more contract work, but closes ambiguity better and is the lesson's preferred bounded pattern.

Vendor GID downstream: fast start, high coupling to Shopify semantics.

Versioned Shopify adapter: more design effort, but keeps version/scopes/mapping/retry evidence at the provider boundary.

Experienced bridge: eighteen review questions

  1. What exactly are connector_id and shop reference?
  2. Which API surface is used?
  3. Which API version was requested?
  4. Which version actually fulfilled the response?
  5. What is the support/stability status of that version?
  6. Which access scopes are required?
  7. How are external order ID and GID traced?
  8. Which mapping version produced the canonical order ID?
  9. What triggers a mapping-version bump?
  10. What are webhook topic and delivery ID?
  11. How was HMAC verified against the raw body?
  12. What payload digest is recorded?
  13. How are duplicate deliveries neutralized?
  14. How does the ledger prevent regression from out-of-order delivery?
  15. Does the mutation support Shopify idempotency?
  16. Did the same-intent retry reuse the same key?
  17. What are response, retry and reconciliation states?
  18. Can a reviewer reconstruct the outcome from evidence_ref alone?

Guided and independent practice

The offline lab contains eight fixtures: baseline, insufficient scope, invalid HMAC, duplicate webhook, out-of-order regression, same-intent retry with a new key, API version fall-forward, and a transfer case with stale mapping after a version change.

Independent task: migrate an integration from 2026-07 to a later API version where one adapter field is deprecated. State which evidence can be reused, which evidence must be rechecked, what requires a mapping bump, and why a successful request on the new version alone does not authorize local promotion.

Verification evidence

A passing artifact fills all 23 dimensions or returns an explicit typed non-success state. No real secret/token is stored; requested and observed versions are traceable; scopes are explicit; GID never becomes canonical truth directly; HMAC and event identity are checked before event acceptance; duplicate/out-of-order behavior cannot create extra side effects or regression; idempotency is limited to supported mutations; the same-intent retry preserves operation identity; and post-send uncertainty closes through reconciliation.

The lab is fully synthetic and offline. It requires no network, real shop, token or customer data.

Assessment and transfer

To complete the lesson you must be able to:

  1. explain COM-027's boundary against COM-028 and COM-029;
  2. build Shopify Connector Contract and Event Ledger v1;
  3. separate requested version from observed version;
  4. verify access scope separately from authentication;
  5. map external GID through a versioned identity mapping;
  6. handle webhook authenticity, deduplication and ordering independently;
  7. apply retry idempotency only to supported operations with stable key reuse;
  8. rebuild the version-change transfer without blindly reusing the baseline decision.

References and freshness

  • Shopify GraphQL Admin API — rechecked 15 September 2026; 2026-07 is the latest stable version and the versioned endpoint is current FACT evidence.
  • Shopify API versioning — rechecked 15 September 2026; quarterly releases, support lifetime, release candidate and fall-forward semantics are FACT evidence.
  • Shopify Webhooks / Verify deliveries / Delivery structure — rechecked 15 September 2026; HMAC, delivery/event IDs, version header, duplicate and out-of-order behavior are FACT evidence.
  • Shopify Implementing idempotency — rechecked 15 September 2026; supported-mutation scope, same-intent key reuse and the documented 24-hour retention window are FACT evidence.
  • Mapping, typed HOLD states and local-promotion policy are MAKNOW DESIGN.

Assessment

There is no answer key in this lesson pack; answer it yourself and mark honestly. "Needs review" sends the lesson to your review queue.

COM-027-S1 retrieval

Explain what COM-027 owns and name one adjacent non-goal.

lesson ✗AI ✗notes ✗

COM-027-S2 application

Build Shopify Connector Contract and Event Ledger v1 for the baseline fixture.

lesson ✗AI ✗notes ✗

COM-027-S3 diagnosis

A mutation timed out after send and a retry generated a new idempotency key. Diagnose the unsafe boundary and minimal repair.

lesson ✗AI ✗notes ✗

COM-027-S4 transfer

The Shopify API version changes and a mapped field is deprecated. Recompute version/mapping evidence without copying the prior success result.

lesson ✗AI ✗notes ✗
Assessment rubric
DimensionSufficient evidence
Shop/API identityconnector, shop, API surface and requested/observed version are explicit
Access boundaryrequired access scopes are explicit; no real token is embedded
Identity mappingShopify ID/GID maps through a versioned adapter to canonical identity
Webhook authenticityHMAC and payload digest are verified before event acceptance
Delivery safetyduplicate and out-of-order deliveries cannot create duplicate effect or regression
Mutation idempotencysupported mutations use stable same-intent keys; distinct operations differ
Reconciliationunknown-after-send or retry uncertainty closes against bounded evidence
Transferversion/schema change is recomputed rather than copied from baseline

References & freshness

Shopify GraphQL Admin API reference
·
Shopify API versioning
·
Shopify webhooks
·
Shopify verify webhook deliveries
·
Shopify implementing idempotency
·
COM-027 Frozen Lesson Bible
·

Case studies

Lab files

python run_checks.py را اجرا کنید. همه fixtureها ساختگی‌اند و هیچ shop واقعی، شبکه، access token یا داده مشتری لازم نیست.