# 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

```
/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
```

## Development Commands

### Frontend (shopcall.ai-main)
```bash
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

**Supabase CLI Location**: `~/bin/supabase` (run from `/home/claude/shopcall/supabase` directory)

```bash
cd /home/claude/shopcall/supabase

# Deploy Edge Functions
~/bin/supabase functions deploy <function-name>

# Deploy with project ref
~/bin/supabase functions deploy <function-name> --project-ref ztklqodcdjeqpsvhlpud

# Test locally
~/bin/supabase functions serve

# Login (if needed)
~/bin/supabase login

# Link to project (if needed)
~/bin/supabase link --project-ref ztklqodcdjeqpsvhlpud
```

## 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

### 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`

### 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

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

```bash
# 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:

```bash
# 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**:
```sql
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:**
```bash
cd /home/claude/shopcall/supabase

# Deploy a specific function
~/bin/supabase functions deploy <function-name> --project-ref ztklqodcdjeqpsvhlpud

# Deploy multiple functions
~/bin/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:**
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

2. **Via CLI** (alternative, requires manual authentication):
   ```bash
   cd /home/claude/shopcall/supabase

   # Deploy a specific function
   ~/bin/supabase functions deploy <function-name> --project-ref ztklqodcdjeqpsvhlpud

   # Deploy multiple functions at once
   ~/bin/supabase functions deploy oauth-woocommerce oauth-shopify api --project-ref ztklqodcdjeqpsvhlpud
   ```

3. **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**:
```sql
-- 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)
