AizuDemy

Bikin CRUD App Tanpa Ngetik Banyak Kode: Vibe Coding untuk Pemula

Konsep CRUD dan Transformasi Vibe Coding

Membuat aplikasi CRUD (Create, Read, Update, Delete) adalah pondasi dasar dalam pengembangan perangkat lunak berbasis web. Hampir seluruh sistem informasi, mulai dari manajemen stok, e-commerce, hingga platform portal berita, beroperasi di atas empat fungsi dasar ini. Bagi pengembang pemula, penulisan kode CRUD secara manual kerap menjadi proses yang repetitif dan menyita waktu karena banyaknya boilerplate code yang harus dibuat dari nol.

Proses konvensional menuntut penulisan query SQL manual, pembuatan form input HTML, penanganan request HTTP POST dan GET, validasi data di sisi server, hingga penyusunan tabel responsif. Melalui pendekatan CRUD vibe coding, paradigma tersebut bergeser. Anda tidak lagi mengetik setiap baris kode secara manual, melainkan mengarahkan model kecerdasan buatan (AI) untuk menggenerasi struktur kode aplikasi CRUD AI berbasis PHP Native dan MySQLi dengan cepat dan terstruktur.

Vibe coding bukan berarti menyerahkan kontrol penuh kepada AI tanpa pengawasan. Pada seri Belajar Vibe Coding ini, peran pengembang berfokus sebagai arsitek sistem dan pemeriksa kode (code reviewer). AI bertindak sebagai eksekutor pengetikan kode. Pendekatan ini memangkas durasi pengembangan tanpa mengorbankan kualitas arsitektur maupun keamanan dasar aplikasi.

Perancangan Skema Database Manajemen Produk

Sebelum mengeksekusi prompt ke AI, perancangan skema database yang presisi merupakan langkah krusial. Kecerdasan buatan memerlukan atribut data yang terdefinisi secara spesifik agar tidak menghasilkan struktur tabel yang keliru atau memicu eror relasi.

Studi kasus pada panduan ini menggunakan sistem manajemen produk. Tabel products dirancang dengan struktur kolom sebagai berikut:

  • id: Identifier unik (Primary Key, Auto Increment, INT)
  • name: Nama produk (VARCHAR 150, NOT NULL)
  • sku: Kode stok unik (VARCHAR 50, UNIQUE, NOT NULL)
  • price: Harga barang (DECIMAL 10,2, NOT NULL)
  • stock: Jumlah stok barang (INT, DEFAULT 0, NOT NULL)
  • created_at: Waktu pencatatan data (TIMESTAMP, DEFAULT CURRENT_TIMESTAMP)

Cetak biru skema database tersebut siap diconvert menjadi Perintah SQL instan melalui AI. Berikut adalah sintaks SQL yang digunakan untuk inisialisasi tabel:

CREATE TABLE `products` (
  `id` INT AUTO_INCREMENT PRIMARY KEY,
  `name` VARCHAR(150) NOT NULL,
  `sku` VARCHAR(50) UNIQUE NOT NULL,
  `price` DECIMAL(10,2) NOT NULL,
  `stock` INT DEFAULT 0 NOT NULL,
  `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Formulasi Prompt Backend PHP dan MySQLi

Efektivitas CRUD vibe coding sangat bergantung pada detail instruksi prompt. Instruksi teknis yang spesifik meminimalisir kesalahan sintaks dan celah keamanan. Berikut adalah urutan prompt terstruktur untuk menggenerasi modul CRUD secara utuh.

Langkah 1: Setup Koneksi Database (db.php)

Gunakan prompt berikut untuk menggenerasi file koneksi database:

"Buatkan file PHP bernama db.php untuk menghubungkan aplikasi ke database MySQL bernama toko_db. Gunakan ekstensi MySQLi dengan pendekatan prosedural. Host: localhost, user: root, pass: empty. Sertakan penanganan eror koneksi menggunakan mysqli_connect_error() dan hentikan eksekusi jika koneksi gagal."

Langkah 2: Tampilan Data Utama (index.php)

Gunakan prompt berikut untuk menggenerasi halaman utama pembacaan data:

"Buatkan file index.php yang meng-include db.php. Tampilkan seluruh data dari tabel products dalam tabel HTML Bootstrap 5 CDN. Kolom tabel: No, Nama Produk, SKU, Harga (format Rupiah via number_format), Stok, dan Aksi. Kolom Aksi berisi tombol Edit dan Hapus. Tambahkan tombol 'Tambah Produk Baru' di atas tabel. Amankan output variabel HTML menggunakan htmlspecialchars()."

Langkah 3: Form Tambah dan Update Data (create.php dan edit.php)

Gunakan prompt berikut untuk menggenerasi modul pemrosesan data:

"Buatkan file create.php dan edit.php beserta script penanganannya. Ketentuan: 1) Styling form menggunakan Bootstrap 5. 2) Gunakan Prepared Statements (mysqli_prepare) untuk proses INSERT dan UPDATE. 3) Validasi server-side: input tidak boleh kosong, stok tidak boleh negatif. 4) Setelah sukses eksekusi, redirect ke index.php dengan status success."

Langkah 4: Penghapusan Data Secure (delete.php)

Gunakan prompt berikut untuk fitur hapus data:

"Buatkan file delete.php yang menerima parameter id melalui method GET. Gunakan Prepared Statement untuk menghapus data berdasarkan id. Pada index.php, tambahkan konfirmasi JavaScript (onclick confirm) pada tombol hapus sebelum mengarah ke delete.php."

Implementasi Kode PHP Native dan MySQLi Procedural

Berikut adalah implementasi kode lengkap hasil generasi prompt di atas yang telah diverifikasi kelayakannya.

1. File Koneksi: db.php

<?php
$host = "localhost";
$user = "root";
$pass = "";
$db   = "toko_db";

$conn = mysqli_connect($host, $user, $pass, $db);

if (!$conn) {
    die("Koneksi database gagal: " . mysqli_connect_error());
}
?>

2. File Halaman Utama: index.php

<?php
require_once 'db.php';
$query = "SELECT * FROM products ORDER BY id DESC";
$result = mysqli_query($conn, $query);
?>
<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <title>Manajemen Produk</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="container py-4">
    <h2 class="mb-4">Daftar Produk</h2>
    <a href="create.php" class="btn btn-primary mb-3">Tambah Produk Baru</a>
    <table class="table table-bordered table-striped">
        <thead class="table-dark">
            <tr>
                <th>No</th>
                <th>Nama Produk</th>
                <th>SKU</th>
                <th>Harga</th>
                <th>Stok</th>
                <th>Aksi</th>
            </tr>
        </thead>
        <tbody>
            <?php 
            $no = 1;
            while ($row = mysqli_fetch_assoc($result)) : 
            ?>
            <tr>
                <td><?= $no++; ?></td>
                <td><?= htmlspecialchars($row['name'], ENT_QUOTES, 'UTF-8'); ?></td>
                <td><?= htmlspecialchars($row['sku'], ENT_QUOTES, 'UTF-8'); ?></td>
                <td>Rp <?= number_format($row['price'], 0, ',', '.'); ?></td>
                <td><?= (int)$row['stock']; ?></td>
                <td>
                    <a href="edit.php?id=<?= $row['id']; ?>" class="btn btn-warning btn-sm">Edit</a>
                    <a href="delete.php?id=<?= $row['id']; ?>" class="btn btn-danger btn-sm" onclick="return confirm('Yakin ingin menghapus data ini?')">Hapus</a>
                </td>
            </tr>
            <?php endwhile; ?>
        </tbody>
    </table>
</body>
</html>

3. File Form Tambah Data: create.php

<?php
require_once 'db.php';
$error = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $name  = trim($_POST['name']);
    $sku   = trim($_POST['sku']);
    $price = $_POST['price'];
    $stock = $_POST['stock'];

    if (empty($name) || empty($sku) || $price === '' || $stock === '') {
        $error = "Semua field harus diisi!";
    } elseif ($stock < 0 || $price < 0) {
        $error = "Harga dan stok tidak boleh negatif!";
    } else {
        $stmt = mysqli_prepare($conn, "INSERT INTO products (name, sku, price, stock) VALUES (?, ?, ?, ?)");
        mysqli_stmt_bind_param($stmt, "ssdi", $name, $sku, $price, $stock);
        
        if (mysqli_stmt_execute($stmt)) {
            header("Location: index.php");
            exit;
        } else {
            $error = "Gagal menyimpan data: SKU mungkin sudah ada.";
        }
        mysqli_stmt_close($stmt);
    }
}
?>
<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <title>Tambah Produk</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="container py-4">
    <h2>Tambah Produk Baru</h2>
    <?php if ($error): ?>
        <div class="alert alert-danger"><?= $error; ?></div>
    <?php endif; ?>
    <form method="POST" class="w-50">
        <div class="mb-3">
            <label class="form-label">Nama Produk</label>
            <input type="text" name="name" class="form-control" required>
        </div>
        <div class="mb-3">
            <label class="form-label">SKU</label>
            <input type="text" name="sku" class="form-control" required>
        </div>
        <div class="mb-3">
            <label class="form-label">Harga</label>
            <input type="number" step="0.01" name="price" class="form-control" required>
        </div>
        <div class="mb-3">
            <label class="form-label">Stok</label>
            <input type="number" name="stock" class="form-control" required>
        </div>
        <button type="submit" class="btn btn-success">Simpan</button>
        <a href="index.php" class="btn btn-secondary">Batal</a>
    </form>
</body>
</html>

4. File Form Edit Data: edit.php

<?php
require_once 'db.php';
$id = $_GET['id'] ?? null;
if (!$id) { header("Location: index.php"); exit; }

$stmt = mysqli_prepare($conn, "SELECT * FROM products WHERE id = ?");
mysqli_stmt_bind_param($stmt, "i", $id);
mysqli_stmt_execute($stmt);
$product = mysqli_fetch_assoc(mysqli_stmt_get_result($stmt));
mysqli_stmt_close($stmt);

if (!$product) { header("Location: index.php"); exit; }

$error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $name  = trim($_POST['name']);
    $sku   = trim($_POST['sku']);
    $price = $_POST['price'];
    $stock = $_POST['stock'];

    if (empty($name) || empty($sku) || $price === '' || $stock === '') {
        $error = "Semua field harus diisi!";
    } else {
        $updateStmt = mysqli_prepare($conn, "UPDATE products SET name=?, sku=?, price=?, stock=? WHERE id=?");
        mysqli_stmt_bind_param($updateStmt, "ssdii", $name, $sku, $price, $stock, $id);
        if (mysqli_stmt_execute($updateStmt)) {
            header("Location: index.php");
            exit;
        } else {
            $error = "Gagal memperbarui data.";
        }
        mysqli_stmt_close($updateStmt);
    }
}
?>
<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <title>Edit Produk</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="container py-4">
    <h2>Edit Produk</h2>
    <?php if ($error): ?>
        <div class="alert alert-danger"><?= $error; ?></div>
    <?php endif; ?>
    <form method="POST" class="w-50">
        <div class="mb-3">
            <label class="form-label">Nama Produk</label>
            <input type="text" name="name" class="form-control" value="<?= htmlspecialchars($product['name']); ?>" required>
        </div>
        <div class="mb-3">
            <label class="form-label">SKU</label>
            <input type="text" name="sku" class="form-control" value="<?= htmlspecialchars($product['sku']); ?>" required>
        </div>
        <div class="mb-3">
            <label class="form-label">Harga</label>
            <input type="number" step="0.01" name="price" class="form-control" value="<?= $product['price']; ?>" required>
        </div>
        <div class="mb-3">
            <label class="form-label">Stok</label>
            <input type="number" name="stock" class="form-control" value="<?= $product['stock']; ?>" required>
        </div>
        <button type="submit" class="btn btn-primary">Update</button>
        <a href="index.php" class="btn btn-secondary">Batal</a>
    </form>
</body>
</html>

5. File Eksekusi Hapus Data: delete.php

<?php
require_once 'db.php';

$id = $_GET['id'] ?? null;

if ($id) {
    $stmt = mysqli_prepare($conn, "DELETE FROM products WHERE id = ?");
    mysqli_stmt_bind_param($stmt, "i", $id);
    mysqli_stmt_execute($stmt);
    mysqli_stmt_close($stmt);
}

header("Location: index.php");
exit;
?>

Prosedur Pengujian Fitur

Pengujian aplikasi hasil generasi AI wajib dilakukan melalui empat tahapan skenario untuk memastikan seluruh fungsionalitas berjalan normal.

1. Pengujian Tambah Data (Create)

  • Input Valid: Masukkan nama "Kopi Arabika", SKU "KOP-001", harga "45000", stok "20". Data harus tersimpan dan tampil di tabel index.php.
  • Input Invalid: Kosongkan kolom input atau masukkan angka negatif pada stok. Sistem harus menolak eksekusi dan menampilkan pesan peringatan.
  • Handling Duplikat: Masukkan SKU yang sudah terdaftar. Sistem harus menanggulangi eror duplikasi tanpa menampilkan fatal error fatal MySQL server.

2. Pengujian Tampilan Data (Read)

Buka halaman index.php. Verifikasi bahwa data ditampilkan secara berurutan berdasarkan ID terbaru. Pastikan format angka harga diubah secara otomatis menjadi format mata uang Rupiah (contoh: Rp 45.000).

3. Pengujian Perubahan Data (Update)

Klik tombol 'Edit' pada salah satu baris data. Pastikan form edit.php terisi secara otomatis (pre-filled) dengan data produk terkait. Ubah nilai stok atau harga lalu tekan Update. Verifikasi perubahan langsung terefleksi pada halaman utama.

4. Pengujian Penghapusan Data (Delete)

Klik tombol 'Hapus' pada baris data. Dialog konfirmasi JavaScript harus muncul. Jika tombol 'Cancel' diklik, proses dibatalkan. Jika tombol 'OK' diklik, script delete.php mengeksekusi penghapusan dan mengarahkan kembali ke index.php.

Analisis Keamanan: Prepared Statement dan Anti-XSS

Kode yang dibuat oleh AI wajib diaudit terhadap dua jenis celah keamanan paling umum pada aplikasi web berbasis PHP.

1. Pencegahan SQL Injection

SQL Injection terjadi ketika input pengguna digabungkan langsung ke dalam query SQL tanpa sanitasi. Penggunaan Prepared Statements memisahkan antara struktur query SQL dan data input. Karakter berbahaya dalam input diisolasi sehingga dianggap sebagai nilai string murni, bukan perintah SQL.

Sintaks pemrosesan query aman menggunakan MySQLi:

$stmt = mysqli_prepare($conn, "DELETE FROM products WHERE id = ?");
mysqli_stmt_bind_param($stmt, "i", $id);
mysqli_stmt_execute($stmt);

2. Pencegahan Cross-Site Scripting (XSS)

XSS terjadi ketika karakter HTML atau JavaScript yang diinput oleh pengguna dieksekusi oleh browser saat data ditampilkan. Fungsi htmlspecialchars() mengubah karakter khusus seperti <, >, dan " menjadi HTML entities (contoh: &lt; dan &gt;), sehingga mencegah eksekusi skrip jahat pada browser pengguna.

echo htmlspecialchars($row['name'], ENT_QUOTES, 'UTF-8');

Checklist Kelayakan Operasional Modul

Sebelum modul CRUD dinyatakan selesai, pastikan seluruh poin pengujian pada tabel checklist berikut telah terpenuhi:

  • [x] File koneksi database terisolasi dan terpisah dari logika tampilan.
  • [x] Form HTML menyertakan atribut validasi tipe input bawaan HTML5 (seperti required dan type="number").
  • [x] Seluruh operasi INSERT, UPDATE, dan DELETE menggunakan mysqli_prepare.
  • [x] Variabel keluaran HTML dibungkus menggunakan htmlspecialchars().
  • [x] Fitur penghapusan data menyertakan modal/dialog konfirmasi interaktif.
  • [x] Penanganan eror SQL tidak memaparkan struktur sensitif database ke layar publik.

Kesimpulan dan Langkah Selanjutnya

Penerapan CRUD vibe coding membuktikan bahwa pengembangan modul backend berbasis PHP Native dan MySQLi dapat diselesaikan secara presisi dalam waktu singkat. Dengan menyerahkan tugas penulisan boilerplate code kepada AI dan berfokus pada kualitas prompt, arsitektur data, serta pengujian keamanan, produktivitas pengembang meningkat pesat.

Meskipun demikian, modul CRUD yang telah dibangun saat ini masih bersifat terbuka tanpa proteksi hak akses. Setiap pengguna yang mengetahui URL aplikasi dapat melakukan manipulasi data secara langsung.

Pada Bagian 6 dari Seri Belajar Vibe Coding, kita akan membahas cara mengamankan modul ini dengan mengimplementasikan Fitur Autentikasi User (Login & Register) serta Manajemen Session PHP menggunakan pendekatan prompt AI terstruktur.

📖 Artikel Terkait