CLAUDE.md 30 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

ShopCall.ai is an AI-powered calling system integrated with e-commerce platforms. The project consists of:

  • shopcall.ai-main: React/Vite frontend application with TypeScript
  • supabase: Supabase Edge Functions for backend API

Repository Structure

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
│   │   ├── i18n/              # Internationalization (i18next)
│   │   ├── lib/               # Utility functions
│   │   └── App.tsx            # Main application with routing
│   └── package.json
└── supabase/                   # Supabase Edge Functions
    └── functions/              # Backend API functions
        └── _shared/           # Shared utilities across functions

Development Commands

Frontend (shopcall.ai-main)

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

Supabase Edge Functions

cd supabase

# Deploy Edge Functions
npx supabase functions deploy <function-name>

# Deploy with project ref
npx supabase functions deploy <function-name> --project-ref <project-ref>

# Test locally
npx supabase functions serve

# Login (if needed)
npx supabase login

# Link to project (if needed)
npx supabase link --project-ref <project-ref>

Technology Stack

Frontend

  • Framework: React 18 with Vite
  • Language: TypeScript
  • UI Library: shadcn-ui with Radix UI primitives
  • Styling: Tailwind CSS
  • Routing: React Router v6
  • State Management: React Query (@tanstack/react-query)
  • Form Handling: React Hook Form with Zod validation
  • Theme: next-themes for dark mode support
  • i18n: i18next with react-i18next for internationalization

Backend

  • Platform: Supabase Edge Functions (Deno)
  • Database: Supabase (PostgreSQL with auth)
  • Authentication: Supabase Auth

Architecture

Frontend Architecture

Authentication Flow:

  • AuthContext provider (src/components/context/AuthContext.tsx) manages global auth state
  • Token stored in localStorage as session_data
  • PrivateRoute component protects authenticated routes
  • Auth validation via Supabase client

Routing 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:

  • Page components in src/pages/ handle routing
  • Content components (e.g., DashboardContent.tsx) contain page logic
  • UI components in src/components/ui/ are reusable shadcn components
  • Context providers wrap the app in App.tsx

Internationalization (i18n):

  • Configuration: src/i18n/config.ts
  • Translations: src/i18n/locales/ (JSON files per language)
  • Uses i18next with react-i18next and browser language detection
  • Access translations via useTranslation() hook: const { t } = useTranslation()

Backend Architecture

Supabase Edge Functions: Backend logic implemented as serverless Edge Functions

Authentication:

  • Handled by Supabase Auth
  • User management and session handling via Supabase client

E-commerce Integrations:

  • Shopify integration (fully implemented)
    • OAuth flow: oauth-shopify (OAuth 2.0 with HMAC verification)
    • GDPR webhooks: webhooks-shopify (customers/data_request, customers/redact, shop/redact)
    • API client: _shared/shopify-client.ts
    • Data synchronization: shopify-sync (manual sync for products, orders, customers)
    • Scheduled background sync: shopify-scheduled-sync (automated via pg_cron) - NOT YET IMPLEMENTED
    • Read-only access with scopes: read_products, read_orders, read_customers, read_inventory, read_price_rules
    • Secure OAuth 2.0 with HMAC-SHA256 signature validation
    • Rate limiting (5 req/sec) and retry logic with exponential backoff
    • Automatic pagination support for all data types
    • Shopify App Store compliant - includes mandatory GDPR webhooks
    • API Version: Shopify Admin API 2024-01
  • WooCommerce integration (fully implemented)
    • Authentication: Manual API key connection (Consumer Key + Consumer Secret)
    • NO OAuth flow - Uses direct API key authentication with OAuth 1.0a signatures
    • Edge Function: oauth-woocommerce with action connect_manual
    • API client: _shared/woocommerce-client.ts
    • Data synchronization: woocommerce-sync (manual sync for products, orders, customers)
    • Scheduled background sync: woocommerce-scheduled-sync (automated via pg_cron, hourly)
    • API Version: WooCommerce REST API v3 (/wp-json/wc/v3/)
    • IMPORTANT: Uses latest WooCommerce REST API v3 (NOT legacy API)
    • Official documentation: https://woocommerce.github.io/woocommerce-rest-api-docs
    • Requires: WooCommerce 3.5+ and WordPress 4.4+
    • Legacy API versions (v1, v2, v3 at /wc-api/v*) are deprecated and NOT supported
    • Read-only access to products, orders, and customers
    • Secure OAuth 1.0a with HMAC-SHA256 signatures for API requests
    • Rate limiting (5 req/sec) and retry logic with exponential backoff
    • Pagination support for large datasets
    • Connection test validates credentials before storing
  • ShopRenter integration (fully implemented)
    • OAuth flow: oauth-shoprenter-init, oauth-shoprenter-callback
    • Uninstall webhook: webhook-shoprenter-uninstall
    • Data sync endpoints: shoprenter-products, shoprenter-orders, shoprenter-customers
    • Manual sync: shoprenter-sync
    • Scheduled background sync: shoprenter-scheduled-sync (automated via pg_cron, hourly)
    • API client: _shared/shoprenter-client.ts
    • Token refresh: Automatic access token refresh when expired
  • Store credentials in Supabase stores table

MCP Server Functions (Model Context Protocol):

  • mcp-shopify - MCP server for Shopify data access
  • mcp-woocommerce - MCP server for WooCommerce data access
  • mcp-shoprenter - MCP server for ShopRenter data access
  • Shared utilities in _shared/mcp-*.ts (types, helpers, SSE)

VAPI Integration (Voice AI):

  • vapi-webhook - Receives end-of-call reports from VAPI
  • Stores call transcripts, recordings, and analytics in call_logs table
  • See docs/VAPI_INTEGRATION.md for detailed documentation

Custom Content Management:

  • custom-content-create - Create new custom content entries
  • custom-content-upload - Upload files (PDF, documents)
  • custom-content-process - Process and vectorize content
  • custom-content-list - List user's custom content
  • custom-content-view - View content details
  • custom-content-delete - Delete content
  • custom-content-retry - Retry failed processing
  • custom-content-sync-status - Check processing status

AI Context & Vector Search:

  • get-ai-context - Build AI context from store data and custom content
  • Uses Qdrant for vector storage (_shared/qdrant-client.ts)
  • Text chunking and embedding (_shared/text-chunker.ts)
  • PDF processing (_shared/pdf-processor.ts)

Shared Utilities (supabase/functions/_shared/):

  • cors.ts - CORS headers handling
  • error-handler.ts - Standardized error responses
  • unified-response.ts - Consistent API response format
  • api-key-auth.ts - API key authentication
  • platform-adapters.ts - E-commerce platform data normalization
  • access-policy-helpers.ts - GDPR data access policy enforcement

Database Schema (Supabase)

stores table:

- id: UUID (primary key)
- user_id: UUID (FK to profiles.id)
- platform_name: text (e.g., 'shopify', 'woocommerce', 'shoprenter')
- store_name: text
- store_url: text
- api_key: text (Consumer Key for WooCommerce, Access Token for ShopRenter/Shopify)
- api_secret: text (Consumer Secret for WooCommerce, Refresh Token for ShopRenter)
- access_token: text (for platforms using separate access_token field)
- refresh_token: text (for platforms using separate refresh_token field)
- token_expires_at: timestamp (token expiration time)
- scopes: text[]
- alt_data: jsonb (platform-specific data, e.g., expires_at, last_sync_at, wcVersion, wpVersion)
- connected_at: timestamp (when store was connected)
- is_active: boolean (default: true)
- phone_number: text
- package: text
- sync_status: text ('idle', 'syncing', 'completed', 'error')
- sync_started_at: timestamptz (when current/last sync started)
- sync_completed_at: timestamptz (when last sync completed)
- sync_error: text (error message from last failed sync)
- created_at: timestamp
- updated_at: timestamp

oauth_states table (for OAuth flow state management):

- id: UUID (primary key)
- state: text (UUID for CSRF protection, unique)
- user_id: UUID (FK to auth.users, nullable)
- platform: text (e.g., 'shopify', 'woocommerce', 'shoprenter')
- shopname: text (nullable)
- expires_at: timestamptz
- created_at: timestamptz

pending_shoprenter_installs table (temporary storage during OAuth):

- id: UUID (primary key)
- installation_id: text (UUID, unique)
- shopname: text
- access_token: text
- refresh_token: text (nullable)
- token_type: text (nullable, default: 'Bearer')
- expires_in: integer (nullable)
- scopes: text[] (nullable)
- expires_at: timestamptz
- created_at: timestamptz

oauth_nonces table (stores OAuth nonce values for OAuth flows):

- id: UUID (primary key)
- nonce: text (unique)
- user_id: UUID (FK to auth.users, nullable)
- platform: text
- shop: text (nullable)
- app_url: text (nullable)
- shopname: text (nullable)
- created_at: timestamptz
- expires_at: timestamptz

pending_signups table (stores pending signup data with OTP for email verification):

- id: UUID (primary key)
- signup_id: text (unique)
- email: text
- password: text
- full_name: text
- company_name: text
- user_name: text
- otp: text
- created_at: timestamptz
- expires_at: timestamptz (expires after 15 minutes)

profiles table (user profile information):

- id: UUID (primary key, FK to auth.users)
- full_name: text (nullable)
- username: text (nullable, unique)
- email: text (nullable)
- company_name: text (nullable)
- is_verified: boolean (nullable)
- created_at: timestamp (default: now())
- updated_at: timestamp (default: now())

shoprenter_products_cache table (cached product data):

- id: UUID (primary key)
- store_id: UUID (FK to stores)
- shoprenter_product_id: varchar
- product_data: jsonb
- last_synced_at: timestamptz
- created_at: timestamptz
- updated_at: timestamptz

shoprenter_tokens table (ShopRenter token management):

- id: UUID (primary key)
- store_id: UUID (FK to stores)
- access_token: text
- refresh_token: text (nullable)
- expires_at: timestamptz (nullable)
- scopes: text[] (nullable)
- shopname: varchar
- shop_domain: varchar
- is_active: boolean (default: true)
- last_sync_at: timestamptz (nullable)
- created_at: timestamptz
- updated_at: timestamptz

shoprenter_webhooks table (webhook registrations):

- id: UUID (primary key)
- store_id: UUID (FK to stores)
- webhook_id: varchar
- topic: varchar
- webhook_url: text
- is_active: boolean (default: true)
- created_at: timestamptz
- updated_at: timestamptz

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 (default: true)
- last_received_at: timestamptz (nullable)
- total_received: integer (default: 0)
- created_at: timestamptz
- updated_at: timestamptz
- UNIQUE(store_id, shopify_webhook_id)

system_config table (system-wide configuration):

- key: text (primary key)
- value: text
- description: text (nullable)
- created_at: timestamptz
- updated_at: timestamptz

call_logs table (call history and analytics):

- id: UUID (primary key)
- user_id: UUID (FK to auth.users, nullable)
- contact_id: UUID (nullable)
- workspace_id: UUID
- status: call_status_enum (pending, scheduled, in_progress, completed, failed, cancelled)
- attempt_number: integer
- scheduled_at: timestamptz (nullable)
- started_at: timestamptz (nullable)
- ended_at: timestamptz (nullable)
- duration_seconds: integer (nullable)
- transcript: text (nullable)
- summary: text (nullable)
- call_outcome: call_outcome_enum (pending, resolved, interested, potential, not_interested, no_answer, voicemail, busy, callback_requested, false)
- assistant_id: text (nullable)
- assistant_name: text (nullable)
- callprovider_id: text (nullable)
- phone_number_id: text (nullable)
- customer_number: text (nullable)
- assistant_phone_number: text (nullable)
- call_type: call_type_enum (inbound, outbound, inbound_dummy)
- cost_stt: numeric (nullable)
- cost_llm: numeric (nullable)
- cost_tts: numeric (nullable)
- cost_total: numeric (nullable)
- cost_twilio: numeric (nullable)
- cost_totals: numeric (nullable)
- ended_reason: text (nullable)
- recording_url: text (nullable)
- created_at: timestamptz
- updated_at: timestamptz

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)
- products_access_policy: data_access_policy enum ('sync', 'api_only', 'not_allowed') - GDPR-compliant access control
- customers_access_policy: data_access_policy enum ('sync', 'api_only', 'not_allowed') - GDPR-compliant access control
- orders_access_policy: data_access_policy enum ('sync', 'api_only', 'not_allowed') - GDPR-compliant access control
- created_at: timestamptz
- updated_at: timestamptz

Environment Configuration

Quick Setup

  1. Frontend: Copy shopcall.ai-main/.env.example to .env and fill in your values
  2. Backend: Copy supabase/.env.example to .env and fill in your values
  3. Database: Configure pg_cron settings in Supabase Dashboard (see below)

Frontend .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

# GDPR Compliance Settings (optional)
# Hide data access policy settings from store owners for stricter GDPR compliance
# When set to 'true', the corresponding settings will be hidden in the UI
VITE_HIDE_ORDERS_ACCESS_SETTINGS=true    # Hide orders access policy settings
VITE_HIDE_CUSTOMERS_ACCESS_SETTINGS=true # Hide customers access policy settings

Note: VITE_API_URL is derived from VITE_SUPABASE_URL by appending /functions/v1

GDPR Settings: When VITE_HIDE_ORDERS_ACCESS_SETTINGS and VITE_HIDE_CUSTOMERS_ACCESS_SETTINGS are set to true, store owners won't see these settings in the UI, and new stores will default to api_only mode (direct API access, no local caching of PII).

Supabase Edge Functions .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

Supabase Database Settings (for pg_cron)

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:

  • pg_cron jobs will run successfully but silently fail
  • No sync will actually happen (appears "stuck")
  • No error logs will be visible

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.

Deployment

Frontend

  • Build: npm run build generates static files in dist/
  • Deployment: Can be deployed to any static hosting service (Netlify, Vercel, GitHub Pages, etc.)
  • SPA routing handled by React Router

Supabase Edge Functions

  • Deployment: Use supabase functions deploy command
  • Edge Functions are deployed to Supabase infrastructure
  • Automatically scaled and managed by Supabase

Using Supabase MCP Tools (Recommended for Claude)

IMPORTANT: 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.

Available MCP Tools

Edge Functions Management:

  • mcp__supabase__list_edge_functions - List all deployed Edge Functions
  • mcp__supabase__deploy_edge_function - Deploy an Edge Function (with files array)
  • mcp__supabase__get_edge_function - Get Edge Function code

Database Operations:

  • mcp__supabase__list_tables - List database tables
  • mcp__supabase__list_extensions - List database extensions
  • mcp__supabase__list_migrations - List all migrations
  • mcp__supabase__apply_migration - Apply a new migration (DDL operations)
  • mcp__supabase__execute_sql - Execute raw SQL queries

Project Information:

  • mcp__supabase__get_project_url - Get the project API URL
  • mcp__supabase__get_anon_key - Get the anonymous API key
  • mcp__supabase__generate_typescript_types - Generate TypeScript types from database

Monitoring & Debugging:

  • mcp__supabase__get_logs - Get logs for Edge Functions or other services
  • mcp__supabase__get_advisors - Check for security/performance issues

Branching (Development):

  • mcp__supabase__create_branch - Create a development branch
  • mcp__supabase__list_branches - List all branches
  • mcp__supabase__merge_branch - Merge branch to production
  • mcp__supabase__delete_branch - Delete a development branch

Best Practices

  1. Always use MCP tools for Supabase operations in Claude Code
  2. Check Edge Function logs when debugging deployment issues:

    mcp__supabase__get_logs(service: "edge-function")
    
  3. Monitor deployments by listing Edge Functions after deployment

  4. Environment variables are configured via .env files in both frontend and supabase directories

  5. For production deployment, ensure both .env files are properly configured

Common Workflows

Deploying Edge Functions via CLI:

cd supabase

# Deploy a specific function
npx supabase functions deploy <function-name> --project-ref <project-ref>

# Deploy multiple functions
npx supabase functions deploy api oauth-woocommerce oauth-shopify --project-ref <project-ref>

Checking Deployment Status: Use the MCP tool mcp__supabase__list_edge_functions to verify deployment status and version numbers.

Debugging 404/500 Errors:

  1. Check if Edge Function is deployed using mcp__supabase__list_edge_functions
  2. Review logs using mcp__supabase__get_logs(service: "edge-function")
  3. Verify environment variables are set in supabase/.env
  4. Redeploy the function if needed

Development Workflow

When making changes:

  1. Frontend Changes: Work in shopcall.ai-main/src/
  2. Backend Changes: Modify Supabase Edge Functions in supabase/functions/
  3. Auth Flow Changes: Update AuthContext and Supabase Auth configuration
  4. New Protected Routes: Add to App.tsx inside <PrivateRoute> wrapper
  5. New API Endpoints: Create new Edge Functions in supabase/functions/

⚠️ Critical: Deploying Edge Function Changes

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:

  1. 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

  1. Via CLI (alternative, requires manual authentication):

    cd supabase
    
    # Deploy a specific function
    npx supabase functions deploy <function-name> --project-ref <project-ref>
    
    # Deploy multiple functions at once
    npx supabase functions deploy oauth-woocommerce oauth-shopify api --project-ref <project-ref>
    
  2. Verify deployment:

    • Check version number increased using mcp__supabase__list_edge_functions
    • Review logs using mcp__supabase__get_logs(service: "edge-function")
    • Test the endpoint to ensure changes are live

Common mistake: Forgetting to redeploy after code changes means the old version continues running in production!

Which functions to deploy:

  • If you modified a function file directly (e.g., oauth-woocommerce/index.ts), deploy that function
  • If you modified a shared file (e.g., _shared/woocommerce-client.ts), deploy ALL functions that import it
  • When in doubt, check which functions import the modified file and deploy all of them

Important Notes

  • Backend is implemented as Supabase Edge Functions (serverless)
  • Supabase handles user authentication, data storage, and API endpoints
  • Frontend is a static React application that can be hosted anywhere
  • All API calls go through Supabase Edge Functions
  • OAuth flows store credentials in Supabase stores table

Path Aliases

Frontend uses TypeScript path alias:

  • @/./src/

Example: import { Button } from "@/components/ui/button"

Background Sync & Scheduling

Automated Synchronization for E-commerce Platforms

The project includes automated background sync capabilities for ShopRenter and WooCommerce using PostgreSQL's pg_cron extension. Shopify scheduled sync is prepared in the migration but not yet implemented.

How it works:

  1. pg_cron schedules database jobs at specified intervals
  2. pg_net makes HTTP requests from the database to Edge Functions
  3. Platform-specific scheduled-sync Edge Functions process all active stores
  4. Sync results are logged to sync_logs table

Implemented Scheduled Syncs:

  • ShopRenter: shoprenter-scheduled-sync (runs hourly at minute 0)
  • WooCommerce: woocommerce-scheduled-sync (runs hourly at minute 5)
  • Shopify: Migration prepared, Edge Function not yet deployed

Sync Frequencies (configurable per store in store_sync_config):

  • 15min - Every 15 minutes (high-frequency updates)
  • 30min - Every 30 minutes
  • hourly - Every hour (default, recommended)
  • 6hours - Every 6 hours
  • daily - Once per day

Configuration:

  • Per-store sync frequency via store_sync_config table
  • Enable/disable sync per store
  • Choose what to sync (products, orders, customers)
  • Automatic next sync calculation
  • Default sync config auto-created when connecting new stores

Monitoring:

  • sync_logs table tracks all sync executions
  • Logs include per-store success/failure status
  • Sync duration and item counts tracked
  • Stores table has sync_status, sync_started_at, sync_completed_at, sync_error fields

Setup Requirements:

  1. Run migrations:
    • supabase/migrations/20250129_shoprenter_scheduled_sync.sql
    • supabase/migrations/20251030_woocommerce_scheduled_sync.sql
    • supabase/migrations/20251030_shopify_integration.sql
  2. Deploy Edge Functions:
    • supabase functions deploy shoprenter-scheduled-sync
    • supabase functions deploy woocommerce-scheduled-sync
    • supabase functions deploy shopify-scheduled-sync (when implemented)
  3. Configure INTERNAL_SYNC_SECRET in Edge Functions environment
  4. Configure database settings in Supabase Dashboard (see Environment Configuration section)
  5. Monitor sync_logs table for execution results

Manual 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 (if view exists)
SELECT * FROM sync_statistics;

-- Check current pg_cron jobs
SELECT * FROM cron.job;

Security:

  • INTERNAL_SYNC_SECRET prevents unauthorized sync triggers
  • Only internal pg_cron jobs can trigger scheduled sync
  • Row-level security ensures users only see their own sync logs

Trigger Functions:

  • trigger_shoprenter_scheduled_sync() - Triggers ShopRenter sync
  • trigger_woocommerce_scheduled_sync() - Triggers WooCommerce sync
  • trigger_shopify_scheduled_sync() - Triggers Shopify sync (when implemented)