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

# Referral

<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: "Referral"
description: "Program referral dengan code generation, commission tracking, leaderboard, multi-channel sharing, dan withdrawal system di SNISHOP ERP."
------------------------------------------------------------------------------------------------------------------------------------------------------

# Referral

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

Halaman Referral mengelola program referral untuk mendorong customer mengajak orang lain berbelanja. Dibangun di atas `Referral.jsx` (745 baris) dengan sistem code generation unik, commission tracking otomatis, leaderboard, dan withdrawal system.

Setiap participant mendapat kode referral 8-karakter yang bisa dibagikan melalui WhatsApp, Facebook, Twitter, LinkedIn, atau Email. Setiap referral sukses tercatat dan commission otomatis masuk ke balance.

## Arsitektur Komponen

```mermaid theme={null}
graph TD
    A[Referral.jsx<br/>745 lines] --> B[My Referral Code]
    A --> C[Stats Dashboard]
    A --> D[Referral History]
    A --> E[Commission History]
    A --> F[Leaderboard]
    A --> G[Share Links]
    A --> H[ReferralCodeModal<br/>260 lines]
    A --> I[ReferralSettingsTab<br/>Admin]
    A --> J[base44.entities.User]
    A --> K[base44.entities.Referral]
    A --> L[base44.entities.ReferralCode]
    A --> M[base44.entities.Commission]
    A --> N[base44.entities.ReferralSetting]
    A --> O[base44.entities.WithdrawalRequest]
    A --> P[base44.entities.MarketplaceCommissionSettings]
    A --> Q[base44.entities.PricingPlan]
    A --> R[base44.entities.Subscription]
```

## Ringkasan Modul

Modul Referral merupakan salah satu fitur marketing utama dalam SNISHOP ERP yang memungkinkan setiap pengguna menjadi affiliate dan mendapatkan komisi dari setiap referensi berhasil. Sistem ini mencakup:

* **Code Generation** — Pembuatan kode referral unik 8-karakter secara otomatis untuk setiap pengguna
* **Commission Tracking** — Pencatatan dan kalkulasi komisi secara real-time berdasarkan pembelian referee
* **Leaderboard** — Peringkat referrer teraktif untuk mendorong kompetisi sehat (gamifikasi)
* **Multi-Channel Sharing** — Distribusi link referral melalui 5 kanal: WhatsApp, Facebook, Twitter, LinkedIn, dan Email
* **Withdrawal System** — Pencairan saldo komisi ke rekening bank dengan approval workflow
* **Admin Settings** — Konfigurasi commission rate per plan langganan

***

## Entity Relationship Diagram

```mermaid theme={null}
erDiagram
    User ||--o{ ReferralCode : "memiliki"
    User ||--o{ Referral : "sebagai referrer"
    User ||--o{ Referral : "sebagai referee"
    User ||--o{ Commission : "menerima komisi"
    User ||--o{ Commission : "membayar melalui pembelian"
    User ||--o{ WithdrawalRequest : "mengajukan penarikan"
    User ||--o| Subscription : "memiliki langganan"
    User }o--|| User : "referred_by"

    ReferralCode }o--|| User : "dimiliki oleh"
    Referral }o--|| User : "referrer"
    Referral }o--|| User : "referee"

    Commission }o--|| User : "referrer"
    Commission }o--|| User : "referee"

    ReferralSetting }o--|| PricingPlan : "mengatur plan"

    WithdrawalRequest }o--|| User : "pemohon"

    Subscription }o--|| User : "langganan user"
    Subscription }o--|| PricingPlan : "plan yang dipilih"

    User {
        string id PK
        string email
        string full_name
        string role "admin | user"
        string subscription_plan
        string referral_code
        string referred_by FK
        number commission_balance
        number total_earnings
        number balance
        number admin_commission_balance
    }

    Referral {
        string id PK
        string referrer_id FK
        string referee_id FK
        string referee_email
        string referee_name
        string description
        string status "signed_up | purchased"
    }

    ReferralCode {
        string id PK
        string code UK
        string user_id FK
        string user_email
        string user_name
        string description
        boolean is_active
    }

    Commission {
        string id PK
        string referrer_id FK
        string referee_id FK
        string purchase_id
        number purchase_amount
        number commission_rate
        number commission_amount
        string plan_purchased
        string purchase_type "first_time | renewal"
        string description
        string status "unpaid | paid_to_balance | rejected"
    }

    ReferralSetting {
        string id PK
        string plan_key FK
        string description
        number first_purchase_commission_rate
        number renewal_commission_rate
    }

    WithdrawalRequest {
        string id PK
        string user_id FK
        string user_email
        number amount
        string bank_account_id
        object bank_account_details
        string withdrawal_source "commission | admin_commission"
        string description
        string status "pending | approved | rejected"
        string admin_notes
        string proof_of_transfer_url
    }

    PricingPlan {
        string id PK
        string planKey UK
        string name
        number price
        number yearlyPrice
        boolean isActive
    }

    Subscription {
        string id PK
        string user_id FK
        string service_name
        number cost
        string status "active | paused | cancelled"
        string billing_cycle
    }

    MarketplaceCommissionSettings {
        string id PK
        number commission_rate
        string description
        number min_withdrawal
        number withdrawal_fee
        boolean is_active
    }
```

***

## Entity Schema Tables

### User (Referral Fields)

Field-field pada entity `User` yang berkaitan langsung dengan sistem referral dan komisi.

| Field | Tipe | Required | Default | Deskripsi |
| - | - | - | - | - |
| `referral_code` | string | Tidak | — | Kode referral unik milik user, digunakan sebagai parameter referral link |
| `referred_by` | string | Tidak | — | ID user yang mereferensikan user ini saat mendaftar (FK ke User) |
| `commission_balance` | number | Tidak | `0` | Saldo komisi dari referral yang dapat ditarik (withdraw) |
| `total_earnings` | number | Tidak | `0` | Total komisi yang pernah diterima secara akumulasi (sejarah penghasilan) |
| `balance` | number | Tidak | `0` | Saldo deposit umum untuk membeli membership atau addon |
| `admin_commission_balance` | number | Tidak | `0` | Saldo komisi admin basic dari proses transaksi produk digital |

### Referral

Entity yang merekam setiap hubungan referral antara referrer dan referee.

| Field | Tipe | Required | Default | Deskripsi |
| - | - | - | - | - |
| `referrer_id` | string (FK → User) | **Ya** | — | ID pengguna yang mengundang (referrer) |
| `referee_id` | string (FK → User) | **Ya** | — | ID pengguna yang diundang (referee) |
| `referee_email` | string | **Ya** | — | Email pengguna yang diundang |
| `referee_name` | string | Tidak | — | Nama pengguna yang diundang |
| `description` | string (max 1000) | Tidak | — | Catatan tambahan mengenai referral ini |
| `status` | enum | Tidak | `signed_up` | Status undangan: `signed_up` atau `purchased` |

### ReferralCode

Entity yang menyimpan kode referral unik yang di-generate untuk setiap pengguna.

| Field | Tipe | Required | Default | Deskripsi |
| - | - | - | - | - |
| `code` | string | **Ya** | — | Kode referral unik (8 karakter, uppercase) |
| `user_id` | string (FK → User) | **Ya** | — | ID user pemilik kode referral |
| `user_email` | string | Tidak | — | Email user pemilik kode |
| `user_name` | string | Tidak | — | Nama user pemilik kode |
| `description` | string (max 1000) | Tidak | — | Catatan atau pesan promosi yang menyertai kode referral ini |
| `is_active` | boolean | Tidak | `true` | Status aktif kode; jika `false`, kode tidak bisa digunakan untuk referral baru |

### Commission

Entity yang merekam setiap transaksi komisi yang dihasilkan dari referral yang berhasil melakukan pembelian.

| Field | Tipe | Required | Default | Deskripsi |
| - | - | - | - | - |
| `referrer_id` | string (FK → User) | **Ya** | — | ID pengguna yang menerima komisi |
| `referee_id` | string (FK → User) | **Ya** | — | ID pengguna yang melakukan pembelian |
| `purchase_id` | string | Tidak | — | ID dari transaksi pembelian terkait (misal: ID UpgradeRequest) |
| `purchase_amount` | number | **Ya** | — | Jumlah pembelian yang menjadi dasar perhitungan komisi |
| `commission_rate` | number | **Ya** | — | Persentase komisi yang diterapkan (misal: 0.50 untuk 50%) |
| `commission_amount` | number | **Ya** | — | Jumlah komisi yang didapat (hasil kalkulasi: `purchase_amount * commission_rate`) |
| `plan_purchased` | string | Tidak | — | Paket yang dibeli oleh referee (misal: `Pro`, `Business`) |
| `purchase_type` | enum | Tidak | — | Jenis pembelian: `first_time` atau `renewal` |
| `description` | string (max 1000) | Tidak | — | Catatan detail mengenai komisi ini |
| `status` | enum | Tidak | `unpaid` | Status komisi: `unpaid`, `paid_to_balance`, atau `rejected` |

### ReferralSetting

Entity konfigurasi yang menentukan commission rate untuk setiap plan langganan.

| Field | Tipe | Required | Default | Deskripsi |
| - | - | - | - | - |
| `plan_key` | string | **Ya** | — | Kunci paket langganan terkait (misal: `free`, `pro`, `business`) |
| `description` | string (max 1000) | Tidak | — | Penjelasan mengenai pengaturan komisi referral untuk paket ini |
| `first_purchase_commission_rate` | number | **Ya** | `0.5` | Persentase komisi untuk pembelian pertama (misal: 0.50 untuk 50%) |
| `renewal_commission_rate` | number | **Ya** | `0.1` | Persentase komisi untuk pembelian kedua dan seterusnya (misal: 0.10 untuk 10%) |

### WithdrawalRequest

Entity yang mengelola permintaan penarikan saldo komisi oleh pengguna.

| Field | Tipe | Required | Default | Deskripsi |
| - | - | - | - | - |
| `user_id` | string (FK → User) | **Ya** | — | ID pengguna yang meminta penarikan |
| `user_email` | string | Tidak | — | Email pengguna pemohon |
| `amount` | number | **Ya** | — | Jumlah yang ditarik (dalam Rupiah) |
| `bank_account_id` | string | **Ya** | — | ID rekening bank tujuan penarikan |
| `bank_account_details` | object | Tidak | — | Snapshot detail rekening bank saat penarikan dilakukan |
| `withdrawal_source` | enum | Tidak | `commission` | Sumber penarikan: `commission` (dari commission\_balance) atau `admin_commission` (dari admin\_commission\_balance) |
| `description` | string (max 1000) | Tidak | — | Alasan atau keterangan tambahan dari pengguna mengenai penarikan ini |
| `status` | enum | Tidak | `pending` | Status permintaan: `pending`, `approved`, atau `rejected` |
| `admin_notes` | string | Tidak | — | Catatan dari admin yang memproses permintaan |
| `proof_of_transfer_url` | string | Tidak | — | URL bukti transfer dari admin setelah penarikan disetujui |

### MarketplaceCommissionSettings

Entity konfigurasi global untuk kebijakan komisi marketplace dan penarikan saldo.

| Field | Tipe | Required | Default | Deskripsi |
| - | - | - | - | - |
| `commission_rate` | number | **Ya** | `10` | Persentase komisi marketplace (0-100) |
| `description` | string (max 1000) | Tidak | — | Penjelasan mengenai kebijakan komisi marketplace dan ketentuan penarikan saldo |
| `min_withdrawal` | number | Tidak | `100000` | Minimum penarikan saldo (dalam Rupiah) |
| `withdrawal_fee` | number | Tidak | `5000` | Biaya admin per penarikan (dalam Rupiah) |
| `is_active` | boolean | Tidak | `true` | Status aktif pengaturan komisi marketplace |

***

## Enum Reference Tables

### Referral Status

| Nilai | Deskripsi |
| - | - |
| `signed_up` | Referee telah mendaftar menggunakan kode referral, namun belum melakukan pembelian |
| `purchased` | Referee telah melakukan pembelian (pertama atau perpanjangan), komisi mulai diproses |

### Commission Status

| Nilai | Deskripsi |
| - | - |
| `unpaid` | Komisi telah tercatat namun belum dibayarkan ke saldo pengguna |
| `paid_to_balance` | Komisi telah dibayarkan dan ditambahkan ke `commission_balance` pengguna |
| `rejected` | Komisi ditolak (misal: transaksi dibatalkan atau ditemukan kecurangan) |

### Commission Purchase Type

| Nilai | Deskripsi |
| - | - |
| `first_time` | Pembelian pertama kali oleh referee — commission rate lebih tinggi |
| `renewal` | Perpanjangan subscription oleh referee — commission rate lebih rendah |

### Withdrawal Source

| Nilai | Deskripsi |
| - | - |
| `commission` | Penarikan dari `commission_balance` (komisi referral biasa) |
| `admin_commission` | Penarikan dari `admin_commission_balance` (komisi admin basic dari transaksi) |

### Withdrawal Request Status

| Nilai | Deskripsi |
| - | - |
| `pending` | Permintaan penarikan menunggu review dan approval admin |
| `approved` | Permintaan disetujui, admin sedang atau telah mentransfer dana |
| `rejected` | Permintaan ditolak oleh admin (dengan catatan alasan penolakan) |

### ReferralCode Active Status

| Nilai | Deskripsi |
| - | - |
| `true` | Kode referral aktif dan dapat digunakan oleh calon referee baru |
| `false` | Kode referral dinonaktifkan, tidak bisa digunakan untuk referral baru |

### User Role

| Nilai | Deskripsi |
| - | - |
| `admin` | Administrator dengan akses penuh ke pengaturan referral dan approval withdrawal |
| `user` | Pengguna biasa yang dapat berpartisipasi dalam program referral |

### Subscription Plan

| Nilai | Deskripsi |
| - | - |
| `free` | Paket gratis tanpa fitur premium |
| `pro` | Paket profesional dengan fitur lanjutan |
| `business` | Paket bisnis dengan akses fitur company |
| `advanced` | Paket tingkat lanjut dengan fitur lengkap |
| `enterprise` | Paket enterprise dengan akses tanpa batas |

### Subscription Status

| Nilai | Deskripsi |
| - | - |
| `active` | Langganan aktif dan berjalan normal |
| `paused` | Langganan dijeda sementara |
| `cancelled` | Langganan dibatalkan |

***

## State Diagrams

### Referral Status Lifecycle

```mermaid theme={null}
stateDiagram-v2
    [*] --> signed_up : Referee mendaftar<br/>dengan kode referral
    signed_up --> purchased : Referee melakukan<br/>pembelian pertama/renewal
    purchased --> purchased : Referee melakukan<br/>pembelian selanjutnya

    note right of signed_up
        Komisi belum dihasilkan.
        Referral tercatat di history
        sebagai "pending".
    end note

    note right of purchased
        Komisi dihitung dan dicatat
        di entity Commission.
        Status komisi: unpaid → paid_to_balance
    end note
```

### Commission Status Lifecycle

```mermaid theme={null}
stateDiagram-v2
    [*] --> unpaid : Pembelian referee<br/>terdeteksi
    unpaid --> paid_to_balance : Admin memproses<br/>atau auto-pay
    unpaid --> rejected : Transaksi dibatalkan<br/>atau kecurangan

    paid_to_balance --> [*] : Komisi masuk ke<br/>commission_balance

    rejected --> [*] : Komisi tidak<br/>dibayarkan

    note right of unpaid
        Komisi tercatat namun
        belum masuk ke saldo
        pengguna.
    end note

    note right of paid_to_balance
        commission_amount ditambahkan
        ke User.commission_balance
        dan User.total_earnings
    end note
```

### Withdrawal Request Status Lifecycle

```mermaid theme={null}
stateDiagram-v2
    [*] --> pending : User mengajukan<br/>penarikan saldo
    pending --> approved : Admin menyetujui<br/>permintaan
    pending --> rejected : Admin menolak<br/>permintaan

    approved --> [*] : Dana ditransfer,<br/>bukti upload

    rejected --> [*] : Saldo dikembalikan<br/>ke commission_balance

    note right of pending
        Permintaan masuk antrian.
        Saldo sudah di-lock
        (tidak bisa digunakan lagi).
    end note

    note right of approved
        Admin upload bukti transfer
        di proof_of_transfer_url.
        Saldo user dikurangi.
    end note

    note right of rejected
        Saldo dikembalikan ke
        User.commission_balance.
        admin_notes berisi alasan.
    end note
```

### ReferralCode Lifecycle

```mermaid theme={null}
stateDiagram-v2
    [*] --> Active : Code di-generate<br/>saat user registrasi
    Active --> Inactive : Admin atau user<br/>menonaktifkan kode
    Inactive --> Active : Kode diaktifkan<br/>kembali
    Inactive --> [*] : Kode dihapus
    Active --> [*] : Kode dihapus
```

***

## Sequence Diagrams

### Flow 1: Membuat dan Membagikan Referral Link

```mermaid theme={null}
sequenceDiagram
    participant User as Referrer (User)
    participant UI as Referral.jsx
    participant B44 as Base44 API
    participant RC as ReferralCode Entity

    User->>UI: Buka halaman Referral
    UI->>B44: Query ReferralCode WHERE user_id = current_user
    B44-->>UI: Return ReferralCode (atau null)

    alt Kode sudah ada
        UI->>UI: Tampilkan kode referral existing
    else Kode belum ada
        UI->>UI: Generate 8-char code<br/>charset: ABCDEFGHJKLMNPQRSTUVWXYZ23456789
        UI->>B44: Check uniqueness (code not exists)
        B44-->>UI: Code is unique
        UI->>B44: Create ReferralCode {code, user_id, user_email, user_name, is_active: true}
        B44-->>RC: Insert record
        RC-->>UI: Return created code
    end

    User->>UI: Pilih channel sharing
    UI->>UI: Format link: {origin}?ref={code}

    alt WhatsApp
        UI->>User: whatsapp://send?text=...
    else Facebook
        UI->>User: Facebook share dialog
    else Twitter
        UI->>User: Twitter intent URL
    else LinkedIn
        UI->>User: LinkedIn share URL
    else Email
        UI->>User: mailto:?subject=...&body=...
    end
```

### Flow 2: Tracking Konversi Referral (Signup → Purchase)

```mermaid theme={null}
sequenceDiagram
    participant Ref as Referrer
    participant Ree as Referee (Calon)
    participant Modal as ReferralCodeModal
    participant B44 as Base44 API
    participant RefEnt as Referral Entity
    participant CommEnt as Commission Entity
    participant UserEnt as User Entity

    Ref->>Ree: Bagikan link: {origin}?ref={code}
    Ree->>Modal: Buka signup page dengan param ref

    Modal->>Modal: Extract ref code dari URL
    Modal->>B44: Query ReferralCode WHERE code = ref AND is_active = true
    B44-->>Modal: Return ReferralCode

    alt Code tidak valid / tidak aktif
        Modal->>Ree: Tampilkan error: kode tidak valid
    else Code valid
        Modal->>Modal: Validasi: code != user sendiri (self-referral check)
        Modal->>Modal: Validasi: user belum pernah di-referral (double-referral check)

        alt Self-referral atau double-referral
            Modal->>Ree: Tampilkan error
        else Valid
            Ree->>B44: Submit form registrasi
            B44->>UserEnt: Create User (referred_by = referrer_id)
            B44->>RefEnt: Create Referral {referrer_id, referee_id, referee_email, status: signed_up}
            RefEnt-->>Modal: Referral created
            Modal->>Modal: Set preferences.referral_modal_dismissed = true
            Modal->>Ree: Redirect ke dashboard
        end
    end

    Note over Ree,B44: === Referee melakukan pembelian ===

    Ree->>B44: Lakukan pembelian subscription
    B44->>B44: Lookup Referral WHERE referee_id = current_user
    B44->>B44: Lookup ReferralSetting WHERE plan_key = purchased_plan

    alt Pembelian pertama (first_time)
        B44->>B44: rate = first_purchase_commission_rate
    else Perpanjangan (renewal)
        B44->>B44: rate = renewal_commission_rate
    end

    B44->>B44: commission_amount = purchase_amount * rate
    B44->>CommEnt: Create Commission {referrer_id, referee_id, purchase_amount, commission_rate, commission_amount, purchase_type, status: unpaid}
    B44->>RefEnt: Update Referral SET status = purchased
    B44->>UserEnt: Update User SET total_earnings += commission_amount
```

### Flow 3: Payout / Penarikan Komisi

```mermaid theme={null}
sequenceDiagram
    participant User as Referrer (User)
    participant UI as Referral.jsx
    participant B44 as Base44 API
    participant WR as WithdrawalRequest Entity
    participant Admin as Admin
    participant UserEnt as User Entity

    User->>UI: Ajukan penarikan komisi
    UI->>B44: Get User.commission_balance
    B44-->>UI: Return balance

    UI->>UI: Validasi: amount >= min_withdrawal
    UI->>UI: Validasi: amount <= commission_balance

    alt Saldo tidak cukup
        UI->>User: Error: Saldo komisi tidak mencukupi
    else Valid
        User->>UI: Submit WithdrawalRequest {amount, bank_account_id, withdrawal_source: commission}
        UI->>B44: Create WithdrawalRequest {status: pending}
        B44->>WR: Insert record
        B44->>UserEnt: Lock saldo (reduce commission_balance)
        WR-->>UI: Request created

        Note over Admin,B44: === Admin Review ===

        Admin->>B44: Review WithdrawalRequest
        B44-->>Admin: Show pending requests

        alt Approve
            Admin->>B44: Update status = approved
            Admin->>B44: Upload proof_of_transfer_url
            B44->>WR: Update record
            Note over UserEnt: Saldo sudah dipotong,<br/>tidak ada perubahan lagi
        else Reject
            Admin->>B44: Update status = rejected, admin_notes = "..."
            B44->>WR: Update record
            B44->>UserEnt: Restore commission_balance += amount
        end
    end
```

***

## Code Generation Algorithm

Kode referral dihasilkan dari karakter set khusus untuk menghindari kebingungan visual:

```
Character set: 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'
Length: 8 characters
Total kemungkinan: 34^8 = ~1.785 triliun kombinasi
```

```mermaid theme={null}
flowchart LR
    A[Random Selection] --> B[8 chars dari set]
    B --> C[Uppercase]
    C --> D[Unique Check<br/>via ReferralCode]
    D --> E{Exists?}
    E -->|Ya| A
    E -->|Tidak| F[Unique Referral Code]
```

**Karakter yang dikecualikan:** `I` (mirip `1`), `O` (mirip `0`) — untuk menghindari kesalahan input manual oleh referee.

**Implementasi pseudo-code:**

```javascript theme={null}
const CHARSET = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
const CODE_LENGTH = 8;

function generateReferralCode() {
    let code;
    do {
        code = Array.from({ length: CODE_LENGTH }, () =>
            CHARSET[Math.floor(Math.random() * CHARSET.length)]
        ).join('');
    } while (existingCodes.has(code)); // Ensure uniqueness
    return code;
}
```

***

## Referral Flow Lengkap

```mermaid theme={null}
sequenceDiagram
    participant Referrer
    participant Referred
    participant ReferralCodeModal
    participant Base44

    Referrer->>Referred: Share referral link<br/>{origin}?ref={code}
    Referred->>ReferralCodeModal: Open signup page
    ReferralCodeModal->>ReferralCodeModal: Validate code (8-char, uppercase)
    ReferralCodeModal->>Base44: Check ReferralCode.is_active
    Base44-->>ReferralCodeModal: Code valid
    ReferralCodeModal->>ReferralCodeModal: Check self-referral
    ReferralCodeModal->>ReferralCodeModal: Check double-referral
    ReferralCodeModal->>Base44: Create Referral (status: signed_up)
    Base44->>Base44: Update user.referred_by
    Note over Base44: Saat referred purchase:<br/>status → purchased<br/>Create Commission
```

***

## Validation Rules

| Rule | Deskripsi | Implementasi |
| - | - | - |
| Code format | 8 karakter, uppercase, dari character set `ABCDEFGHJKLMNPQRSTUVWXYZ23456789` | Validasi di frontend saat input manual |
| Self-referral | User tidak bisa menggunakan kode referral miliknya sendiri | Check: `code.user_id !== current_user.id` |
| Double-referral | User yang sudah pernah di-referral tidak bisa di-referral lagi | Check: `Referral WHERE referee_id = current_user` tidak ada |
| Active check | Kode harus memiliki `is_active = true` | Query: `ReferralCode WHERE code = ref AND is_active = true` |
| Minimum withdrawal | Penarikan minimal sesuai `MarketplaceCommissionSettings.min_withdrawal` | Validasi di frontend dan backend |
| Balance check | Jumlah penarikan tidak boleh melebihi `commission_balance` | Validasi: `amount <= User.commission_balance` |
| Description limit | Maksimal 1000 karakter untuk field description di semua entity | Validasi maxLength di schema |

***

## Commission Structure

Sistem komisi menggunakan model **tiered rate** berdasarkan jenis pembelian dan plan yang dibeli:

| Tipe | Rate | Deskripsi | Contoh Kalkulasi |
| - | - | - | - |
| `first_time` | `first_purchase_commission_rate` dari ReferralSetting | Komisi dari pembelian pertama referee — rate lebih tinggi untuk insentif | Plan Pro (Rp 200.000) × 50% = **Rp 100.000** |
| `renewal` | `renewal_commission_rate` dari ReferralSetting | Komisi dari perpanjangan subscription referee — rate lebih rendah | Plan Pro (Rp 200.000) × 10% = **Rp 20.000** |

**Formula komisi:**

```
commission_amount = purchase_amount × commission_rate
```

Dimana `commission_rate` diambil dari `ReferralSetting` berdasarkan `plan_key` yang dibeli dan jenis pembelian (`first_time` atau `renewal`).

**Contoh konfigurasi ReferralSetting:**

| Plan Key | First Purchase Rate | Renewal Rate |
| - | - | - |
| `pro` | 0.50 (50%) | 0.10 (10%) |
| `business` | 0.40 (40%) | 0.08 (8%) |
| `advanced` | 0.30 (30%) | 0.05 (5%) |
| `enterprise` | 0.25 (25%) | 0.05 (5%) |

***

## Stats Dashboard

Dashboard menampilkan metrik-metrik kunci untuk memantau performa referral:

| Metrik | Rumus | Sumber Data |
| - | - | - |
| **Total Earnings** | `SUM(commission.commission_amount) WHERE referrer_id = current_user` | Commission entity |
| **Commission Balance** | `User.commission_balance` | User entity |
| **Successful Referrals** | `COUNT(Referral) WHERE referrer_id = current_user AND status = 'purchased'` | Referral entity |
| **Pending Referrals** | `COUNT(Referral) WHERE referrer_id = current_user AND status = 'signed_up'` | Referral entity |
| **My Rank** | Peringkat dari `listReferralLeaderboard` | Leaderboard function |
| **Conversion Rate** | `successful / (successful + pending) × 100%` | Kalkulasi frontend |

***

## Withdrawal System

### Ketentuan Penarikan

| Setting | Nilai | Sumber |
| - | - | - |
| Minimum penarikan | Sesuai `MarketplaceCommissionSettings.min_withdrawal` (default: Rp 100.000) | MarketplaceCommissionSettings |
| Biaya admin | Sesuai `MarketplaceCommissionSettings.withdrawal_fee` (default: Rp 5.000) | MarketplaceCommissionSettings |
| Sumber dana | `commission` atau `admin_commission` | WithdrawalRequest.withdrawal\_source |

### Proses Penarikan

```mermaid theme={null}
flowchart TD
    A[User buka halaman Referral] --> B{commission_balance >= min_withdrawal?}
    B -->|Tidak| C[Tampilkan info:<br/>saldo belum mencukupi]
    B -->|Ya| D[User input jumlah penarikan]
    D --> E[User pilih rekening bank]
    E --> F[Submit WithdrawalRequest]
    F --> G[Status: pending]
    G --> H{Admin review}
    H -->|Approved| I[Upload bukti transfer]
    I --> J[Status: approved]
    J --> K[Selesai]
    H -->|Rejected| L[Catat admin_notes]
    L --> M[Saldo dikembalikan]
    M --> N[Status: rejected]
```

***

## Leaderboard

```mermaid theme={null}
flowchart TD
    A[listReferralLeaderboard] --> B[Rank by successful referrals<br/>COUNT WHERE status = purchased]
    B --> C[Top 1: Crown icon 👑]
    B --> D[Top 2: Trophy icon 🏆]
    B --> E[Top 3: Medal icon 🥉]
    B --> F[Others: Award icon 🏅]
```

Leaderboard di-refresh otomatis setiap **10 detik** bersamaan dengan data referral lainnya untuk memastikan peringkat selalu terkini.

**Algoritma ranking:**

1. Hitung jumlah referral dengan `status = 'purchased'` per referrer
2. Urutkan secara descending (terbanyak ke tersedikit)
3. Assign rank berdasarkan posisi
4. Tampilkan dengan ikon berbeda untuk top 3

***

## 5 Share Channels

| Channel | Method | Format URL |
| - | - | - |
| WhatsApp | Deep link WhatsApp | `whatsapp://send?text=...` |
| Facebook | Facebook share dialog | `https://www.facebook.com/sharer/sharer.php?u=...` |
| Twitter | Twitter intent URL | `https://twitter.com/intent/tweet?text=...` |
| LinkedIn | LinkedIn share URL | `https://www.linkedin.com/sharing/share-offsite/?url=...` |
| Email | Mailto link | `mailto:?subject=...&body=...` |

**Format referral link:** `{origin}?ref={code}`

Contoh: `https://snishop.my.canva.site/?ref=AB3D5F7K`

***

## Auto-Refresh

Data referral di-refresh otomatis setiap **10 detik** untuk tracking realtime. Ini mencakup:

* Daftar referral (history)
* Statistik dashboard (total earnings, balance, rank)
* Leaderboard (peringkat terbaru)
* Commission history (komisi baru yang masuk)

***

## RBAC Permission Table

### Referral Module Access

| Aksi | User (role: user) | Admin (role: admin) | Keterangan |
| - | - | - | - |
| Lihat kode referral sendiri | ✅ | ✅ | Setiap user bisa melihat kode referral miliknya |
| Bagikan referral link | ✅ | ✅ | Semua user bisa berpartisipasi |
| Lihat referral history | ✅ | ✅ | Hanya referral milik sendiri |
| Lihat commission history | ✅ | ✅ | Hanya komisi milik sendiri (sebagai referrer atau referee) |
| Ajukan withdrawal | ✅ | ✅ | Selama saldo mencukupi |
| Lihat leaderboard | ✅ | ✅ | Semua user bisa melihat peringkat |
| Lihat semua referral (global) | ❌ | ✅ | Admin bisa melihat seluruh referral di sistem |
| Kelola ReferralSetting | ❌ | ✅ | Hanya admin yang bisa mengubah commission rate |
| Approve/reject withdrawal | ❌ | ✅ | Hanya admin yang bisa memproses withdrawal |
| Nonaktifkan referral code | ❌ | ✅ | Admin bisa menonaktifkan kode tertentu |
| Lihat semua commission (global) | ❌ | ✅ | Admin bisa audit seluruh komisi |

### RLS (Row-Level Security) — Commission Entity

Commission entity memiliki RLS rules yang lebih detail:

| Operasi | Kondisi Akses |
| - | - |
| Create | User adalah referrer ATAU referee ATAU user ber-role admin |
| Read | User adalah referrer ATAU referee ATAU user ber-role admin |
| Update | User adalah referrer ATAU referee ATAU user ber-role admin |
| Delete | User adalah referrer ATAU referee ATAU user ber-role admin |

### RLS — WithdrawalRequest Entity

| Operasi | Kondisi Akses |
| - | - |
| Create | User adalah pemilik request (`user_id`) ATAU email cocok ATAU user ber-role admin |
| Read | User adalah pemilik request ATAU email cocok ATAU user ber-role admin |
| Update | User adalah pemilik request ATAU email cocok ATAU user ber-role admin |
| Delete | User adalah pemilik request ATAU email cocok ATAU user ber-role admin |

***

## ReferralCodeModal (260 baris)

Modal yang muncul saat user signup dengan referral code:

```mermaid theme={null}
flowchart TD
    A[Signup Page] --> B{ref param in URL?}
    B -->|Ya| C[Auto-fill code]
    B -->|Tidak| D[Show modal]
    C --> E[Validate code]
    D --> E
    E --> F{Valid?}
    F -->|Ya| G[Create Referral entity]
    F -->|Tidak| H[Show error]
    G --> I[Set preferences.referral_modal_dismissed]
```

**Detail validasi di ReferralCodeModal:**

1. **Format check** — Kode harus 8 karakter uppercase dari character set yang valid
2. **Active check** — Query `ReferralCode` untuk memastikan `is_active = true`
3. **Self-referral check** — Pastikan `code.user_id !== current_user.id`
4. **Double-referral check** — Pastikan belum ada `Referral` dengan `referee_id = current_user.id`
5. **Existence check** — Pastikan kode benar-benar ada di database

***

## Integrasi dengan Entity Lain

### PricingPlan

Setiap plan dalam `PricingPlan` dapat memiliki konfigurasi commission rate yang berbeda melalui `ReferralSetting`. Plan yang tersedia:

| Plan Key | Nama | Deskripsi |
| - | - | - |
| `free` | Free | Paket gratis — tidak ada komisi referral |
| `pro` | Pro | Paket profesional |
| `business` | Business | Paket bisnis |
| `advanced` | Advanced | Paket tingkat lanjut |
| `enterprise` | Enterprise | Paket enterprise |

### Subscription

Ketika referee membeli subscription, sistem akan:

1. Lookup `Referral` untuk menemukan referrer
2. Lookup `ReferralSetting` berdasarkan `plan_key` subscription
3. Tentukan `purchase_type` (`first_time` atau `renewal`)
4. Hitung `commission_amount` berdasarkan rate
5. Create record `Commission` dengan status `unpaid`
6. Update `Referral.status` menjadi `purchased`

### ProductOrder

Untuk produk digital, `ProductOrder` memiliki field `product_commission_rate` yang menyimpan commission rate saat order dibuat, serta `admin_commission_amount` untuk komisi admin basic.

***

## Cara Akses

Dari sidebar, klik menu **Marketing** > **Referral**. Memerlukan user yang sudah login.

***

## Flow Penggunaan

1. **Buka halaman Referral** dari sidebar — lihat kode referral unik kamu di atas halaman
2. **Bagikan kode referral** melalui WhatsApp, Facebook, Twitter, LinkedIn, atau Email — link berformat `{origin}?ref={code}`
3. **Orang yang mendaftar** menggunakan kode kamu otomatis tercatat sebagai referral dengan status `signed_up`
4. **Saat referral melakukan pembelian** pertama, status berubah ke `purchased` dan komisi dihitung berdasarkan `ReferralSetting`
5. **Pantau stats dashboard** untuk melihat total earnings, successful referrals, dan rank di leaderboard
6. **Tarik saldo komisi** jika sudah mencapai minimum withdrawal yang ditentukan di `MarketplaceCommissionSettings`

***

## Tips

* **Optimalkan commission rate** — Buat rate yang menarik tapi tetap menguntungkan secara bisnis. Commission rate yang terlalu kecil tidak memotivasi referrer untuk aktif berbagi
* **Promosikan program referral secara aktif** di semua channel — banyak customer tidak tahu program ini ada. Manfaatkan email marketing dan notifikasi in-app
* **Manfaatkan leaderboard untuk gamifikasi** — ranking mendorong kompetisi sehat antar referrer. Pertimbangkan reward tambahan untuk top referrer bulanan
* **Evaluasi program secara berkala** — sesuaikan rate jika perlu berdasarkan ROI. Analisis conversion rate dari `signed_up` ke `purchased` untuk mengukur efektivitas
* **Monitor withdrawal requests** secara rutin — proses penarikan dengan cepat untuk menjaga kepercayaan peserta program
* **Gunakan description field** di ReferralCode untuk membuat pesan promosi yang menarik saat membagikan kode
* **Pastikan minimum withdrawal** masuk akal — terlalu tinggi akan mengecilkan partisipasi, terlalu rendah akan membebani operasional

***

## Troubleshooting

| Masalah | Kemungkinan Penyebab | Solusi |
| - | - | - |
| Kode referral tidak bisa digunakan | Kode sudah dinonaktifkan (`is_active = false`) | Admin perlu mengaktifkan kembali kode |
| Komisi tidak masuk setelah pembelian | Referral status masih `signed_up` | Pastikan referee telah menyelesaikan pembelian |
| Withdrawal ditolak | Saldo tidak mencukupi atau data rekening tidak valid | Periksa saldo dan lengkapi data rekening bank |
| Self-referral error | User mencoba menggunakan kode sendiri | Gunakan kode referral dari user lain |
| Double-referral error | User sudah pernah di-referral sebelumnya | Satu user hanya bisa di-referral satu kali |
| Link referral tidak berfungsi | Parameter `ref` tidak ada di URL | Pastikan format link: `{origin}?ref={code}` |


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