> ## Documentation Index
> Fetch the complete documentation index at: https://docs.quinnsambal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Email marketing

<style>
  {`
    [class*="max-w-none"][class*="table"] {
      display: block !important;
      overflow-x: auto !important;
      max-width: 100% !important;
      width: 100% !important;
      flex-grow: 0 !important;
    }
    [class*="max-w-none"][class*="table"] > table {
      width: 100% !important;
      max-width: 100% !important;
      table-layout: fixed !important;
    }
    .mermaid {
      max-width: 100% !important;
      overflow-x: auto !important;
    }
    article svg[role="img"] {
      max-width: 100% !important;
      height: auto !important;
    }
    article img, .prose img {
      max-width: 100% !important;
      height: auto !important;
    }
    img[src*="LOGO"], img[src*="logo"] {
      max-width: 120px !important;
      max-height: 40px !important;
      width: auto !important;
      height: auto !important;
      object-fit: contain !important;
    }
    `}
</style>

***

title: "Email Marketing"
description: "Email campaign dengan AI content generation, ReactQuill editor, template library, scheduled sending, dan open rate analytics di SNISHOP ERP."
-----------------------------------------------------------------------------------------------------------------------------------------------------------

# Email Marketing

<img src="https://mintcdn.com/quinnofspicy/e4f_upKhVWcjsUmM/docs/mintlify/screenshots/communication/email-marketing.png?fit=max&auto=format&n=e4f_upKhVWcjsUmM&q=85&s=60fa592d27e41977f8d656a7c8aad0ba" alt="Email Marketing" width="1920" height="1080" data-path="docs/mintlify/screenshots/communication/email-marketing.png" />

Email Marketing memungkinkan kamu membuat dan mengirim campaign email profesional langsung dari dalam ERP. Dibangun di atas `EmailMarketing.jsx` (539 baris) dengan fitur **AI content generation** via InvokeLLM, editor rich-text ReactQuill, template library, dan scheduled sending.

Modul ini memiliki permission gating khusus (`can_edit_finance`) karena email marketing sering berkaitan dengan promosi dan komunikasi finansial ke customer.

## Arsitektur Komponen

```mermaid theme={null}
graph TD
    A[EmailMarketing.jsx<br/>539 lines] --> B[ERPAccessGuard<br/>can_edit_finance]
    A --> C[Stats Dashboard]
    A --> D[Template Library]
    A --> E[AI Email Generator]
    A --> F[Campaign Form]
    A --> G[Campaign List]
    D --> H[TemplatePicker<br/>platform=email]
    E --> I[InvokeLLM<br/>structured JSON]
    F --> J[ReactQuill Editor]
    F --> K[Recipient Selector<br/>from CRM]
    F --> L[Schedule Picker]
    F --> M[SendEmail<br/>base44 integration]
    A --> N[base44.entities.EmailCampaign]
    A --> O[base44.entities.Customer]
    A --> P[base44.entities.NewsletterSubscriber]
```

### Deskripsi Arsitektur

Arsitektur Email Marketing terdiri dari beberapa lapisan utama:

1. **Presentation Layer** — `EmailMarketing.jsx` sebagai komponen utama yang mengorkestrasi seluruh tampilan UI termasuk stats dashboard, campaign list, dan campaign form.
2. **Access Control Layer** — `ERPAccessGuard` memvalidasi permission `can_edit_finance` sebelum user dapat mengakses modul ini.
3. **Content Generation Layer** — `InvokeLLM` menghasilkan konten email terstruktur (subject, preheader, content HTML) berdasarkan brief, tipe campaign, tone, dan target audience yang dipilih user.
4. **Editor Layer** — `ReactQuill` menyediakan rich-text editing untuk konten HTML email dengan dukungan formatting, hyperlink, dan blockquote.
5. **Template Layer** — `TemplatePicker` dengan `platform="email"` menyediakan template email siap pakai yang dapat di-customize lebih lanjut.
6. **Dispatch Layer** — `SendEmail` (base44 integration) menangani pengiriman email individual ke setiap penerima dalam `recipient_list`.
7. **Data Layer** — Entity `EmailCampaign`, `Customer`, dan `NewsletterSubscriber` menyimpan data campaign, daftar penerima, dan subscriber newsletter.

## Entity EmailCampaign

Entity `EmailCampaign` menyimpan seluruh data campaign email marketing yang dibuat dan dikirim melalui modul ini.

| Field | Tipe | Required | Default | Deskripsi |
| - | - | - | - | - |
| `company_id` | `string` | Tidak | — | Scope perusahaan (multi-tenant). Mengikat campaign ke perusahaan tertentu. |
| `campaign_name` | `string` | **Ya** | — | Nama campaign yang akan ditampilkan di daftar campaign. Jika tidak diisi, sistem auto-generate dari tipe campaign + tanggal. |
| `subject` | `string` | **Ya** | — | Subjek email yang akan muncul di inbox penerima. Dapat diisi manual atau di-generate oleh AI. |
| `content` | `string` (HTML) | **Ya** | — | Isi email dalam format HTML rich-text. Ditulis menggunakan editor ReactQuill. Tag yang diizinkan: `h1`, `h2`, `p`, `ul`, `li`, `strong`, `a`, `blockquote`. |
| `recipient_list` | `string[]` | Tidak | — | Array alamat email penerima. Diambil dari entity `Customer` di modul CRM. |
| `send_date` | `datetime` | Tidak | — | Jadwal pengiriman campaign. Jika kosong, email dikirim langsung (immediate). Jika diisi, campaign berstatus `scheduled` hingga waktu yang ditentukan. |
| `status` | `enum` | Tidak | `draft` | Status campaign: `draft`, `scheduled`, `sent`, `failed`. Mengatur lifecycle campaign dari pembuatan hingga pengiriman. |
| `sent_count` | `number` | Tidak | `0` | Jumlah email yang berhasil terkirim. Diupdate setelah proses pengiriman selesai. |
| `opened_count` | `number` | Tidak | `0` | Jumlah email yang telah dibuka oleh penerima. Digunakan untuk menghitung open rate. |
| `clicked_count` | `number` | Tidak | `0` | Jumlah link yang diklik oleh penerima di dalam email. Metrik penting untuk mengukur engagement. |
| `template_id` | `string` | Tidak | — | ID template yang digunakan sebagai basis konten campaign. Menghubungkan ke template di `TemplatePicker`. |

### Validasi dan Constraints

* **Required fields**: `campaign_name`, `subject`, dan `content` wajib diisi sebelum campaign dapat disimpan.
* **Default status**: Campaign baru selalu berstatus `draft` hingga secara eksplisit dijadwalkan atau dikirim.
* **HTML content**: Konten email harus berupa HTML valid. Editor ReactQuill memvalidasi tag yang diizinkan untuk mencegah injeksi script.

## Entity NewsletterSubscriber

Entity `NewsletterSubscriber` mengelola daftar subscriber newsletter yang mendaftar melalui berbagai halaman di website SNISHOP.

| Field | Tipe | Required | Default | Deskripsi |
| - | - | - | - | - |
| `email` | `string` | **Ya** | — | Alamat email subscriber. Harus unik dan valid. |
| `name` | `string` | Tidak | — | Nama lengkap subscriber. Bersifat opsional untuk personalisasi email. |
| `description` | `string` | Tidak | — | Catatan atau preferensi konten yang diinginkan subscriber. Maksimum 1000 karakter. |
| `subscribed_from` | `enum` | Tidak | `blog` | Halaman asal subscriber mendaftar: `blog`, `home`, `about`, `partnership`, `other`. |
| `is_active` | `boolean` | Tidak | `true` | Status aktif subscription. Jika `false`, subscriber tidak akan menerima email newsletter. |
| `unsubscribed_date` | `datetime` | Tidak | — | Tanggal dan waktu subscriber melakukan unsubscribe. Diisi otomatis saat subscriber menonaktifkan langganan. |
| `interests` | `string[]` | Tidak | — | Array topik yang diminati subscriber. Digunakan untuk segmentasi dan personalisasi konten newsletter. |

### Validasi dan Constraints

* **Required fields**: Hanya `email` yang wajib diisi saat pendaftaran subscriber baru.
* **Default is\_active**: Subscriber baru secara otomatis berstatus aktif (`true`).
* **Description maxLength**: Field `description` dibatasi maksimal 1000 karakter untuk mencegah input berlebihan.

## Entity Customer (Sumber Data Penerima)

Entity `Customer` dari modul CRM berfungsi sebagai sumber data utama untuk daftar penerima email campaign. Field-field yang relevan untuk email marketing:

| Field | Tipe | Deskripsi Relevansi Email Marketing |
| - | - | - |
| `email` | `string` | Alamat email utama customer — digunakan sebagai alamat penerima email campaign. |
| `name` | `string` | Nama customer — digunakan untuk personalisasi konten email (misalnya "Halo, Budi!"). |
| `customer_type` | `enum` | Tipe customer: `individual`, `business`, `retail`, `reseller`, `distributor`, `modern_market`. Berguna untuk segmentasi campaign. |
| `status` | `enum` | Status customer: `lead`, `prospect`, `customer`, `inactive`. Dapat digunakan untuk filter penerima (misalnya hanya kirim ke `customer` aktif). |
| `tags` | `string[]` | Tag yang diberikan ke customer — dapat digunakan untuk segmentasi campaign berdasarkan kategori. |
| `preferences.preferred_contact` | `enum` | Metode kontak preferensi: `phone`, `whatsapp`, `email`. Menunjukkan apakah customer bersedia dihubungi via email. |
| `company_id` | `string` | Scope perusahaan — memastikan campaign hanya menjangkau customer dari perusahaan yang sesuai. |
| `is_active` | `boolean` | Status aktif customer — customer non-aktif sebaiknya tidak dimasukkan ke recipient list. |

## Stats Dashboard

4 kartu metrik di bagian atas menampilkan ringkasan performa email marketing secara real-time:

| Metrik | Rumus | Deskripsi |
| - | - | - |
| **Total Campaigns** | `campaigns.length` | Total campaign yang pernah dibuat, termasuk draft, scheduled, sent, dan failed. |
| **Total Subscribers** | `customers.length` | Total customer yang bisa menerima email. Berasal dari entity Customer di modul CRM. |
| **Emails Sent** | `Σ campaigns[].sent_count` | Akumulasi total email yang berhasil terkirim dari semua campaign. |
| **Open Rate** | `Math.round((total opened / total sent) × 100)%` | Persentase email yang dibuka oleh penerima. Metrik kunci untuk mengukur efektivitas subject line dan relevansi konten. |

### Interpretasi Metrik

* **Open Rate > 25%**: Performa sangat baik. Subject line dan waktu pengiriman sudah optimal.
* **Open Rate 15-25%**: Performa rata-rata. Masih ada ruang perbaikan di subject line atau segmentasi.
* **Open Rate \< 15%**: Perlu evaluasi menyeluruh — pertimbangkan A/B testing subject line, perbaikan segmentasi, atau penyesuaian waktu pengiriman.
* **Click Rate** (`clicked_count / sent_count`): Mengukur seberapa menarik konten email dan CTA (call-to-action) yang disajikan.

## AI Email Generator

```mermaid theme={null}
sequenceDiagram
    participant User
    participant AI Generator
    participant InvokeLLM
    participant CampaignForm

    User->>AI Generator: Input brief + dropdowns
    AI Generator->>InvokeLLM: Structured prompt (Indonesian)
    Note over InvokeLLM: response_json_schema:<br/>{ subject, preheader, content }
    InvokeLLM-->>AI Generator: Generated email
    AI Generator->>CampaignForm: Auto-fill subject + content
```

### Input Parameter

| Parameter | Opsi | Deskripsi |
| - | - | - |
| **Brief** | Free text | Deskripsi singkat campaign yang menjadi panduan AI dalam menghasilkan konten. Semakin detail brief, semakin relevan output yang dihasilkan. |
| **Campaign Type** | `promo`, `newsletter`, `product_update`, `announcement`, `educational` | Jenis campaign yang menentukan struktur dan gaya konten yang akan di-generate. |
| **Tone** | `friendly`, `professional`, `urgent`, `educational` | Gaya bahasa yang digunakan dalam email. Mempengaruhi pemilihan kata dan struktur kalimat. |
| **Audience** | `customers`, `leads`, `umkm`, `enterprise` | Target penerima email. AI menyesuaikan kedalaman konten dan terminologi berdasarkan audience. |

### Output Schema

AI menghasilkan email dengan struktur JSON berikut:

```json theme={null}
{
  "subject": "Subject email yang menarik",
  "preheader": "Preheader text untuk preview",
  "content": "<h1>...</h1><p>...</p><ul>...</ul>"
}
```

Content harus berupa HTML dengan tag yang diizinkan: `h1`, `h2`, `p`, `ul`, `li`, `strong`, `a`, `blockquote`.

### Auto Campaign Name

Jika user tidak mengisi nama campaign, sistem auto-generate dari type + tanggal:

```
"Campaign Promo - 10 Oktober 2026"
```

### Tips AI Generator

* Berikan brief yang spesifik dan mendetail — sertakan nama produk, diskon, atau informasi kunci yang ingin disampaikan.
* Pilih `tone` yang sesuai dengan brand voice perusahaan untuk konsistensi komunikasi.
* Untuk audience `enterprise`, AI akan menghasilkan konten yang lebih formal dan data-driven.
* Selalu review dan edit hasil AI sebelum mengirim — gunakan ReactQuill editor untuk penyempurnaan.

## Campaign Form

| Field | Komponen | Deskripsi |
| - | - | - |
| Campaign Name | Text input | Nama campaign yang muncul di daftar campaign. Auto-generate jika dikosongkan. |
| Subject | Text input | Subjek email yang muncul di inbox penerima. Dapat diisi otomatis oleh AI Generator. |
| Content | ReactQuill editor | Isi email dalam format HTML. Mendukung rich-text formatting termasuk heading, list, bold, hyperlink, dan blockquote. |
| Recipients | Multi-select + "Select All" | Pilih penerima dari entity Customer. Fitur "Select All" memilih semua customer sekaligus. |
| Send Date | DateTime picker | Jadwal pengiriman. Kosongkan untuk kirim langsung (immediate sending). |

### Recipient Selection

Penerima dipilih dari entity **Customer** di modul CRM. Fitur "Select All" memilih semua customer sekaligus. Untuk segmentasi yang lebih granular, gunakan filter berdasarkan `customer_type`, `status`, atau `tags`.

## Email Sending Pipeline

```mermaid theme={null}
flowchart TD
    A[User klik Kirim] --> B{send_date set?}
    B -->|Ya| C[Status: scheduled]
    B -->|Tidak| D[Send Immediately]
    D --> E[Dynamic import SendEmail]
    E --> F[Iterate recipient_list]
    F --> G[Send individual email]
    G --> H{Success?}
    H -->|Ya| I[sentCount++]
    H -->|Error| J[Continue, track failure]
    I --> K[Update campaign: status=sent]
    J --> K
    K --> L[Update sent_count]
```

### Individual Sending

Setiap email dikirim **individual** (bukan bulk) ke setiap penerima. Ini memastikan personalisasi dan mengurangi risiko spam filter.

### Detail Pipeline Pengiriman

1. **Validasi** — Sistem memvalidasi bahwa `recipient_list` tidak kosong dan `content` berisi HTML valid.
2. **Penentuan Mode** — Jika `send_date` diisi, campaign disimpan dengan status `scheduled`. Jika kosong, langsung masuk ke pipeline pengiriman.
3. **Dynamic Import** — Modul `SendEmail` di-import secara dinamis untuk optimasi ukuran komponen awal.
4. **Iterasi Penerima** — Setiap alamat di `recipient_list` diproses satu per satu.
5. **Pengiriman Individual** — Email dikirim secara individual (bukan CC/BCC massal) untuk personalisasi dan deliverability optimal.
6. **Error Handling** — Jika satu email gagal, proses tetap berlanjut ke penerima berikutnya. Kegagalan dicatat untuk troubleshooting.
7. **Update Status** — Setelah seluruh iterasi selesai, `sent_count` diupdate dan status campaign berubah menjadi `sent`.

## Campaign Status

| Status | Warna Badge | Deskripsi |
| - | - | - |
| `draft` | Abu-abu | Campaign baru yang belum dijadwalkan atau dikirim. Masih dapat diedit bebas. |
| `scheduled` | Biru | Dijadwalkan untuk dikirim pada waktu tertentu (`send_date`). Dapat di-override dengan "Kirim Sekarang". |
| `sent` | Hijau | Berhasil terkirim ke seluruh penerima. Metrik `sent_count` dan `opened_count` aktif terupdate. |
| `failed` | Merah | Gagal terkirim sebagian atau seluruhnya. Dapat di-retry atau dilihat detail error. |

### Aksi per Status

| Status | Aksi Tersedia |
| - | - |
| `draft` | Edit, Hapus, Jadwalkan, Kirim Langsung |
| `scheduled` | **Kirim Sekarang** (override schedule), Edit, Hapus |
| `sent` | Lihat detail, Monitor metrik (open rate, click rate) |
| `failed` | Retry, Lihat error, Edit dan kirim ulang |

## Template Library

Menggunakan komponen shared `TemplatePicker` dengan `platform="email"`:

```mermaid theme={null}
flowchart LR
    A[TemplatePicker] --> B[Pre-built Templates]
    B --> C[Select Template]
    C --> D[Auto-fill Campaign Form]
    D --> E[Customize di ReactQuill]
    E --> F[Siap Kirim]
```

Template mencakup berbagai format email marketing yang sudah diuji untuk engagement optimal:

| Kategori Template | Penggunaan | Deskripsi |
| - | - | - |
| **Promo** | Diskon, flash sale, penawaran spesial | Layout menonjolkan harga dan CTA button yang eye-catching. |
| **Newsletter** | Update berkala, tips, informasi industri | Layout konten panjang dengan section yang terstruktur. |
| **Product Update** | Peluncuran produk baru, fitur baru | Layout fokus pada visual produk dan benefit. |
| **Announcement** | Pengumuman penting, maintenance, kebijakan | Layout formal dan to-the-point. |
| **Educational** | Tutorial, how-to, tips & tricks | Layout step-by-step dengan ilustrasi. |

### Cara Menggunakan Template

1. Klik **"Pilih Template"** di campaign form.
2. Browse kategori template yang tersedia.
3. Klik template yang sesuai — konten akan otomatis mengisi field `content`.
4. Edit konten di ReactQuill editor sesuai kebutuhan.
5. Subject line juga dapat di-auto-fill dari template.

## Permission & Security

| Guard | Value | Deskripsi |
| - | - | - |
| `ERPAccessGuard` | `requiredPermission="can_edit_finance"` | Hanya user dengan izin finance yang bisa akses |

Ini adalah satu-satunya modul Communication dengan explicit permission gating, karena email marketing sering berkaitan dengan promosi harga dan informasi finansial.

### RBAC Permission Matrix

| Role | Create Campaign | Edit Campaign | Delete Campaign | Send Campaign | View Stats | Manage Subscribers |
| - | - | - | - | - | - | - |
| **Admin** | Ya | Ya | Ya | Ya | Ya | Ya |
| **Finance** (`can_edit_finance`) | Ya | Ya | Ya | Ya | Ya | Tidak |
| **Marketing** | Ya | Ya | Tidak | Ya | Ya | Ya |
| **Viewer** | Tidak | Tidak | Tidak | Tidak | Ya | Tidak |

> **Catatan**: Permission gating utama menggunakan `can_edit_finance`. Role-based granularity di atas merupakan best practice yang direkomendasikan untuk implementasi selanjutnya.

## Integrasi Lintas Modul

| Modul | Komponen | Fungsi |
| - | - | - |
| CRM | Customer entity | Sumber daftar penerima email campaign |
| CRM | NewsletterSubscriber entity | Daftar subscriber newsletter dari halaman website |
| AI | InvokeLLM | Generate konten email dari brief dengan structured JSON output |
| Template | TemplatePicker | Library template email siap pakai dengan berbagai kategori |
| Editor | ReactQuill | Rich-text HTML editor untuk konten email |
| Email | SendEmail (base44) | Dispatch email individual ke setiap penerima |
| Animation | framer-motion | Stagger animations untuk UX yang smooth |

### Alur Data Lintas Modul

```mermaid theme={null}
flowchart LR
    subgraph CRM
        C[Customer]
        NS[NewsletterSubscriber]
    end
    subgraph AI
        LLM[InvokeLLM]
    end
    subgraph Template
        TP[TemplatePicker]
    end
    subgraph Email Marketing
        CF[Campaign Form]
        EC[EmailCampaign]
        SE[SendEmail]
    end
    C -->|email addresses| CF
    NS -->|subscriber emails| CF
    LLM -->|generated content| CF
    TP -->|template HTML| CF
    CF -->|save| EC
    EC -->|dispatch| SE
```

## Cara Akses

Dari sidebar, klik menu **Communication** > **Email Marketing**. Diperlukan permission `can_edit_finance`.

## Flow Penggunaan

1. Buka Email Marketing dari sidebar — lihat stats dashboard di atas untuk ringkasan performa
2. Klik **"Buat Campaign"** untuk memulai campaign baru
3. Gunakan **AI Generator** untuk generate konten: isi brief, pilih type, tone, dan audience
4. AI menghasilkan subject dan content HTML — edit di ReactQuill jika perlu
5. Atau pilih **Template** dari library dan sesuaikan konten
6. Pilih penerima dari daftar Customer — gunakan "Select All" untuk kirim ke semua
7. Atur jadwal pengiriman atau pilih **Kirim Langsung**
8. Klik **Simpan** — campaign masuk ke daftar dengan status `scheduled` atau langsung `sent`
9. Monitor open rate, click rate, dan sent count di campaign list

## Entity Relationship Diagram

```mermaid theme={null}
erDiagram
    EmailCampaign {
        string company_id
        string campaign_name
        string subject
        string content
        array recipient_list
        datetime send_date
        string status
        number sent_count
        number opened_count
        number clicked_count
        string template_id
    }

    NewsletterSubscriber {
        string email
        string name
        string description
        string subscribed_from
        boolean is_active
        datetime unsubscribed_date
        array interests
    }

    Customer {
        string company_id
        string name
        string email
        string phone
        string customer_type
        string status
        array tags
        object preferences
        boolean is_active
    }

    EmailCampaign }o--|| Customer : "recipient_list (email addresses)"
    EmailCampaign }o--o| NewsletterSubscriber : "subscriber segments"
    Customer ||--o{ NewsletterSubscriber : "may subscribe to newsletter"
```

### Penjelasan Relasi

* **EmailCampaign → Customer**: Campaign menggunakan alamat email dari entity Customer sebagai `recipient_list`. Relasi ini bersifat many-to-many karena satu campaign bisa dikirim ke banyak customer, dan satu customer bisa menerima banyak campaign.
* **EmailCampaign → NewsletterSubscriber**: Campaign juga dapat menargetkan subscriber newsletter berdasarkan `interests` atau `subscribed_from`. Relasi bersifat opsional.
* **Customer → NewsletterSubscriber**: Seorang customer dapat juga menjadi newsletter subscriber. Email menjadi kunci penghubung antar entity.

## Entity Schema Tables

### EmailCampaign — Full Schema

| Field | Type | Required | Default | Description |
| - | - | - | - | - |
| `company_id` | `string` | Tidak | — | ID perusahaan untuk multi-tenant scoping |
| `campaign_name` | `string` | **Ya** | — | Nama campaign yang ditampilkan di UI |
| `subject` | `string` | **Ya** | — | Subjek email yang muncul di inbox penerima |
| `content` | `string` | **Ya** | — | Konten email dalam format HTML |
| `recipient_list` | `array<string>` | Tidak | — | Array alamat email penerima |
| `send_date` | `string (date-time)` | Tidak | — | Waktu terjadwal untuk pengiriman campaign |
| `status` | `string (enum)` | Tidak | `draft` | Status lifecycle campaign |
| `sent_count` | `number` | Tidak | `0` | Jumlah email berhasil terkirim |
| `opened_count` | `number` | Tidak | `0` | Jumlah email yang dibuka penerima |
| `clicked_count` | `number` | Tidak | `0` | Jumlah link yang diklik di dalam email |
| `template_id` | `string` | Tidak | — | ID template yang digunakan sebagai basis konten |

### NewsletterSubscriber — Full Schema

| Field | Type | Required | Default | Description |
| - | - | - | - | - |
| `email` | `string` | **Ya** | — | Alamat email subscriber |
| `name` | `string` | Tidak | — | Nama lengkap subscriber (opsional) |
| `description` | `string` | Tidak | — | Catatan/preferensi konten (max 1000 char) |
| `subscribed_from` | `string (enum)` | Tidak | `blog` | Halaman asal pendaftaran subscriber |
| `is_active` | `boolean` | Tidak | `true` | Status aktif subscription |
| `unsubscribed_date` | `string (date-time)` | Tidak | — | Tanggal unsubscribe |
| `interests` | `array<string>` | Tidak | — | Topik yang diminati subscriber |

### Customer — Email-Relevant Fields

| Field | Type | Required | Default | Description |
| - | - | - | - | - |
| `company_id` | `string` | **Ya** | — | ID perusahaan (multi-tenant) |
| `name` | `string` | **Ya** | — | Nama lengkap customer |
| `email` | `string` | Tidak | — | Alamat email untuk penerimaan campaign |
| `phone` | `string` | **Ya** | — | Nomor telepon utama |
| `whatsapp_number` | `string` | Tidak | — | Nomor WhatsApp untuk follow up |
| `company` | `string` | Tidak | — | Nama perusahaan customer (B2B) |
| `customer_type` | `string (enum)` | Tidak | `individual` | Segmentasi tipe customer |
| `status` | `string (enum)` | Tidak | `lead` | Status lifecycle customer |
| `tags` | `array<string>` | Tidak | — | Label segmentasi customer |
| `preferences.preferred_contact` | `string (enum)` | Tidak | — | Metode kontak preferensi |
| `is_active` | `boolean` | Tidak | `true` | Status aktif customer |

## State Diagrams

### Campaign Status Lifecycle

```mermaid theme={null}
stateDiagram-v2
    [*] --> draft : Campaign baru dibuat
    draft --> scheduled : Set send_date
    draft --> sent : Kirim langsung (tanpa send_date)
    draft --> [*] : Hapus campaign

    scheduled --> sent : Waktu tiba / Kirim Sekarang
    scheduled --> draft : Hapus send_date
    scheduled --> [*] : Hapus campaign

    sent --> [*] : Selesai (final)

    note right of draft : Campaign dalam mode edit.\nBelum dijadwalkan atau dikirim.
    note right of scheduled : Campaign menunggu waktu\npengiriman yang ditentukan.
    note right of sent : Email berhasil terkirim.\nMetrik aktif terupdate.

    state failed {
        [*] --> partial_failure : Beberapa email gagal
        [*] --> total_failure : Semua email gagal
        partial_failure --> [*]
        total_failure --> [*]
    }

    draft --> failed : Error saat kirim langsung
    scheduled --> failed : Error saat scheduled send
    failed --> draft : Reset ke draft untuk edit
    failed --> sent : Retry berhasil
```

### Newsletter Subscriber Lifecycle

```mermaid theme={null}
stateDiagram-v2
    [*] --> Active : Subscribe dari halaman website
    Active --> Active : Update interests/preferences
    Active --> Unsubscribed : User klik unsubscribe
    Unsubscribed --> Active : Re-subscribe
    Unsubscribed --> [*] : Hapus data

    note right of Active : is_active = true\nMenerima email newsletter
    note right of Unsubscribed : is_active = false\nunsubscribed_date terisi
```

## Sequence Diagrams

### Flow 1: Mengirim Campaign Email

```mermaid theme={null}
sequenceDiagram
    actor User
    participant UI as EmailMarketing.jsx
    participant Form as CampaignForm
    participant DB as base44 (Supabase)
    participant Email as SendEmail Service
    participant Recipients as Daftar Penerima

    User->>UI: Klik "Buat Campaign"
    UI->>Form: Tampilkan form campaign
    User->>Form: Isi campaign_name, subject, content
    User->>Form: Pilih recipients dari Customer list
    User->>Form: Atur send_date (opsional)
    User->>Form: Klik "Simpan"

    alt send_date diisi
        Form->>DB: Insert EmailCampaign (status=scheduled)
        DB-->>Form: Campaign saved
        Form-->>UI: Tampilkan success notification
    else kirim langsung
        Form->>DB: Insert EmailCampaign (status=draft)
        DB-->>Form: Campaign saved
        Form->>Email: Dynamic import SendEmail
        loop Untuk setiap penerima
            Form->>Email: Send individual email
            Email->>Recipients: Deliver email
            alt Success
                Recipients-->>Email: 200 OK
                Email-->>Form: Increment sent_count
            else Failure
                Recipients-->>Email: Error
                Email-->>Form: Track failure, continue
            end
        end
        Form->>DB: Update campaign (status=sent, sent_count=N)
        DB-->>Form: Updated
        Form-->>UI: Tampilkan success notification
    end
```

### Flow 2: Tracking Open Rate

```mermaid theme={null}
sequenceDiagram
    actor Recipient as Penerima Email
    participant EmailClient as Email Client
    participant Tracker as Open Tracker
    participant DB as base44 (Supabase)
    participant UI as EmailMarketing Dashboard

    Recipient->>EmailClient: Buka email
    EmailClient->>Tracker: Load tracking pixel / beacon
    Tracker->>DB: Increment opened_count untuk campaign
    DB-->>Tracker: Updated count
    Tracker-->>EmailClient: Serve 1x1 transparent pixel
    Note over UI: Open rate terupdate di dashboard
    UI->>DB: Query campaign metrics
    DB-->>UI: Return updated opened_count
    UI-->>UI: Recalculate open rate percentage
```

### Flow 3: Bounce Handling

```mermaid theme={null}
sequenceDiagram
    participant Email as SendEmail Service
    participant Bounce as Bounce Handler
    participant DB as base44 (Supabase)
    participant UI as EmailMarketing Dashboard

    Email->>Bounce: Delivery notification
    alt Hard Bounce
        Bounce->>DB: Mark recipient as invalid
        Bounce->>DB: Update campaign status jika perlu
        Note over Bounce: Hard bounce: email tidak valid,<br/>domain tidak ada, dll.
    else Soft Bounce
        Bounce->>DB: Log bounce untuk retry
        Note over Bounce: Soft bounce: mailbox penuh,<br/>server down sementara, dll.
        Bounce->>Bounce: Schedule retry (jika applicable)
    end
    Bounce-->>UI: Update campaign metrics
    UI->>DB: Query campaign status
    DB-->>UI: Return updated status & counts
```

### Flow 4: AI Content Generation

```mermaid theme={null}
sequenceDiagram
    actor User
    participant UI as AI Generator Panel
    participant LLM as InvokeLLM Service
    participant Form as CampaignForm

    User->>UI: Isi brief campaign
    User->>UI: Pilih Campaign Type
    User->>UI: Pilih Tone
    User->>UI: Pilih Audience
    User->>UI: Klik "Generate"

    UI->>LLM: Kirim structured prompt
    Note over LLM: Prompt mencakup:<br/>- Brief deskripsi<br/>- Campaign type context<br/>- Tone & style guide<br/>- Audience profile<br/>- response_json_schema
    LLM-->>UI: Return JSON: { subject, preheader, content }

    UI->>Form: Auto-fill subject field
    UI->>Form: Auto-fill content (HTML) di ReactQuill
    Note over Form: User dapat edit manual<br/>hasil generate AI
    User->>Form: Review & edit konten
    User->>Form: Lanjutkan ke pilih recipients & kirim
```

## Enum Reference Tables

### EmailCampaign.status

| Nilai | Deskripsi | Badge Color |
| - | - | - |
| `draft` | Campaign baru, belum dijadwalkan atau dikirim. Masih dalam mode editing. | Abu-abu |
| `scheduled` | Campaign telah diatur dengan `send_date` dan menunggu waktu pengiriman. | Biru |
| `sent` | Email berhasil terkirim ke penerima. Metrik (open, click) aktif tercatat. | Hijau |
| `failed` | Pengiriman email gagal sebagian atau seluruhnya. Memerlukan retry atau investigasi. | Merah |

### NewsletterSubscriber.subscribed\_from

| Nilai | Deskripsi |
| - | - |
| `blog` | Subscriber mendaftar dari halaman blog |
| `home` | Subscriber mendaftar dari halaman utama (homepage) |
| `about` | Subscriber mendaftar dari halaman tentang perusahaan |
| `partnership` | Subscriber mendaftar dari halaman partnership/kemitraan |
| `other` | Subscriber mendaftar dari halaman lainnya |

### Customer.customer\_type (Segmentasi Penerima)

| Nilai | Deskripsi | Relevansi Email Marketing |
| - | - | - |
| `individual` | Customer perorangan | Target untuk promo retail, newsletter umum |
| `business` | Customer perusahaan (B2B) | Target untuk penawaran korporat, product update |
| `retail` | Customer retail/toko | Target untuk promo produk, program loyalty |
| `reseller` | Reseller | Target untuk info margin, katalog produk baru |
| `distributor` | Distributor | Target untuk info supply chain, volume discount |
| `modern_market` | Pasar modern (minimarket, supermarket) | Target untuk penawaran distribusi, placement |

### Customer.status (Filter Penerima)

| Nilai | Deskripsi | Termasuk di Campaign? |
| - | - | - |
| `lead` | Calon customer yang belum bertransaksi | Opsional — untuk nurturing campaign |
| `prospect` | Calon customer yang sedang diproses | Opsional — untuk conversion campaign |
| `customer` | Customer aktif yang sudah bertransaksi | **Ya** — target utama campaign |
| `inactive` | Customer yang sudah tidak aktif | Umumnya dikecualikan dari campaign |

### AI Generator — Campaign Type

| Nilai | Deskripsi | Contoh Penggunaan |
| - | - | - |
| `promo` | Campaign promosi dan diskon | Flash sale, diskon akhir tahun, penawaran spesial |
| `newsletter` | Newsletter berkala | Update bulanan, tips industri, roundup konten |
| `product_update` | Pengumuman produk baru | Peluncuran fitur baru, versi produk, katalog |
| `announcement` | Pengumuman penting | Perubahan kebijakan, maintenance, berita perusahaan |
| `educational` | Konten edukasi | Tutorial, how-to guide, tips & tricks |

### AI Generator — Tone

| Nilai | Deskripsi | Karakteristik |
| - | - | - |
| `friendly` | Ramah dan hangat | Sapaan informal, emoji, bahasa percakapan |
| `professional` | Formal dan profesional | Bahasa baku, struktur rapi, data-driven |
| `urgent` | Mendesak dan penting | Kata-kata action-oriented, deadline, scarcity |
| `educational` | Edukatif dan informatif | Step-by-step, penjelasan detail, referensi |

### AI Generator — Audience

| Nilai | Deskripsi | Penyesuaian Konten |
| - | - | - |
| `customers` | Customer yang sudah bertransaksi | Personalisasi berdasarkan riwayat pembelian |
| `leads` | Calon customer potensial | Fokus pada value proposition dan benefit |
| `umkm` | Usaha mikro, kecil, dan menengah | Bahasa sederhana, fokus pada solusi praktis |
| `enterprise` | Perusahaan besar | Formal, data-driven, fokus pada ROI |

## Tips

* Kirim email di waktu optimal: pagi hari kerja (08:00-10:00) biasanya memberikan open rate tertinggi
* Subject line yang menarik sangat menentukan — gunakan AI generator untuk brainstorming subject yang engaging
* Jangan terlalu sering mengirim email — 2-4 kali sebulan sudah cukup untuk menjaga engagement tanpa memicu unsubscribe
* Gunakan A/B testing untuk subject line — kirim 2 versi ke subset kecil, lalu kirim versi terbaik ke semua penerima
* Personalisasi konten dengan nama penerima dan data relevan untuk meningkatkan click-through rate
* Monitor open rate secara berkala — jika di bawah 15%, evaluasi subject line dan waktu pengiriman
* Segmentasi penerima berdasarkan `customer_type` dan `tags` untuk konten yang lebih relevan dan targeted
* Manfaatkan `interests` di NewsletterSubscriber untuk mengirim konten yang sesuai dengan minat subscriber
* Selalu pastikan `is_active` customer bernilai `true` sebelum memasukkan ke `recipient_list`
* Gunakan `clicked_count` untuk mengukur efektivitas CTA (call-to-action) dalam email


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.