# Design Spec: Loan List Enhancement — Sisa Pinjaman, Sorting & Filter Status

**Tanggal:** 2026-05-20
**Status:** Approved
**Project:** KSU Cooperative (ksu-app + ksu_mobile_app)

---

## 1. Tujuan

Menambah tiga fitur pada Loan List:
1. **Sisa Pinjaman** — tampilkan remaining balance di setiap card list
2. **Sorting** — sorting berdasarkan sisa pinjaman + default sort by `disbursedAt` (tanggal aktivasi)
3. **Filter Status** — sudah ada, hanya perlu verifikasi visibility untuk semua role

---

## 2. Database Migration (ksu-app)

### Migration: Add `remaining_balance` to `loans` table

**File:** `database/migrations/2026_05_20_XXXXXX_add_remaining_balance_to_loans_table.php`

```php
Schema::table('loans', function (Blueprint $table) {
    $table->bigInteger('remaining_balance')->default(0)->index()->after('customer_paid_amount');
});
```

**Logika kalkulasi** (konsisten dengan `RepaymentServiceImpl.getOutstandingLoanAmount`):
```
remaining_balance = customer_paid_amount - SUM(paid_amount) dari repayment_schedules
```

**Untuk loan non-activated (belum cair):** `remaining_balance = 0` (belum ada outstanding)
**Untuk loan non-activated yang baru di-submit:** `remaining_balance = original_loan_amount` (belum ada pembayaran, sisa = jumlah awal)

---

## 3. Artisan Command: Backfill Data Lama

**File:** `app/Console/Commands/BackfillRemainingBalance.php`

```bash
php artisan loans:backfill-remaining-balance
```

Logic:
1. Loop semua loans
2. Jika status = `activated`: hitung `remaining_balance = customer_paid_amount - SUM(paid_amount dari repayment_schedules)`
3. Jika status ≠ `activated`: `remaining_balance = 0`

---

## 4. Backend API Changes (ksu-app)

### 4.1 Sync trigger — update `remaining_balance` on payment events

**File:** `app/Services/RepaymentServiceImpl.php`

Di method `doPayment()` dan `rollbackPayment()` — setelah payment/rollback berhasil, update kolom:
```php
$loan->update(['remaining_balance' => $this->getOutstandingLoanAmount($loan)]);
```

### 4.2 `LoanServiceImpl.getAllLoans()` — Transform response

Tambahkan `remaining_balance` ke setiap loan object yang di-return:
```php
$loan->remainingBalance = $loan->remaining_balance;
```

### 4.3 Sorting `sortBy: 'remaining_balance'`

**File:** `app/Services/LoanServiceImpl.php`, method `applyFilters()`

Tambah case di switch statement:
```php
case 'remaining_balance':
    $query->orderBy('loans.remaining_balance', $sortOrder);
    break;
```

### 4.4 Default sort berubah

**Sebelum:** `ORDER BY created_at DESC`
**Sesudah:** `ORDER BY disbursed_at DESC` (tanggal aktivasi pinjam), null values di akhir

Artinya loans yang sudah diaktifkan (disbursed) tampil lebih dulu, diurutkan dari yang terbaru.

---

## 5. Frontend Changes (ksu_mobile_app)

### 5.1 Loan Model — tambah field

**File:** `lib/models/loan.dart`

```dart
Decimal remainingBalance; // nullable Decimal
```

### 5.2 LoanFragment — Tampilkan sisa pinjaman di card

**File:** `lib/fragment/LoanFragment.dart`

Tambah baris di bawah `originalLoanAmount` di setiap loan card:
```
Pinjaman: Rp 2.000.000
Sisa:     Rp 1.200.000    ← NEW
```

Styling: font lebih kecil dari jumlah pinjaman, warna `textSecondary`.

### 5.3 LoanFragment — Default sort by `disbursedAt`

**File:** `lib/fragment/LoanFragment.dart`

Di `_applyInitialFilters()`:
```dart
sortBy: 'disbursed_at',  // berubah dari 'created_at'
sortOrder: 'desc',
```

### 5.4 LoanFragment — Tambah sort option "Sisa Pinjaman"

**File:** `lib/fragment/LoanFragment.dart`

Di `_buildSortingSection()` — tambah option:
```dart
ListTile(
  title: const Text('Sisa Pinjaman'),
  leading: Radio<String>(
    value: 'remaining_balance',
    groupValue: sortBy,
    ...
  ),
  onTap: () => setModalState(() => onSortByChanged('remaining_balance')),
),
```

### 5.5 Filter status — verifikasi visibility

Filter status sudah ada di `_buildStatusFilterSection()`. Cek apakah visibility perlu disesuaikan untuk semua role. Saat ini conditional `authStore.hasRoleOrHigher(Role.lead)` — pertimbangkan apakah PDL juga perlu akses filter status.

---

## 6. Ringkasan Perubahan per File

### ksu-app (Backend)
| File | Perubahan |
|------|-----------|
| `database/migrations/..._add_remaining_balance_to_loans_table.php` | Migration baru |
| `app/Console/Commands/BackfillRemainingBalance.php` | Backfill command baru |
| `app/Services/RepaymentServiceImpl.php` | Sync trigger on payment/rollback |
| `app/Services/LoanServiceImpl.php` | Transform + sorting + default sort |

### ksu_mobile_app (Frontend)
| File | Perubahan |
|------|-----------|
| `lib/models/loan.dart` | Tambah `remainingBalance` field |
| `lib/fragment/LoanFragment.dart` | Tampilkan sisa, sort option, default sort |

---

## 7. Urutan Implementasi

1. Migration + Artisan command (backend)
2. Sync trigger di RepaymentServiceImpl (backend)
3. Transform + sorting di LoanServiceImpl (backend)
4. Test backend API (verifikasi response + sorting)
5. Flutter: Loan model update
6. Flutter: UI card + sort option
7. End-to-end test