Claude Code untuk ketepatan impor/ekspor data: tentukan aturan validasi, format error konsisten, dan fuzz tests untuk impor CSV/JSON agar mengurangi tiket dukungan kasus tepi.

Impor jarang gagal karena kode itu “salah”. Mereka gagal karena data dunia nyata berantakan, tidak konsisten, dan dibuat oleh orang yang tidak melihat asumsi Anda.
Masalah CSV biasanya tentang bentuk dan format. Masalah JSON biasanya tentang makna dan tipe. Keduanya bisa rusak dengan cara yang tampak kecil tapi menghasilkan hasil yang membingungkan.
Masalah ini muncul berulang kali di tiket dukungan:
Ketepatan bukan hanya “apakah terimpor”. Anda harus memutuskan hasil mana yang diterima, karena pengguna lebih memperhatikan kesalahan diam daripada kegagalan keras.
Kebanyakan tim bisa setuju pada tiga hasil:
Edge case menjadi rework ketika orang tidak bisa tahu apa yang salah atau bagaimana memperbaikinya dengan cepat. Skenario umum: pelanggan mengunggah CSV berisi 5.000 baris, importer mengatakan “Invalid format”, dan mereka mencoba lagi tiga kali dengan edit acak. Itu menjadi banyak tiket plus seseorang di tim Anda mencoba mereproduksi file secara lokal.
Tetapkan tujuan yang mengurangi siklus: lebih sedikit retry, perbaikan lebih cepat, hasil yang dapat diprediksi. Sebelum menulis aturan, putuskan apa arti “partial” (dan apakah Anda mengizinkannya), bagaimana Anda akan melaporkan masalah per baris, dan apa yang harus dilakukan pengguna selanjutnya (mengedit file, memetakan field, atau mengekspor versi yang diperbaiki). Jika Anda menggunakan platform vibe-coding seperti Koder.ai (koder.ai) untuk menghasilkan validator dan tes dengan cepat, kontrak impor tetap apa yang menjaga perilaku itu konsisten seiring produk berkembang.
Sebelum menulis satu aturan validasi pun, tentukan apa arti “input valid” untuk produk Anda. Sebagian besar bug impor adalah ketidakcocokan ekspektasi antara apa yang diunggah pengguna dan apa yang sistem Anda anggap.
Mulai dengan format, dan jelaskan secara eksplisit. “CSV” bisa berarti koma atau titik-koma, baris header atau tidak, UTF-8 atau “apa pun yang Excel hasilkan.” Untuk JSON, tentukan apakah Anda menerima satu objek, array record, atau JSON Lines (satu objek JSON per baris). Jika Anda menerima JSON bersarang, definisikan path mana yang Anda baca dan mana yang diabaikan.
Kemudian kunci kontrak field. Untuk setiap field, tentukan apakah wajib, opsional, atau opsional dengan default. Default adalah bagian dari kontrak, bukan detail implementasi. Jika country hilang, apakah Anda default ke kosong, memilih negara tertentu, atau menolak baris?
Perilaku parsing adalah tempat di mana impor "toleran" menciptakan masalah jangka panjang. Tentukan di muka seberapa ketat Anda tentang trimming spasi, normalisasi huruf besar/kecil, dan menerima varian seperti "yes"/"true"/"1". Toleransi boleh-boleh saja jika bisa diprediksi dan terdokumentasi.
Duplikat adalah keputusan kontrak lain yang mempengaruhi ketepatan dan kepercayaan. Definisikan apa yang dihitung sebagai duplikat (email yang sama, external_id yang sama, atau kombinasi field), di mana Anda mendeteksinya (di dalam file, terhadap data yang ada, atau keduanya), dan apa yang Anda lakukan saat terjadi (keep first, keep last, merge, atau reject).
Checklist kontrak yang bisa Anda tempel ke spesifikasi:
Contoh: mengimpor “customers.” Jika email adalah kunci unik, putuskan apakah " [email protected] " sama dengan "[email protected]", apakah email yang hilang diperbolehkan ketika external_id ada, dan apakah duplikat di dalam file harus ditolak meskipun database belum memiliki kecocokan. Setelah kontrak ini tetap, perilaku konsisten di UI dan API jauh lebih mudah, baik Anda mengimplementasikannya di Koder.ai atau di tempat lain.
Impor yang berantakan sering dimulai dari satu fungsi validate() raksasa. Pendekatan yang lebih bersih adalah aturan berlapis dengan nama jelas dan fungsi kecil. Itu membuat perubahan lebih mudah ditinjau, dan tes lebih mudah ditulis.
Mulai dengan aturan tingkat field: pemeriksaan satu nilai yang dapat lulus atau gagal sendiri (tipe, rentang, panjang, nilai yang diizinkan, regex). Buat mereka membosankan dan dapat diprediksi. Contoh: email cocok pola email dasar, age adalah integer antara 0 dan 120, status adalah salah satu dari active|paused|deleted.
Tambahkan aturan lintas-field hanya bila memang penting. Pemeriksaan ini bergantung pada beberapa field, dan bug sering tersembunyi di sini. Contoh klasik: startDate harus sebelum endDate, atau total sama dengan subtotal + tax - discount. Tulis aturan ini sehingga bisa menunjuk ke field spesifik, bukan sekadar “record invalid”.
Pisahkan aturan tingkat record dari aturan tingkat file. Aturan tingkat record memeriksa satu baris (CSV) atau satu objek (JSON). Aturan tingkat file memeriksa seluruh upload: header wajib ada, kunci unik tidak berulang across rows, jumlah kolom sesuai ekspektasi, atau file menyatakan versi yang didukung.
Normalisasi harus eksplisit, bukan “ajaib”. Tentukan apa yang Anda normalisasi sebelum memvalidasi, dan dokumentasikan. Contoh umum termasuk trimming spasi, normalisasi Unicode (agar karakter yang tampak identik dapat dibandingkan sama), dan memformat nomor telepon ke satu format penyimpanan konsisten.
Struktur yang tetap terbaca:
Versi-kan aturan Anda. Letakkan schemaVersion (atau profil impor) di file atau permintaan API. Saat Anda mengubah arti “valid”, Anda masih bisa mengimpor ekspor lama menggunakan versi lama. Pilihan itu mencegah banyak tiket “dulu bekerja kemarin”.
Importer yang baik gagal dengan cara yang membantu. Error samar menyebabkan retry acak dan pekerjaan dukungan yang dapat dihindari. Format error yang jelas membantu pengguna memperbaiki file dengan cepat, dan membantu Anda menyempurnakan validasi tanpa merusak client.
Mulai dengan bentuk objek error yang stabil dan pertahankan konsistensi di CSV dan JSON. Anda bisa menggunakan Claude Code untuk mengusulkan skema dan beberapa contoh realistis, lalu kunci itu sebagai bagian dari kontrak impor.
Anggap setiap error sebagai record kecil dengan field yang tidak berubah. Pesan bisa berkembang, tetapi kode dan lokasi harus tetap stabil.
code: pengenal singkat dan stabil seperti REQUIRED_MISSING atau INVALID_DATEmessage: kalimat ramah-pengguna untuk UIpath: di mana masalahnya (JSON pointer seperti /customer/email, atau nama kolom seperti email)row atau line: untuk CSV, sertakan nomor baris 1-based (dan opsional baris asli)severity: setidaknya error dan warningBuat error actionable. Sertakan apa yang Anda harapkan dan apa yang sebenarnya terlihat, dan bila memungkinkan tunjukkan contoh yang akan lolos. Misal: diharapkan YYYY-MM-DD, didapat 03/12/24.
Bahkan jika Anda mengembalikan list datar, sertakan data cukup untuk mengelompokkan error per baris dan per field. Banyak UI ingin “Baris 12 memiliki 3 masalah” lalu menyorot setiap kolom. Tim dukungan suka pengelompokan karena pola menjadi jelas (mis. setiap baris kehilangan country).
Respons ringkas bisa terlihat seperti ini:
{
"importId": "imp_123",
"status": "failed",
"errors": [
{
"code": "INVALID_DATE",
"message": "Signup date must be in YYYY-MM-DD.",
"path": "signup_date",
"row": 12,
"severity": "error",
"expected": "YYYY-MM-DD",
"actual": "03/12/24"
},
{
"code": "UNKNOWN_FIELD",
"message": "Column 'fav_colour' is not recognized.",
"path": "fav_colour",
"row": 1,
"severity": "warning"
}
]
}
Rencanakan lokalisasi tanpa mengubah error codes. Simpan code netral-bahasa dan tahan, dan anggap message sebagai teks yang dapat diganti. Jika nanti Anda menambahkan messageKey atau pesan terjemahan, client lama masih dapat bergantung pada kode yang sama untuk filter, grup, dan analytics.
Untuk menghindari “impor misterius,” respons API Anda harus menjawab dua pertanyaan: apa yang terjadi, dan apa yang harus dilakukan pengguna selanjutnya.
Bahkan ketika ada error, kembalikan ringkasan konsisten agar UI dan tooling dukungan bisa menangani setiap impor dengan cara yang sama.
Sertakan:
created, updated, skipped, failed countstotalRows (atau totalRecords untuk JSON)mode (misal: "createOnly", "upsert", atau "updateOnly")startedAt dan finishedAt timestampscorrelationId yang bisa diminta dukungancorrelationId itu sangat berharga. Saat seseorang melaporkan “tidak terimpor,” Anda bisa menemukan run yang tepat dan laporan error tanpa menebak-nebak.
Jangan masukkan 10.000 error baris ke dalam respons. Kembalikan contoh kecil (mis. 20) yang menunjukkan pola, dan sediakan cara terpisah untuk mengambil laporan penuh bila perlu.
Buat setiap error spesifik dan stabil:
Contoh bentuk respons (sukses dengan beberapa row gagal):
{
"importId": "imp_01HZY...",
"correlationId": "c_9f1f2c2a",
"status": "completed_with_errors",
"summary": {
"totalRows": 1200,
"created": 950,
"updated": 200,
"skipped": 10,
"failed": 40
},
"errorsSample": [
{
"row": 17,
"field": "email",
"code": "invalid_format",
"message": "Email must contain '@'.",
"value": "maria.example.com"
}
],
"report": {
"hasMore": true,
"nextPageToken": "p_002"
},
"next": {
"suggestedAction": "review_errors"
}
}
Perhatikan field next. Bahkan payload sukses minimal sebaiknya membantu produk melangkah: tunjukkan layar review, tawarkan retry, atau buka koleksi yang diimpor.
Orang mencoba lagi. Jaringan gagal. Jika file yang sama diimpor dua kali, Anda ingin hasil yang dapat diprediksi.
Jadilah eksplisit tentang idempotency: terima idempotencyKey (atau hitung hash file), dan kembalikan importId yang sudah ada jika request itu pengulangan. Jika mode Anda upsert, definisikan aturan pencocokan (mis. email adalah kunci unik). Jika create-only, kembalikan “skipped” untuk duplikat, bukan “created again.”
Jika seluruh request tidak valid (auth salah, content-type salah, file tak terbaca), gagal cepat dan kembalikan status: "rejected" dengan daftar error singkat. Jika file valid namun ada masalah per baris, perlakukan itu sebagai job selesai dengan failed > 0 sehingga pengguna dapat memperbaiki dan meng-upload ulang tanpa kehilangan ringkasan.
Kebiasaan yang berguna: minta model menulis kontrak dalam format terstruktur, bukan sekadar prosa. “Paragraf membantu” sering melewatkan detail seperti aturan trimming, nilai default, dan apakah sel kosong berarti “missing” atau “empty”.
Gunakan prompt yang memaksa tabel yang bisa cepat ditinjau manusia dan bisa langsung dikonversi pengembang menjadi kode. Minta untuk setiap field aturan, contoh pass/fail, dan catatan eksplisit untuk hal ambigu (mis. empty string vs null).
You are helping design an importer for CSV and JSON.
Output a Markdown table with columns:
Field | Type | Required? | Normalization | Validation rules | Default | Pass examples | Fail examples
Rules must be testable (no vague wording).
Then output:
1) A list of edge cases to test (CSV + JSON).
2) Proposed test names with expected result (pass/fail + error code).
Finally, list any contradictions you notice (required vs default, min/max vs examples).
Setelah draf pertama, perketat dengan meminta satu contoh positif dan satu contoh negatif per aturan. Itu mendorong cakupan untuk sudut rumit seperti string kosong, nilai hanya-whitespace, kolom hilang, null vs "null", integer sangat besar, notasi ilmiah, ID duplikat, dan field JSON ekstra.
Untuk skenario konkret, bayangkan mengimpor “customers” dari CSV: email wajib, phone opsional, dan signup_date default ke hari ini jika hilang. Model harus menandai kontradiksi jika Anda juga mengatakan "signup_date wajib". Ia harus mengusulkan tes seperti import_customers_missing_email_returns_row_error dan menentukan kode error serta bentuk pesan yang Anda kembalikan.
Lakukan satu kali tinjau lagi sebelum implementasi: minta model menyatakan kembali aturan sebagai checklist dan tunjukkan di mana default, field wajib, dan normalisasi mungkin saling bertentangan. Langkah review itu menangkap banyak perilaku yang memicu tiket.
Fuzz testing menghentikan “file aneh” menjadi tiket dukungan. Mulai dari set kecil file CSV/JSON yang benar, lalu hasilkan ribuan variasi yang sedikit rusak dan pastikan importer Anda bereaksi dengan aman dan jelas.
Mulai dengan korpus seed kecil contoh valid yang merepresentasikan penggunaan nyata: file valid terkecil, file tipikal, dan file besar. Untuk JSON, sertakan satu objek, banyak objek, dan struktur nested jika Anda mendukungnya.
Lalu tambahkan mutator otomatis yang mengubah satu hal pada satu waktu. Jaga mutasi dapat direproduksi dengan mencatat random seed sehingga Anda bisa memutar ulang kegagalan.
Dimensi fuzz yang menangkap sebagian besar masalah dunia nyata:
Jangan berhenti pada sintaks. Tambahkan fuzz semantik juga: tukar field serupa (email vs username), tanggal ekstrem, ID duplikat, kuantitas negatif, atau nilai yang melanggar enum.
Fuzz tests hanya membantu jika kriteria lulus ketat. Importer Anda tidak boleh crash atau hang, dan error harus konsisten dan actionable.
Sekumpulan aturan lulus praktis:
Jalankan tes ini di CI pada setiap perubahan. Saat menemukan kegagalan, simpan file persis sebagai fixture dan tambahkan tes regresi agar tidak kembali.
Jika Anda menggunakan Claude Code untuk pekerjaan ini, minta ia menghasilkan fixture seed yang cocok dengan kontrak Anda, rencana mutasi, dan output error yang diharapkan. Anda masih memilih aturan, tetapi Anda mendapatkan permukaan tes luas dengan cepat, terutama untuk quoting CSV dan corner case JSON.
Kebanyakan tiket impor muncul dari aturan yang tidak jelas dan umpan balik yang tidak berguna.
Satu perangkap umum adalah parsing “best effort” yang tidak terdokumentasi. Jika importer Anda diam-diam memangkas spasi, menerima koma dan titik-koma, atau menebak format tanggal, pengguna membangun alur kerja di sekitar tebakan itu. Lalu perubahan kecil, atau generator file yang berbeda, merusak semuanya. Pilih perilaku, dokumentasikan, dan uji.
Pelaku lain yang sering adalah pesan error generik. “Invalid CSV” atau “Bad request” memaksa pengguna menebak. Mereka mengunggah file yang sama lima kali, dan dukungan akhirnya meminta file. Error harus menunjuk ke baris, field, alasan jelas, dan kode yang stabil.
Menolak seluruh file karena satu baris buruk juga sering menyakitkan. Kadang itu tepat (mis. impor finansial di mana partial data berbahaya). Banyak impor bisnis bisa dilanjutkan dan melaporkan ringkasan, selama Anda menawarkan pilihan eksplisit seperti strict mode vs partial import.
Masalah encoding teks menciptakan tiket yang membandel. UTF-8 adalah default yang tepat, tetapi CSV nyata sering berisi BOM, kutip keriting, atau spasi tak terputus hasil copy dari spreadsheet. Tangani ini konsisten dan laporkan apa yang terdeteksi sehingga pengguna dapat memperbaiki pengaturan ekspor mereka.
Akhirnya, mengubah kode error antara rilis merusak client dan automasi. Perbaiki redaksi jika perlu, tetapi pertahankan kode dan makna stabil. Versi-kan hanya saat benar-benar diperlukan.
Perangkap yang perlu diantisipasi:
Contoh: pelanggan mengekspor CSV dari Excel, yang menambahkan BOM dan memformat tanggal sebagai 03/04/2026. Importer Anda menebak MM/DD, tapi pelanggan mengharapkan DD/MM. Jika laporan error Anda menyertakan format yang terdeteksi, field yang tepat, dan perbaikan yang disarankan, pengguna bisa memperbaikinya tanpa bolak-balik.
Sebagian besar masalah impor adalah ketidakcocokan kecil antara apa yang pengguna pikir file itu maksud dan apa yang sistem Anda terima. Perlakukan ini sebagai gerbang rilis.
Tes praktis: gunakan satu file yang sengaja berantakan. Contoh: CSV di mana header muncul dua kali (dua kolom “email”), field boolean menggunakan “Y”, dan tanggal adalah “03/04/05”. Importer Anda tidak boleh menebak. Ia harus menerapkan aturan pemetaan terdokumentasi atau menolak dengan error spesifik.
Dua cek yang sering dilewatkan tim:
Pertama, verifikasi importer melaporkan error dengan detail lokasi cukup untuk memperbaiki file sumber. “Invalid date” tidak actionable. “Baris 42, kolom start_date: diharapkan YYYY-MM-DD, mendapat 03/04/05” itu.
Kedua, jalankan file invalid yang sama dua kali dan bandingkan hasil. Jika urutan error berubah, kode berubah, atau nomor baris bergeser, pengguna kehilangan kepercayaan. Perilaku deterministik itu membosankan, dan itu memang tujuannya.
Impor nyata yang umum adalah pesanan pelanggan datang dari ekspor spreadsheet. Seseorang mengekspor CSV dari sistem lama, mengeditnya di Excel, lalu mengunggahnya. Sebagian besar tiket terjadi ketika importer diam-diam “memperbaiki” data, atau ketika pesan error tidak mengatakan apa yang harus diubah.
Bayangkan file bernama orders.csv dengan kolom: order_id,customer_email,order_date,currency,total_amount.
Berikut tiga baris buruk yang realistis (sebagaimana dilihat pengguna):
order_id,customer_email,order_date,currency,total_amount
A-1001,[email protected],2026-01-05,USD,129.99
A-1002,not-an-email,01/06/2026,USD,49.00
,[email protected],2026-01-07,US, -10
Baris 2 memiliki email tidak valid dan format tanggal ambigu. Baris 3 kehilangan order_id, memiliki kode mata uang yang tidak didukung (US bukan USD), dan jumlah negatif.
Jika API Anda mengembalikan error, jaga bentuk konsisten dan spesifik. Berikut contoh respons yang mendukung partial success:
{
"correlation_id": "imp_20260109_7f3a9d",
"import_id": "ord_01HZZ...",
"status": "partial_success",
"summary": {
"total_rows": 3,
"imported_rows": 1,
"failed_rows": 2
},
"errors": [
{
"row_number": 2,
"field": "customer_email",
"code": "invalid_email",
"message": "Email must contain a valid domain.",
"value": "not-an-email"
},
{
"row_number": 2,
"field": "order_date",
"code": "invalid_date_format",
"message": "Use ISO-8601 (YYYY-MM-DD).",
"value": "01/06/2026"
},
{
"row_number": 3,
"field": "order_id",
"code": "required",
"message": "order_id is required.",
"value": ""
},
{
"row_number": 3,
"field": "currency",
"code": "unsupported_currency",
"message": "Allowed values: USD, EUR, GBP.",
"value": "US"
},
{
"row_number": 3,
"field": "total_amount",
"code": "must_be_positive",
"message": "total_amount must be greater than 0.",
"value": " -10"
}
],
"retry": {
"mode": "upload_failed_only",
"failed_row_numbers": [2, 3]
}
}
Partial success penting karena pengguna tidak perlu meng-upload ulang seluruh file. Alur retry sederhana: perbaiki hanya baris gagal, ekspor CSV kecil berisi baris 2 dan 3, lalu unggah ulang. Importer Anda harus memperlakukan ini sebagai idempotent saat order_id ada, sehingga “retry” memperbarui record yang sama daripada membuat duplikat.
Untuk dukungan, correlation_id adalah jalur tercepat ke diagnosis. Agen dukungan bisa meminta nilai itu, menemukan run impor di log, dan mengonfirmasi apakah parser melihat kolom ekstra, delimiter salah, atau encoding tak terduga.
Langkah selanjutnya yang membuat ini dapat diulang:
Kebanyakan kegagalan berasal dari data dunia nyata yang berantakan, bukan dari “kode yang rusak.” Masalah CSV biasanya terkait dengan bentuk (header, delimiter, quoting, encoding), sedangkan masalah JSON biasanya terkait dengan makna (tipe, null vs kosong, nesting tak terduga). Perlakukan keduanya sebagai input yang tidak dipercaya dan validasi terhadap kontrak yang eksplisit.
Tentukan tiga hasil di awal:
Pilih default (banyak produk memilih partial) dan buat konsisten di UI dan API.
Tuliskan sebuah import contract sebelum menulis validasi:
Ini mencegah kejutan “kemarin berjalan” ketika perilaku berubah.
Standarkan pada satu format tidak ambigu per field (mis. tanggal sebagai YYYY-MM-DD). Jika Anda menerima varian, buat aturan yang eksplisit dan dapat diprediksi (mis. terima true/false/1/0, tapi jangan terima setiap tebakan spreadsheet). Hindari menebak tanggal ambigu seperti 01/02/03; minta format ISO atau tolak dengan pesan jelas.
Putuskan:
Jika pengguna dapat mengulang impor, kombinasikan ini dengan idempotency sehingga upload yang sama tidak membuat duplikat.
Gunakan lapisan daripada satu validate() besar:
Kembalikan bentuk error yang stabil dengan:
Selalu kembalikan ringkasan yang konsisten, bahkan saat ada error:
Dukung retry secara eksplisit:
idempotencyKey (atau gunakan hash file)importId yang sama jika request diulangTanpa ini, retry pengguna normal bisa membuat duplikat.
Mulai dengan beberapa file seed yang baik, lalu buat banyak mutasi kecil (satu perubahan per kali):
NaN/Infinity di JSON)Sebuah fuzz test "lulus" bila importer tidak crash/hang dan selalu mengembalikan error yang deterministik dan actionable.
Rule kecil dengan nama jelas lebih mudah dites dan lebih aman untuk diubah.
code (identifier yang stabil)message (ramah pengguna)path/field (nama kolom atau JSON pointer)row/line (untuk CSV)severity (error vs warning)Buat actionable dengan menyertakan apa yang diharapkan dan apa yang ditemukan bila memungkinkan.
created, updated, skipped, failed, plus totalRows/totalRecordsstatus (success, rejected, completed_with_errors)startedAt, finishedAt)correlationId untuk dukungan/debuggingUntuk file besar, sertakan errorsSample kecil dan cara untuk mengambil laporan penuh nanti.