From bd3841b716bb8db3f5f21dbd51357401ebe4f357 Mon Sep 17 00:00:00 2001 From: dwindown Date: Fri, 2 Jan 2026 15:19:41 +0700 Subject: [PATCH] Add master template wrapper to OTP emails - Add EmailTemplateRenderer class to send-auth-otp edge function - Wrap OTP email content in master template with brutalist design - Email now includes proper header, footer, and styling - No changes needed to checkout flow (uses auth page for registration) Benefits: - Professional branded emails with ACCESS HUB header - Consistent brutalist design across all emails - Responsive layout - Better email client compatibility --- DEPLOY-OTP-FIX.md | 156 +++++++++++++ supabase/functions/send-auth-otp/index.ts | 267 +++++++++++++++++++++- 2 files changed, 420 insertions(+), 3 deletions(-) create mode 100644 DEPLOY-OTP-FIX.md 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}} + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + `; + + 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