Saltar al contenido principal

Ecommerce Shopify Operations Runbook

Operational runbook for diagnosing and recovering ecommerce integration issues in apps/backend/src/ecommerce/.

This runbook is source-backed and reflects the current Shopify-only implementation.


Scope

Codepaths covered:

  • interfaces/ecommerce.controller.ts
  • infrastructure/shopify/shopify-webhook.controller.ts
  • application/ecommerce.service.ts
  • infrastructure/ecommerce-polling.processor.ts
  • infrastructure/ecommerce-provider.factory.ts
  • infrastructure/ecommerce-connection.repository.ts
  • apps/backend/src/main.ts raw body setup for Shopify webhook HMAC verification

1) Triage matrix

SymptomLikely area
OAuth callback redirects with ?error=...handleOAuthCallback and provider code exchange
Webhooks arrive but no orders ingestedwebhook signature validation / payload parsing / dedup
Orders sync only intermittentlypolling queue and repeat job state
Product push endpoints return accepted but no data in Shopifyprovider API/scopes/mapping failures
Unknown e-commerce provider errorsprovider value unsupported by factory
Connection shows active but no recent sync logsworker not consuming queue or no events triggering sync

2) First checks

  1. Check connection state:
curl -s "http://localhost:4000/ecommerce/connection?businessId=<businessId>" \
-H "Authorization: Bearer <app-token>"
  1. Check recent sync logs:
curl -s "http://localhost:4000/ecommerce/sync/log?businessId=<businessId>&page=1&limit=20" \
-H "Authorization: Bearer <app-token>"
  1. Validate granted scopes (debug endpoint):
curl -s "http://localhost:4000/ecommerce/debug/scopes?businessId=<businessId>" \
-H "Authorization: Bearer <app-token>"

3) OAuth and connection flow checks

Expected flow:

  1. GET /ecommerce/oauth/url
  2. provider authorization screen
  3. provider callback to GET /ecommerce/oauth/callback
  4. token exchange + webhook registration + encrypted credential persistence
  5. repeat poll job registration
  6. redirect back to PWA settings with ?connected=true

If callback returns error:

  • verify state integrity (decode base64url and confirm expected business/provider/shop fields)
  • verify provider app credentials/config
  • verify callback base URL used for webhook registration (APP_BASE_URL)

Operational note:

  • webhook registration failures are non-fatal during connect; polling fallback still runs

4) Webhook diagnostics

Route: POST /ecommerce/webhooks/shopify

Critical behavior:

  • route expects raw body buffer for HMAC verification
  • auth failure (signature / unknown shop / missing secret) returns 401
  • non-auth application errors return 200 { ok: false } intentionally (prevents retry storms)

Checklist:

  1. confirm x-shopify-shop-domain, x-shopify-hmac-sha256, x-shopify-topic headers
  2. confirm connection exists for incoming shop domain
  3. confirm webhook secret is stored/decryptable
  4. confirm payload topic is supported by adapter parser
  5. check sync log entries of type order_webhook

5) Polling diagnostics

Queue behavior from code:

  • queue: ecommerce-polling
  • repeat job name: poll
  • repeat every 15 minutes
  • repeat job id: ecommerce-poll-{businessId}

Key checks:

  1. manual enqueue:
curl -s -X POST "http://localhost:4000/ecommerce/sync/poll?businessId=<businessId>" \
-H "Authorization: Bearer <app-token>"
  1. run synchronous debug poll:
curl -s "http://localhost:4000/ecommerce/debug/poll?businessId=<businessId>" \
-H "Authorization: Bearer <app-token>"
  1. inspect sync log for order_webhook entries

Current implementation note:

  • order_poll exists as a sync-log type in the domain/query DTOs, but polling calls the same ingestion path as webhooks and currently writes order_webhook. Treat order_poll as reserved until EcommerceService.ingestOrder records the source path separately.

Important implementation detail:

  • startup dedup in EcommercePollingProcessor uses job.key to remove true duplicates safely

6) Product/collection sync diagnostics

Manual triggers:

  • POST /ecommerce/sync/products
  • POST /ecommerce/sync/collections

Expected behavior:

  • controller responds with HTTP 202 and a syncLogId
  • current source awaits the paginated batch loop before returning; this is not a queued background job today
  • summary sync log status should be success, partial, or error
  • batch size is fixed at 50 records in EcommerceService.runBatchPush

If pushes fail:

  • inspect errorDetail in sync logs
  • check token scopes (debug/scopes)
  • verify connection status and token decrypt path
  • verify product/collection data assumptions (active products, non-archived collections)

7) Known constraints

  • Factory currently supports only shopify; WooCommerce is not wired yet.
  • disconnect is idempotent: returns 204 even if no connection exists.
  • inbound order dedup relies on ingested-order guard (insertIfNew).
  • mapping and inventory deductions depend on external-to-FlowPOS product mapping accuracy.
  • OAuth state is base64url-encoded JSON in current service code. Do not rely on it as a signed or TTL-bound token unless the implementation changes.
  • Shopify registers inventory_levels/update, but the adapter currently parses only orders/create; inbound Shopify inventory webhooks are ignored.

8) Recovery playbook

Preferred order:

  1. re-check scopes and connection
  2. trigger sync/poll manually
  3. run debug/poll for immediate confirmation
  4. disconnect and reconnect OAuth if credentials or webhook state is suspect
  5. re-run product/collection sync after reconnect

Escalate to provider adapter debugging if failures persist with valid connection/scopes.