siakad-itm/docs/code-style.md
Yoga Pangestu 353829e053
Some checks failed
tests / ci (pull_request) Has been cancelled
feat: Refactor Admin Manage structure into sub-namespaces for better organization
- Created sub-namespaces under Admin\Manage for Course, Academic, Announcement, Finance, and Service.
- Added new FormRequest classes for handling validation in each sub-namespace.
- Implemented Service classes for managing business logic related to each resource.
- Updated routes to reflect the new sub-namespace structure.
- Enhanced code organization and maintainability by grouping related functionalities.
2026-08-25 21:17:48 +07:00

178 lines
6.6 KiB
Markdown

# Panduan Gaya Kode
Dokumen ini mencatat konvensi penulisan kode di proyek ini, supaya kontributor
(termasuk AI assistant) mengikuti pola yang sama dan tidak menulis ulang
solusi yang sudah ada dengan cara berbeda-beda di tiap file.
Setiap bagian punya status:
-**Selesai** — sudah diterapkan di seluruh kode yang relevan.
- 🚧 **Sebagian** — sudah ada polanya, tapi belum diterapkan di semua tempat.
- 📝 **Rencana** — baru berupa kesepakatan, belum diterapkan.
---
## 1. Enum ✅
**Aturan:** setiap backed enum (`enum X: string`) wajib pakai trait
`App\Enums\Concerns\HasValues`. Jangan pernah menulis
`array_values(X::cases())` atau `array_column(X::cases(), 'value')` secara
manual — pakai `X::values()` (atau `X::options()` kalau butuh label untuk
dropdown/select).
```php
// app/Enums/Concerns/HasValues.php
trait HasValues
{
public static function values(): array // ['male', 'female']
public static function options(): array // [{value: 'male', label: 'Laki-laki'}, ...]
}
```
Struktur enum standar:
```php
enum Gender: string
{
use HasValues;
case Male = 'male';
case Female = 'female';
public function label(): string
{
return match ($this) {
self::Male => 'Laki-laki',
self::Female => 'Perempuan',
};
}
}
```
**Sebelum → Sesudah**
```php
// ❌ Jangan
'gender' => ['required', 'string', Rule::in(array_values(Gender::cases()))],
'type' => ['required', 'string', Rule::in(array_column(FeedbackType::cases(), 'value'))],
// ✅ Pakai
'gender' => ['required', 'string', Rule::in(Gender::values())],
'type' => ['required', 'string', Rule::in(FeedbackType::values())],
```
Untuk data yang dikirim ke frontend (mis. isi `<Select>`), pakai `options()`
alih-alih membangun array `{value, label}` manual dengan `array_map`:
```php
// ❌ Jangan
'types' => array_map(fn (FeedbackType $type) => [
'value' => $type->value,
'label' => $type->label(),
], FeedbackType::cases()),
// ✅ Pakai
'types' => FeedbackType::options(),
```
Enum baru **wajib** langsung pakai `use HasValues;` sejak awal dibuat, tidak
perlu menunggu ada kebutuhan `values()`/`options()` baru ditambahkan.
---
## 2. Migration ✅
**Aturan:** kolom `enum()` di migration wajib pakai `EnumClass::values()`,
konsisten dengan aturan Enum di atas. Kolom `->default()` wajib pakai
`EnumClass::Case->value` (string), bukan objek case-nya langsung.
```php
// ❌ Jangan
$table->enum('status', array_values(StudentStatus::cases()))
->nullable()
->default(StudentStatus::Active); // objek enum, bukan string
// ✅ Pakai
$table->enum('status', StudentStatus::values())
->nullable()
->default(StudentStatus::Active->value);
```
---
## 3. Bahasa UI ✅
Seluruh teks yang tampil ke pengguna (label, judul halaman, pesan toast,
placeholder, pesan error) ditulis dalam **Bahasa Indonesia**. Istilah teknis
dan identifier kode tetap dalam bahasa aslinya (bahasa Inggris), tapi teks
yang dibaca pengguna — termasuk teks di halaman auth/settings bawaan
starter-kit yang aslinya berbahasa Inggris — harus diterjemahkan supaya
konsisten dengan sisa aplikasi.
---
## 4. Struktur modul Admin ✅
Semua fitur berada di bawah `/admin` — tidak ada lagi controller atau
halaman yang menggantung di top-level `App\Http\Controllers` /
`resources/js/pages/` di luar folder `admin/`. Setiap fitur admin baru
(CRUD) mengikuti struktur namespace yang sama, di salah satu dari lima grup:
| Grup | Namespace Controller/Request | Prefix route |
| ------------------ | --------------------------------------- | ------------------ |
| Master data | `Admin\Master` | `admin/master/*` |
| Data operasional | `Admin\Manage` | `admin/manage/*` |
| Manajemen pengguna | `Admin\Users` | `admin/users/*` |
| Pengaturan akun | `Admin\Settings` | `admin/settings/*` |
| Resource mandiri | `Admin` (langsung, tanpa sub-namespace) | `admin/<resource>` |
"Resource mandiri" dipakai untuk fitur yang tidak cocok masuk ke 4 grup di
atas — misalnya `Admin\FeedbackController` di `admin/feedback` (data
personal milik user yang sedang login, bukan data akademik yang dikelola
admin atas user lain).
Nama route mengikuti pola `admin.<grup>.<resource>.<action>` (atau
`admin.<resource>.<action>` untuk resource mandiri), dan file Wayfinder
hasil generate mengikuti struktur folder yang sama di
`resources/js/routes/admin/<grup>/<resource>/`.
Halaman CRUD frontend memakai pola: `PageHeader` (judul + tombol Tambah) →
`FormDialog` (Create/Edit) → `DataTable` + `columns.tsx``DeleteConfirmDialog`.
### 4.1 Sub-namespace di dalam `Admin\Manage`
`Admin\Manage` sendiri dipecah lagi jadi 5 sub-namespace, mengikuti
pengelompokan yang sama seperti grup di `app-sidebar.tsx` (Kelas, Kelola,
Pengumuman, Keuangan, Layanan). **URL/nama route tidak berubah** (tetap flat
`admin/manage/*` / `admin.manage.*`) — hanya struktur folder PHP-nya
(Controller, Request, Service) yang mengikuti sub-namespace ini.
| Sub-namespace | Grup sidebar | Resource |
| --------------------------- | ------------ | -------------------------------------------------------------------------- |
| `Admin\Manage\Course` | Kelola | Course, CourseClass, ClassEnrollment |
| `Admin\Manage\Academic` | Kelas | CourseRegistration, Material, Assignment, Submission, Schedule, Attendance |
| `Admin\Manage\Announcement` | Pengumuman | Announcement |
| `Admin\Manage\Finance` | Keuangan | TuitionInvoice, TuitionPayment |
| `Admin\Manage\Service` | Layanan | LetterRequest, AcademicAdvisingLog |
Kalau menambah resource baru di salah satu grup ini, taruh Controller di
`app/Http/Controllers/Admin/Manage/<SubNamespace>/`, Request-nya di
`app/Http/Requests/Admin/Manage/<SubNamespace>/`, dan Service-nya di
`app/Services/Admin/Manage/<SubNamespace>/` — jangan taruh langsung di
`Admin\Manage` tanpa sub-namespace lagi.
---
## 5. Wayfinder ✅
Selalu jalankan generate dengan flag form variant, supaya `<Form
{...Controller.method.form()}>` tidak error saat runtime:
```bash
php artisan wayfinder:generate --with-form
```
`vite.config.ts` sudah diset `wayfinder({ formVariants: true })` sehingga
dev-server otomatis benar. Flag `--with-form` hanya wajib diingat kalau
generate manual lewat CLI.