# Review Refaktorisasi Thin Controller ke DDD Pragmatis (CodeIgniter 3)

Secara umum, koding Controller CodeIgniter 3 (CI3) yang diunggah **sudah cukup fungsional dan memiliki struktur delegasi yang bagus (layak jalan untuk skala aplikasi kecil-menengah), namun belum sepenuhnya ideal atau *production-ready* tingkat tinggi menurut standar arsitektur modern dan Domain-Driven Design (DDD) pragmatis.**

Mari kita bedah secara objektif kelebihan koding ini, serta beberapa area kritikal yang perlu direfaktorisasi agar kode Anda benar-benar aman, mudah diuji (*testable*), dan siap menghadapi skala yang lebih besar:

---

## I. Aspek Positif (Mengapa Koding Ini Sudah Bagus)

### 1. Penerapan *Thin Controller* yang Baik
Anda sudah berhasil menghindari *Fat Controller* (kontroler yang gemuk dengan kueri database mentah). Controller `Create` ini murni bertindak sebagai delegator. Logika penyimpanan, penyusunan data pratinjau, dan pembatalan didelegasikan ke service luar seperti:
- `ComSalesOrderService`
- `ComTransactionReversalEngine`
- `ComSalesOrderFollowupService`

Hal ini sangat sesuai dengan arsitektur berlapis (*layered architecture*) dalam DDD.

### 2. Pemisahan Konteks Autentikasi
Menarik data `$authContext` dari sesi login dan membungkusnya secara terpisah sebelum dikirim ke service adalah langkah penulisan kode yang aman. Hal ini menjaga agar logika otorisasi dan identitas pengguna tetap terisolasi dengan rapi.

---

## II. Area Kritikal yang Perlu Diperbaiki (*Refactoring Opportunities*)

Meskipun sudah layak jalan, ada beberapa *technical debt* (utang teknis) dan *anti-pattern* yang membuat koding ini berisiko di lingkungan produksi skala besar:

### 1. Ketergantungan Ekstrem pada Global State (`$_SESSION`)
* **Masalah:** Metode seperti `recordColumn()` memodifikasi state transaksi secara langsung ke dalam session PHP (`$_SESSION[$cCode]['main'][$colName] = $val;`).
* **Risiko:** State mutable yang disimpan di session server sangat rentan terhadap *race condition* (jika pengguna membuka dua tab browser sekaligus) dan inkonsistensi data jika koneksi terputus di tengah jalan.
* **Solusi DDD Pragmatis:** Controller seharusnya tidak memanipulasi session secara langsung untuk urusan logika bisnis. Gunakan objek **DTO (Data Transfer Object)** atau simpan draf transaksi sementara di database (misal menggunakan PostgreSQL/MySQL atau MongoDB yang Anda load di konstruktor).

### 2. Penggunaan Fungsi `mati_disini()` (*Abrupt Exit*)
* **Masalah:** Di hampir semua metode (`save`, `doEdit`, `recordColumn`, `autoOtorisasi`), validasi yang gagal langsung memicu fungsi pembatalan keras `mati_disini("pesan")`.
* **Risiko:** Penggunaan `exit`/`die` (di dalam `mati_disini`) memotong siklus hidup framework CI3 secara paksa. Ini membuat kode Anda **mustahil untuk di-unit test**. Selain itu, ini tidak ramah bagi integrasi API (misalnya front-end Angular/React akan menerima respon rusak, bukan JSON yang terstruktur).
* **Solusi:** Ubah controller agar melempar *Exception* atau mengembalikan objek *Status/Result* terstruktur (misal menggunakan HTTP status code `400 Bad Request` dengan payload JSON berisi pesan eror).

### 3. Kebocoran Logika UI (*UI Concerns*) ke Layer Service
* **Masalah:** Controller Anda menyusun konfigurasi langkah tampilan (`$customConfig` berisi `steps`, `components`, `preProcessor`, dll.) lalu melemparnya ke level Service (`$salesService->createSalesOrder($transactionPayload, ..., $customConfig)`).
* **Risiko:** Berdasarkan prinsip DDD, lapisan bisnis/service (*Domain/Application Layer*) harus **independen dari detail presentasi/UI**. Jika langkah UI berubah, Anda terpaksa mengubah logika di dalam Service.
* **Solusi:** Service hanya perlu menerima data murni (payload transaksi). Biarkan aturan aliran (*workflow*) dikelola di level aplikasi, bukan dengan melempar struktur UI ke dalam domain.

### 4. Kopling Manual `require_once` dan Pemuatan Model Berulang
* **Masalah:** Di setiap metode, Anda menulis pengecekan manual seperti `if (!class_exists('ComSalesOrderService') ...) { require_once ... }`.
* **Risiko:** Ini mengotori koding controller Anda dengan masalah infrastruktur pemuatan file.
* **Solusi:** Manfaatkan Autoloader PHP (seperti Composer dengan standar PSR-4) bahkan di CI3 sekalipun, agar seluruh kelas service dapat dimuat otomatis tanpa baris `require_once` manual.

### 5. Controller Menghasilkan Skrip Client-Side (XSS & *Separation of Concerns*)
* **Masalah:** Di dalam `recordColumn()`, controller langsung mengeprint tag `<script>` / inline JS ke browser.
* **Risiko:** Mencampur aduk logika controller dengan tampilan client-side, berpotensi menimbulkan celah XSS jika input tidak disanitasi dengan ketat, serta merusak prinsip *Separation of Concerns*.
* **Solusi:** Kembalikan response terstruktur (JSON) atau delegasikan rendering skrip/tampilan sepenuhnya ke layer View/Template.

---

## III. Analisis Struktur Controller `Create` & Integrasi Akuntansi

### 1. Deskripsi Berkas
Berkas controller PHP berbasis framework **CodeIgniter 3 (CI3)** dengan nama kelas `Create` yang mewarisi `Modul_Controller`. Controller ini bertugas mengelola alur pembuatan, pengeditan, hingga pembatalan transaksi (khususnya *Sales Order* / Penjualan).

### 2. Pengamatan Kunci Struktur Kode
* **Penerapan Delegasi Service (*Thin Controller*):**  
  Secara arsitektur, implementasi sudah melangkah di jalur yang benar. Controller ini tidak melakukan kueri database SQL secara mentah (*raw queries*). Untuk proses penyimpanan utama, metode `save()` dan `doEdit()` mendelegasikan logika pemrosesan ke layanan eksternal yaitu `ComSalesOrderService` (melalui method `createSalesOrder` dan `editSalesOrder`).
* **Ketergantungan Kuat pada State *Session* (`$_SESSION`):**  
  Sistem sangat mengandalkan penyimpanan state transaksi sementara di dalam session PHP (`$_SESSION[$cCode]`) sebelum akhirnya dibungkus sebagai payload dan dikirim ke Service untuk disimpan ke database.
* **Batas Transaksi saat Penyelamatan Data (*Saving*):**  
  Di dalam method `save()`, payload transaksi dikirim ke service. Jika prosesnya sukses (`$res['status'] === true`), session dibersihkan dan UI menampilkan pesan sukses menggunakan *SweetAlert* (`swalAlert`).

---

## IV. Hubungan Alur Penjualan ke Modul Akuntansi (Pragmatis - *Single Bounded Context*)

Jika Anda ingin menghubungkan proses **Penjualan ke modul Akuntansi** dalam arsitektur saat ini:

1. **Prinsip *"Bukan 1 Transaksi 1 Kontroler"*:**  
   Kontroler `Create` ini hanya bertugas memicu proses (*orchestration / entry point*).
2. **Batas Transaksi Database (*Unit of Work*):**  
   Batas transaksi database Anda berada di dalam method `createSalesOrder` milik **`ComSalesOrderService`**. Di dalam method inilah Anda memulai transaksi database (*begin transaction* / `trans_start`).
3. **Pemicuan Layanan Akuntansi (*Accounting Domain Service*):**  
   Setelah data penjualan berhasil disimpan di dalam service tersebut, Anda langsung memanggil **Accounting Domain Service** (misalnya `JurnalAccountingService`) untuk memproses pembukuannya.
4. **Mekanisme Atomisitas & *Rollback*:**  
   Jika salah satu langkah gagal (baik simpan penjualan maupun penjurnalan), *rollback* (`trans_rollback` / `trans_complete`) dilakukan di level service tersebut, dan mengembalikan status `false` beserta pesan error ke controller untuk ditampilkan ke pengguna.

---

### Langkah Diskusi Lanjutan
1. Membedah cara memicu pencatatan akuntansi secara bersih dan atomik dari proses `save()`.
2. Menyusun struktur kelas entitas / DTO untuk menggantikan manipulasi langsung `$_SESSION`.
