Skip to content

AGA — Address Gateway

By Romi Fadli, S.Kom. 10 min read Storage & Data
On this page
A four-level tree of Indonesian regions, with one chosen path coloured level by level, feeding a form of four cascading dropdowns in the same colours

AGA — Address Gateway — adalah service HTTP kecil berbahasa Rust yang menjawab satu pertanyaan bagi aplikasi mana pun yang meminta alamat Indonesia: provinsi apa saja yang ada, kabupaten dan kota mana yang termasuk satu provinsi, kecamatan mana yang termasuk satu kabupaten, dan desa mana yang termasuk satu kecamatan. Seluruh hirarki administratif ikut di dalamnya — 38 provinsi sampai 83.768 desa, berkunci kode wilayah resmi Kementerian Dalam Negeri — dan disajikan sebagai empat lookup pendek, masing-masing satu tingkat lebih dalam dari sebelumnya.

Saya membangunnya sekali lalu memakainya ulang di setiap project yang punya form alamat, karena semuanya butuh dropdown bertingkat yang sama, kode yang sama, dan pencarian yang sama. Menyimpan salinan delapan puluh ribu desa di dalam tiap aplikasi berarti delapan puluh ribu baris yang harus dijaga tetap identik di mana-mana. Satu service dengan satu salinan data membuat semua aplikasi mendapat jawaban yang sama.

Sekilas

Bahasa & frameworkRust, dengan actix-web dan sqlx di atas PostgreSQL
ArsitekturClean Architecture
Versi2.1.0
StatusStabil, berjalan di production
BentukService HTTP mandiri di belakang API gateway, dipakai ulang lintas project
Kode sumberPrivat
Apa module ini dan bagaimana keadaannya.

Yang dikerjakannya

A. Menyajikan hirarki administratif setingkat demi setingkat

Form alamat mengisi dropdown-nya berurutan: provinsi dulu, lalu kabupaten atau kota di dalamnya, lalu kecamatan, lalu desa. AGA mengikuti urutan itu persis. Tiap lookup menerima kode yang dipilih satu tingkat di atasnya dan mengembalikan tingkat di bawahnya, terurut menurut nama, jadi form tak pernah mengunduh lebih dari daftar yang akan segera ditampilkannya.

B. Memakai kode wilayah resmi sebagai identitas

Tiap wilayah dikenali dari kode bertitik Kementerian Dalam Negeri — 11 untuk provinsi, 11.01 untuk kabupaten, 11.01.01 untuk kecamatan, 11.01.01.2001 untuk desa — bukan dari nomor internal. Aplikasi bisa menyimpan kode itu di samping alamat dan membacanya kembali bertahun-tahun kemudian, dari AGA atau dari sumber lain yang memakai kode yang sama.

C. Mencari wilayah dari potongan namanya

Setiap lookup menerima kata pencarian opsional yang dicocokkan di bagian mana pun dari nama, tanpa peduli huruf besar-kecil. User yang mengetik beberapa huruf nama desa hanya melihat desa yang cocok. Kata pencarian dipangkas spasinya, yang kosong berarti tanpa filter, dan jumlah hasilnya dibatasi supaya pencarian satu huruf tetap murah.

D. Membawa datanya sendiri

Tabel dan seluruh data ikut dikompilasi ke dalam service, dalam bentuk migration database. Database kosong menjadi API wilayah yang lengkap dalam satu kali start, tanpa langkah import terpisah dan tanpa file yang harus diunduh.

E. Melaporkan dengan jujur apakah ia sanggup menjawab

Readiness check meminta jawaban sepele dari database dan baru melapor 200 bila jawaban itu datang, 503 bila tidak. Dengan begitu platform container atau service induk bisa membedakan AGA yang sekadar hidup dari AGA yang benar-benar bisa melayani.

Antarmuka

KemampuanKegunaan
Provinsisemua provinsi
Kabupaten dan kotakabupaten dan kota dalam satu provinsi
Kecamatankecamatan dalam satu kabupaten atau kota
Desadesa dalam satu kecamatan
Readinessapakah database menjawab; tanpa autentikasi
Versinama dan versi service; tanpa autentikasi
Antarmuka HTTP AGA; setiap lookup juga menerima kata pencarian.

AGA bisa dipasang di route mana pun pada gateway, dan setiap lookup menjawab dengan envelope yang sama, berisi request id kiriman pemanggil atau yang dibuat AGA sendiri:

json
{
  "status": { "code": 200, "message": "Ok" },
  "request_id": "0199a3c2-5f1e-7c4b-9d2a-6e8f1b3c5a70",
  "data": [
    { "id": "11.01", "province_id": "11", "name": "KAB. ACEH SELATAN" },
    { "id": "11.02", "province_id": "11", "name": "KAB. ACEH TENGGARA" }
  ]
}

Standar

StandarYang dijaminnya di sini
Kode wilayah Kementerian Dalam Negeriidentitas yang dikenali sistem lain di Indonesia, divalidasi per tingkat
W3C Trace Context dan OpenTelemetry (OTLP, semantic conventions)trace, log, dan metrics yang menyambung trace pemanggil lintas service
UUIDv7request id yang tak pernah bertabrakan dan terurut menurut waktu
OpenAPI 3.0.3kontrak setiap endpoint yang terbaca mesin
Standar yang dipatuhi AGA, dan yang dijamin masing-masing.

Di dalamnya

AGA mengikuti Clean Architecture. Domain memegang keempat wilayah, format kodenya, serta aturan untuk nama dan kata pencarian. Lapisan application memegang satu use case per lookup beserta port yang dibutuhkannya — repository per tingkat, health check database, dan authenticator. PostgreSQL, identitas dari gateway, konfigurasi, dan telemetry masing-masing tinggal di lapisan infrastructure, dan satu composition root menjadi satu-satunya tempat yang mengenal keempat lapisan sekaligus. Karena tiap use case menerima repository-nya lewat port, 60 test-nya berjalan dengan repository in-memory dan health check palsu, tanpa database.

Keputusan rancangan

Data ikut di dalam binary, dan memuatnya adalah keputusan, bukan efek samping. Migration saya kompilasi ke dalam service, jadi image yang berjalan adalah image yang membawa data, dan tak ada deployment yang bisa memasangkan satu versi kode dengan versi wilayah yang lain. Menjalankannya bersifat opt-in lewat flag konfigurasi, sebab service yang menulis ulang skemanya setiap kali start adalah service yang bisa mengejutkan database production. Migration berjalan di koneksinya sendiri dengan statement logging dimatikan. Seed desa berupa satu insert hampir lima megabyte; library database mencatatnya utuh sebagai slow statement, dan satu catatan itu lebih besar dari batas yang diterima collector telemetry, sehingga collector membuang seluruh batch tempat ia tiba — termasuk log lain yang tak berkaitan. Saat start, service juga meminta jawaban sepele dari database dan mencatat hasilnya tanpa menolak start, supaya database yang masih booting tak ikut menjatuhkan service.

Setiap baris mengenal seluruh garis leluhurnya. Desa menyimpan kodenya sendiri dan juga kode kecamatan, kabupaten, dan provinsinya. Tiap kolom itu berindeks dan terikat ke tabel induknya. Ongkosnya beberapa byte per baris; imbalannya lookup yang tak pernah butuh join di tingkat mana pun, dan ruang untuk pertanyaan baru seperti "semua desa di provinsi ini" tanpa mengubah skema. Nama juga berindeks, untuk pencarian.

Input yang tak sah berhenti di pintu, dan data yang tak sah tak pernah keluar. Tiap tingkat punya format kodenya sendiri, diperiksa regular expression di domain sebelum query disusun. Kode yang cacat menjadi 400 dengan pesan yang menyebut field-nya, bukan daftar kosong yang tampak seperti jawaban. Nama dipangkas spasinya, tak boleh kosong, dan tak boleh melebihi lebar kolomnya. Aturan yang sama berlaku ke arah sebaliknya: baris database yang melanggarnya diperlakukan sebagai kegagalan server dan dicatat, tak diteruskan ke form. Kata pencarian dipangkas, dibatasi panjangnya, selalu dikirim ke database sebagai bound parameter dan tak pernah ditempel ke dalam query, dan hasilnya dibatasi serta terurut menurut nama.

Siap berarti database menjawab. Versi sebelumnya punya health check di root yang selalu menjawab 200 karena tak memeriksa apa pun. Container yang sudah kehilangan database-nya tetap tampak sehat, dan service di depannya tak bisa tahu. Saya menggantinya dengan readiness check di bawah prefix service sendiri, yang menjalankan query sepele dan mengembalikan 503 dengan body datar yang menyebut dependensi yang gagal — bentuk yang sama dengan module lain di sampingnya, supaya satu pemeriksaan gabungan bisa membaca semuanya. Check lama saya hapus, tak saya pertahankan berdampingan, dan test yang membuktikan 503 itu dibuktikan sendiri lewat sabotase: memaksa handler selalu menjawab 200 membuat test-nya gagal.

Identitas datang dari gateway, bukan dari token. AGA berada di belakang API gateway yang mengautentikasi setiap pemanggil dan hanya meneruskan identitas yang sudah terverifikasi — kontrak yang sama dengan module saya yang lain — dan identitas itu dicatat di trace request.

Satu kontrak, dijaga persis. Setiap respons membawa envelope yang sama dan request id — diterima dari pemanggil atau dibuat sendiri — yang juga dipantulkan di header. Body 400 satu-satunya pengecualian yang disengaja: ia tak memuat request id di dalam body, karena versi yang digantikan AGA pun tidak, dan aplikasi sudah mem-parse bentuk itu byte demi byte.

Setiap request bisa diikuti lintas service. Telemetry pindah dari menulis langsung ke Elasticsearch menjadi OpenTelemetry lewat collector. Trace context yang masuk dilanjutkan, sehingga satu lookup tampil sebagai anak dari halaman yang memintanya. Metrics memakai delta temporality, karena exporter Elasticsearch milik collector membuang histogram dan counter yang kumulatif. Metrics HTTP diberi label pola route, bukan path mentah, supaya seratus ribu kode tak berubah menjadi seratus ribu deret. Alamat client diambil dari header forwarded hanya bila datang dari trusted proxy, dan telemetry bisa dimatikan sehingga yang tersisa stdout, dengan flush saat shutdown ketika ia menyala. Jalur trace hanya melihat span: sebelum perubahan itu, setiap baris log terekspor dua kali, sekali sebagai span event dan sekali sebagai log record.

Ia penyedia, jadi pemakainya yang memegang deployment. Image dibangun dua tahap, berjalan sebagai user non-root, dan membaca konfigurasinya dari file yang di-mount. AGA tak lagi membawa deployment sendiri: tiap project yang memakainya menjalankannya di dalam stack project itu, dengan database dan collector-nya sendiri, karena project itulah yang tahu bagaimana ia di-backup dan ke mana telemetry-nya pergi.

Spesifikasi

MasukanRequest dari aplikasi di belakang API gateway, membawa identitas yang terverifikasi
HasilDaftar wilayah beserta kode, kode induk, dan namanya, dalam satu envelope JSON
Data38 provinsi, 514 kabupaten dan kota, 7 277 kecamatan, 83 768 desa
PenyimpananPostgreSQL, dengan tabel dan data yang dipasang lewat migration tertanam
BatasKata pencarian dan hasilnya sama-sama dibatasi
ObservabilityTrace, log, dan metrics OpenTelemetry lewat OTLP, atau stdout saja
Test60, tanpa database
Berjalan sebagaiImage container yang dibangun dua tahap, sebagai user non-root, dengan konfigurasi di-mount dari file
Yang diterima, dikembalikan, dan dibutuhkan AGA.

Terkait

Ke mana trace, log, dan metrics AGA pergi setelah meninggalkan service.

Istilah

Hirarki administratif
Empat tingkat wilayah Indonesia yang bersarang: provinsi, kabupaten atau kota, kecamatan, dan desa.
Kode wilayah
Identitas bertitik yang diberikan Kementerian Dalam Negeri kepada tiap wilayah, makin panjang di tiap tingkat, seperti 11.01.01.2001.
Migration
Script berversi yang mengubah skema atau data database, dijalankan sekali dan dicatat supaya tak pernah dijalankan dua kali.
Readiness check
Endpoint yang melaporkan apakah service sanggup melayani request saat ini, bukan sekadar apakah prosesnya hidup.
API gateway
Service di depan service lain yang mengautentikasi pemanggil dan hanya meneruskan identitas yang sudah terverifikasi.
Port
Interface yang didefinisikan lapisan dalam dan diimplementasikan lapisan luar, supaya aturan tak pernah bergantung pada tool tertentu.

Technologies covered

  • Rust
  • PostgreSQL
  • OpenTelemetry

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 →
A central core holding people, organisations, documents, and certificates, connected to eight surrounding services for storage, addresses, certificates, timestamps, the root, signing, thumbnails, and face challenges

Inti Laravel dari platform penandatanganan dokumen: memegang user, identitas, organisasi, sistem client, dokumen beserta versi bertanda tangannya, stempel, dan sertifikat, serta mengorkestrasi service yang menandatangani, menstempel waktu, merender, dan menyimpan — tanpa pernah memegang file.

9 min read Read more →
A purple root circle linked to a blue and an orange intermediate circle, which lead to a signed document with a green seal and to a clock.

Aurograf

DevOps

Platform tanda tangan digital Pemerintah Kota Tangerang Selatan: penanda tangan membuktikan identitasnya, menandatangani PDF hingga PAdES B-LTA dengan sertifikat dari otoritas milik platform sendiri, dan siapa pun bisa memverifikasinya — versi 2, yang saya rancang, bangun, dan operasikan.

10 min read Read more →

Related Articles