Lewati ke isi

08 — Proyek Capstone: Membangun API Toko dari Nol dengan AI

← Glosarium | Index | Lanjut: Pustaka Prompt →


Bab ini menyatukan semua yang dipelajari (API + Database + Docker + Security) menjadi satu proyek nyata, dikerjakan sepenuhnya lewat AI dengan disiplin review. Tujuannya bukan menghafal kode — tapi mengalami loop kerja lengkap yang menghasilkan output berkualitas.

Yang dibangun: API mini toko online — produk, keranjang, checkout dengan pengurangan stok, dan riwayat order. Cukup kecil untuk selesai dalam beberapa sesi, cukup lengkap untuk menyentuh setiap topik.

Estimasi: 3–5 sesi. Kerjakan bertahap; jangan generate semua sekaligus.

📌 Framework di contoh memakai Laravel + PostgreSQL, tapi polanya berlaku untuk stack apa pun. Ganti detail sesuai tumpukan Anda saat memberi prompt.


Fase 0 — Spesifikasi (jangan lewati!)

Kualitas output vibe coding ditentukan di sini, bukan saat generate. Tulis dokumen singkat ini dulu:

PROYEK: API Toko Mini

ENTITAS & ATURAN BISNIS:
- Product: punya nama, harga, stok. Harga & stok bisa berubah.
- Cart: satu cart aktif per user. Berisi banyak item.
- CartItem: product + quantity.
- Order: dibuat dari cart saat checkout. Menyimpan total & status.
- OrderItem: SALINAN product+harga+qty saat checkout (harga tidak boleh berubah kemudian).

ATURAN KRITIS:
1. Checkout mengurangi stok. Stok tidak boleh minus (anti-overselling).
2. Checkout = transaction: buat order + order_items + kurangi stok, semua-atau-batal.
3. User hanya mengakses cart & order MILIKNYA (anti-IDOR).
4. Harga di order_items disalin saat checkout (price_at_time).

ENDPOINT:
GET    /v1/products                 publik      200
GET    /v1/products/{id}            publik      200 | 404
GET    /v1/cart                     auth        200
POST   /v1/cart/items               auth        201 | 422
DELETE /v1/cart/items/{product_id}  auth        204 | 404
POST   /v1/checkout                 auth        201 | 422(stok kurang/cart kosong)
GET    /v1/orders                   auth        200  (hanya milik user)
GET    /v1/orders/{id}              auth        200 | 404 (hanya milik user)

Simpan ini sebagai docs/spec.md. Ini kontrak yang akan Anda pegang di setiap review.


Fase 1 — Fondasi Docker

Bangun environment sebelum kode, supaya "jalan di laptop saya" tidak pernah jadi masalah.

💡 Prompt: "Buatkan docker-compose.yml untuk proyek Laravel 11 + PostgreSQL 16 + Redis 7. Syarat (wajib semua): data Postgres di named volume; semua credential lewat .env dengan .env.example yang nilainya kosong; healthcheck untuk Postgres; service app menunggu Postgres sehat; versi image spesifik (bukan latest); sertakan .dockerignore yang mengabaikan .env, node_modules, vendor, .git. Jangan hardcode password di mana pun."

Gate review sebelum lanjut (dari checklist §Docker): - [ ] Tidak ada password hardcoded — cari manual di semua file - [ ] .env ada di .gitignore DAN .dockerignore - [ ] Postgres pakai volume + healthcheck - [ ] Image pakai versi spesifik

Jalankan docker compose up -d sampai semua service healthy. Baru lanjut.


Fase 2 — Skema Database

Desain data dulu — ini menentukan segalanya.

💡 Prompt (desain): "Berdasarkan spec ini [tempel Fase 0], buatkan ERD Mermaid dan jelaskan tiap relasi & keputusan penting. JANGAN tulis kode dulu — saya mau review desainnya. Perhatikan khusus: bagaimana order_items menyalin harga, dan bagaimana mencegah stok minus."

Review ERD terhadap spec. Tantang balik: "Bagaimana kalau produk dihapus setelah masuk order lama? Apakah order_items masih menyimpan namanya?" (Jawaban benar: order_items harus menyimpan salinan nama+harga, tidak sekadar FK ke products.)

💡 Prompt (migration): "Setuju dengan ERD. Buat migration Laravel untuk semua tabel. Wajib: harga DECIMAL(15,2); FK + index; order_items menyimpan product_name & price_at_time (salinan); constraint stock >= 0; timestamps; soft delete untuk products; rollback lengkap."

Gate review (dari checklist §Database): - [ ] Harga DECIMAL, bukan float - [ ] order_items punya salinan harga & nama — bukan cuma product_id - [ ] Constraint stock >= 0 ada di level DB - [ ] Semua FK ter-index - [ ] Migration punya rollback

Jalankan migration. Buat seeder berisi 5 produk contoh.


Fase 3 — Endpoint Baca (paling aman dulu)

Mulai dari yang tidak mengubah data — risiko rendah, membangun momentum.

💡 Prompt: "Implementasikan GET /v1/products (dengan pagination 20/halaman + filter opsional ?search=) dan GET /v1/products/{id} (404 bila tidak ada). Response format konsisten: bungkus dalam data, sertakan meta untuk pagination, harga sebagai integer/desimal konsisten, timestamps ISO 8601. Terapkan praktik: escape output, tidak ada N+1."

Gate review (§API + §Database): - [ ] GET benar-benar read-only - [ ] Pagination ada (tidak mengembalikan seluruh tabel) - [ ] 404 untuk produk tidak ada — cek dengan curl - [ ] Tidak ada N+1 (tanya AI: "berapa query yang dijalankan endpoint ini?")

Tes dengan tabel (Langkah 3 di tutorial §2.14).


Fase 4 — Endpoint Cart (mulai ada auth & kepemilikan)

Sekarang masuk wilayah yang butuh autentikasi + otorisasi.

💡 Prompt: "Implementasikan auth Bearer (Laravel Sanctum) dan endpoint cart: GET /v1/cart, POST /v1/cart/items ({product_id exists, quantity min 1}), DELETE /v1/cart/items/{product_id}. WAJIB: user hanya mengakses cart miliknya sendiri (cek kepemilikan eksplisit, bukan hanya cek login); validasi lewat FormRequest; duplikat item menambah quantity, bukan baris baru; response 201/204/422/404 sesuai spec."

Gate review (§Security — ini titik rawan!): - [ ] Setiap endpoint cek kepemilikan, bukan cuma login (anti-IDOR) - [ ] Uji manual: login user A, coba hapus item cart user B → harus gagal - [ ] Validasi di server (FormRequest), bukan cuma frontend - [ ] product_id divalidasi exists


Fase 5 — Checkout (puncak: transaction + race condition)

Endpoint paling kritis — menyentuh uang, stok, dan konsistensi. Perlakukan sebagai risiko 🔴.

💡 Prompt: "Implementasikan POST /v1/checkout. Alur: ambil cart user login → validasi tidak kosong → untuk tiap item cek & kurangi stok secara ATOMIC (aman dari race condition, tidak boleh oversell) → buat order + order_items (salin nama & harga produk saat ini) → hitung total → kosongkan cart. SEMUA dalam satu database transaction (batal total bila ada langkah gagal). Response: 201 + order; 422 bila cart kosong atau stok kurang (sebut produk mana). Jelaskan mekanisme anti-race-condition yang kamu pakai."

Gate review — paling ketat (§Database §3.8 + §Security): - [ ] Seluruh operasi dibungkus transaction (cari DB::transaction / BEGIN) - [ ] Pengurangan stok atomic (WHERE stock >= qty lalu cek baris terpengaruh, atau lock) — bukan baca-lalu-tulis terpisah - [ ] Harga & nama disalin ke order_items - [ ] Cart kosong → 422, bukan order Rp0 - [ ] Kepemilikan cart dicek

Tes race condition (penting!): minta AI menulis skrip yang mengirim 5 request checkout bersamaan untuk produk berstok 3. Hasil benar: 3 sukses, 2 gagal 422, stok akhir = 0 (bukan negatif). Kalau stok jadi negatif → mekanisme atomic-nya salah, kembali ke prompt.


Fase 6 — Endpoint Order & Finalisasi

💡 Prompt: "Implementasikan GET /v1/orders dan GET /v1/orders/{id} — hanya menampilkan order milik user login (anti-IDOR), dengan order_items-nya (tanpa N+1). Lalu buatkan spesifikasi OpenAPI 3.0 untuk SELURUH API ini."

Gate review akhir — jalankan checklist bab 06 secara penuh di seluruh proyek, plus:

💡 Prompt audit menyeluruh: "Audit SELURUH codebase proyek ini sebagai senior + security engineer. Cek terhadap daftar ini: [tempel checklist bab 06]. Untuk tiap file, laporkan temuan format [severity — file:baris — masalah — perbaikan]. Nyatakan eksplisit kategori yang bersih. Jangan mengarang temuan."


Definition of Done — Kapan Proyek "Selesai"

Output vibe coding disebut berkualitas kalau semua ini terpenuhi:

Fungsional - [ ] Semua 8 endpoint jalan sesuai spec Fase 0 - [ ] Setiap endpoint lulus tabel tes (happy path + edge case) - [ ] Checkout lulus tes race condition (stok tak pernah negatif)

Kualitas kode - [ ] Tidak ada N+1 di endpoint list - [ ] Operasi multi-tabel pakai transaction - [ ] Format response konsisten di semua endpoint

Keamanan - [ ] Setiap endpoint auth mengecek kepemilikan data (uji silang antar user) - [ ] Tidak ada secret hardcoded; .env ter-gitignore - [ ] Validasi server-side di semua input - [ ] Password (bila ada register) di-hash bcrypt/argon2

Infrastruktur - [ ] docker compose up -d menjalankan seluruh stack dari nol - [ ] Data Postgres selamat setelah docker compose down lalu up (volume benar) - [ ] Migration bisa dijalankan di environment kosong

Dokumentasi - [ ] docs/spec.md dan spesifikasi OpenAPI tersedia - [ ] Setiap fitur punya catatan tes

Kalau ada satu saja yang belum ✅ — proyek belum selesai, terlepas dari "sudah kelihatan jalan".


Yang Baru Saja Anda Latih

Bukan sekadar membuat API. Anda melatih loop kerja yang membedakan vibe coding amatir dari profesional:

Spesifikasi jelas → prompt presisi → generate → review dengan checklist →
tes edge case → revisi berbukti → gate sebelum lanjut → definition of done

Loop inilah produk sebenarnya dari seluruh materi ini. Framework berganti, bahasa berganti, model AI berganti — loop ini tetap.


← Glosarium | Index | Lanjut: Pustaka Prompt →