258 lines
13 KiB
Markdown
258 lines
13 KiB
Markdown
# Audit Kondisi Project SMAN 1 — Detail
|
|
|
|
**Tanggal:** 2026-02-23
|
|
|
|
---
|
|
|
|
## 1. Struktur Module
|
|
|
|
### Module yang sudah ada
|
|
|
|
| Module | Lokasi | Isi utama |
|
|
|--------|--------|-----------|
|
|
| **Academic** | `app/Modules/Academic/` | Classes, Students, Subjects, Teachers, Schedules, Lesson Slots, **DapodikSync** (controller + service + mapping model) |
|
|
| **Attendance** | `app/Modules/Attendance/` | AttendanceSession, Checkin, Report |
|
|
| **Auth** | `app/Modules/Auth/` | Login, User, Role, UserRole |
|
|
| **Dashboard** | `app/Modules/Dashboard/` | Dashboard, Schedule, Attendance, Realtime |
|
|
| **Devices** | `app/Modules/Devices/` | Device, Mobile, DeviceAuth |
|
|
| **Notification** | `app/Modules/Notification/` | Telegram, Parent, StudentParent |
|
|
| **Geo** | `app/Modules/Geo/` | Zone, GeoFence |
|
|
|
|
### Cek per modul yang Anda tanyakan
|
|
|
|
| Modul | Status | Keterangan |
|
|
|-------|--------|------------|
|
|
| **Classes** | ✅ Ada | Di dalam **Academic**: ClassModel, ClassEntity, ClassController (CRUD), route GET/POST/PUT/DELETE `/api/academic/classes`, halaman `/dashboard/academic/classes` |
|
|
| **Students** | ✅ Ada | Di dalam **Academic**: StudentModel, StudentEntity, StudentController (CRUD + paginasi), route GET/POST/PUT/DELETE `/api/academic/students`, halaman `/dashboard/academic/students` |
|
|
| **Attendance** | ✅ Ada | Module **Attendance** terpisah: AttendanceSessionModel, AttendanceCheckinService, AttendanceReportService, dll. Tabel: `attendance_sessions` (bukan `attendance_logs`) |
|
|
| **Schedule** | ✅ Ada | Di dalam **Academic**: ScheduleModel, ScheduleManagementController, ScheduleResolverService, lesson_slots. Tabel: `schedules`, `lesson_slots` |
|
|
| **DapodikSync** | ✅ Ada | Di dalam **Academic**: DapodikClient, DapodikSyncService, DapodikSyncController, DapodikRombelMappingModel. Route: POST sync/students, GET/PUT rombels. Halaman `/dashboard/academic/dapodik` |
|
|
|
|
**Kesimpulan:** Semua modul yang Anda sebut (Classes, Students, Attendance, Schedule, DapodikSync) **sudah ada**. Tidak ada modul terpisah bernama "Classes" atau "Students"; semuanya di bawah **Academic**.
|
|
|
|
---
|
|
|
|
## 2. Database
|
|
|
|
### Tabel yang ada (beserta struktur)
|
|
|
|
**Catatan:** Tidak ada tabel bernama `attendance_logs`. Yang dipakai: **`attendance_sessions`**.
|
|
|
|
### 2.1 Tabel `classes`
|
|
|
|
| Field | Type | Relasi |
|
|
|-------|------|--------|
|
|
| id | INT PK AUTO_INCREMENT | - |
|
|
| name | VARCHAR(100) | - (rombel, mis. A, B, C) |
|
|
| grade | VARCHAR(50) | - (tingkat, mis. 10, X) |
|
|
| major | VARCHAR(50) NOT NULL DEFAULT 'IPA' | - (jurusan) |
|
|
| wali_user_id | INT NULL | FK → users.id (SET NULL) |
|
|
| created_at | DATETIME NULL | - |
|
|
| updated_at | DATETIME NULL | - |
|
|
|
|
**Relasi keluar:** `students.class_id`, `schedules.class_id`, `dapodik_rombel_mappings.class_id` → classes.id
|
|
|
|
---
|
|
|
|
### 2.2 Tabel `students`
|
|
|
|
| Field | Type | Relasi |
|
|
|-------|------|--------|
|
|
| id | INT PK AUTO_INCREMENT | - |
|
|
| nisn | VARCHAR(50) NOT NULL UNIQUE | - |
|
|
| name | VARCHAR(255) | - |
|
|
| gender | VARCHAR(1) NULL | L/P |
|
|
| class_id | INT NULL | FK → classes.id (SET NULL) — **nullable untuk unmapped** |
|
|
| is_active | TINYINT(1) DEFAULT 1 | - |
|
|
| parent_link_code | VARCHAR | (dari migration lain) |
|
|
| created_at | DATETIME NULL | - |
|
|
| updated_at | DATETIME NULL | - |
|
|
|
|
**Relasi:** class_id → classes.id (boleh NULL untuk siswa belum di-map dari Dapodik).
|
|
|
|
---
|
|
|
|
### 2.3 Tabel `attendance_sessions` (bukan attendance_logs)
|
|
|
|
| Field | Type | Relasi |
|
|
|-------|------|--------|
|
|
| id | INT PK | - |
|
|
| student_id | INT | FK → students.id |
|
|
| schedule_id | INT NULL | FK → schedules.id |
|
|
| device_id | INT | FK → devices.id |
|
|
| attendance_date | DATE | (dari migration unik) |
|
|
| checkin_at | DATETIME | - |
|
|
| latitude, longitude, confidence | DECIMAL | - |
|
|
| status | ENUM(PRESENT, LATE, OUTSIDE_ZONE, NO_SCHEDULE, INVALID_DEVICE) | - |
|
|
| created_at, updated_at | DATETIME NULL | - |
|
|
|
|
**Relasi:** student_id → students, schedule_id → schedules, device_id → devices.
|
|
|
|
---
|
|
|
|
### 2.4 Tabel `schedules`
|
|
|
|
| Field | Type | Relasi |
|
|
|-------|------|--------|
|
|
| id | INT PK | - |
|
|
| class_id | INT | FK → classes.id |
|
|
| lesson_slot_id | INT NULL | FK → lesson_slots.id |
|
|
| subject_id | INT | FK → subjects.id |
|
|
| teacher_user_id | INT NULL | FK → users.id |
|
|
| teacher_name | VARCHAR(255) | - |
|
|
| day_of_week | TINYINT (1=Senin, 7=Minggu) | - |
|
|
| start_time, end_time | TIME | - |
|
|
| room | VARCHAR(100) NULL | - |
|
|
| is_active | TINYINT DEFAULT 1 | - |
|
|
| created_at, updated_at | DATETIME NULL | - |
|
|
|
|
**Unique:** (class_id, lesson_slot_id, day_of_week).
|
|
|
|
**Relasi:** class_id → classes, subject_id → subjects, teacher_user_id → users, lesson_slot_id → lesson_slots.
|
|
|
|
---
|
|
|
|
### 2.5 Tabel tambahan terkait
|
|
|
|
- **dapodik_rombel_mappings:** id, dapodik_rombel (UNIQUE), class_id (FK → classes, NULL), last_seen_at, created_at, updated_at.
|
|
- **lesson_slots:** id, slot_number, start_time, end_time, is_active.
|
|
- **subjects:** id, name, code (nullable).
|
|
|
|
---
|
|
|
|
## 3. Flow Master Data
|
|
|
|
### 3.1 Kelas: input manual atau belum?
|
|
|
|
- **Input kelas:** **manual** lewat halaman **Classes** (`/dashboard/academic/classes`), hanya untuk role ADMIN.
|
|
- Form: Tingkat (text), Jurusan (text), Rombel (text), Wali Kelas (dropdown user).
|
|
- Data disimpan ke tabel **classes** (name = rombel, grade, major, wali_user_id).
|
|
- **Jika belum pernah input:** tabel `classes` **kosong** → tidak ada pilihan kelas di mana pun (Schedule Builder, Students, dll.).
|
|
|
|
### 3.2 Schedule Builder mengambil data kelas dari mana?
|
|
|
|
- **Dari API:** `GET /api/academic/classes` (admin_only).
|
|
- Halaman Schedule Builder index (`/dashboard/academic/schedule-builder`) memanggil API ini lalu mengisi **dropdown "Kelas"** (option value = class id, text = nama/rombel).
|
|
- Data sumber: **tabel `classes`** via ClassController::index().
|
|
|
|
### 3.3 Kenapa dropdown kelas bisa kosong?
|
|
|
|
- **Penyebab:** Tabel **classes tidak punya data** (belum ada satu baris pun).
|
|
- **Alur:** Tidak ada kelas → API `/api/academic/classes` mengembalikan array kosong → dropdown hanya berisi "— Pilih kelas —" → Open Builder tidak bisa dipakai.
|
|
- **Solusi:** Login sebagai ADMIN → buka **Academic → Classes** → tambah minimal satu kelas (mis. Tingkat 10, Jurusan IPA, Rombel 1). Setelah itu dropdown di Schedule Builder akan terisi.
|
|
|
|
---
|
|
|
|
## 4. Dapodik Integration
|
|
|
|
| Aspek | Status | Keterangan |
|
|
|-------|--------|------------|
|
|
| **Controller Dapodik Sync** | ✅ Ada | `App\Modules\Academic\Controllers\DapodikSyncController` |
|
|
| **Endpoint API** | ✅ Ada | POST `/api/academic/dapodik/sync/students`, GET `/api/academic/dapodik/rombels`, PUT `/api/academic/dapodik/rombels/{id}` (semua admin_only) |
|
|
| **Rencana vs realisasi** | ✅ Sudah diimplementasi | DapodikClient (getSekolah, getPesertaDidik), DapodikSyncService (sync siswa + rombel mapping), halaman Dapodik di dashboard |
|
|
|
|
**Env yang dipakai:** DAPODIK_BASE_URL, DAPODIK_TOKEN, DAPODIK_NPSN (di .env).
|
|
|
|
---
|
|
|
|
## 5. Student Page
|
|
|
|
### Apakah halaman Student sudah tampil?
|
|
|
|
- **Route:** ✅ Ada — `GET /dashboard/academic/students` → `DashboardAcademicController::students`, filter `dashboard_admin_page`.
|
|
- **Controller:** ✅ Ada — method `students()` me-render view `dashboard/students`.
|
|
- **View:** ✅ Ada — `app/Views/dashboard/students.php` (tabel, filter, paginasi, modal tambah/edit/hapus).
|
|
- **Query/relasi:** ✅ API GET `/api/academic/students` jalan; join ke `classes` untuk class_label; `class_id` boleh NULL (tidak gagal).
|
|
|
|
### Kenapa bisa “belum tampil”?
|
|
|
|
Kemungkinan:
|
|
|
|
1. **Bukan ADMIN** — halaman dan menu Students hanya untuk role ADMIN. Jika login bukan ADMIN, menu Academic (termasuk Students) tidak muncul.
|
|
2. **URL salah** — harus akses tepat: `/dashboard/academic/students` (mis. `http://localhost/sman1/backend/public/dashboard/academic/students`).
|
|
3. **Session/redirect** — jika belum login atau filter redirect, akan ke halaman login/dashboard.
|
|
4. **Data kosong** — halaman tetap tampil; yang kosong hanya **tabel siswa** (belum ada data siswa). Bukan penyebab “halaman tidak tampil”.
|
|
|
|
**Kesimpulan:** Secara kode, route, controller, view, dan relasi **sudah ada dan konsisten**. Kalau “belum tampil”, paling mungkin karena **bukan user ADMIN** atau **salah URL/base URL**.
|
|
|
|
---
|
|
|
|
## 6. Problem Diagnosis
|
|
|
|
### “Schedule Builder meminta kelas, tapi tidak ada tempat input kelas”
|
|
|
|
- **Faktanya:** **Sudah ada tempat input kelas**, yaitu halaman **Classes** (`/dashboard/academic/classes`), hanya untuk ADMIN.
|
|
- **Alur yang benar:**
|
|
1. ADMIN buka **Academic → Classes** (atau lewat **Academic → Settings** → kartu Classes).
|
|
2. Klik **Tambah Kelas** → isi Tingkat, Jurusan, Rombel, (opsional) Wali Kelas → Simpan.
|
|
3. Setelah ada minimal 1 kelas, buka **Schedule Builder** → dropdown **Kelas** terisi → pilih kelas → Open Builder.
|
|
|
|
Jadi masalahnya bukan “tidak ada tempat input”, melainkan:
|
|
|
|
- **User belum pernah mengisi kelas** di halaman Classes, atau
|
|
- **Menu Classes tidak terlihat** (mis. karena tidak login sebagai ADMIN).
|
|
|
|
**Rekomendasi:** Di halaman Schedule Builder index bisa ditambah kalimat singkat: “Jika dropdown kosong, tambah dulu kelas di **Academic → Classes**.”
|
|
|
|
---
|
|
|
|
## 7. Ringkasan Kondisi Project
|
|
|
|
| Aspek | Status | Keterangan |
|
|
|-------|--------|------------|
|
|
| **Module Academic (Classes, Students, Subjects, Teachers, Schedules, Lesson Slots)** | ✅ Sudah jadi | CRUD API + halaman dashboard per entitas |
|
|
| **Module Attendance** | ✅ Sudah jadi | attendance_sessions, check-in, report |
|
|
| **Module Schedule (jadwal per kelas)** | ✅ Sudah jadi | Schedule Builder, bulk save, lesson_slots |
|
|
| **Module DapodikSync** | ✅ Sudah jadi | Sync siswa, mapping rombel → class, halaman Dapodik |
|
|
| **Tabel classes, students, schedules, attendance_sessions** | ✅ Sudah jadi | Struktur + relasi jelas (termasuk lesson_slots, subjects, dapodik_rombel_mappings) |
|
|
| **Input kelas manual** | ✅ Sudah jadi | Halaman Classes, form lengkap |
|
|
| **Schedule Builder pakai data kelas** | ✅ Sudah jadi | Dari GET /api/academic/classes |
|
|
| **Halaman Students** | ✅ Sudah jadi | Route, controller, view, API, paginasi, filter |
|
|
| **Dropdown kelas kosong** | ⚠️ Setengah jadi | Fitur jalan; kosong karena **belum ada data kelas** di DB |
|
|
| **Dapodik sebagai sumber master kelas** | ⚠️ Setengah jadi | Saat ini Dapodik hanya **sync siswa** + mapping **rombel → class**. Kelas internal tetap **buat manual** di Classes; belum ada “sync rombel → buat kelas otomatis” |
|
|
|
|
---
|
|
|
|
## 8. Arsitektur saran: Dapodik sebagai sumber utama master data
|
|
|
|
Target alur: **DAPODIK → Sync → Classes → Students → Schedule → Attendance**.
|
|
|
|
### Kondisi saat ini
|
|
|
|
- **Classes:** input manual; tidak ada sync dari Dapodik.
|
|
- **Students:** bisa dari Dapodik (sync siswa + mapping rombel → class_id). class_id bisa NULL (unmapped).
|
|
- **Schedule & Attendance:** sudah mengandalkan classes + students.
|
|
|
|
### Opsi arsitektur
|
|
|
|
**Opsi A — Kelas tetap manual (minimal change)**
|
|
- Tetap: Classes diisi manual (grade + major + rombel).
|
|
- Dapodik: sync siswa + mapping **dapodik_rombel → class_id**.
|
|
- Sesuai jika: rombel Dapodik banyak dan Anda ingin satu rombel Dapodik = satu kelas internal yang sudah Anda buat manual.
|
|
|
|
**Opsi B — Sync rombel Dapodik → buat/update kelas (disarankan untuk “Dapodik sumber utama”)**
|
|
|
|
1. **Tambah sync kelas/rombel dari Dapodik**
|
|
- Endpoint Dapodik: daftar rombongan belajar (rombel) per sekolah.
|
|
- Logic: untuk setiap rombel Dapodik, **buat atau update** satu baris di `classes` (mis. parse nama rombel jadi grade + major + name/rombel), plus **tetap** isi `dapodik_rombel_mappings` (dapodik_rombel → class_id) agar siswa sync bisa map ke kelas yang sama.
|
|
- Aturan: satu `dapodik_rombel` = satu `class_id`; kelas bisa dibuat otomatis dari nama rombel Dapodik (mis. "10 IPA 1" → grade=10, major=IPA, name=1).
|
|
|
|
2. **Urutan sync disarankan**
|
|
- **Sync rombel/kelas dulu** (baca Dapodik → insert/update `classes` + `dapodik_rombel_mappings`).
|
|
- **Lalu sync siswa** (seperti sekarang); mapping rombel → class_id sudah terisi, sehingga siswa dapat class_id otomatis.
|
|
|
|
3. **Tetap boleh edit manual**
|
|
- Halaman **Classes** tetap dipakai untuk koreksi/naming (grade, major, rombel, wali).
|
|
- Setelah sync, admin bisa ubah nama/struktur kelas jika perlu.
|
|
|
|
**Opsi C — Hybrid (seperti B + flag sumber)**
|
|
- Tambah kolom mis. `source` (manual / dapodik) di `classes` supaya bisa bedakan kelas yang dari Dapodik vs yang buat manual.
|
|
|
|
### Rekomendasi singkat
|
|
|
|
- **Langkah 1:** Pastikan **ada data kelas** (manual) dulu agar Schedule Builder dan dropdown siswa tidak kosong.
|
|
- **Langkah 2:** Jika ingin Dapodik sebagai sumber utama kelas, tambah **sync rombel Dapodik → classes** (Opsi B); jadwalkan sync rombel dulu, baru sync siswa.
|
|
- **Langkah 3:** Tetap pakai **Dapodik Sync** yang sudah ada untuk siswa dan mapping rombel → class; setelah kelas bisa dari Dapodik, mapping itu akan mengisi class_id siswa tanpa perlu input kelas manual dulu.
|
|
|
|
Dengan ini, arsitektur bergerak ke: **DAPODIK → Sync (rombel + siswa) → Classes & Students terisi → Schedule (manual di builder) → Attendance**.
|