Saltar al contenido principal

Ecommerce Provider Port

Source-backed guide for the e-commerce provider contract in apps/backend/src/ecommerce/domain/ecommerce-provider.port.ts.

Use this when adding providers or reviewing whether a change belongs in the domain port, application service, infrastructure adapter, or HTTP interface.


Intent

The e-commerce module lets FlowPOS sync products, inventory, collections, and external orders without making the application layer depend on Shopify-specific HTTP shapes. EcommerceService depends on EcommerceProviderPort; concrete platform behavior belongs behind infrastructure adapters.

Current runtime provider status:

  • shopify is registered in EcommerceProviderFactory
  • woocommerce is a reserved enum/status value, but no backend adapter is registered and the connect DTO does not accept it

Hexagonal map

LayerCodepathsResponsibility
Domaindomain/ecommerce-provider.port.ts, domain/ecommerce-connection.domain.tsProvider-neutral DTOs and persistence contracts
Applicationapplication/ecommerce.service.ts, application/listeners/*Connection orchestration, outbound sync, inbound ingestion, polling decisions
Infrastructureinfrastructure/ecommerce-provider.factory.ts, infrastructure/shopify/*, Kysely repository, polling processorProvider HTTP calls, webhook security, payload parsing, persistence, queue worker
Interfacesinterfaces/ecommerce.controller.ts, provider webhook controllers, DTOsAuthenticated endpoints, public OAuth callback/webhook routes, request parsing

Port contract

EcommerceProviderPort groups provider responsibilities by workflow:

AreaMethodsNotes
ConnectiongetAuthorizationUrl, exchangeCodeForToken, revokeConnection, registerWebhooksCurrent shipped flow is OAuth-oriented because Shopify is the only adapter
Products and inventorypushProduct, pushCollection, updateInventoryLevelAdapters return external IDs and variant mappings in provider-neutral shapes
OrderspullOrders, acknowledgeOrderUsed by polling fallback after a connection is active
Webhook securityverifyWebhookSignature, parseWebhookPayloadHMAC headers and raw payload parsing stay inside adapters

The port should only include behavior every supported provider can satisfy. Provider-specific authentication, webhook header names, platform API versions, and retry policies are infrastructure concerns.


Factory registration

EcommerceProviderFactory currently maps:

Provider keyAdapter
shopifyShopifyAdapter

Unsupported provider names fail fast with Unknown e-commerce provider: (<provider>).

To add another provider:

  1. implement the adapter under apps/backend/src/ecommerce/infrastructure/
  2. satisfy EcommerceProviderPort with provider-neutral return values
  3. register the adapter in EcommerceProviderFactory
  4. register providers/controllers in EcommerceModule as needed
  5. expand the interface DTOs so the provider can be selected
  6. add adapter, webhook, service, and polling tests for the new provider

Do not branch inside EcommerceService for platform-specific payload formats. Branch in the application layer only when the FlowPOS use case truly differs, such as connection setup for OAuth vs credential-based providers.


WooCommerce extension boundary

WooCommerce is expected to be credential-based rather than OAuth redirect-based. Do not overload the Shopify OAuth endpoints with Consumer Key / Consumer Secret semantics.

Recommended shape for a future WooCommerce implementation:

  • add a credential-based interface endpoint and DTO
  • keep WordPress/WooCommerce REST URL validation in the interface/application boundary
  • keep Consumer Key / Consumer Secret usage inside the WooCommerce adapter
  • register WooCommerce webhooks through adapter code
  • map WooCommerce payloads into EcommerceOrder, EcommerceProduct, and EcommerceCollection domain DTOs before returning to the application layer

Until this is implemented, API consumers should treat woocommerce as reserved forward compatibility.


Common pitfalls

  • ConnectEcommerceDto accepts only shopify; adding an enum value alone does not expose a provider.
  • Shopify orders/create webhooks are parsed into orders; the currently registered Shopify inventory webhook does not produce inbound inventory changes.
  • The repository can store a saleId for an ingested external order, but the current application service does not create FlowPOS sale records from Shopify orders.
  • OAuth state is part of the current Shopify flow. If a provider does not use OAuth, document the interface workflow separately instead of pretending it is the same domain behavior.