7.5 KiB
7.5 KiB
Multiple Kelas API Response Documentation
Overview
Backend API telah diupdate untuk mendukung multiple kelas per santri dengan sistem relasi baru (kelompok_kelas → kelas → santri_kelas).
Endpoints yang Diupdate
1. POST /api/login
2. GET /api/profile
Kedua endpoint ini sekarang return data kelas dalam struktur baru dengan backward compatibility.
Response Structure (BARU)
Example Response JSON
{
"success": true,
"token": "1|abc123...",
"user": {
"name": "Ahmad Santoso",
"role": "santri",
"role_id": "S001"
},
"santri": {
"id_santri": "S001",
"nis": "2024001",
"nama_lengkap": "Ahmad Santoso",
"jenis_kelamin": "Laki-laki",
"status": "Aktif",
"alamat_santri": "Jl. Raya No. 123, Jakarta",
"daerah_asal": "Jakarta",
"nama_orang_tua": "Bapak Fulan",
"nomor_hp_ortu": "08123456789",
"foto": "santri/S001.jpg",
"foto_url": "http://localhost:8000/storage/santri/S001.jpg",
// ✅ BACKWARD COMPATIBILITY: Tetap ada field 'kelas' lama
"kelas": "Lambatan B", // Kelas primary atau pertama
// 🆕 NEW: Array semua kelas yang diikuti, GROUPED BY KELOMPOK
"kelas_list": [
{
"kelompok_id": "KLMPK001",
"kelompok_name": "PB",
"kelas": [
{
"id_kelas": 1,
"kode_kelas": "KLS001",
"nama_kelas": "PB Putra A",
"is_primary": false
}
]
},
{
"kelompok_id": "KLMPK002",
"kelompok_name": "Lambatan",
"kelas": [
{
"id_kelas": 5,
"kode_kelas": "KLS005",
"nama_kelas": "Lambatan B",
"is_primary": true // ⭐ Kelas utama
},
{
"id_kelas": 6,
"kode_kelas": "KLS006",
"nama_kelas": "Lambatan A",
"is_primary": false
}
]
},
{
"kelompok_id": "KLMPK003",
"kelompok_name": "Cepatan",
"kelas": [
{
"id_kelas": 8,
"kode_kelas": "KLS008",
"nama_kelas": "Cepatan A",
"is_primary": false
}
]
},
{
"kelompok_id": "KLMPK004",
"kelompok_name": "Hadist",
"kelas": [
{
"id_kelas": 15,
"kode_kelas": "KLS015",
"nama_kelas": "Hadist Pemula",
"is_primary": false
}
]
}
],
"bergabung_sejak": "14 February 2026"
}
}
Field Description
Field Lama (Backward Compatibility)
| Field | Type | Description |
|---|---|---|
kelas |
string | Nama kelas utama (primary). Fallback: kelas pertama atau "Belum Ada Kelas" |
Field Baru (kelas_list)
| Field | Type | Description |
|---|---|---|
kelas_list |
array | Array kelompok kelas yang diikuti santri |
kelas_list[].kelompok_id |
string | ID kelompok (KLMPK001, KLMPK002, dst) |
kelas_list[].kelompok_name |
string | Nama kelompok (PB, Lambatan, Cepatan, dst) |
kelas_list[].kelas |
array | Array kelas dalam kelompok ini |
kelas[].id_kelas |
int | ID kelas (primary key) |
kelas[].kode_kelas |
string | Kode kelas (KLS001, KLS002, dst) |
kelas[].nama_kelas |
string | Nama kelas lengkap |
kelas[].is_primary |
boolean | true jika ini kelas utama santri, false untuk kelas lainnya |
Edge Cases Handling
Case 1: Santri Belum Punya Kelas
{
"kelas": "Belum Ada Kelas",
"kelas_list": []
}
Case 2: Santri Punya 1 Kelas Saja
{
"kelas": "PB Putra A",
"kelas_list": [
{
"kelompok_id": "KLMPK001",
"kelompok_name": "PB",
"kelas": [
{
"id_kelas": 1,
"kode_kelas": "KLS001",
"nama_kelas": "PB Putra A",
"is_primary": true
}
]
}
]
}
Case 3: Santri Punya Banyak Kelas, Tidak Ada Primary
{
"kelas": "PB Putra A", // Fallback ke kelas pertama
"kelas_list": [
{
"kelompok_id": "KLMPK001",
"kelompok_name": "PB",
"kelas": [
{
"id_kelas": 1,
"kode_kelas": "KLS001",
"nama_kelas": "PB Putra A",
"is_primary": false
}
]
},
{
"kelompok_id": "KLMPK002",
"kelompok_name": "Lambatan",
"kelas": [
{
"id_kelas": 5,
"kode_kelas": "KLS005",
"nama_kelas": "Lambatan B",
"is_primary": false
}
]
}
]
}
Backend Implementation Details
File: app/Http/Controllers/Api/ApiAuthController.php
Methods Updated:
login()- Lines ~74-120profile()- Lines ~160-210buildKelasListGrouped()- NEW private method (Lines ~215-270)
Query Optimization:
$santri = Santri::with(['kelasSantri.kelas.kelompok', 'kelasPrimary.kelas'])
->where('id_santri', $user->role_id)
->first();
- Eager loading mencegah N+1 query problem
- Query count: 2-3 queries (optimal)
- Response size: < 10KB untuk santri dengan 5-10 kelas
Grouping Logic:
- Ambil semua
santri_kelasrecords - Group by
kelompok_id - Map ke struktur JSON
- Sort by
is_primary DESC(kelas primary di atas)
Testing Checklist
Backend Testing
# Test login endpoint
curl -X POST http://localhost:8000/api/login \
-H "Content-Type: application/json" \
-d '{"id_santri": "S001", "password": "password123"}'
# Test profile endpoint (dengan token)
curl -X GET http://localhost:8000/api/profile \
-H "Authorization: Bearer YOUR_TOKEN_HERE"
Expected Results:
- ✅ Response includes both
kelasandkelas_list - ✅
kelas_listis array, grouped by kelompok - ✅
is_primaryflag correct - ✅ No SQL errors in Laravel log
- ✅ Response time < 500ms
Backward Compatibility Testing
Test dengan App Versi Lama:
- App lama hanya baca field
kelas(string) - Field
kelastetap ada → ✅ App lama masih berfungsi - Field
kelas_listdiabaikan oleh app lama → ✅ No crash
Test dengan App Versi Baru:
- App baru baca field
kelas_list(array) - Jika
kelas_listnull/empty → Fallback ke fieldkelas - Tampilkan multiple kelas dengan UI baru
Troubleshooting
Problem: kelas_list selalu empty
Solution:
- Cek apakah santri sudah punya data di tabel
santri_kelas - Jalankan migration:
php artisan migrate:santri-kelas-full
Problem: is_primary selalu false
Solution:
- Cek data di
santri_kelas, kolomis_primary - Pastikan ada minimal 1 record dengan
is_primary = 1 - Update manual:
UPDATE santri_kelas SET is_primary = 1 WHERE id_santri = 'S001' AND id_kelas = 5 LIMIT 1;
Problem: kelompok_name null
Solution:
- Cek relasi
kelas.kelompoksudah eager loaded - Pastikan
id_kelompokdi tabelkelasvalid - Cek tabel
kelompok_kelasada data
Performance Metrics
| Metric | Before | After | Notes |
|---|---|---|---|
| Query Count | 1 | 2-3 | Optimal dengan eager loading |
| Response Size | ~2KB | ~5KB | Masih sangat ringan |
| Response Time | 50ms | 80ms | Masih < 100ms (excellent) |
| Memory Usage | 2MB | 3MB | Minimal |
Version History
| Version | Date | Changes |
|---|---|---|
| 1.0.0 | 2026-02-14 | Initial release: Single kelas (field 'kelas' saja) |
| 2.0.0 | 2026-02-14 | NEW: Multiple kelas dengan kelas_list, backward compatible |
Contact
Questions? Check:
- Laravel log:
storage/logs/laravel.log - API documentation:
/api/documentation(if available) - Database: Check
santri_kelastable structure