Skip to main content

Schema reference

This reference separates Django-managed application tables from the tables created dynamically in each client's Shopify Supabase database.

Application database models

ShopifyConnection

Existing control-plane model read by the subscriber to map a permanent Shopify domain to one organization.

FieldPurpose
organization_idOne-to-one tenant owner
setup_by_idUser who configured the connection
shop_urlConfigured shop URL
client_idShopify application credential
api_secret_keySecret used for direct webhook HMAC verification
myshopify_domainPermanent domain used by subscriber organization resolution
access_token, token_expires_atShopify API access state
created_at, updated_atConnection audit timestamps

ShopifyEvent

Existing direct-webhook audit model written by shopify_webhook_view.

FieldPurpose
organization_idOwning organization
topicShopify slash topic
shop_domainSource shop
payloadRaw JSON body
received_atApplication receipt time

Indexes: shopify_app_org_recv_idx on organization and descending receipt time, and shopify_app_org_topic_idx on organization and topic.

Database

Existing database registry read by ShopifyEventStorage.

FieldPurpose
database_nameLogical database name; shopify is the fallback selector
typeApplication type; shopify is the primary selector
organization_idClient owner
is_deletedExcludes retired targets from resolution
datasource_id, last_sync_dateExisting Redash/sync metadata outside this pipeline

The model enforces unique (organization_id, database_name) values.

DatabaseCredential

Existing one-to-one credential record read after the target Database is selected.

FieldPurpose
database_idOne-to-one target database
db_typeDefaults to postgresql
host, port, db_name, usernameConnection components
encrypted_passwordFernet-encrypted password
created_at, updated_atCredential audit timestamps

Password decryption requires the backend's DB_CREDENTIAL_FERNET_KEY to match the key used during encryption.

SubscriberFailedEvent

New Django model introduced by PR #23. The default physical table name is subscriber_subscriberfailedevent.

FieldType / defaultPurpose
idBig auto primary keyRetry record identifier
sourceString, emptyEvent source
event_typeString, emptyNormalized event type
event_idString, emptyWebhook/event identifier when known
shop_domainString, emptyShopify tenant key
organization_idNullable bigint, indexedResolved organization when known
envelopeJSON objectComplete enriched replay payload
error_typeStringLatest exception class
error_messageTextLatest exception message
tracebackTextFull latest Python traceback
statuspendingpending, resolved, or failed
retry_count0Number of failed replay attempts
max_retries5Terminal failure threshold
next_retry_atNullable timestampEarliest next eligible replay
last_attempted_atNullable timestampLast replay start
resolved_atNullable timestampSuccessful replay completion
created_at, updated_atAutomatic timestampsLifecycle audit

Named indexes:

  • sub_failed_status_retry_idx on (status, next_retry_at)
  • sub_failed_source_type_idx on (source, event_type)
  • sub_failed_shop_event_idx on (shop_domain, event_id)

Client Supabase event ledger

shopify_events

ColumnPostgreSQL typeConstraint / behavior
idBIGSERIALPrimary key
event_idTEXTRequired; explicit webhook ID or deterministic hash
organization_idBIGINTRequired
shop_domainTEXTRequired
topicTEXTRequired slash form, for example orders/create
event_typeTEXTRequired dot form, for example orders.create
resource_typeTEXTRequired module name
resource_idTEXTRequired, empty string when not found
payloadJSONBOriginal Shopify payload
parsed_payloadJSONBTyped customer representation or raw fallback
received_atTIMESTAMPTZEnvelope timestamp or processing time
inserted_atTIMESTAMPTZDefaults to NOW() on first insert

Uniqueness and indexes:

  • Unique (organization_id, shop_domain, event_id)
  • shopify_events_org_topic_idx on (organization_id, topic, received_at DESC)
  • shopify_events_org_resource_idx on (organization_id, resource_type, resource_id)

Client Supabase resource snapshots

All 12 module tables share one physical shape.

ColumnPostgreSQL typeConstraint / behavior
organization_idBIGINTComposite primary key
shop_domainTEXTComposite primary key
shopify_idTEXTComposite primary key
topicTEXTMost recently processed slash topic
event_typeTEXTMost recently processed dot event type
payloadJSONBLatest raw resource body
parsed_payloadJSONBLatest parsed or fallback body
is_deletedBOOLEANDefaults to false; set from delete topics
first_seen_atTIMESTAMPTZDefaults to first insert time and is never overwritten
last_seen_atTIMESTAMPTZEvent receipt time, updated on conflict

Every table has a primary key on (organization_id, shop_domain, shopify_id) and an index named <table>_org_topic_idx on (organization_id, topic).

Provisioned target tables

ResourceTable
Event ledgershopify_events
Ordersshopify_orders
Checkoutsshopify_checkouts
Cartsshopify_carts
Productsshopify_products
Customersshopify_customers
Customer groupsshopify_customer_groups
Payment termsshopify_payment_terms
Refundsshopify_refunds
Selling plan groupsshopify_selling_plan_groups
Returnsshopify_returns
Reverse deliveriesshopify_reverse_deliveries
Reverse fulfillment ordersshopify_reverse_fulfillment_orders

Security and retention notes

  • Supabase passwords are designed to be stored encrypted in DatabaseCredential; plaintext DSNs should not be committed.
  • ShopifyConnection.api_secret_key and access_token are currently plain model fields with an in-code encryption TODO. That is outside PR #22/#23 but remains a production hardening item.
  • Failure envelopes and tracebacks may include client payload data. Access, retention, and redaction rules should treat the failure table as sensitive.
  • No row-level security policy, table partitioning, TTL, or purge process is introduced by these PRs.