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 Key | Shopify Type | Protocol Column | Description |
|---|---|---|---|---|
| 1 | dosage | single_line_text_field | dosage_info (JSON) | “2 capsules”, “1 scoop (5g)“ |
| 2 | frequency | single_line_text_field | schedule (JSON) | “twice daily”, “once in the morning” |
| 3 | timing | single_line_text_field | timing | ”with meals”, “before bed” |
| 4 | duration | single_line_text_field | duration_days (parsed) | “30 days”, “8 weeks” |
| 5 | instructions | multi_line_text_field | instructions | Detailed usage directions |
| 6 | warnings | multi_line_text_field | warnings | Contraindications, precautions |
| 7 | protocol_category | single_line_text_field | protocol_category | ”supplement”, “probiotic”, etc. |
| 8 | protocol_json | json | protocol_json | Full structured protocol object |
| 9 | enrichment_version | number_integer | enrichment_version | Schema version for forward compat |
| 10 | enriched_at | date_time | enriched_at | Last AI enrichment timestamp |
| 11 | functional_goals | json | functional_goals | Wellness outcomes JSON array |
| 12 | evidence_level | single_line_text_field | evidence_level | anecdotal/emerging/established/clinically_studied |
| 13 | usage_type | single_line_text_field | usage_type | ingestion/application/topical/inhalation |
Database Models
ShopifyProtocolSync (Bridge Table)
Tracks sync state between Shopify products and Journals records. Located indata/schemas/db/models/integrations/shopify_sync.py.
| Column | Type | Description |
|---|---|---|
| shopify_product_id | String(255) | Shopify product GID |
| shopify_shop_domain | String(255) | e.g. “store.myshopify.com” |
| protocol_id | FK → protocol.id | Local protocol record |
| product_id | FK → product.id | Local product record |
| sync_status | String | pending, synced, error, stale |
| enrichment_version | Integer | Last synced version |
| last_synced_at | DateTime | Last successful sync |
| error_message | String | Error details if sync failed |
UserProtocolSubscription
Lightweight “follow/subscribe” action for marketplace protocols. Located indata/schemas/db/models/integrations/subscription.py.
| Column | Type | Description |
|---|---|---|
| clerk_user_id | String(255) | Subscribing user |
| protocol_id | FK → protocol.id | Subscribed protocol |
| status | String | active, paused, cancelled |
| subscribed_at | DateTime | When user subscribed |
| paused_at | DateTime | When paused (if applicable) |
| cancelled_at | DateTime | When cancelled (if applicable) |
| share_data | Boolean | Share adherence data with partner |
(clerk_user_id, protocol_id)
Extended Protocol Fields
Added to existingProtocol model (models/syntropy/protocol.py):
timing,warnings,protocol_category— from Shopify metafieldsprotocol_json— full structured protocol object (JSON)enrichment_version,enriched_at— AI enrichment trackingshopify_product_id— links to Shopify product GIDfunctional_goals— wellness outcomes (JSON array)evidence_level,certifications— quality indicators
Extended ProtocolProduct Fields
Added to existingProtocolProduct model (models/syntropy/product.py, DB table: product):
shopify_product_id— Shopify product GIDprice— product price (float)sku— stock keeping unit
API Contract
Partner Analytics (Journals → Shopify app)
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 noread_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 metafields —
orders/paidwebhook is live for purchase events - No payment for subscriptions — protocol follows are free
- Seed data fallback — demo protocols loaded from
data/seed/catalog.pywhen no DB data exists - No protocol versioning — Shopify updates overwrite, don’t create versions
CRUD Operations
Subscription operations infunctions/db_utils/subscriptions.py:
subscribe_to_protocol_sync()— create or reactivate subscriptionunsubscribe_from_protocol_sync()— cancel subscriptionpause_subscription_sync()/resume_subscription_sync()— lifecycle managementget_user_subscriptions_sync()— list user’s subscriptionsbatch_get_subscription_status_sync()— bulk status lookup (N+1 prevention)