Skip to main content

Shopify Protocol Sync

Cross-app data flow between the Shopify Protocols seller app and Syntropy Journals consumer app.
Naming convention: ProtocolProduct = the physical item (supplement, probiotic). Protocol = the usage plan wrapping a ProtocolProduct. See README for entity model.

Architecture

Scope Design: No Order Access for Partners

The partner Shopify app (shopify.app.toml) requests only read_products,write_products. This is intentional:
  • Partners manage products, not orders. They enrich product metafields with protocol data.
  • Partners see aggregate outcomes (adherence rates, completion funnels) — not individual purchases.
  • Order data is consumer-side only — users sync their own purchase history via consumer_shopify.py.
  • Privacy boundary: no user PII, purchase history, or health data crosses to the partner.

Shopify Metafield Schema

Namespace: shrine_protocols
#Metafield KeyShopify TypeProtocol ColumnDescription
1dosagesingle_line_text_fielddosage_info (JSON)“2 capsules”, “1 scoop (5g)“
2frequencysingle_line_text_fieldschedule (JSON)“twice daily”, “once in the morning”
3timingsingle_line_text_fieldtiming”with meals”, “before bed”
4durationsingle_line_text_fieldduration_days (parsed)“30 days”, “8 weeks”
5instructionsmulti_line_text_fieldinstructionsDetailed usage directions
6warningsmulti_line_text_fieldwarningsContraindications, precautions
7protocol_categorysingle_line_text_fieldprotocol_category”supplement”, “probiotic”, etc.
8protocol_jsonjsonprotocol_jsonFull structured protocol object
9enrichment_versionnumber_integerenrichment_versionSchema version for forward compat
10enriched_atdate_timeenriched_atLast AI enrichment timestamp
11functional_goalsjsonfunctional_goalsWellness outcomes JSON array
12evidence_levelsingle_line_text_fieldevidence_levelanecdotal/emerging/established/clinically_studied
13usage_typesingle_line_text_fieldusage_typeingestion/application/topical/inhalation

Database Models

ShopifyProtocolSync (Bridge Table)

Tracks sync state between Shopify products and Journals records. Located in data/schemas/db/models/integrations/shopify_sync.py.
ColumnTypeDescription
shopify_product_idString(255)Shopify product GID
shopify_shop_domainString(255)e.g. “store.myshopify.com”
protocol_idFK → protocol.idLocal protocol record
product_idFK → product.idLocal product record
sync_statusStringpending, synced, error, stale
enrichment_versionIntegerLast synced version
last_synced_atDateTimeLast successful sync
error_messageStringError details if sync failed

UserProtocolSubscription

Lightweight “follow/subscribe” action for marketplace protocols. Located in data/schemas/db/models/integrations/subscription.py.
ColumnTypeDescription
clerk_user_idString(255)Subscribing user
protocol_idFK → protocol.idSubscribed protocol
statusStringactive, paused, cancelled
subscribed_atDateTimeWhen user subscribed
paused_atDateTimeWhen paused (if applicable)
cancelled_atDateTimeWhen cancelled (if applicable)
share_dataBooleanShare adherence data with partner
Unique constraint: (clerk_user_id, protocol_id)

Extended Protocol Fields

Added to existing Protocol model (models/syntropy/protocol.py):
  • timing, warnings, protocol_category — from Shopify metafields
  • protocol_json — full structured protocol object (JSON)
  • enrichment_version, enriched_at — AI enrichment tracking
  • shopify_product_id — links to Shopify product GID
  • functional_goals — wellness outcomes (JSON array)
  • evidence_level, certifications — quality indicators

Extended ProtocolProduct Fields

Added to existing ProtocolProduct model (models/syntropy/product.py, DB table: product):
  • shopify_product_id — Shopify product GID
  • price — product price (float)
  • sku — stock keeping unit

API Contract

Partner Analytics (Journals → Shopify app)

GET /api/v1/analytics/summary
GET /api/v1/analytics/protocols/{id}/adherence
GET /api/v1/analytics/protocols/{id}/feedback
Authorization: Bearer <partner_api_token>
Summary returns: avgPdc, activeUsers, avgStreakDays, totalProtocols. Per-protocol returns: pdc, activeUsers, avgStreak, completionRate30d/60d/90d. Feedback returns: anonymized [{ status, note, timestamp }].

Purchase & Order Tracking

Order tracking is handled on the consumer side by Journals directly — not by the Shopify partner app. The partner app has no read_orders scope and never accesses individual order data. It only consumes the aggregated analytics above. Consumer-side order correlation (e.g., linking a Shopify purchase to a protocol subscription) is a Journals-side concern, using the consumer’s own Shopify connection or direct input.

Current Limitations

  • Batch sync for metafieldsorders/paid webhook is live for purchase events
  • No payment for subscriptions — protocol follows are free
  • Seed data fallback — demo protocols loaded from data/seed/catalog.py when no DB data exists
  • No protocol versioning — Shopify updates overwrite, don’t create versions

CRUD Operations

Subscription operations in functions/db_utils/subscriptions.py:
  • subscribe_to_protocol_sync() — create or reactivate subscription
  • unsubscribe_from_protocol_sync() — cancel subscription
  • pause_subscription_sync() / resume_subscription_sync() — lifecycle management
  • get_user_subscriptions_sync() — list user’s subscriptions
  • batch_get_subscription_status_sync() — bulk status lookup (N+1 prevention)