# Attendance Mobile API (API Key)

Base URL:
`{APP_URL}/api/v1/attendance`

Auth:
- Header utama: `X-Api-Key: <ATTENDANCE_INGEST_API_KEY>`
- Fallback body/query: `api_key`

## 1) Login (validasi API key)
`POST /login`

Contoh:
```bash
curl -X POST "http://127.0.0.1:8000/api/v1/attendance/login" \
  -H "X-Api-Key: YOUR_KEY" \
  -H "Accept: application/json"
```

## 2) Request Data (site geofence + policy)
`GET /request-data`

Contoh:
```bash
curl "http://127.0.0.1:8000/api/v1/attendance/request-data" \
  -H "X-Api-Key: YOUR_KEY" \
  -H "Accept: application/json"
```

## 3) Check-in
`POST /checkin`

Body minimal:
- `log_at` (YYYY-MM-DD HH:mm:ss)
- `client_log_id` (unik per event)
- `finger_id` atau `employee_code`

Body disarankan untuk mobile secure:
- `site_code`, `latitude`, `longitude`, `gps_accuracy`
- `is_mock_location`, `location_provider`
- `device_id`, `integrity_verdict`
- `face_match_score`, `face_liveness_score`
- `face_image` (file selfie, multipart, jpg/jpeg/png/webp max 4MB)

Contoh:
```bash
curl -X POST "http://127.0.0.1:8000/api/v1/attendance/checkin" \
  -H "X-Api-Key: YOUR_KEY" \
  -H "Accept: application/json" \
  -F "log_at=2026-03-04 08:01:00" \
  -F "client_log_id=MOB-20260304080100-10022" \
  -F "finger_id=10022" \
  -F "site_code=HQ-JKT" \
  -F "latitude=-6.2000000" \
  -F "longitude=106.8166667" \
  -F "gps_accuracy=10.5" \
  -F "is_mock_location=false" \
  -F "location_provider=fused" \
  -F "device_id=android-secure-id" \
  -F "integrity_verdict=pass" \
  -F "face_match_score=0.91" \
  -F "face_liveness_score=0.88" \
  -F "face_image=@D:/photos/selfie-checkin.jpg" \
  -F "notes=mobile checkin"
```

## 4) Check-out
`POST /checkout`

Sama seperti check-in, hanya endpoint berbeda:
```bash
curl -X POST "http://127.0.0.1:8000/api/v1/attendance/checkout" \
  -H "X-Api-Key: YOUR_KEY" \
  -H "Accept: application/json" \
  -F "log_at=2026-03-04 17:05:00" \
  -F "client_log_id=MOB-20260304170500-10022" \
  -F "finger_id=10022" \
  -F "site_code=HQ-JKT" \
  -F "latitude=-6.2001000" \
  -F "longitude=106.8166000" \
  -F "gps_accuracy=9.2" \
  -F "is_mock_location=false" \
  -F "location_provider=fused" \
  -F "device_id=android-secure-id" \
  -F "integrity_verdict=pass" \
  -F "face_match_score=0.93" \
  -F "face_liveness_score=0.90" \
  -F "face_image=@D:/photos/selfie-checkout.jpg" \
  -F "notes=mobile checkout"
```

## 5) Report
`GET /report`

Query wajib:
- `date_from=YYYY-MM-DD`
- `date_to=YYYY-MM-DD`

Filter opsional:
- `employee_code`
- `finger_id`
- `log_type` (`in|out|unknown`)
- `validation_status` (`passed|warning|rejected`)
- `per_page` (max 500)

Contoh:
```bash
curl "http://127.0.0.1:8000/api/v1/attendance/report?date_from=2026-03-01&date_to=2026-03-04&finger_id=10022&per_page=100" \
  -H "X-Api-Key: YOUR_KEY" \
  -H "Accept: application/json"
```

## 6) Logout
`POST /logout`

Catatan: mode API key bersifat stateless, logout hanya sinyal dari client.

Contoh:
```bash
curl -X POST "http://127.0.0.1:8000/api/v1/attendance/logout" \
  -H "X-Api-Key: YOUR_KEY" \
  -H "Accept: application/json"
```

## Response penting
- `duplicate=true`: `client_log_id` sudah pernah masuk (idempotent, aman retry)
- `validation_status`: `passed|warning|rejected`
- `validation_reason`: alasan reject/warning (radius, mock gps, integrity, face score, dll)
- `face_image_path`: path file selfie yang tersimpan di server

## 7) Proses Faceid+GPS di Mobile

Mode `Faceid+GPS` pada aplikasi Android berjalan bertahap. Tujuannya agar mudah dibaca saat debugging dan saat memeriksa log mobile client.

Urutan proses:
1. App memastikan kamera depan siap.
2. App memastikan foto referensi lokal tersedia.
   - Referensi lokal biasanya hasil sync dari server atau hasil ganti foto profil.
3. User menekan tombol `Cocokkan CNN`.
4. App mengambil foto `capture` terbaru dari kamera.
5. App melakukan `assessment` ke foto referensi:
   - wajah ditemukan atau tidak
   - ada indikasi masker / wajah tertutup atau tidak
   - area mata lemah / glare berat atau tidak
   - koordinat bounding box wajah
6. App melakukan `assessment` ke foto capture dengan kriteria yang sama.
7. Jika referensi atau capture tidak layak, proses berhenti dengan alasan yang jelas.
8. Jika keduanya layak, app menjalankan `compare`:
   - embedding wajah referensi
   - embedding wajah capture
   - hitung `similarity score`
9. Jika `similarity >= min_face_match_score`, maka tombol submit dianggap siap untuk mode face.

Catatan implementasi:
- Bounding box wajah yang sudah ditemukan pada tahap assessment dipakai lagi saat compare agar hasil lebih konsisten.
- Jika compare gagal, app tetap mencatat tahap terakhir ke log mobile.

## 8) Trace Log Face Scan ke Mobile Client Logs

Saat user menekan `Cocokkan CNN`, mobile sekarang mengirim jejak proses ke endpoint:

`POST /mobile-client-log`

Jenis log:
- `error_type=face_scan_trace`

Field context penting:
- `stage`
- `mode`
- `employee_code`
- `finger_id`
- `selected_site_code`
- `gps_ready`
- `site_required`
- `site_within_radius`
- `profile_photo_local_path`
- `last_capture_path`
- `face_score`
- `min_face_match_score`

Stage yang saat ini dicatat:
- `camera_not_ready`
- `reference_missing`
- `compare_started`
- `capture_taken`
- `reference_assessed`
- `candidate_assessed`
- `reference_rejected`
- `candidate_rejected`
- `compare_finished`
- `match_success`
- `match_below_threshold`
- `compare_exception`

Arti singkat stage:
- `camera_not_ready`: kamera belum siap saat proses dimulai
- `reference_missing`: foto referensi lokal belum tersedia
- `compare_started`: proses face compare mulai dijalankan
- `capture_taken`: foto capture berhasil diambil
- `reference_assessed`: assessment foto referensi selesai
- `candidate_assessed`: assessment foto capture selesai
- `reference_rejected`: referensi ditolak, misalnya wajah tidak terbaca atau terindikasi tertutup
- `candidate_rejected`: capture ditolak, misalnya wajah tidak terbaca atau terindikasi tertutup
- `compare_finished`: compare embedding selesai dan score sudah didapat
- `match_success`: score memenuhi threshold
- `match_below_threshold`: wajah terbaca tetapi score masih di bawah threshold
- `compare_exception`: ada exception runtime saat proses compare

Cara membaca di Laravel:
1. Buka halaman `attendance-mobile-client-logs`
2. Filter atau cari `face_scan_trace`
3. Urutkan berdasarkan waktu terbaru
4. Baca stage terakhir untuk mengetahui proses berhenti di mana

Contoh diagnosis cepat:
- berhenti di `reference_missing`
  - foto referensi lokal belum ada
- berhenti di `reference_rejected`
  - foto referensi ada, tapi wajahnya tidak layak dipakai
- berhenti di `candidate_rejected`
  - foto capture dari kamera tidak layak dipakai
- sampai `compare_finished` lalu `match_below_threshold`
  - wajah terbaca, tapi score similarity masih kurang
