Daily Taqwa
Sistem presensi salat anti-manipulasi untuk ~2.000 pegawai OIKN di Masjid Negara IKN

- pegawai OIKN yang dilayani
- ~2.000
- presensi dalam lima menit, sesuai rancangan
- ~500
- waktu salat dicatat per pegawai
- 5
- papan peringkat, termasuk Subuh dan direktorat
- 4
Di halaman ini
Masalahnya
Otorita IKN ingin mendorong sekitar 2.000 pegawainya salat di Masjid Negara IKN, dan ingin tahu apakah mereka benar hadir. Daftar hadir kertas bisa diisi belakangan. Presensi digital yang sederhana bisa dipalsukan dari luar masjid. Pimpinan SDM juga ingin melihat tren kehadiran di setiap direktorat, lebih dari sekadar daftar siapa yang datang.
Waktunya membuat masalah ini lebih sulit daripada presensi kantor biasa. Waktu salat singkat, dan presensi menumpuk di beberapa menit sekitar azan. Pengecekan lokasi juga harus tahan terhadap orang yang memang berusaha memalsukannya.
Yang saya bangun
Hanya aplikasi mobile yang bisa presensi
Browser tidak bisa membuktikan bahwa lokasi GPS-nya berasal dari ponsel sungguhan. Aplikasi fake GPS gratisan dan tools browser bisa menembus geofence berbasis web, seketat apa pun server-nya. Jadi saya memisahkan sistemnya. Aplikasi mobile native adalah satu-satunya klien yang boleh mengirim presensi. Aplikasi ini merekam cek liveness dan membaca GPS dengan deteksi lokasi palsu bawaan ponsel. Portal web menampilkan jadwal salat, peringkat, profil, catatan rilis, dan panel admin. Keduanya memakai satu backend yang memegang semua aturan.
Server yang memegang jam
Server menghitung setiap waktu salat, menyimpannya di cache, dan memeriksanya lagi saat presensi masuk. Ponsel tidak pernah mengirim waktu yang ikut dihitung. IKN memakai WITA, delapan jam di depan UTC. Presensi Subuh pukul 05.00 WITA jatuh di hari sebelumnya dalam UTC. Saya membuat semua tanggal di database memakai waktu setempat, supaya Subuh dan Isya tidak tercatat di hari yang salah.
Satu presensi, satu langkah, tanpa duplikat
Presensi mengerjakan semuanya dalam satu langkah: memakai kode sekali pakai, memeriksa waktu salat, geofence, kecepatan perpindahan sejak presensi terakhir, dan hasil liveness, lalu menyimpan catatannya. Kalau satu bagian gagal, tidak ada yang tersimpan. Database menolak catatan kedua untuk orang, hari, dan waktu salat yang sama, jadi dua ketukan bersamaan tidak menghasilkan dua catatan. Rekap harian, bulanan, dan per direktorat ikut diperbarui di langkah yang sama, sehingga selalu cocok dengan catatannya.
Satu login untuk web dan mobile
Kedua aplikasi masuk lewat single sign-on OIKN yang sudah ada. Web memakai redirect browser standar. Aplikasi mobile login langsung, lalu menukar login itu dengan sesi miliknya sendiri di backend. Saya memetakan NIP, unit kerja, dan jenis kelamin dari data login ke profil pegawai. Beberapa sistem kepegawaian mengirim NIP dalam format aneh, dan PPPK serta pegawai militer punya nomor yang tidak standar, jadi saya menerimanya juga.
Peringkat, riwayat, dan alat yang diminta SDM
Ada empat papan peringkat: bulanan per jenis kelamin, tahunan, khusus Subuh, dan per direktorat. Peringkat Anda sendiri tetap tampil di bawah kalau berada di luar sepuluh besar. Kalender bulanan mewarnai kelima waktu salat setiap hari. Setelah peluncuran, muncul kebutuhan yang tidak ada di spesifikasi. Data login tidak membawa jenis kelamin, jadi pegawai bisa mengoreksi jenis kelamin dan direktorat di profilnya, dan login berikutnya tidak menimpa koreksi itu. SDM bisa mengunggah data kertas lama lewat halaman web, dan admin bisa melihat login web dan mobile secara terpisah untuk memantau adopsi aplikasi.
Hasilnya
Daily Taqwa sudah berjalan di produksi di OIKN. Aplikasi mobile-nya live dan menjadi satu-satunya jalur presensi. Portal web menjalankan peringkat dan administrasi di backend yang sama. Sistem ini melayani sekitar 2.000 pegawai dan dirancang untuk sekitar 500 presensi dalam lima menit saat Zuhur. Saya membangunnya antara April dan Juni 2026. Cakupannya tumbuh melampaui spesifikasi awal: single sign-on menggantikan akun lokal, dan alat-alat SDM di atas lahir dari masukan setelah peluncuran.
Di balik layarDetail teknis untuk engineer
- Waktu salat dihitung dengan library Python
praytimesdan di-cache di Redis. Helperget_wita_date()mengubah setiap tanggal presensi ke WITA (UTC+8) sebelum masuk ke constraint berbasis tanggal. - Layanan presensi berjalan dalam satu blok
@transaction.atomicdenganSELECT FOR UPDATEpada baris user: pemakaian nonce, validasi waktu, geofence Haversine dengan radius yang bisa diatur, cek kecepatan, cek liveness, penyimpanan foto, dan pembaruan rekap. UNIQUE(user_id, date, prayer)menjadi pengaman utama dari race condition. Layanan menangkapIntegrityErrordan mengembalikan pesan "sudah presensi". Nonce sekali pakai dengan TTL dua menit.- SSO web memakai Keycloak PKCE lewat
mozilla-django-oidc. Mobile memakai Direct Access Grant: mendapatid_tokenKeycloak lalu menukarnya di endpoint backend dengan token SimpleJWT. Klaim (NIP, unit_kerja, gender) dipetakan ke model user dengan pencocokan eselon fuzzy. NIP yang datang sebagai float diubah menjadi string. - Flag
profile_self_editedmencegah sinkronisasi OIDC menimpa direktorat yang sudah dikoreksi pengguna.last_login_webdanlast_login_mobilemenggantikan satu fieldlast_loginbawaan Django. - Pencocokan wajah dengan
dlibditunda menjadi liveness saja. Server memeriksa frame ada dan tidak identik;face-api.jsmenjalankan tantangan liveness di klien. - EXIF foto dihapus dengan Pillow, dan foto hanya disajikan lewat endpoint yang terautentikasi. Presigned URL MinIO mengarah ke hostname Docker internal, jadi endpoint-nya mengalirkan byte foto langsung.
import_backfill_csvmengimpor data kertas secara idempoten dengan--appenddan menggabungkan akun SSO berdasarkan NIP. Perintah ini juga dibungkus halaman unggah untuk admin.- Panel admin punya editor geofence Leaflet, pengaturan waktu per salat, impor user massal dari Excel, log presensi dengan pratinjau foto, dan audit log.
- Sekitar 15 model, sekitar 30 endpoint API, 23 file halaman frontend, sekitar 18.800 baris Python dan TypeScript, 85 commit.
Tangkapan layar
Sedang merekrut, atau membangun hal serupa?
Saya terbuka untuk posisi full-time dan proyek freelance tertentu.