Skip to content
Blog DevOps

Bagaimana Saya Mengubah Database Kepegawaian Lama Menjadi Data Bersih, Tahap demi Tahap

By Romi Fadli, S.Kom. 19 min read Storage & Data
On this page
Messy legacy records pass through three ordered phases into a clean table, while rejected rows branch off into a report

Pendahuluan

A. Sistem kepegawaian yang tak bisa dimatikan begitu saja

Pemerintah kota menyimpan seluruh perjalanan kerja setiap ASN di satu tempat: siapa dia, keluarganya, pendidikannya, setiap pangkat dan jabatan yang pernah dipegang, nilai kinerjanya, cutinya, penghargaannya, juga catatan disiplinnya. Bertahun-tahun tempat itu adalah sistem kepegawaian lama yang dibangun tim lain. Saya sedang membangun penggantinya, dan sebelum siapa pun bisa bersandar pada sistem baru, data di sistem lama harus tiba di sana — semuanya, dan dengan benar.

Sistem lama tidak berhenti selama itu berlangsung. Pegawai tetap mengisi data ke sana setiap hari, jadi tak ada akhir pekan yang tenang untuk menyalin semuanya sekali lalu memensiunkan sistem lama. Migrasinya harus dijalankan berulang kali terhadap salinan database lama yang baru, tiap kali sedikit lebih lengkap, sampai saat pemerintah kota memutuskan sistem barulah yang resmi. Migrasi yang hanya berhasil sekali tak ada gunanya di sini; ia wajib bisa diulang, dan setiap pengulangan harus meninggalkan sistem baru dalam keadaan yang bisa diperiksa orang.

Tantangannya: mengubah database kepegawaian lama menjadi data bersih untuk sistem baru, tahap demi tahap — tanpa menghentikan sistem lama, tanpa menyentuhnya, dan tanpa membiarkan satu baris pun hilang diam-diam.

Yang membuatnya sulit bukan volumenya. Puluhan ribu pegawai dan beberapa ratus ribu baris terkait muat dengan nyaman di database modern mana pun. Yang membuatnya sulit adalah bentuk datanya: sistem lama nyaris tak menegakkan aturan apa pun, sehingga database-nya merekam bukan apa yang diatur, melainkan apa yang kebetulan diketik orang selama lebih dari satu dekade.

B. Arti "bersih" untuk data kepegawaian

Bersih bukan berarti rapi dipandang. Dalam sistem kepegawaian, bersih berarti setiap nilai berkode merujuk ke satu entri di tabel referensi, setiap relasi menunjuk record yang benar-benar ada, setiap tanggal adalah tanggal sungguhan, dan setiap angka bermakna sesuai nama kolomnya. Sifat-sifat itu penting karena sistem baru bertindak berdasarkan datanya. Ia menghitung kapan pegawai jatuh tempo naik pangkat, kapan gajinya naik berkala, kapan ia mencapai batas usia pensiun, dan anggota keluarga mana yang berhak atas tunjangan. Pangkat yang disimpan sebagai teks bebas atau tanggal yang berisi nol bukan sekadar kelihatan berantakan; ia membuat perhitungan itu keliru bagi orang sungguhan.

Bersih juga berarti jujur soal apa yang tidak ada. Ketika data lama memang tak memuat satu fakta, sistem baru harus menyatakannya dengan cara yang bisa ditemukan dan diperbaiki orang, bukan mengarang nilai yang tampak masuk akal.

C. Pendekatan yang saya tolak

Pendekatan tercepat adalah satu script besar yang membaca setiap tabel dan menulis setiap baris, dijalankan sekali pada malam peralihan. Saya menolaknya karena ia gagal di ketiga syarat sekaligus: tak aman diulang, tak bisa diperiksa di tengah jalan, dan ketika bertemu baris yang tak dimengertinya, ia entah menghentikan seluruh run atau membuang baris itu tanpa suara.

Pendekatan kedua adalah melonggarkan skema baru sampai data lama muat: kolom wajib dijadikan opsional, kode tak dikenal disimpan sebagai teks, tanggal nol diterima. Itu memindahkan setiap persoalan dari migrasi ke dalam sistem baru secara permanen, dan baru muncul bertahun-tahun kemudian sebagai perhitungan yang salah. Pendekatan ketiga adalah membersihkan database lama di tempat terlebih dulu. Itu berarti menulis ke sistem yang masih dipakai setiap hari dan masih menjadi sumber kebenaran — persis yang tak boleh terjadi.

Yang tersisa adalah migrasi yang tersusun dari tahap-tahap kecil berurutan: membaca data lama lewat pintu yang dijaga, menerjemahkannya dengan peta eksplisit, menjaga aturan sistem baru tetap utuh, dan melaporkan setiap baris yang tak bisa diterima ketimbang menebak.

D. Empat belas hambatan yang menghalangi

Gampang dirumuskan, canggung dibangun. Empat belas rintangan berdiri di antara database lama dan data bersih di sistem baru.

Hambatan pertama: sumbernya harus tetap hidup dan tak tersentuh. Sistem lama dipakai setiap hari, jadi migrasi membaca salinannya, dan janji untuk tidak menulis tak boleh bersandar pada niat baik atau pada apa yang kebetulan diizinkan bagi akun database-nya. Memercayai kedisiplinan adalah alternatif yang ditolak; jaminannya harus ditegakkan oleh code yang membuka koneksinya.

Hambatan kedua: datanya tak punya format yang konsisten. Encoding karakter lama, mode database yang longgar, tanggal berisi nol, tahun yang mustahil, placeholder seperti tanda hubung atau titik di kolom wajib, dan nomor identitas yang tersimpan dalam notasi ilmiah spreadsheet. Menerima nilai apa adanya adalah alternatif yang ditolak.

Hambatan ketiga: tipe data tak cocok dengan maknanya. Pangkat tersimpan sebagai teks "III/a", nilai kinerja kehilangan pemisah desimalnya, nominal gaji diketik tangan dengan digit yang hilang atau nol berlebih. Mengonversinya membabi buta adalah alternatif yang ditolak, sebab konversi yang salah tampak persis seperti yang benar.

Hambatan keempat: tak ada foreign key, dan relasi ditulis sebagai teks bebas. Alamat tanpa kode wilayah — satu nama kota dieja dengan puluhan cara — tempat lahir, instansi, program studi, dasar hukum, dan nama penanda tangan. Mencocokkannya secara longgar saat impor adalah alternatif yang ditolak.

Hambatan kelima: kode status adalah nomor baris internal sistem lama, bukan kode resmi. Membaca kolom status apa adanya akan menempatkan puluhan ribu pegawai pada kode resmi yang keliru, dan sebagian kode resmi yang dibutuhkan data lama bahkan belum ada di tabel referensi sistem baru.

Hambatan keenam: sebagian makna tersembunyi di code lama, bukan di skemanya. Penanda "terverifikasi" yang diset job terjadwal, bukan oleh manusia; penolakan yang dicatat dengan menghapus barisnya; kolom yang isinya berbeda dari namanya. Membaca skemanya saja adalah alternatif yang ditolak.

Hambatan ketujuh: kiriman yang belum diverifikasi tak boleh dibuang, tapi juga tak boleh diterima sebagai fakta. Membuangnya menghilangkan kerja terbaru pegawai; mengimpornya sebagai data resmi melompati peninjauan yang sedang mereka tunggu.

Hambatan kedelapan: sistem baru punya kolom wajib, sedangkan data lamanya kosong. Menjadikan kolom itu opsional demi migrasi adalah alternatif yang ditolak.

Hambatan kesembilan: tahap-tahapnya saling bergantung, dan setiap tahap harus bisa diulang. Keluarga tak bisa diimpor sebelum pegawai pemiliknya, dan dokumen tak bisa sebelum record yang dilekatinya. Menjalankan satu tahap dua kali tak boleh menggandakan apa pun.

Hambatan kesepuluh: baris yang buruk tak boleh menghentikan run, tapi juga tak boleh lolos diam-diam. Berhenti di persoalan pertama membuat migrasi mustahil selesai; melewatinya tanpa suara membuatnya mustahil dipercaya.

Hambatan kesebelas: identitas tak bisa diandalkan untuk menyatukan orang. Nomor identitas yang tak sah atau ganda, anak yang sama sekali tak punya nomor identitas, anak yang tak tertaut ke perkawinan mana pun. Menggabungkan record berdasarkan apa pun yang kebetulan cocok adalah alternatif yang ditolak.

Hambatan kedua belas: menentukan kapan sistem lama berhenti menjadi sumber. Karena ia terus berjalan, migrasi butuh batas waktu, dan memilih tanggal yang terasa pas adalah alternatif yang ditolak.

Hambatan ketiga belas: setiap gladi butuh titik awal yang cepat dan bisa dipercaya. Menjalankan ulang seluruh tahap dari nol untuk tiap uji terlalu lambat untuk sering berlatih.

Hambatan keempat belas: dokumen harus ikut pindah tanpa menahan yang lain. Ratusan ribu file tak bisa disalin dalam waktu yang dibutuhkan untuk mengimpor record-nya, dan record-nya tak bisa menunggu file-nya.

Urutannya mengikuti jalan yang ditempuh satu baris. Yang pertama menentukan bagaimana data lama boleh dibaca sama sekali. Yang kedua sampai keenam soal arti satu nilai. Yang ketujuh dan kedelapan soal apa yang boleh diterima sistem baru. Yang kesembilan sampai kesebelas soal menjalankan migrasi secara utuh, dan tiga terakhir soal menjalankannya berulang kali sampai sistem lama bisa ditinggalkan.

Metode

A. Pintu ke sumber yang hanya bisa membaca

Inilah jawaban atas hambatan pertama: setiap query ke database lama lewat satu class, dan class itu menegakkan akses hanya-baca dalam dua lapis yang saling lepas. Sebelum query pertama, sesi database-nya sendiri dialihkan ke mode hanya-baca, sehingga server menolak penulisan apa pun, terlepas dari hak akunnya. Lalu setiap pernyataan SQL diperiksa sebelum dikirim: ia wajib diawali kata kunci membaca, hanya satu pernyataan, dan tak memuat satu pun kata kunci yang menulis, mengunci, atau mengubah keadaan sesi.

php
private const LEADING = '/^(SELECT|WITH|SHOW|DESCRIBE|EXPLAIN)\b/i';
private const FORBIDDEN = '/\b(INSERT|UPDATE|DELETE|CREATE|ALTER|DROP|TRUNCATE|SET|CALL|INTO|LOCK)\b/i';

public function select(string $sql, array $bindings = []): array
{
    self::assertReadOnly($sql);   // tolak apa pun yang bukan satu pembacaan
    return $this->connection()->select($sql, $bindings);
}

Satu lapis saja biasanya sudah cukup. Dua lapis berarti kekeliruan di salah satunya — setelan sesi yang terlupa, pola yang melewatkan satu kata kunci — tetap tertangkap oleh yang lain, dan sumber kebenarannya tak pernah bergantung pada satu baris code yang kebetulan benar.

B. Menormalkan tiap nilai di tempat ia dibaca

Hambatan kedua dijawab kolom demi kolom, tepat ketika nilainya dibaca. Tanggal nol dan tahun mustahil menjadi kosong, tak pernah ditebak. Placeholder seperti tanda hubung atau titik dihitung kosong. Nomor identitas diperiksa panjang dan bentuknya, dan nomor yang tiba dalam notasi ilmiah dikenali sebagai rusak, bukan diperbaiki, sebab digit yang hilang tak bisa dikembalikan. Nilai yang tak bisa dinormalkan tidak dikarang; ia dilaporkan.

C. Perbaikan yang wajib membuktikan dirinya

Ketika tipe tak cocok dengan maknanya, saya hanya menerima perbaikan bila hasilnya jatuh di dalam rentang yang sah untuk nilai itu. Nilai kinerja yang kehilangan pemisah desimal hanya dibagi ulang bila hasilnya berada di antara nilai terendah dan tertinggi yang mungkin; selebihnya dilaporkan. Pangkat yang ditulis sebagai teks diterjemahkan lewat tabel ejaan yang dikenal, bukan diurai. Nominal gaji sama sekali tak diperbaiki: sistem baru menurunkannya dari tabel gaji resmi, jadi nominal ketikan tangan hanya dibandingkan, tak pernah dipercaya.

D. Teks bebas menjadi rujukan lewat peta eksplisit

Jawaban atas hambatan keempat adalah sekumpulan tabel pemetaan yang disimpan sebagai file CSV di repository, satu per jenis rujukan: instansi, program studi, gelar akademik, perangkat daerah. Masing-masing memetakan teks bebas atau identifier lama ke satu entri di tabel referensi baru. Duplikat di master data lama — instansi yang sama dimasukkan berkali-kali — diberi peta penggabungan, sehingga semuanya menunjuk satu entri. Alamat dicocokkan dengan kode wilayah resmi, dan alamat yang tak cocok disimpan sebagai teks lalu dilaporkan, bukan dipaksakan ke wilayah terdekat.

php
// teks bebas lama → id referensi, lewat peta yang eksplisit dan bisa ditinjau
$id = $institutionMap[normalise($row->institution)] ?? null;
if ($id === null) {
    $report->issue('INSTITUTION_UNMAPPED', "education:{$row->key}");   // simpan teksnya, tandai
}

Peta-peta itu dibangun oleh satu perintah yang mendaftar setiap nilai lama yang berbeda dan bisa menambahkan yang belum terpetakan, sehingga celah antara data lama dan petanya selalu terlihat dan menyempit di tiap putaran.

E. Membereskan data referensi sebelum menerjemahkan kode

Hambatan kelima dijawab dengan urutan yang disengaja. Pertama, tabel referensi sistem baru dilengkapi: setiap kode resmi yang dibutuhkan data lama, termasuk untuk jenis kepegawaian yang lebih baru, ditambahkan beserta nama dan dasar hukumnya. Baru sesudah itu tabel terjemahan dibangun, dari nomor baris internal sistem lama ke kode resmi. Membaca kolom status lama secara langsung akan tampak benar padahal keliru bagi sebagian besar pegawai, sebab nomor-nomornya kebetulan bertumpang tindih dengan kode sungguhan yang bermakna lain.

F. Membaca code lama, dan menjadikan makna eksplisit

Untuk hambatan keenam, saya membaca source code sistem lama, bukan hanya skemanya, karena sebagian aturan hanya ada di sana: status mana yang benar-benar berarti terverifikasi, di mana penolakan dicatat, untuk apa satu kolom sesungguhnya dipakai. Setiap temuan itu dijadikan eksplisit di sistem baru. Setiap istilah berkode mendapat tabel referensinya sendiri dengan kode, nama, deskripsi, dan — bila ada — peraturan yang mendasarinya, dan perilaku yang bergantung pada kode — misalnya apakah satu jenis cuti mengubah kedudukan hukum pegawai — menjadi kolom tabel referensi itu, bukan syarat yang terkubur di dalam code.

G. Data yang belum diverifikasi menjadi usulan

Jawaban atas hambatan ketujuh adalah mengimpor setiap baris, tapi tidak setiap baris sebagai fakta. Baris terverifikasi menjadi record resmi. Baris yang masih menunggu peninjauan dan berumur paling lama satu tahun menjadi usulan di alur peninjauan milik sistem baru, sehingga peninjau memutuskannya persis seperti memutuskan kiriman baru. Baris belum terverifikasi yang lebih tua menjadi usulan yang sudah ditolak sebagai kedaluwarsa oleh migrasi, sehingga tak ada yang hilang dan tak ada yang basi diterima diam-diam. Karena usulan hasil migrasi tak punya pengaju, ia tak bisa dikembalikan untuk diperbaiki; ia hanya bisa disetujui atau ditolak.

php
$state = match (true) {
    $row->verified            => 'official record',
    $row->ageInDays <= 365    => 'proposal: submitted',
    default                   => 'proposal: rejected (expired in migration)',
};

H. Yang wajib tetap wajib

Untuk hambatan kedelapan, setiap kolom wajib tetap saya biarkan wajib, dan nilai yang hilang diberi placeholder yang bisa dilacak. Nomor SK yang kosong menjadi penanda yang unik di dalam kolomnya dan mudah dicari, sehingga celahnya bisa didaftar lalu diisi belakangan oleh orang yang memegang arsip kertasnya. Ketika tanggal bisa diturunkan dengan jujur — pertengahan tahun ijazah diterbitkan, misalnya — ia diturunkan dengan cara yang konsisten; bila tidak bisa, ia dilaporkan.

php
// Kolom wajib yang dibiarkan kosong oleh data lama: tetap wajib,
// tapi celahnya dibuat bisa ditemukan, bukan diisi nilai karangan.
function placeholder(string $column, int $n): string
{
    return "Not yet recorded #{$n}";   // unik per kolom, bisa dicari
}

I. Tahap berurutan yang aman dijalankan dua kali

Hambatan kesembilan dijawab dengan memecah migrasi menjadi tiga belas tahap, masing-masing satu perintah, yang dijalankan menurut urutan ketergantungan datanya: pegawai, identitas, keluarga, karier, struktur organisasi, kinerja, angka kredit, kenaikan gaji berkala, jabatan, jabatan lama, riwayat lain, dokumen, dan terakhir usulan.

bash
import-legacy employees --dry-run          # batalkan tiap chunk, laporan saja
import-legacy family --id=1042,1043        # gladi pada beberapa pegawai
import-legacy documents --cutoff="$CUTOFF"       # momen yang disepakati

Setiap tahap bersifat idempoten. Setiap baris hasil impor membawa sumber asalnya dan kuncinya di sumber itu, dan run kedua memperbarui baris yang sudah ada, bukan membuat baris baru. Dry run menjalankan tahapnya lalu membatalkan setiap chunk, sehingga gladi penuh tak meninggalkan apa pun selain laporannya, dan satu tahap bisa dicoba pada segelintir pegawai sebelum dijalankan untuk semua.

J. Laporan, bukan crash

Untuk hambatan kesepuluh, setiap tahap menulis laporan dengan satu baris per persoalan dan kode yang tetap untuk jenis persoalannya: nomor identitas tak sah, nomor identitas yang tak cocok dengan tanggal lahir, relasi keluarga yang terpaksa ditolak, pasangan yang menunjuk pegawai itu sendiri, nilai di luar rentangnya. Run-nya tetap berjalan, dan laporannya adalah daftar apa yang tak bisa ia terima.

php
// jalan terus, tapi catat persis apa yang tak diterima: kode dan kunci, tanpa nama
$report->issue('IDENTITY_NUMBER_INVALID', "employee:{$row->key}");
$report->issue('RELATION_REJECTED', "family:{$row->key}");

Laporan itu sengaja tak memuat data pribadi — hanya kode dan kunci — sehingga bisa diserahkan ke tim kepegawaian untuk ditinjau tanpa menjadi persoalan privasi tersendiri. Menghitung kode-kodenya sesudah tiap run juga menunjukkan apakah datanya makin bersih dari satu putaran ke putaran berikutnya.

K. Relasi dibangun, bukan ditebak

Hambatan kesebelas dijawab dengan memodelkan keluarga sebagai graf orang, perkawinan, dan relasi orang tua–anak, serta menolak menggabungkan orang berdasarkan bukti yang lemah. Nomor identitas yang tak sah atau muncul dua kali tidak menyatukan dua record menjadi satu. Anak yang tak bisa ditempatkan di perkawinan tertentu ditautkan ke pegawainya saja. Setiap penolakan muncul di laporan, sehingga kasus yang butuh keputusan manusia terdaftar, bukan terselesaikan secara kebetulan.

L. Cut-over yang diambil dari bukti

Untuk hambatan kedua belas, saya membiarkan datanya yang memilih batas. Setiap record dokumen saya cocokkan dengan daftar file yang benar-benar ada di server lama. Sampai satu malam tertentu, hampir setiap record punya file-nya; sesudahnya, hampir tak ada. Momen itulah yang menjadi cut-over, dan setiap query ke database lama kini membawanya sebagai syarat, sehingga seluruh tahap sepakat persis baris mana yang termasuk migrasi. Ia berupa setelan, bukan konstanta, jadi tiap gladi bisa menggesernya.

sql
-- setiap query sumber dibatasi pada momen yang sama;
-- baris tanpa timestamp adalah data lama dan ikut terbawa
AND (created_at IS NULL OR created_at <= :cutoff)

M. Titik awal yang hanya dipakai bila cocok

Hambatan ketiga belas dijawab dengan menyimpan dump data-saja dari migrasi yang sudah tuntas, lalu me-restore-nya ke skema hasil migrasi baru setiap kali saya ingin memulai gladi dari keadaan yang terbukti baik. Restore hanya berjalan bila kedua skemanya identik, yang dicek dulu dengan membandingkan dump skema-saja. Me-restore data lama ke skema yang sudah berubah akan menghasilkan database yang tampak benar tapi keliru secara halus, dan itu lebih buruk ketimbang menunggu run penuh.

N. Dokumen yang menyusul dengan iramanya sendiri

Untuk hambatan keempat belas, record dokumen diimpor bersama yang lain, dan file-nya menyusul terpisah. Setiap dokumen mempertahankan path aslinya sebagai kuncinya di object storage, sehingga record-nya sudah tahu di mana file-nya akan berada. Selama file belum tersalin, dokumen tampil sebagai belum tersedia, bukan rusak. Setiap file diperiksa jenis isinya yang sebenarnya sebelum diterima, apa pun nama yang dibawanya.

Hasil dan Pembahasan

A. Hasil satu putaran penuh

Satu putaran penuh kini menjalankan ketiga belas tahap terhadap salinan baru database lama dalam waktu jauh di bawah satu jam, dan meninggalkan dua hasil: database baru yang setiap nilai berkodenya merujuk tabel referensi dan setiap relasinya menunjuk record yang benar-benar ada, serta sekumpulan laporan yang mendaftar, menurut kodenya, setiap baris yang ditolak migrasi. Gladi sudah menjadi rutinitas, bukan peristiwa — itulah yang dibutuhkan migrasi yang berjalan berdampingan dengan sistem yang masih hidup.

B. Kenapa laporan lebih penting ketimbang code-nya

Keluaran yang paling berguna ternyata laporannya, bukan datanya. Laporan mengubah "data lamanya berantakan" menjadi daftar yang bisa dikerjakan tim kepegawaian, diurutkan menurut jenis persoalan, tanpa data pribadi di dalamnya. Setiap putaran menunjukkan kode mana yang menyusut, sehingga pertanyaan apakah migrasi sudah siap berhenti menjadi perasaan dan berubah menjadi satu angka per kode.

C. Di mana pendekatan ini cocok

Bentuk ini cocok untuk migrasi apa pun yang sumbernya terus berjalan dan datanya tak pernah dikekang: tahap berurutan, pintu hanya-baca, peta eksplisit, placeholder yang jujur, dan laporan ketimbang crash. Kerjanya lebih banyak daripada satu script, dan untuk sekali salin data yang sudah bersih ia berlebihan. Untuk sumber yang aturannya hidup di kebiasaan orang dan bukan di database-nya, inilah pembeda antara migrasi yang selesai dan migrasi yang bisa dipercaya.

Simpulan

Bagian tersulit dari memindahkan database kepegawaian lama tak pernah jumlah barisnya. Bagian tersulitnya adalah data lama merekam kebiasaan, bukan aturan, sedangkan sistem baru bertindak berdasarkan aturan. Setiap keputusan di atas berangkat dari penolakan untuk mengaburkan perbedaan itu: data lama dibaca tapi tak pernah disentuh, setiap nilai diterjemahkan lewat peta yang eksplisit, tak ada yang tak sah diterima sebagai fakta, dan tak ada yang hilang dikarang.

Satu kebiasaan yang akan saya bawa ke migrasi mana pun: melapor, bukan menebak. Migrasi yang berhenti di baris buruk pertama tak bisa selesai, dan yang diam-diam melewatinya tak bisa dipercaya; migrasi yang terus berjalan sambil mencatat, dalam bentuk yang bisa ditindaklanjuti orang, persis apa yang tak mau ia terima, bisa dijalankan sesering yang dibutuhkan sampai tak ada lagi yang perlu dicatat.

Istilah

Migrasi
Memindahkan data dari sistem lama ke sistem baru, sekaligus menerjemahkannya ke struktur dan aturan sistem baru di perjalanan.
Idempoten
Aman dijalankan lebih dari sekali: run kedua menghasilkan keadaan yang sama dengan run pertama, bukan menciptakan duplikat.
Foreign key
Aturan database bahwa nilai di satu tabel wajib merujuk baris yang ada di tabel lain, sehingga relasi tak bisa menunjuk kekosongan.
Tabel referensi
Tabel yang mendaftar nilai sah dari kolom berkode, masing-masing dengan kode, nama, dan arti, yang dirujuk record lain.
Cut-over
Momen sesudahnya sistem lama tak lagi diperlakukan sebagai sumber data yang dimigrasikan.
Dry run
Menjalankan satu langkah secara penuh tapi membuang perubahannya, sehingga efek dan laporannya terlihat tanpa disimpan.

Technologies covered

  • PHP

About the author

Photo of Romi Fadli

Romi Fadli, S.Kom.

Solution Architect · Backend Engineer · Embedded Systems

In my day job I work as a solution architect. I design the system, lead the team that builds it — quality assurance, backend developers, a UI developer, DevOps and DevSecOps — and write the most critical modules myself, such as a certificate authority, a long-term PDF signer, and the core API of a personnel system.

I work across the whole stack that a running system actually needs. On the hardware side that means PCB design, microcontrollers, and embedded firmware — including RISC-V boards running FreeRTOS and Embassy, speaking MQTT over mutually authenticated TLS on a microcontroller with 64 KB of SRAM.

Most of my day-to-day work is software: Rust backends and API modules built on Clean Architecture, an OAuth2/OpenID Connect authorization server written from scratch, PAdES document signing, and certificate authorities — root CAs, timestamping authorities, and OCSP responders. I also build the frontends that sit on top of them.

Running all of that means infrastructure: Docker Compose stacks, networking, Mikrotik and RADIUS, observability with OpenTelemetry, and a steady habit of writing command-line tools and utilities for Linux when the existing ones do not fit.

Share

Enjoyed this?

Get an email when a new article is published.

Referenced by

Employees and administrators use the Web App, which talks to the Core API; the Core API uses storage, regions, face and preview services, sends documents to the Aurograf signing platform, sends logs and traces to the log stack, and imports from the old system

SIMPEG

Programming

Sistem informasi kepegawaian Pemerintah Kota Tangerang Selatan: pegawai mengurus record-nya sendiri dan mengikuti layanannya, admin bekerja tepat pada bagian organisasinya, dan setiap aturan berasal dari peraturan yang menetapkannya. Saya pimpin dan bangun sejak 2023.

10 min read Read more →
The core API at the centre, fed by storage, address, face and preview services, with documents sent across a boundary to an external signing platform

Inti Laravel sistem kepegawaian aparatur sipil negara: record pegawai dan riwayat karier, usulan swalayan yang diperiksa, keputusan kenaikan gaji berkala, kenaikan pangkat, dan pensiun, aturan dari peraturan, bagan organisasi berversi, dan akses berlingkup sampai satu unit.

11 min read Read more →

Related Articles