# Unified Email Template System ## Overview All emails now use a **single master template** for consistent branding and design. The master template wraps content-only HTML from database templates. ## Architecture ``` Database Template (content only) ↓ Process Shortcodes ({nama}, {platform_name}, etc.) ↓ EmailTemplateRenderer.render() - wraps with master template ↓ Complete HTML Email sent via provider ``` ## Master Template **Location:** `supabase/shared/email-template-renderer.ts` **Features:** - Brutalist design (black borders, hard shadows) - Responsive layout (600px max width) - `.tiptap-content` wrapper for auto-styling - Header with brand name + notification ID - Footer with unsubscribe links - All CSS included (no external dependencies) **CSS Classes for Content:** - `.tiptap-content h1, h2, h3` - Headings - `.tiptap-content p` - Paragraphs - `.tiptap-content a` - Links (underlined, bold) - `.tiptap-content ul, ol` - Lists - `.tiptap-content table` - Tables with brutalist borders - `.btn` - Buttons with hard shadow - `.otp-box` - OTP codes with dashed border - `.alert-success, .alert-danger, .alert-info` - Colored alert boxes ## Database Templates ### Format **CORRECT** (content-only): ```html

Payment Successful!

Hello {nama}, your payment has been confirmed.

Parameter Value
Order ID {order_id}
``` **WRONG** (full HTML): ```html ...

Payment Successful!

... ``` ### Why Content-Only? The master template provides: - Email client compatibility (resets, Outlook fixes) - Consistent header/footer - Responsive wrapper - Brutalist styling Your content just needs the **body HTML** - no ``, ``, or `` tags. ## Usage in Edge Functions ### Auth OTP (`send-auth-otp`) ```typescript import { EmailTemplateRenderer } from "../shared/email-template-renderer.ts"; // Fetch template from database const template = await supabase .from("notification_templates") .select("*") .eq("key", "auth_email_verification") .single(); // Process shortcodes let htmlContent = template.email_body_html; Object.entries(templateVars).forEach(([key, value]) => { htmlContent = htmlContent.replace(new RegExp(`{${key}}`, 'g'), value); }); // Wrap with master template const htmlBody = EmailTemplateRenderer.render({ subject: template.email_subject, content: htmlContent, brandName: settings.platform_name || 'ACCESS HUB', }); // Send via send-email-v2 await fetch(`${supabaseUrl}/functions/v1/send-email-v2`, { method: 'POST', body: JSON.stringify({ to: email, html_body: htmlBody, // ... other fields }), }); ``` ### Other Notifications (`send-notification`) ```typescript import { EmailTemplateRenderer } from "../shared/email-template-renderer.ts"; // Fetch template and process shortcodes const htmlContent = replaceVariables(template.body_html || template.body_text, allVariables); // Wrap with master template const htmlBody = EmailTemplateRenderer.render({ subject: subject, content: htmlContent, brandName: settings.brand_name || "ACCESS HUB", }); // Send via provider (SMTP, Resend, etc.) await sendViaSMTP({ html: htmlBody, ... }); ``` ## Available Shortcodes See `ShortcodeProcessor.DEFAULT_DATA` in `supabase/shared/email-template-renderer.ts`: **User:** - `{nama}` - User name - `{email}` - User email **Order:** - `{order_id}` - Order ID - `{tanggal_pesanan}` - Order date - `{total}` - Total amount - `{metode_pembayaran}` - Payment method **Product:** - `{produk}` - Product name - `{kategori_produk}` - Product category **Access:** - `{link_akses}` - Access link - `{username_akses}` - Access username - `{password_akses}` - Access password **Consulting:** - `{tanggal_konsultasi}` - Consultation date - `{jam_konsultasi}` - Consultation time - `{link_meet}` - Meeting link **And many more...** ## Creating New Templates ### 1. Design Content-Only HTML Use brutalist components: ```html

Welcome!

Hello {nama}, welcome to {platform_name}!

Your Details

Field Value
Email {email}
Plan {plan_name}

Go to Dashboard

Success! Your account is ready to use.
``` ### 2. Add to Database ```sql INSERT INTO notification_templates ( key, name, is_active, email_subject, email_body_html ) VALUES ( 'welcome_email', 'Welcome Email', true, 'Welcome to {platform_name}!', '---

Welcome!

...---' ); ``` ### 3. Use in Edge Function ```typescript const template = await getTemplate('welcome_email'); const htmlContent = processShortcodes(template.body_html, { nama: user.name, platform_name: settings.brand_name, email: user.email, plan_name: user.plan, dashboard_link: 'https://...', }); const htmlBody = EmailTemplateRenderer.render({ subject: template.subject, content: htmlContent, brandName: settings.brand_name, }); ``` ## Migration Notes ### Old Templates (Self-Contained HTML) If you have old templates with full HTML: **Before:** ```html

Welcome!

Hello...

``` **After (Content-Only):** ```html

Welcome!

Hello...

``` Remove: - `` - ``, ``, `` tags - `