# AGENTS.md — Module/Feature Development Checklist > Checklist saat membuat module atau fitur baru. ## ⚠️ WAJIB BACA SEBELUM KERJA Sebelum memulai/modifikasi apapun, **WAJIB** baca file di `.ai/` folder: ``` .ai/ ├── CONTEXT.md # Project context, roles, module mapping ├── REFERENCE.md # Database schema (tabel, relasi, enums) └── CONVENTIONS.md # Aturan kode (backend + frontend) ``` **Baca urutan:** 1. `CONTEXT.md` → pahami project, role, dan module 2. `REFERENCE.md` → pahami struktur data 3. `CONVENTIONS.md` → pahami cara nulis kode **Jangan pernah skip membaca `.ai/` folder** — semua aturan ada di sana. **Catatan Penting:** - File `.ai/` adalah **contoh best practice & referensi**, bukan berarti semua pola di situ sudah ada di project - Jika pola di `.ai/` belum ada di project → **ikuti pola yang sudah ada di codebase** - Jangan buang waktu mencari file/pattern yang belum tentu ada --- ## Workflow: Trace Codebase Sebelum mengubah/menambah fitur, **pahami dulu alur kode yang sudah ada**. ### Cara Trace: Mulai dari file yang relevan (Route/Controller/Service), lalu **ikuti setiap pemanggilan**: - Jika ada `use ... Service` → baca file Service - Jika ada `use ... Model` → baca file Model - Jika ada `use ... Trait` → baca file Trait - Jika ada `use ... Enum` → baca file Enum - Jika ada Form Request → baca file Form Request ### Contoh Trace: ``` ProductController └── panggil ProductService → baca └── panggil Product model → baca └── pakai HasFactory trait → baca ``` **Ikuti terus sampai semua pemanggilan dipahami. Jangan ubah kode tanpa memahami alur yang sudah ada.** --- ## Documentation: Catatan Session Kerja Setiap kali bekerja pada suatu fitur, **WAJIB** buat/dokumentasi di `/docs` folder. ### Format: `/docs/{nama-fitur}.md` Isi dokumen: 1. **Tujuan** — fitur apa yang dibuat/diubah 2. **File yang dibaca** — daftar file + ringkasan singkat 3. **Pola yang ditemukan** — struktur kode, relasi, flow 4. **Perubahan yang dilakukan** — apa saja yang diubah ### Contoh: ```markdown # Fitur: Transfer Stok Produk ## Tujuan Menambah fitur perpindahan stok dari gudang baik ke reject ## File yang Dibaca - `routes/web.php` → ProductController di route `admin.manage.products` - `app/Http/Controllers/Admin/Manage/ProductController.php` → ada method `index`, `store`, `update` - `app/Services/Admin/Manage/ProductService.php` → panggil Product model, pakai `HasStockAdjustment` trait - `app/Models/Product.php` → relasi `stocks()`, accessor `formatted_stock` ## Pola yang Ditemukan - Service handle logic, Controller zero logic - Pakai trait `HasStockAdjustment` untuk adjust stock - Stock ada di tabel `stocks` dengan relasi ke product ## Perubahan - Tambah method `transferStock()` di ProductService - Tambah route `POST /products/{product}/transfer-stock` ``` ### Kapan harus update? - Saat mulai sesi baru → buat dokumen baru - Saat lanjut sesi sebelumnya → baca dulu dokumen yang sudah ada --- ## Backend ### 1. Migration ```bash php artisan make:migration create_{table}_table ``` - [ ] Kolom sesuai kebutuhan - [ ] Foreign key → `$table->foreignId('user_id')->constrained()->cascadeOnDelete()` - [ ] Custom FK → `$table->foreignId('created_by_id')->constrained('users')->restrictOnDelete()` - [ ] Soft deletes → `$table->softDeletes()` (kecuali: Attendance, StokOpnameItem, RetailStockHistory, StockMutation) - [ ] Timestamps → `$table->timestamps()` ### 2. Model ```bash php artisan make:model {Model} -m ``` - [ ] `#[Guarded(['id'])]` — jangan pakai $fillable - [ ] `#[Appends([...])]` — di atas class declaration - [ ] `protected function casts(): array` — method syntax, bukan property - [ ] Scopes — `#[Scope]` + `protected function name(Builder $query): void` - [ ] Accessors — `Attribute::make(get: fn () => ...)`, NAMA BERBEDA dari kolom DB - [ ] Relasi — WAJIB 2 ARAH di kedua model - [ ] Select — `select(['id', 'name', ...])` + eager load relasi **Urutan isi model:** 1. `casts()` 2. Scopes (abjad) 3. Accessors (abjad) 4. Relations (abjad) ### 3. Enum (jika perlu) ```bash php artisan make:enum {EnumName} ``` - [ ] Pakai `HasValues` trait - [ ] Buat `label(): string` method - [ ] Buat scopes untuk setiap case ### 4. Service ```bash # Manual create app/Services/Admin/{Module}/{Model}Service.php ``` - [ ] Return type di SEMUA method - [ ] Method wajib: `paginated()`, `getAll()`, `store()`, `update()`, `destroy()` - [ ] Select kolom yang dibutuhkan + eager load relasi - [ ] Gunakan traits jika perlu: `HandlesCashTransactions`, `HasStockAdjustment`, `RegistersMedia` - [ ] Urutan method: CRUD → custom methods → private helpers (di paling bawah) ### 5. Form Request ```bash php artisan make:request {Model}Request ``` - [ ] `authorize(): bool` → return true - [ ] `rules(): array` → validasi sesuai kebutuhan - [ ] `attributes(): array` → label Bahasa Indonesia - [ ] `prepareForValidation()` → strip currency jika ada input Rupiah - [ ] Unique ignore → `Rule::unique('table')->ignore($this->route('model')?->id)` ### 6. Controller ```bash php artisan make:controller Admin/{Module}/{Model}Controller ``` - [ ] Constructor promotion → `public function __construct(private {Model}Service $service) {}` - [ ] Return type di SEMUA method (`Response`) - [ ] Zero logic — semua di service - [ ] Flash → `Inertia::flash('toast', ['type' => 'success', 'message' => '...'])` sebelum `return back()` - [ ] `handleAction()` untuk 2+ query - [ ] Method order: `__construct`, `index`, `create`, `store`, `show`, `edit`, `update`, `destroy`, custom actions ### 7. Route ```php // routes/web.php Route::resource('{module}', {Model}Controller::class) ->parameters(['{module}' => '{model}']); ``` - [ ] Route group sesuai module - [ ] Middleware `permission:{permission}` jika perlu ### 8. Permission ```php // database/seeders/RolePermissionSeeder.php ``` - [ ] Tambah permissions: `{model}.view`, `{model}.create`, `{model}.update`, `{model}.delete` - [ ] Assign ke role yang sesuai --- ## Frontend ### 9. Columns ```bash resources/js/pages/admin/{module}/{model}/columns.tsx ``` - [ ] Type definition → `export type {Model} = { ... }` - [ ] Column factory → `export function create{Model}Columns(params): ColumnDef<{Model}>[]` - [ ] Gunakan `formatted_*` accessor dari model, bukan format di TypeScript - [ ] Actions column → conditional on `can('{model}.update')` / `can('{model}.delete')` ### 10. Index Page ```bash resources/js/pages/admin/{module}/{model}/index.tsx ``` - [ ] Simple CRUD → `DataTable` + `FormDialog` + `DeleteConfirmDialog` - [ ] Complex list → `CardTable` + `FilterPopover` + `useCardTableExpand` - [ ] Hooks: `useCan()`, `useServerTable()` - [ ] Permission check → `can('{model}.create')` untuk tombolTambah ### 11. Create/Edit Page ```bash resources/js/pages/admin/{module}/{model}/create.tsx resources/js/pages/admin/{module}/{model}/edit.tsx ``` - [ ] Simple CRUD → inline `FormDialog` di index page - [ ] Complex form → full-page `
` + draft saving - [ ] Gunakan `RupiahInput`, `NumberInput`, `FileUpload`, `Combobox` sesuai kebutuhan - [ ] Route helpers → Ziggy (`route('admin.{module}.{model}.store')`) ### 12. Sidebar ```tsx // resources/js/components/app-sidebar.tsx ``` - [ ] Tambah item di `masterItems` / `manageItems` / `financeItems` / `hrItems` - [ ] Permission → `permission: '{model}.view'` - [ ] Icon → dari `lucide-react` --- ## Testing ### 13. Manual Test - [ ] Create — form validasi, flash message, redirect - [ ] Read — data muncul di index, pagination, search - [ ] Update — form terisi data lama, flash message - [ ] Delete — konfirmasi, flash message - [ ] Permission — user tanpa akses tidak bisa akses - [ ] Relasi — eager load tidak N+1 --- ## Update `.ai/` Files > **WAJIB** update `.ai/` files saat ada perubahan supaya tetap updated. ### Kapan harus update? - [ ] Tambah kolom baru → update `REFERENCE.md` (tambah kolom + type + relation) - [ ] Tambah migration baru → update `REFERENCE.md` (tambah tabel baru) - [ ] Tambah relasi baru → update `REFERENCE.md` (tambah relasi di 2 model) - [ ] Tambah model baru → update `CONTEXT.md` (tambah ke Module Overview) - [ ] Tambah role/permission baru → update `CONTEXT.md` (tambah ke Roles & Akses) - [ ] Tambah enum baru → update `REFERENCE.md` (tambah ke tabel Enums) - [ ] Tambah service trait baru → update `REFERENCE.md` (tambah ke Service Concerns) - [ ] Tambah accessor baru → update `CONVENTIONS.md` jika ada pattern baru ### Checklist update `.ai/`: ``` □ REFERENCE.md — kolom/tabel/relasi/enum sudah sesuai? □ CONTEXT.md — module mapping sudah sesuai? □ CONVENTIONS.md — ada pattern baru yang perlu ditambah? ``` --- ## Quick Reference ### File Paths | Item | Path | |------|------| | Migration | `database/migrations/` | | Model | `app/Models/` | | Enum | `app/Enums/` | | Service | `app/Services/Admin/{Module}/` | | Form Request | `app/Http/Requests/Admin/{Module}/` | | Controller | `app/Http/Controllers/Admin/{Module}/` | | Route | `routes/web.php` | | Permission | `database/seeders/RolePermissionSeeder.php` | | Columns | `resources/js/pages/admin/{module}/{model}/columns.tsx` | | Index | `resources/js/pages/admin/{module}/{model}/index.tsx` | | Create | `resources/js/pages/admin/{module}/{model}/create.tsx` | | Edit | `resources/js/pages/admin/{module}/{model}/edit.tsx` | | Sidebar | `resources/js/components/app-sidebar.tsx` | ### Conventions - Baca `.ai/CONVENTIONS.md` untuk aturan lengkap - Baca `.ai/REFERENCE.md` untuk database schema - Baca `.ai/CONTEXT.md` untuk project context & roles