13 KiB
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
classeskosong → 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
classesvia 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/classesmengembalikan 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, filterdashboard_admin_page. - Controller: ✅ Ada — method
students()me-render viewdashboard/students. - View: ✅ Ada —
app/Views/dashboard/students.php(tabel, filter, paginasi, modal tambah/edit/hapus). - Query/relasi: ✅ API GET
/api/academic/studentsjalan; join keclassesuntuk class_label;class_idboleh NULL (tidak gagal).
Kenapa bisa “belum tampil”?
Kemungkinan:
- Bukan ADMIN — halaman dan menu Students hanya untuk role ADMIN. Jika login bukan ADMIN, menu Academic (termasuk Students) tidak muncul.
- URL salah — harus akses tepat:
/dashboard/academic/students(mis.http://localhost/sman1/backend/public/dashboard/academic/students). - Session/redirect — jika belum login atau filter redirect, akan ke halaman login/dashboard.
- 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:
- ADMIN buka Academic → Classes (atau lewat Academic → Settings → kartu Classes).
- Klik Tambah Kelas → isi Tingkat, Jurusan, Rombel, (opsional) Wali Kelas → Simpan.
- 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”)
-
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 isidapodik_rombel_mappings(dapodik_rombel → class_id) agar siswa sync bisa map ke kelas yang sama. - Aturan: satu
dapodik_rombel= satuclass_id; kelas bisa dibuat otomatis dari nama rombel Dapodik (mis. "10 IPA 1" → grade=10, major=IPA, name=1).
-
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.
- Sync rombel/kelas dulu (baca Dapodik → insert/update
-
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) diclassessupaya 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.