# 🏛️ BLUEPRINT ARSITEKTUR MIGRASI ENTERPRISE
## Refactoring Mega-Controllers ke Modular Domain Services & Centralized Engines
**Target Framework:** CodeIgniter 3 (CI 3.1.8) Legacy Environment  
**Standar Kepatuhan:** ISO 9001 (Manajemen Mutu), ISO 27001 (Keamanan & Integritas Data), PSAK/IFRS, DJP Coretax  
**Sasaran Utama:** Memangkas MTTR (*Mean Time To Resolution*) dari 300+ menit menjadi **< 15 menit (SLA Enterprise SAP Equivalent)**.

---

## 1. 📋 EXECUTIVE SUMMARY & PRINSIP MIGRASI

### 1.1 Masalah Utama Sistem Saat Ini (*Current State Bottlenecks*)
1. **Mega-Controllers (*High Cognitive Load*):** File controller berukuran 4.500 hingga 22.500 baris kode (`Create.php`, `_shoppingCart.php`, `coTransaksiUi.php`).
2. **Stateful Session Sprawl:** Variabel transaksi tersebar dan dimutasi secara acak di dalam `$_SESSION[$cCode]` oleh belasan sub-controller tanpa kontrak data yang jelas.
3. **Magic Strings & Polymorphic Identifiers:** Representasi entitas yang sama menggunakan string berbeda (`'pusat'`, `'center'`, `'dc'`, `ID 12`, `cabang_id = -1`).
4. **Transport Layer Fragile:** Menggunakan iframe `#result` untuk eksekusi script DOM daripada payload data terstruktur (JSON).
5. **Ketiadaan Single Source of Truth:** Rumus stok dan diskon dihitung ulang secara terpisah di controller, helper, dan JavaScript view.

### 1.2 Prinsip Migrasi: *The Strangler Fig Pattern* (Anti-Rewrite Total)
> **PANTANGAN UTAMA:** Dilarang melakukan penulisan ulang (*full rewrite*) dari nol karena berisiko melumpuhkan operasional harian.

Migrasi dilakukan secara **bertahap, non-destruktif, dan modular (*Strangler Fig Pattern*)**:
* Sistem lama tetap berjalan 100%.
* Logika bisnis diekstrak satu per satu ke dalam **Centralized Domain Services (Com\*)**.
* Controller lama secara bertahap dijadikan *Thin Controller* (hanya bertindak sebagai pengarah lalu lintas / *router & delegator*).

---

## 2. 🏗️ PERBANDINGAN ARSITEKTUR: AS-IS vs TO-BE

```mermaid
graph TD
    subgraph "CURRENT (AS-IS) ARCHITECTURE"
        UI1["UI View (Iframe #result)"] -->|URL Script Strings| C1["Mega Controller (22.000 Lines)"]
        C1 <-->|Mutasi Acak| S1["$_SESSION Global Sprawl"]
        C1 -->|Kalkulasi Duplikat| DB1[("MySQL & Stock Locker")]
    end

    subgraph "TARGET (TO-BE) ARCHITECTURE"
        UI2["UI View (AJAX / JSON Fetch)"] -->|Structured DTO / Payload| C2["Thin Controller (< 300 Lines)"]
        C2 -->|Validasi & Delegasi| DL["Domain Service Layer"]
        DL --> SE["ComStockEngine (Stok, Booking, Intransit)"]
        DL --> PE["ComPricingEngine (Diskon, Pajak, DPP)"]
        DL --> AE["ComAccountingEngine (Journaling, GL)"]
        SE & PE & AE --> Repos["Repository & Dual-Write Locker"]
        Repos --> DB2[("MySQL & MongoDB Draft")]
    end
```

---

## 3. 🧩 4 PILAR UTAMA BLUEPRINT MIGRASI

---

### PILAR 1: Sentralisasi Engine Bisnis (*Single Source of Truth Services*)
Semua formula dan kalkulasi bisnis dipindahkan dari controller ke model domain `Com*` di `application/models/Coms/`.

#### 1.1 `ComStockEngine.php` (Sentralisasi Seluruh Logika Persediaan)
Tidak ada lagi controller yang boleh menulis formula stok `($stokFisik - $stok_booking) - $qty` sendiri. Semua memanggil engine terpusat:
```php
/**
 * [AGENT_LOG]
 * ROLE      : Lead Architect & Inventory Specialist
 * PURPOSE   : Centralized Engine untuk perhitungan seluruh status stok (Fisik, Avail, Booking, Intransit)
 * COMPLIANCE: ISO 9001 (8.5.1), ISO 27001 (A.8.24), PSAK 14
 * LOG_EXPIRE: 2026-11-15
 * [/AGENT_LOG]
 */
class ComStockEngine extends CI_Model {
    
    /**
     * Menghitung status stok lengkap untuk 1 produk pada gudang tertentu
     */
    public function getStockStatus($productId, $warehouseStatusId, $cabangId = null, $cartQty = 0) {
        $isPusat = $this->isCenterWarehouse($warehouseStatusId);
        
        // 1. Ambil stok fisik dari Locker
        $stokFisik = $this->getPhysicalStock($productId, $isPusat, $cabangId);
        
        // 2. Ambil antrean booking SO
        $stokBooking = $this->getBookingStock($productId, $warehouseStatusId, $cabangId);
        
        // 3. Ambil stok dalam perjalanan (In Transit)
        $stokIntransit = $this->getIntransitStock($productId, $isPusat, $cabangId);
        
        // 4. Hitung ketersediaan
        $stokAvailGudang = $stokFisik - $stokBooking;
        $sisaSiapJual    = $stokAvailGudang - $stokIntransit - $cartQty;
        
        return array(
            'stok_fisik'       => (float)$stokFisik,
            'stok_booking'     => (float)$stokBooking,
            'stok_intransit'   => (float)$stokIntransit,
            'stok_avail'       => (float)$stokAvailGudang,
            'sisa_siap_jual'   => (float)$sisaSiapJual,
            'is_minus'         => ($sisaSiapJual < 0)
        );
    }
}
```

#### 1.2 `ComPricingEngine.php` (Sentralisasi Diskon, DPP, & PPN)
Menangani matrix harga, promosi bertingkat, diskon persentase/nominal, pembulatan, dan kalkulasi Coretax PPN 11% secara presisi.

#### 1.3 `ComAccountingEngine.php` (Sentralisasi Jurnal & GL)
Menjamin kepatuhan *Double-Entry Bookkeeping* (Debit = Kredit) dan *Immutable Audit Trail* (tidak ada UPDATE/DELETE pada tabel mutasi).

---

### PILAR 2: Eliminasi *Magic Strings* Menggunakan Kamus Konstanta (*Enums*)
Membuat berkas `application/config/everest_constants.php` untuk membakukan seluruh status dan identitas entitas.

```php
<?php
defined('BASEPATH') OR exit('No direct script access allowed');

// 1. Identitas Gudang & Cabang
define('WH_STATUS_PUSAT_ID', 12);
define('WH_STATUS_CABANG_ID', 13);
define('CABANG_PUSAT_ID', -1);
define('GUDANG_PUSAT_ID', -1);

// 2. Tipe Entitas
define('WH_TYPE_PUSAT', 'pusat');
define('WH_TYPE_CABANG', 'cabang');

// 3. State Transaksi & Locker
define('LOCKER_STATE_ACTIVE', 'active');
define('LOCKER_STATE_HOLD', 'hold');
define('LOCKER_JENIS_PRODUK', 'produk');
define('LOCKER_JENIS_SUPPLIES', 'supplies');
define('LOCKER_JENIS_JASA', 'jasa');

// 4. Kategori Produk Khusus
define('PRODUK_KATEGORI_JASA_ID', 4);
```

---

### PILAR 3: Kontrak Data Terstruktur (*Data Transfer Objects / DTOs*)
Menggantikan array bebas `$_SESSION` dengan struktur DTO yang divalidasi ketat sebelum diproses.

```php
/**
 * Kontrak Standar Item Keranjang Belanja
 */
class CartItemDTO {
    public $productId;
    public $productCode;
    public $productName;
    public $qty;
    public $uom;
    public $price;
    public $discountPercent;
    public $discountNominal;
    public $warehouseStatusId;
    public $isPusat;
    
    public function __construct(array $data) {
        $this->productId         = (int)isset($data['id']) ? $data['id'] : 0;
        $this->productCode       = (string)isset($data['produk_kode']) ? $data['produk_kode'] : '';
        $this->productName       = (string)isset($data['nama']) ? $data['nama'] : '';
        $this->qty               = (float)isset($data['jml']) ? $data['jml'] : 0;
        $this->warehouseStatusId = (int)isset($data['gudang_status_id']) ? $data['gudang_status_id'] : WH_STATUS_CABANG_ID;
        $this->isPusat           = ($this->warehouseStatusId === WH_STATUS_PUSAT_ID);
    }
}
```

---

### PILAR 4: Dekomposisi Controller (*Thin Controller Pattern*)
Controller hanya menerima input, memvalidasi sesi/izin, memanggil Domain Service, dan mengembalikan respons:

```php
// CONTOH CONTROLLER YANG BERSIH (< 80 baris)
class _shoppingCart extends Modul_Controller {
    
    public function updateItemQty() {
        $this->load->model('Coms/ComStockEngine');
        
        $itemDto = new CartItemDTO($this->input->post());
        
        // Delegasikan kalkulasi ke Engine terpusat
        $stockStatus = $this->ComStockEngine->getStockStatus(
            $itemDto->productId, 
            $itemDto->warehouseStatusId, 
            my_cabang_id(), 
            $itemDto->qty
        );
        
        // Simpan ke sesi transaksi
        $this->updateSessionCart($itemDto, $stockStatus);
        
        // Return JSON terstruktur
        return $this->output
            ->set_content_type('application/json')
            ->set_output(json_encode(array(
                'status' => 'success',
                'data'   => $stockStatus
            )));
    }
}
```

---

## 4. 📅 TAHAPAN IMPLEMENTASI (5-PHASE ROADMAP)

| Fase | Durasi Est. | Fokus Pekerjaan | Tingkat Risiko | Output / Deliverable |
| :--- | :---: | :--- | :---: | :--- |
| **Fase 1** | Minggu 1 | **Setup Fondasi & Constants** | **0% (Nol Risiko)** | Berkas `everest_constants.php`, pendaftaran helper global. |
| **Fase 2** | Minggu 2 | **Pembangunan Centralized Engines** | **Rendah** | `ComStockEngine`, `ComPricingEngine`, `ComAccountingEngine` (diuji dengan Unit Test). |
| **Fase 3** | Minggu 3 | **Penyambungan Modul Penjualan (`582`)** | **Sedang** | Refactor `_shoppingCart.php` & `_processSelectProduct.php` memanggil engine baru. |
| **Fase 4** | Minggu 4 | **Penyambungan Modul Distribusi & Pembelian** | **Sedang** | Refactor modul `distribusifg` & `pembelian` menggunakan engine terpusat. |
| **Fase 5** | Minggu 5 | **Observability & Error Tracing Dashboard** | **Nol Risiko** | Pemasangan logging real-time kalkulasi stok/diskon untuk investigasi instan (< 5 menit). |

---

## 5. 🛡️ MITIGASI RISIKO & VERIFIKASI KEAMANAN (ISO 9001 / 27001)

1. **Dual-Run / Shadow Verification:**
   Selama masa transisi Fase 3, sistem akan menghitung stok menggunakan metode lama dan metode baru secara paralel di background. Jika ditemukan selisih angka (misal > 0 rupiah atau > 0 unit), sistem otomatis mencatat peringatan ke log audit sebelum melakukan transaksi.
2. **ACID Transaction Preservation:**
   Setiap operasi mutasi database tetap dilindungi `$this->db->trans_start()` dan `$this->db->trans_complete()`.
3. **Pemberitahuan Developer (Gatekeeper Rule):**
   Setiap perubahan pada sub-modul wajib melalui konfirmasi persetujuan sebelum diterapkan ke kode produksi.
