Skip to content

Seed Migration dan Status Mapping untuk Import Fasilitas Budaya

Adityo Guni Waluyo

Membuat kategori baru lewat seed migration yang idempoten, lalu import data fasilitas budaya dengan pemetaan status eksisting dan rencana.

Ringkasan

Artikel ini cerita soal import 8 fasilitas budaya PPKD pas kategori "Sarana Budaya" belum ada di database. Solusinya pakai seed migration idempoten dengan ON DUPLICATE KEY UPDATE, jadi aman dijalankan ulang di environment mana aja. Fasilitas eksisting langsung published, yang rencana masuk draft, dan importernya ada dry-run plus guard development biar gak ada duplikat.

Ketika Kategori Belum Ada di Database

Data sarana dan prasarana budaya dari PPKD (Pusat Pengembangan Kebudayaan Daerah) siap diimport: 8 fasilitas, 4 eksisting dan 4 rencana. Satu masalah — kategori "Sarana Budaya" belum ada di tabel categories. Tanpa kategori, importer tidak punya target untuk menulis data.

Opsi pertama: buat kategori secara manual lewat SQL, lalu jalankan importer. Opsi ini gagal pada prinsip reproduktibilitas — siapa pun yang menjalankan environment baru harus tahu urutan eksekusinya. Opsi yang dipilih: seed migration sebagai bagian dari rangkaian migrasi resmi, terikat versi, idempoten, dan bisa dijalankan ulang tanpa efek samping.

Seed Migration yang Idempoten

Migration 000075 membuat kategori Sarana Budaya dengan satu pernyataan INSERT yang dilindungi ON DUPLICATE KEY UPDATE. Jika kategori sudah ada (sudah dijalankan sebelumnya), pernyataan hanya memperbarui kolom yang boleh berubah — bukan membuat duplikat.

INSERT INTO categories (name, slug, module, sort_order) VALUES
  ('Sarana Budaya', 'sarana-budaya', 'BUDAYA', 5)
ON DUPLICATE KEY UPDATE
  module = VALUES(module),
  sort_order = VALUES(sort_order);

Pola ini memastikan migration aman dijalankan di environment mana pun , fresh database, staging, atau produksi. Tidak ada IF NOT EXISTS yang ambigu, tidak ada pengecekan manual sebelum INSERT. Database yang menentukan apakah baris baru dibuat atau baris lama diperbarui.

MySQL mendokumentasikan perilaku ini secara eksplisit: ketika baris yang akan diinsert akan menyebabkan duplikat pada UNIQUE index atau PRIMARY KEY, yang terjadi adalah UPDATE pada baris lama, bukan error. Down migration menggunakan DELETE FROM categories WHERE slug = 'sarana-budaya' , simetris dan aman karena hanya satu baris yang terpengaruh.

Pemetaan Status ke Publish

Delapan fasilitas dalam data sumber memiliki dua status: "Eksisting" (sudah beroperasi) dan "Rencana" (masih dalam perencanaan). Perbedaan ini diterjemahkan langsung ke status publikasi , fasilitas eksisting langsung published, fasilitas rencana masuk sebagai draft.

func publishStatus(source string) string {
    switch strings.ToLower(strings.TrimSpace(source)) {
    case "eksisting":
        return "published"
    default:
        return "draft"
    }
}

Fasilitas rencana juga membawa catatan (catatan) dari sumber yang menjelaskan mengapa statusnya masih draft. Catatan ini disimpan di atribut entitas, bukan di kolom utama , data utama tetap bersih untuk rendering publik, sementara konteks verifikasi tetap tersedia untuk admin.

Pendekatan ini memisahkan data yang siap konsumsi publik dari data yang masih dalam verifikasi. Pengunjung portal hanya melihat fasilitas yang sudah eksisting dan tervalidasi. Tim pengelola tetap bisa melihat rencana yang sedang diverifikasi melalui dashboard admin.

Pola Import dengan Dry-Run

Setiap CLI penulis data di project ini mengikuti pola yang sama: flag --dry-run yang memprediksi apa yang akan terjadi tanpa menulis ke database. Dry-run menampilkan entitas yang akan diinsert, yang akan di-skip (karena sudah ada), dan yang akan dihapus (saat reconcile). Ini memungkinkan validasi sebelum eksekusi sesungguhnya.

Guard APP_ENV=development menambah lapisan proteksi. CLI hanya boleh berjalan ketika environment variable bernilai development secara eksplisit. Nilai default dari config loader yang juga development tidak cukup , guard memeriksa kesamaan string, bukan keberadaan nilai. Pola fail-closed ini mencegah import data yang secara desain destruktif berjalan di lingkungan produksi.

Idempotensi importer dijamin oleh kombinasi slug dan attributes.no sebagai kunci deduplikasi. Menjalankan importer dua kali menghasilkan skip penuh pada run kedua , tidak ada duplikat, tidak ada error. Kombinasi seed migration untuk kategori dan importer untuk data membentuk rangkaian yang bisa dijalankan ulang dari nol di environment mana pun.

Tes integrasi membuktikan seluruh rangkaian bekerja. Fixtures menyiapkan dua baris JSON , satu eksisting, satu rencana , lalu menjalankan importer. Kedua entitas terinsert. Pada run kedua, kedua entitas di-skip karena kombinasi slug dan nomor atribut sudah ada. Hasilnya: EntitiesInserted == 2 pada run pertama, 0 pada run kedua. Tidak ada data ganda, tidak ada error.

Pola kombinasi seed migration dan data importer ini bukan spesifik untuk sarana budaya. Setiap kali project membutuhkan kategori baru beserta data awal, rangkaian yang sama bisa digunakan: migration untuk membuat kategori, importer untuk mengisi data, dan guard untuk memastikan proses hanya berjalan di environment yang tepat. Konsistensi pola ini mengurangi beban kognitif bagi siapa pun yang baru bergabung dalam tim , semua importer terlihat dan berperilaku sama.

Artikel terkait