diff --git a/EMAIL-TEMPLATE-SYSTEM.md b/EMAIL-TEMPLATE-SYSTEM.md
new file mode 100644
index 0000000..0bc0629
--- /dev/null
+++ b/EMAIL-TEMPLATE-SYSTEM.md
@@ -0,0 +1,358 @@
+# 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
+
+
+
+
+
+
+
+
+
+```
+
+**After (Content-Only):**
+```html
+Welcome!
+Hello...
+```
+
+Remove:
+- ``
+- ``, ``, `` tags
+- `