C:\ARDI\PROJECTS\HR_ATTENDANCE> type case-study.txt

HR Attendance & Leave System

Sistem Absensi & Cuti HR

How I replaced a hand-made attendance recap and paper leave forms with a system that all 33 employees of a rural bank now use, running on one office server with no internet access.

Bagaimana saya mengganti rekap absensi manual dan formulir cuti kertas dengan sistem yang sekarang dipakai seluruh 33 karyawan sebuah BPR, berjalan di satu server kantor tanpa akses internet.

33employees use it dailykaryawan pakai tiap hari
7roles with their own accessperan dengan hak akses sendiri
~8 wk~8 mggfirst commit to release candidatedari commit pertama ke rilis
1developer: medeveloper: saya

My role: sole developer and the bank's only IT staff, so requirements, design, code, deployment, training and support. Stack: Python, FastAPI, SQLAlchemy, SQLite, Jinja2, HTMX, APScheduler, openpyxl, pyzk for the ZKTeco terminal. Timeline: first commit 6 August 2026, release candidate 11 September 2026, in daily use since.

Peran saya: developer tunggal sekaligus satu-satunya staf IT bank: kebutuhan, desain, kode, deployment, pelatihan, dan dukungan. Stack: Python, FastAPI, SQLAlchemy, SQLite, Jinja2, HTMX, APScheduler, openpyxl, pyzk untuk mesin ZKTeco. Waktu: commit pertama 6 Agustus 2026, rilis kandidat 11 September 2026, dipakai setiap hari sejak itu.

01 The problemMasalahnya

Before

Sebelum

  • Attendance lived on a fingerprint terminal. Every payroll period HR exported a spreadsheet and recapped it by hand: late arrivals, absences, overtime.
  • Security guards' night shifts were split across two calendar days, so their records never added up without manual fixing.
  • Leave requests were paper forms walking between manager, director and HR, with the yearly quota tracked separately.
  • Data absensi ada di mesin sidik jari. Setiap periode payroll HR mengekspor spreadsheet lalu merekapnya manual: terlambat, tidak masuk, lembur.
  • Shift malam satpam terpecah di dua tanggal kalender, jadi datanya tidak pernah cocok tanpa diperbaiki manual.
  • Pengajuan cuti pakai formulir kertas yang berpindah antara manager, direksi, dan HR, dengan kuota tahunan dicatat terpisah.

After

Sesudah

  • Scans arrive by themselves every 90 seconds and land on the right person.
  • HR downloads a payroll-ready Excel recap instead of building one, saving hours every payroll period.
  • Leave is requested, approved and recorded online, with the quota counted in working days and an audit trail.
  • Scan masuk sendiri setiap 90 detik dan tercatat ke orang yang tepat.
  • HR mengunduh rekap Excel siap payroll alih-alih menyusunnya sendiri, hemat berjam-jam setiap periode payroll.
  • Cuti diajukan, disetujui, dan dicatat online, dengan kuota dihitung dalam hari kerja dan jejak audit.

Constraints: the office server has no internet access, employee data must stay inside the office, fewer than 50 staff, and one IT person to build and run it.

Batasan: server kantor tanpa akses internet, data karyawan harus tetap di dalam kantor, kurang dari 50 staf, dan hanya satu orang IT untuk membangun sekaligus menjalankannya.

02 What I builtYang saya bangun

hr-dashboard.jpg
HR system dashboard with demo data

Dashboard — demo data, made-up names

Dashboard — data demo, nama karangan

hr-attendance.jpg
Attendance list with demo data

Attendance list — demo data

Daftar presensi — data demo

03 ArchitectureArsitektur

hr_attendance — architecture
ZKTeco terminalfingerprint scansFastAPI appAPScheduler · Jinja2 · HTMXSQLiteattendance · leaveStaff browsersoffice LAN · 7 rolesPayroll Excelopenpyxl exportBackupsevery 6 hpoll every 90 sSQLAlchemyHTTPrecapcopy

Everything runs on one office PC on the LAN. Nothing leaves the building.

Semuanya berjalan di satu PC kantor di LAN. Tidak ada data yang keluar gedung.

04 Key decisionsKeputusan penting

Server-rendered pages with HTMX, not a SPA

No build step and no CDN, so it works fully offline and one person can maintain it.

SQLite, with numbered migrations

Fewer than 50 users on one machine. A single file is easy to back up, and 17 SQL migrations apply themselves on startup.

An air-gapped install

Every dependency is bundled with the app, and one script installs it on a PC that has never seen the internet.

Build in-house rather than buy

I wrote a memo to the Board comparing a vendor offer. The rules are specific to this bank, the requirements changed four times in five days once people used it, and the data stays in the office.

Halaman server-rendered dengan HTMX, bukan SPA

Tanpa proses build dan tanpa CDN, jadi berjalan penuh secara offline dan bisa dirawat satu orang.

SQLite, dengan migrasi bernomor

Kurang dari 50 pengguna di satu mesin. Satu file mudah di-backup, dan 17 migrasi SQL berjalan sendiri saat aplikasi menyala.

Instalasi tanpa internet

Semua dependensi dibundel bersama aplikasi, dan satu skrip memasangnya di PC yang tidak pernah terhubung internet.

Bangun sendiri, bukan beli

Saya menulis memo ke Direksi yang membandingkan penawaran vendor. Aturannya sangat khusus untuk bank ini, kebutuhannya berubah empat kali dalam lima hari setelah dipakai, dan data tetap di dalam kantor.

05 Hard problemsMasalah tersulit

Night shifts that crossed midnight

A guard on the night shift scans at 23:00 and again at 07:00 the next morning. Filed by calendar date, that became one day with no exit and a next day whose exit looked like an arrival. I rebuilt guard attendance around shifts instead of dates, with a rotation schedule, so a night shift is one record again.

A login loop nobody reported

While auditing something unrelated, I found that the "change your password" page and the "complete your profile" page each sent users to the other. 22 of 40 accounts were stuck. I fixed it, wrote it up in the audit, and changed how I work: re-audit after every big change instead of trusting an earlier review.

Saying the risks out loud

The system works, but backups sat on the same disk and everything depended on me. I put both in writing to the Board, with fixes: an off-machine backup, a visible "last backup" age, and training a colleague as backup.

Shift malam yang melewati tengah malam

Satpam shift malam scan pukul 23:00 lalu lagi pukul 07:00 besok paginya. Kalau dicatat per tanggal, jadinya satu hari tanpa jam pulang dan hari berikutnya yang jam pulangnya terbaca sebagai jam masuk. Saya membangun ulang absensi satpam berdasarkan shift, bukan tanggal, lengkap dengan jadwal rotasi, sehingga satu shift malam kembali jadi satu catatan.

Login berputar-putar yang tidak dilaporkan siapa pun

Saat mengaudit hal lain, saya menemukan halaman "ganti password" dan "lengkapi profil" saling melempar pengguna ke satu sama lain. 22 dari 40 akun terjebak. Saya memperbaikinya, mencatatnya di laporan audit, dan mengubah cara kerja: audit ulang setiap selesai perubahan besar, bukan mengandalkan review sebelumnya.

Menyampaikan risiko secara terbuka

Sistemnya jalan, tapi backup masih di disk yang sama dan semuanya bergantung pada saya. Keduanya saya sampaikan tertulis ke Direksi, lengkap dengan solusinya: backup di luar mesin, penanda umur backup terakhir yang terlihat, dan melatih satu rekan sebagai cadangan.

06 ResultsHasil

07 What I learnedPelajaran

Need someone who can build the system and keep the network under it running?

Butuh orang yang bisa membangun sistemnya sekaligus menjaga jaringan di bawahnya?

WhatsApp Email Download CVUnduh CV More projectsProyek lain