# BLUEPRINT ARSITEKTUR: ENTERPRISE MESSENGER & AI COPILOT HUB
**Sistem ERP Everest — Versi 2.0 (Agustus 2026)**

---

## 1. Ringkasan Eksekutif & Tujuan

Blueprint ini mendokumentasikan arsitektur, spesifikasi teknis, skema data, serta panduan operasional dari modul **Enterprise Messenger & AI Copilot Hub** pada ERP Everest. 

Modul ini dirancang untuk menyatukan tiga fungsi komunikasi kritis dalam satu widget terpadu:
1. **🤖 Asisten Cerdas AI (Everest AI Copilot)**: Konsultasi instan alur transaksi, rumus akuntansi, dan operasional ERP via model bahasa besar (LLM).
2. **🏢 Komunikasi Antar Cabang**: Saluran koordinasi operasional antar kantor cabang dan kantor pusat (misal mutasi barang, konfirmasi pengiriman, atau otorisasi).
3. **👤 Komunikasi Antar User (Direct Message 1-on-1)**: Saluran pesan privat antar karyawan/staf lintas divisi dan cabang.

---

## 2. Batasan Teknologi & Lingkungan Eksekusi

Berdasarkan aturan tata kelola codebase ERP Everest:
* **Bahasa Pemrograman**: PHP 5.6 murni.
  * Sintaks array wajib menggunakan `array()` (bukan `[]`).
  * Tidak menggunakan null coalescing operator `??`, arrow functions `fn()`, anonymous classes, atau scalar type hints.
* **Framework**: CodeIgniter **3.1.8** dengan Wiredesignz HMVC Extension.
* **Database Transaksional**: **MySQL / MariaDB** (menggunakan database `run_everest_modul`).
* **Larangan Penggunaan**: **MongoDB TIDAK DIGUNAKAN** sama sekali untuk modul ini.
* **Frontend Stack**: AdminLTE 2.3.11, Bootstrap 3.3.7, jQuery 2.2.3, FontAwesome, dan Web Audio API (native browser).

---

## 3. Diagram Arsitektur & Alur Data

```mermaid
graph TD
    subgraph Browser Client
        UI[Widget Messenger & AI<br/>he_chat_helper.php]
        Trigger[Floating Button & Badge]
        Audio[Web Audio API Chime]
    end

    subgraph Core Framework CI3
        Layout[Layout.php Library<br/>Injeksi Otomatis sebelum body]
        Ctrl[Chat.php Controller<br/>Non-blocking Session Handler]
        Cfg[ai_chat.php Config<br/>API Key & Provider Config]
    end

    subgraph Database Layer MySQL
        Model[MdlChat.php Model]
        TblMsg[(sys_chat_message)]
        TblCabang[(per_cabang)]
        TblEmp[(per_employee)]
    end

    subgraph External Cloud
        AI_Gemini[Google Gemini API<br/>gemini-1.5-flash]
        AI_OpenAI[OpenAI API<br/>gpt-4o-mini]
    end

    Layout --> UI
    UI <-->|AJAX Fast Poll 1.5s / Send| Ctrl
    Ctrl --> Cfg
    Ctrl <--> Model
    Model <--> TblMsg
    Model <--> TblCabang
    Model <--> TblEmp
    Ctrl <-->|cURL Server-side| AI_Gemini
    Ctrl <-->|cURL Server-side| AI_OpenAI
    UI --> Audio
```

---

## 4. Struktur Basis Data (MySQL Schema)

Tabel utama obrolan adalah `sys_chat_message` yang tersimpan pada MariaDB transaksional dengan skema polimorfik:

### DDL Tabel `sys_chat_message`
```sql
CREATE TABLE IF NOT EXISTS `sys_chat_message` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `chat_type` VARCHAR(20) NOT NULL DEFAULT 'branch' COMMENT 'Tipe: branch, direct, ai',
  `sender_id` INT(11) NOT NULL COMMENT 'ID User pengirim (0 jika AI)',
  `sender_name` VARCHAR(100) NOT NULL COMMENT 'Nama staf pengirim / Everest AI',
  `sender_cabang_id` INT(11) NOT NULL COMMENT 'ID Cabang pengirim (-1 jika Pusat/AI)',
  `sender_cabang_nama` VARCHAR(100) NOT NULL COMMENT 'Nama Cabang pengirim',
  `target_id` INT(11) NOT NULL DEFAULT '0' COMMENT 'Cabang ID / User ID / AI Target ID',
  `target_name` VARCHAR(100) NOT NULL DEFAULT '' COMMENT 'Nama Cabang / Nama User target',
  `cabang_id` INT(11) NOT NULL DEFAULT '0' COMMENT 'Kolom backward-compatible cabang',
  `message` TEXT NOT NULL COMMENT 'Isi pesan teks',
  `ref_transaksi` VARCHAR(100) DEFAULT NULL COMMENT 'Nomor dokumen referensi (opsional)',
  `is_read` TINYINT(1) DEFAULT '0' COMMENT '0: belum dibaca, 1: sudah dibaca',
  `created_at` DATETIME NOT NULL COMMENT 'Waktu pengiriman pesan',
  PRIMARY KEY (`id`),
  KEY `idx_type_target` (`chat_type`, `target_id`, `id`),
  KEY `idx_sender` (`sender_id`, `id`),
  KEY `idx_created_at` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
```

### Mekanisme Self-Healing Migration
Model `MdlChat.php` menjalankan metode `ensure_table_exists()` setiap kali diinisialisasi. Metode ini mengecek:
1. Apakah tabel `sys_chat_message` sudah ada.
2. Jika sudah ada dari rilis sebelumnya, secara otomatis menjalankan `ALTER TABLE` untuk menyuntikkan kolom `chat_type`, `target_id`, dan `target_name` tanpa perlu intervensi manual dari DBA.

---

## 5. Rincian Komponen & Berkas Sistem

| Berkas | Peran & Tanggung Jawab |
|---|---|
| [`application/config/ai_chat.php`](file:///w:/everest_13agus/application/config/ai_chat.php) | Menyimpan konfigurasi provider AI, endpoint, model, dan API Key terpusat. |
| [`application/models/Mdls/MdlChat.php`](file:///w:/everest_13agus/application/models/Mdls/MdlChat.php) | Model query MySQL untuk isolasi pesan, update status baca, query unread, dan daftar kontak. |
| [`application/controllers/Chat.php`](file:///w:/everest_13agus/application/controllers/Chat.php) | Controller gerbang AJAX, pembebasan lock sesi PHP (`session_write_close`), dan integrasi cURL ke LLM. |
| [`application/helpers/he_chat_helper.php`](file:///w:/everest_13agus/application/helpers/he_chat_helper.php) | Helper UI yang menghasilkan markup CSS, HTML multi-tab messenger, logika deduplikasi DOM, dan audio chime. |
| [`application/libraries/Layout.php`](file:///w:/everest_13agus/application/libraries/Layout.php) | Menginjeksi widget secara global ke seluruh halaman modul sebelum tag `</body>`. |

---

## 6. Logika Inti & Solusi Masalah Teknis

### 6.1. Proteksi Anti-Dobel (Deduplikasi Mutlak)
Untuk mencegah gelembung pesan (*chat bubble*) muncul ganda saat pengiriman manual berbarengan dengan respons polling:
1. Setiap elemen gelembung di-render dengan ID unik: `id="ev-msg-" + m.id`.
2. Di dalam JavaScript fungsi `appendMessageBubble()`:
   ```javascript
   if (document.getElementById('ev-msg-' + mId)) {
       return; // Langsung dibatalkan jika ID sudah ada di DOM
   }
   ```
3. Pelacakan kursor ID: `lastMessageId = Math.max(lastMessageId, parseInt(m.id))`.

### 6.2. Proteksi Anti-Iframe & Single Instance Guard
ERP Everest memiliki halaman modal atau pratinjau yang dimuat di dalam tag `<iframe>`.
* **Guard PHP**: Variabel `static $is_rendered = false;` di `he_chat_helper.php` memastikan fungsi render tidak menghasilkan output dua kali dalam satu lifecycle HTTP request.
* **Guard JS**: 
  ```javascript
  if (window.self !== window.top) {
      // Jika termuat di dalam iframe, musnahkan elemen dari DOM iframe
      $('#ev-chat-trigger, #ev-chat-window').remove();
      return;
  }
  ```

### 6.3. Akselerasi Real-time & Pembebasan Lock Sesi PHP
Polling cepat (1.5 detik) tanpa konfigurasi yang tepat dapat menyebabkan *session lock contention* pada PHP bawaan.
* Di awal controller `Chat.php`:
  ```php
  private function check_auth_ajax() {
      // Validasi sesi aktif...
      if (session_status() === PHP_SESSION_ACTIVE) {
          session_write_close(); // Lepas kunci file session segera!
      }
  }
  ```
* **Hasil**: Request polling berjalan paralel secara murni tanpa menghambat navigasi atau transaksi pada tab browser pengguna lain.
* **Frekuensi Polling**:
  * Jendela obrolan terbuka: **1.5 detik (1500 ms)**.
  * Jendela obrolan tertutup: **3.0 detik (3000 ms)** untuk refresh badge notifikasi.

### 6.4. Notifikasi Audio Halus (Web Audio API)
Alih-alih membebani server dengan berkas audio MP3 eksternal, sistem menggunakan osilator Web Audio API bawaan browser untuk menghasilkan nada *chime* lembut frekuensi 880Hz -> 1760Hz saat ada pesan baru masuk:
```javascript
var ctx = new AudioContext();
var osc = ctx.createOscillator();
osc.frequency.setValueAtTime(880, ctx.currentTime);
osc.frequency.exponentialRampToValueAtTime(1760, ctx.currentTime + 0.12);
```

### 6.5. Kontekstual Transaksi (Fitur Tombol Klip 📎)
Ketika staf membuka chat saat berada di halaman transaksi (misal sedang mengedit invoice atau menerima barang), staf dapat menekan tombol klip (📎).
* Script otomatis memindai URL atau input DOM untuk nomor transaksi (format `xxxx.xxxxxxxx`).
* Pesan yang dikirim akan menyertakan tautan aktif yang jika diklik oleh lawan bicara akan langsung membuka modal resume transaksi via `renderCrossModulResumeLink()`.

---

## 7. Panduan Konfigurasi Asisten AI (Everest AI)

Pengaturan AI sepenuhnya terpusat pada file [`application/config/ai_chat.php`](file:///w:/everest_13agus/application/config/ai_chat.php).

### Skenario A: Menggunakan Google Gemini (Rekomendasi)
```php
$config['ai_chat'] = array(
    'enabled'       => true,
    'provider'      => 'gemini',
    'api_key'       => 'AIzaSyYourGeminiApiKeyHere',
    'model'         => 'gemini-1.5-flash', // Sangat cepat dan hemat kuota
    'endpoint'      => 'https://generativelanguage.googleapis.com/v1beta/models/',
    'timeout'       => 30,
    'system_prompt' => 'Anda adalah asisten cerdas ERP Everest...'
);
```

### Skenario B: Menggunakan OpenAI / ChatGPT
```php
$config['ai_chat'] = array(
    'enabled'         => true,
    'provider'        => 'openai',
    'api_key'         => 'sk-proj-YourOpenAIApiKeyHere',
    'model'           => 'gpt-4o-mini',
    'openai_endpoint' => 'https://api.openai.com/v1/chat/completions',
    'timeout'         => 30,
    'system_prompt'   => 'Anda adalah asisten cerdas ERP Everest...'
);
```

> [!NOTE]
> Jika `api_key` dibiarkan kosong, bot AI akan memberikan panduan ramah kepada pengguna untuk melengkapi berkas konfigurasi, tanpa menyebabkan galat/crash pada sistem.

---

## 8. Pemeliharaan & Skalabilitas Masa Depan

1. **Retensi & Pembersihan Pesan Usang (Housekeeping)**:
   Karena pesan disimpan di MySQL, administrator dapat menjadwalkan pembersihan berkala (misal pesan obrolan umum yang lebih lama dari 6 bulan) via cron job query sederhana:
   ```sql
   DELETE FROM sys_chat_message WHERE created_at < NOW() - INTERVAL 180 DAY;
   ```
2. **Ekspansi ke Grup / Divisi**:
   Dengan adanya kolom `chat_type` dan `target_id`, sistem di masa depan dapat dengan mudah diperluas untuk mendukung grup chat per divisi (misal: Grup Keuangan, Grup Gudang, dsb.).
