# Hadirin — Backend API & Panel Admin (PHP + MySQL)

Backend resmi aplikasi absensi **Hadirin**. Dibangun dengan PHP 8 (tanpa framework)
dan MySQL/MariaDB, siap dipasang di XAMPP/Laragon, hosting shared, atau server sekolah.

```
backend/
├── hadirin.sql              ← skema database (import manual via phpMyAdmin)
├── install.php              ← ⭐ installer sekali-klik (database + tabel + data contoh)
├── config/config.php        ← koneksi DB & pengaturan (jam masuk, dll)
├── api/                     ← REST API untuk aplikasi Flutter/HP
│   ├── index.php            ← router utama
│   └── handlers/            ← logika per fitur
├── admin/                   ← Panel admin web (bisa dibuka dari HP/laptop)
└── uploads/foto/            ← foto profil (dibuat otomatis)
```

---

## 1) Cara Pasang (lokal/XAMPP)

1. Salin folder `backend/` ini ke `C:\xampp\htdocs\hadirin\` (jadi `C:\xampp\htdocs\hadirin\backend\`).
2. Pastikan **Apache** dan **MySQL** menyala di XAMPP Control Panel.
3. Buka di browser: `http://localhost/hadirin/backend/install.php`
4. Klik **🚀 Jalankan Instalasi** — database `hadirin`, semua tabel, akun admin,
   5 karyawan contoh, rekap absensi bulan berjalan, dan 2 pengajuan izin dibuat otomatis.
5. Selesai. **Hapus `install.php`** dari server (disarankan).

### Akun bawaan

| Peran | NIP | Sandi |
|---|---|---|
| Admin (panel web + aplikasi) | `19850712` | `hadirin123` |
| Karyawan contoh (Siti Aminah) | `19900321` | `hadirin123` |
| Karyawan lain | `19881205`, `19950617`, `19891130`, `19920214` | `hadirin123` |

> Reset sandi karyawan bisa dilakukan dari panel admin (tombol 🔑 → kembali ke `hadirin123`).


### NIP Karyawan: Otomatis atau Manual

Saat menambah karyawan, kolom **NIP boleh dikosongkan** — sistem otomatis
membuat NIP dengan format `K-YYYYMM-XXX` (contoh: `K-202608-001`, unik per
bulan). Bisa juga diisi manual (huruf/angka, 4–20 karakter).

---

## 1b) Cara Pasang di Hosting (cPanel) — TANPA XAMPP

Error `#1044 Access denied ... to database 'hadirin'` terjadi karena user
hosting tidak berhak membuat database sendiri. Ikuti langkah ini:

1. **cPanel → MySQL® Databases**
   - *Create New Database*: isi `hadirin` → jadi `medp2337_hadirin` → Create.
   - *Add User to Database*: pilih user + database itu, centang **ALL PRIVILEGES**.
2. **phpMyAdmin** → klik database `medp2337_hadirin` → tab **Import** →
   pilih **`hadirin_hosting.sql`** (versi khusus hosting, tanpa CREATE DATABASE) → Go.
3. Edit **`config/config.php`**:
   ```php
   define('DB_NAME', 'medp2337_hadirin');  // nama db sebenarnya
   define('DB_USER', 'medp2337');          // user database cPanel
   define('DB_PASS', 'PASSWORD_DB_ANDA');  // password USER DATABASE (bukan cPanel)
   ```
4. Upload folder `backend/` ke `public_html/hadirin/backend/`.
5. Panel admin: `https://domain-anda/hadirin/backend/admin/`
   (login: NIP `19850712` / sandi `hadirin123` — segera ganti sandi setelah masuk!)

> `install.php` juga bisa dipakai di hosting: buat dulu database di cPanel,
> set `DB_NAME` di `config/config.php`, baru jalankan install.php
> (instalernya otomatis memakai database yang sudah ada itu).
> Alternatif tanpa install.php: import `hadirin_hosting.sql` lewat phpMyAdmin.

## 2) Fitur Panel Admin (lengkap)

| Fitur | Keterangan |
|---|---|
| **Dashboard** | Statistik hari ini: hadir, telat, izin, sakit, cuti + daftar kehadiran hari ini + izin pending |
| **Kelola Karyawan** | Tambah / edit / hapus, reset kata sandi, aktif/nonaktif, NIP otomatis atau manual |
| **Absensi Manual** | 📌 Tambah / koreksi / hapus absensi karyawan (untuk yang lupa absen atau darurat) |
| **Rekap Bulanan** | Tabel rekap semua karyawan per bulan + tombol cetak (print) |
| **Perizinan** | Setujui / tolak izin dengan catatan — yang disetujui otomatis tercatat ke absensi |
| **Keamanan** | Login session, proteksi admin terakhir, password ter-hash (bcrypt) |

> Semua menu panel admin bisa dibuka dari browser HP/laptop: `http://<ip-laptop>/hadirin/backend/admin/`

---

---

## 2) Panel Admin Web

Buka `http://localhost/hadirin/backend/admin/login.php`

Fitur:
- **Dashboard** — ringkasan: karyawan aktif, hadir hari ini, izin menunggu, absen bulan ini
- **Data Karyawan** — tambah / edit / hapus / reset sandi / jadikan admin / aktif-nonaktif
- **Absensi** — lihat per bulan & per karyawan, tambah/koreksi manual, hapus rekaman
- **Rekap Bulanan** — tabel rekap semua karyawan + tombol Cetak/Simpan PDF
- **Pengajuan Izin** — setujui / tolak; yang disetujui **otomatis tercatat ke rekap absensi**

Aturan yang diterapkan otomatis:
- Hari kerja = **Senin–Jumat**
- Absen masuk **setelah 08:00** = status **telat** (bisa diubah di `config/config.php`)
- Karyawan yang cuti/sakit (setelah disetujui admin) tidak dihitung absen bolos

---

## 3) REST API (untuk aplikasi Flutter)

Base URL: `http://localhost/hadirin/backend/api/`

Semua endpoint `admin/*` wajib token admin. Endpoint lain wajib token karyawan.
Kirim token lewat header: `Authorization: Bearer <token>`

### Auth & Profil
| Method | Endpoint | Keterangan |
|---|---|---|
| POST | `/auth/login` | body JSON `{nip, password}` → `{token, employee}` |
| POST | `/auth/logout` | hapus sesi |
| GET | `/me` | profil saya |
| PUT | `/me` | update `{email, no_hp, alamat}` |
| POST | `/me/foto` | multipart `foto` (file) |
| POST | `/me/password` | `{password_lama, password_baru}` |

### Absensi (karyawan)
| Method | Endpoint | Keterangan |
|---|---|---|
| POST | `/attendance/checkin` | absen masuk (status hadir/telat otomatis) |
| POST | `/attendance/checkout` | absen pulang |
| GET | `/attendance/today` | status hari ini |
| GET | `/attendance?bulan=2026-08&status=hadir` | riwayat + filter |
| GET | `/attendance/rekap?bulan=2026-08` | rekap bulanan saya (hadir/telat/izin/sakit/cuti/persen) |

### Pengajuan (karyawan)
| Method | Endpoint | Keterangan |
|---|---|---|
| GET | `/leave-requests?status=pending` | daftar pengajuan saya |
| POST | `/leave-requests` | `{jenis, tanggal_mulai, tanggal_selesai, alasan}` |
| DELETE | `/leave-requests/{id}` | batalkan (hanya status pending) |

### Admin — Karyawan
| Method | Endpoint | Keterangan |
|---|---|---|
| GET | `/admin/employees?q=&status=` | daftar + cari |
| GET | `/admin/employees/{id}` | detail |
| POST | `/admin/employees` | tambah `{nip, nama, password?, posisi?, divisi?, ...}` |
| PUT | `/admin/employees/{id}` | edit |
| DELETE | `/admin/employees/{id}` | hapus beserta riwayat |
| POST | `/admin/employees/{id}/reset-password` | `{password}` |

### Admin — Rekap, Absensi, Izin
| Method | Endpoint | Keterangan |
|---|---|---|
| GET | `/admin/rekap?bulan=2026-08` | rekap semua karyawan + ringkasan |
| GET | `/admin/attendance?bulan=&employee_id=` | riwayat semua |
| POST | `/admin/attendance` | tambah/koreksi manual |
| DELETE | `/admin/attendance/{id}` | hapus rekaman |
| GET | `/admin/leave-requests?status=pending` | semua pengajuan |
| PUT | `/admin/leave-requests/{id}` | `{status: disetujui|ditolak, catatan_admin?}` |
| GET | `/admin/stats` | angka dashboard |

### Contoh panggilan (curl)
```bash
# Login
curl -X POST http://localhost/hadirin/backend/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"nip":"19850712","password":"hadirin123"}'

# Absen masuk (pakai token hasil login)
curl -X POST http://localhost/hadirin/backend/api/attendance/checkin \
  -H "Authorization: Bearer TOKEN_ANDA"

# Rekap bulanan
curl http://localhost/hadirin/backend/api/attendance/rekap?bulan=2026-08 \
  -H "Authorization: Bearer TOKEN_ANDA"
```

Format respons selalu: `{"ok": true/false, "message": "...", "data": ...}`

---

## 4) Menghubungkan Aplikasi Flutter

Di file Flutter `lib/data/app_config.dart`:

```dart
// Saat HP (Infinix) & laptop dalam 1 WiFi — ganti IP dengan IP laptop
const String apiBaseUrl = 'http://192.168.1.10/hadirin/backend/api';
const bool useMock = false;   // false = pakai backend beneran
```

Catatan: HP Android memblokir `http://` polos (cleartext) di atas Android 9.
Pastikan `android:usesCleartextTraffic="true"` ada di `AndroidManifest.xml`
(debug build sudah diizinkan otomatis oleh Flutter).

---

## 5) Keamanan (sudah diterapkan)

- ✅ Semua query memakai **prepared statements** (anti SQL injection)
- ✅ Sandi disimpan sebagai **bcrypt hash** (`password_hash`)
- ✅ Token sesi acak 64-hex, kedaluwarsa 30 hari
- ✅ Proteksi: admin terakhir tidak bisa dihapus/dinonaktifkan
- ✅ Validasi input di sisi server (NIP, tanggal, status, dll)

## 6) Keamanan (tugas Anda saat produksi)

- Ubah sandi MySQL default & buat user khusus
- Ganti `DB_PASS` di `config/config.php`, aktifkan HTTPS
- Hapus `install.php` dan folder `api/handlers` jangan di-edit sembarangan
- Backup database rutin: `mysqldump -u root hadirin > backup.sql`