This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
ShopCall.ai is an AI-powered calling system integrated with e-commerce platforms. The project consists of:
/data/shopcall/
├── shopcall.ai-main/ # Frontend application
│ ├── src/
│ │ ├── components/ # React components
│ │ │ ├── context/ # React context providers (AuthContext)
│ │ │ └── ui/ # shadcn-ui component library
│ │ ├── pages/ # Route pages (Dashboard, Login, CallLogs, etc.)
│ │ ├── hooks/ # Custom React hooks
│ │ ├── lib/ # Utility functions
│ │ └── App.tsx # Main application with routing
│ └── package.json
└── supabase/ # Supabase Edge Functions
└── functions/ # Backend API functions
cd shopcall.ai-main
npm install # Install dependencies
npm run dev # Start dev server on port 8080
npm run build # Production build
npm run build:dev # Development build
npm run lint # Run ESLint
npm run preview # Preview production build
# Deploy Edge Functions
supabase functions deploy <function-name>
# Test locally
supabase functions serve
Authentication Flow:
src/components/context/AuthContext.tsx) manages global auth statesession_dataRouting Structure:
/ (Index) → Landing page
/signup → User registration
/login → User login
/otp → OTP verification
/dashboard (protected) → Main dashboard
/call-logs (protected) → Call history
/analytics (protected) → Analytics dashboard
/webshops (protected) → E-commerce integrations
/phone-numbers (protected) → Phone number management
/ai-config (protected) → AI configuration
/onboarding (protected) → User onboarding flow
/about, /privacy, /terms → Public pages
Component Organization:
src/pages/ handle routingDashboardContent.tsx) contain page logicsrc/components/ui/ are reusable shadcn componentsApp.tsxSupabase Edge Functions: Backend logic implemented as serverless Edge Functions
Authentication:
E-commerce Integrations:
oauth-shopify (OAuth 2.0 with HMAC verification)webhooks-shopify (customers/data_request, customers/redact, shop/redact)_shared/shopify-client.tsshopify-sync (manual sync for products, orders, customers)oauth-woocommerce (OAuth 1.0a authentication)_shared/woocommerce-client.tswoocommerce-sync (manual sync for products, orders, customers)/wp-json/wc/v3/)/wc-api/v*) are deprecated and NOT supportedoauth-shoprenter-init, oauth-shoprenter-callbackwebhook-shoprenter-uninstallshoprenter-products, shoprenter-orders, shoprenter-customersshoprenter-syncshoprenter-scheduled-sync (automated via pg_cron)_shared/shoprenter-client.tsstores tablestores table:
- user_id: UUID (FK to auth.users)
- platform_name: text (e.g., 'shopify', 'woocommerce', 'shoprenter')
- store_name: text
- store_url: text
- api_key: text (access token for ShopRenter)
- api_secret: text (refresh token for ShopRenter)
- scopes: text[]
- alt_data: jsonb (platform-specific data, e.g., expires_at, last_sync_at)
- phone_number: text
- package: text
oauth_states table (for OAuth flow state management):
- state: text (UUID for CSRF protection)
- user_id: UUID (FK to auth.users)
- platform: text (e.g., 'shoprenter')
- shopname: text
- expires_at: timestamp
pending_shoprenter_installs table (temporary storage during OAuth):
- installation_id: text (UUID)
- shopname: text
- access_token: text
- refresh_token: text
- token_type: text
- expires_in: integer
- scopes: text[]
- expires_at: timestamp
shoprenter_products_cache table (cached product data):
- store_id: UUID (FK to stores)
- shoprenter_product_id: text
- name: text
- sku: text
- price: decimal
- currency: text
- description: text
- stock: integer
- active: boolean
- raw_data: jsonb
- last_synced_at: timestamp
woocommerce_products_cache table (cached WooCommerce products):
- id: UUID (primary key)
- store_id: UUID (FK to stores)
- wc_product_id: text
- name: text
- sku: text
- price: decimal
- currency: text
- description: text
- short_description: text
- stock_quantity: integer
- stock_status: text
- type: text ('simple', 'variable', 'grouped', 'external')
- categories: jsonb
- images: jsonb
- raw_data: jsonb
- last_synced_at: timestamptz
- created_at: timestamptz
- UNIQUE(store_id, wc_product_id)
woocommerce_orders_cache table (cached WooCommerce orders):
- id: UUID (primary key)
- store_id: UUID (FK to stores)
- wc_order_id: text
- order_number: text
- status: text
- total: decimal
- currency: text
- customer_name: text
- customer_email: text
- line_items: jsonb
- billing_address: jsonb
- shipping_address: jsonb
- created_at: timestamptz
- raw_data: jsonb
- last_synced_at: timestamptz
- UNIQUE(store_id, wc_order_id)
woocommerce_customers_cache table (cached WooCommerce customers):
- id: UUID (primary key)
- store_id: UUID (FK to stores)
- wc_customer_id: text
- email: text
- first_name: text
- last_name: text
- username: text
- billing_address: jsonb
- shipping_address: jsonb
- orders_count: integer
- total_spent: decimal
- raw_data: jsonb
- last_synced_at: timestamptz
- created_at: timestamptz
- UNIQUE(store_id, wc_customer_id)
shopify_products_cache table (cached Shopify products):
- id: UUID (primary key)
- store_id: UUID (FK to stores)
- shopify_product_id: text
- title: text
- handle: text
- vendor: text
- product_type: text
- status: text
- price: decimal
- compare_at_price: decimal
- currency: text
- sku: text
- inventory_quantity: integer
- description: text
- images: jsonb
- variants: jsonb
- options: jsonb
- tags: text[]
- raw_data: jsonb
- last_synced_at: timestamptz
- created_at: timestamptz
- UNIQUE(store_id, shopify_product_id)
shopify_orders_cache table (cached Shopify orders):
- id: UUID (primary key)
- store_id: UUID (FK to stores)
- shopify_order_id: text
- order_number: text
- name: text (e.g., "#1001")
- email: text
- phone: text
- financial_status: text
- fulfillment_status: text
- total_price: decimal
- subtotal_price: decimal
- total_tax: decimal
- currency: text
- customer_name: text
- customer_email: text
- line_items: jsonb
- billing_address: jsonb
- shipping_address: jsonb
- note: text
- tags: text[]
- order_created_at: timestamptz
- order_updated_at: timestamptz
- raw_data: jsonb
- last_synced_at: timestamptz
- created_at: timestamptz
- UNIQUE(store_id, shopify_order_id)
shopify_customers_cache table (cached Shopify customers):
- id: UUID (primary key)
- store_id: UUID (FK to stores)
- shopify_customer_id: text
- email: text
- first_name: text
- last_name: text
- phone: text
- accepts_marketing: boolean
- orders_count: integer
- total_spent: decimal
- currency: text
- state: text (enabled, disabled, declined, invited)
- addresses: jsonb
- default_address: jsonb
- tags: text[]
- note: text
- customer_created_at: timestamptz
- customer_updated_at: timestamptz
- raw_data: jsonb
- last_synced_at: timestamptz
- created_at: timestamptz
- UNIQUE(store_id, shopify_customer_id)
gdpr_requests table (GDPR compliance tracking):
- id: UUID (primary key)
- store_id: UUID (FK to stores)
- request_type: text ('data_request', 'customer_redact', 'shop_redact')
- customer_id: text
- shop_domain: text
- request_payload: jsonb
- status: text ('pending', 'processing', 'completed', 'failed')
- processed_at: timestamptz
- error_message: text
- created_at: timestamptz
- updated_at: timestamptz
shopify_webhooks table (webhook registration tracking):
- id: UUID (primary key)
- store_id: UUID (FK to stores)
- shopify_webhook_id: text
- topic: text (e.g., 'orders/create', 'products/update')
- address: text (webhook callback URL)
- format: text (default: 'json')
- is_active: boolean
- last_received_at: timestamptz
- total_received: integer
- created_at: timestamptz
- updated_at: timestamptz
- UNIQUE(store_id, shopify_webhook_id)
shoprenter_webhooks table (webhook registrations):
- store_id: UUID (FK to stores)
- shoprenter_webhook_id: text
- event: text (e.g., 'order/create')
- callback_url: text
- is_active: boolean
- last_received_at: timestamp
- total_received: integer
sync_logs table (scheduled sync execution logs):
- id: UUID (primary key)
- sync_type: text ('manual', 'scheduled', 'webhook')
- platform: text ('shopify', 'woocommerce', 'shoprenter')
- stores_processed: integer
- results: jsonb (detailed results per store)
- started_at: timestamptz
- completed_at: timestamptz
- created_at: timestamptz
store_sync_config table (per-store sync configuration):
- id: UUID (primary key)
- store_id: UUID (FK to stores, unique)
- enabled: boolean (default: true)
- sync_frequency: text ('15min', '30min', 'hourly', '6hours', 'daily')
- last_sync_at: timestamptz
- next_sync_at: timestamptz (auto-calculated)
- sync_products: boolean (default: true)
- sync_orders: boolean (default: true)
- sync_customers: boolean (default: true)
- created_at: timestamptz
- updated_at: timestamptz
shopcall.ai-main/.env.example to .env and fill in your valuessupabase/.env.example to .env and fill in your values.env (shopcall.ai-main)Required environment variables:
# Supabase Configuration (from Supabase Dashboard → Settings → API)
VITE_SUPABASE_URL=https://YOUR_PROJECT.supabase.co
VITE_SUPABASE_ANON_KEY=your_supabase_anon_key
# Backend API Base URL (typically VITE_SUPABASE_URL + /functions/v1)
VITE_API_URL=https://YOUR_PROJECT.supabase.co/functions/v1
# Frontend URL (for OAuth callbacks)
VITE_FRONTEND_URL=http://localhost:8080 # or https://yourdomain.com for production
Note: VITE_API_URL is derived from VITE_SUPABASE_URL by appending /functions/v1
.env (supabase)Required environment variables:
# Supabase Configuration (from Supabase Dashboard → Settings → API)
SUPABASE_URL=https://YOUR_PROJECT.supabase.co
SUPABASE_ANON_KEY=your_supabase_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key
# Frontend URL (same as VITE_FRONTEND_URL in frontend .env)
FRONTEND_URL=http://localhost:8080 # or https://yourdomain.com for production
# E-commerce Platform OAuth Credentials
SHOPIFY_API_KEY=your_shopify_api_key
SHOPIFY_API_SECRET=your_shopify_api_secret
SHOPRENTER_CLIENT_ID=your_shoprenter_client_id
SHOPRENTER_CLIENT_SECRET=your_shoprenter_client_secret
# Internal Security (generate with: openssl rand -hex 32)
INTERNAL_SYNC_SECRET=your_random_secure_secret
# Email Configuration (from https://resend.com/api-keys)
RESEND_API_KEY=your_resend_api_key
CRITICAL: Configure in Supabase Dashboard → Project Settings → Database → Custom Postgres Configuration:
app.internal_sync_secret = 'same_as_INTERNAL_SYNC_SECRET_above'
app.supabase_url = 'https://YOUR_PROJECT.supabase.co'
Why this is required: The pg_cron jobs run database-side trigger functions that need to make HTTP requests to Edge Functions. These settings allow the trigger functions to authenticate and call the scheduled sync Edge Functions.
Without these settings:
To verify settings are configured:
SELECT
current_setting('app.internal_sync_secret', true) as internal_secret,
current_setting('app.supabase_url', true) as supabase_url;
Both values should be non-NULL.
npm run build generates static files in dist/supabase functions deploy commandIMPORTANT: When working with Supabase in Claude Code, ALWAYS use the Supabase MCP tools instead of CLI commands. These tools provide direct integration with Supabase without requiring manual authentication.
Edge Functions Management:
mcp__supabase__list_edge_functions - List all deployed Edge Functionsmcp__supabase__deploy_edge_function - Deploy an Edge Function (with files array)mcp__supabase__get_edge_function - Get Edge Function codeDatabase Operations:
mcp__supabase__list_tables - List database tablesmcp__supabase__list_extensions - List database extensionsmcp__supabase__list_migrations - List all migrationsmcp__supabase__apply_migration - Apply a new migration (DDL operations)mcp__supabase__execute_sql - Execute raw SQL queriesProject Information:
mcp__supabase__get_project_url - Get the project API URLmcp__supabase__get_anon_key - Get the anonymous API keymcp__supabase__generate_typescript_types - Generate TypeScript types from databaseMonitoring & Debugging:
mcp__supabase__get_logs - Get logs for Edge Functions or other servicesmcp__supabase__get_advisors - Check for security/performance issuesBranching (Development):
mcp__supabase__create_branch - Create a development branchmcp__supabase__list_branches - List all branchesmcp__supabase__merge_branch - Merge branch to productionmcp__supabase__delete_branch - Delete a development branchCheck Edge Function logs when debugging deployment issues:
mcp__supabase__get_logs(service: "edge-function")
Monitor deployments by listing Edge Functions after deployment
Environment variables are configured via .env files in both frontend and supabase directories
For production deployment, ensure both .env files are properly configured
Deploying Edge Functions via CLI:
# Deploy a specific function
supabase functions deploy <function-name> --project-ref ztklqodcdjeqpsvhlpud
# Deploy multiple functions
supabase functions deploy api oauth-woocommerce oauth-shopify --project-ref ztklqodcdjeqpsvhlpud
Checking Deployment Status:
Use the MCP tool mcp__supabase__list_edge_functions to verify deployment status and version numbers.
Debugging 404/500 Errors:
mcp__supabase__list_edge_functionsmcp__supabase__get_logs(service: "edge-function")supabase/.envWhen making changes:
shopcall.ai-main/src/supabase/functions/<PrivateRoute> wrappersupabase/functions/IMPORTANT: After modifying any Supabase Edge Function code, you MUST redeploy the function to Supabase for the changes to take effect!
Steps to deploy Edge Functions:
Via MCP Tools (PREFERRED for Claude Code):
Use mcp__supabase__deploy_edge_function with:
- name: function name (e.g., "trigger-sync", "api", "oauth-shopify")
- files: array of files with name and content properties
Example:
mcp__supabase__deploy_edge_function(
name: "trigger-sync",
files: [{"name": "index.ts", "content": "..."}]
)
Benefits: No manual authentication, automatic project selection, works directly in Claude Code
Via CLI (alternative, requires manual authentication):
# Deploy a specific function
supabase functions deploy <function-name> --project-ref ztklqodcdjeqpsvhlpud
# Deploy multiple functions at once
supabase functions deploy oauth-woocommerce oauth-shopify api --project-ref ztklqodcdjeqpsvhlpud
Verify deployment:
mcp__supabase__list_edge_functionsmcp__supabase__get_logs(service: "edge-function")Common mistake: Forgetting to redeploy after code changes means the old version continues running in production!
Which functions to deploy:
oauth-woocommerce/index.ts), deploy that function_shared/woocommerce-client.ts), deploy ALL functions that import itstores tableFrontend uses TypeScript path alias:
@/ → ./src/Example: import { Button } from "@/components/ui/button"
The ShopRenter integration includes automated background sync capabilities using PostgreSQL's pg_cron extension.
How it works:
sync_logs tableSync Frequencies:
15min - Every 15 minutes (high-frequency updates)30min - Every 30 minuteshourly - Every hour (default, recommended)6hours - Every 6 hoursdaily - Once per dayConfiguration:
store_sync_config tableMonitoring:
sync_logs table tracks all sync executionssync_statistics view provides aggregated metricsSetup Requirements:
supabase/migrations/20250129_shoprenter_scheduled_sync.sqlsupabase functions deploy shoprenter-scheduled-syncINTERNAL_SYNC_SECRET in Edge Functions environmentsync_logs table for execution resultsManual Control:
-- Enable/disable sync for a store
SELECT set_store_sync_enabled('store-uuid', true);
-- Change sync frequency
SELECT set_store_sync_frequency('store-uuid', 'hourly');
-- View recent sync logs
SELECT * FROM sync_logs ORDER BY created_at DESC LIMIT 10;
-- View sync statistics
SELECT * FROM sync_statistics;
Security:
INTERNAL_SYNC_SECRET prevents unauthorized sync triggers