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.tsinfrastructure/shopify/shopify-webhook.controller.tsapplication/ecommerce.service.tsinfrastructure/ecommerce-polling.processor.tsinfrastructure/ecommerce-provider.factory.tsinfrastructure/ecommerce-connection.repository.ts
1) Triage matrix
| Symptom | Likely area |
|---|---|
OAuth callback redirects with ?error=... | handleOAuthCallback and provider code exchange |
| Webhooks arrive but no orders ingested | webhook signature validation / payload parsing / dedup |
| Orders sync only intermittently | polling queue and repeat job state |
| Product push endpoints return accepted but no data in Shopify | provider API/scopes/mapping failures |
Unknown e-commerce provider errors | provider value unsupported by factory |
| Connection shows active but no recent sync logs | worker not consuming queue or no events triggering sync |
2) First checks
- Check connection state:
curl -s "http://localhost:4000/ecommerce/connection?businessId=<businessId>" \
-H "Authorization: Bearer <app-token>"
- Check recent sync logs:
curl -s "http://localhost:4000/ecommerce/sync/log?businessId=<businessId>&page=1&limit=20" \
-H "Authorization: Bearer <app-token>"
- 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:
GET /ecommerce/oauth/url- provider authorization screen
- provider callback to
GET /ecommerce/oauth/callback - token exchange + webhook registration + encrypted credential persistence
- repeat poll job registration
- redirect back to PWA settings with
?connected=true
If callback returns error:
- verify
stateintegrity (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:
- confirm
x-shopify-shop-domain,x-shopify-hmac-sha256,x-shopify-topicheaders - confirm connection exists for incoming shop domain
- confirm webhook secret is stored/decryptable
- confirm payload topic is supported by adapter parser
- 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:
- manual enqueue:
curl -s -X POST "http://localhost:4000/ecommerce/sync/poll?businessId=<businessId>" \
-H "Authorization: Bearer <app-token>"
- run synchronous debug poll:
curl -s "http://localhost:4000/ecommerce/debug/poll?businessId=<businessId>" \
-H "Authorization: Bearer <app-token>"
- inspect sync log for
order_pollandorder_webhookentries
Important implementation detail:
- startup dedup in
EcommercePollingProcessorusesjob.keyto remove true duplicates safely
6) Product/collection sync diagnostics
Manual triggers:
POST /ecommerce/sync/productsPOST /ecommerce/sync/collections
Expected behavior:
- endpoint returns accepted response with
syncLogId - batch loop runs paginated pushes
- summary sync log status should be
success,partial, orerror
If pushes fail:
- inspect
errorDetailin sync logs - check token scopes (
debug/scopes) - verify connection
statusand 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. disconnectis idempotent: returns204even 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.
8) Recovery playbook
Preferred order:
- re-check scopes and connection
- trigger
sync/pollmanually - run
debug/pollfor immediate confirmation - disconnect and reconnect OAuth if credentials or webhook state is suspect
- re-run product/collection sync after reconnect
Escalate to provider adapter debugging if failures persist with valid connection/scopes.