Skip to content
Blog Programming

Bagaimana Saya Mengubah Bentuk Dokumen Sendiri Tanpa Meninggalkan Mesin Sendiri

By Romi Fadli, S.Kom. 18 min read Tooling & Automation
On this page
Three rows inside a dashed boundary: images combining into one PDF, a PDF splitting into images, and a PDF becoming smaller

Tiap beberapa bulan sekali ada saja yang meminta dokumen saya dalam bentuk yang kebetulan tidak saya punya. Empat foto yang harus jadi satu PDF. PDF yang harus di bawah dua megabyte. Dokumen hasil generate yang layout-nya perlu saya periksa halaman demi halaman sebelum dilihat orang lain. Tak satu pun dari ketiganya sulit. Ketiganya, secara bawaan, diselesaikan dengan mengunggah dokumen itu ke situs milik orang yang tak pernah saya temui.

Pendahuluan

A. Berapa ongkos sebenarnya jalan yang paling mudah

Cari salah satu konversi itu, dan halaman pertama hasil pencarian penuh tool web gratisan. Mereka bekerja. Pilih file, terunggah, beberapa detik kemudian ada yang kembali. Gesekannya begitu kecil sampai pertanyaan apakah mengunggah tadi ide bagus tak pernah sempat terbentuk.

Ongkos yang kelihatan adalah yang biasa dikeluhkan orang: watermark tercap melintang di hasilnya, batas ukuran di tier gratis, kuota harian yang di-reset tengah malam, dan tawaran berbayar untuk melenyapkan ketiganya. Semua itu menjengkelkan, dan semua itu bukan ongkos yang sebenarnya.

Ongkos sebenarnya: salinan dokumen itu kini berada di mesin yang tak saya kendalikan, di bawah syarat yang tak saya baca, disimpan selama jangka waktu yang tak pernah diberitahukan. Untuk screenshot laporan bug, itu tak relevan. Untuk KTP, ijazah, kontrak, atau dokumen kepegawaian, justru di situlah seluruh perkaranya — dan dokumen semacam itulah yang persis diminta diubah bentuknya oleh urusan administratif, sebab dokumen semacam itulah yang jadi pokok urusan administratif.

B. Tiga bentuk, satu keadaan

Pekerjaannya terbelah jadi tiga operasi yang tampak tak berhubungan, padahal berhubungan.

Gambar-gambar jadi satu PDF. Foto atau screenshot yang diminta sebuah form sebagai satu lampiran tunggal. Inilah permintaan yang paling sering datang, dan yang paling kentara mengundang pemakaian tool web.

PDF jadi gambar-gambar. Kebalikannya, dan yang motifnya paling tak kentara. Saya memakainya untuk memeriksa layout dokumen hasil generator, satu halaman demi satu halaman, dan untuk menarik slide dari sebuah deck jadi gambar terpisah. Ini pemeriksaan, bukan pengiriman.

PDF yang dikecilkan. Sama sekali bukan pergantian format, melainkan pergantian ukuran, sebab kolom unggah memutuskan bahwa batasnya dua megabyte sementara dokumennya tiga.

Yang mengikat ketiganya bukan format file-nya. Melainkan bahwa ketiganya adalah perlakuan yang ingin saya berikan kepada dokumen yang semestinya tidak meninggalkan mesin tempatnya berada.

C. Apa nilainya "di mesin sendiri"

Mengerjakannya secara lokal membeli tiga keuntungan, dan cuma satu di antaranya soal privasi.

Pertama, tak ada batas. Tak ada kuota harian, tak ada plafon ukuran, tak ada watermark pada konversi kelima puluh dalam sehari. Tool yang berjalan lokal tak punya model bisnis yang bergantung pada membuat versi gratisnya terasa sedikit menyakitkan.

Kedua, ia bisa disusun bersama yang lain. Perintah lokal bisa dipanggil dari dalam script, dirangkai sesudah generator dokumen, atau dijalankan berulang menyisir isi folder. Situs web tak bisa dipanggil dari apa pun; ia cuma bisa dikunjungi.

Ketiga, dokumennya tetap di tempatnya. Justru keuntungan itulah yang membuat saya menulis ketiganya ketimbang menyimpan bookmark, tapi ia sendirian takkan cukup — privasi saja biasanya kalah oleh kenyamanan, dan alasan jujur ketiganya ada adalah versi lokalnya ternyata lebih nyaman juga.

D. Ketiga tool ini apa

Tiga program kecil. Dua ditulis Python, dibangun di atas library yang sudah memecahkan bagian sulitnya — Pillow untuk gambar, pdf2image untuk merender halaman PDF. Satunya lima baris shell yang membungkus Ghostscript, interpreter open-source lawas yang membaca dan menulis ulang file PDF maupun PostScript.

Tak satu pun memuat algoritma orisinal. Konversinya sendiri sudah terpecahkan ke segala arah, dan tak sedikit pun saya yang memecahkannya. Artikel ini bicara soal lapisan di atasnya: default mana yang dipatok, keputusan mana yang diambil mewakili pemakainya, dan di mana script lima baris justru jawaban yang tepat ketimbang sebuah program.

E. Enam hambatan yang menghalangi

Jadi tujuannya gampang dirumuskan: sanggup mengubah bentuk dokumen saya sendiri — menggabung, memecah, mengecilkan — sepenuhnya di mesin tempatnya sudah berada, tanpa batas pemakaian dan tanpa menyerahkan apa pun ke pihak ketiga. Cukup nyaman sampai saya benar-benar meraihnya, bukan meraih situsnya.

Gampang dirumuskan, canggung dibangun. Enam hambatan berdiri antara tujuan itu dan tiga perintah yang saya pakai tanpa berpikir, dan yang pertama adalah alasan kenapa lima sisanya pernah sepadan dengan usahanya.

Yang pertama, jalan yang nyaman menuntut penyerahan dokumennya lebih dulu sebelum ia mau menolong. Konverter web butuh file terunggah sebelum berbuat apa-apa, artinya keputusan memakainya diambil sebelum ada hasil apa pun untuk menilainya. Alternatif yang ditolak cukup memberi pelajaran: software desktop berbayar memang memecahkan soal privasinya tapi menuntut bayaran untuk pekerjaan yang semestinya sebuah perintah, sementara "pilih saja situs yang bereputasi" bukan pertahanan, sebab reputasi bukan sifat yang bisa saya verifikasi dari luar.

Yang kedua, script Python bukan perintah. Kedua tool gambar bergantung pada library yang tak terpasang secara bawaan. Itu membuat keduanya script yang menuntut interpreter, virtualenv, dan kedisiplinan menjaga virtualenv itu tetap utuh melewati tiap upgrade sistem. Tool yang menuntut perawatan sebelum dipakai adalah tool yang akan saya hindari persis pada saat saya sedang terburu-buru — dan itu artinya tiap kali saya membutuhkannya.

Yang ketiga, PDF menolak gambar yang di mana pun sebenarnya sah. Screenshot hampir selalu membawa alpha channel, dan PDF tak mengenal konsep itu. Diberi gambar semacam itu secara langsung, penyimpanannya gagal — pada input yang paling umum yang ada, dihasilkan oleh cara paling umum menghasilkannya.

Yang keempat, mengecilkan gambar bukan aritmetika seperti yang terlihat. Meminta "lima puluh persen" lalu membagi dua lebarnya menghasilkan gambar berluas seperempat, dan itu bukan yang dimaksud siapa pun. Batas ukuran dinyatakan dalam megabyte, megabyte mengikuti luas, dan luas adalah kuadrat dari dimensi liniernya. Keliru di sini menghasilkan keluaran yang jauh lebih kecil dari yang diminta sambil tampak seperti berhasil.

Yang kelima, arah sebaliknya menghasilkan banyak file dan bukan satu, sehingga penamaan jadi pertanyaan sungguhan. Memecah PDF melahirkan satu folder, dan menjalankan perintah yang sama dua kali adalah keadaan yang normal — sekali untuk melihat, sekali lagi sesudah ada yang diperbaiki. Perilaku yang paling kentara adalah menulis ke folder yang sama, dan itu diam-diam memusnahkan hasil pertama persis pada saat ia hendak dibandingkan dengan yang kedua.

Yang keenam, mengecilkan PDF adalah jenis operasi berbeda dengan jenis kendali yang berbeda pula. Gambar menerima persentase. PDF tidak: tool yang mengerjakannya dengan baik menerima profil kualitas, bukan ukuran sasaran, dan tak ada cara menyuruh "buat ini muat di bawah dua megabyte". Ukurannya jadi akibat, bukan perintah.

Masing-masing punya seksi di bawah. Dua yang pertama menentukan apakah tool ini terpakai sama sekali; tiga berikutnya menentukan apakah tiap arah mengerjakan tugasnya dengan benar; yang terakhir soal memilih batas ketimbang merekayasa jalan memutarinya.

Metode

A. Membiarkan dokumennya tetap di tempatnya

Inilah jawaban atas hambatan pertama, dan ia lebih berupa keputusan ketimbang teknik: konversinya berjalan sebagai perintah lokal, sehingga pertanyaan tentang apa yang disimpan layanan jarak jauh tak pernah muncul sama sekali.

Yang membuatnya praktis adalah bagian sulitnya sudah terpecahkan dan tinggal dipasang. Pillow mengurus pembacaan gambar dan keluaran PDF; pdf2image merender halaman PDF lewat Poppler; Ghostscript menulis ulang PDF. Tak satu pun perlu dibuat, dan tak satu pun menelepon ke mana-mana.

bash
# the whole point, expressed as three commands
img2pdf ~/scan/ ~/submit/lampiran.pdf     # images  -> one PDF
pdf2img ~/submit/lampiran.pdf ~/periksa/  # PDF     -> one image per page
pdf-compress besar.pdf kecil.pdf          # PDF     -> smaller PDF

Keuntungan kedua langsung terlihat dari bentuk itu. Ketiganya perintah, jadi ketiganya bisa duduk di dalam script yang menghasilkan dokumen lalu seketika merendernya jadi gambar untuk diperiksa. Rangkaian semacam itu sama sekali tak tersedia ketika langkah konversinya berupa situs web.

B. Menjadikannya perintah, bukan script

Inilah jawaban atas hambatan kedua. Kedua tool Python dikemas jadi executable tunggal memakai PyInstaller, dan alasannya perawatan, bukan pendistribusian.

python
exe = EXE(
    pyz, a.scripts, a.binaries, a.datas,
    name='img2pdf',
    upx=True,          # compress the bundle; ~15 MB instead of more
    console=True,      # it is a terminal tool, not a window
)

Bundel membawa interpreter-nya sendiri beserta salinan tiap library yang ia import. Ongkosnya ukuran: kira-kira lima belas megabyte untuk mengantarkan tiga ratus baris kode buatan saya, perbandingan yang akan terdengar konyol seandainya alternatifnya tidak lebih buruk. Alternatifnya adalah virtualenv di suatu sudut home directory yang harus bertahan melewati tiap upgrade Python yang diputuskan sistem, dan yang akan saya ketahui rusaknya justru saat saya sudah telat mengurus sesuatu.

Saya ingin tepat soal kenapa pertukaran ini benar di sini dan tidak secara umum. Ini tool yang dipakai segelintir kali dalam sebulan, oleh satu orang, di satu mesin, di mana mode kegagalan berupa environment rusak terasa jauh lebih menjengkelkan ketimbang sedikitnya pekerjaan yang tool ini lakukan. Lima belas megabyte di disk yang masih lapang ratusan gigabyte bukan ongkos sungguhan. Seandainya ini library yang di-import kode lain, atau program yang dikirim ke armada mesin, perhitungannya akan sama sekali berbeda.

C. Memberi PDF gambar yang mau ia terima

Inilah jawaban atas hambatan ketiga, dan ia dua baris yang ditaruh sebelum apa pun menyentuh gambarnya.

python
img = Image.open(img_file)

# PDF has no alpha channel; screenshots almost always do
if img.mode != 'RGB':
    img = img.convert('RGB')

Screenshot datang sebagai RGBA, PNG bertransparansi datang sebagai RGBA atau LA, dan sesekali hasil scan datang sebagai greyscale satu kanal. Model pencitraan PDF tak mengenal transparansi dalam bentuk yang dibawa ketiganya, jadi penyimpanannya gagal ketimbang diam-diam memipihkannya.

Mengonversi tanpa pandang bulu ketika mode-nya apa pun selain RGB adalah versi tumpul dari ini, dan tumpul memang yang benar. Alpha channel yang terbuang adalah transparansi yang memang tak saya inginkan pada dokumen yang tujuannya dicetak atau dikirim, sementara greyscale yang dinaikkan jadi RGB cuma menambah sedikit ukuran file dan tak lebih. Alternatifnya — menangani tiap mode lewat cabangnya sendiri — berarti lebih banyak kode demi pembedaan yang tak lagi berarti begitu tujuannya sebuah halaman.

D. Mengecilkan menurut luas, bukan menurut lebar

Inilah jawaban atas hambatan keempat, dan inilah satu baris di ketiga tool ini yang paling saya sukai.

python
scale = (compress_percent / 100) ** 0.5   # sqrt: the PERCENTAGE is area
new_width  = int(img.width  * scale)
new_height = int(img.height * scale)
img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)

Akar kuadrat itulah seluruh gagasannya. Permintaan lima puluh persen berarti separuh pixel-nya, dan pixel mengikuti luas. Mengalikan kedua dimensi dengan sqrt(0.5), kira-kira 0.707, memotong luasnya jadi separuh. Mengalikan keduanya dengan 0.5 justru memotongnya jadi seperempat — gambar empat kali lebih kecil dari yang diminta, yang di layar masih tampak masuk akal dan baru ketahuan saat tulisan di dalamnya ternyata tak terbaca.

Ini penting sebab angka yang ada di kepala pemakainya berasal dari batas ukuran, batas ukuran soal byte, dan byte mengikuti luas jauh lebih rapat ketimbang mengikuti lebar. Keliru menaruh pangkatnya tidak menghasilkan error. Ia menghasilkan dokumen yang secara teknis di bawah batas dan secara praktis tak berguna.

LANCZOS adalah filter resampling-nya, dipilih sebab mengecilkan gambar padat tulisan — dan dokumen hasil scan memang begitu — dengan filter yang lebih murah menghasilkan persis jenis hasil lembek beraliasing yang membuat pemeriksanya menyipitkan mata.

Ada keputusan kedua yang lebih senyap di sebelahnya. Ketika kompresi sama sekali tak diminta, gambar yang lebih lebar dari 1200 pixel tetap dikecilkan ke lebar itu:

python
# even with no --compress: a ceiling, because a 12 MP phone photo
# of an A4 sheet is not more readable than a 1200px one, only bigger
max_width = 1200
if img.width > max_width:
    ratio = max_width / img.width
    img = img.resize((max_width, int(img.height * ratio)), Image.Resampling.LANCZOS)

Ini default yang mengubah input tanpa diminta, dan biasanya hal semacam itu patut dicurigai. Ia tetap dipertahankan sebab input yang mendominasi adalah foto ponsel atas selembar kertas, di mana kelebihan pixel-nya tak membawa kelebihan keterbacaan apa pun sementara ia membawa beberapa megabyte tambahan menuju batas yang sebentar lagi mengukur dokumen itu. Menjadikannya default ketimbang flag adalah penilaian bahwa keadaan yang paling sering terjadi semestinya tak perlu argumen.

E. Satu masuk, banyak keluar

Inilah jawaban atas hambatan kelima, dan ia sepenuhnya soal apa yang terjadi pada kali kedua perintahnya dijalankan.

python
def get_unique_folder_name(base_folder):
    if not os.path.exists(folder):
        return folder
    counter = 2
    while True:                         # periksa_2, periksa_3, ...
        candidate = f"{folder}_{counter}"
        if not os.path.exists(candidate):
            return candidate
        counter += 1

Memecah PDF adalah langkah pemeriksaan, dan pemeriksaan sifatnya berulang: render halamannya, temukan yang keliru, perbaiki generatornya, render lagi. Kedua kumpulan halaman itu perlu ada bersamaan, sebab seluruh tujuan jalan kedua memang untuk dibandingkan dengan yang pertama.

Menulis ke folder yang sudah ada akan memusnahkan perbandingan itu persis pada saat ia jadi mungkin. Menolak berjalan memang aman sekaligus menjengkelkan. Menambahkan suffix berangka menyimpan keduanya, tak berongkos apa pun, dan menghasilkan folder yang namanya terang-terangan menyatakan mana yang lebih dulu.

Perhatikan ketidaksimetrisannya dengan arah maju: menggabungkan banyak file jadi satu tak punya perkara semacam itu, sebab keluarannya satu path yang disebut pemakainya secara eksplisit. Menghasilkan banyak file dari satu-lah yang membuat penamaan jadi pertanyaan rancangan sama sekali.

F. Profil kualitas, bukan ukuran sasaran

Inilah jawaban atas hambatan keenam. Ia lima baris shell, dan bagian menariknya justru apa yang tak ada di dalamnya.

bash
gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/screen \
  -dNOPAUSE -dQUIET -dBATCH \
  -sOutputFile="$2" "$1"

Tak ada persentase di sini, dan tak ada ukuran sasaran, sebab Ghostscript memang tak menerimanya. -dPDFSETTINGS menerima sebuah profil — /screen, /ebook, /printer, /prepress — masing-masing berupa seikat keputusan tentang penurunan resolusi gambar dan penanaman font. Ukuran yang keluar adalah akibat dari keputusan-keputusan itu bertemu dokumen yang ini, bukan angka yang bisa diminta.

Itu batas yang sengaja tak saya rekayasa jalan memutarinya. Membangun perulangan yang mencoba profil demi profil sampai keluarannya muat di bawah sebuah ambang memang mungkin dan sebagian besar akan berhasil, sekaligus berarti meng-encode ulang dokumen itu berkali-kali demi memenuhi sebuah angka, dengan kualitas sebagai variabel yang diam. Versi jujurnya: pilih profil yang paling agresif, lihat hasilnya, lalu pakai profil lain bila belum cukup baik.

Flag di sekelilingnya seluruhnya soal bisa dipanggil: -dNOPAUSE dan -dBATCH supaya ia tak berhenti menunggu masukan atau tertahan di akhir, -dQUIET supaya ia tak bercerita. Bawaan Ghostscript menganggap ada manusia yang mengawasi; perintah yang dipanggil dari script butuh kebalikannya.

Hasil dan Pembahasan

A. Berapa ongkos membangun tiap tool

Ketiganya sama sekali tak sebanding ukurannya, dan ukuran itu memberi keterangan.

ToolBentukKe mana usahanya pergi
img2pdf~300 baris Python, dibundelPenanganan input, colour mode, dua jalur penskalaan
pdf2img~150 baris Python, dibundelPenamaan folder keluaran, penomoran halaman
pdf-compress5 baris shellMemilih satu profil dan enam flag

Baris terakhir yang layak direnungkan. pdf-compress mengerjakan pekerjaan yang benar-benar sulit — menulis ulang PDF dengan gambar beresolusi turun dan font yang di-subset — dan sama sekali tak memuat logika, sebab seluruh logikanya ada di Ghostscript. Yang tersisa untuk diputuskan cuma profil mana dan flag mana, dan keputusan itu layak disimpan justru sebab ia mustahil diingat.

Perbandingan itu juga memperlihatkan ke mana sebenarnya baris-baris di tool Python itu dihabiskan. Nyaris tak ada yang untuk konversinya. Seluruhnya penanganan input, colour mode, keputusan penskalaan, dan penamaan — batas antara sebuah library dan seorang manusia, dan bagian itulah yang tak disediakan library mana pun.

B. Versi yang cuma menambah satu flag

Ada salinan img2pdf yang lebih lama bersebelahan dengan yang sekarang, dan beda keduanya tiga puluh baris yang mewujudkan --compress dan tak lebih.

Flag itu ada sebab sebuah form menolak kiriman karena ukurannya terlalu besar. Sampai kejadian itu, plafon tetap 1200 pixel selalu cukup untuk tiap dokumen yang pernah saya lemparkan kepadanya, dan tak ada alasan memikirkan perkaranya lebih jauh. Satu penolakan melahirkan kebutuhan yang spesifik — turun di bawah angka yang disebut — dan plafon tetap tak punya cara menjawabnya, sebab ia konstanta, bukan kendali.

Begitulah bentuk sebagian besar penambahan saya pada ketiga tool ini. Bukan rencana, bukan daftar fitur, melainkan satu kegagalan spesifik yang tak sanggup dijawab perilaku yang sudah ada, melahirkan kode yang pas untuk menjawabnya. Tool-nya tumbuh satu flag sebab satu flag itulah yang dituntut keadaan.

C. Di mana pendekatan ini berhenti jadi tepat

Tool lokal dengan default yang dipatok cocok untuk dokumen milik satu orang dan kurang cocok untuk beberapa hal lain.

Plafon 1200 pixel mengandaikan dokumen yang tujuannya dibaca, bukan karya visual atau foto yang justru detailnya jadi pokok — untuk itu ini tool yang keliru, dan default-nya diam-diam merusak input. Profil /screen Ghostscript menyasar pembacaan di layar, jadi PDF yang tujuannya dicetak butuh profil lain dari yang terpatok. Lalu tak satu pun dari ketiganya melakukan OCR: PDF yang dibuat dari foto adalah PDF berisi gambar, tak bisa dicari dan tak bisa diseleksi — memadai untuk dikirim, tak berguna untuk diarsipkan.

Simpulan

Tiga tool, dan yang mereka miliki bersama bukan format file-nya. Melainkan bahwa ketiganya membuat dokumen bisa diubah bentuknya tanpa diserahkan kepada siapa pun, dan itu ternyata lebih berarti sebagai sifat praktis ketimbang sebagai prinsip: tanpa batas, tanpa watermark, dan bisa dipanggil dari dalam script.

Yang akan saya bawa dari membangun ketiganya: keputusan yang menarik tak pernah ada di konversinya. Pillow dan Ghostscript yang mengerjakan itu. Yang tersisa adalah serangkaian penilaian kecil tentang apa yang dikerjakan mewakili pemakainya — pipihkan colour mode apa pun, patok lebarnya, ambil akar kuadratnya, tambahkan suffix berangka — dan tiap satunya cuma bisa dibela dalam konteks sempit berupa dokumen satu orang di satu mesin. Kesempitan itu bukan kelemahan ketiga tool ini. Justru itulah alasan ketiganya cukup pendek untuk sepadan ditulis.

Istilah

Alpha channel
Keterangan transparansi per pixel yang dibawa berdampingan dengan warnanya. Screenshot hampir selalu punya; model pencitraan PDF tak menerimanya, jadi ia harus dibuang sebelum gambar jadi sebuah halaman.
Colour mode
Bagaimana nilai sebuah pixel disusun — RGB untuk warna, RGBA untuk warna plus transparansi, L untuk greyscale. Konversi antar mode bersifat lossy ke satu arah dan sekadar boros ke arah sebaliknya.
Filter resampling
Algoritma yang menentukan nilai pixel saat ukuran gambar berubah. LANCZOS tergolong mahal dan menjaga tepi tulisan lebih baik ketimbang alternatif yang lebih murah.
Profil PDFSETTINGS
Seikat keputusan Ghostscript bernama tentang penurunan resolusi gambar dan penanaman font. Menerima sebuah tujuan, misalnya layar atau cetak, bukan ukuran file sasaran.
Executable terbundel
Script yang dikemas bersama interpreter dan library-nya jadi satu file, sehingga ia berjalan tanpa environment yang disiapkan. Menukar ruang disk dengan hilangnya persiapan.
OCR
Optical character recognition — menurunkan teks yang bisa diseleksi dari gambar berisi tulisan. Tak ada di ketiga tool ini, dan itulah kenapa PDF yang dibangun dari foto tak bisa dicari isinya.

Technologies covered

  • Python
  • Pillow
  • Ghostscript
  • PyInstaller

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.

Related Articles

A stack of Markdown documents and an orange arrow leading to a browser page with a side menu, a heading, paragraphs, a dark code panel, and a table of contents with its active entry highlighted

Satu script yang mengubah dokumentasi Markdown satu project menjadi situs statis yang terbuka dari folder tanpa server maupun internet: menu, daftar isi yang mengikuti pembaca, tabel yang tak pernah terpotong, kode dengan tombol salin, dan tautan yang tetap berfungsi.

7 min read Read more →
An old layout with a grey banner and a new structure with a green banner, each holding a blue database, a purple document store, and an orange telemetry store; three coloured paths pass through one export package marked with a green check

Empat perintah yang memindahkan stack dari layout lama ke struktur baru melintasi versi mayor: export tanpa mengubah data sumber, import tiap store sesuai cara yang diizinkan versinya, verifikasi apa yang benar-benar tiba, dan rename modul sambil memindahkan datanya.

11 min read Read more →
Three image layer stacks, each with a version tag of its own colour, blue, orange, and green, each leading to an archive file banded in the same colour

Perintah yang memberi versi tersendiri pada tiap modul stack, mem-build image-nya di bawah tag yang berarti tepat satu build, menolak memakai ulang versi atau menelan compile yang gagal, dan mengarsipkan image menurut nama dan tag supaya versi tak saling menimpa.

7 min read Read more →