backend
Catatan teknis seputar web development, DevOps, dan integrasi AI.
93 artikel
- 20.10backend
Tiga Celah Mapper yang Hanya Terlihat di Data Asli
Fixture hijau bukan jaminan: nested object, camelCase, dan datetime penuh baru ketahuan saat 5330 baris asli masuk ke ingest.
TL;DR: Dump JSON 5330 baris masuk mulus tanpa error, tapi kolom nama perusahaan sama tanggalnya kosong semua, ternyata mapper salah asumsi bentuk data. Field penyedia ternyata objek bersarang, kuncinya camelCase, plus tanggalnya datetime penuh yang ditolak date.fromisoformat. Setelah dibenerin, semua baris kebaca dan idempotensi jalan, pelajarannya mulai dari data asli, bukan asumsi.
#python#data-engineering#schema - 18.58backend
Kolom event_date yang Selalu NULL dan Tabel Bulan 13 Entri
Data tanggal berbahasa Indonesia membuat kolom event_date kosong terus. Parser locale stdlib bukan jawabannya; tabel bulan eksplisit iya.
TL;DR: Tanggal dari feed dateng dalam bentuk teks kayak Senin, 08 Jun. 2026, tapi mapper cuma coba fromisoformat, jadinya gagal diam-diam dan event_date kosong semua. Ide pake locale Python ketolak soalnya nggak thread-safe plus bug-nya numpuk sejak 2010.
#python#locale#data-engineering - 18.57database
Satu Aturan, Satu Tempat: Identitas Email dalam Skema Basis Data
Dua constraint menjaga satu aturan identitas email. Menghapus yang redundan ternyata bukan kosmetik, melainkan menutup celah spesifikasi ganda.
TL;DR: Migrasi ini cuma ngehapus constraint komposit tenant-email dan ganti email jadi unique, intinya satu aturan mending ditulis sekali aja. Soalnya dua spesifikasi buat aturan yang sama itu bahaya—pas aturan berubah, yang lama bisa balik nyala diam-diam. Verifikasinya aman: roundtrip migrasi bersih, autogenerate nggak nemu drift, dan insert duplikat lintas tenant tetap ditolak database.
#postgresql#alembic#sqlalchemy - 17.49database
Validasi Database yang Tidak Menghukum Evolusi Nilai
Tiga kolom enum-like hanya dijaga aplikasi. CHECK constraint memindahkan garansi ke database, dan evolusi nilai jadi operasi murah.
TL;DR: Dulu validasi enum cuma di aplikasi, jadi gampang jebol kalau ada insert manual iseng. Akhirnya ditambah tiga CHECK constraint di database biar nilai ngaco langsung ketolak, nggak pake ENUM native karena ribet kalau mau nambah nilai baru. Untuk tabel kecil validasi langsung full, kalau udah gede pake trik NOT VALID dulu biar nggak ngunci tabel.
#postgresql#database#testing - 17.39backend
Kontrak Endpoint Ingest yang Tahan Kegagalan Parsial
Satu angka sukses untuk seluruh batch menyembunyikan kegagalan parsial. Kontrak per-item created/updated/unchanged/rejected membuatnya terlihat.
TL;DR: Endpoint baru /v1/signals:ingest akhirnya nggak pakai satu status buat se-batch, tapi kasih status per item biar kegagalan parsial kelihatan. Tiap item bisa jadi created, updated, unchanged, atau rejected, plus ada pengaman kayak limit ukuran, jumlah item, dan rate limit. Autentikasi pakai Bearer token juga dibenerin, kalau token belum disetting server ngasih 503 bukan 401, dan semua udah dites live.
#fastapi#api#rest-api - 17.37backend
Content Hash sebagai Identitas Observasi dalam Pipeline Ingest
Observasi yang sama tercatat dua kali hanya karena nama ditulis berbeda. Content hash dari tuple kanonik menutup celah duplikasi itu.
TL;DR: Pipeline sempat ngitung dobel gara-gara nama PT ditulis beda titik sama spasi padahal perusahaannya sama. Makanya dibikin normalize_company buat beresin nama plus content_hash_for yang nge-hash tuple kanonik pakai SHA-256 biar identitasnya konsisten. Terus di database dikunci pakai UniqueConstraint dan ON CONFLICT biar duplikat nggak lolos lagi.
#postgresql#python#sqlalchemy - 16.01backend
Status Antrean Scraper yang Jujur: dari Empty sampai Recheck
Antrean scraper dengan dua status akhir menyembunyikan empat realitas. Pemisahan empty, incomplete, error, plus worklist berbasis umur data menutup celah itu.
TL;DR: Panen data macet gara-gara status cuma ada ok dan error, jadi halaman yang sukses dimuat tapi kosong nganggur di pending terus. Nambahin retry cuma buang jatah kunjungan, ternyata masalahnya bukan jaringan. Solusinya: perbanyak status jadi empty sama incomplete, tandain pas proses jalan, terus susun daftar recheck dari umur data.
#python#scraping#state-machine - 15.05backend
Rebuild Hanya untuk Pemulihan: Menjaga Ledger Tetap Sehat
Insiden rebuild yang mengubah 20 baris sehat jadi 77 UNKNOWN memaksa kontrak baru: alat pemulihan hanya mengisi kekosongan, tidak pernah menimpa baris sehat.
TL;DR: Gara-gara prinsip "raw is truth", alat rebuild malah merusak data sehat karena parser ikut baca berkas sub-tab yang bukan data detail. Kontraknya pun diubah jadi recovery-only: baris sehat dipertahankan, sub-tab diabaikan, dan ketemu UNKNOWN berarti nggak nulis apa-apa sama sekali. Karena raw-nya append-only, ledger yang sehat cukup dilengkapi, bukan ditimpa ulang.
#python#data-engineering#sqlite - 15.04backend
Melacak Jejak Panen Data dengan Log Audit SQLite
Dua penjaga lokal untuk pipeline panen data: rulebook AGENTS.md untuk agen koding dan log audit SQLite yang idempoten lewat UPSERT.
TL;DR: Pas panen data di DemandScope error terus, aku bingung commit mana yang ngasilin datanya karena Git cuma nyatet berkas berubah doang. Solusinya gampang: bikin AGENTS.md buat ngatur agen koding biar nggak sembarangan nulis data atau commit kredensial. Terus bikin log audit SQLite per target pakai UPSERT biar idempoten, jadi tiap data bisa dilacak asalnya.
#sqlite#scraping#audit-trail