http://localhost:3000/api
Semua endpoint (kecuali endpoint auth) memerlukan autentikasi melalui session NextAuth.
Cookie: authjs.session-token=<token>
GET/POST /api/auth/[...nextauth]Ditangani langsung oleh NextAuth (signIn, signOut, session, callback, dll). Gunakan helper signIn() / signOut() dari next-auth/react di sisi client.
POST /api/auth/registerAccess: Public
Request Body:
{
"email": "user@example.com",
"password": "password123",
"fullName": "User Name",
"phoneNumber": "081234567890"
}User baru dibuat dengan role: EMPLOYEE dan status: PENDING (perlu disetujui admin melalui endpoint Approvals).
Response: 201 Created
{
"message": "User registered successfully",
"userId": "user-id"
}Error: 400 jika email sudah terdaftar atau validasi gagal.
GET /api/usersAccess:
ADMIN: semua userMANAGER: semua user (read-only scope)EMPLOYEE: ditentukan olehgetUserScope(hanya diri sendiri)
Response:
{
"users": [
{
"id": "user-id",
"email": "user@example.com",
"fullName": "User Name",
"phoneNumber": "081234567890",
"employeeId": "EMP001",
"role": "EMPLOYEE",
"status": "ACTIVE"
}
]
}POST /api/usersAccess: Admin only
Request Body:
{
"email": "user@example.com",
"password": "password123",
"fullName": "User Name",
"phoneNumber": "081234567890",
"role": "EMPLOYEE"
}Jika password tidak diisi, default "123456" digunakan. Mengembalikan 409 jika email atau nomor telepon sudah dipakai.
GET /api/users/:idAccess:
ADMIN/MANAGER: dapat melihat user manapunEMPLOYEE: hanya profil sendiri
Response: objek user (tanpa field password).
PATCH /api/users/:idAccess:
ADMIN: dapat mengubah user manapun termasukroleEMPLOYEE: hanya profil sendiri, fieldrolediabaikan
Request Body (partial):
{
"fullName": "Updated Name",
"phoneNumber": "081234567890",
"password": "newpassword123"
}DELETE /api/users/:idAccess: Admin only
Response: 204 No Content
GET /api/profileAccess: User yang sedang login
Response:
{
"id": "user-id",
"fullName": "User Name",
"email": "user@example.com",
"phoneNumber": "081234567890",
"employeeId": "EMP001",
"role": "EMPLOYEE",
"status": "ACTIVE",
"createdAt": "2024-01-01T00:00:00.000Z",
"_count": { "activities": 5 }
}PATCH /api/profileAccess: User yang sedang login
Request Body:
{
"fullName": "Updated Name",
"phoneNumber": "081234567890"
}POST /api/profile/passwordAccess: User yang sedang login
Request Body:
{
"newPassword": "newpassword123",
"confirmPassword": "newpassword123"
}Response:
{ "message": "Password berhasil diubah" }GET /api/approvalsAccess: Admin only
Mengembalikan daftar user dengan status: PENDING.
PATCH /api/approvalsAccess: Admin only
Request Body:
{
"userId": "user-id",
"action": "approve"
}action bernilai "approve" (set status: ACTIVE) atau "reject" (hapus user).
Response:
{ "success": true }GET /api/activitiesAccess:
ADMIN/MANAGER: melihat semua activityEMPLOYEE: hanya activity miliknya sendiri
Response:
{
"activities": [
{
"id": "activity-id",
"title": "Training Session",
"description": "Monthly training",
"date": "2024-01-15T00:00:00.000Z",
"location": "Meeting Room A",
"flag": 0,
"latitude": -6.2,
"longitude": 106.8,
"radius": 100,
"isActive": true,
"attendanceToken": "token",
"user": { "fullName": "User Name", "email": "user@example.com" },
"attendances": []
}
]
}POST /api/activitiesAccess: Semua user yang sudah login
Request Body:
{
"title": "New Activity",
"description": "Activity description",
"date": "2024-01-15",
"location": "Location Name",
"latitude": -6.2,
"longitude": 106.8,
"radius": 100,
"flag": 0
}GET /api/activities/:idAccess: Public — termasuk relasi user dan attendances.
PATCH /api/activities/:idAccess: Admin atau pemilik activity
Request Body (partial): sama dengan field create, ditambah isActive, latitude, longitude, radius.
DELETE /api/activities/:idAccess: Admin atau pemilik activity
Response: 204 No Content
POST /api/activities/:id/attendanceAccess: User yang sedang login
Request Body:
{
"latitude": -6.2,
"longitude": 106.8
}Logika:
- Activity harus
isActive - Jika activity punya koordinat, lokasi user diverifikasi terhadap
radius(geofencing Haversine) - Jika user sudah pernah absen, mengembalikan
alreadyAttended: true - Status attendance:
ON_TIMEatauLATEberdasarkanactivity.date
Response:
{ "message": "Terimakasih atas kedatangannya, anda Tiba pukul 08:00. Tepat waktu." }GET /api/my-attendanceAccess:
EMPLOYEE: hanya attendance miliknya sendiriADMIN/MANAGER: seluruh attendance
Response:
{
"attendances": [
{
"id": "attendance-id",
"status": "ON_TIME",
"timestamp": "2024-01-15T08:00:00.000Z",
"activity": {
"title": "Training Session",
"date": "2024-01-15T00:00:00.000Z",
"location": "Meeting Room A"
}
}
]
}GET /api/izinAccess:
ADMIN/MANAGER: semua pengajuan izinEMPLOYEE: hanya pengajuan milik sendiri
Query Parameters (opsional):
status— filter berdasarkan status:PENDING,APPROVED,REJECTED,CANCELLEDuserId— filter berdasarkan user (hanya untuk Admin/Manager)
Response:
[
{
"id": "leave-id",
"type": "CUTI",
"startDate": "2024-02-01T00:00:00.000Z",
"endDate": "2024-02-05T00:00:00.000Z",
"reason": "Liburan keluarga",
"status": "PENDING",
"approverNote": null,
"user": { "id": "...", "fullName": "User Name", "email": "...", "employeeId": "EMP001" },
"approvedBy": null,
"createdAt": "2024-01-20T10:00:00.000Z"
}
]POST /api/izinAccess: Semua user yang sudah login
Request Body:
{
"type": "CUTI",
"startDate": "2024-02-01",
"endDate": "2024-02-05",
"reason": "Liburan keluarga"
}Tipe izin yang valid: CUTI (Cuti Tahunan), SAKIT, DINAS, IZIN (Izin Pribadi).
Validasi:
startDatetidak boleh lebih besar dariendDate- Tidak boleh tumpang tindih dengan pengajuan lain yang masih
PENDINGatauAPPROVED - Jika tipe
CUTI, saldo cuti tahun berjalan harus mencukupi
Response: 201 Created — objek LeaveRequest yang dibuat.
Error: 400 validasi gagal, 409 tumpang tindih tanggal.
GET /api/izin/:idAccess: Pemilik request, Admin, atau Manager
PATCH /api/izin/:idAccess:
ADMIN/MANAGER: approve atau reject (hanya statusPENDING)- Pemilik: cancel (hanya status
PENDING)
Request Body:
{
"action": "approve",
"approverNote": "Disetujui. Selamat berlibur."
}action bernilai "approve", "reject", atau "cancel". approverNote opsional.
Ketika CUTI disetujui, usedDays pada LeaveBalance otomatis bertambah sesuai jumlah hari kerja.
Response: objek LeaveRequest yang diperbarui.
DELETE /api/izin/:idAccess: Pemilik (hanya status PENDING) atau Admin
Response: 204 No Content
GET /api/izin/balanceAccess: Semua user yang sudah login
Query Parameters (opsional):
year— tahun yang diminta (default: tahun berjalan)userId— target user (hanya Admin/Manager)
Response:
{
"id": "balance-id",
"userId": "user-id",
"year": 2024,
"totalDays": 12,
"usedDays": 3,
"remaining": 9
}Jika record belum ada, otomatis dibuat dengan kuota default 12 hari.
GET /api/master/access-matrixAccess: Semua user yang sudah login
Mengembalikan daftar Menu beserta relasi accesses (RoleAccess per role).
POST /api/master/access-matrixAccess: Admin only
Request Body:
{
"role": "MANAGER",
"menuId": "menu-id",
"canAccess": true
}role salah satu dari ADMIN, MANAGER, EMPLOYEE.
GET /api/seed-menusAccess: Tidak ada pengecekan session (utility endpoint)
Melakukan upsert daftar menu default ke tabel Menu.
GET /api/config?key=<key>Access:
- Dengan parameter
key: semua user yang login - Tanpa parameter
key: Admin only
POST /api/configAccess: Admin only
Request Body:
{
"key": "app_name",
"value": "AttendIQ",
"description": "Nama aplikasi"
}| Status | Keterangan |
|---|---|
400 Bad Request |
Validasi gagal (Zod), mengembalikan array errors atau pesan tunggal |
401 Unauthorized |
Tidak ada session aktif |
403 Forbidden |
Role tidak memiliki izin akses |
404 Not Found |
Resource tidak ditemukan |
409 Conflict |
Duplikasi data (email/telepon sudah dipakai, atau tanggal izin tumpang tindih) |
500 Internal Server Error |
Kesalahan server |
- Tidak ada rate limiting yang diimplementasikan saat ini.
- Endpoint list (
/api/activities,/api/izin,/api/users,/api/approvals) belum mendukung pagination — semua data dikembalikan dalam satu response. - Geofencing check-in menggunakan formula Haversine untuk menghitung jarak koordinat.
- Saldo cuti (
LeaveBalance) hanya berlaku untuk tipeCUTI; tipe lain (SAKIT,DINAS,IZIN) tidak dibatasi kuota.