Skip to main content

Overview

Charlie is built on security-first principles: no customer PII, no payment data, minimal Shopify API permissions, and full data residency within the Shopify and Cloudflare ecosystem.

Data governance

What Charlie stores

Charlie stores only operational configuration in its own database (Cloudflare D1 — SQLite). The complete database schema contains ten tables, none of which hold customer PII:
Charlie contains no customer PII, no order content, no payment information. This is enforced at the Shopify API scope level — Charlie does not request read_customers access.

What Charlie writes to Shopify

Charlie computes and writes back operational values to Shopify metafields. All values are merchant configuration or computed inventory data — no customer data is involved. Variant metafields Product metafields Location metafields

What Charlie never touches

The following data stays exclusively within Shopify and is never accessed, processed, or stored by Charlie:
  • Customer PII (names, emails, addresses, phone numbers)
  • Payment and billing information
  • Order content and transaction history
  • Customer purchase history

Data ownership and portability


Shopify API permissions

Charlie requests only the scopes required for omnichannel fulfillment operations. No customer data scope is requested or used.
No read_customers scope is requested or used at any point. Charlie has zero API access to customer PII.

Security controls

Authentication and session management

  • All admin routes enforce shopify.authenticate.admin(request) before any processing — unauthenticated requests are rejected immediately
  • Sessions stored in Cloudflare D1 using Shopify’s official session storage adapter
  • direct_api_mode = "online" — no long-lived offline tokens
  • Access tokens stored server-side only, never exposed to client-side code

Multi-tenancy isolation

Every database query is scoped by shop domain at the ORM layer. No query executes without an explicit WHERE shop = ? filter derived from the authenticated Shopify session. This is enforced in code on every data access function — not by convention alone.

Webhook security

HTTP security headers

Applied globally to all requests via Hono secureHeaders() middleware:
Content-Security-Policy and X-Frame-Options are intentionally omitted. Charlie runs as a Shopify embedded app inside an iframe — Shopify manages these restrictions at the platform level.

Rate limiting

Charlie implements a token-bucket rate limiter for all outbound Shopify API calls:
  • Max 20 requests/second toward Shopify API
  • Max 10 concurrent requests per worker instance
  • Queue-based backpressure — requests wait rather than fail under load

Encryption

Error monitoring

Sentry is used for operational error monitoring. Error payloads contain stack traces and request context only — no customer PII, no access tokens, no session content. Sentry is disabled in development environments.

GDPR compliance

Charlie implements all three mandatory Shopify GDPR compliance webhooks:

Shop redact (shop/redact)

Triggered when a merchant uninstalls and requests data deletion. Charlie deletes all shop-specific data atomically across all database tables.

Customer data request (customers/data_request)

Charlie acknowledges this webhook and returns no data — by design. The app stores no personal customer data to return. This is documented explicitly in the codebase: This app does NOT store any personal customer data. We only store shop-level configuration (locations, safety stock rules, etc.). No customer PII, order details, or personal identifiers are persisted. If this app ever stores customer data in the future, this service must be updated.

Customer redact (customers/redact)

No-op by design — Charlie stores no customer-level data to redact.

Infrastructure and sub-processors

Charlie does not currently hold SOC2 certification. All compute and storage infrastructure runs on Cloudflare (SOC2 Type II certified).

Risk summary


Last modified on April 23, 2026