# List Page — Sistem Absensi Digital SMA

> **Versi:** 1.0.0 · **Tanggal:** April 2026  
> **Stack:** Laravel 13.x · Blade · Tailwind CSS · Flowbite Admin Dashboard (Free) · Alpine.js

---

## Daftar Isi

1. [Halaman Umum (Auth)](#1-halaman-umum-auth)
2. [Panel Super Admin](#2-panel-super-admin)
3. [Panel Operator](#3-panel-operator)
4. [Panel Guru (Teacher)](#4-panel-guru-teacher)
5. [Panel Siswa (Student)](#5-panel-siswa-student)
6. [Halaman Kiosk (Scanner)](#6-halaman-kiosk-scanner)
7. [Rekomendasi Urutan Pengerjaan](#7-rekomendasi-urutan-pengerjaan)

---

## 1. Halaman Umum (Auth)

| # | Nama Halaman | Route (Name / URL) | Role Akses | Konten Halaman | Interaktivitas Alpine.js | Data / Field Database |
|---|---|---|---|---|---|---|
| 1.1 | **Login** | `GET /login` · `login` | Guest | • Logo & nama sekolah (dari `SETTINGS`) • Form: email, password, remember me • Tombol "Masuk" • Pesan error validasi | • `x-data="{ loading: false }"` disable tombol saat submit • Show/hide password toggle | `USERS.email`, `USERS.password`, `USERS.is_active`, `USERS.role` |
| 1.2 | **Profil & Ubah Password** | `GET /profile` · `profile.edit` | All authenticated | • Card info profil: nama, email, role • Form ubah nama & email • Form ubah password: lama, baru, konfirmasi • Tombol simpan per section | • Tab toggle "Info Profil" / "Ubah Password" via `x-data="{ tab: 'info' }"` • Validasi realtime password match | `USERS.name`, `USERS.email`, `USERS.password`, `TEACHERS.*` / `STUDENTS.*` |

---

## 2. Panel Super Admin

### 2.1 Dashboard & Master Data

| # | Nama Halaman | Route | Role | Konten Halaman | Alpine.js | Data DB |
|---|---|---|---|---|---|---|
| 2.1.1 | **Dashboard** | `GET /admin/dashboard` · `admin.dashboard` | `super_admin` | • Stat cards: guru aktif, siswa aktif, total kelas, kehadiran hari ini (%) • Grafik kehadiran 7 hari (Chart.js) • Tabel 5 alert terbaru • Quick links | • Filter periode chart `x-data="{ period: '7d' }"` | `TEACHERS`, `STUDENTS`, `CLASSROOMS`, `*_DAILY_ATTENDANCES`, `notifications` |
| 2.1.2 | **Manajemen User** | `GET /admin/users` · `admin.users.index` | `super_admin` | • Filter: role, status, search nama/email • Tabel: nama, email, role (badge), status (badge), created_at, aksi • Tombol "Tambah Pengguna" • Pagination | • Modal create/edit `x-data="{ showModal, modalMode }"` • Role-based fields: `x-show="role==='teacher'"` • Konfirmasi toggle status | `USERS.*`, `TEACHERS.employee_number, full_name`, `STUDENTS.student_number, full_name, classroom_id` |
| 2.1.3 | **Data Guru** | `GET /admin/teachers` · `admin.teachers.index` | `super_admin` | • Filter: search nama/NIP, status, gender • Tabel: foto, NIP, nama, gender, status QR, aktif, aksi • Aksi: edit, toggle aktif, regenerate QR, download QR | • Modal form + upload foto preview `URL.createObjectURL()` • Modal konfirmasi regenerate QR | `TEACHERS.*`, `USERS.email, is_active`, `TEACHER_QR_TOKENS.*` |
| 2.1.4 | **Data Siswa** | `GET /admin/students` · `admin.students.index` | `super_admin` | • Filter: search nama/NIS, kelas, tingkat, status, gender • Tabel: foto, NIS, nama, kelas, gender, status QR, aktif, aksi • Aksi: edit, toggle aktif, regenerate QR, download QR | • Filter cascading tingkat→kelas • Modal form + foto preview • Modal regenerate QR | `STUDENTS.*`, `USERS.*`, `CLASSROOMS.*`, `STUDENT_QR_TOKENS.*` |
| 2.1.5 | **Data Kelas** | `GET /admin/classrooms` · `admin.classrooms.index` | `super_admin` | • Filter: tingkat, status • Tabel: nama, tingkat (badge), wali kelas, jml siswa, status, aksi • Aksi: edit, toggle aktif | • Modal form create/edit • Dropdown wali kelas searchable | `CLASSROOMS.*`, `TEACHERS.full_name`, `STUDENTS.count` |
| 2.1.6 | **Data Mapel** | `GET /admin/subjects` · `admin.subjects.index` | `super_admin` | • Filter: search, status • Tabel: kode, nama, status, aksi | • Modal form inline | `SUBJECTS.*` |

### 2.2 Akademik

| # | Nama Halaman | Route | Role | Konten Halaman | Alpine.js | Data DB |
|---|---|---|---|---|---|---|
| 2.2.1 | **Tahun Ajaran** | `GET /admin/academic-years` · `admin.academic-years.index` | `super_admin` | • Tabel: nama TA, tanggal, semester 1 status, semester 2 status, aksi • Tombol "Tambah TA" • Aksi: edit, kelola semester, aktivasi | • Modal create/edit • Konfirmasi aktivasi semester (warning menonaktifkan yang lain) | `ACADEMIC_YEARS.*`, `SEMESTERS.*` |
| 2.2.2 | **Jadwal Pelajaran** | `GET /admin/schedules` · `admin.schedules.index` | `super_admin` | • Filter: semester, kelas, hari, guru • Grid view: kolom=hari, baris=sesi, cell=mapel+guru • Tombol "Tambah Jadwal" • Warning konflik | • Tab view per kelas/per guru `x-data="{ view: 'per_kelas' }"` • Modal form dropdown cascading • Alert konflik jadwal | `SCHEDULES.*`, `SEMESTERS.*`, `SUBJECTS.*`, `CLASSROOMS.*`, `TEACHERS.*` |
| 2.2.3 | **Kenaikan Kelas** | `GET /admin/promotions` · `admin.promotions.index` | `super_admin` | • Info TA & status semester 2 • Tabel siswa: NIS, nama, kelas, tingkat, dropdown keputusan, dropdown kelas tujuan • Filter: kelas, tingkat • Tombol "Proses" • **Hanya aktif jika Sem 2 ditutup** | • `x-show="decision !== 'lulus'"` untuk kelas tujuan • Konfirmasi ganda: ketik nama TA `x-data="{ confirmText: '' }"` • Disabled state jika Sem 2 aktif | `STUDENTS.*`, `CLASSROOMS.*`, `ACADEMIC_YEARS.*`, `SEMESTERS.*` |

### 2.3 Absensi & Monitoring

| # | Nama Halaman | Route | Role | Konten Halaman | Alpine.js | Data DB |
|---|---|---|---|---|---|---|
| 2.3.1 | **Absensi Harian Guru** | `GET /admin/teacher-daily-attendances` | `super_admin`, `operator` | • Filter: tanggal (default hari ini), status, search guru • Cards ringkasan: hadir, terlambat, absen, izin, sakit • Tabel: nama, NIP, check-in, check-out, status, auto/manual, notes, aksi • Aksi: koreksi | • Date picker auto-submit • Modal koreksi: dropdown status, textarea catatan | `TEACHER_DAILY_ATTENDANCES.*`, `TEACHERS.*` |
| 2.3.2 | **Absensi Harian Siswa** | `GET /admin/student-daily-attendances` | `super_admin`, `operator` | • Filter: tanggal, kelas, tingkat, status, search • Cards ringkasan per kelas • Tabel: nama, NIS, kelas, check-in/out, status, aksi | • Filter cascading tingkat→kelas • Modal koreksi • Bulk koreksi | `STUDENT_DAILY_ATTENDANCES.*`, `STUDENTS.*`, `CLASSROOMS.*` |
| 2.3.3 | **Absensi Mengajar** | `GET /admin/teaching-attendances` | `super_admin`, `operator` | • Filter: tanggal, guru, kelas, semester • Tabel: tanggal, guru, mapel, kelas, sesi, status, submitted_by, aksi • Aksi: koreksi, assign pengganti | • Modal koreksi • Modal assign guru pengganti | `TEACHING_ATTENDANCES.*`, `SCHEDULES.*`, `SUBJECTS.*`, `CLASSROOMS.*`, `TEACHERS.*` |
| 2.3.4 | **Absensi Mapel Siswa** | `GET /admin/student-subject-attendances` | `super_admin`, `operator` | • Filter: tanggal, kelas, mapel, semester • Tabel: tanggal, siswa, kelas, mapel, guru, status, aksi | • Filter cascading • Modal koreksi | `STUDENT_SUBJECT_ATTENDANCES.*`, `STUDENTS.*`, `SUBJECTS.*`, `CLASSROOMS.*`, `TEACHERS.*` |

### 2.4 Perizinan & Kalender

| # | Nama Halaman | Route | Role | Konten Halaman | Alpine.js | Data DB |
|---|---|---|---|---|---|---|
| 2.4.1 | **Izin Guru** | `GET /admin/teacher-leaves` | `super_admin`, `operator` | • Tab: Pending, Approved, Rejected, Semua • Tabel: guru, tanggal, alasan, lampiran, status, reviewer, aksi • Tombol "Input Manual" • Aksi: approve, reject | • Tab `x-data="{ activeTab: 'pending' }"` • Modal approve (textarea notes) • Modal reject (textarea wajib) • Modal input manual | `TEACHER_LEAVE_REQUESTS.*`, `TEACHERS.*`, `USERS.name` |
| 2.4.2 | **Izin Siswa** | `GET /admin/student-leaves` | `super_admin`, `operator` | • Sama + filter kelas | • Sama | `STUDENT_LEAVE_REQUESTS.*`, `STUDENTS.*`, `CLASSROOMS.*` |
| 2.4.3 | **Kalender Libur** | `GET /admin/holidays` | `super_admin` | • View kalender + tabel list • Tabel: tanggal, deskripsi, tipe, scope, absensi aktif, kelas terkait, aksi • Tombol "Tambah" | • Toggle view `x-data="{ view: 'calendar' }"` • Modal form: scope toggle → show checkbox kelas jika `per_class` | `HOLIDAYS.*`, `CLASSROOM_HOLIDAYS.*`, `CLASSROOMS.*` |

### 2.5 QR, Kiosk & Pengganti

| # | Nama Halaman | Route | Role | Konten Halaman | Alpine.js | Data DB |
|---|---|---|---|---|---|---|
| 2.5.1 | **Kiosk Token** | `GET /admin/kiosk-tokens` | `super_admin` | • Tabel: nama kiosk, device ID, token (masked), status, expires_at, created_by, aksi • Tombol "Buat Token" • Aksi: copy, toggle aktif | • Modal create • Show token sekali `x-data="{ newToken, showToken }"` → copy clipboard | `KIOSK_TOKENS.*`, `USERS.name` |
| 2.5.2 | **Guru Pengganti** | `GET /admin/substitutes` | `super_admin`, `operator` | • Filter: tanggal, guru asli, kelas • Tabel: tanggal, guru asli, pengganti, mapel, kelas, sesi, ditunjuk oleh, aksi • Tombol "Tetapkan" • Aksi: batalkan | • Modal form: pilih tanggal → load jadwal → pilih guru pengganti | `SUBSTITUTE_TEACHERS.*`, `SCHEDULES.*`, `TEACHERS.*`, `SUBJECTS.*`, `CLASSROOMS.*` |

### 2.6 Laporan, Settings & Notifikasi

| # | Nama Halaman | Route | Role | Konten Halaman | Alpine.js | Data DB |
|---|---|---|---|---|---|---|
| 2.6.1 | **Lap. Absensi Harian Guru** | `GET /admin/reports/teacher-daily` | `super_admin`, `operator` | • Filter: date range, guru • Tabel rekap: guru, hadir, terlambat, absen, izin, sakit, % • Ekspor PDF/Excel • Grafik ringkasan | • Date range picker • Loading state saat generate | `TEACHER_DAILY_ATTENDANCES.*`, `TEACHERS.*` |
| 2.6.2 | **Lap. Absensi Harian Siswa** | `GET /admin/reports/student-daily` | `super_admin`, `operator` | • Filter: date range, kelas, tingkat • Tabel rekap per siswa • Ekspor PDF/Excel | • Cascading filter | `STUDENT_DAILY_ATTENDANCES.*`, `STUDENTS.*`, `CLASSROOMS.*` |
| 2.6.3 | **Lap. Absensi Mengajar** | `GET /admin/reports/teaching` | `super_admin`, `operator` | • Filter: semester, guru • Tabel: guru, total sesi, mengajar, tidak, % • Ekspor | • Semester filter default aktif | `TEACHING_ATTENDANCES.*`, `SCHEDULES.*`, `TEACHERS.*` |
| 2.6.4 | **Lap. Absensi Mapel Siswa** | `GET /admin/reports/student-subject` | `super_admin`, `operator` | • Filter: semester, kelas, mapel • Tabel: siswa, mapel, sesi, hadir, absen, % • Ekspor | • Cascading filter | `STUDENT_SUBJECT_ATTENDANCES.*`, `STUDENTS.*`, `SUBJECTS.*` |
| 2.6.5 | **Konfigurasi Sistem** | `GET /admin/settings` | `super_admin` | • Group: Absensi, Alert, Sistem • Input per tipe: text, number, toggle, JSON • Simpan per group • Upload logo sekolah | • Group tabs `x-data="{ activeGroup }"` • Dynamic input `x-show="type==='boolean'"` → toggle • Dirty check `x-data="{ isDirty }"` | `SETTINGS.*` |
| 2.6.6 | **Notifikasi** | `GET /admin/notifications` | `super_admin`, `operator` | • Tab: Belum Dibaca, Semua • List: ikon, judul, pesan, waktu, badge • "Tandai Semua Dibaca" | • Tab filter • Mark read via AJAX • Badge count polling 30s | `notifications` |

---

## 3. Panel Operator

> Operator mengakses halaman shared dengan Super Admin di prefix `/admin/` (middleware `role:super_admin,operator`). Perbedaan: **sidebar menu lebih terbatas** — tidak akses master data CRUD, konfigurasi, tahun ajaran, kenaikan kelas, kiosk token.

**Halaman yang diakses:** Dashboard (2.1.1 versi operator), Absensi Harian Guru/Siswa (2.3.1–2.3.2), Absensi Mengajar (2.3.3), Absensi Mapel (2.3.4), Izin Guru/Siswa (2.4.1–2.4.2), Guru Pengganti (2.5.2), Semua Laporan (2.6.1–2.6.4), Notifikasi (2.6.6), Regenerate QR (via tombol di halaman guru/siswa read-only).

---

## 4. Panel Guru (Teacher)

| # | Nama Halaman | Route | Role | Konten Halaman | Alpine.js | Data DB |
|---|---|---|---|---|---|---|
| 4.1 | **Dashboard** | `GET /teacher/dashboard` | `teacher` | • Card profil: foto, nama, NIP • Stat bulan ini: hadir, terlambat, absen • Jadwal hari ini + status sesi • Notifikasi terbaru | — | `TEACHERS.*`, `SCHEDULES.*`, `TEACHING_ATTENDANCES.*`, `TEACHER_DAILY_ATTENDANCES.*` |
| 4.2 | **Jadwal Hari Ini** | `GET /teacher/schedules/today` | `teacher` | • List card sesi: waktu, mapel, kelas, status • Tombol "Mulai Sesi" / "Selesai" / "Input Absensi" • Info guru pengganti | • Konfirmasi mulai/selesai sesi • Disabled jika bukan miliknya | `SCHEDULES.*`, `TEACHING_ATTENDANCES.*`, `SUBSTITUTE_TEACHERS.*`, `SUBJECTS.*`, `CLASSROOMS.*` |
| 4.3 | **Input Absensi Mapel** | `GET /teacher/teaching/{schedule}/attendance` | `teacher` | • Info sesi: mapel, kelas, waktu • Tabel siswa: foto, NIS, nama, radio status, notes • Default: hadir • Tombol "Simpan" | • Bulk set all `x-data="{ setAll(s) }"` • Counter realtime • Validasi semua siswa punya status | `STUDENTS.*`, `STUDENT_SUBJECT_ATTENDANCES.*`, `SCHEDULES.*`, `SUBJECTS.*` |
| 4.4 | **Jadwal Mingguan** | `GET /teacher/schedules` | `teacher` | • Grid: kolom=hari, baris=sesi, cell=mapel+kelas • Semester aktif | — (read-only) | `SCHEDULES.*`, `SUBJECTS.*`, `CLASSROOMS.*` |
| 4.5 | **Rekap Absensi Harian** | `GET /teacher/my-attendances` | `teacher` | • Filter: bulan/tahun • Ringkasan: hadir, terlambat, absen, izin, sakit • Tabel: tanggal, check-in/out, status, notes | • Month picker auto-filter | `TEACHER_DAILY_ATTENDANCES.*` |
| 4.6 | **Rekap Mengajar** | `GET /teacher/my-teaching` | `teacher` | • Filter: semester • Tabel: tanggal, mapel, kelas, sesi, status, notes • Ringkasan % | — | `TEACHING_ATTENDANCES.*`, `SCHEDULES.*`, `SUBJECTS.*` |
| 4.7 | **Pengajuan Izin** | `GET /teacher/leaves` | `teacher` | • List: tanggal, alasan, lampiran, status, notes reviewer • Tombol "Ajukan Izin" • Aksi: batalkan (jika pending) | • Modal form: date range, alasan, upload lampiran (max 2MB) • File validation client-side • Konfirmasi batal | `TEACHER_LEAVE_REQUESTS.*` |
| 4.8 | **Notifikasi** | `GET /teacher/notifications` | `teacher` | • List notifikasi + badge unread | • Mark read, polling | `notifications` |

---

## 5. Panel Siswa (Student)

| # | Nama Halaman | Route | Role | Konten Halaman | Alpine.js | Data DB |
|---|---|---|---|---|---|---|
| 5.1 | **Dashboard** | `GET /student/dashboard` | `student` | • Card profil: foto, nama, NIS, kelas • Stat bulan ini • Status hari ini • Jadwal hari ini • Notifikasi terbaru | — | `STUDENTS.*`, `CLASSROOMS.*`, `STUDENT_DAILY_ATTENDANCES.*`, `SCHEDULES.*` |
| 5.2 | **Rekap Absensi Harian** | `GET /student/my-attendances` | `student` | • Filter: bulan/tahun • Ringkasan + tabel: tanggal, check-in/out, status, notes | • Month picker | `STUDENT_DAILY_ATTENDANCES.*` |
| 5.3 | **Rekap Absensi Mapel** | `GET /student/my-subject-attendances` | `student` | • Filter: semester, mapel • Tabel grouped by mapel: total sesi, hadir, absen, % • Expand: detail per tanggal | • Accordion per mapel `x-data="{ expanded }"` | `STUDENT_SUBJECT_ATTENDANCES.*`, `SUBJECTS.*`, `SCHEDULES.*` |
| 5.4 | **Jadwal Pelajaran** | `GET /student/schedules` | `student` | • Grid: kolom=hari, baris=sesi, cell=mapel+guru+waktu | — (read-only) | `SCHEDULES.*`, `SUBJECTS.*`, `TEACHERS.*` |
| 5.5 | **Pengajuan Izin** | `GET /student/leaves` | `student` | • List: tanggal, alasan, status, reviewer notes • Tombol "Ajukan Izin" • Aksi: batalkan | • Modal form + upload lampiran • Konfirmasi batal | `STUDENT_LEAVE_REQUESTS.*` |
| 5.6 | **Notifikasi** | `GET /student/notifications` | `student` | • List + badge unread | • Mark read, polling | `notifications` |

---

## 6. Halaman Kiosk (Scanner)

| # | Nama Halaman | Route | Akses | Konten Halaman | Alpine.js / JS | Data DB |
|---|---|---|---|---|---|---|
| 6.1 | **Scanner QR** | `GET /kiosk/{token}` | Kiosk Token (no login) | • Header: nama sekolah, nama kiosk, jam realtime, tanggal • Area kamera (html5-qrcode viewfinder) • Status koneksi (hijau/merah) • Card feedback: ✅ Check-in berhasil (hijau) ✅ Check-out berhasil (biru) ⚠️ Double scan (kuning) ❌ QR tidak dikenal (merah) ❌ User nonaktif (merah) ℹ️ Hari libur (abu) ℹ️ Sudah lengkap (info) • Counter scan hari ini | • Auto-dismiss card 5 detik • Health check polling 10s → ubah indikator koneksi • Jam realtime `setInterval` 1s • html5-qrcode lifecycle di `x-init`/`destroy` • Fullscreen toggle • Sound feedback | `KIOSK_TOKENS.*`, `*_QR_TOKENS.*`, `TEACHERS.*`, `STUDENTS.*`, `*_DAILY_ATTENDANCES.*`, `HOLIDAYS.*` |

---

## 7. Rekomendasi Urutan Pengerjaan

### Minggu 1–2: Foundation & Auth
- **Hari 1–2:** Setup project (Laravel 13, Tailwind, Flowbite, Alpine.js). Layout master Blade. → Gunakan **Flowbite Sidebar** + **Navbar**. Buat `layouts/app.blade.php` + `layouts/guest.blade.php`
- **Hari 3–4:** Auth system (`AuthController`, `RoleMiddleware`, redirect per role). → Flowbite Login Form template
- **Hari 5–7:** Layout per panel (sidebar berbeda per role via `@role` directive). Dashboard placeholder.
- **Hari 8–10:** Reusable Blade components: `<x-data-table>`, `<x-modal>`, `<x-alert>`, `<x-badge>`, `<x-stat-card>`, `<x-filter-bar>`

### Minggu 3–4: Master Data CRUD
- Users (2.1.2) → Teachers (2.1.3) → Students (2.1.4) → Classrooms (2.1.5) → Subjects (2.1.6) → Settings (2.6.5)
- **Tips:** Bangun 1 CRUD tuntas dulu, lalu copy pattern. Gunakan `Route::resource()` + `FormRequest`.

### Minggu 5: Akademik
- Tahun Ajaran & Semester (2.2.1) → Jadwal Pelajaran (2.2.2)
- **Tips:** Buat `Semester::active()` scope. Validasi konflik jadwal di FormRequest.

### Minggu 6–7: QR & Scanner (Core)
- QR Token management → Kiosk Token (2.5.1) → Halaman Scanner (6.1) → Absensi Harian monitoring (2.3.1, 2.3.2)
- **Tips:** Buat `ScanProcessingService` dengan validation chain. `KioskAuthMiddleware`. Test menyeluruh.

### Minggu 8: Sesi Mengajar & Absensi Mapel
- Sesi mengajar guru (4.2) → Input absensi mapel (4.3) → Guru pengganti (2.5.2) → Monitoring admin (2.3.3, 2.3.4)

### Minggu 9: Perizinan
- Leave request guru (4.7) → siswa (5.5) → Approval flow admin (2.4.1, 2.4.2) → Input manual

### Minggu 10: Scheduler, Alert & Kalender
- Auto-absent commands → Auto not-teaching → Alert commands → Notifikasi (2.6.6, 4.8, 5.6) → Kalender libur (2.4.3)

### Minggu 11: Laporan & Portal Siswa
- 4 halaman laporan (2.6.1–2.6.4) → Export PDF (DomPDF) → Export Excel → Portal siswa (5.1–5.4)

### Minggu 12: Kenaikan Kelas & Polish
- Kenaikan kelas (2.2.3) → Operator panel differentiation → Dashboard charts → QA & bug fix

---

### Blade Layout Structure

```
resources/views/
├── layouts/
│   ├── app.blade.php           {{-- @yield('content'), @include sidebar --}}
│   ├── guest.blade.php         {{-- Login --}}
│   └── kiosk.blade.php         {{-- Tanpa sidebar --}}
├── partials/
│   ├── sidebar-admin.blade.php
│   ├── sidebar-operator.blade.php
│   ├── sidebar-teacher.blade.php
│   └── sidebar-student.blade.php
├── components/
│   ├── data-table.blade.php    {{-- Reusable table + pagination --}}
│   ├── modal.blade.php         {{-- Alpine.js modal --}}
│   ├── confirm-dialog.blade.php
│   ├── stat-card.blade.php
│   ├── badge.blade.php
│   ├── alert.blade.php
│   ├── filter-bar.blade.php
│   └── photo-upload.blade.php
├── admin/ → teacher/ → student/ → kiosk/
```

### Flowbite Components Paling Dipakai
**Sidebar** (navigasi), **Navbar** (top bar + notif bell), **Tables**, **Modals**, **Badges** (status), **Cards** (dashboard), **Alerts**, **Pagination**, **Forms**, **Tabs**, **Breadcrumbs**, **Datepicker**, **Charts** (ApexCharts)

### Alpine.js Pattern Utama
```js
// Modal CRUD
x-data="{ showModal: false, modalMode: 'create', formData: {} }"
// Konfirmasi Hapus
x-data="{ showConfirm: false, deleteUrl: '' }"
// Filter Toggle
x-data="{ showFilter: false }"
// Tab Navigation
x-data="{ activeTab: 'all' }"
// File Preview
x-data="{ previewUrl: null, handleFile(e) { this.previewUrl = URL.createObjectURL(e.target.files[0]) } }"
```

---

> **Total halaman unik: ±35 halaman.** Dengan reusable Blade components yang solid, banyak halaman bisa di-scaffold cepat setelah pattern pertama terbentuk.
