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

# Sales pipeline

<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: "Sales Pipeline — Manajemen Pipeline"
description: "Sales pipeline kanban dengan 6 tahap, lead-to-customer conversion, invoice matching, dan dual view mode di SNISHOP ERP."
--------------------------------------------------------------------------------------------------------------------------------------

# Sales Pipeline — Manajemen Pipeline

<img src="https://mintcdn.com/quinnofspicy/e4f_upKhVWcjsUmM/docs/mintlify/screenshots/crm/sales-pipeline.png?fit=max&auto=format&n=e4f_upKhVWcjsUmM&q=85&s=8638c89ed1c7d4f68c975fcbbd2d0014" alt="Sales Pipeline" width="1920" height="1080" data-path="docs/mintlify/screenshots/crm/sales-pipeline.png" />

Sales Pipeline Management mengelola seluruh siklus penjualan dari lead hingga closing. Tersedia dalam dua mode tampilan: Kanban Board dan List View, dengan fitur lead-to-customer conversion dan invoice matching.

## Arsitektur

```mermaid theme={null}
flowchart TB
    subgraph VIEWS["Dual View Mode"]
        KAN[Kanban Board<br/>Drag & Drop]
        LST[List View<br/>Tabel]
    end

    subgraph STAGES["6 Pipeline Stages"]
        PRO[Prospect<br/>Lead Baru]
        QUA[Qualified<br/>Terkualifikasi]
        PRP[Proposal<br/>Penawaran]
        NEG[Negotiation<br/>Negosiasi]
        WON[Won<br/>Menang]
        LST2[Lost<br/>Kalah]
    end

    subgraph FEATURES["Fitur Utama"]
        MET[Metrics Bar<br/>5 KPI]
        CRUD[Lead CRUD<br/>Create/Edit/Delete]
        CONV[Lead → Customer<br/>Conversion]
        INV[Invoice<br/>Matching]
        OVD[Overdue<br/>Detection]
    end

    subgraph ENTITIES["Entitas"]
        SP[SalesPipeline]
        CU[Customer]
        IN[Invoice]
    end

    KAN --> STAGES
    LST --> STAGES
    MET --> FEATURES
    CONV --> CU
    INV --> IN
    STAGES --> SP
```

## Akses Halaman

URL: `/sales-pipeline`

## Entitas: SalesPipeline

| Field | Tipe | Deskripsi |
| - | - | - |
| `customer_id` | string | ID pelanggan (setelah konversi) |
| `lead_name` | string | Nama lead |
| `lead_email` | string | Email lead |
| `lead_phone` | string | Telepon lead |
| `company_name` | string | Nama perusahaan lead |
| `assigned_to` | string | ID karyawan yang menangani |
| `pipeline_stage` | enum | Tahap pipeline |
| `estimated_value` | number | Estimasi nilai deal |
| `probability` | number | Probabilitas closing (%) |
| `expected_close_date` | date | Target tanggal closing |
| `actual_close_date` | date | Tanggal closing aktual |
| `source_lead` | enum | Sumber lead |
| `notes` | string | Catatan |
| `company_id` | string | ID perusahaan |
| `created_date` | datetime | Tanggal dibuat |

## 6 Tahap Pipeline

```mermaid theme={null}
stateDiagram-v2
    [*] --> prospect: Lead Baru
    prospect --> qualified: Terkualifikasi
    qualified --> proposal: Buat Proposal
    proposal --> negotiation: Negosiasi
    negotiation --> won: Deal Closed
    negotiation --> lost: Deal Gagal
    
    prospect --> lost: Tidak qualify
    qualified --> lost: Tidak lanjut
    
    won --> [*]
    lost --> [*]
```

| Tahap | Label | Deskripsi | Warna |
| - | - | - | - |
| `prospect` | Prospect | Lead baru masuk | Biru |
| `qualified` | Qualified | Sudah terverifikasi | Cyan |
| `proposal` | Proposal | Penawaran dikirim | Kuning |
| `negotiation` | Negotiation | Sedang negosiasi | Orange |
| `won` | Won | Deal berhasil | Hijau |
| `lost` | Lost | Deal gagal | Merah |

## Sumber Lead

| Source | Label |
| - | - |
| `website` | Website |
| `referral` | Referral |
| `advertisement` | Iklan |
| `cold_call` | Cold Call |
| `social_media` | Media Sosial |
| `event` | Event |
| `other` | Lainnya |

## Metrics Bar

5 KPI ditampilkan di bagian atas pipeline:

| Metrik | Perhitungan | Keterangan |
| - | - | - |
| **Total Pipeline Value** | SUM `estimated_value` | Total nilai seluruh lead aktif |
| **Won Value** | SUM `estimated_value` where stage = `won` | Total nilai deal yang menang |
| **Weighted Forecast** | SUM `estimated_value × probability%` | Forecast tertimbang |
| **Conversion Rate** | `won / (won + lost) × 100%` | Tingkat konversi |
| **Overdue Leads** | COUNT where `expected_close_date < today` AND stage ≠ won/lost | Lead yang lewat target |

## Dual View Mode

### Kanban Board View

Setiap tahap pipeline ditampilkan sebagai kolom, lead sebagai card:

```
┌─────────────┬─────────────┬─────────────┬─────────────┬─────────────┬─────────────┐
│  PROSPECT   │  QUALIFIED  │  PROPOSAL   │ NEGOTIATION │    WON      │    LOST     │
│             │             │             │             │             │             │
│ ┌─────────┐ │ ┌─────────┐ │ ┌─────────┐ │ ┌─────────┐ │ ┌─────────┐ │ ┌─────────┐ │
│ │ Lead A  │ │ │ Lead D  │ │ │ Lead F  │ │ │ Lead H  │ │ │ Lead J  │ │ │ Lead L  │ │
│ │ Rp 5M   │ │ │ Rp 3M   │ │ │ Rp 10M  │ │ │ Rp 8M   │ │ │ Rp 15M  │ │ │ Rp 2M   │ │
│ │ 60%     │ │ │ 70%     │ │ │ 80%     │ │ │ 90%     │ │ │ ✓       │ │ │ ✗       │ │
│ └─────────┘ │ └─────────┘ │ └─────────┘ │ └─────────┘ │ └─────────┘ │ └─────────┘ │
│ ┌─────────┐ │             │             │             │             │             │
│ │ Lead B  │ │             │             │             │             │             │
│ │ Rp 7M   │ │             │             │             │             │             │
│ └─────────┘ │             │             │             │             │             │
└─────────────┴─────────────┴─────────────┴─────────────┴─────────────┴─────────────┘
```

### List View

Tabel dengan kolom: Lead Name, Company, Stage, Value, Probability, Expected Close, Assigned To, Actions.

## Stage Advancement

Tombol **"Maju"** memajukan lead ke tahap berikutnya:

```
prospect → qualified → proposal → negotiation → won
```

Lead di tahap `won` atau `lost` tidak bisa dimajukan lagi.

## Lead-to-Customer Conversion

Saat lead mencapai tahap `won`, sistem bisa mengkonversinya menjadi pelanggan:

```mermaid theme={null}
sequenceDiagram
    participant User
    participant Pipe as SalesPipeline
    participant Dup as Duplicate Check
    participant Cust as Customer Entity
    participant SP as SalesPipeline

    User->>Pipe: Klik "Convert to Customer"
    Pipe->>Dup: Check by email/name
    alt Duplicate Found
        Dup-->>Pipe: Link existing customer
    else No Duplicate
        Pipe->>Cust: Create new Customer
        Cust-->>Pipe: customer_id
    end
    Pipe->>SP: Update stage = 'won', link customer_id
```

### Duplicate Detection

| Check | Field |
| - | - |
| Email match | `lead_email` vs `Customer.email` |
| Name match | `lead_name` vs `Customer.name` |

Jika ditemukan duplikat, lead di-link ke customer yang sudah ada. Jika tidak, customer baru dibuat.

## Invoice Matching

Pipeline cross-reference `Invoice` entity untuk mencocokkan lead dengan invoice yang sudah ada:

| Match Criteria | Field |
| - | - |
| Customer name | `Invoice.customer_name` vs `SalesPipeline.lead_name` |
| Email | `Invoice.customer_email` vs `SalesPipeline.lead_email` |

## Overdue Detection

Lead dianggap overdue jika:

```
expected_close_date < today AND pipeline_stage NOT IN ('won', 'lost')
```

Lead overdue ditandai dengan badge merah di card/tabel.

## Form Lead

### Create/Edit Dialog

| Field | Tipe | Required |
| - | - | - |
| Nama Lead | text | Ya |
| Email | email | Tidak |
| Telepon | tel | Tidak |
| Perusahaan | text | Tidak |
| Sumber Lead | select | Ya |
| Estimasi Nilai | number (Rupiah) | Ya |
| Probabilitas | number (0-100%) | Ya |
| Target Close | date | Ya |
| Assigned To | select | Tidak |
| Catatan | textarea | Tidak |

## React Query

Pipeline menggunakan React Query untuk manajemen data:

| Hook | Fungsi |
| - | - |
| `useQuery` | Fetch SalesPipeline entities |
| `useMutation` | Create/update/delete leads |
| `useQueryClient` | Invalidate cache setelah mutasi |

## Embedded vs Standalone

| Versi | Lokasi | Fitur |
| - | - | - |
| **Embedded** (`SalesFunnelBoard`) | Tab "Pipeline" di `/crm` | UI sederhana, integration banner |
| **Standalone** (`SalesPipelineManagement`) | `/sales-pipeline` | Full-featured, dual view |

Kedua versi menggunakan logic yang sama: stage definitions, source options, entity queries, mutations, dan conversion logic.

## Integrasi dengan CRM

```mermaid theme={null}
flowchart LR
    PIPE[Sales Pipeline] -->|Won + Convert| CUST[Customer]
    CUST -->|POS Transaction| POS[POS]
    CUST -->|Invoice| INV[Invoice]
    INV -->|Payment| FIN[Finance]
```

Lead yang di-convert menjadi customer akan terintegrasi dengan POS, Invoice, dan Finance.

***

## Entity Relationship Diagram

```mermaid theme={null}
erDiagram
    SalesPipeline {
        string _id PK
        string company_id FK
        string lead_id
        string lead_name
        string lead_email
        string lead_phone
        string company_name
        string assigned_to FK
        string pipeline_stage "prospect|qualified|proposal|negotiation|won|lost"
        number estimated_value
        string currency
        number probability
        date expected_close_date
        date actual_close_date
        string source_lead
        array product_interest
        array interaction_history
        string next_action
        date next_action_date
        string notes
        datetime created_date
        datetime updated_date
        string created_by_id FK
    }

    Customer {
        string _id PK
        string company_id FK
        string name
        string email
        string phone
        string company
        string customer_type "individual|business|retail|reseller|distributor|modern_market"
        string status "lead|prospect|customer|inactive"
        number lifetime_value
        number total_orders
        string auth_user_id FK
    }

    CompanyPOSTransaction {
        string _id PK
        string company_id FK
        string transaction_number
        string invoice_number
        datetime transaction_date
        array items
        number subtotal
        number total
        string payment_method
        string payment_status
        string customer_id FK
        string cashier_id FK
        string source
        string order_status
        string sales_channel
    }

    SalesPipeline ||--o| Customer : "convert → won"
    Customer ||--o{ CompanyPOSTransaction : "melakukan transaksi"
    SalesPipeline }o--|| User : "assigned_to (sales person)"
```

## Tabel Schema — SalesPipeline

Schema lengkap entitas `SalesPipeline` berdasarkan definisi JSONC base44 (19 field + system fields):

| # | Field | Tipe | Required | Default | Deskripsi |
| - | - | - | - | - | - |
| 1 | `_id` | string | auto | — | Primary key (base44) |
| 2 | `company_id` | string | **Ya** | — | ID perusahaan (multi-tenant) |
| 3 | `lead_id` | string | Tidak | — | ID prospek/lead (jika diimpor dari sumber eksternal) |
| 4 | `lead_name` | string | **Ya** | — | Nama lengkap prospek |
| 5 | `lead_email` | string | Tidak | — | Email prospek |
| 6 | `lead_phone` | string | Tidak | — | Nomor telepon prospek |
| 7 | `company_name` | string | Tidak | — | Nama perusahaan prospek |
| 8 | `assigned_to` | string | **Ya** | — | ID sales person yang menangani |
| 9 | `pipeline_stage` | enum | Tidak | `"prospect"` | Stage dalam sales pipeline |
| 10 | `estimated_value` | number | Tidak | — | Perkiraan nilai penjualan (Rupiah) |
| 11 | `currency` | string | Tidak | `"IDR"` | Mata uang estimasi |
| 12 | `probability` | number | Tidak | `0` | Probabilitas konversi (0–100%) |
| 13 | `expected_close_date` | date | Tidak | — | Tanggal penutupan yang diharapkan |
| 14 | `actual_close_date` | date | Tidak | — | Tanggal closing aktual |
| 15 | `source_lead` | enum | Tidak | — | Sumber prospek masuk |
| 16 | `product_interest` | array\<string> | Tidak | — | Daftar produk yang diminati |
| 17 | `interaction_history` | array\<object> | Tidak | — | Riwayat interaksi dengan prospek |
| 18 | `next_action` | string | Tidak | — | Deskripsi aksi selanjutnya |
| 19 | `next_action_date` | date | Tidak | — | Tanggal aksi selanjutnya |
| 20 | `notes` | string | Tidak | — | Catatan internal |
| — | `created_date` | datetime | auto | now() | Timestamp pembuatan |
| — | `updated_date` | datetime | auto | now() | Timestamp update terakhir |
| — | `created_by_id` | string | auto | — | ID user pembuat (base44) |

### Sub-schema: `interaction_history[]`

| Field | Tipe | Deskripsi |
| - | - | - |
| `interaction_date` | date | Tanggal interaksi |
| `interaction_type` | enum | Jenis: `call`, `email`, `meeting`, `message` |
| `notes` | string | Catatan interaksi |
| `done_by` | string | ID user yang melakukan interaksi |

## State Machine — Deal Lifecycle

```mermaid theme={null}
stateDiagram-v2
    direction LR

    [*] --> prospect: Lead baru dibuat

    prospect --> qualified: Validasi & kualifikasi
    prospect --> lost: Tidak qualify

    qualified --> proposal: Proposal dikirim
    qualified --> lost: Budget/timeline tidak cocok

    proposal --> negotiation: Negosiasi harga & termin
    proposal --> lost: Proposal ditolak

    negotiation --> won: Deal closed ✓
    negotiation --> lost: Gagal negosiasi

    won --> [*]: Convert ke Customer
    lost --> [*]: Arsip

    state prospect {
        [*] --> ContactLead
        ContactLead --> QualifyCheck
    }

    state negotiation {
        [*] --> PriceDiscuss
        PriceDiscuss --> TermAgree
        TermAgree --> FinalReview
    }
```

### Stage Transition Rules

| Dari → Ke | Syarat | Auto-set Field |
| - | - | - |
| `prospect` → `qualified` | Lead terverifikasi, ada budget & kebutuhan | — |
| `prospect` → `lost` | Lead tidak valid / tidak respon | `actual_close_date` |
| `qualified` → `proposal` | Proposal/penawaran disiapkan | — |
| `qualified` → `lost` | Budget/timeline tidak match | `actual_close_date` |
| `proposal` → `negotiation` | Proposal diterima untuk negosiasi | — |
| `proposal` → `lost` | Proposal ditolak | `actual_close_date` |
| `negotiation` → `won` | Kesepakatan tercapai | `actual_close_date = today` |
| `negotiation` → `lost` | Gagal mencapai kesepakatan | `actual_close_date` |

### Probability by Stage (Default)

| Stage | Default Probability |
| - | - |
| `prospect` | 10% |
| `qualified` | 30% |
| `proposal` | 50% |
| `negotiation` | 75% |
| `won` | 100% |
| `lost` | 0% |

## Sequence Diagrams

### 1. Pembuatan Deal Baru

```mermaid theme={null}
sequenceDiagram
    actor Sales as Sales Person
    participant UI as Pipeline UI
    participant API as base44 API
    participant DB as Database

    Sales->>UI: Klik "Tambah Lead"
    UI->>UI: Buka Create Dialog
    Sales->>UI: Isi form (nama, email, perusahaan, source, estimasi nilai)
    Sales->>UI: Submit form
    UI->>API: INSERT SalesPipeline
    Note right of API: Set default:<br/>pipeline_stage = "prospect"<br/>probability = 10<br/>currency = "IDR"<br/>company_id = active_company_id
    API->>DB: Write document
    DB-->>API: Return _id
    API-->>UI: Created response
    UI->>UI: Invalidate React Query cache
    UI-->>Sales: Lead muncul di kolom Prospect
```

### 2. Stage Progression (Advancement)

```mermaid theme={null}
sequenceDiagram
    actor Sales as Sales Person
    participant UI as Pipeline UI
    participant API as base44 API
    participant DB as Database

    Sales->>UI: Klik "Maju" pada card lead
    UI->>UI: Tentukan next stage
    Note right of UI: prospect→qualified→proposal→<br/>negotiation→won
    UI->>API: UPDATE SalesPipeline {_id}
    Note right of API: Set:<br/>pipeline_stage = next_stage<br/>probability = stage_default
    API->>DB: Patch document
    DB-->>API: Updated
    API-->>UI: Success response
    UI->>UI: Invalidate cache & re-fetch
    UI-->>Sales: Card pindah kolom berikutnya

    alt Stage = "won"
        UI->>UI: Tampilkan tombol "Convert to Customer"
    end
```

### 3. Win/Loss Resolution & Conversion

```mermaid theme={null}
sequenceDiagram
    actor Sales as Sales Person
    participant UI as Pipeline UI
    participant API as base44 API
    participant SP as SalesPipeline
    participant DUP as Duplicate Check
    participant CUST as Customer Entity
    participant POS as CompanyPOSTransaction

    Sales->>UI: Klik "Lost" pada lead
    UI->>API: UPDATE pipeline_stage = "lost", actual_close_date = today
    API-->>UI: Updated
    UI-->>Sales: Lead pindah kolom Lost

    Note over Sales,POS: === Skenario: Deal Won + Convert ===

    Sales->>UI: Stage = "won" → klik "Convert to Customer"
    UI->>API: QUERY Customer WHERE email = lead_email OR name = lead_name
    API-->>UI: Hasil duplicate check

    alt Duplicate Found
        UI->>API: UPDATE SalesPipeline SET customer_id = existing_id
    else No Duplicate
        UI->>API: INSERT Customer {name, email, phone, company, source, status = "customer"}
        API-->>UI: new customer_id
        UI->>API: UPDATE SalesPipeline SET customer_id = new_id
    end

    Note over CUST,POS: Customer aktif → bisa transaksi POS
    POS->>CUST: Referensi customer_id saat transaksi
    CUST-->>POS: Return data customer (name, phone, lifetime_value)
```

## Enum Tables

### `pipeline_stage` — Tahap Pipeline

| Value | Label (ID) | Warna Badge | Probability Default | Deskripsi |
| - | - | - | -: | - |
| `prospect` | Prospect | Biru | 10% | Lead baru masuk, belum diverifikasi |
| `qualified` | Qualified | Cyan | 30% | Lead terverifikasi, ada kebutuhan & budget |
| `proposal` | Proposal | Kuning | 50% | Penawaran/resmi sudah dikirim |
| `negotiation` | Negotiation | Orange | 75% | Sedang negosiasi harga & termin |
| `won` | Won | Hijau | 100% | Deal berhasil disepakati |
| `lost` | Lost | Merah | 0% | Deal gagal / tidak lanjut |

### `source_lead` — Sumber Lead

| Value | Label (ID) | Deskripsi |
| - | - | - |
| `website` | Website | Lead dari formulir kontak website |
| `referral` | Referral | Referensi dari customer/partner existing |
| `advertisement` | Iklan | Dari kampanye iklan (Google Ads, Meta, dll) |
| `cold_call` | Cold Call | Outreach telepon langsung |
| `social_media` | Media Sosial | Dari Instagram, LinkedIn, TikTok, dll |
| `event` | Event | Dari pameran, seminar, atau acara |
| `other` | Lainnya | Sumber lainnya |

### `interaction_type` — Jenis Interaksi

| Value | Label (ID) | Deskripsi |
| - | - | - |
| `call` | Telepon | Panggilan telepon |
| `email` | Email | Korespondensi email |
| `meeting` | Meeting | Pertemuan tatap muka / virtual |
| `message` | Pesan | Chat / WhatsApp / DM |

### `currency` — Mata Uang

| Value | Label | Deskripsi |
| - | - | - |
| `IDR` | Rupiah | Default — Indonesian Rupiah |

## RBAC — Hak Akses Sales Pipeline

Berdasarkan RLS rules dari entity JSONC:

| Operasi | Admin | Owner (created\_by) | Sales (same company) |
| - | :-: | :-: | :-: |
| **Create** | Ya | Ya | Ya (jika `company_id` = `active_company_id`) |
| **Read** | Ya | Ya | Ya (jika `company_id` = `active_company_id`) |
| **Update** | Ya | Ya | Ya (jika `company_id` = `active_company_id`) |
| **Delete** | Ya | Ya | Ya (jika `company_id` = `active_company_id`) |

### RLS Condition Detail

```
$or:
  1. (data.company_id == user.data.active_company_id) AND (company_id NOT IN [null, ""])
  2. created_by_id == user.id
  3. user.role == "admin"
```

**Catatan:**

* Multi-tenant isolation: setiap company hanya melihat data pipeline-nya sendiri.
* Creator fallback: user yang membuat lead tetap bisa akses meski `company_id` berubah.
* Admin override: role `admin` memiliki akses penuh tanpa batasan company.


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