diff --git a/DEPLOY-OTP-FIX.md b/DEPLOY-OTP-FIX.md
new file mode 100644
index 0000000..302912f
--- /dev/null
+++ b/DEPLOY-OTP-FIX.md
@@ -0,0 +1,156 @@
+# Deploy OTP Email Fix
+
+## Problem
+The `send-auth-otp` edge function was trying to insert into `notification_logs` table which doesn't exist, causing the function to crash AFTER sending the email. This meant:
+- ✅ Email was sent by Mailketing API
+- ❌ Function crashed before returning success
+- ❌ Frontend might have shown error
+
+## Solution
+Removed all references to `notification_logs` table from the edge function.
+
+## Deployment Steps
+
+### 1. SSH into your server
+```bash
+ssh root@lovable.backoffice.biz.id
+```
+
+### 2. Navigate to the project directory
+```bash
+cd /path/to/your/project
+```
+
+### 3. Pull the latest changes
+```bash
+git pull origin main
+```
+
+### 4. Deploy the edge function
+```bash
+# Option A: If using Supabase CLI
+supabase functions deploy send-auth-otp
+
+# Option B: If manually copying files
+cp supabase/functions/send-auth-otp/index.ts /path/to/supabase/functions/send-auth-otp/index.ts
+
+# Then restart the edge function container
+docker-compose restart edge-functions
+# or
+docker restart $(docker ps -q --filter 'name=supabase_edge_runtime')
+```
+
+### 5. Verify deployment
+```bash
+# Check if function is loaded
+supabase functions list
+
+# Should show:
+# send-auth-otp ...
+# verify-auth-otp ...
+# send-email-v2 ...
+```
+
+### 6. Test the fix
+```bash
+# Test with curl
+curl -X POST https://lovable.backoffice.biz.id/functions/v1/send-auth-otp \
+ -H "Authorization: Bearer YOUR_SERVICE_ROLE_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{"user_id":"TEST_USER_ID","email":"test@example.com"}'
+
+# Expected response:
+# {"success":true,"message":"OTP sent successfully"}
+```
+
+### 7. Test full registration flow
+1. Open browser to https://with.dwindi.com/auth
+2. Register with new email
+3. Check email inbox
+4. Should receive OTP code
+
+## What Changed
+
+### File: `supabase/functions/send-auth-otp/index.ts`
+
+**Before:**
+```typescript
+// Log notification
+await supabase
+ .from('notification_logs')
+ .insert({
+ user_id,
+ email: email,
+ notification_type: 'auth_email_verification',
+ status: 'sent',
+ provider: 'mailketing',
+ error_message: null,
+ });
+```
+
+**After:**
+```typescript
+// Note: notification_logs table doesn't exist, skipping logging
+```
+
+## Troubleshooting
+
+### If email still not received:
+
+1. **Check edge function logs:**
+ ```bash
+ docker logs $(docker ps -q --filter 'name=supabase_edge_runtime') | tail -50
+ ```
+
+2. **Check if OTP was created:**
+ ```sql
+ SELECT * FROM auth_otps ORDER BY created_at DESC LIMIT 1;
+ ```
+
+3. **Check notification settings:**
+ ```sql
+ SELECT platform_name, from_name, from_email, api_token
+ FROM notification_settings
+ LIMIT 1;
+ ```
+
+4. **Verify email template:**
+ ```sql
+ SELECT key, name, is_active, LENGTH(email_body_html) as html_length
+ FROM notification_templates
+ WHERE key = 'auth_email_verification';
+ ```
+
+5. **Test email sending directly:**
+ ```bash
+ curl -X POST https://lovable.backoffice.biz.id/functions/v1/send-email-v2 \
+ -H "Authorization: Bearer YOUR_SERVICE_ROLE_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "to": "your@email.com",
+ "api_token": "YOUR_MAILKETING_TOKEN",
+ "from_name": "Test",
+ "from_email": "test@with.dwindi.com",
+ "subject": "Test Email",
+ "html_body": "
Test
"
+ }'
+ ```
+
+## Success Criteria
+
+✅ Edge function returns `{"success":true}`
+✅ No crashes in edge function logs
+✅ OTP created in database
+✅ Email received with OTP code
+✅ OTP verification works
+✅ User can login after verification
+
+## Next Steps
+
+After successful deployment:
+1. Test registration with multiple email addresses
+2. Test OTP verification flow
+3. Test login after verification
+4. Test "resend OTP" functionality
+5. Test expired OTP (wait 15 minutes)
+6. Test wrong OTP code
diff --git a/supabase/functions/send-auth-otp/index.ts b/supabase/functions/send-auth-otp/index.ts
index 0d43510..befec5c 100644
--- a/supabase/functions/send-auth-otp/index.ts
+++ b/supabase/functions/send-auth-otp/index.ts
@@ -11,6 +11,260 @@ interface SendOTPRequest {
email: string;
}
+// Email Template Renderer (Master Template)
+interface EmailTemplateData {
+ subject: string;
+ content: string;
+ brandName?: string;
+ brandLogo?: string;
+}
+
+class EmailTemplateRenderer {
+ private static readonly MASTER_TEMPLATE = `
+
+
+
+
+
+ {{subject}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+ {{brandName}}
+
+ |
+
+
+ NOTIF #{{timestamp}}
+
+ |
+
+
+ |
+
+
+
+ |
+
+ {{content}}
+
+ |
+
+
+
+ |
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ `;
+
+ static render(data: EmailTemplateData): string {
+ let html = this.MASTER_TEMPLATE;
+
+ html = html.replace(/{{subject}}/g, data.subject || 'Notification');
+ html = html.replace(/{{brandName}}/g, data.brandName || 'ACCESS HUB');
+ html = html.replace(/{{brandLogo}}/g, data.brandLogo || '');
+ html = html.replace(/{{timestamp}}/g, Date.now().toString().slice(-6));
+ html = html.replace(/{{content}}/g, data.content);
+
+ return html;
+ }
+}
+
// Generate 6-digit OTP code
function generateOTP(): string {
return Math.floor(100000 + Math.random() * 900000).toString();
@@ -124,10 +378,17 @@ serve(async (req: Request) => {
subject = subject.replace(new RegExp(`{${key}}`, 'g'), value);
});
- // Process shortcodes in HTML body
- let htmlBody = template.email_body_html;
+ // Process shortcodes in HTML body content
+ let htmlContent = template.email_body_html;
Object.entries(templateVars).forEach(([key, value]) => {
- htmlBody = htmlBody.replace(new RegExp(`{${key}}`, 'g'), value);
+ htmlContent = htmlContent.replace(new RegExp(`{${key}}`, 'g'), value);
+ });
+
+ // Wrap in master template
+ const htmlBody = EmailTemplateRenderer.render({
+ subject: subject,
+ content: htmlContent,
+ brandName: settings.platform_name || 'ACCESS HUB',
});
// Send email via send-email-v2