feat: API wali murid (Sanctum) + verifikasi admin

- Pasang laravel/sanctum, routes/api.php (prefix api/v1, 10 endpoint)
- Migrasi: parent_name di students, parent_students (pivot wali↔anak),
  parent_devices (token FCM), permission parents-verify
- Auth wali: registrasi NISN+HP (auto-verify jika HP cocok data siswa,
  pending jika tidak) + login token Sanctum
- Endpoint: me, logout, students, link anak, violations, sp-letters,
  notifications, register device
- Halaman admin Verifikasi Wali (approve/reject) + menu sidebar
- Sync kesiswaan: tarik data orang tua (student_parents) ke students
- 8 feature test baru (ParentApiTest) — total suite 39 test hijau
This commit is contained in:
Novy San87
2026-08-05 18:58:29 +07:00
parent b06419624b
commit 3efce0f919
24 changed files with 1437 additions and 4 deletions
+23 -2
View File
@@ -5,12 +5,13 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasFactory, Notifiable;
use HasApiTokens, HasFactory, Notifiable;
public const ROLES = ['admin', 'bk', 'wali_kelas', 'staff', 'other', 'kepala_sekolah', 'waka_kesiswaan', 'ketua_tim'];
public const ROLES = ['admin', 'bk', 'wali_kelas', 'staff', 'other', 'kepala_sekolah', 'waka_kesiswaan', 'ketua_tim', 'parent'];
protected $fillable = [
'name', 'username', 'email', 'phone', 'password', 'role', 'roles', 'is_active', 'active_session_token',
@@ -66,6 +67,7 @@ class User extends Authenticatable
public function isKepalaSekolah(): bool { return $this->hasRole('kepala_sekolah'); }
public function isWakaKesiswaan(): bool { return $this->hasRole('waka_kesiswaan'); }
public function isKetuaTim(): bool { return $this->hasRole('ketua_tim'); }
public function isParent(): bool { return $this->hasRole('parent'); }
/**
* Role dengan visibilitas data GLOBAL (semua kelas/siswa).
@@ -136,6 +138,25 @@ class User extends Authenticatable
return $this->hasMany(Violation::class, 'recorded_by');
}
/**
* Relasi akun wali murid → anak (pivot parent_students).
*/
public function parentStudents()
{
return $this->hasMany(\App\Models\ParentStudent::class, 'user_id');
}
/**
* Anak-anak (siswa) milik akun wali, hanya yang statusnya aktif.
*/
public function children()
{
return $this->belongsToMany(\App\Models\Student::class, 'parent_students', 'user_id', 'student_id')
->withPivot(['relation', 'status', 'verified_at'])
->withTimestamps()
->wherePivot('status', 'active');
}
public function appNotifications()
{
return $this->hasMany(AppNotification::class, 'user_id');