This guide explains how to deploy ShopCall.ai with static hosting and Supabase Edge Functions.
The database migrations have already been applied. The following tables were created:
Stores temporary signup data with OTP for email verification (15-minute expiration).
Stores OAuth state/nonce values for secure OAuth flows (10-minute expiration).
Stores e-commerce platform credentials and configuration.
auth - /functions/v1/auth/*
/auth/signup - Create new user account with OTP/auth/signup/verify - Verify OTP and complete registration/auth/signup/resend-otp - Resend OTP email/auth/login - Email/password login/auth/logout - Sign out/auth/check - Validate session tokenshopify-oauth - /functions/v1/shopify-oauth/*
/shopify-oauth/init - Initialize Shopify OAuth flow/shopify-oauth/callback - Handle Shopify OAuth callbackwoocommerce-oauth - /functions/v1/woocommerce-oauth/*
/woocommerce-oauth/init - Initialize WooCommerce OAuth flow/woocommerce-oauth/callback - Handle WooCommerce callbackshoprenter-oauth - /functions/v1/oauth-shoprenter-*
/oauth-shoprenter-init - Initialize ShopRenter OAuth flow/oauth-shoprenter-callback - Handle ShopRenter OAuth callbackshoprenter-webhooks - /functions/v1/webhook-shoprenter-*
/webhook-shoprenter-uninstall - Handle ShopRenter app uninstallshoprenter-api - /functions/v1/shoprenter-*
/shoprenter-products/:storeId - Fetch products from ShopRenter/shoprenter-orders/:storeId - Fetch orders from ShopRenter/shoprenter-customers/:storeId - Fetch customers from ShopRenter/shoprenter-sync/:storeId - Trigger manual data synchronizationshoprenter-scheduled-sync - /functions/v1/shoprenter-scheduled-sync
INTERNAL_SYNC_SECRET header for authenticationgdpr-webhooks - /functions/v1/gdpr-webhooks/*
/gdpr-webhooks/customers-data-request - Handle customer data requests/gdpr-webhooks/customers-redact - Handle customer data redaction/gdpr-webhooks/shop-redact - Handle shop data redactionConfigure these in your Supabase project settings:
# Supabase (automatically available)
SUPABASE_URL=https://YOUR_PROJECT.supabase.co
SUPABASE_ANON_KEY=your_anon_key
# Email Service (Resend)
RESEND_API_KEY=re_YOUR_API_KEY
# Shopify Integration
SHOPIFY_API_KEY=your_shopify_api_key
SHOPIFY_API_SECRET=your_shopify_api_secret
SHOPIFY_REDIRECT_URI=https://YOUR_PROJECT.supabase.co/functions/v1/shopify-oauth/callback
# ShopRenter Integration
SHOPRENTER_CLIENT_ID=your_shoprenter_client_id
SHOPRENTER_CLIENT_SECRET=your_shoprenter_client_secret
# Scheduled Sync Security
INTERNAL_SYNC_SECRET=generate_random_secure_secret_here
# Frontend URL (for OAuth redirects)
FRONTEND_URL=https://yourdomain.com
# Edge Function Base URL
EDGE_FUNCTION_BASE_URL=https://YOUR_PROJECT.supabase.co/functions/v1
# Service Role Key (for admin operations)
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key
Create or update .env file in shopcall.ai-main/:
# Supabase Configuration
VITE_SUPABASE_URL=https://YOUR_PROJECT.supabase.co
VITE_SUPABASE_ANON_KEY=your_anon_key
# Backend API Base URL (Supabase Edge Functions)
VITE_API_URL=https://YOUR_PROJECT.supabase.co/functions/v1
# Frontend URL (for OAuth callbacks)
VITE_FRONTEND_URL=https://yourdomain.com
cd shopcall.ai-main
npm install
npm run build
This creates a dist/ directory with your static files.
dist/ to your web server (e.g., /var/www/html/)Create .htaccess file in the root directory for SPA routing:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
Enable mod_rewrite:
sudo a2enmod rewrite
sudo systemctl restart apache2
dist/ to your web server (e.g., /var/www/shopcall.ai/)Configure nginx:
server {
listen 80;
server_name yourdomain.com;
root /var/www/shopcall.ai;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
Test and reload:
sudo nginx -t
sudo systemctl reload nginx
cd shopcall.ai-main && npm run buildshopcall.ai-main/distAdd the API key to your Supabase Edge Function secrets:
supabase secrets set RESEND_API_KEY=your_api_key
Verify your sending domain in Resend (recommended for production)
https://yourdomain.comhttps://YOUR_PROJECT.supabase.co/functions/v1/shopify-oauth/callbackhttps://YOUR_PROJECT.supabase.co/functions/v1/gdpr-webhooks/customers-data-requesthttps://YOUR_PROJECT.supabase.co/functions/v1/gdpr-webhooks/customers-redacthttps://YOUR_PROJECT.supabase.co/functions/v1/gdpr-webhooks/shop-redactNo special configuration needed. The OAuth flow is initiated from the dashboard.
Register your app with ShopRenter by emailing partnersupport@shoprenter.hu with:
https://yourdomain.com/integrationshttps://YOUR_PROJECT.supabase.co/functions/v1/oauth-shoprenter-callbackhttps://YOUR_PROJECT.supabase.co/functions/v1/webhook-shoprenter-uninstallproduct:read, product:write, customer:read, customer:write, order:read, order:write, category:read, webhook:read, webhook:writesr_install parameter.Once approved, you'll receive:
SHOPRENTER_CLIENT_ID)SHOPRENTER_CLIENT_SECRET)Test your integration with a ShopRenter test store (request at https://www.shoprenter.hu/tesztigenyles/?devstore=1)
The ShopRenter integration includes automated background synchronization using PostgreSQL's pg_cron extension.
Execute the scheduled sync migration in your Supabase SQL Editor:
# Option A: Via Supabase CLI
supabase db push
# Option B: Via Supabase Dashboard
# 1. Go to SQL Editor in Supabase Dashboard
# 2. Create a new query
# 3. Copy contents of supabase/migrations/20250129_shoprenter_scheduled_sync.sql
# 4. Run the query
This migration will:
pg_cron and pg_net extensionssync_logs table for tracking sync executionsstore_sync_config table for per-store configurationIn Supabase Dashboard, configure the required settings for pg_cron to call Edge Functions:
Add the following settings:
app.internal_sync_secret = <SAME_VALUE_AS_INTERNAL_SYNC_SECRET_ABOVE>
app.supabase_url = https://YOUR_PROJECT.supabase.co
Generate INTERNAL_SYNC_SECRET:
# Generate a secure random secret (32 characters)
openssl rand -hex 32
Deploy the scheduled sync Edge Function to Supabase:
supabase functions deploy shoprenter-scheduled-sync
Check that the pg_cron job is scheduled:
-- Run in Supabase SQL Editor
SELECT * FROM cron.job WHERE jobname = 'shoprenter-hourly-sync';
You should see output like:
jobid | schedule | command | nodename | jobname
------+-------------+---------------------------------------------+-----------+-------------------------
1 | 0 * * * * | SELECT trigger_shoprenter_scheduled_sync(); | localhost | shoprenter-hourly-sync
After the scheduled job runs (at the top of each hour), check the logs:
-- View recent sync logs
SELECT
id,
sync_type,
platform,
stores_processed,
started_at,
completed_at,
EXTRACT(EPOCH FROM (completed_at - started_at)) as duration_seconds
FROM sync_logs
ORDER BY created_at DESC
LIMIT 10;
-- View sync statistics
SELECT * FROM sync_statistics
ORDER BY sync_date DESC, platform
LIMIT 20;
By default, all ShopRenter stores are configured to sync hourly. You can customize:
-- Disable sync for a specific store
SELECT set_store_sync_enabled('store-uuid-here', false);
-- Change sync frequency (options: '15min', '30min', 'hourly', '6hours', 'daily')
SELECT set_store_sync_frequency('store-uuid-here', '6hours');
-- View all store sync configurations
SELECT
ssc.store_id,
s.store_name,
ssc.enabled,
ssc.sync_frequency,
ssc.last_sync_at,
ssc.next_sync_at,
ssc.sync_products,
ssc.sync_orders,
ssc.sync_customers
FROM store_sync_config ssc
JOIN stores s ON s.id = ssc.store_id
WHERE s.platform_name = 'shoprenter';
| Frequency | Cron Schedule | Use Case |
|---|---|---|
15min |
Every 15 minutes | High-frequency stores (limited by API rate limits) |
30min |
Every 30 minutes | Active stores with frequent updates |
hourly |
Every hour | Default - Balanced for most stores |
6hours |
Every 6 hours | Low-traffic stores |
daily |
Once per day | Archive/backup stores |
Job not running:
-- Check if pg_cron extension is enabled
SELECT * FROM pg_extension WHERE extname = 'pg_cron';
-- Check job status
SELECT * FROM cron.job_run_details
WHERE jobid = (SELECT jobid FROM cron.job WHERE jobname = 'shoprenter-hourly-sync')
ORDER BY start_time DESC
LIMIT 10;
Edge Function not being called:
app.internal_sync_secret and app.supabase_url are set in database settingsshoprenter-scheduled-sync Edge Function is deployedSync failing for specific stores:
-- Check sync results for a specific store
SELECT
results->>'store_id' as store_id,
results->>'store_name' as store_name,
results->>'status' as status,
results->>'error_message' as error_message,
results->'products' as products_stats,
results->'orders' as orders_stats,
results->'customers' as customers_stats
FROM sync_logs, jsonb_array_elements(results) as results
WHERE platform = 'shoprenter'
AND results->>'store_id' = 'your-store-uuid'
ORDER BY created_at DESC
LIMIT 5;
Manual trigger for testing:
# Manually trigger scheduled sync (for testing)
curl -X POST https://YOUR_PROJECT.supabase.co/functions/v1/shoprenter-scheduled-sync \
-H "x-internal-secret: YOUR_INTERNAL_SYNC_SECRET" \
-H "Content-Type: application/json"
INTERNAL_SYNC_SECRET is required to prevent unauthorized sync triggers# Test signup
curl -X POST https://YOUR_PROJECT.supabase.co/functions/v1/auth/signup \
-H "Content-Type: application/json" \
-d '{
"email": "test@example.com",
"password": "testpass123",
"full_name": "Test User",
"company_name": "Test Company",
"user_name": "testuser"
}'
# Test login
curl -X POST https://YOUR_PROJECT.supabase.co/functions/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "test@example.com",
"password": "testpass123"
}'
/dashboard, /call-logs)Issue: 404 errors on routes when refreshing
.htaccess (Apache) or nginx configuration is properly set up for client-side routingIssue: CORS errors when calling Edge Functions
corsHeaders in each function)Issue: Email not sending
Issue: OAuth callback fails
delete_expired_pending_signups()delete_expired_oauth_nonces().env files to version controlFor issues or questions: