7.6 KiB
| name | description |
|---|---|
| cleo-code-review | Review struktur dan penulisan kode Cleo Minimarket (Next.js 16, Server Actions, Drizzle, MariaDB MyISAM) terhadap aturan CLAUDE.md dan bug yang pernah ditemukan. Pakai saat diminta "review", "cek kode", "cek commit yang belum dipush", atau sebelum push. |
cleo-code-review
Review read-only atas perubahan kode di proyek ini. Tujuannya menangkap bug nyata dan pelanggaran aturan proyek sebelum di-push. Jangan memperbaiki file kecuali diminta.
1. Tentukan cakupan
- Default: commit yang belum di-push plus perubahan yang belum di-commit.
git status -sb git log --oneline '@{u}..HEAD' git diff --stat '@{u}' git diff '@{u}' - Kalau user menyebut commit, branch, atau file tertentu, pakai itu.
- Abaikan
old-source/,backup/,drizzle/,components/ui/,db/amigo/schema.ts(referensi, backup, atau generated), kecuali perubahannya memang di sana dan mencurigakan.
2. Jalankan pengecekan otomatis
pnpm exec tsc --noEmit
pnpm lint
pnpm exec prettier --check <file yang berubah>
pnpm build
Kutip baris error terpendek yang menentukan. Build perlu dijalankan karena cacheComponents
membuat error Suspense baru muncul di build, bukan di tsc.
3. Baca diff dengan checklist ini
Untuk temuan di sekitar kode, baca file utuhnya, jangan hanya potongan diff.
Auth dan routing
proxy.tshanya redirect berdasarkan ada/tidaknya cookie. Redirect "sudah login -> /" di proxy memicu loop saat cookie kedaluwarsa (proxy kirim ke/,getCurrentUser()kirim ke/login). Redirect seperti itu harus memakai session yang divalidasi (redirectIfLoggedIn()didata/auth.ts), dipanggil dari page di dalam<Suspense>.- Matcher proxy harus tetap mengecualikan
login,api, dan aset statis. - Import dari path internal Next (
next/dist/...) hampir selalu salah. - Page dan action yang butuh user memanggil
getCurrentUser(); layout tidak dipakai untuk cek session. - Komponen yang membaca
headers()/cookies()/searchParamsberada di dalam<Suspense>.
Server Actions
- File bernama
actions.ts(jamak), diawali"use server", dikolokasikan dengan fitur. - Setiap action: cek session, validasi zod sebelum menyentuh DB, panggil fungsi
data/(bukan query langsung), kembalikan objek kecil,revalidatePathsebelumredirect. - Error validasi dikembalikan per field (
z.flattenError(err).fieldErrors), bukan hanyaissues[0].message; kalau tidak, pesan tampil di field yang salah. - Return yang gagal ikut membawa
values(isian mentah), karena React 19 me-reset form setelah action selesai dan ketikan user hilang. console.errorberisi tag nama action,user.id, input relevan (tanpa password/secret), dan error asli sebagai argumen terpisah. Pesan ke UI bahasa Indonesia dan bisa ditindaklanjuti, tidak pernah pesan DB mentah.- Hasil
getCurrentUser()disimpan ke variabel kalau dipakai di log.
Komponen client
- Jangan menutup sheet/dialog lewat
useEffect(() => { if (state.ok) setOpen(false) }, [state.ok]): tidak jalan lagi saat sukses kedua (true -> true) dan dilarang lintreact-hooks/set-state-in-effect. Bungkus action diuseActionStatedan panggilsetOpen(false)di sana. - Input form memakai
defaultValue={state.values?.[name] ?? dataAwal ?? ""}; error per field ditampilkan di<FieldError>field itu, error umum di dekat tombol submit. - Tipe dari modul
data/(server-only) di-import denganimport type. - Konfirmasi destruktif memakai
AlertDialog, bukanSheetyang di-override class-nya. Tombol konfirmasi berupaButton type="submit"supaya error action sempat terlihat. - Prop yang tidak dipakai pemanggil mana pun dibuang.
Data Access Layer (data/)
- Diawali
import "server-only". - Fungsi yang diekspor tapi tidak dipakai di mana pun: tandai untuk dihapus.
- Tipe input diturunkan dari tipe baris (
Omit<...>) daripada ditulis ulang manual. - Query lewat Drizzle atau
sqltag, tidak pernah string concatenation. PolaLIKEmemakai escape\,%,_. - MariaDB
cleoitu MyISAM: tidak ada transaksi danFOR UPDATEtidak mengunci. Penomoran otomatis harus tahan bentrok dengan PHP lama (retry saatER_DUP_ENTRY), update stok atomik satu statement, master + detail divalidasi penuh sebelum statement pertama. - Tanggal "hari ini" pakai zona
Asia/Jakarta, bukantoISOString()(UTC). - Tanggal
0000-00-00tetap string, tidak diubah keDate. - Batas panjang zod sama dengan panjang kolom di
db/amigo/schema.ts. - Aturan bisnis dicocokkan dengan kode lama di
old-source/(mis. format kode pelanggan).
Struktur dan maintainability
Bagian ini butuh konteks di luar diff. Kalau diff menambah atau mengubah fitur, baca juga fitur lain yang sejenis.
- Fitur baru mengikuti pola fitur acuan
app/(dashboard)/master/pelanggan/:page.tsx,actions.ts,_components/, dan satu filedata/<fitur>.tsper domain. Penyimpangan dari pola itu harus punya alasan yang jelas. - Nama fungsi
data/seragam antar fitur:list<Fitur>,get<Fitur>,insert<Fitur>,update<Fitur>,delete<Fitur>. Istilah domain konsisten (mis.pelanggan, bukan campurcustomer), kecuali nama kolom/tabel lama didb/amigo/schema.ts. - Arah dependency:
app/boleh importdata/,components/,lib/;data/boleh importdb/danlib/. Tidak boleh sebaliknya (data/ataulib/import dariapp/).- Fitur A tidak import
_components/atauactions.tsmilik fitur B. Kalau dibutuhkan bersama, pindahkan komponen kecomponents/atau logika kelib//data/. components/(lintas fitur) tidak import dariapp/.
- Duplikasi lintas fitur: kode yang sama muncul di fitur kedua dipindah ke satu tempat
bersama, bukan disalin. Kandidat umum: escape
LIKE, tipe hasil action ({ ok, error, fieldErrors, values }), pola log error action, pagination, kotak pencarian, skema zod yang berulang. Jangan memindahkan saat baru dipakai satu fitur. - Aturan bisnis lama (kode huruf harga
convHrgP/convProfit, format tanggaldd-mm-yyyy, tanggal "hari ini"Asia/Jakarta) punya satu implementasi dilib/, tidak ditulis ulang per fitur. data/tidak berisi logika tampilan (format rupiah, format tanggal untuk UI, teks label).- File di atas sekitar 250 baris, atau komponen yang mengerjakan beberapa hal sekaligus (form, daftar, dan dialog dalam satu file), ditandai untuk dipecah.
- Navigasi: setiap
hrefdiapp/(dashboard)/_components/nav-items.tspunyapage.tsx, dan setiap page baru di(dashboard)terdaftar di nav (kecuali halaman detail/turunan). - Kalau perubahan memperkenalkan konvensi baru (folder, helper bersama, pola action), cek
apakah
CLAUDE.mdikut diperbarui supaya fitur berikutnya mengikuti pola yang sama.
Kerapian
- Format sesuai Prettier (titik koma, baris tidak terlalu panjang, newline di akhir file).
- Urutan import: package luar, baris kosong, lalu
@/..., lalu path relatif. - Nama file kebab-case, komponen PascalCase, import lintas folder lewat alias
@/.
4. Laporkan
Kalimat pertama berisi kesimpulan: siap di-push atau belum, dan hasil tsc/lint/build.
Lalu temuan dikelompokkan dan diberi nomor berurutan lintas kelompok:
- Bug: perilaku salah yang bisa dialami user. Sertakan skenario konkretnya.
- Tidak sesuai aturan proyek: pelanggaran CLAUDE.md.
- Struktur dan maintainability: menyimpang dari pola fitur acuan, arah dependency salah, duplikasi lintas fitur, file terlalu besar, nav tidak sinkron.
- Kerapian: format, kode mati, duplikasi kecil di dalam satu file.
Setiap temuan menyebut file:baris, apa yang salah, dan arah perbaikannya dalam satu atau
dua kalimat. Tutup dengan daftar singkat hal yang sudah benar, lalu saran urutan perbaikan.