# Product Requirements Document
## AI Sales Agent for Property — Powered by CodeIgniter 4

| | |
|---|---|
| **Versi Dokumen** | 1.0 |
| **Tanggal** | 31 Agustus 2026 |
| **Status** | Draft untuk Review |
| **Target Pembaca** | Product Manager, UI/UX Designer, Backend Developer, Frontend Developer, AI Engineer, QA Engineer, Project Manager |

---

## Daftar Isi

1. [Executive Summary](#1-executive-summary)
2. [Product Vision](#2-product-vision)
3. [Problem Statement](#3-problem-statement)
4. [Goals & Objectives](#4-goals--objectives)
5. [User Personas](#5-user-personas)
6. [User Journey](#6-user-journey)
7. [System Architecture](#7-system-architecture)
8. [Functional Requirements](#8-functional-requirements)
9. [Non Functional Requirements](#9-non-functional-requirements)
10. [AI Agent Architecture](#10-ai-agent-architecture)
11. [AI Agent State Machine](#11-ai-agent-state-machine)
12. [Customer Profiling Design](#12-customer-profiling-design)
13. [Lead Scoring Design](#13-lead-scoring-design)
14. [Follow-up Engine](#14-follow-up-engine)
15. [Knowledge Base](#15-knowledge-base)
16. [AI Tools / Function Calling](#16-ai-tools--function-calling)
17. [Human Handover](#17-human-handover)
18. [Database Design](#18-database-design)
19. [API Requirements](#19-api-requirements)
20. [CodeIgniter 4 Architecture](#20-codeigniter-4-architecture)
21. [Security](#21-security)
22. [Error Handling](#22-error-handling)
23. [Dashboard](#23-dashboard)
24. [Development Roadmap](#24-development-roadmap)
25. [Acceptance Criteria](#25-acceptance-criteria)
26. [Risks & Mitigation](#26-risks--mitigation)
27. [Future Development](#27-future-development)

---

## Asumsi Global

Dokumen ini dibangun di atas beberapa asumsi eksplisit karena beberapa detail belum ditentukan oleh stakeholder. Asumsi ini harus dikonfirmasi sebelum atau selama fase development:

| # | Asumsi | Alasan |
|---|--------|--------|
| A1 | Bot WhatsApp existing menyediakan webhook incoming message berformat JSON (nomor, nama, isi pesan, tipe pesan, timestamp, message ID) dan REST API untuk mengirim pesan (text, image, document). | Diperlukan sebagai kontrak integrasi minimal; kontrak sebenarnya harus dikonfirmasi ke tim WhatsApp bot. |
| A2 | LLM Provider bersifat pluggable, kompatibel dengan format tool/function calling ala OpenAI Chat Completion / Anthropic Messages API. | User tidak menentukan provider spesifik. |
| A3 | Satu nomor WhatsApp customer = satu Lead utama (kecuali di-merge manual oleh admin). | Struktur data paling sederhana untuk MVP. |
| A4 | MVP berjalan single-tenant (satu perusahaan/developer properti), multi-project di dalam tenant yang sama. | Sesuai skala awal; multi-tenant menjadi future improvement. |
| A5 | Tidak menggunakan queue broker (Redis/RabbitMQ) di MVP; concurrency ditangani lewat database locking + cron job interval pendek (1 menit). | Menyederhanakan infrastruktur awal sesuai instruksi "tidak menggunakan n8n sebagai core system" dan minim dependency. |
| A6 | Mata uang default adalah Rupiah (IDR), lokal Indonesia, pesan dan seluruh copy AI menggunakan Bahasa Indonesia. | Konteks pasar properti Indonesia. |

---

## 1. Executive Summary

Aplikasi **AI Sales Agent for Property** adalah sistem back-office berbasis **CodeIgniter 4 + MySQL** yang berfungsi sebagai *AI Sales Agent Engine* di atas WhatsApp Bot yang sudah dimiliki perusahaan. Sistem ini menerima leads dari berbagai sumber, melakukan percakapan otomatis dengan customer melalui WhatsApp, melakukan profiling dan qualifikasi leads secara real-time menggunakan LLM dengan *function calling*, menghitung skor potensi leads, melakukan follow-up otomatis terjadwal, menangani keberatan dasar (objection handling), mengundang customer melakukan site visit, dan pada akhirnya melakukan **handover terstruktur** kepada sales manusia lengkap dengan ringkasan AI (AI Summary) agar sales tidak perlu mengulang percakapan dari nol.

Sistem **tidak menggantikan** peran sales manusia dalam hal site visit, negosiasi, booking, KPR, dan akad — AI berperan sebagai *First Responder, Lead Qualifier, Customer Profiler,* dan *Appointment Setter*.

MVP difokuskan pada 6 fase pengembangan bertahap (lihat [Bab 24](#24-development-roadmap)), dimulai dari fondasi manajemen leads dan percakapan, dilanjutkan dengan AI core (intent detection, profiling, response generation), sales intelligence (scoring, state machine, objection handling), automation (follow-up engine via cron), konversi (site visit, handover), hingga analytics (dashboard).

---

## 2. Product Vision

> **"Menjadi AI-powered Property Sales Agent yang menerima leads, memahami kebutuhan customer secara konsultatif, melakukan profiling otomatis dari percakapan natural, memberi rekomendasi produk yang tepat, menangani keberatan dengan pendekatan konsultatif (bukan agresif), menjadwalkan follow-up yang bervariasi dan relevan, mengukur potensi setiap leads secara objektif, serta mengarahkan customer yang siap ke tahap site visit — sebelum diserahkan secara mulus kepada sales manusia dengan bekal ringkasan lengkap."**

### Peran AI vs Peran Sales Manusia

| Peran AI Sales Agent | Peran Sales Manusia |
|---|---|
| First Responder (respon cepat 24/7) | Site Visit pendampingan langsung |
| Lead Qualifier (menyaring leads awal) | Personal relationship & trust building |
| Customer Profiler (mengumpulkan data dari chat) | Negosiasi harga & term pembayaran |
| Property Consultant (edukasi produk dasar) | Booking fee & dokumen |
| Follow-up Agent (reminder terjadwal, non-repetitif) | Proses KPR bersama bank |
| Appointment Setter (jadwal site visit) | Closing & Akad |
| Sales Assistant (ringkasan customer untuk sales) | Retensi & referral pasca-akad |

---

## 3. Problem Statement

Berdasarkan kondisi bisnis properti saat ini:

1. Volume leads tinggi dari multi-channel (Meta Ads, IG, Landing Page, Referral, dll) melebihi kapasitas follow-up manual sales.
2. Leads baru sering tidak dihubungi dalam waktu responsif (response time lambat = leads dingin).
3. Kualitas follow-up antar sales tidak konsisten — sebagian sales proaktif, sebagian pasif.
4. Customer berhenti merespon karena follow-up repetitif dan tidak relevan ("template spam").
5. Sales kesulitan menggali kebutuhan riil customer karena keterbatasan waktu per leads.
6. Data customer tidak lengkap/tidak terdokumentasi, sehingga sulit dipakai untuk segmentasi.
7. Customer harus mengulang cerita saat pindah dari chatbot/CS ke sales manusia — pengalaman buruk.
8. Leads potensial (hot leads) hilang karena tenggelam di antara leads dingin yang jumlahnya lebih banyak.
9. Waktu sales banyak terpakai untuk leads cold/warm, bukan leads yang benar-benar siap closing.
10. Tidak ada mekanisme otomatis untuk menentukan prioritas leads mana yang harus didahulukan.

**Dampak bisnis:** rendahnya conversion rate dari leads ke site visit dan closing, cost-per-lead yang tinggi menjadi sia-sia, serta beban kerja sales yang tidak proporsional.

---

## 4. Goals & Objectives

### 4.1 Tujuan Produk

| # | Tujuan | Metrik Terkait |
|---|---|---|
| 1 | Menghubungi leads baru secara otomatis dalam < 1 menit sejak masuk | First Response Time |
| 2 | Memahami kebutuhan customer melalui percakapan natural | Profile Completeness Score |
| 3 | Melakukan profiling otomatis tanpa form panjang | % leads dengan profile ≥ 70% lengkap |
| 4 | Memberikan informasi produk relevan dari Knowledge Base | Knowledge Retrieval Accuracy |
| 5 | Melakukan lead qualification & scoring objektif | Distribusi COLD/WARM/HOT/VERY HOT |
| 6 | Menangani objection dasar secara konsultatif | Objection Resolution Rate |
| 7 | Follow-up otomatis non-repetitif | Follow-up Response Rate |
| 8 | Mengarahkan customer ke site visit | Site Visit Conversion Rate |
| 9 | Handover ke sales dengan ringkasan lengkap | Handover Completeness Rate |
| 10 | Menyediakan dashboard funnel end-to-end | Funnel Drop-off Analysis |

### 4.2 Target Funnel Konversi

```
LEAD → CONVERSATION → QUALIFIED LEAD → HOT LEAD → SITE VISIT → SALES HANDOVER → BOOKING → KPR → AKAD
```

### 4.3 Objective Kuantitatif (Target Awal — dapat disesuaikan setelah baseline MVP berjalan)

| Metrik | Target Awal |
|---|---|
| First Response Time | < 1 menit (otomatis via AI) |
| AI Resolution Rate (tanpa handover) | ≥ 40% percakapan awal |
| Qualification Rate | ≥ 50% leads baru mencapai status QUALIFIED |
| Site Visit Conversion dari HOT Lead | ≥ 25% |
| Handover Completeness | 100% handover disertai AI Summary |

---

## 5. User Personas

### 5.1 Admin / Marketing Manager
- **Kebutuhan:** Import leads massal (Excel/CSV/API dari Meta Ads), memantau funnel keseluruhan, konfigurasi Knowledge Base & promosi.
- **Pain point saat ini:** Tidak tahu leads mana yang aktif ditindaklanjuti AI vs mangkrak.

### 5.2 Sales Offline (Sales Consultant)
- **Kebutuhan:** Menerima leads yang sudah "matang" (qualified/hot) lengkap dengan ringkasan kebutuhan, tanpa perlu bertanya ulang dari nol.
- **Pain point saat ini:** Menerima leads mentah tanpa konteks, harus menggali ulang kebutuhan dari awal.

### 5.3 Sales Team Leader / Supervisor
- **Kebutuhan:** Memantau performa AI dan performa masing-masing sales, mengatur distribusi leads antar sales.
- **Pain point saat ini:** Tidak ada visibilitas terhadap kecepatan follow-up dan kualitas closing tiap sales.

### 5.4 Customer (End User via WhatsApp)
- **Kebutuhan:** Mendapat respon cepat, informasi akurat, tidak merasa "dipaksa" atau dispam, dan bisa langsung terhubung ke manusia bila diperlukan.
- **Pain point saat ini:** Respon lambat, informasi tidak konsisten, follow-up repetitif dan mengganggu.

### 5.5 AI Engineer / Backend Developer
- **Kebutuhan:** Dokumentasi tools/function calling yang jelas, struktur state machine yang eksplisit, logging AI yang dapat diaudit dan di-debug.

---

## 6. User Journey

### 6.1 Journey Customer (Happy Path)

```
1. Customer melihat iklan Meta Ads → klik → chat WA
2. Lead otomatis tercatat di sistem (status: NEW)
3. AI merespon dalam <1 menit (status: CONTACTED)
4. Customer membalas (status: RESPONDED)
5. AI menggali kebutuhan (Discovery) → Profiling bertahap
6. AI merekomendasikan produk sesuai kebutuhan (Product Matching)
7. Customer bertanya harga & cicilan → AI hitung simulasi KPR
8. Customer memiliki keberatan (harga/lokasi) → AI Objection Handling
9. Lead score naik → status WARM → HOT
10. AI mengundang site visit → Customer setuju → Appointment dibuat
11. AI melakukan Human Handover ke sales dengan AI Summary
12. Sales melanjutkan: site visit, negosiasi, booking, KPR, akad
```

### 6.2 Journey Customer (Cold / Tidak Merespon)

```
1. Lead baru, AI kirim pesan pembuka
2. Customer tidak membalas
3. Follow-up H+1 (reminder ringan, gaya berbeda dari pesan awal)
4. Tidak membalas → Follow-up H+3 (value proposition/promo)
5. Tidak membalas → Follow-up H+7 (edukasi/urgency)
6. Tidak membalas setelah batas maksimum → status LOST (dapat direaktivasi manual)
```

### 6.3 Journey Sales (Setelah Handover)

```
1. Sales menerima notifikasi leads baru (assigned) + AI Summary
2. Sales membaca ringkasan (profil, budget, objection, buying intent)
3. Sales mengambil alih percakapan (conversation_mode: HUMAN_ACTIVE)
4. Sales melakukan follow-up personal, site visit, negosiasi
5. Sales update status: BOOKING → KPR → AKAD
6. (Opsional) Sales mengembalikan percakapan ke AI bila butuh follow-up rutin non-krusial
```

---

## 7. System Architecture

### 7.1 High-Level Flow

```
Customer
   │
   ▼
WhatsApp
   │
   ▼
Existing WhatsApp Bot  (di luar scope pengembangan)
   │  (Webhook POST)
   ▼
CodeIgniter 4 Backend — Webhook Controller
   │
   ▼
Message Processor (validasi, deduplikasi, normalisasi)
   │
   ▼
AI Sales Agent Engine (Orchestrator / Decision Engine)
   │
   ├─► Customer Profiling Engine
   ├─► Intent Detection
   ├─► Knowledge Base Retrieval
   ├─► Lead Scoring Engine
   ├─► Objection Handling Engine
   ├─► Next Best Action Engine
   │
   ▼
AI Response Generator (LLM + Tool Calling)
   │
   ▼
WhatsApp Bot API (Send Message)
   │
   ▼
Customer
```

### 7.2 Alur Konversi ke Sales

```
AI Agent
   │  (buying intent tinggi terdeteksi)
   ▼
Site Visit Invitation
   │
   ▼
Appointment Scheduling
   │
   ▼
Assign Sales (rule-based / round-robin / manual)
   │
   ▼
Human Handover (AI Summary dikirim ke sales)
   │
   ▼
Sales Offline (conversation_mode: HUMAN_ACTIVE)
```

### 7.3 Komponen Utama

| Komponen | Tanggung Jawab |
|---|---|
| Webhook Controller | Menerima payload dari WhatsApp Bot, validasi signature/token |
| Message Processor | Deduplikasi (message_id), normalisasi format, simpan ke `messages` |
| AI Sales Agent Engine | Orkestrasi seluruh proses AI (lihat Bab 10) |
| Knowledge Base Service | Retrieval informasi produk/promo/FAQ |
| Lead Scoring Service | Hitung skor & temperature leads |
| Follow-up Scheduler (Cron) | Eksekusi follow-up terjadwal |
| WhatsApp Gateway Service | Wrapper pemanggilan API bot WA existing (send message) |
| Notification Service | Notifikasi ke sales (WA/Email/in-app) saat handover |

### 7.4 Diagram Komponen (Konseptual)

```
┌─────────────────────────────────────────────────────────────┐
│                     CodeIgniter 4 Backend                     │
│                                                                 │
│  ┌──────────────┐   ┌───────────────────┐   ┌──────────────┐ │
│  │  Controllers  │──▶│      Services      │──▶│    Models     │ │
│  │  (Webhook,    │   │  AI/, Sales/,      │   │ (Eloquent-    │ │
│  │   API, Admin) │   │  WhatsApp/         │   │  style CI4)   │ │
│  └──────────────┘   └───────────────────┘   └──────────────┘ │
│         │                     │                      │         │
│         ▼                     ▼                      ▼         │
│  ┌──────────────┐   ┌───────────────────┐   ┌──────────────┐ │
│  │   Filters     │   │  Libraries/AiTools │   │    MySQL      │ │
│  │  (Auth, Rate  │   │  (Tool Calling     │   │   Database    │ │
│  │   Limit)      │   │   Implementations) │   │               │ │
│  └──────────────┘   └───────────────────┘   └──────────────┘ │
│                                                                 │
│  ┌──────────────┐   ┌───────────────────┐                     │
│  │   Commands    │   │      Events        │                     │
│  │ (Spark CLI —  │   │  (LeadStatusChanged,│                     │
│  │  Cron Jobs)   │   │   HandoverTriggered)│                     │
│  └──────────────┘   └───────────────────┘                     │
└─────────────────────────────────────────────────────────────┘
          │                                        │
          ▼                                        ▼
  ┌───────────────┐                       ┌────────────────┐
  │  LLM API       │                       │ WhatsApp Bot    │
  │ (Function      │                       │ API (existing)  │
  │  Calling)      │                       │                 │
  └───────────────┘                       └────────────────┘
```

---

## 8. Functional Requirements

Functional requirements dijabarkan per modul secara detail di Bab 10–17. Ringkasan modul:

| Kode | Modul | Ringkasan |
|---|---|---|
| FR-A | Lead Management | Input, import, tracking, status pipeline leads |
| FR-B | Conversation Management | Penyimpanan & lifecycle percakapan, mode AI/Human |
| FR-C | Customer Profiling Engine | Ekstraksi profil dari percakapan otomatis |
| FR-D | AI Intent Detection | Klasifikasi intent, sentiment, urgency |
| FR-E | AI Sales Agent Engine (Decision Engine) | Orkestrasi seluruh proses pengambilan keputusan AI |
| FR-F | AI State Machine | Journey state customer |
| FR-G | Knowledge Base | Sumber informasi produk yang akurat, tanpa halusinasi |
| FR-H | AI Tools/Function Calling | Aksi nyata yang dapat dipanggil AI |
| FR-I | Lead Scoring | Perhitungan skor & temperature leads |
| FR-J | Follow-up Engine | Follow-up otomatis terjadwal, non-repetitif |
| FR-K | Objection Handling | Deteksi & penanganan keberatan customer |
| FR-L | Next Best Action | Penentuan tindakan optimal berikutnya |
| FR-M | Site Visit Appointment | Penjadwalan kunjungan lokasi |
| FR-N | Human Handover | Transfer percakapan ke sales dengan ringkasan |
| FR-O | Dashboard & Analytics | Visibilitas funnel, performa AI, performa sales |

Detail requirement, user flow, business rule, database requirement, dan acceptance criteria untuk setiap modul dijelaskan pada bab-bab berikut.

---

## MODUL A — LEAD MANAGEMENT

### Functional Requirements

- FR-A1: Sistem dapat menambahkan lead secara manual melalui form admin.
- FR-A2: Sistem dapat mengimpor leads dari file Excel (.xlsx) dan CSV dengan template kolom standar (nama, nomor WA, sumber, campaign, project, catatan).
- FR-A3: Sistem menyediakan REST API untuk menerima leads dari sumber eksternal (Meta Lead Ads via integrasi pihak ketiga/manual, landing page, website).
- FR-A4: Setiap lead memiliki atribut source (Meta Ads, Facebook Lead Ads, Instagram, Landing Page, Website, WhatsApp, Referral, Import Excel, Manual Input).
- FR-A5: Sistem mendukung campaign tracking (nama campaign, ad set, ad id opsional) dan project tracking (leads terkait project properti tertentu).
- FR-A6: Leads dapat di-assign ke sales tertentu, baik manual maupun otomatis (round robin/rule-based).
- FR-A7: Sistem mencatat lead status mengikuti pipeline baku dan lead temperature (COLD/WARM/HOT/VERY HOT) serta lead score numerik.
- FR-A8: Duplikasi lead (nomor WA sama) dideteksi otomatis saat import/API — opsi merge atau skip.

### Status Pipeline

```
NEW → CONTACTED → RESPONDED → QUALIFIED → WARM → HOT → SITE_VISIT → BOOKING → KPR → AKAD
                                                                                          ↘
                                                                                          LOST (dapat terjadi di titik manapun)
```

| Status | Deskripsi | Trigger Masuk |
|---|---|---|
| NEW | Lead baru masuk, belum dihubungi | Import/API/manual |
| CONTACTED | AI sudah mengirim pesan pertama | AI kirim pesan pembuka |
| RESPONDED | Customer membalas minimal 1x | Incoming message pertama dari customer |
| QUALIFIED | Profil dasar (kebutuhan, budget kasar) terkumpul | Profile completeness ≥ threshold |
| WARM | Skor menengah, tertarik tapi belum urgent | Lead score dalam rentang WARM |
| HOT | Skor tinggi, buying intent kuat | Lead score dalam rentang HOT |
| SITE_VISIT | Appointment site visit dibuat/terjadwal | Appointment created |
| BOOKING | Customer melakukan booking unit | Update manual oleh sales |
| KPR | Proses KPR berjalan | Update manual oleh sales |
| AKAD | Transaksi selesai | Update manual oleh sales |
| LOST | Leads tidak berlanjut/menolak | Manual, atau otomatis setelah follow-up maksimum tanpa respon |

### Business Rules

- BR-A1: Perubahan status wajib tercatat di `lead_status_history` (audit trail) dengan actor (AI/Sales/System) dan timestamp.
- BR-A2: Status tidak boleh mundur otomatis oleh AI (misal dari HOT ke WARM) — penurunan status hanya via aturan eksplisit (leads tidak respon dalam periode tertentu) atau manual oleh sales.
- BR-A3: Lead yang berstatus BOOKING/KPR/AKAD tidak dapat diubah AI secara otomatis — locked untuk perubahan oleh sales/admin saja.
- BR-A4: Satu nomor WA = satu lead aktif; jika ada leads baru dengan nomor sama pada project berbeda, sistem membuat entri `lead_project_interest` tambahan alih-alih duplikasi lead utama.

### Database Requirement

Lihat detail tabel `leads`, `lead_status_history`, `lead_sources` pada [Bab 18](#18-database-design).

### Acceptance Criteria

- [ ] AC-A1: Admin dapat mengimpor 500 baris Excel dalam < 30 detik dengan laporan sukses/gagal per baris.
- [ ] AC-A2: API `POST /leads` menerima payload dan mengembalikan `lead_id` dalam response < 500ms.
- [ ] AC-A3: Setiap perubahan status tercatat di history dengan actor yang benar.
- [ ] AC-A4: Duplikasi nomor WA terdeteksi dan ditampilkan sebagai warning saat import.

---

## MODUL B — CONVERSATION MANAGEMENT

### Functional Requirements

- FR-B1: Seluruh pesan (incoming & outgoing) tersimpan dengan lengkap: isi pesan, sender type, timestamp, message status (sent/delivered/read/failed).
- FR-B2: Sistem membedakan sender: `CUSTOMER`, `AI`, `SALES`, `SYSTEM`.
- FR-B3: Setiap conversation memiliki `conversation_mode` yang menentukan siapa yang aktif merespon.
- FR-B4: Sales dapat melakukan takeover manual kapan pun (override AI), dan dapat mengembalikan kontrol ke AI.
- FR-B5: AI tidak boleh mengirim pesan ketika `conversation_mode` = `HUMAN_ACTIVE`.

### Conversation Mode

| Mode | Deskripsi |
|---|---|
| AI_ACTIVE | AI merespon otomatis |
| WAITING_HUMAN | AI sudah trigger handover, menunggu sales mengambil alih (AI berhenti merespon, pesan customer di-hold/dinotifikasi ke sales) |
| HUMAN_ACTIVE | Sales sedang aktif menangani percakapan, AI nonaktif |
| CLOSED | Percakapan ditutup/diarsipkan (leads LOST atau AKAD selesai) |

### Conversation Lifecycle

```
[Lead Baru] → AI_ACTIVE
     │
     │ (trigger handover: high intent / request human / objection kompleks)
     ▼
WAITING_HUMAN  ──(sales membuka chat)──▶ HUMAN_ACTIVE
     │                                         │
     │ (timeout, tidak diambil sales)          │ (sales pilih "kembalikan ke AI")
     ▼                                         ▼
[Notifikasi eskalasi ke supervisor]        AI_ACTIVE
                                                │
                                     (leads closed/lost/akad)
                                                ▼
                                             CLOSED
```

### Database Requirement

Lihat tabel `conversations`, `messages` pada [Bab 18](#18-database-design).

### Human Takeover Mechanism

1. Sales membuka detail leads di dashboard → klik "Ambil Alih Percakapan".
2. Sistem update `conversations.mode` = `HUMAN_ACTIVE`, `assigned_sales_id` = sales tersebut.
3. Event `ConversationTakenOver` dipicu → dicatat di log, AI berhenti memproses pesan masuk untuk conversation ini kecuali dikembalikan.
4. Sales dapat mengetik pesan via dashboard (dikirim melalui WhatsApp Gateway Service) — tersimpan sebagai sender `SALES`.
5. Sales dapat klik "Kembalikan ke AI" → mode kembali `AI_ACTIVE`.

### Acceptance Criteria

- [ ] AC-B1: 100% pesan masuk/keluar tersimpan dengan sender type yang benar.
- [ ] AC-B2: Ketika mode `HUMAN_ACTIVE`, AI tidak mengirim respon otomatis (diverifikasi via log `ai_conversation_logs` kosong pada periode tsb).
- [ ] AC-B3: Takeover oleh sales tercermin real-time di dashboard (< 2 detik update status).

---

## MODUL C — CUSTOMER PROFILING ENGINE

### Desain Sistem

AI mengumpulkan data profil customer **secara bertahap dan implisit** dari percakapan natural, tanpa form. Setiap kali AI memproses pesan customer, LLM diminta melakukan ekstraksi informasi terstruktur (melalui *structured output* / tool call `updateCustomerProfile()`) berdasarkan isi pesan terbaru dan histori percakapan.

### Kategori Profile

| Kategori | Field | Tipe |
|---|---|---|
| **Personal** | nama, umur, pekerjaan, perusahaan, lokasi kerja | FACT/INFERENCE |
| **Family** | status pernikahan, jumlah anak, jumlah anggota keluarga | FACT/INFERENCE |
| **Financial** | estimasi penghasilan, budget rumah, budget DP, kemampuan cicilan bulanan, metode pembayaran (cash/KPR) | FACT/INFERENCE |
| **Property Preference** | tujuan beli (rumah pertama/tinggal/investasi/upgrade), lokasi diminati, tipe rumah, jumlah kamar, project diminati, produk diminati | FACT/INFERENCE |
| **Buying Intent** | kapan ingin membeli, purchase timeline, urgency, readiness | FACT/INFERENCE |
| **Objection** | harga, DP, cicilan, lokasi, jarak, legalitas, KPR, pasangan, masih membandingkan project | FACT/INFERENCE |

### FACT vs AI INFERENCE

Setiap field profil memiliki:
- `value`: nilai yang tersimpan
- `source_type`: `FACT` (customer eksplisit menyatakan) atau `INFERENCE` (AI menyimpulkan dari konteks, misal: "kerja di bank, biasanya budget menengah ke atas")
- `confidence`: skor 0.0–1.0 untuk INFERENCE (FACT selalu 1.0)
- `evidence_message_id`: referensi ke `messages.id` yang menjadi bukti/dasar
- `updated_at`, `updated_by` (`AI`/`SALES`/`SYSTEM`)

**Aturan penting:** Field dengan `source_type = INFERENCE` dan `confidence < 0.6` **tidak boleh digunakan sebagai dasar keputusan otomatis** (misal menaikkan lead score signifikan) — hanya ditampilkan sebagai "dugaan" kepada sales. Field `FACT` diprioritaskan menimpa `INFERENCE` bila ada konflik.

### Alur Kerja

```
Pesan customer masuk
     │
     ▼
LLM menganalisis pesan + histori percakapan
     │
     ▼
LLM memanggil tool updateCustomerProfile(fields[])
     │
     ▼
Setiap field divalidasi: FACT atau INFERENCE?
     │
     ▼
Sistem menyimpan ke lead_profiles (nilai terkini)
     │
     ▼
Sistem mencatat ke lead_profile_history (audit/versioning)
     │
     ▼
Trigger recalculation Lead Score (jika field relevan)
```

### Business Rules

- BR-C1: AI tidak boleh menanyakan ulang informasi yang sudah tercatat sebagai FACT kecuali customer mengoreksi.
- BR-C2: Data sensitif (penghasilan) hanya disimpan jika customer menyebutkan secara sukarela — AI tidak boleh memaksa/mendesak.
- BR-C3: Profile completeness dihitung dari jumlah field FACT terisi dibagi total field kunci (lihat Bab 13).

### Acceptance Criteria

- [ ] AC-C1: Setelah 5 pertukaran pesan pada skenario normal, minimal 40% field kunci (budget, lokasi, tujuan beli) tercatat.
- [ ] AC-C2: Setiap field profil memiliki `source_type` yang benar dan `evidence_message_id` yang valid.
- [ ] AC-C3: Riwayat perubahan profil dapat ditelusuri lengkap per field.

---

## MODUL D — AI INTENT DETECTION

### Cara Kerja

Setiap pesan masuk dari customer diproses oleh LLM dengan prompt khusus intent classification (dapat berupa *single-call* bersamaan dengan response generation menggunakan structured output, untuk efisiensi biaya & latency). Output terstruktur:

```json
{
  "intent": "PRICE_INQUIRY",
  "confidence": 0.92,
  "sentiment": "neutral",
  "urgency": "medium",
  "recommended_action": "CALCULATE_KPR_SIMULATION"
}
```

### Daftar Intent

| Intent | Deskripsi |
|---|---|
| GREETING | Sapaan awal |
| PRODUCT_INQUIRY | Bertanya produk/unit |
| PRICE_INQUIRY | Bertanya harga |
| PROMO_INQUIRY | Bertanya promosi |
| LOCATION_INQUIRY | Bertanya lokasi |
| FACILITY_INQUIRY | Bertanya fasilitas |
| KPR_INQUIRY | Bertanya KPR |
| INSTALLMENT_INQUIRY | Bertanya cicilan |
| SITE_VISIT | Ingin/bertanya kunjungan lokasi |
| OBJECTION_PRICE | Keberatan harga |
| OBJECTION_LOCATION | Keberatan lokasi |
| OBJECTION_INSTALLMENT | Keberatan cicilan |
| COMPARE_PRODUCT | Membandingkan produk/project lain |
| NOT_INTERESTED | Menyatakan tidak tertarik |
| FOLLOW_UP | Respon terhadap follow-up |
| HUMAN_REQUEST | Meminta bicara dengan manusia |
| UNKNOWN | Tidak terklasifikasi jelas |

### Penggunaan dalam Sistem

- Intent + confidence menjadi salah satu input utama **Next Best Action Engine** (Bab 13/Modul terkait).
- `HUMAN_REQUEST` dengan confidence tinggi → trigger langsung ke Human Handover (Bab 17).
- Intent kategori `OBJECTION_*` → trigger Objection Handling Engine.
- Sentiment negatif berturut-turut (≥2x) → menaikkan prioritas eskalasi ke sales.
- Semua hasil deteksi intent dicatat di `ai_conversation_logs` untuk analisis & continuous improvement prompt.

### Acceptance Criteria

- [ ] AC-D1: Akurasi klasifikasi intent ≥ 85% pada sample uji manual (100 pesan representatif).
- [ ] AC-D2: Intent `HUMAN_REQUEST` memicu handover dalam < 5 detik dari pesan diterima.
- [ ] AC-D3: Confidence rendah (< 0.5) menghasilkan `recommended_action = CLARIFY` bukan asumsi sepihak.

---

## MODUL E — AI SALES AGENT ENGINE (DECISION ENGINE)

### Alur Proses per Pesan Masuk

```
1. Understand customer message         → Normalisasi teks, cek bahasa, cek konten media
2. Analyze intent                      → Modul D
3. Check customer profile              → Ambil lead_profiles terkini
4. Check conversation state            → Ambil ai_agent_states terkini (Bab 11)
5. Check lead status & score           → Ambil leads.status, leads.score
6. Check product knowledge             → Retrieval dari Knowledge Base (Bab 15)
7. Determine sales strategy            → Berdasarkan state + intent + objection profile
8. Determine next best action          → Rule Engine (Bab 13-Next Best Action)
9. Generate response                   → LLM dengan tool calling (Bab 16)
10. Update profile                     → Tool updateCustomerProfile()
11. Update lead score                  → Tool calculateLeadScore()
12. Schedule follow-up jika diperlukan → Tool scheduleFollowUp()
```

### Decision Engine — Prinsip Kerja

Decision Engine adalah **kombinasi rule-based pre/post-processing** dengan **LLM sebagai reasoning core**:

1. **Pre-processing (deterministic/rule-based):** Sistem menyiapkan *context payload* untuk LLM — profil terkini, state, skor, hasil retrieval Knowledge Base, riwayat percakapan (N pesan terakhir), dan daftar tools yang boleh dipanggil sesuai state saat ini (lihat kolom "Allowed Actions" di Bab 11).
2. **LLM Reasoning:** LLM menerima system prompt (persona sales konsultatif, rules ketat "jangan mengarang informasi", instruksi format output) + context payload, lalu menghasilkan response teks dan/atau tool calls.
3. **Tool Execution Loop:** Jika LLM memanggil tool, sistem mengeksekusi tool tersebut (Bab 16), mengembalikan hasilnya ke LLM (multi-turn tool use), hingga LLM menghasilkan final response teks untuk customer.
4. **Post-processing (deterministic):** Validasi response (tidak melebihi batas panjang WA, tidak mengandung informasi yang tidak ada di Knowledge Base — cross-check dasar), simpan log keputusan (`ai_tool_logs`, `ai_conversation_logs`), kirim pesan via WhatsApp Gateway Service.

### Diagram Decision Engine

```
┌────────────────────────────────────────────────────────┐
│                     Incoming Message                      │
└───────────────────────────┬────────────────────────────┘
                             ▼
                  ┌─────────────────────┐
                  │ Context Builder      │ (profile, state, score,
                  │ (deterministic)      │  history, KB snapshot)
                  └──────────┬──────────┘
                             ▼
                  ┌─────────────────────┐
                  │   LLM Reasoning       │◄────┐
                  │ (Intent + Response +  │     │ tool result
                  │  Tool Calls)          │     │
                  └──────────┬──────────┘     │
                             │                   │
                    tool_call?│ yes              │
                             ▼                   │
                  ┌─────────────────────┐        │
                  │  Tool Executor        │────────┘
                  │  (Libraries/AiTools)  │
                  └──────────┬──────────┘
                             │ no more tool calls
                             ▼
                  ┌─────────────────────┐
                  │ Response Validator    │
                  │ (guardrails)          │
                  └──────────┬──────────┘
                             ▼
                  ┌─────────────────────┐
                  │ Send via WA Gateway   │
                  └─────────────────────┘
```

### Guardrails Wajib

- AI dilarang menyebutkan harga/promo yang tidak ada di Knowledge Base (Bab 15) — jika tidak ditemukan, AI harus menyatakan akan dikonfirmasi tim terkait.
- AI dilarang berjanji hal yang tidak bisa dipenuhi (misal "pasti disetujui KPR").
- AI wajib menggunakan gaya bahasa konsultatif, tidak agresif/mendesak (khususnya saat objection handling).
- Setiap keputusan (state transition, score update, tool call) wajib memiliki log yang bisa diaudit.

---

## 9. Non Functional Requirements

Lihat detail lengkap NFR (performance, scalability, availability, dsb) di [Bab 22 versi user] — dikonsolidasikan di bawah:

| Kategori | Requirement |
|---|---|
| **Performance** | Waktu respon AI end-to-end (webhook diterima → pesan terkirim) target < 8 detik pada kondisi normal (termasuk 1 LLM call + maksimal 2 tool call). |
| **Scalability** | Arsitektur modular (service layer terpisah) agar mudah dipindah ke arsitektur queue-based saat volume meningkat; database diindeks pada kolom pencarian utama (`phone_number`, `status`, `assigned_sales_id`). |
| **Availability** | Target uptime backend 99.5%; webhook endpoint harus idempotent agar retry dari WA Bot tidak menyebabkan duplikasi. |
| **Security** | Lihat Bab 21. |
| **Logging** | Seluruh interaksi AI (input, output, tool calls, keputusan) tercatat terstruktur di `ai_conversation_logs` & `ai_tool_logs` dengan retention minimal 12 bulan. |
| **Monitoring** | Endpoint health-check (`/health`), monitoring cron job (last run timestamp, status sukses/gagal), alert jika LLM API error rate > threshold. |
| **Error Handling** | Lihat Bab 22/23. |
| **AI Timeout** | Timeout LLM API call: 20 detik. Jika timeout, sistem mengirim fallback response dan mencatat error. |
| **Retry Mechanism** | Retry otomatis (max 2x, exponential backoff) untuk kegagalan transient pada LLM API dan WhatsApp Gateway API. |
| **Fallback Response** | Jika seluruh retry gagal, sistem mengirim pesan fallback standar ("Mohon maaf, sedang ada kendala teknis, tim kami akan segera membantu") dan memicu notifikasi ke admin. |
| **Data Backup** | Backup database harian (automated `mysqldump` via cron), retensi 30 hari. |
| **Audit Trail** | Seluruh perubahan status leads, profile, dan handover tercatat dengan actor dan timestamp. |

---

## 10. AI Agent Architecture

Sudah dijabarkan detail pada **Modul E** (Bab AI Sales Agent Engine) di atas — mencakup alur 12 langkah proses per pesan, prinsip kerja Decision Engine, diagram, dan guardrails.

### Layered View AI Engine

```
┌───────────────────────────────────────────────┐
│  Orchestration Layer                            │
│  Services/AI/SalesAgentOrchestrator.php         │
├───────────────────────────────────────────────┤
│  Reasoning Layer                                │
│  Services/AI/LlmClient.php (wrapper API LLM)    │
├───────────────────────────────────────────────┤
│  Domain Services                                │
│  Services/AI/IntentDetectionService.php         │
│  Services/AI/ProfilingService.php               │
│  Services/AI/LeadScoringService.php             │
│  Services/AI/ObjectionHandlingService.php       │
│  Services/AI/NextBestActionService.php          │
│  Services/AI/KnowledgeBaseService.php           │
├───────────────────────────────────────────────┤
│  Tool Execution Layer                           │
│  Libraries/AiTools/*.php                        │
├───────────────────────────────────────────────┤
│  Data Layer                                     │
│  Models/*.php → MySQL                           │
└───────────────────────────────────────────────┘
```

---

## 11. AI Agent State Machine

State machine merepresentasikan **journey customer**, terpisah dari `leads.status` (pipeline bisnis) — state ini lebih granular untuk mengarahkan *behavior* AI dalam percakapan.

| State | Tujuan | AI Behavior | Exit Condition / Trigger | Allowed Actions | Next State |
|---|---|---|---|---|---|
| **NEW_LEAD** | Memulai kontak pertama | Kirim salam pembuka, perkenalan singkat, tanya kebutuhan dasar | Customer merespon | sendMessage, updateLeadStatus | QUALIFICATION |
| **QUALIFICATION** | Menyaring apakah leads relevan (bukan salah sasaran/spam) | Tanya tujuan beli, area minat secara ringan | Info dasar diperoleh (tujuan beli + area) | updateCustomerProfile, calculateLeadScore | DISCOVERY |
| **DISCOVERY** | Menggali kebutuhan mendalam | Tanya budget, tipe rumah, jumlah kamar, timeline | Profile completeness ≥ 50% | updateCustomerProfile, getProductDetail | PRODUCT_MATCHING |
| **PRODUCT_MATCHING** | Mencocokkan kebutuhan dengan produk tersedia | Panggil checkProductAvailability, rekomendasikan 1-3 unit relevan | Produk cocok ditemukan & disampaikan | checkProductAvailability, getProductDetail | PRODUCT_EDUCATION |
| **PRODUCT_EDUCATION** | Edukasi detail produk, harga, fasilitas, promo | Jelaskan spesifikasi, hitung simulasi KPR bila diminta | Customer menunjukkan ketertarikan/keberatan | getActivePromotion, calculateKpr | OBJECTION_HANDLING atau FOLLOW_UP atau VISIT_INVITATION |
| **OBJECTION_HANDLING** | Menangani keberatan tanpa memaksa | Klarifikasi concern, berikan solusi/alternatif konsultatif | Objection teratasi / tereskalasi | updateCustomerProfile (objection), handoverToHuman (jika kompleks) | PRODUCT_EDUCATION atau FOLLOW_UP atau HUMAN_HANDOVER |
| **FOLLOW_UP** | Menjaga engagement saat customer pasif/tidak merespon | Kirim pesan follow-up terjadwal dengan strategi bervariasi | Customer merespon kembali, atau mencapai batas follow-up | scheduleFollowUp | Kembali ke state sebelum idle, atau LOST |
| **VISIT_INVITATION** | Mengajak site visit saat intent tinggi terdeteksi | Tawarkan jadwal kunjungan, jelaskan benefit | Customer setuju/menolak | createAppointment | VISIT_SCHEDULED atau FOLLOW_UP |
| **VISIT_SCHEDULED** | Appointment terkonfirmasi | Kirim konfirmasi & reminder, siapkan handover | Waktu appointment mendekat / tercapai | assignSales, handoverToHuman | HUMAN_HANDOVER |
| **HUMAN_HANDOVER** | Transfer ke sales manusia | Kirim AI Summary, hentikan respon otomatis | Sales mengambil alih (conversation_mode = HUMAN_ACTIVE) | getConversationSummary, handoverToHuman | BOOKING (dikelola sales) |
| **BOOKING** | Dikelola sales, AI pasif | AI tidak merespon kecuali diminta sales | Update manual oleh sales | (locked, hanya SYSTEM/SALES) | KPR |
| **KPR** | Dikelola sales, AI pasif | AI tidak merespon kecuali diminta sales | Update manual oleh sales | (locked) | AKAD |
| **AKAD** | Transaksi selesai | AI tidak aktif; opsional AI kirim ucapan selamat | Manual | (locked) | (terminal) |
| **LOST** | Leads tidak berlanjut | AI berhenti follow-up | Manual atau otomatis (follow-up maksimum tercapai) | (dapat direaktivasi manual oleh admin) | NEW_LEAD (jika direaktivasi) |

**Catatan implementasi:** state disimpan di tabel `ai_agent_states` (1 baris aktif per lead + histori transisi di kolom terpisah/tabel log), sehingga AI Sales Agent Engine dapat membaca `current_state` sebelum menentukan *allowed actions* mana yang boleh dipanggil LLM.

---

## 12. Customer Profiling Design

Sudah dijabarkan detail lengkap pada **Modul C** di atas (kategori profile, FACT vs INFERENCE, alur kerja, business rules, acceptance criteria).

---

## 13. Lead Scoring Design

### Prinsip

Skor leads dipisah menjadi dua komponen utama agar dapat dianalisis independen:

1. **Profile Completeness Score (PCS)** — seberapa lengkap data profil terkumpul (0–100).
2. **Buying Intent Score (BIS)** — seberapa kuat sinyal niat beli, gabungan dari explicit data + behavioral data (0–100).

**Total Lead Score = (PCS × 30%) + (BIS × 70%)**

*Rasional pembobotan:* buying intent lebih menentukan prioritas follow-up sales dibanding kelengkapan data semata — customer dengan intent tinggi tapi profil belum lengkap tetap harus diprioritaskan.

### 13.1 Profile Completeness Score (PCS)

Dihitung dari jumlah field kunci yang terisi dengan `source_type = FACT` dibagi total field kunci, dikali 100.

| Kategori | Field Kunci Dihitung | Bobot per Field |
|---|---|---|
| Property Preference | tujuan beli, lokasi diminati, tipe rumah | 15 masing-masing |
| Financial | budget rumah, metode pembayaran | 15 masing-masing |
| Buying Intent | timeline pembelian | 15 |
| Personal | pekerjaan | 10 |

*(Total maksimum = 100. Field INFERENCE dihitung dengan bobot × confidence, maksimum kontribusi 50% dari bobot penuh.)*

### 13.2 Buying Intent Score (BIS)

**Explicit Data (bobot 40% dari BIS)**

| Sinyal | Poin |
|---|---|
| Budget disebutkan secara eksplisit | +15 |
| Metode pembayaran diketahui | +10 |
| Timeline pembelian < 3 bulan | +15 |
| Timeline pembelian 3–6 bulan | +8 |
| Timeline pembelian > 6 bulan / belum pasti | +2 |

**Behavioral Data (bobot 35% dari BIS)**

| Sinyal | Poin |
|---|---|
| Membalas dalam < 1 jam (rata-rata) | +10 |
| Bertanya harga | +8 |
| Bertanya promo | +5 |
| Bertanya simulasi KPR | +10 |
| Bertanya lokasi/akses | +5 |
| Bertanya legalitas | +7 |
| Bersedia dijadwalkan site visit | +15 |

**Buying Intent Eksplisit dari Percakapan (bobot 25% dari BIS)**

| Sinyal | Poin |
|---|---|
| Menyatakan "mau beli segera" / urgent | +20 |
| Sedang survey/membandingkan (tanpa penolakan) | +10 |
| Hanya mencari informasi umum tanpa niat jelas | +2 |
| Menyatakan tidak tertarik (NOT_INTERESTED) | -30 |

*Skor dinormalisasi ke skala 0–100 sesuai bobot kategori masing-masing (Explicit×0.4 + Behavioral×0.35 + Intent×0.25, masing-masing dinormalisasi dulu ke 0–100 sebelum dikalikan bobot).*

### 13.3 Temperature Mapping

| Total Lead Score | Temperature |
|---|---|
| 0 – 29 | COLD |
| 30 – 54 | WARM |
| 55 – 79 | HOT |
| 80 – 100 | VERY HOT |

### 13.4 Contoh Perhitungan

**Kasus:** Customer sudah menyebutkan budget (FACT), metode KPR (FACT), timeline "3 bulan lagi", membalas cepat, bertanya harga & KPR, belum menyebutkan lokasi spesifik, belum bersedia dijadwalkan visit.

- PCS: tujuan beli (15) + budget (15) + metode pembayaran (15) + timeline (15) = 60/100 (lokasi & pekerjaan belum terisi)
- BIS Explicit: budget (15) + metode (10) + timeline 3-6 bln (8) = 33 → dinormalisasi terhadap maks 40 poin kategori = ~82.5 dari 100 skala kategori
- BIS Behavioral: respon cepat (10) + tanya harga (8) + tanya KPR (10) = 28 → dari maks 55 poin kategori ≈ 51
- BIS Intent: belum ada pernyataan urgent eksplisit → asumsikan "sedang survey" (10) → dari maks 20 ≈ 50
- BIS Total ≈ (82.5×0.4)+(51×0.35)+(50×0.25) ≈ 33+17.85+12.5 ≈ 63.35
- **Total Lead Score = (60×0.3)+(63.35×0.7) = 18 + 44.3 ≈ 62.3 → Temperature: HOT**

*(Catatan: formula dan bobot di atas adalah baseline awal untuk MVP dan harus dikalibrasi ulang menggunakan data historis setelah 1-2 bulan berjalan.)*

### 13.5 Trigger Recalculation

Lead score dihitung ulang setiap kali: profil diperbarui, intent baru terdeteksi, atau appointment site visit dibuat/dibatalkan. Riwayat skor tersimpan di `lead_score_history` untuk analisis tren.

---

## 14. Follow-up Engine

### Strategi Follow-up

Follow-up **tidak boleh berupa pesan template yang sama berulang**. Sistem menggunakan pustaka strategi berbeda per tahap:

| Tahap | Interval Default | Strategi | Contoh Pendekatan |
|---|---|---|---|
| Follow-up 1 | H+1 (dari pesan terakhir tanpa respon) | Reminder ringan | "Halo Kak, masih ada yang bisa dibantu terkait [produk]?" |
| Follow-up 2 | H+3 | Value proposition / Promo | Info promo aktif, keunggulan produk relevan dengan minat sebelumnya |
| Follow-up 3 | H+7 | Edukasi / Simulasi KPR | Kirim simulasi cicilan berdasarkan budget yang pernah disebutkan |
| Follow-up 4 (opsional) | H+14 | Urgency / Undangan Site Visit | Info ketersediaan unit terbatas, ajak visit langsung |
| Follow-up terakhir | H+21 | Soft-close | "Kalau saat ini belum waktunya, kami akan info promo terbaru nanti ya" → status LOST bila tetap tidak respon |

*Interval bersifat konfigurasi (bukan hardcode) melalui tabel/konfigurasi admin agar dapat disesuaikan per project/campaign.*

### Penanganan Permintaan Custom dari Customer

Jika customer menyatakan preferensi waktu follow-up sendiri (misal *"follow up saya minggu depan saja"*), LLM mendeteksi intent ini dan memanggil tool `scheduleFollowUp(lead_id, scheduled_at, strategy="CUSTOM_REQUEST")` menggantikan jadwal default — jadwal default lain untuk leads tsb dibatalkan/ditunda otomatis.

### Business Rules / Anti-Spam

- BR-J1: Maksimum 1 follow-up otomatis per hari per lead.
- BR-J2: Jika customer membalas kapan pun, seluruh jadwal follow-up pending untuk siklus tersebut dibatalkan dan direset mengikuti percakapan baru.
- BR-J3: Jika customer eksplisit menyatakan `NOT_INTERESTED` atau meminta berhenti dihubungi, seluruh follow-up dihentikan dan status → LOST (dengan sub-alasan "requested_stop").
- BR-J4: Follow-up tidak dikirim di luar jam operasional yang dikonfigurasi (default 08:00–20:00 waktu lokal) — dijadwalkan ulang ke jam operasional berikutnya.
- BR-J5: Setelah follow-up terakhir tanpa respon, lead otomatis berubah status ke `LOST` (dapat direaktivasi manual oleh admin/sales).

### Scheduling System & Cron Job Concept

- Setiap follow-up terjadwal disimpan di tabel `followups` dengan `scheduled_at` dan `status` (`PENDING`, `SENT`, `CANCELLED`, `FAILED`).
- Command CLI `php spark followup:process` dijalankan via cron setiap 5 menit, mengambil seluruh `followups` dengan `status=PENDING` dan `scheduled_at <= now()`, lalu:
  1. Cek business rules (jam operasional, status lead belum LOST/AKAD, conversation_mode masih AI_ACTIVE).
  2. Generate pesan follow-up (LLM dengan konteks strategi tahap tsb).
  3. Kirim via WhatsApp Gateway Service.
  4. Update status `SENT`, catat di `followup_logs`.
  5. Bila gagal kirim → retry sesuai kebijakan retry (Bab 9), maksimal 2x, lalu `status=FAILED` dan notifikasi admin.

### Database Design

Lihat tabel `followups`, `followup_logs` pada [Bab 18](#18-database-design).

---

## 15. Objection Handling Engine

### Kategori Objection

| Kategori | Contoh Concern |
|---|---|
| PRICE | "Harganya kemahalan" |
| LOCATION | "Lokasinya kurang strategis" |
| DISTANCE | "Terlalu jauh dari kantor/kota" |
| DOWN_PAYMENT | "DP-nya berat" |
| INSTALLMENT | "Cicilan per bulan terlalu tinggi" |
| KPR_APPROVAL | "Takut KPR tidak disetujui" |
| LEGALITY | "Ragu soal legalitas/sertifikat" |
| FACILITY | "Fasilitasnya kurang lengkap" |
| DEVELOPER_TRUST | "Belum yakin dengan developernya" |
| FAMILY_DECISION | "Harus diskusi dulu dengan pasangan/keluarga" |
| COMPETITOR_COMPARISON | "Masih bandingkan dengan project lain" |
| NOT_READY | "Belum siap beli sekarang" |

### Struktur Penanganan per Objection

Setiap kategori objection dikonfigurasi dengan struktur berikut (disimpan di tabel `objections` sebagai basis pengetahuan, dapat dikonsumsi LLM sebagai referensi):

| Komponen | Deskripsi |
|---|---|
| **Detection** | Pola/intent yang memicu kategori ini (`OBJECTION_PRICE`, dst. dari Modul D, atau klasifikasi tambahan dari LLM) |
| **Customer Concern** | Ringkasan inti kekhawatiran |
| **Clarification Question** | Pertanyaan lanjutan untuk menggali detail keberatan (bukan langsung membantah) |
| **Sales Strategy** | Pendekatan konsultatif (mis. tawarkan skema pembayaran alternatif, bandingkan value bukan hanya harga) |
| **Recommended Response Style** | Nada bahasa: empatik, tidak defensif, berbasis fakta dari Knowledge Base |
| **Escalation Condition** | Kapan wajib dialihkan ke sales manusia (mis. objection berulang ≥2x tanpa progress, atau menyangkut negosiasi harga langsung) |

### Prinsip Pendekatan Konsultatif

1. **Acknowledge** — akui perasaan/concern customer terlebih dahulu.
2. **Clarify** — gali detail keberatan sebenarnya (jangan asumsi).
3. **Respond with facts** — jawab dengan data dari Knowledge Base, bukan klaim tanpa dasar.
4. **Offer alternative** — tawarkan solusi (skema DP bertahap, unit alternatif, dsb) bila relevan dan tersedia di Knowledge Base.
5. **Escalate if needed** — jika objection kompleks (negosiasi harga khusus, kasus legal spesifik), eskalasi ke sales dengan `handoverToHuman()`.

AI **dilarang** menggunakan teknik tekanan tinggi (high-pressure closing), membantah perasaan customer, atau memberi diskon/harga yang tidak terverifikasi di Knowledge Base.

### Acceptance Criteria

- [ ] AC-Obj1: Setiap objection terdeteksi tercatat di `lead_profiles` (Objection Profile) dan riwayatnya di `lead_profile_history`.
- [ ] AC-Obj2: Objection berulang ≥2x pada kategori sama pada 1 lead memicu rekomendasi eskalasi ke sales.

---

## 16. Knowledge Base

### Kategori

`PROJECT`, `CLUSTER`, `PRODUCT`, `PRODUCT_TYPE`, `PRICE`, `PROMOTION`, `FACILITY`, `LOCATION`, `ACCESS`, `SPECIFICATION`, `PAYMENT`, `KPR`, `LEGALITY`, `FAQ`, `POLICY`.

### Prinsip Utama: No Hallucination

AI **dilarang mengarang informasi**. Aturan retrieval:

1. Setiap klaim faktual dalam response AI (harga, promo, spesifikasi, fasilitas) harus dapat ditelusuri ke entri di Knowledge Base yang relevan (`knowledge_documents` / tabel terstruktur `products`, `promotions`, dll).
2. Jika informasi tidak ditemukan di Knowledge Base, AI **wajib** merespon dengan variasi kalimat seperti: *"Untuk informasi [topik] ini, saya akan konfirmasikan ke tim terkait ya, mohon ditunggu."* dan mencatat sebagai `knowledge_gap` untuk ditindaklanjuti admin/sales.
3. System prompt LLM secara eksplisit menyertakan instruksi: *"Hanya gunakan informasi dari konteks Knowledge Base yang diberikan. Jangan membuat asumsi harga, promo, atau spesifikasi yang tidak tercantum."*

### Retrieval Process

Untuk MVP, retrieval menggunakan pendekatan **structured query + keyword/category matching** (bukan vector search penuh, untuk menyederhanakan infrastruktur awal):

```
1. Sistem mengidentifikasi entitas relevan dari intent + profil (mis. project_id, product_type)
2. Query terstruktur ke tabel products/promotions/faqs berdasarkan entitas tsb
3. (Untuk FAQ/dokumen bebas teks) pencarian keyword/full-text search MySQL (FULLTEXT INDEX)
   pada knowledge_documents sebagai fallback
4. Hasil retrieval disusun sebagai "context snippet" disisipkan ke prompt LLM
5. LLM menyusun response berbasis snippet tsb saja
```

*Catatan future improvement:* migrasi ke vector embedding search (RAG) untuk retrieval semantik yang lebih baik saat volume dokumen bertambah besar (lihat Bab 27).

### Database Structure (Ringkas)

Lihat detail tabel `projects`, `clusters`, `products`, `product_units`, `promotions`, `faqs`, `knowledge_documents` pada [Bab 18](#18-database-design).

### Data Update Mechanism & Versioning

- Admin mengelola Knowledge Base melalui panel admin (CRUD project/produk/promo/FAQ).
- Setiap perubahan pada `knowledge_documents` dan `products` dicatat versi (`version`, `updated_by`, `updated_at`) — histori disimpan di tabel `*_history` terkait agar dapat ditelusuri konten mana yang aktif saat suatu percakapan terjadi (penting untuk audit bila customer komplain informasi berbeda).
- Promo memiliki `valid_from` dan `valid_until` — retrieval otomatis mengabaikan promo yang sudah kedaluwarsa.

### AI Response Rules

- Selalu menyertakan disclaimer implisit bahwa harga/promo dapat berubah sewaktu-waktu, mendorong konfirmasi final ke sales saat mendekati keputusan pembelian.
- Tidak membandingkan secara negatif dengan kompetitor/project lain di luar data internal.

---

## 17. AI Tools / Function Calling

AI menggunakan *tool calling* untuk mengambil aksi nyata di dalam sistem. Berikut daftar tools minimal beserta kontrak masing-masing.

### 17.1 `checkProductAvailability`
- **Purpose:** Mengecek ketersediaan unit produk sesuai kriteria.
- **Input:** `project_id`, `product_type` (opsional), `min_price`, `max_price` (opsional)
- **Output:** daftar `product_units` tersedia (id, nama unit, tipe, harga, status)
- **Permission:** AI (read-only)
- **Validation:** `project_id` wajib valid & aktif
- **Error Handling:** Jika project tidak ditemukan → return error terstruktur, AI merespon meminta klarifikasi project ke customer

### 17.2 `getProductDetail`
- **Purpose:** Mengambil detail spesifikasi produk/unit.
- **Input:** `product_id`
- **Output:** spesifikasi, harga, fasilitas terkait, gambar (opsional URL)
- **Permission:** AI (read-only)
- **Validation:** `product_id` valid
- **Error Handling:** Produk tidak ditemukan → fallback "akan dikonfirmasi tim terkait"

### 17.3 `getActivePromotion`
- **Purpose:** Mengambil promosi aktif untuk project/produk tertentu.
- **Input:** `project_id` (opsional), `product_id` (opsional)
- **Output:** daftar promosi aktif dalam rentang `valid_from`–`valid_until`
- **Permission:** AI (read-only)
- **Validation:** minimal salah satu dari `project_id`/`product_id` diisi, atau kosong = promo umum
- **Error Handling:** Tidak ada promo aktif → return array kosong, AI menyatakan tidak ada promo berjalan saat ini (bukan mengarang)

### 17.4 `calculateKpr`
- **Purpose:** Menghitung simulasi KPR (cicilan bulanan) berdasarkan harga, DP, tenor, suku bunga acuan.
- **Input:** `product_id` atau `price`, `dp_percentage`, `tenor_years`, `interest_rate` (default dari konfigurasi bila tidak diisi)
- **Output:** `dp_amount`, `loan_amount`, `monthly_installment`, disclaimer simulasi
- **Permission:** AI (compute, tidak mengubah data)
- **Validation:** `dp_percentage` ≥ minimum kebijakan (mis. 10%), `tenor_years` dalam rentang valid (1–25 tahun)
- **Error Handling:** Parameter di luar rentang wajar → AI klarifikasi ke customer, tidak memaksakan hitung

### 17.5 `getCustomerProfile`
- **Purpose:** Mengambil profil lengkap lead saat ini untuk konteks reasoning.
- **Input:** `lead_id`
- **Output:** seluruh field profil beserta `source_type` & `confidence`
- **Permission:** AI (read-only, internal context)
- **Validation:** `lead_id` harus sesuai conversation aktif (tidak boleh cross-lead)

### 17.6 `updateCustomerProfile`
- **Purpose:** Menyimpan/memperbarui field profil hasil ekstraksi dari percakapan.
- **Input:** `lead_id`, `fields[]` (field_name, value, source_type, confidence, evidence_message_id)
- **Output:** status sukses, field yang berhasil diupdate
- **Permission:** AI (write, terbatas ke `lead_profiles` milik lead aktif)
- **Validation:** field_name harus termasuk daftar field yang diizinkan (whitelist); value melewati sanitasi dasar
- **Error Handling:** field tidak dikenal → diabaikan & dicatat sebagai warning log (tidak menggagalkan seluruh update)

### 17.7 `updateLeadStatus`
- **Purpose:** Mengubah status pipeline lead (terbatas pada transisi yang diizinkan AI, lihat BR-A2/BR-A3).
- **Input:** `lead_id`, `new_status`, `reason`
- **Output:** status sukses/gagal, status sebelumnya
- **Permission:** AI (write, terbatas — tidak boleh set status BOOKING/KPR/AKAD)
- **Validation:** cek transisi valid sesuai pipeline; status terlarang untuk AI → ditolak dengan error eksplisit
- **Error Handling:** Transisi tidak valid → tool return error, AI tidak mengklaim ke customer bahwa status berubah

### 17.8 `calculateLeadScore`
- **Purpose:** Memicu perhitungan ulang PCS/BIS/Total Score.
- **Input:** `lead_id`
- **Output:** `pcs`, `bis`, `total_score`, `temperature`
- **Permission:** AI (write ke `lead_scores`, `lead_score_history`)
- **Validation:** lead harus ada dan aktif
- **Error Handling:** N/A (operasi deterministik internal), kegagalan dicatat & tidak menghentikan response ke customer

### 17.9 `scheduleFollowUp`
- **Purpose:** Menjadwalkan follow-up (default atau custom sesuai permintaan customer).
- **Input:** `lead_id`, `scheduled_at`, `strategy`, `reason` (`AUTO`/`CUSTOM_REQUEST`)
- **Output:** `followup_id`, `scheduled_at` terkonfirmasi
- **Permission:** AI (write ke `followups`)
- **Validation:** `scheduled_at` harus di masa depan dan dalam jam operasional yang dikonfigurasi; batalkan follow-up pending lain untuk siklus yang sama
- **Error Handling:** waktu di luar jam operasional → sistem otomatis menyesuaikan ke jam operasional terdekat, dikonfirmasi ke AI

### 17.10 `createAppointment`
- **Purpose:** Membuat jadwal site visit.
- **Input:** `lead_id`, `preferred_date`, `preferred_time`, `project_id`
- **Output:** `appointment_id`, status (`PENDING_CONFIRMATION`/`CONFIRMED`), sales yang di-assign (jika langsung tersedia)
- **Permission:** AI (write ke `appointments`)
- **Validation:** tanggal/waktu tidak boleh di masa lalu; cek ketersediaan slot dasar (kapasitas per hari, dikonfigurasi admin)
- **Error Handling:** slot penuh → AI menawarkan alternatif tanggal/waktu ke customer

### 17.11 `assignSales`
- **Purpose:** Menentukan sales yang bertanggung jawab atas lead (rule-based: round robin per project, atau berdasar wilayah).
- **Input:** `lead_id`, `project_id`
- **Output:** `sales_id` ter-assign
- **Permission:** SYSTEM/AI (write ke `sales_assignments`) — dapat dioverride manual oleh admin/supervisor
- **Validation:** sales harus berstatus aktif dan memiliki kapasitas (belum melebihi batas leads aktif, dikonfigurasi)
- **Error Handling:** tidak ada sales tersedia → assignment ke antrian "unassigned", notifikasi ke supervisor

### 17.12 `handoverToHuman`
- **Purpose:** Memicu proses handover formal (mengubah `conversation_mode`, generate AI Summary, kirim notifikasi ke sales).
- **Input:** `lead_id`, `trigger_reason`
- **Output:** status handover, `summary_id`
- **Permission:** AI (write ke `conversations`, `handover_logs`)
- **Validation:** lead harus punya sales ter-assign (memicu `assignSales` dahulu bila belum ada)
- **Error Handling:** gagal generate summary → tetap lakukan handover dengan data minimal (profil + histori 10 pesan terakhir), dicatat sebagai partial handover

### 17.13 `getConversationSummary`
- **Purpose:** Menghasilkan ringkasan percakapan (dipakai internal oleh `handoverToHuman` dan dapat dipanggil manual oleh sales/admin kapan saja).
- **Input:** `lead_id`
- **Output:** ringkasan terstruktur (lihat format di Bab 17 Human Handover)
- **Permission:** AI (read + compute, tidak mengubah data lead)
- **Validation:** minimal harus ada 1 pesan dalam conversation
- **Error Handling:** conversation kosong → return ringkasan "belum ada interaksi signifikan"

### Kapan AI Menggunakan Tool

System prompt LLM secara eksplisit mendefinisikan kapan tiap tool relevan (dipetakan dari **Allowed Actions** per state pada Bab 11, dan dari intent pada Bab Modul D). LLM diberi daftar tools yang **tersedia sesuai state saat ini saja** (bukan seluruh tools sekaligus) untuk mengurangi risiko pemanggilan tool yang tidak sesuai konteks dan mengurangi token usage.

---

## MODUL — NEXT BEST ACTION ENGINE

### Decision Tree (Ringkas)

```
Customer baru (state=NEW_LEAD)
   → Action: QUALIFY (sapa & gali tujuan beli)

Customer belum punya info budget (state=DISCOVERY, financial profile kosong)
   → Action: EXPLORE_FINANCIAL_CAPABILITY

Customer menunjukkan minat pada produk tertentu (intent=PRODUCT_INQUIRY)
   → Action: EXPLAIN_PRODUCT (checkProductAvailability + getProductDetail)

Customer bertanya cicilan (intent=INSTALLMENT_INQUIRY / KPR_INQUIRY)
   → Action: CALCULATE_KPR (calculateKpr)

Customer menyampaikan keberatan (intent=OBJECTION_*)
   → Action: HANDLE_OBJECTION (Modul Objection Handling)

Buying Intent Score tinggi (≥ threshold HOT) & belum ada appointment
   → Action: INVITE_SITE_VISIT (state → VISIT_INVITATION)

Customer setuju jadwal site visit
   → Action: CREATE_APPOINTMENT (createAppointment)

Customer eksplisit minta bicara manusia (intent=HUMAN_REQUEST)
   → Action: HUMAN_HANDOVER (langsung, prioritas tertinggi)

Customer tidak merespon dalam periode tertentu
   → Action: SCHEDULE_FOLLOWUP (Modul Follow-up Engine)
```

### Prinsip Rule Engine

Next Best Action Engine adalah **layer rule-based** yang berjalan **sebelum** LLM reasoning — hasilnya berupa daftar "kandidat aksi yang direkomendasikan" beserta prioritas, yang kemudian disisipkan ke prompt LLM sebagai *guidance* (bukan perintah mutlak — LLM tetap dapat menyesuaikan dengan nuansa percakapan aktual, namun tools yang dapat dipanggil dibatasi sesuai Allowed Actions state). Prioritas tertinggi selalu: `HUMAN_REQUEST` > kondisi darurat/komplain > objection aktif > qualifikasi/discovery > engagement pasif (follow-up).

---

## 18. Site Visit Appointment

### Functional Requirements

- FR-M1: AI dapat mengundang customer untuk site visit ketika buying intent tinggi terdeteksi (state `VISIT_INVITATION`).
- FR-M2: Customer memilih tanggal & waktu preferensi via percakapan natural (AI mem-parsing ke format terstruktur).
- FR-M3: Sistem memvalidasi ketersediaan slot (kapasitas harian per project, dikonfigurasi admin).
- FR-M4: Appointment yang berhasil dibuat otomatis memicu `assignSales`.
- FR-M5: Sistem mengirim konfirmasi ke customer dan reminder H-1 (via cron/follow-up mechanism serupa).

### Appointment Flow

```
AI mendeteksi buying intent tinggi (BIS ≥ threshold)
     │
     ▼
AI mengundang site visit (state → VISIT_INVITATION)
     │
     ▼
Customer memilih tanggal & waktu
     │
     ▼
Sistem validasi slot (createAppointment tool)
     │
     ├─ Slot tersedia ──▶ Appointment status: CONFIRMED
     │                         │
     │                         ▼
     │                    assignSales()
     │                         │
     │                         ▼
     │                    Kirim konfirmasi ke customer
     │                         │
     │                         ▼
     │                    (H-1) Kirim reminder otomatis
     │                         │
     │                         ▼
     │                    handoverToHuman() (state → HUMAN_HANDOVER)
     │
     └─ Slot penuh ──▶ AI tawarkan alternatif tanggal/waktu
```

### Database Structure

Lihat tabel `appointments` pada [Bab 18](#18-database-design) (di bawah — penomoran bab database mengikuti struktur output final, lihat Bab 20).

### Business Rules

- BR-M1: Kapasitas maksimum appointment per hari per project dikonfigurasi admin (default: 10).
- BR-M2: Appointment H-1 tanpa konfirmasi ulang dari customer tetap berjalan (reminder bersifat informatif, bukan syarat).
- BR-M3: Pembatalan oleh customer melalui chat (AI mendeteksi intent pembatalan) → status `CANCELLED`, notifikasi ke sales ter-assign.

### Sales Assignment Rules

- Default: round-robin di antara sales aktif yang menangani project terkait.
- Override: admin/supervisor dapat menetapkan aturan wilayah/spesialisasi produk melalui panel admin.
- Jika sales yang di-assign tidak merespon appointment dalam SLA tertentu (dikonfigurasi, default 2 jam kerja), sistem mengeskalasi notifikasi ke supervisor.

---

## 19. Human Handover

### Trigger Handover

- Customer eksplisit meminta bicara dengan sales (`HUMAN_REQUEST`)
- Sentimen negatif/marah terdeteksi berturut-turut
- Customer siap site visit (state `VISIT_SCHEDULED`)
- Customer siap booking (menyatakan intent booking eksplisit)
- Negosiasi kompleks (permintaan diskon di luar kebijakan Knowledge Base)
- AI tidak yakin (confidence intent rendah berulang, atau LLM secara eksplisit menyatakan tidak dapat membantu)
- Knowledge Base tidak memiliki jawaban (`knowledge_gap` berulang pada topik krusial)
- Lead tergolong high value (skor VERY HOT atau budget di atas threshold tertentu)

### AI Summary — Format

Ringkasan yang dihasilkan `getConversationSummary()` / `handoverToHuman()` mencakup:

```
Nama: [dari profile]
Status Keluarga: [status pernikahan, jumlah anak — bila tersedia]
Pekerjaan: [pekerjaan, perusahaan]
Lokasi Kerja: [lokasi kerja]
Budget: [budget rumah, kemampuan cicilan]
Metode Pembayaran: [cash/KPR]
Produk Diminati: [project/unit yang dibahas]
Objection Utama: [kategori objection dominan + status penanganan]
Buying Intent: [ringkasan timeline & urgency]
Ringkasan Percakapan: [3-5 kalimat summary naratif, digenerate LLM]
Rekomendasi Aksi untuk Sales: [saran next step, mis. "Fokus tawarkan skema DP bertahap"]
```

### Handover Workflow

```
1. Trigger terdeteksi (rule-based / LLM-flagged)
2. Sistem memastikan sales sudah ter-assign (assignSales jika belum)
3. Sistem generate AI Summary (LLM call khusus summarization)
4. conversation_mode: AI_ACTIVE → WAITING_HUMAN
5. Notifikasi terkirim ke sales (WhatsApp internal/Email/in-app dashboard)
6. Sales membuka dashboard, klik "Ambil Alih" → conversation_mode → HUMAN_ACTIVE
7. AI Pause: AI tidak lagi memproses pesan masuk pada conversation ini
8. (Opsional) Sales klik "Kembalikan ke AI" → conversation_mode → AI_ACTIVE, AI Resume dengan konteks penuh (histori tetap utuh)
```

### Conversation Lock & AI Pause/Resume Mechanism

- Selama `WAITING_HUMAN`/`HUMAN_ACTIVE`, webhook tetap menyimpan pesan masuk customer ke `messages`, namun **AI Sales Agent Engine tidak dipanggil** untuk generate response (dicegat di Message Processor berdasarkan `conversation_mode`).
- Saat sales mengembalikan ke AI, AI menerima kembali seluruh histori percakapan (termasuk yang terjadi selama HUMAN_ACTIVE) sebagai konteks agar tidak kehilangan kontinuitas.

### Acceptance Criteria

- [ ] AC-N1: 100% handover menghasilkan AI Summary tersimpan sebelum notifikasi ke sales dikirim.
- [ ] AC-N2: AI tidak mengirim pesan otomatis apa pun setelah `conversation_mode` berubah dari `AI_ACTIVE`.
- [ ] AC-N3: Notifikasi ke sales terkirim dalam < 10 detik dari trigger handover.

---

## 20. Database Design

### Ringkasan Tabel Utama

| Tabel | Fungsi | Relasi Kunci |
|---|---|---|
| `users` | Akun pengguna sistem (admin, supervisor) | 1—N ke `sales` (opsional bila sales adalah subset user) |
| `sales` | Data sales offline | 1—N ke `leads` (assigned_sales_id), `appointments` |
| `leads` | Data inti leads/customer | N—1 ke `lead_sources`; 1—1 ke `lead_profiles`; 1—N ke `conversations`, `lead_scores` |
| `lead_profiles` | Profil terkini per lead (1 baris per lead, kolom per field atau EAV — lihat catatan) | 1—1 ke `leads` |
| `lead_profile_history` | Riwayat perubahan tiap field profil | N—1 ke `leads`, `messages` (evidence) |
| `lead_status_history` | Riwayat perubahan status pipeline | N—1 ke `leads` |
| `conversations` | Sesi percakapan per lead & mode aktif | 1—1/1—N ke `leads`; 1—N ke `messages` |
| `messages` | Seluruh pesan masuk/keluar | N—1 ke `conversations` |
| `ai_agent_states` | State machine journey per lead | 1—1 ke `leads` (current) + histori |
| `ai_memories` | Ringkasan/memori jangka panjang AI per lead (opsional, untuk konteks LLM ringkas) | N—1 ke `leads` |
| `lead_scores` | Skor terkini (PCS, BIS, total, temperature) | 1—1 ke `leads` |
| `lead_score_history` | Riwayat perubahan skor | N—1 ke `leads` |
| `followups` | Jadwal follow-up | N—1 ke `leads` |
| `followup_logs` | Log eksekusi follow-up | N—1 ke `followups` |
| `appointments` | Jadwal site visit | N—1 ke `leads`, `projects`, `sales` |
| `projects` | Data project properti | 1—N ke `clusters`, `products` |
| `clusters` | Cluster/tipe dalam project | N—1 ke `projects`; 1—N ke `products` |
| `products` | Produk/tipe rumah | N—1 ke `clusters`/`projects`; 1—N ke `product_units` |
| `product_units` | Unit spesifik yang dapat dijual | N—1 ke `products` |
| `promotions` | Data promosi | N—1 ke `projects`/`products` (nullable = promo umum) |
| `faqs` | Pertanyaan umum & jawaban | N—1 ke `projects` (nullable = FAQ umum) |
| `knowledge_documents` | Dokumen bebas teks (kebijakan, legal, dsb) dengan FULLTEXT index | N—1 ke `projects` (nullable) |
| `objections` | Basis pengetahuan strategi objection handling per kategori | (referensi statis, tidak terikat lead) |
| `sales_assignments` | Riwayat assignment sales ke lead | N—1 ke `leads`, `sales` |
| `handover_logs` | Log & AI Summary tiap handover | N—1 ke `leads`, `conversations` |
| `ai_tool_logs` | Log setiap tool call AI (input/output) | N—1 ke `leads`/`conversations` |
| `ai_conversation_logs` | Log keputusan AI per pesan (intent, sentiment, urgency, action) | N—1 ke `messages` |

### Field Penting per Tabel Kunci

**`leads`**
`id (PK)`, `phone_number (unique, indexed)`, `name`, `source_id (FK)`, `campaign_name`, `project_id (FK, nullable)`, `assigned_sales_id (FK, nullable)`, `status (enum pipeline)`, `temperature (enum)`, `created_at`, `updated_at`

**`lead_profiles`**
`id (PK)`, `lead_id (FK, unique)`, kolom per field kunci (mis. `occupation`, `budget_min`, `budget_max`, `payment_method`, `purchase_timeline`, dst.) **atau** desain EAV `lead_profile_fields (lead_id, field_name, value, source_type, confidence, evidence_message_id)` — **rekomendasi MVP: gunakan EAV** untuk fleksibilitas menambah field tanpa migrasi berulang.

**`conversations`**
`id (PK)`, `lead_id (FK)`, `mode (enum: AI_ACTIVE, WAITING_HUMAN, HUMAN_ACTIVE, CLOSED)`, `assigned_sales_id (FK, nullable)`, `last_message_at`, `created_at`

**`messages`**
`id (PK)`, `conversation_id (FK)`, `lead_id (FK, denormalized untuk query cepat)`, `sender_type (enum: CUSTOMER, AI, SALES, SYSTEM)`, `content (text)`, `message_type (text/image/document)`, `wa_message_id (unique, untuk deduplikasi)`, `status (sent/delivered/read/failed)`, `created_at`

**`ai_agent_states`**
`id (PK)`, `lead_id (FK)`, `current_state (enum sesuai Bab 11)`, `previous_state`, `entered_at`, `metadata (json)`

**`lead_scores`**
`id (PK)`, `lead_id (FK, unique)`, `pcs`, `bis`, `total_score`, `temperature`, `calculated_at`

**`followups`**
`id (PK)`, `lead_id (FK)`, `scheduled_at`, `strategy (enum)`, `status (PENDING/SENT/CANCELLED/FAILED)`, `reason (AUTO/CUSTOM_REQUEST)`, `created_at`

**`appointments`**
`id (PK)`, `lead_id (FK)`, `project_id (FK)`, `sales_id (FK, nullable)`, `scheduled_date`, `scheduled_time`, `status (PENDING_CONFIRMATION/CONFIRMED/CANCELLED/COMPLETED)`, `created_at`

**`handover_logs`**
`id (PK)`, `lead_id (FK)`, `conversation_id (FK)`, `trigger_reason`, `ai_summary (json/text)`, `handed_over_at`, `taken_over_by (FK sales, nullable)`, `taken_over_at`

### ERD Konseptual (Ringkas)

```
users ──┐
        ├──< sales >──< sales_assignments >── leads
                              │                   │
                              │                   ├──1:1── lead_profiles (EAV: lead_profile_fields)
                              │                   ├──1:N── lead_profile_history
                              │                   ├──1:N── lead_status_history
                              │                   ├──1:1── ai_agent_states
                              │                   ├──1:1── lead_scores ──1:N── lead_score_history
                              │                   ├──1:N── followups ──1:N── followup_logs
                              │                   ├──1:N── appointments ──N:1── projects
                              │                   ├──1:N── conversations ──1:N── messages
                              │                   │                          └──1:N── ai_conversation_logs
                              │                   ├──1:N── handover_logs
                              │                   └──1:N── ai_tool_logs
                              │
projects ──1:N── clusters ──1:N── products ──1:N── product_units
    │                                  │
    ├──1:N── promotions                └──1:N── (referenced by lead_profiles/messages context)
    ├──1:N── faqs
    └──1:N── knowledge_documents

objections (basis pengetahuan statis, direferensikan oleh AI, tidak FK langsung ke leads)
```

---

## 21. API Requirements

Seluruh endpoint berada di bawah prefix `/api/v1` (kecuali webhook yang path-nya mengikuti kontrak bot WA existing). Autentikasi menggunakan Bearer Token (lihat Bab Security).

### Lead API

| Method | Endpoint | Deskripsi |
|---|---|---|
| GET | `/leads` | List leads dengan filter (status, temperature, source, project, assigned_sales) & pagination |
| POST | `/leads` | Membuat lead baru (manual/integrasi eksternal) |
| GET | `/leads/{id}` | Detail lead lengkap (profile, score, state, appointment terkait) |
| PUT | `/leads/{id}` | Update data lead (terbatas field yang diizinkan, mis. assigned_sales_id oleh admin) |

**Contoh Request `POST /leads`:**
```json
{
  "name": "Budi Santoso",
  "phone_number": "628123456789",
  "source": "META_ADS",
  "campaign_name": "Promo Agustus - Cluster A",
  "project_id": 3
}
```
**Contoh Response:**
```json
{ "status": "success", "data": { "lead_id": 1024, "status": "NEW" } }
```

### Conversation API

| Method | Endpoint | Deskripsi |
|---|---|---|
| GET | `/conversations` | List percakapan aktif (filter by mode, sales) |
| GET | `/conversations/{id}/messages` | Riwayat pesan dalam satu percakapan (paginated) |

### AI API (Internal — dipanggil oleh Message Processor, dapat juga digunakan untuk testing/tools admin)

| Method | Endpoint | Deskripsi |
|---|---|---|
| POST | `/ai/process-message` | Memproses satu pesan masuk melalui AI Sales Agent Engine, mengembalikan response & aksi yang diambil |
| POST | `/ai/analyze-lead` | Menjalankan analisis ulang (profiling + scoring) tanpa mengirim pesan baru (mis. untuk re-sync manual) |
| POST | `/ai/handover` | Memicu handover manual (dipanggil dari dashboard admin/sales) |

### Follow Up API

| Method | Endpoint | Deskripsi |
|---|---|---|
| POST | `/followups` | Membuat jadwal follow-up manual |
| GET | `/followups` | List jadwal follow-up (filter by lead, status) |

### Appointment API

| Method | Endpoint | Deskripsi |
|---|---|---|
| POST | `/appointments` | Membuat appointment (dari dashboard, atau internal dari AI tool) |
| PUT | `/appointments/{id}` | Update status appointment (confirm/cancel/reschedule) |

### Webhook API

| Method | Endpoint | Deskripsi |
|---|---|---|
| POST | `/webhook/whatsapp` | Menerima payload incoming message dari WhatsApp Bot existing. Wajib idempotent (cek `wa_message_id`), validasi token/signature (Bab 21). |

**Contoh payload masuk (asumsi kontrak — perlu konfirmasi format aktual bot existing):**
```json
{
  "message_id": "wamid.XXXX",
  "from": "628123456789",
  "sender_name": "Budi Santoso",
  "message_type": "text",
  "text": "Halo, saya mau tanya soal cluster A",
  "timestamp": "2026-08-31T10:15:00+07:00"
}
```

---

## 22. CodeIgniter 4 Architecture

### Struktur Folder

```
app/
├── Controllers/
│   ├── Api/
│   │   ├── LeadController.php
│   │   ├── ConversationController.php
│   │   ├── FollowUpController.php
│   │   ├── AppointmentController.php
│   │   └── AiController.php
│   ├── Webhook/
│   │   └── WhatsAppWebhookController.php
│   └── Admin/
│       ├── DashboardController.php
│       ├── KnowledgeBaseController.php
│       └── LeadManagementController.php
│
├── Models/
│   ├── LeadModel.php
│   ├── LeadProfileFieldModel.php
│   ├── ConversationModel.php
│   ├── MessageModel.php
│   ├── AiAgentStateModel.php
│   ├── LeadScoreModel.php
│   ├── FollowUpModel.php
│   ├── AppointmentModel.php
│   ├── ProjectModel.php
│   ├── ProductModel.php
│   └── ... (1 model per tabel)
│
├── Services/
│   ├── AI/
│   │   ├── SalesAgentOrchestrator.php     // Decision Engine utama
│   │   ├── LlmClient.php                  // Wrapper API LLM
│   │   ├── IntentDetectionService.php
│   │   ├── ProfilingService.php
│   │   ├── LeadScoringService.php
│   │   ├── ObjectionHandlingService.php
│   │   ├── NextBestActionService.php
│   │   ├── KnowledgeBaseService.php
│   │   └── ConversationSummaryService.php
│   ├── Sales/
│   │   ├── LeadAssignmentService.php
│   │   ├── HandoverService.php
│   │   └── AppointmentService.php
│   └── WhatsApp/
│       ├── WhatsAppGatewayService.php     // Wrapper kirim pesan ke bot existing
│       └── WebhookValidatorService.php
│
├── Libraries/
│   └── AiTools/
│       ├── AiToolRegistry.php             // Daftar & dispatcher tools
│       ├── CheckProductAvailabilityTool.php
│       ├── GetProductDetailTool.php
│       ├── GetActivePromotionTool.php
│       ├── CalculateKprTool.php
│       ├── GetCustomerProfileTool.php
│       ├── UpdateCustomerProfileTool.php
│       ├── UpdateLeadStatusTool.php
│       ├── CalculateLeadScoreTool.php
│       ├── ScheduleFollowUpTool.php
│       ├── CreateAppointmentTool.php
│       ├── AssignSalesTool.php
│       ├── HandoverToHumanTool.php
│       └── GetConversationSummaryTool.php
│
├── Commands/
│   ├── ProcessScheduledFollowups.php      // spark followup:process
│   ├── RecalculateLeadScores.php          // spark leadscore:recalculate
│   ├── DetectInactiveLeads.php            // spark leads:detect-inactive
│   ├── SendAppointmentReminders.php       // spark appointment:remind
│   ├── CheckAiConversationTimeout.php     // spark ai:check-timeout
│   └── GenerateDailyReport.php            // spark report:daily
│
├── Filters/
│   ├── ApiAuthFilter.php
│   ├── WebhookSignatureFilter.php
│   └── RateLimitFilter.php
│
├── Events/
│   ├── LeadStatusChanged.php
│   ├── ConversationHandedOver.php
│   └── AppointmentCreated.php
│
└── Listeners/ (di app/Config/Events.php terdaftar closure/handler)
    ├── NotifySalesOnHandover.php
    └── LogLeadStatusChange.php
```

### Prinsip Desain

- **Separation of Concerns:** Controller hanya menangani HTTP concern (validasi request, format response); logika bisnis berada di Service layer.
- **Service Layer:** Setiap domain (AI, Sales, WhatsApp) memiliki service tersendiri dengan tanggung jawab jelas dan dapat diuji unit secara independen.
- **Tool Registry Pattern:** `AiToolRegistry` mendaftarkan seluruh tools dengan skema input/output (JSON Schema) yang dikirim ke LLM API sebagai definisi tools — memudahkan penambahan tools baru tanpa mengubah orchestrator.
- **Repository Pattern:** Digunakan secara pragmatis hanya pada Model yang query-nya kompleks (mis. `LeadModel` dengan banyak filter dashboard) — tidak dipaksakan di seluruh model untuk menghindari over-engineering pada MVP.
- **SOLID:** Setiap Service/Tool memiliki satu tanggung jawab; dependency Service disuntik melalui constructor (CI4 Services container / manual DI sederhana).

---

## 23. Security

| Aspek | Requirement |
|---|---|
| **API Authentication** | Seluruh endpoint `/api/v1/*` (kecuali webhook) menggunakan Bearer Token (personal access token per integrasi/admin), divalidasi via `ApiAuthFilter`. |
| **Webhook Validation** | Endpoint `/webhook/whatsapp` memvalidasi shared-secret/signature header dari bot WA existing (`WebhookSignatureFilter`) — request tanpa signature valid ditolak (403). |
| **Data Access Control** | Role-based: `Admin` (akses penuh), `Supervisor` (akses tim & laporan), `Sales` (akses leads assigned saja). |
| **Role Based Access** | Diimplementasikan via CI4 Filters + kolom `role` pada `users`, dicek di setiap Controller Admin. |
| **AI Prompt Security** | System prompt tidak boleh menyertakan data sensitif lintas-lead; input customer di-sanitasi sebelum disisipkan ke prompt untuk mencegah prompt injection (mis. instruksi tersembunyi dari customer yang mencoba mengubah perilaku AI/mengakses data lead lain) — validasi output tool call terhadap `lead_id` milik conversation aktif. |
| **PII Protection** | Data pribadi (nomor HP, penghasilan) tidak ditampilkan penuh di log/dashboard non-esensial; akses penuh dibatasi role tertentu. |
| **Audit Log** | Seluruh aksi tulis (status change, profile update, handover) tercatat dengan actor & timestamp — tidak dapat dihapus dari UI (append-only). |
| **Message Encryption Recommendation** | Data pesan disimpan terenkripsi at-rest (kolom `content` di-enkripsi menggunakan CI4 Encryption Service) — direkomendasikan untuk fase produksi, opsional untuk MVP awal bila timeline ketat. |
| **Rate Limiting** | `RateLimitFilter` pada endpoint publik (webhook) dan API eksternal untuk mencegah abuse/flood. |

---

## 24. Error Handling

| Skenario | Fallback Strategy |
|---|---|
| **AI API error** (LLM down/timeout) | Retry 2x exponential backoff → jika gagal, kirim fallback message standar ke customer, catat error, notifikasi admin via log/alert. |
| **WhatsApp API error** (gagal kirim pesan) | Retry 2x → jika gagal, tandai `messages.status = failed`, masuk antrian retry manual/cron ulang berikutnya. |
| **Database error** | Transaksi di-rollback, response API mengembalikan error terstruktur (500 dengan kode internal), tidak mengekspos detail teknis ke customer. |
| **Tool execution error** | Tool mengembalikan error terstruktur ke LLM (bukan exception mentah) agar LLM dapat merespon customer secara wajar (mis. "mohon tunggu, akan dikonfirmasi tim"), dicatat di `ai_tool_logs`. |
| **Duplicate message** | Deduplikasi berbasis `wa_message_id` unik di tabel `messages` — pesan duplikat diabaikan (idempotent), response 200 tetap dikembalikan ke webhook caller. |
| **Webhook retry** | Karena idempotent by `wa_message_id`, retry dari sisi bot WA aman diproses ulang tanpa efek ganda. |
| **Customer message terlalu panjang** | Dipotong/diringkas sebelum masuk prompt (batas karakter dikonfigurasi), pesan asli tetap tersimpan utuh di `messages`. |
| **AI confidence rendah** | `recommended_action = CLARIFY` — AI bertanya klarifikasi alih-alih mengasumsikan; jika berulang → eskalasi ke handover. |
| **Knowledge tidak ditemukan** | AI merespon bahwa informasi akan dikonfirmasi tim terkait; dicatat sebagai `knowledge_gap` untuk review admin. |
| **AI memberikan response tidak sesuai** | Response Validator (guardrail post-processing) memfilter/memblokir response yang melanggar aturan dasar (mis. menyebut harga di luar Knowledge Base terdeteksi via cross-check angka); jika terdeteksi, sistem mengirim fallback message dan mencatat insiden untuk review manual. |
| **Customer meminta manusia** | Langsung trigger Human Handover (prioritas tertinggi, lihat Bab 19). |

---

## 25. Dashboard

### Dashboard Admin

| Widget | Deskripsi |
|---|---|
| Total Leads | Jumlah keseluruhan leads (dengan filter periode) |
| New Leads | Leads masuk hari ini/periode tertentu |
| Active Conversation | Jumlah percakapan aktif (AI_ACTIVE + HUMAN_ACTIVE) |
| AI Active Conversation | Jumlah percakapan yang sedang ditangani AI |
| Human Active Conversation | Jumlah percakapan yang sedang ditangani sales |
| Cold / Warm / Hot Leads | Distribusi leads per temperature |
| Site Visit | Jumlah appointment terjadwal/selesai |
| Booking / KPR / Akad | Jumlah leads pada tiap tahap akhir pipeline |

### AI Performance

| Metrik | Definisi |
|---|---|
| Total Conversation | Jumlah percakapan yang diproses AI |
| Response Rate | % pesan customer yang direspon AI dalam SLA |
| Qualification Rate | % leads baru yang mencapai status QUALIFIED |
| Site Visit Conversion | % HOT leads yang berhasil dijadwalkan site visit |
| Handover Rate | % percakapan yang berakhir dengan handover ke sales |
| AI Resolution Rate | % percakapan yang selesai tanpa perlu handover |

### Sales Performance

| Metrik | Definisi |
|---|---|
| Assigned Leads | Jumlah leads yang di-assign ke sales tsb |
| Follow-up Speed | Rata-rata waktu sales merespon setelah handover |
| Site Visit | Jumlah site visit yang ditangani |
| Booking | Jumlah booking dihasilkan |
| Closing | Jumlah akad selesai |

### Funnel Visualization

```
LEAD → CONTACTED → RESPONDED → QUALIFIED → HOT → SITE VISIT → BOOKING → KPR → AKAD
```
Ditampilkan sebagai funnel chart dengan jumlah & persentase drop-off antar tahap, filter berdasarkan periode, source, dan project.

---

## 26. Development Roadmap (MVP)

### PHASE 1 — FOUNDATION

| | |
|---|---|
| **Objective** | Membangun fondasi data leads, percakapan, dan integrasi WhatsApp dasar |
| **Fitur** | Lead Management (CRUD, import Excel/CSV, API), Conversation Management (simpan pesan, mode dasar), Customer Profile (struktur tabel, belum otomatis dari AI), Integrasi Webhook WhatsApp (terima & kirim pesan dasar tanpa AI) |
| **Dependency** | Kontrak API bot WA existing harus dikonfirmasi terlebih dahulu |
| **Priority** | Wajib (blocking seluruh fase berikutnya) |
| **Acceptance Criteria** | Pesan masuk dari WA tersimpan; admin dapat membalas manual via dashboard dan terkirim ke customer; import Excel berhasil dengan laporan sukses/gagal |

### PHASE 2 — AI CORE

| | |
|---|---|
| **Objective** | Mengaktifkan AI sebagai first responder dengan pemahaman dasar |
| **Fitur** | Intent Detection, Customer Profiling otomatis, AI Response Generation (LLM basic, tanpa seluruh tools), Knowledge Base (struktur data + retrieval dasar) |
| **Dependency** | Phase 1 selesai; API key LLM tersedia |
| **Priority** | Wajib |
| **Acceptance Criteria** | AI merespon pesan customer otomatis dengan informasi akurat dari Knowledge Base; profil ter-update otomatis dari percakapan |

### PHASE 3 — SALES INTELLIGENCE

| | |
|---|---|
| **Objective** | Menambahkan kecerdasan penilaian leads dan penanganan percakapan lanjutan |
| **Fitur** | Lead Scoring Engine, AI State Machine (Bab 11), Next Best Action Engine, Objection Handling Engine |
| **Dependency** | Phase 2 selesai (butuh data profiling & intent sebagai input) |
| **Priority** | Wajib |
| **Acceptance Criteria** | Setiap lead memiliki skor & temperature yang ter-update otomatis; AI menangani minimal 5 kategori objection dasar sesuai desain Bab 15 |

### PHASE 4 — AUTOMATION

| | |
|---|---|
| **Objective** | Mengotomasi follow-up agar tidak ada leads yang terlewat |
| **Fitur** | Follow-up Engine, Scheduler (tabel `followups`), Cron Job Commands (`followup:process`, dll) |
| **Dependency** | Phase 3 selesai (strategi follow-up butuh state & score) |
| **Priority** | Wajib |
| **Acceptance Criteria** | Follow-up terkirim sesuai jadwal H+1/H+3/H+7 dengan strategi berbeda; anti-spam rules berjalan (BR-J1–J5) |

### PHASE 5 — CONVERSION

| | |
|---|---|
| **Objective** | Mengonversi leads panas menjadi site visit dan handover ke sales |
| **Fitur** | Site Visit Appointment, Sales Assignment, Human Handover (AI Summary) |
| **Dependency** | Phase 4 selesai |
| **Priority** | Wajib |
| **Acceptance Criteria** | AI berhasil membuat appointment tervalidasi; handover selalu disertai AI Summary lengkap (AC-N1) |

### PHASE 6 — ANALYTICS

| | |
|---|---|
| **Objective** | Memberikan visibilitas penuh ke seluruh funnel dan performa |
| **Fitur** | Dashboard Admin, AI Performance, Sales Performance, Funnel Visualization |
| **Dependency** | Phase 1–5 selesai (butuh data lengkap dari seluruh modul) |
| **Priority** | Tinggi (dapat berjalan paralel dengan akhir Phase 5) |
| **Acceptance Criteria** | Seluruh metrik pada Bab 25 dapat ditampilkan akurat dan real-time (< 5 menit delay) |

---

## 27. Acceptance Criteria (Konsolidasi Level Produk)

- [ ] Sistem dapat menerima leads dari minimal 5 sumber berbeda (manual, Excel, CSV, API, WhatsApp langsung).
- [ ] AI merespon pesan pertama customer dalam < 1 menit.
- [ ] Profil customer terkumpul otomatis tanpa form, dengan pembedaan FACT/INFERENCE yang konsisten.
- [ ] Lead score dan temperature ter-update otomatis dan dapat ditelusuri riwayatnya.
- [ ] Follow-up otomatis berjalan sesuai jadwal dengan strategi bervariasi dan mematuhi anti-spam rules.
- [ ] AI tidak pernah memberikan informasi harga/promo di luar Knowledge Base (0 insiden halusinasi pada UAT).
- [ ] Objection handling menggunakan pendekatan konsultatif, tervalidasi via review manual sample percakapan.
- [ ] Site visit dapat dijadwalkan end-to-end dari percakapan WhatsApp.
- [ ] Human handover selalu disertai AI Summary yang akurat dan lengkap.
- [ ] Dashboard menampilkan funnel dan performa AI/sales secara real-time.
- [ ] Seluruh perubahan status/profil/skor tercatat dengan audit trail lengkap.

---

## 28. Risks & Mitigation

| Risiko | Dampak | Mitigasi |
|---|---|---|
| Kontrak API bot WA existing berbeda dari asumsi (A1) | Rework integrasi webhook & gateway service | Konfirmasi dokumentasi API bot WA di awal Phase 1, buat adapter layer (`WhatsAppGatewayService`) agar perubahan kontrak terisolasi. |
| Biaya LLM API membengkak seiring volume percakapan | Cost overrun operasional | Gunakan prompt efisien (batasi histori pesan yang disisipkan, tools terbatas sesuai state), monitoring biaya per periode, cache hasil retrieval Knowledge Base. |
| AI menghasilkan informasi tidak akurat (halusinasi) | Menurunkan trust customer, risiko reputasi | Guardrails ketat (Bab 10, Bab 16), response validator, review sample percakapan berkala, mekanisme `knowledge_gap` untuk continuous improvement. |
| Lead scoring formula belum akurat di awal (belum ada data historis) | Prioritas leads salah, sales fokus ke leads yang salah | Formula awal bersifat baseline (Bab 13), rencanakan kalibrasi ulang setelah 1-2 bulan data terkumpul, sediakan override manual oleh sales/admin. |
| Ketergantungan tunggal pada satu LLM provider | Risiko downtime/perubahan harga provider | Desain `LlmClient` sebagai wrapper abstraksi agar provider dapat diganti tanpa mengubah business logic (Bab 22 — Service Layer). |
| Tanpa queue system, volume tinggi dapat memperlambat cron/webhook processing | Delay respon AI saat traffic tinggi | Monitoring performa dari awal; migrasi ke queue system (Bab 27) direncanakan begitu volume melebihi kapasitas cron-based processing. |
| Sales mengabaikan leads hasil handover (SLA tidak terjaga) | Leads panas menjadi dingin kembali, ROI AI menurun | SLA eskalasi ke supervisor bila appointment/handover tidak direspon dalam waktu tertentu (Bab 18); dashboard follow-up speed sales (Bab 25). |
| Data pribadi customer (PII) bocor/disalahgunakan | Risiko hukum & reputasi | Role-based access control, audit log, rekomendasi enkripsi pesan at-rest (Bab 21). |

---

## 29. Future Development

Fitur/peningkatan berikut **di luar scope MVP**, direkomendasikan untuk roadmap lanjutan:

1. **Vector-based Knowledge Retrieval (RAG penuh)** — migrasi dari structured/keyword search ke embedding-based semantic search untuk akurasi retrieval yang lebih tinggi saat volume dokumen bertambah besar.
2. **Queue System (Redis/RabbitMQ)** — menggantikan cron-interval processing untuk skala tinggi & real-time processing yang lebih baik.
3. **Multi-tenant Architecture** — mendukung banyak perusahaan/developer properti dalam satu instalasi (SaaS model).
4. **Voice Note & Image Understanding** — AI dapat memahami pesan suara (transkripsi) dan gambar (mis. customer kirim foto denah/brosur kompetitor).
5. **Integrasi Channel Lain** — Instagram DM, Facebook Messenger, Telegram sebagai tambahan channel selain WhatsApp.
6. **A/B Testing Prompt & Strategi Follow-up** — eksperimen otomatis untuk optimasi conversion rate.
7. **Predictive Lead Scoring dengan Machine Learning** — model prediktif berbasis data historis closing, menggantikan/melengkapi rule-based scoring.
8. **Integrasi CRM/ERP Eksternal** — sinkronisasi dua arah dengan sistem CRM/ERP perusahaan bila ada.
9. **Self-Service Sales Mobile App** — aplikasi mobile untuk sales menerima notifikasi handover & mengelola leads di lapangan.
10. **Automated Compliance/Consent Management** — pencatatan consent customer terkait komunikasi otomatis sesuai regulasi perlindungan data yang berlaku.

---

*Dokumen ini adalah baseline PRD untuk memulai pengembangan MVP. Formula, threshold, dan interval waktu yang tercantum (skor, follow-up, SLA) bersifat baseline awal dan perlu dikalibrasi ulang berdasarkan data aktual setelah sistem berjalan.*
