Absensi GPS
Arsitektur Sistem
Backend
Frontend
API
  • Struktur
  • Alur Kerja
  • Implementasi GPS
  • Pengembangan dan Pengujian
Deployment
Pengujian
Arsitektur Sistem
Backend
Frontend
API
  • Struktur
  • Alur Kerja
  • Implementasi GPS
  • Pengembangan dan Pengujian
Deployment
Pengujian
  • Backend (Laravel)

Backend (Laravel)

Pendahuluan

Backend aplikasi Absensi GPS dibangun menggunakan framework Laravel 12, yang menyediakan struktur yang kuat dan fitur-fitur modern untuk pengembangan aplikasi web. Backend bertanggung jawab untuk mengelola data, autentikasi pengguna, dan menyediakan API untuk frontend dan aplikasi mobile.

Struktur Proyek

app/
├── Http/
│   ├── Controllers/
│   │   ├── AbsensiController.php
│   │   ├── DashboardController.php
│   │   ├── KelasController.php
│   │   ├── LaporanController.php
│   │   ├── SiswaController.php
│   │   ├── UserController.php
│   │   └── Api/
│   │       ├── AbsensiMobileController.php
│   │       ├── AuthController.php
│   │       ├── ServerStatusController.php
│   │       └── SiswaController.php
│   ├── Middleware/
│   │   └── ValidateApiKey.php
│   └── Requests/
├── Models/
│   ├── Absensi.php
│   ├── Kelas.php
│   ├── Siswa.php
│   └── User.php
└── Providers/

Model

Model merepresentasikan struktur data dan logika bisnis aplikasi. Berikut adalah model utama dalam aplikasi:

User.php

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

    protected $fillable = [
        'name',
        'email',
        'password',
        'role',
    ];

    protected $hidden = [
        'password',
        'remember_token',
    ];

    protected $casts = [
        'email_verified_at' => 'datetime',
        'password' => 'hashed',
    ];
}

Kelas.php

class Kelas extends Model
{
    use HasFactory;

    protected $fillable = [
        'nama_kelas',
        'deskripsi',
    ];

    public function siswa()
    {
        return $this->hasMany(Siswa::class);
    }
}

Siswa.php

class Siswa extends Model
{
    use HasFactory;

    protected $fillable = [
        'id_siswa',
        'nama',
        'password',
        'kelas_id',
        'alamat',
        'no_telp',
        'email',
    ];

    protected $hidden = [
        'password',
    ];

    protected $casts = [
        'password' => 'hashed',
    ];

    public function kelas()
    {
        return $this->belongsTo(Kelas::class);
    }

    public function absensi()
    {
        return $this->hasMany(Absensi::class);
    }
}

Absensi.php

class Absensi extends Model
{
    use HasFactory;

    protected $fillable = [
        'siswa_id',
        'tanggal',
        'waktu_masuk',
        'waktu_keluar',
        'status',
        'lokasi_masuk',
        'lokasi_keluar',
    ];

    public function siswa()
    {
        return $this->belongsTo(Siswa::class);
    }
}

Controller

Controller menangani logika aplikasi dan menghubungkan model dengan view. Berikut adalah controller utama dalam aplikasi:

AbsensiController

Mengelola data absensi siswa, termasuk:

  • Menampilkan daftar absensi
  • Menambahkan absensi manual
  • Mengubah status absensi
  • Mengedit detail absensi

DashboardController

Mengelola tampilan dashboard, termasuk:

  • Menampilkan statistik absensi
  • Menampilkan grafik absensi per tanggal
  • Menampilkan grafik absensi per kelas
  • Menampilkan grafik status absensi

LaporanController

Mengelola laporan absensi, termasuk:

  • Menampilkan laporan absensi berdasarkan filter
  • Mengunduh laporan absensi dalam format Excel

API Controller

Controller API digunakan untuk menyediakan endpoint untuk aplikasi mobile:

  • AuthController - Menangani autentikasi siswa
  • AbsensiMobileController - Menangani absensi masuk dan keluar
  • ServerStatusController - Menangani pengecekan status server

Middleware

Middleware berfungsi sebagai filter untuk request HTTP. Berikut adalah middleware utama dalam aplikasi:

ValidateApiKey

Middleware ini digunakan untuk memvalidasi API key yang dikirimkan oleh aplikasi mobile. API key disimpan dalam file .env dan dibandingkan dengan API key yang dikirimkan dalam header Authorization.

class ValidateApiKey
{
    public function handle(Request $request, Closure $next): Response
    {
        // Ambil API key dari .env
        $validApiKey = env('MOBILE_API_KEY');
        // Ambil API key dari header Authorization
        $providedApiKey = $request->header('Authorization');

        // Support format: "Bearer <api_key>" atau langsung "<api_key>"
        if ($providedApiKey && str_starts_with($providedApiKey, 'Bearer ')) {
            $providedApiKey = substr($providedApiKey, 7);
        }

        if (!$providedApiKey || $providedApiKey !== $validApiKey) {
            return response()->json([
                'success' => false,
                'message' => 'Unauthorized: Invalid API key',
            ], 401);
        }

        return $next($request);
    }
}

Route

Route menentukan bagaimana aplikasi merespons request ke URL tertentu. Berikut adalah route utama dalam aplikasi:

Web Route

// routes/web.php
Route::get('/', function () {
    return redirect()->route('login');
});

Route::middleware('auth')->group(function () {
    Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
});

Admin Route

// routes/admin.php
Route::middleware(['auth', 'role:admin,guru'])->group(function () {
    // Kelas Routes
    Route::resource('kelas', KelasController::class);
    
    // Siswa Routes
    Route::resource('siswa', SiswaController::class);
    
    // User Routes
    Route::resource('users', UserController::class);
    
    // Laporan Routes
    Route::get('laporan', [LaporanController::class, 'index'])->name('laporan.index');
    Route::get('laporan/download', [LaporanController::class, 'download'])->name('laporan.download');
    
    // Absensi Routes
    Route::get('absensi', [AbsensiController::class, 'index'])->name('absensi.index');
    Route::get('absensi/create', [AbsensiController::class, 'create'])->name('absensi.create');
    Route::post('absensi', [AbsensiController::class, 'store'])->name('absensi.store');
    Route::get('absensi/{id}/edit', [AbsensiController::class, 'edit'])->name('absensi.edit');
    Route::put('absensi/{id}', [AbsensiController::class, 'update'])->name('absensi.update');
    Route::put('absensi/{id}/status', [AbsensiController::class, 'updateStatus'])->name('absensi.updateStatus');
});

API Route

// routes/api.php
// API untuk mendapatkan daftar siswa berdasarkan kelas (untuk admin/guru)
Route::get('/siswa', [SiswaController::class, 'index']);

// API Mobile untuk Android
// API untuk cek status server (untuk scanning dari Android)
Route::get('/mobile/status', [ServerStatusController::class, 'status'])->middleware(ValidateApiKey::class);

// API untuk autentikasi siswa
Route::post('/mobile/auth/login', [AuthController::class, 'login'])->middleware(ValidateApiKey::class);

// API untuk absensi
Route::middleware(ValidateApiKey::class)->group(function () {
    // Absensi masuk
    Route::post('/mobile/absensi/masuk', [AbsensiMobileController::class, 'absenMasuk']);
    
    // Absensi keluar
    Route::post('/mobile/absensi/keluar', [AbsensiMobileController::class, 'absenKeluar']);
    
    // Status absensi hari ini
    Route::get('/mobile/absensi/status', [AbsensiMobileController::class, 'statusAbsensi']);
});

Database Migration

Migration digunakan untuk mengelola struktur database. Berikut adalah migration utama dalam aplikasi:

create_users_table

Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password');
    $table->enum('role', ['admin', 'guru'])->default('guru');
    $table->rememberToken();
    $table->timestamps();
});

create_kelas_table

Schema::create('kelas', function (Blueprint $table) {
    $table->id();
    $table->string('nama_kelas');
    $table->text('deskripsi')->nullable();
    $table->timestamps();
});

create_siswa_table

Schema::create('siswa', function (Blueprint $table) {
    $table->id();
    $table->string('id_siswa')->unique();
    $table->string('nama');
    $table->string('password');
    $table->foreignId('kelas_id')->constrained()->onDelete('cascade');
    $table->text('alamat')->nullable();
    $table->string('no_telp')->nullable();
    $table->string('email')->nullable();
    $table->timestamps();
});

create_absensi_table

Schema::create('absensi', function (Blueprint $table) {
    $table->id();
    $table->foreignId('siswa_id')->constrained()->onDelete('cascade');
    $table->date('tanggal');
    $table->time('waktu_masuk')->nullable();
    $table->time('waktu_keluar')->nullable();
    $table->enum('status', ['hadir', 'sakit', 'izin', 'alpha'])->default('alpha');
    $table->string('lokasi_masuk')->nullable();
    $table->string('lokasi_keluar')->nullable();
    $table->timestamps();
});

Seeder

Seeder digunakan untuk mengisi database dengan data awal. Berikut adalah seeder utama dalam aplikasi:

UserSeeder

public function run(): void
{
    // Admin
    User::create([
        'name' => 'Admin',
        'email' => 'admin@example.com',
        'password' => Hash::make('password'),
        'role' => 'admin',
    ]);
    
    // Guru
    User::create([
        'name' => 'Guru',
        'email' => 'guru@example.com',
        'password' => Hash::make('password'),
        'role' => 'guru',
    ]);
}

KelasSeeder

public function run(): void
{
    // Membuat kelas dengan nama spesifik
    Kelas::factory()->createMany([
        ['nama_kelas' => 'X IPA 1'],
        ['nama_kelas' => 'X IPA 2'],
        ['nama_kelas' => 'X IPS 1'],
        ['nama_kelas' => 'X IPS 2'],
        ['nama_kelas' => 'XI IPA 1'],
        ['nama_kelas' => 'XI IPA 2'],
        ['nama_kelas' => 'XI IPS 1'],
        ['nama_kelas' => 'XI IPS 2'],
        ['nama_kelas' => 'XII IPA 1'],
        ['nama_kelas' => 'XII IPA 2'],
        ['nama_kelas' => 'XII IPS 1'],
        ['nama_kelas' => 'XII IPS 2'],
    ]);
}

SiswaSeeder

public function run(): void
{
    // Ambil semua ID kelas
    $kelasIds = Kelas::pluck('id')->toArray();
    
    // Buat 10 siswa untuk setiap kelas
    foreach ($kelasIds as $kelasId) {
        Siswa::factory()->count(10)->create([
            'kelas_id' => $kelasId,
        ]);
    }
    
    // Buat satu siswa dengan data spesifik
    Siswa::factory()->create([
        'id_siswa' => 'S123456',
        'nama' => 'Budi Santoso',
        'password' => Hash::make('password'),
        'kelas_id' => $kelasIds[0],
        'alamat' => 'Jl. Contoh No. 123, Jakarta',
        'no_telp' => '081234567890',
        'email' => 'budi@example.com',
    ]);
}

AbsensiSeeder

public function run(): void
{
    // Ambil semua ID siswa
    $siswaIds = Siswa::pluck('id')->toArray();
    
    // Buat absensi untuk 30 hari terakhir
    $startDate = Carbon::now()->subDays(30);
    $endDate = Carbon::now();
    
    for ($date = $startDate; $date->lte($endDate); $date->addDay()) {
        // Lewati hari Minggu
        if ($date->dayOfWeek === Carbon::SUNDAY) {
            continue;
        }
        
        foreach ($siswaIds as $siswaId) {
            // 80% kemungkinan siswa hadir
            if (rand(1, 100) <= 80) {
                Absensi::factory()->create([
                    'siswa_id' => $siswaId,
                    'tanggal' => $date->format('Y-m-d'),
                ]);
            }
        }
    }
}

Kesimpulan

Backend Laravel menyediakan fondasi yang kuat untuk aplikasi Absensi GPS, dengan fitur-fitur seperti:

  • Model yang merepresentasikan struktur data
  • Controller yang menangani logika aplikasi
  • Middleware untuk validasi API key
  • Route untuk menentukan endpoint
  • Migration untuk mengelola struktur database
  • Seeder untuk mengisi data awal

Dengan struktur ini, backend dapat mengelola data absensi dengan efisien dan menyediakan API yang aman untuk frontend dan aplikasi mobile.

Last Updated:: 5/15/25, 9:30 PM
Contributors: Nur Wahyudin