# PPDB Admin Panel Restructuring - Documentation

## Project Status: ✅ COMPLETED

**Date:** June 16, 2024  
**Objective:** Restructure admin panel into 4 specialized submenu views matching PPDB business process requirements.

---

## Architecture Overview

The admin panel now uses a **dispatcher pattern** with 4 specialized handlers, each providing focused data views for specific PPDB business functions.

### Route & Navigation Flow

```
GET /admin/pendaftar ┌─→ listPendaftar() dispatcher
                     │
                     ├─→ (no ?menu param) → handleDataPendaftar() → pendaftar.blade.php
                     │
                     ├─→ ?menu=berkas → handleVerifikasiBerkas() → verifikasi_berkas.blade.php
                     │
                     ├─→ ?menu=pembayaran → handleVerifikasiPembayaran() → verifikasi_pembayaran.blade.php
                     │
                     └─→ ?menu=seleksi → handleHasilSeleksi() → hasil_seleksi.blade.php
```

---

## 1. Data Pendaftar (Default View)

**URL:** `/admin/pendaftar`  
**Controller Method:** `handleDataPendaftar()` (lines 97-150)

### Purpose
Display comprehensive list of all applicants with their registration and payment status.

### Table Structure

| Column | Source | Purpose |
|--------|--------|---------|
| No. | Pagination counter | Row numbering |
| Kode Pendaftar | users.id_user | Applicant code (monospace) |
| Nama Anak | biodata_siswa.nama_anak | Applicant name |
| NISN | biodata_siswa.nik | National Student ID |
| Jenis Kelamin | biodata_siswa.jenis_kelamin | Gender (L/P) with color coding |
| Tempat, Tgl Lahir | biodata_siswa.tgl_lahir_panjang | Birth place and date |
| Nama Orang Tua/Wali | users.nama_pendaftar | Parent/guardian name + email |
| Nomor HP | biodata_siswa.no_hp | Parent contact number |
| Asal Sekolah | biodata_siswa.nama_sekolah_asal | Previous school |
| Tgl Pendaftaran | users.created_at | Registration date (d M Y format) |
| Status Pendaftaran | users.status_langkah | Step status with color badge |
| Aksi | — | Lihat Detail \| Edit Data |

### Filters

- **Search:** Searches across nama_anak, nama_pendaftar, sekolah_asal
- **Status:** Filter by registration step (Bayar Formulir, Isi Formulir, Tes Online, Selesai)
- **Jenis Kelamin:** Filter by gender (Laki-laki / Perempuan)
- **Asal Sekolah:** Text input filter for school name

### Status Mapping

Status Langkah colors and labels:
- `bayar_pendaftaran` → 🟡 Yellow "Bayar Formulir"
- `isi_formulir` → 🔵 Blue "Isi Formulir"
- `tes_online` → 🔵 Blue "Tes Online"
- `bayar_uang_pangkal` → 🟡 Yellow "Bayar Pangkal"
- `verifikasi_berkas` → 🟡 Yellow "Verif. Berkas"
- `selesai` → 🟢 Green "Selesai"

### Database Query

```php
$q = DB::table('users')
  ->leftJoin('biodata_siswa', 'users.id_user', '=', 'biodata_siswa.id_user')
  ->leftJoin('pembayaran as pend', function($join){
    $join->on('users.id_user', '=', 'pend.id_user')
         ->where('pend.jenis_pembayaran', '=', 'Pendaftaran');
  })
  ->leftJoin('pembayaran as pang', function($join){
    $join->on('users.id_user', '=', 'pang.id_user')
         ->where('pang.jenis_pembayaran', '=', 'Uang Pangkal');
  })
  ->where('users.role', '=', 'pendaftar')
  ->select('users.*', 'biodata_siswa.*', 'pend.status as bayar_pendaftaran_status', ...)
  ->paginate(20);
```

---

## 2. Verifikasi Berkas (Document Verification)

**URL:** `/admin/pendaftar?menu=berkas`  
**Controller Method:** `handleVerifikasiBerkas()` (lines 152-185)  
**Permission:** Accessible to all admin users

### Purpose
Review uploaded documents from applicants and verify document completeness and validity.

### Table Structure

| Column | Source | Purpose |
|--------|--------|---------|
| No. | Counter | Row numbering |
| Kode Pendaftar | users.id_user | Applicant code |
| Nama Orang Tua/Wali | users.nama_pendaftar | Parent name |
| Nama Anak | biodata_siswa.nama_anak | Applicant name |
| Dokumen (count) | File count in uploads/ | Number of uploaded files |
| Tanggal Upload | biodata_siswa.tgl_verifikasi_berkas | Latest file upload date |
| Status Verifikasi | biodata_siswa.status_berkas | Verification status |
| Catatan | biodata_siswa.catatan_berkas | Admin verification notes |
| Aksi | — | Lihat Detail \| Verifikasi |

### Status Filters

- **Status Berkas:** Belum Dicek \| Valid \| Tidak Valid

### Database Query

```php
$q = DB::table('biodata_siswa')
  ->join('users', 'biodata_siswa.id_user', '=', 'users.id_user')
  ->whereNotNull('biodata_siswa.berkas')
  ->where('users.role', '=', 'pendaftar')
  ->select('biodata_siswa.*', 'users.nama_pendaftar', 'users.email', ...)
  ->paginate(20);
```

### Status Indicators

- 🟡 **Belum Dicek** (Not Verified) - Default status
- 🟢 **Valid** - Documents approved
- 🔴 **Tidak Valid** - Documents rejected, requires resubmission

### Actions

- **Lihat Detail:** Opens applicant detail page
- **Verifikasi:** Links to document verification section in detail page

---

## 3. Verifikasi Pembayaran (Payment Verification)

**URL:** `/admin/pendaftar?menu=pembayaran`  
**Controller Method:** `handleVerifikasiPembayaran()` (lines 187-220)  
**Permission:** Requires `can_approve_payments` feature gate

### Purpose
Review payment transactions (registration fee and capital contribution) for verification and approval.

### Table Structure

| Column | Source | Purpose |
|--------|--------|---------|
| No. | Counter | Row numbering |
| Kode Bayar | pembayaran.id_pembayaran | Payment transaction code |
| Nama Orang Tua | pembayaran.nama_penyetor | Payer name |
| Nama Anak | users.nama_anak (via JOIN) | Applicant name |
| Jenis Pembayaran | pembayaran.jenis_pembayaran | Pendaftaran \| Uang Pangkal |
| Nominal | pembayaran.nominal | Payment amount (formatted currency) |
| Bukti Transfer | pembayaran.bukti_bayar | Link to proof file |
| Tanggal Bayar | pembayaran.tgl_pembayaran | Payment date (d M Y) |
| Status | pembayaran.status | Menunggu \| Disetujui \| Ditolak |
| Aksi | — | Download Bukti \| Setujui \| Detail |

### Status Filters

- **Jenis Pembayaran:** Pendaftaran \| Uang Pangkal
- **Status Verifikasi:** Pending \| Disetujui \| Ditolak

### Status Badges

- 🟡 **Menunggu** (Pending) - Yellow badge, yellow action button
- 🟢 **Disetujui** (Approved) - Green badge
- 🔴 **Ditolak** (Rejected) - Red badge

### Actions

- **Download Bukti:** Download payment proof file from `public/uploads/bukti_bayar/`
- **Setujui:** Approve payment (only visible for Pending status)
- **Detail:** View full transaction details in detail page

### Database Query

```php
$q = DB::table('pembayaran')
  ->leftJoin('users', 'pembayaran.id_user', '=', 'users.id_user')
  ->where('users.role', '=', 'pendaftar')
  ->select('pembayaran.*', 'users.nama_pendaftar', 'users.nama_anak', ...)
  ->orderBy('pembayaran.tgl_pembayaran', 'desc')
  ->paginate(20);
```

### Permission Logic

```php
// In layout.blade.php navigation
@can('approve_payments')
  <!-- Verifikasi Pembayaran menu visible only to authorized users -->
@endcan
```

---

## 4. Hasil Seleksi (Selection Results)

**URL:** `/admin/pendaftar?menu=seleksi`  
**Controller Method:** `handleHasilSeleksi()` (lines 222-250)

### Purpose
Display and manage final selection results for all applicants (accepted, rejected, waitlisted).

### Table Structure

| Column | Source | Purpose |
|--------|--------|---------|
| No. | Counter | Row numbering |
| Kode Pendaftar | users.id_user | Applicant code |
| Nama Orang Tua/Wali | users.nama_pendaftar | Parent/guardian name |
| Nama Anak | biodata_siswa.nama_anak | Applicant name |
| Jenis Kelamin | biodata_siswa.jenis_kelamin | Gender |
| Status Seleksi | users.status_seleksi | Selection outcome |
| Tanggal Penetapan | users.tgl_penetapan | Decision date (d M Y) |
| Aksi | — | Lihat Detail \| Ubah Status |

### Status Filters

- **Status Seleksi:** Semua Status \| Diterima \| Cadangan \| Tidak Diterima

### Status Badges

- 🟢 **✓ Diterima** (Accepted) - Green badge
- 🔴 **✗ Tidak Diterima** (Rejected) - Red badge
- 🟡 **⊙ Cadangan** (Waitlist/daftar_tunggu) - Yellow badge

### Actions

- **Lihat Detail:** View applicant profile and selection details
- **Ubah Status:** Change selection status (placeholder for future implementation)

### Database Query

```php
$q = DB::table('users')
  ->leftJoin('biodata_siswa', 'users.id_user', '=', 'biodata_siswa.id_user')
  ->where('users.role', '=', 'pendaftar')
  ->whereNotNull('users.status_seleksi')
  ->select('users.*', 'biodata_siswa.*')
  ->orderBy('users.tgl_penetapan', 'desc')
  ->paginate(20);
```

---

## Common Features Across All Views

### Search & Filter Pattern

All views implement consistent search + filter mechanism:

```html
<form method="GET">
  <input type="text" name="search" placeholder="...">
  <select name="filter_param">
    <option value="">Semua XXX</option>
    <option value="value" {{ request('filter_param')=='value'?'selected':'' }}>Label</option>
  </select>
  <button type="submit">Terapkan Filter</button>
  <a href="?menu=...">Reset</a>
</form>
```

### Pagination

- **Per Page:** 20 records
- **Query String Preservation:** Uses `->withQueryString()` to maintain filters across pages
- **Link Format:** Paginator links include menu parameter

### Data Export Consideration

Current implementation supports data in HTML table format. Future considerations:
- CSV export functionality
- PDF report generation
- Bulk action processing

---

## Implementation Details

### File Locations

```
app/Http/Controllers/
  └─ AdminController.php           (listPendaftar dispatcher + 4 handlers)

resources/views/admin/
  ├─ layout.blade.php              (Sidebar navigation with ?menu= links)
  ├─ pendaftar.blade.php           (Data Pendaftar view)
  ├─ verifikasi_berkas.blade.php   (Berkas verification view)
  ├─ verifikasi_pembayaran.blade.php (Payment verification view)
  └─ hasil_seleksi.blade.php       (Selection results view)
```

### Controller Signature

```php
// Dispatcher method
public function listPendaftar()
{
  $menu = request('menu');
  return match($menu) {
    'berkas' => $this->handleVerifikasiBerkas(),
    'pembayaran' => $this->handleVerifikasiPembayaran(),
    'seleksi' => $this->handleHasilSeleksi(),
    default => $this->handleDataPendaftar(),
  };
}

// Handler signature (same pattern for all 4)
private function handleDataPendaftar()
{
  $q = DB::table(...)->join(...)...;
  
  // Apply filters from request params
  if (request('search')) {
    $q->where(/* search conditions */);
  }
  
  $pendaftar = $q->paginate(20);
  return view('admin.pendaftar', compact('pendaftar'));
}
```

### View Structure

Each view follows this pattern:

```blade
@extends('admin.layout')
@section('title', 'View Title')
@section('content')

{{-- Filter section --}}
<div class="card">
  <form method="GET">
    {{-- Search input --}}
    {{-- Filter selects --}}
  </form>
</div>

{{-- Data table --}}
<div class="card">
  <table>
    <thead>...</thead>
    <tbody>
      @forelse($data as $row)
        <tr>{{-- columns --}}</tr>
      @empty
        <tr><td>No data</td></tr>
      @endforelse
    </tbody>
  </table>
</div>

@endsection
```

---

## Database Fields Required

### users table
- `id_user` - Primary key
- `nama_pendaftar` - Parent/guardian name
- `email` - Email address
- `role` - User role (must be 'pendaftar')
- `status_langkah` - Current registration step
- `status_seleksi` - Selection status (diterima/tidak_diterima/daftar_tunggu)
- `tgl_penetapan` - Selection decision date
- `created_at` - Registration timestamp

### biodata_siswa table
- `id_user` - Foreign key to users
- `nama_anak` - Applicant name
- `nik` - NISN (National Student ID)
- `jenis_kelamin` - Gender (L/P)
- `tgl_lahir_panjang` - Birth place and date
- `no_hp` - Parent phone number
- `nama_sekolah_asal` - Previous school
- `berkas` - Uploaded documents JSON or path
- `status_berkas` - Document verification status
- `catatan_berkas` - Verification notes
- `tgl_verifikasi_berkas` - Verification timestamp

### pembayaran table
- `id_pembayaran` - Primary key
- `id_user` - Foreign key to users
- `jenis_pembayaran` - Type (Pendaftaran/Uang Pangkal)
- `nominal` - Amount
- `nama_penyetor` - Payer name
- `bukti_bayar` - Proof file path
- `tgl_pembayaran` - Payment date
- `status` - Status (pending/disetujui/ditolak)

---

## Future Enhancements

### Phase 2 - Action Handlers
- [ ] Edit Data action - allows parent/guardian to update registration data
- [ ] Cetak Formulir (Print Form) - generate PDF registration form
- [ ] Ubah Status Seleksi - dialog to change selection status with reason logging
- [ ] Tolak Berkas - reject documents with required reason capture

### Phase 3 - Bulk Operations
- [ ] Bulk approve payments
- [ ] Bulk update selection status
- [ ] Bulk export to Excel/CSV
- [ ] Bulk send notifications

### Phase 4 - Advanced Features
- [ ] Real-time filtering without page reload
- [ ] Export filtered data to various formats
- [ ] Advanced search with date range filters
- [ ] Audit log for all admin actions

---

## Testing Checklist

- [x] AdminController syntax validation
- [x] All view files syntax validation
- [x] Database query structure validation
- [ ] Browser testing - Data Pendaftar view displays correctly
- [ ] Browser testing - Verifikasi Berkas filters work
- [ ] Browser testing - Verifikasi Pembayaran pagination works
- [ ] Browser testing - Hasil Seleksi search functionality works
- [ ] Permission testing - can_approve_payments gate functions
- [ ] Data accuracy - all columns display correct values

---

## Deployment Notes

1. **Database Migration:** No new migration needed - uses existing tables
2. **Permissions:** Ensure `can_approve_payments` feature is properly seeded for authorized admins
3. **File Permissions:** Verify `public/uploads/` directories are readable by web server
4. **Caching:** Clear route cache after deployment: `php artisan route:cache`
5. **Session:** No session structure changes required

---

**Last Updated:** June 16, 2024  
**Version:** 1.0 - Initial Implementation
