> ## 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.

# Automation

<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: "Automation"
description: "Workflow automation dengan 12 trigger types, 7 action types, background engine, dan integrasi Google Sheets/Slack/Discord di SNISHOP ERP."
--------------------------------------------------------------------------------------------------------------------------------------------------------

# Automation

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

Halaman Automation memungkinkan kamu membuat workflow yang berjalan otomatis berdasarkan trigger dan action yang ditentukan. Dibangun di atas `Automation.jsx` (105 baris) dengan engine utama di `WorkflowAutomationManager.jsx` (427 baris) dan `WorkflowEngine.jsx` yang berjalan di background.

Sistem ini mendukung **12 jenis trigger** dari berbagai modul (task, invoice, stock, KPI, leave request) dan **7 jenis action** termasuk integrasi ke Google Sheets, Slack, dan Discord.

## Arsitektur Komponen

```mermaid theme={null}
graph TD
    A[Automation.jsx<br/>105 lines] --> B[WorkflowAutomationManager<br/>427 lines]
    A --> C[WorkflowEngine<br/>Background]
    B --> D[Workflow CRUD]
    B --> E[Multi-Action Editor]
    B --> F[Toggle Active/Inactive]
    C --> G[2-minute Polling]
    C --> H[Trigger Evaluation]
    C --> I[Action Execution]
    C --> J[Update trigger_count]
    A --> K[base44.entities.WorkflowAutomation]
    A --> L[base44.entities.DirectMessage]
    C --> M[Google Sheets API]
    C --> N[Slack Webhook]
    C --> O[Discord Webhook]
```

## Entity WorkflowAutomation

| Field | Tipe | Deskripsi |
| - | - | - |
| `id` | UUID | Primary key |
| `name` | string | Nama workflow |
| `description` | string | Deskripsi workflow |
| `trigger_type` | enum | Jenis trigger (12 opsi) |
| `trigger_conditions` | object | Kondisi trigger (misal `{days_before: 3}`) |
| `actions` | array | Daftar action yang dijalankan |
| `is_active` | boolean | Status aktif workflow |
| `trigger_count` | number | Berapa kali trigger dijalankan |
| `company_id` | FK → Company | Scope perusahaan |
| `user_id` | FK → User | Scope user (opsional) |
| `created_at` | Timestamp | Waktu pembuatan |
| `updated_at` | Timestamp | Waktu update terakhir |
| `created_by` | FK → User | User yang membuat |

## 12 Trigger Types

| Trigger | Sumber | Deskripsi |
| - | - | - |
| `task_created` | Tasks | Task baru dibuat |
| `task_status_changed` | Tasks | Status task berubah |
| `task_due_approaching` | Tasks | Deadline task mendekat |
| `task_overdue` | Tasks | Task melewati deadline |
| `invoice_created` | Finance | Invoice baru dibuat |
| `invoice_overdue` | Finance | Invoice melewati jatuh tempo |
| `low_stock` | Inventory | Stok produk rendah |
| `leave_request` | HR | Pengajuan cuti baru |
| `kpi_target_missed` | KPI | Target KPI tidak tercapai |
| `schedule_daily` | System | Trigger harian (jadwal) |
| `schedule_weekly` | System | Trigger mingguan (jadwal) |
| `schedule_monthly` | System | Trigger bulanan (jadwal) |

### Trigger Conditions

| Trigger | Condition Object | Deskripsi |
| - | - | - |
| `task_due_approaching` | `{ days_before: 3 }` | X hari sebelum deadline |
| `low_stock` | `{ threshold: 10 }` | Stok di bawah threshold |
| `schedule_daily` | `{ time: '09:00' }` | Waktu eksekusi harian |
| `schedule_weekly` | `{ day: 'monday', time: '09:00' }` | Hari & waktu eksekusi |
| `schedule_monthly` | `{ day: 1, time: '09:00' }` | Tanggal & waktu eksekusi |

## 7 Action Types

| Action | Deskripsi | Data Fields |
| - | - | - |
| `send_notification` | Kirim notifikasi in-app | `message`, `recipient` |
| `send_chat_message` | Kirim pesan ke channel | `message`, `channel_id` |
| `create_task` | Buat task baru otomatis | Task fields |
| `create_notification_all_members` | Notifikasi ke semua anggota | `message` |
| `sync_google_sheets` | Sync data ke Google Sheets | `spreadsheetId`, `sheetName` |
| `send_slack_alert` | Kirim alert ke Slack | `message`, `channelId` |
| `send_discord_alert` | Kirim alert ke Discord | `message`, `channelId` |

### Recipient Options

| Recipient | Deskripsi |
| - | - |
| `self` | Kirim ke pembuat workflow |
| `all_members` | Kirim ke semua anggota company |
| `admins` | Kirim ke semua admin |

## Workflow Engine

```mermaid theme={null}
flowchart TD
    A[WorkflowEngine] --> B[Every 2 minutes]
    B --> C[Load active workflows]
    C --> D{Evaluate triggers}
    D -->|Match| E[Execute actions]
    E --> F[Update trigger_count++]
    D -->|No match| G[Skip]
    F --> H[Next evaluation in 2 min]
    G --> H
```

### Background Polling

Engine berjalan di background dan mengevaluasi semua workflow aktif setiap **2 menit**.

### Multi-Action Execution

Satu workflow bisa memiliki beberapa action yang dijalankan berurutan saat trigger terpicu.

```mermaid theme={null}
sequenceDiagram
    participant WE as WorkflowEngine
    participant WA as WorkflowAutomation
    participant A1 as Action 1
    participant A2 as Action 2
    participant A3 as Action 3

    WE->>WA: Check trigger condition
    alt Trigger matched
        WA-->>WE: Return true
        WE->>A1: Execute action 1
        A1-->>WE: Success
        WE->>A2: Execute action 2
        A2-->>WE: Success
        WE->>A3: Execute action 3
        A3-->>WE: Success
        WE->>WA: Update trigger_count++
    else Trigger not matched
        WA-->>WE: Return false
    end
```

## Cross-Module Integration

```mermaid theme={null}
graph LR
    subgraph "Triggers From"
        A[Tasks Module]
        B[Finance Module]
        C[Inventory Module]
        D[HR Module]
        E[KPI Module]
    end
    subgraph "Automation"
        F[WorkflowEngine]
    end
    subgraph "Actions To"
        G[In-App Notification]
        H[Chat Message]
        I[Google Sheets]
        J[Slack]
        K[Discord]
    end
    A --> F
    B --> F
    C --> F
    D --> F
    E --> F
    F --> G
    F --> H
    F --> I
    F --> J
    F --> K
```

## Data Scoping

Workflow di-scope berdasarkan:

* `company_id` — workflow berlaku untuk seluruh perusahaan
* `user_id` — workflow berlaku hanya untuk user tertentu (opsional)

## DirectMessage Integration

Sistem juga menggunakan entity `DirectMessage` untuk internal messaging dengan polling setiap **30 detik** untuk unread count.

## Contoh Workflow

### 1. Reminder Deadline Task

| Field | Value |
| - | - |
| **Name** | "Reminder H-1 Deadline" |
| **Trigger** | `task_due_approaching` |
| **Condition** | `{ days_before: 1 }` |
| **Action 1** | `send_notification` ke task assignee |
| **Action 2** | `send_chat_message` ke channel #tasks |

### 2. Low Stock Alert

| Field | Value |
| - | - |
| **Name** | "Alert Stok Rendah" |
| **Trigger** | `low_stock` |
| **Condition** | `{ threshold: 10 }` |
| **Action 1** | `send_notification` ke inventory manager |
| **Action 2** | `send_slack_alert` ke channel #inventory |
| **Action 3** | `sync_google_sheets` untuk tracking |

### 3. Invoice Overdue Notification

| Field | Value |
| - | - |
| **Name** | "Notifikasi Invoice Jatuh Tempo" |
| **Trigger** | `invoice_overdue` |
| **Condition** | None (semua invoice overdue) |
| **Action 1** | `send_notification` ke finance team |
| **Action 2** | `create_task` untuk follow-up |

## Cara Akses

Dari sidebar, klik menu **Marketing** > **Automation**.

## Flow Penggunaan

1. Buka halaman Automation dari sidebar — lihat daftar workflow yang sudah ada
2. Klik **"Buat Workflow"** untuk membuat automation baru
3. Beri nama dan deskripsi workflow
4. Pilih **trigger type** dari 12 opsi yang tersedia
5. Atur **trigger conditions** jika diperlukan (misal: `days_before: 3`)
6. Tambahkan satu atau lebih **actions** yang harus dijalankan
7. Untuk action eksternal (Google Sheets, Slack, Discord), isi connection details
8. Aktifkan workflow dengan toggle **Active**
9. Monitor `trigger_count` untuk melihat berapa kali workflow sudah berjalan
10. Review dan optimasi workflow secara berkala berdasarkan hasil

## Tips

* Mulai dari workflow sederhana (1 trigger + 1 action) sebelum membuat yang kompleks
* Test workflow dengan skenario berbeda sebelum mengaktifkannya — pastikan trigger terpicu pada kondisi yang tepat
* Gunakan `task_due_approaching` dengan `days_before: 1` untuk reminder H-1 deadline
* Kombinasikan `low_stock` trigger dengan `send_notification` ke admin untuk restock alert
* Review `trigger_count` secara berkala — workflow yang tidak pernah trigger mungkin perlu di-adjust condition-nya
* Dokumentasikan setiap workflow dengan deskripsi yang jelas agar tim lain bisa memahami tujuannya
* Jangan membuat terlalu banyak workflow untuk trigger yang sama — bisa terjadi duplikasi notifikasi

***

## Entity Relationship Diagram

```mermaid theme={null}
erDiagram
    WorkflowAutomation {
        string company_id "ID perusahaan"
        string user_id "Email pemilik workflow"
        string name "Nama workflow automation"
        string description "Deskripsi workflow"
        string trigger_type "Jenis trigger workflow"
        object trigger_conditions "Kondisi tambahan trigger"
        array actions "Daftar aksi yang dijalankan"
        boolean is_active "Status aktif workflow"
        datetime last_triggered_at "Waktu terakhir trigger dijalankan"
        number trigger_count "Jumlah trigger dijalankan"
    }

    Automation {
        string workspace_id "ID workspace"
        string name "Nama automasi"
        string description "Penjelasan tujuan automasi"
        string trigger_type "Jenis trigger"
        object trigger_conditions "Kondisi trigger"
        string action_type "Jenis aksi"
        object action_properties "Properti aksi"
        boolean is_active "Status aktif automasi"
    }

    Customer {
        string company_id "ID perusahaan"
        string name "Nama customer"
        string email "Email customer"
        string phone "Nomor telepon"
        string whatsapp_number "Nomor WhatsApp"
        string company "Nama perusahaan customer"
        string address "Alamat"
        string customer_type "Tipe customer"
        string membership_level_id "ID level membership"
        string membership_level_name "Nama level membership"
        date membership_since "Sejak jadi member"
        number membership_points "Total poin member"
        number lifetime_points "Total poin sepanjang waktu"
        number stamps "Total stamp"
        boolean has_negative_points "Flag saldo negatif"
        number loyalty_deficit_points "Defisit poin loyalty"
        string loyalty_review_notes "Catatan review loyalty"
        datetime last_tier_upgrade_date "Waktu perubahan tier terakhir"
        string last_tier_upgrade_reason "Alasan perubahan tier"
        string last_tier_upgrade_by "Operator pengubah tier"
        string status "Status customer"
        string source "Sumber customer"
        array tags "Tag customer"
        number lifetime_value "Total nilai transaksi"
        number total_orders "Jumlah transaksi"
        number average_order_value "Rata-rata nilai transaksi"
        date last_purchase_date "Tanggal pembelian terakhir"
        date last_contact_date "Terakhir di-follow up"
        string last_contact_method "Metode follow up terakhir"
        string last_contact_notes "Catatan follow up terakhir"
        date birthday "Tanggal ulang tahun"
        object preferences "Preferensi customer"
        string notes "Catatan"
        string auth_user_id "ID autentikasi"
        string default_address_id "ID alamat default"
        array addresses "Buku alamat"
        string billing_address "Alamat penagihan"
        string shipping_address "Alamat pengiriman"
        string parent_customer_id "ID perusahaan induk"
        string outlet_name "Nama cabang"
        string tax_id "NPWP"
        string payment_terms "Ketentuan pembayaran"
        number payment_terms_days "Hari jatuh tempo"
        number credit_limit "Batas plafon riutang"
        boolean is_active "Status aktif"
    }

    Notification {
        string user_id "Email penerima notifikasi"
        string title "Judul notifikasi"
        string message "Pesan notifikasi"
        string description "Detail tambahan notifikasi"
        string url "URL tujuan notifikasi"
        string type "Tipe notifikasi"
        object metadata "Payload tambahan"
        string priority "Prioritas notifikasi"
        boolean is_read "Status sudah dibaca"
        string event_id "Idempotency key"
        string company_id "ID perusahaan"
        string location_id "ID lokasi"
        string source_entity "Nama entity sumber"
        string source_id "ID record sumber"
        string correlation_id "Correlation ID observability"
    }

    EmailCampaign {
        string company_id "ID perusahaan"
        string campaign_name "Nama kampanye"
        string subject "Subjek email"
        string content "HTML email content"
        array recipient_list "Daftar email penerima"
        datetime send_date "Tanggal pengiriman"
        string status "Status kampanye"
        number sent_count "Jumlah terkirim"
        number opened_count "Jumlah dibuka"
        number clicked_count "Jumlah diklik"
        string template_id "ID template"
    }

    NewsletterSubscriber {
        string email "Email subscriber"
        string name "Nama subscriber"
        string description "Catatan preferensi konten"
        string subscribed_from "Halaman asal subscribe"
        boolean is_active "Status aktif subscription"
        datetime unsubscribed_date "Tanggal unsubscribe"
        array interests "Topik yang diminati"
    }

    CustomerLoyaltyLedger {
        string company_id "ID perusahaan"
        string customer_id "ID customer"
        string customer_name "Nama customer"
        string customer_phone "Nomor telepon customer"
        string transaction_id "ID transaksi POS"
        string transaction_number "Nomor struk"
        string idempotency_key "Key anti duplikasi"
        string event_type "Tipe event mutasi"
        string scheme_type "Skema loyalty"
        number points_delta "Perubahan poin"
        number points_before "Saldo poin sebelum"
        number points_after "Saldo poin setelah"
        number stamps_delta "Perubahan stamp"
        number stamps_before "Saldo stamp sebelum"
        number stamps_after "Saldo stamp setelah"
        number eligible_amount "Nilai transaksi eligible"
        string reason "Alasan mutasi"
        number deficit_points "Defisit poin"
        boolean requires_manual_review "Flag perlu review manual"
        object reward_details "Detail reward"
        string performed_by "Operator pemroses"
        string actor_role "Role aktor"
        datetime created_at "Waktu tercatat"
        string finance_record_id "ID FinancialRecord terkait"
    }

    CustomerMembership {
        string company_id "ID perusahaan"
        string level_name "Nama level"
        string level_key "Key unik level"
        string icon "Icon emoji"
        string color "Warna level"
        string description "Penjelasan keanggotaan"
        number discount_percentage "Diskon persentase"
        number points_multiplier "Multiplier poin"
        number min_purchase "Minimum pembelian"
        array benefits "List benefit"
        boolean priority_support "Akses priority support"
        boolean free_delivery "Gratis ongkir"
        number birthday_bonus "Bonus poin ulang tahun"
        boolean is_active "Status aktif"
        number order "Urutan level"
        string scheme_type "Skema loyalty"
        number points_threshold "Ambang batas per poin"
        number points_per_threshold "Poin per threshold"
        number stamps_required "Stamp untuk naik level"
        number stamp_per_transaction "Stamp per transaksi"
        number min_redemption_points "Minimal poin tukar reward"
        string reward_type "Jenis reward"
        number reward_value "Nilai reward"
        string reward_product_id "ID produk reward"
        string reward_product_name "Nama produk reward"
        number expiry_days "Masa kedaluwarsa poin"
    }

    ChatChannel {
        string company_id "ID perusahaan"
        string channel_name "Nama channel"
        string channel_type "Tipe channel"
        string description "Deskripsi channel"
        array members "Daftar member"
        array admins "Daftar admin"
        string created_by "Pembuat channel"
        boolean is_archived "Status diarsipkan"
        string last_message "Pesan terakhir"
        datetime last_message_at "Waktu pesan terakhir"
        number unread_count "Jumlah belum dibaca"
    }

    Discount {
        string company_id "ID perusahaan"
        string discount_name "Nama diskon"
        string discount_type "Tipe diskon"
        number value "Nilai diskon"
        number buy_quantity "Jumlah beli"
        number get_quantity "Jumlah gratis"
        number min_purchase_amount "Minimum pembelian"
        number max_discount_amount "Batas maksimal diskon"
        string applies_to "Berlaku untuk"
        array product_ids "Daftar ID produk"
        array category_names "Daftar nama kategori"
        string coupon_code "Kode kupon"
        number usage_limit "Batas penggunaan"
        number used_count "Jumlah sudah dipakai"
        date start_date "Tanggal mulai"
        date end_date "Tanggal berakhir"
        boolean is_active "Status aktif"
        string description "Deskripsi diskon"
    }

    Voucher {
        string code "Kode voucher"
        string name "Nama voucher"
        string description "Penjelasan voucher"
        string discount_type "Jenis potongan"
        number discount_value "Nilai potongan"
        number min_purchase "Minimum pembelian"
        number max_discount "Maksimum potongan"
        number usage_limit "Batas penggunaan"
        number usage_count "Jumlah sudah dipakai"
        datetime valid_from "Tanggal mulai aktif"
        datetime valid_until "Tanggal berakhir"
        array applicable_plans "Paket yang berlaku"
        boolean is_active "Status aktif"
        string created_by "Pembuat voucher"
    }

    Referral {
        string referrer_id "ID pengundang"
        string referee_id "ID yang diundang"
        string referee_email "Email yang diundang"
        string referee_name "Nama yang diundang"
        string description "Catatan referral"
        string status "Status undangan"
    }

    StockAlert {
        string company_id "ID perusahaan"
        string inventory_id "ID inventori"
        string product_id "ID produk"
        string product_name "Nama produk"
        string location_id "ID lokasi"
        string location_name "Nama lokasi"
        string alert_type "Tipe alert"
        number current_quantity "Jumlah saat ini"
        number threshold_quantity "Jumlah threshold"
        string severity "Tingkat keparahan"
        string status "Status alert"
        string title "Ringkasan alert"
        string description "Penjelasan detail"
        string recommended_action "Tindakan disarankan"
        string fingerprint "Key anti duplikasi"
        string source "Asal pembuat alert"
        string entity_ref_id "ID entitas terkait"
        array movement_ids "ID StockMovement terkait"
        datetime detected_at "Waktu terdeteksi"
        string acknowledged_by "Diakui oleh"
        datetime acknowledged_at "Waktu diakui"
        datetime resolved_at "Waktu diselesaikan"
        boolean auto_reorder_triggered "Auto reorder aktif"
        string notes "Catatan"
    }

    SalesPipeline {
        string company_id "ID perusahaan"
        string lead_id "ID prospek"
        string lead_name "Nama prospek"
        string lead_email "Email prospek"
        string lead_phone "Telepon prospek"
        string company_name "Nama perusahaan prospek"
        string assigned_to "ID sales person"
        string pipeline_stage "Stage pipeline"
        number estimated_value "Perkiraan nilai penjualan"
        string currency "Mata uang"
        number probability "Probabilitas konversi"
        date expected_close_date "Tanggal penutupan diharapkan"
        date actual_close_date "Tanggal penutupan aktual"
        string source_lead "Sumber prospek"
        array product_interest "Produk diminati"
        array interaction_history "Riwayat interaksi"
        string next_action "Aksi selanjutnya"
        date next_action_date "Tanggal aksi selanjutnya"
        string notes "Catatan"
    }

    WorkflowAutomation ||--o{ Notification : "mengirim notifikasi"
    WorkflowAutomation ||--o{ ChatChannel : "mengirim pesan channel"
    WorkflowAutomation }o--|| Customer : "dipicu oleh aktivitas customer"
    WorkflowAutomation }o--|| StockAlert : "dipicu oleh alert stok"
    Automation }o--|| ChatChannel : "beroperasi dalam workspace"
    Customer ||--o{ CustomerLoyaltyLedger : "memiliki riwayat loyalty"
    Customer }o--o| CustomerMembership : "memiliki level membership"
    Customer ||--o{ EmailCampaign : "menerima kampanye email"
    Customer ||--o{ SalesPipeline : "masuk pipeline penjualan"
    Customer ||--o{ Referral : "melakukan referral"
    Customer ||--o{ NewsletterSubscriber : "berlangganan newsletter"
    EmailCampaign }o--o| Discount : "menggunakan diskon"
    EmailCampaign }o--o| Voucher : "menggunakan voucher"
    CustomerMembership ||--o{ Discount : "mendapat diskon member"
    CustomerMembership ||--o{ Voucher : "mendapat voucher member"
    StockAlert ||--o{ Notification : "memicu notifikasi"
    SalesPipeline ||--o{ Notification : "memicu notifikasi pipeline"
```

***

## Entity Schema Tables

### WorkflowAutomation

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | No | ID perusahaan (null = personal) |
| `user_id` | string | Yes | Email pemilik workflow |
| `name` | string | Yes | Nama workflow automation |
| `description` | string | No | Deskripsi workflow |
| `trigger_type` | string (enum) | Yes | Jenis trigger workflow — 15 opsi tersedia |
| `trigger_conditions` | object | No | Kondisi tambahan trigger (mis: status=completed, days\_before=3) |
| `actions` | array | No | Daftar aksi yang dijalankan saat trigger terpicu |
| `is_active` | boolean | No | Status aktif workflow (default: true) |
| `last_triggered_at` | datetime | No | Waktu terakhir trigger dijalankan |
| `trigger_count` | number | No | Jumlah total trigger sudah dijalankan (default: 0) |

### Automation

| Field | Type | Required | Description |
| - | - | - | - |
| `workspace_id` | string | Yes | ID workspace tempat automasi beroperasi |
| `name` | string | Yes | Nama automasi |
| `description` | string | No | Penjelasan tentang tujuan dan cara kerja automasi ini (maks 1000 karakter) |
| `trigger_type` | string (enum) | Yes | Jenis trigger — 5 opsi tersedia |
| `trigger_conditions` | object | No | Kondisi trigger yang harus dipenuhi |
| `action_type` | string (enum) | Yes | Jenis aksi yang dijalankan — 5 opsi tersedia |
| `action_properties` | object | No | Properti aksi berupa konfigurasi detail |
| `is_active` | boolean | No | Status aktif automasi (default: true) |

### Customer

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Yes | ID perusahaan pemilik data customer |
| `name` | string | Yes | Nama lengkap customer |
| `email` | string | No | Alamat email customer |
| `phone` | string | Yes | Nomor telepon customer |
| `whatsapp_number` | string | No | Nomor WhatsApp untuk follow up |
| `company` | string | No | Nama perusahaan customer (B2B) |
| `address` | string | No | Alamat lengkap customer |
| `customer_type` | string (enum) | No | Tipe customer (default: individual) |
| `membership_level_id` | string | No | ID level membership customer |
| `membership_level_name` | string | No | Nama level membership |
| `membership_since` | date | No | Sejak kapan menjadi member |
| `membership_points` | number | No | Total poin member saat ini (default: 0) |
| `lifetime_points` | number | No | Total poin sepanjang waktu (default: 0) |
| `stamps` | number | No | Total stamp yang dimiliki saat ini (default: 0) |
| `has_negative_points` | boolean | No | Flag saldo negatif akibat pembatalan/void transaksi (default: false) |
| `loyalty_deficit_points` | number | No | Defisit poin loyalty yang membutuhkan rekonsiliasi manual (default: 0) |
| `loyalty_review_notes` | string | No | Catatan review penanganan loyalty deficit |
| `last_tier_upgrade_date` | datetime | No | Waktu perubahan level membership terakhir |
| `last_tier_upgrade_reason` | string | No | Alasan perubahan level membership |
| `last_tier_upgrade_by` | string | No | Email operator/admin yang melakukan perubahan tier |
| `status` | string (enum) | No | Status customer (default: lead) |
| `source` | string | No | Sumber customer (ads, referral, walk-in, dll) |
| `tags` | array | No | Tag untuk kategorisasi customer |
| `lifetime_value` | number | No | Total nilai transaksi sepanjang waktu (default: 0) |
| `total_orders` | number | No | Jumlah transaksi (default: 0) |
| `average_order_value` | number | No | Rata-rata nilai transaksi (default: 0) |
| `last_purchase_date` | date | No | Tanggal pembelian terakhir |
| `last_contact_date` | date | No | Terakhir kali di-follow up |
| `last_contact_method` | string (enum) | No | Metode terakhir follow up |
| `last_contact_notes` | string | No | Catatan follow up terakhir |
| `birthday` | date | No | Tanggal ulang tahun customer |
| `preferences` | object | No | Preferensi customer (kontak, pembayaran, bahasa) |
| `notes` | string | No | Catatan umum mengenai customer |
| `auth_user_id` | string | No | ID autentikasi dari Auth provider |
| `default_address_id` | string | No | ID alamat default di buku alamat |
| `addresses` | array | No | Buku alamat tersimpan customer |
| `billing_address` | string | No | Alamat penagihan resmi perusahaan/customer B2B |
| `shipping_address` | string | No | Alamat pengiriman default B2B |
| `parent_customer_id` | string | No | ID perusahaan induk untuk outlet/cabang retailer |
| `outlet_name` | string | No | Nama cabang/outlet |
| `tax_id` | string | No | NPWP/Identitas administrasi pajak |
| `payment_terms` | string (enum) | No | Ketentuan pembayaran B2B (default: net\_30) |
| `payment_terms_days` | number | No | Jumlah hari jatuh tempo pembayaran (default: 30) |
| `credit_limit` | number | No | Batas plafon riutang kredit B2B (default: 0) |
| `is_active` | boolean | No | Status aktif customer B2B (default: true) |

### Notification

| Field | Type | Required | Description |
| - | - | - | - |
| `user_id` | string | Yes | Email pengguna yang menerima notifikasi |
| `title` | string | Yes | Judul notifikasi |
| `message` | string | Yes | Pesan notifikasi |
| `description` | string | No | Detail tambahan atau konteks dari notifikasi ini (maks 1000 karakter) |
| `url` | string | No | URL tujuan saat notifikasi diklik |
| `type` | string (enum) | No | Tipe notifikasi untuk menentukan render aksi (default: SYSTEM) |
| `metadata` | object | No | Payload tambahan untuk notifikasi (invitationId, companyId, companyName) |
| `priority` | string (enum) | No | Prioritas notifikasi (default: normal) |
| `is_read` | boolean | No | Status apakah notifikasi sudah dibaca (default: false) |
| `event_id` | string | No | Idempotency key — notif duplikat dengan event\_id sama diabaikan |
| `company_id` | string | No | ID perusahaan untuk scope filter |
| `location_id` | string | No | ID lokasi untuk scope filter (opsional) |
| `source_entity` | string | No | Nama entity sumber (POSTransaction, Invoice, ProductionBatch, dll) |
| `source_id` | string | No | ID record sumber |
| `correlation_id` | string | No | Correlation ID dari request kritis untuk observability |

### EmailCampaign

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | No | ID perusahaan pemilik kampanye |
| `campaign_name` | string | Yes | Nama kampanye email |
| `subject` | string | Yes | Subjek email yang dikirim |
| `content` | string | Yes | HTML email content |
| `recipient_list` | array | No | Array of customer emails penerima |
| `send_date` | datetime | No | Tanggal dan waktu pengiriman |
| `status` | string (enum) | No | Status kampanye (default: draft) |
| `sent_count` | number | No | Jumlah email terkirim (default: 0) |
| `opened_count` | number | No | Jumlah email dibuka penerima (default: 0) |
| `clicked_count` | number | No | Jumlah link diklik penerima (default: 0) |
| `template_id` | string | No | ID template email yang digunakan |

### NewsletterSubscriber

| Field | Type | Required | Description |
| - | - | - | - |
| `email` | string | Yes | Email subscriber |
| `name` | string | No | Nama subscriber (opsional) |
| `description` | string | No | Catatan atau preferensi konten yang diinginkan subscriber (maks 1000 karakter) |
| `subscribed_from` | string (enum) | No | Dari halaman mana subscribe (default: blog) |
| `is_active` | boolean | No | Status aktif subscription (default: true) |
| `unsubscribed_date` | datetime | No | Tanggal unsubscribe |
| `interests` | array | No | Topik yang diminati subscriber |

### CustomerLoyaltyLedger

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Yes | ID perusahaan |
| `customer_id` | string | Yes | ID customer pemilik transaksi loyalty |
| `customer_name` | string | No | Nama customer saat transaksi |
| `customer_phone` | string | No | Nomor telepon/kontak customer |
| `transaction_id` | string | No | ID transaksi POS atau referensi sale asal |
| `transaction_number` | string | No | Nomor struk/receipt number transaksi |
| `idempotency_key` | string | Yes | Idempotency key untuk mencegah double crediting/posting |
| `event_type` | string (enum) | Yes | Tipe event mutasi loyalty |
| `scheme_type` | string (enum) | No | Skema loyalty yang berlaku (default: points) |
| `points_delta` | number | No | Perubahan poin (+ bertambah, - berkurang) (default: 0) |
| `points_before` | number | No | Saldo poin sebelum event (default: 0) |
| `points_after` | number | No | Saldo poin setelah event (default: 0) |
| `stamps_delta` | number | No | Perubahan stamp (+ bertambah, - berkurang) (default: 0) |
| `stamps_before` | number | No | Saldo stamp sebelum event (default: 0) |
| `stamps_after` | number | No | Saldo stamp setelah event (default: 0) |
| `eligible_amount` | number | No | Nilai transaksi yang sah/eligible untuk perolehan poin (default: 0) |
| `reason` | string | No | Alasan atau keterangan mutasi loyalty |
| `deficit_points` | number | No | Defisit poin jika poin telah terpakai sebelum void/return (default: 0) |
| `requires_manual_review` | boolean | No | Flag jika reversal menghasilkan saldo negatif (default: false) |
| `reward_details` | object | No | Detail reward jika event adalah redeem |
| `performed_by` | string | No | Email atau ID operator yang memproses |
| `actor_role` | string | No | Role aktor (owner, admin, cashier) |
| `created_at` | datetime | No | Waktu event tercatat di server |
| `finance_record_id` | string | No | ID FinancialRecord (biaya COGS reward) yang terhubung |

### CustomerMembership

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Yes | ID perusahaan |
| `level_name` | string | Yes | Nama level (Silver, Gold, Platinum, dll) |
| `level_key` | string | Yes | Key unik untuk level (silver, gold, platinum) |
| `icon` | string | No | Icon emoji untuk level |
| `color` | string | No | Warna untuk level |
| `description` | string | No | Penjelasan mengenai keuntungan dan syarat keanggotaan (maks 1000 karakter) |
| `discount_percentage` | number | No | Diskon % untuk member level ini 0-100 (default: 0) |
| `points_multiplier` | number | No | Multiplier poin yang didapat (default: 1) |
| `min_purchase` | number | No | Minimum pembelian untuk mendapat level ini (default: 0) |
| `benefits` | array | No | List benefit yang didapat member |
| `priority_support` | boolean | No | Akses priority support via WhatsApp (default: false) |
| `free_delivery` | boolean | No | Gratis ongkir (default: false) |
| `birthday_bonus` | number | No | Bonus poin di hari ulang tahun (default: 0) |
| `is_active` | boolean | No | Status aktif level (default: true) |
| `order` | number | No | Urutan level (semakin tinggi semakin premium) (default: 0) |
| `scheme_type` | string (enum) | No | Skema loyalty yang berlaku pada tier ini (default: points) |
| `points_threshold` | number | No | Ambang batas belanja per perolehan poin (default: 10000) |
| `points_per_threshold` | number | No | Jumlah poin yang diperoleh per threshold (default: 1) |
| `stamps_required` | number | No | Jumlah stamp untuk reward atau naik level (default: 10) |
| `stamp_per_transaction` | number | No | Jumlah stamp diperoleh per transaksi eligible (default: 1) |
| `min_redemption_points` | number | No | Minimal poin untuk penukaran reward (default: 0) |
| `reward_type` | string (enum) | No | Jenis reward yang dapat ditukarkan (default: none) |
| `reward_value` | number | No | Nilai reward (persen/nominal diskon) (default: 0) |
| `reward_product_id` | string | No | ID produk reward gratis jika reward\_type = free\_product |
| `reward_product_name` | string | No | Nama produk reward gratis |
| `expiry_days` | number | No | Masa kedaluwarsa poin dalam hari (opsional) |

### ChatChannel

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Yes | ID perusahaan |
| `channel_name` | string | Yes | Nama channel |
| `channel_type` | string (enum) | Yes | Tipe channel (default: public) |
| `description` | string | No | Deskripsi channel |
| `members` | array | No | Array of member emails |
| `admins` | array | No | Array of admin emails |
| `created_by` | string | No | Email pembuat channel |
| `is_archived` | boolean | No | Status channel diarsipkan (default: false) |
| `last_message` | string | No | Isi pesan terakhir |
| `last_message_at` | datetime | No | Waktu pesan terakhir dikirim |
| `unread_count` | number | No | Jumlah pesan belum dibaca (default: 0) |

### Discount

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Yes | ID perusahaan |
| `discount_name` | string | Yes | Nama diskon |
| `discount_type` | string (enum) | Yes | Tipe diskon (default: percentage) |
| `value` | number | Yes | Nilai diskon (% atau nominal) |
| `buy_quantity` | number | No | Untuk tipe buy\_x\_get\_y: jumlah beli |
| `get_quantity` | number | No | Untuk tipe buy\_x\_get\_y: jumlah gratis |
| `min_purchase_amount` | number | No | Minimum pembelian (default: 0) |
| `max_discount_amount` | number | No | Batas maksimal nilai diskon |
| `applies_to` | string (enum) | No | Berlaku untuk (default: all\_products) |
| `product_ids` | array | No | Daftar ID produk target |
| `category_names` | array | No | Daftar nama kategori target |
| `coupon_code` | string | No | Kode kupon unik |
| `usage_limit` | number | No | Batas penggunaan (0 = unlimited) |
| `used_count` | number | No | Jumlah sudah dipakai (default: 0) |
| `start_date` | date | No | Tanggal mulai berlaku |
| `end_date` | date | No | Tanggal berakhir |
| `is_active` | boolean | No | Status aktif diskon (default: true) |
| `description` | string | No | Deskripsi diskon |

### Voucher

| Field | Type | Required | Description |
| - | - | - | - |
| `code` | string | Yes | Kode voucher unik |
| `name` | string | Yes | Nama voucher |
| `description` | string | No | Penjelasan detail voucher, syarat, dan ketentuan (maks 1000 karakter) |
| `discount_type` | string (enum) | Yes | Jenis potongan: persentase atau jumlah tetap |
| `discount_value` | number | Yes | Nilai potongan (persentase 0-100 atau jumlah dalam rupiah) |
| `min_purchase` | number | No | Minimum pembelian untuk menggunakan voucher (default: 0) |
| `max_discount` | number | No | Maksimum potongan (untuk jenis persentase) |
| `usage_limit` | number | No | Batas penggunaan voucher (null = unlimited) |
| `usage_count` | number | No | Jumlah voucher sudah digunakan (default: 0) |
| `valid_from` | datetime | Yes | Tanggal mulai aktif voucher |
| `valid_until` | datetime | Yes | Tanggal berakhir voucher |
| `applicable_plans` | array | No | Paket yang bisa menggunakan voucher ini |
| `is_active` | boolean | No | Status aktif voucher (default: true) |
| `created_by` | string | No | Admin yang membuat voucher |

### Referral

| Field | Type | Required | Description |
| - | - | - | - |
| `referrer_id` | string | Yes | ID pengguna yang mengundang (referrer) |
| `referee_id` | string | Yes | ID pengguna yang diundang (referee) |
| `referee_email` | string | Yes | Email pengguna yang diundang |
| `referee_name` | string | No | Nama pengguna yang diundang |
| `description` | string | No | Catatan tambahan mengenai referral ini (maks 1000 karakter) |
| `status` | string (enum) | No | Status undangan (default: signed\_up) |

### StockAlert

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Yes | ID perusahaan |
| `inventory_id` | string | No | ID inventori |
| `product_id` | string | No | ID produk |
| `product_name` | string | No | Nama produk |
| `location_id` | string | No | ID lokasi |
| `location_name` | string | No | Nama lokasi |
| `alert_type` | string (enum) | Yes | Tipe alert — 11 opsi tersedia |
| `current_quantity` | number | No | Jumlah stok saat ini |
| `threshold_quantity` | number | No | Jumlah threshold untuk alert |
| `severity` | string (enum) | No | Tingkat keparahan (default: medium) |
| `status` | string (enum) | No | Status alert (default: active) |
| `title` | string | No | Ringkasan alert untuk tampilan daftar |
| `description` | string | No | Penjelasan detail anomali/kondisi |
| `recommended_action` | string | No | Tindakan yang disarankan sistem |
| `fingerprint` | string | No | Key stabil per anomali untuk mencegah notifikasi duplikat |
| `source` | string | No | Asal pembuat alert (mis. stock\_anomaly\_detector) |
| `entity_ref_id` | string | No | ID entitas terkait (LotBatch, StockMovement, dsb) |
| `movement_ids` | array | No | ID StockMovement yang memicu anomali |
| `detected_at` | datetime | No | Waktu anomali terdeteksi oleh scanner |
| `acknowledged_by` | string | No | User yang mengakui alert |
| `acknowledged_at` | datetime | No | Waktu alert diakui |
| `resolved_at` | datetime | No | Waktu alert diselesaikan |
| `auto_reorder_triggered` | boolean | No | Apakah auto reorder sudah dipicu (default: false) |
| `notes` | string | No | Catatan tambahan |

### SalesPipeline

| Field | Type | Required | Description |
| - | - | - | - |
| `company_id` | string | Yes | ID perusahaan |
| `lead_id` | string | No | ID prospek/lead |
| `lead_name` | string | Yes | Nama prospek |
| `lead_email` | string | No | Email prospek |
| `lead_phone` | string | No | Nomor telepon prospek |
| `company_name` | string | No | Nama perusahaan prospek |
| `assigned_to` | string | Yes | ID sales person yang ditugaskan |
| `pipeline_stage` | string (enum) | No | Stage dalam sales pipeline (default: prospect) |
| `estimated_value` | number | No | Perkiraan nilai penjualan |
| `currency` | string | No | Mata uang (default: IDR) |
| `probability` | number | No | Probabilitas konversi dalam % (default: 0) |
| `expected_close_date` | date | No | Tanggal penutupan yang diharapkan |
| `actual_close_date` | date | No | Tanggal penutupan aktual |
| `source_lead` | string (enum) | No | Sumber prospek |
| `product_interest` | array | No | Produk yang diminati prospek |
| `interaction_history` | array | No | Riwayat interaksi dengan prospek |
| `next_action` | string | No | Aksi selanjutnya yang harus dilakukan |
| `next_action_date` | date | No | Tanggal aksi selanjutnya |
| `notes` | string | No | Catatan mengenai pipeline |

***

## Siklus Hidup Automation Rule

```mermaid theme={null}
stateDiagram-v2
    [*] --> Draft: Workflow dibuat
    Draft --> Configuring: Mengisi trigger & action
    Configuring --> Draft: Reset konfigurasi
    Configuring --> Active: Toggle aktif
    Draft --> Active: Toggle aktif langsung

    Active --> Evaluating: Engine polling 2 menit
    Evaluating --> TriggerMatched: Kondisi trigger terpenuhi
    Evaluating --> NoMatch: Kondisi tidak terpenuhi
    NoMatch --> Active: Lanjut polling
    TriggerMatched --> ExecutingActions: Jalankan semua action
    ExecutingActions --> UpdatingCounter: Increment trigger_count
    UpdatingCounter --> Active: Selesai, tunggu trigger berikutnya

    Active --> Inactive: Toggle nonaktif
    Inactive --> Active: Toggle aktif kembali
    Inactive --> [*]: Hapus workflow
    Active --> [*]: Hapus workflow
```

***

## Sequence Diagrams

### 1. Alur Trigger Rule

```mermaid theme={null}
sequenceDiagram
    participant WE as WorkflowEngine
    participant WA as WorkflowAutomation
    participant TC as TriggerConditions
    participant ACT as Actions[]

    loop Setiap 2 menit
        WE->>WA: Load workflow aktif
        WA-->>WE: Return daftar workflow
        WE->>TC: Evaluasi trigger_type
        TC-->>WE: Cek kondisi trigger

        alt Trigger cocok
            WE->>WA: Ambil actions[]
            WA-->>WE: Return daftar action
            WE->>ACT: Eksekusi action[0]
            ACT-->>WE: Sukses
            WE->>ACT: Eksekusi action[1]
            ACT-->>WE: Sukses
            WE->>WA: Update trigger_count++
            WE->>WA: Set last_triggered_at
        else Trigger tidak cocok
            WE->>WA: Skip workflow ini
        end
    end
```

### 2. Alur Eksekusi Kampanye Email

```mermaid theme={null}
sequenceDiagram
    participant USR as User (Admin)
    participant EC as EmailCampaign
    participant CUST as Customer[]
    participant NS as NewsletterSubscriber
    participant NOTIF as Notification

    USR->>EC: Buat kampanye baru (draft)
    EC-->>USR: Return campaign_id

    USR->>EC: Set subject, content, recipient_list
    EC-->>USR: Konfirmasi update

    USR->>EC: Set status = scheduled, send_date
    EC-->>USR: Kampanye dijadwalkan

    Note over EC: Menunggu send_date tiba

    EC->>CUST: Kirim email ke recipient_list
    CUST-->>EC: Return sent_count

    alt Email dibuka
        CUST-->>EC: Update opened_count++
    end

    alt Link diklik
        CUST-->>EC: Update clicked_count++
    end

    EC->>NOTIF: Kirim notifikasi hasil kampanye
    NOTIF-->>USR: Admin menerima laporan

    alt Semua email terkirim
        EC->>EC: Set status = sent
    else Ada kegagalan
        EC->>EC: Set status = failed
    end
```

### 3. Alur Customer Journey (Loyalty & Membership)

```mermaid theme={null}
sequenceDiagram
    participant CUST as Customer
    participant POS as POSTransaction
    participant CLL as CustomerLoyaltyLedger
    participant CM as CustomerMembership
    participant C as Customer Entity
    participant NOTIF as Notification
    participant WA as WorkflowAutomation

    CUST->>POS: Lakukan transaksi
    POS->>CLL: Catat event_type = earn
    CLL->>CLL: Hitung points_delta & eligible_amount
    CLL->>C: Update membership_points += points_delta
    CLL->>C: Update lifetime_points += points_delta

    alt Points >= threshold naik tier
        CLL->>CM: Cek level berikutnya
        CM-->>CLL: Return level baru
        CLL->>C: Update membership_level_id
        CLL->>C: Set last_tier_upgrade_date
        CLL->>C: Set last_tier_upgrade_reason
        CLL->>CLL: Catat event_type = tier_upgrade
        CLL->>NOTIF: Notifikasi naik level ke customer
    end

    alt Customer menukarkan reward
        CUST->>POS: Request redeem poin
        POS->>CLL: Catat event_type = redeem
        CLL->>C: Update membership_points -= cost_points
        CLL->>CLL: Set reward_details
    end

    alt Transaksi dibatalkan (void)
        POS->>CLL: Catat event_type = return_reversal
        CLL->>C: Update membership_points -= points_delta
        alt Points jadi negatif
            CLL->>C: Set has_negative_points = true
            CLL->>C: Set loyalty_deficit_points
            CLL->>CLL: Set requires_manual_review = true
            CLL->>NOTIF: Notifikasi perlukan review manual
        end
    end

    WA->>WA: Evaluasi trigger employee_birthday
    alt Hari ulang tahun customer
        WA->>C: Cek birthday == today
        WA->>NOTIF: Kirim notifikasi ucapan ulang tahun
        WA->>C: Tambah birthday_bonus poin
    end
```

### 4. Alur Pipeline Sales & Lead Automation

```mermaid theme={null}
sequenceDiagram
    participant LEAD as Lead/Prospek
    participant SP as SalesPipeline
    participant WA as WorkflowAutomation
    participant NOTIF as Notification
    participant CC as ChatChannel
    participant CUST as Customer

    LEAD->>SP: Masuk dari sumber (website/referral/ads)
    SP->>SP: Set pipeline_stage = prospect
    SP->>SP: Assign assigned_to (sales person)

    WA->>WA: Evaluasi trigger (schedule_daily)
    WA->>SP: Cek lead tanpa follow up > 3 hari

    alt Lead perlu follow up
        WA->>NOTIF: Kirim reminder ke sales person
        WA->>CC: Kirim pesan ke channel #sales
    end

    SP->>SP: Update pipeline_stage = qualified
    SP->>SP: Catat interaction_history

    alt Prospek setuju
        SP->>SP: Update pipeline_stage = won
        SP->>CUST: Konversi lead jadi Customer
        CUST->>CUST: Set status = customer
        WA->>NOTIF: Notifikasi ke tim sales: deal won
    else Prospek menolak
        SP->>SP: Update pipeline_stage = lost
        WA->>NOTIF: Notifikasi ke sales person
    end

    alt Referral dari customer existing
        CUST->>LEAD: Referensikan prospek baru
        SP->>SP: Set source_lead = referral
        WA->>WA: Trigger referral tracking
    end
```

***

## Referensi Enum

### WorkflowAutomation — `trigger_type`

| Nilai | Deskripsi |
| - | - |
| `task_created` | Task baru dibuat di modul Tasks |
| `task_status_changed` | Status task berubah (misal: todo → in\_progress) |
| `task_due_approaching` | Deadline task semakin mendekat |
| `task_overdue` | Task melewati batas deadline |
| `invoice_created` | Invoice baru dibuat di modul Finance |
| `invoice_overdue` | Invoice melewati tanggal jatuh tempo |
| `new_chat_mention` | Ada mention baru di chat internal |
| `pos_transaction` | Transaksi POS baru terjadi |
| `low_stock` | Stok produk berada di bawah threshold |
| `employee_birthday` | Ulang tahun karyawan/customer hari ini |
| `leave_request` | Pengajuan cuti baru masuk |
| `kpi_target_missed` | Target KPI tidak tercapai |
| `schedule_daily` | Trigger terjadwal harian |
| `schedule_weekly` | Trigger terjadwal mingguan |
| `schedule_monthly` | Trigger terjadwal bulanan |

### WorkflowAutomation — `actions[].action_type`

| Nilai | Deskripsi |
| - | - |
| `send_notification` | Kirim notifikasi in-app ke pengguna |
| `send_chat_message` | Kirim pesan ke channel chat internal |
| `create_task` | Buat task baru secara otomatis |
| `change_task_status` | Ubah status task yang sudah ada |
| `assign_task` | Tetapkan task ke pengguna tertentu |
| `create_notification_all_members` | Kirim notifikasi ke seluruh anggota perusahaan |

### Automation — `trigger_type`

| Nilai | Deskripsi |
| - | - |
| `task_created` | Task baru dibuat dalam workspace |
| `task_status_changed` | Status task berubah dalam workspace |
| `task_due_approaching` | Deadline task dalam workspace semakin dekat |
| `user_assigned` | Pengguna ditugaskan ke task |
| `file_uploaded` | File diunggah ke workspace |

### Automation — `action_type`

| Nilai | Deskripsi |
| - | - |
| `change_status` | Ubah status task secara otomatis |
| `assign_user` | Tetapkan task ke pengguna tertentu |
| `send_notification` | Kirim notifikasi ke pengguna |
| `create_subtask` | Buat sub-task baru secara otomatis |
| `move_to_workspace` | Pindahkan task ke workspace lain |

### Customer — `customer_type`

| Nilai | Deskripsi |
| - | - |
| `individual` | Customer perorangan |
| `business` | Customer perusahaan (B2B) |
| `retail` | Customer ritel/end-user |
| `reseller` | Reseller yang menjual kembali produk |
| `distributor` | Distributor wilayah |
| `modern_market` | Pasar modern (minimarket, supermarket) |

### Customer — `status`

| Nilai | Deskripsi |
| - | - |
| `lead` | Prospek yang belum dikonversi |
| `prospect` | Prospek yang sedang di-follow up |
| `customer` | Sudah menjadi customer aktif |
| `inactive` | Customer tidak aktif lagi |

### Customer — `last_contact_method`

| Nilai | Deskripsi |
| - | - |
| `phone` | Follow up melalui telepon |
| `whatsapp` | Follow up melalui WhatsApp |
| `email` | Follow up melalui email |
| `meeting` | Follow up melalui pertemuan langsung |

### Customer — `payment_terms`

| Nilai | Deskripsi |
| - | - |
| `cash` | Pembayaran tunai |
| `net_7` | Jatuh tempo 7 hari |
| `net_14` | Jatuh tempo 14 hari |
| `net_30` | Jatuh tempo 30 hari |
| `net_60` | Jatuh tempo 60 hari |
| `custom` | Ketentuan pembayaran khusus |

### Customer — `preferences.preferred_contact`

| Nilai | Deskripsi |
| - | - |
| `phone` | Preferensi kontak via telepon |
| `whatsapp` | Preferensi kontak via WhatsApp |
| `email` | Preferensi kontak via email |

### Notification — `type`

| Nilai | Deskripsi |
| - | - |
| `SYSTEM` | Notifikasi sistem umum |
| `INVITATION` | Undangan bergabung perusahaan |
| `TASK` | Notifikasi terkait task |
| `STOCK` | Notifikasi terkait stok |
| `INVOICE` | Notifikasi terkait invoice |
| `WORKFLOW` | Notifikasi terkait workflow automation |
| `ANNOUNCEMENT` | Pengumuman dari admin |
| `ORDER` | Notifikasi terkait pesanan |
| `PAYMENT` | Notifikasi terkait pembayaran |
| `LOW_STOCK` | Peringatan stok rendah |
| `DISCREPANCY` | Notifikasi ketidaksesuaian data |
| `EXPIRY` | Peringatan produk mendekati kedaluwarsa |
| `BACKUP` | Notifikasi terkait backup data |
| `BTT_PENDING` | Notifikasi BTT menunggu persetujuan |
| `PAYMENT_DUE` | Peringatan jatuh tempo pembayaran |
| `RECALL` | Notifikasi penarikan produk |

### Notification — `priority`

| Nilai | Deskripsi |
| - | - |
| `low` | Prioritas rendah — tidak mendesak |
| `normal` | Prioritas normal — standar |
| `high` | Prioritas tinggi — perlu perhatian segera |

### EmailCampaign — `status`

| Nilai | Deskripsi |
| - | - |
| `draft` | Kampanye masih dalam tahap draf |
| `scheduled` | Kampanye dijadwalkan untuk dikirim |
| `sent` | Kampanye berhasil terkirim |
| `failed` | Kampanye gagal terkirim |

### NewsletterSubscriber — `subscribed_from`

| Nilai | Deskripsi |
| - | - |
| `blog` | Subscribe dari halaman blog |
| `home` | Subscribe dari halaman utama |
| `about` | Subscribe dari halaman tentang |
| `partnership` | Subscribe dari halaman partnership |
| `other` | Subscribe dari halaman lainnya |

### CustomerLoyaltyLedger — `event_type`

| Nilai | Deskripsi |
| - | - |
| `earn` | Perolehan poin dari transaksi |
| `redeem` | Penukaran poin menjadi reward |
| `return_reversal` | Pembatalan poin akibat retur/void |
| `tier_upgrade` | Kenaikan tier membership |
| `manual_adjustment` | Penyesuaian poin manual oleh operator |

### CustomerLoyaltyLedger — `scheme_type`

| Nilai | Deskripsi |
| - | - |
| `points` | Skema berbasis poin transaksi |
| `stamp` | Skema berbasis stempel per transaksi |
| `spending` | Skema berbasis total belanja |
| `visits` | Skema berbasis jumlah kunjungan |
| `hybrid` | Skema kombinasi beberapa metode |

### CustomerMembership — `scheme_type`

| Nilai | Deskripsi |
| - | - |
| `points` | Tier ditentukan oleh akumulasi poin |
| `stamp` | Tier ditentukan oleh jumlah stamp |
| `spending` | Tier ditentukan oleh total belanja |
| `visits` | Tier ditentukan oleh frekuensi kunjungan |
| `hybrid` | Tier ditentukan oleh kombinasi metode |

### CustomerMembership — `reward_type`

| Nilai | Deskripsi |
| - | - |
| `none` | Tidak ada reward yang dapat ditukar |
| `discount_percentage` | Reward berupa diskon persentase |
| `discount_amount` | Reward berupa potongan nominal |
| `free_product` | Reward berupa produk gratis |

### ChatChannel — `channel_type`

| Nilai | Deskripsi |
| - | - |
| `public` | Channel terbuka untuk semua anggota |
| `private` | Channel terbatas untuk anggota tertentu |
| `direct` | Channel percakapan langsung antar pengguna |

### Discount — `discount_type`

| Nilai | Deskripsi |
| - | - |
| `percentage` | Diskon dalam bentuk persentase |
| `fixed_amount` | Diskon dalam bentuk nominal tetap |
| `buy_x_get_y` | Beli X gratis Y produk |
| `coupon_code` | Diskon dengan memasukkan kode kupon |

### Discount — `applies_to`

| Nilai | Deskripsi |
| - | - |
| `all_products` | Berlaku untuk semua produk |
| `specific_products` | Berlaku untuk produk tertentu saja |
| `specific_categories` | Berlaku untuk kategori tertentu saja |

### Voucher — `discount_type`

| Nilai | Deskripsi |
| - | - |
| `percentage` | Potongan dalam bentuk persentase |
| `fixed_amount` | Potongan dalam bentuk nominal tetap |

### Voucher — `applicable_plans[]`

| Nilai | Deskripsi |
| - | - |
| `pro` | Berlaku untuk paket Pro |
| `business` | Berlaku untuk paket Business |
| `advanced` | Berlaku untuk paket Advanced |
| `enterprise` | Berlaku untuk paket Enterprise |

### Referral — `status`

| Nilai | Deskripsi |
| - | - |
| `signed_up` | Referee sudah mendaftar melalui undangan |
| `purchased` | Referee sudah melakukan pembelian pertama |

### StockAlert — `alert_type`

| Nilai | Deskripsi |
| - | - |
| `low_stock` | Stok berada di bawah threshold minimum |
| `out_of_stock` | Stok habis sepenuhnya |
| `overstock` | Stok berlebih di atas kapasitas |
| `expiring_soon` | Produk mendekati tanggal kedaluwarsa |
| `reconciliation_needed` | Diperlukan rekonsiliasi data stok |
| `negative_stock` | Stok menunjukkan nilai negatif (anomali) |
| `rapid_depletion` | Stok berkurang sangat cepat |
| `orphaned_movement` | Pergerakan stok tanpa referensi yang jelas |
| `duplicate_movement` | Pergerakan stok terdeteksi duplikat |
| `futuristic_date` | Tanggal pergerakan stok di masa depan |
| `lot_negative` | Qty lot/batch menunjukkan nilai negatif |

### StockAlert — `severity`

| Nilai | Deskripsi |
| - | - |
| `low` | Keparahan rendah — pantauan berkala |
| `medium` | Keparahan sedang — perlu ditinjau |
| `high` | Keparahan tinggi — perlu tindakan segera |
| `critical` | Keparahan kritis — harus ditangani sekarang |

### StockAlert — `status`

| Nilai | Deskripsi |
| - | - |
| `active` | Alert aktif dan belum ditindaklanjuti |
| `acknowledged` | Alert sudah diakui oleh pengguna |
| `dismissed` | Alert diabaikan karena tidak relevan |
| `resolved` | Alert sudah diselesaikan sepenuhnya |

### SalesPipeline — `pipeline_stage`

| Nilai | Deskripsi |
| - | - |
| `prospect` | Tahap awal — prospek baru masuk |
| `qualified` | Prospek sudah terqualifikasi |
| `proposal` | Proposal sedang disiapkan/dikirim |
| `negotiation` | Sedang dalam tahap negosiasi |
| `won` | Deal berhasil dimenangkan |
| `lost` | Deal gagal atau prospek menolak |

### SalesPipeline — `source_lead`

| Nilai | Deskripsi |
| - | - |
| `website` | Prospek berasal dari website |
| `referral` | Prospek berasal dari referensi |
| `advertisement` | Prospek berasal dari iklan |
| `cold_call` | Prospek berasal dari telepon langsung |
| `social_media` | Prospek berasal dari media sosial |
| `event` | Prospek berasal dari acara/event |
| `other` | Prospek berasal dari sumber lainnya |

### SalesPipeline — `interaction_history[].interaction_type`

| Nilai | Deskripsi |
| - | - |
| `call` | Interaksi melalui panggilan telepon |
| `email` | Interaksi melalui email |
| `meeting` | Interaksi melalui pertemuan langsung |
| `message` | Interaksi melalui pesan teks/chat |

***

## RBAC Permission Matrix

Berikut adalah matriks permission berbasis role (Role-Based Access Control) untuk setiap entitas yang terlibat dalam sistem Automation. Permission ditentukan berdasarkan kombinasi `User.role`, `WorkspaceMember.role`, dan `admin_type`/`admin_tier`.

### Automation (Level Workspace)

| Role | Create | Read | Update | Delete | Keterangan |
| - | - | - | - | - | - |
| Owner (Workspace) | Ya | Ya | Ya | Ya | Kontrol penuh atas automasi di workspace |
| Admin (Workspace) | Ya | Ya | Ya | Ya | Bisa mengelola automasi di workspace |
| Member (Workspace) | Ya | Ya | Ya (milik sendiri) | Tidak | Bisa buat automasi sendiri, hanya edit milik sendiri |
| Viewer (Workspace) | Tidak | Ya | Tidak | Tidak | Hanya bisa melihat automasi buatkan oleh orang lain |
| Non-member | Tidak | Tidak | Tidak | Tidak | Tidak memiliki akses ke workspace ini |

### WorkflowAutomation (Level Company)

| Role | Create | Read | Update | Delete | Keterangan |
| - | - | - | - | - | - |
| Admin (Company) | Ya | Ya | Ya | Ya | Kontrol penuh atas workflow automation company |
| User (Company member) | Ya | Ya (milik sendiri) | Ya (milik sendiri) | Ya (milik sendiri) | Bisa buat dan kelola workflow sendiri |
| User (Other company) | Tidak | Tidak | Tidak | Tidak | Tidak bisa akses workflow company lain |

### EmailCampaign

| Role | Create | Read | Update | Delete | Keterangan |
| - | - | - | - | - | - |
| Admin (Company) | Ya | Ya (semua) | Ya (semua) | Ya (semua) | Kontrol penuh atas semua campaign di company |
| User (Marketing) | Ya | Ya (milik sendiri) | Ya (milik sendiri) | Ya (milik sendiri) | Bisa kelola campaign yang dibuat sendiri |
| User (Other) | Tidak | Tidak | Tidak | Tidak | Tidak memiliki akses ke campaign |

### NewsletterSubscriber

| Role | Create | Read | Update | Delete | Keterangan |
| - | - | - | - | - | - |
| Admin | Ya | Ya | Ya | Ya | Kontrol penuh atas daftar subscriber |
| User (Marketing) | Ya | Ya | Ya | Tidak | Bisa kelola subscriber tapi tidak bisa hapus |
| Public (self) | Ya (subscribe) | Tidak | Tidak | Ya (unsubscribe) | Hanya bisa subscribe dan unsubscribe diri sendiri |

### Notification

| Role | Create | Read | Update | Delete | Keterangan |
| - | - | - | - | - | - |
| Admin | Ya | Ya (semua) | Ya (semua) | Ya (semua) | Bisa kirim announcement dan kelola semua notifikasi |
| User | Tidak | Ya (milik sendiri) | Ya (mark as read) | Tidak | Hanya bisa baca dan update status baca notifikasi sendiri |
| System (WorkflowEngine) | Ya | Ya | Tidak | Tidak | Otomatis kirim notifikasi dari workflow\_alert dan system events |

### ChatChannel

| Role | Create | Read | Update | Delete | Keterangan |
| - | - | - | - | - | - |
| Admin (Company) | Ya | Ya (semua) | Ya (semua) | Ya (semua) | Kontrol penuh atas semua channel di company |
| Admin (Channel) | Ya | Ya | Ya (channel sendiri) | Tidak | Bisa kelola channel yang di-admin |
| Member (Channel) | Tidak | Ya (channel sendiri) | Tidak | Tidak | Hanya bisa membaca dan mengirim pesan di channel |
| Non-member | Tidak | Tidak | Tidak | Tidak | Tidak bisa akses channel privat |

### Customer

| Role | Create | Read | Update | Delete | Keterangan |
| - | - | - | - | - | - |
| Admin (Company) | Ya | Ya (semua) | Ya (semua) | Ya (semua) | Kontrol penuh atas data customer |
| User (Sales/Marketing) | Ya | Ya (assigned) | Ya (assigned) | Tidak | Bisa tambah dan kelola customer yang di-assign |
| User (Other) | Tidak | Ya (limited) | Tidak | Tidak | Hanya bisa lihat data customer terbatas |

### CustomerLoyaltyLedger

| Role | Create | Read | Update | Delete | Keterangan |
| - | - | - | - | - | - |
| Admin (Company) | Ya | Ya (semua) | Ya (semua) | Ya (semua) | Kontrol penuh atas ledger loyalty |
| Cashier (POS) | Ya | Ya (transaksi sendiri) | Tidak | Tidak | Bisa catat event loyalty dari transaksi POS |
| User (Other) | Tidak | Ya (customer sendiri) | Tidak | Tidak | Hanya bisa lihat riwayat loyalty customer terkait |

### CustomerMembership

| Role | Create | Read | Update | Delete | Keterangan |
| - | - | - | - | - | - |
| Admin (Company) | Ya | Ya | Ya | Ya | Bisa konfigurasi level membership dan skema loyalty |
| User (Marketing) | Tidak | Ya | Ya (limited) | Tidak | Bisa lihat dan update level customer |
| User (Other) | Tidak | Ya (level sendiri) | Tidak | Tidak | Hanya bisa lihat level membership sendiri |

### Discount

| Role | Create | Read | Update | Delete | Keterangan |
| - | - | - | - | - | - |
| Admin (Company) | Ya | Ya | Ya | Ya | Kontrol penuh atas diskon |
| User (Marketing) | Ya | Ya | Ya | Tidak | Bisa buat dan kelola diskon tapi tidak hapus |
| Cashier (POS) | Tidak | Ya (apply) | Tidak | Tidak | Hanya bisa apply diskon saat transaksi |

### Voucher

| Role | Create | Read | Update | Delete | Keterangan |
| - | - | - | - | - | - |
| Admin (Company) | Ya | Ya | Ya | Ya | Kontrol penuh atas voucher |
| User (Marketing) | Ya | Ya | Ya | Tidak | Bisa buat dan kelola voucher tapi tidak hapus |
| User (Other) | Tidak | Ya (available) | Tidak | Tidak | Hanya bisa lihat voucher yang tersedia untuk digunakan |

### StockAlert

| Role | Create | Read | Update | Delete | Keterangan |
| - | - | - | - | - | - |
| Admin (Company) | Ya | Ya (semua) | Ya (semua) | Ya (semua) | Kontrol penuh atas semua alert stok |
| User (Inventory) | Tidak | Ya (semua) | Ya (acknowledge/resolve) | Tidak | Bisa acknowledge dan resolve alert |
| User (Other) | Tidak | Ya (limited) | Tidak | Tidak | Hanya bisa lihat alert stok secara terbatas |

### SalesPipeline

| Role | Create | Read | Update | Delete | Keterangan |
| - | - | - | - | - | - |
| Admin (Company) | Ya | Ya (semua) | Ya (semua) | Ya (semua) | Kontrol penuh atas pipeline penjualan |
| User (Sales) | Ya | Ya (assigned) | Ya (assigned) | Ya (milik sendiri) | Bisa kelola pipeline yang di-assign |
| User (Other) | Tidak | Ya (limited) | Tidak | Tidak | Hanya bisa lihat pipeline secara terbatas |

### Referral

| Role | Create | Read | Update | Delete | Keterangan |
| - | - | - | - | - | - |
| Admin | Ya | Ya (semua) | Ya (semua) | Ya (semua) | Kontrol penuh atas data referral |
| User | Ya (refer someone) | Ya (milik sendiri) | Tidak | Tidak | Bisa refer orang lain dan lihat status referral sendiri |

### Ringkasan Permission Level

| Level Akses | Deskripsi |
| - | - |
| **Full Control** | Bisa Create, Read, Update, Delete tanpa batasan |
| **Manage Own** | Bisa Create, Read, Update data milik sendiri saja |
| **Read All** | Bisa melihat semua data tapi tidak bisa mengubah |
| **Read Own** | Hanya bisa melihat data milik sendiri |
| **No Access** | Tidak memiliki akses sama sekali ke entitas ini |

### Mekanisme Enforce Permission

| Mekanisme | Deskripsi | Implementasi |
| - | - | - |
| Row Level Security (RLS) | Filter data di level database berdasarkan `company_id` dan `user_id` | Supabase RLS policies pada setiap entitas |
| Workspace Role Check | Validasi role user di workspace sebelum operasi | `WorkspaceMember.role` dicek di middleware |
| Company Isolation | Data company A tidak bisa diakses company B | Filter `company_id` pada setiap query |
| API-Level Validation | Validasi permission sebelum memproses request | Check di `WorkflowAutomationManager` dan `WorkflowEngine` |
| UI-Level Hiding | Sembunyikan tombol/fitur yang tidak bisa diakses | Conditional rendering berdasarkan role di `Automation.jsx` |


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