Role dan Permission di Panel Admin Filament
Begitu sebuah aplikasi internal dipakai lebih dari satu jenis pengguna, urusan akses jadi rumit dengan cepat. Di sistem klinik atau rumah sakit misalnya, ada admin yang mengelola master data, staf pendaftaran yang input transaksi harian, dan verifikator yang memvalidasi klaim sebelum dikirim. Kalau aturan siapa-boleh-apa hanya ditempel di tampilan—tombol disembunyikan di sini, menu disembunyikan di sana—cepat atau lambat aturannya jadi tidak konsisten. Ada jalan pintas lewat URL yang lupa dijaga, ada aksi yang tampak tersembunyi di UI tapi sebenarnya masih bisa dieksekusi. Filament menyediakan cara rapi untuk mengatur ini, tapi kuncinya bukan di Filament itu sendiri, melainkan di Policy Laravel yang jadi fondasinya.
Kenapa otorisasi harus tinggal di Policy, bukan di Resource
Godaan paling umum adalah menaruh logika "boleh atau tidak" langsung di dalam Resource atau Page Filament, misalnya lewat pengecekan if (auth()->user()->role === 'admin') di method canEdit(). Ini bekerja untuk sementara, tapi begitu ada jalur akses lain—API, job terjadwal, command artisan, atau panel kedua—aturan itu harus ditulis ulang di tempat lain, dan risiko dua tempat itu tidak sinkron sangat nyata. Pendekatan yang lebih tahan lama adalah menulis semua aturan di Policy standar Laravel, lalu membiarkan Filament memanggilnya lewat Gate. Filament Resource secara default memang sudah otomatis mencari Policy yang sesuai dengan nama model-nya, jadi pekerjaan kita cukup fokus menulis Policy yang benar.
class ClaimPolicy
{
public function update(User $user, Claim $claim): bool
{
return $user->hasRole('admin')
|| ($user->hasRole('verifikator') && $claim->status === 'pending');
}
public function verify(User $user, Claim $claim): bool
{
return $user->hasRole('verifikator');
}
}Dengan pola ini, aturan yang sama otomatis berlaku dari panel Filament, dari controller API, sampai dari test otomatis—karena semuanya lewat Gate::authorize() atau $this->authorize() yang sama.
Merancang role dan permission yang tidak berantakan
Untuk implementasi role sendiri, kombinasi paket seperti spatie/laravel-permission dengan Policy di atasnya biasanya cukup. Yang penting dijaga sejak awal adalah memisahkan dua konsep: role sebagai label jabatan (admin, staf, verifikator), dan permission sebagai aksi granular ("lihat klaim", "verifikasi klaim", "hapus data master"). Role tinggal jadi kumpulan permission. Ini penting karena kebutuhan riil sering lebih halus dari sekadar tiga label—misalnya suatu saat ada staf senior yang boleh verifikasi tapi bukan verifikator penuh. Kalau logika Policy sejak awal memeriksa permission ($user->can('verify-claim')) bukan nama role secara literal, penyesuaian semacam ini tinggal ubah data, tanpa menyentuh kode.
Menyambungkan ke panel: navigasi, resource, sampai field
Setelah Policy siap, sisi Filament tinggal mengikuti. Method canViewAny(), canCreate(), canEdit(), dan canDelete() di Resource otomatis memakai Policy yang sama, jadi navigasi menu pun ikut menyesuaikan—menu yang usernya tidak berhak tidak akan muncul sama sekali, bukan cuma disembunyikan lewat CSS. Untuk kontrol yang lebih halus, misalnya kolom tertentu hanya boleh diedit verifikator, saya biasanya bungkus lewat ->visible(fn () => auth()->user()->can('verify-claim')) pada field atau action, tetap merujuk permission yang sama, bukan aturan baru. Untuk aksi custom seperti tombol "Verifikasi" di tabel, saya taruh ->authorize('verify') pada Action, sehingga tetap lewat Policy, bukan pengecekan manual di closure.
Yang saya bawa pulang
Aturan otorisasi sebaiknya hanya punya satu rumah, yaitu Policy. Filament di atasnya cuma jadi lapisan presentasi yang taat pada aturan itu. Kalau suatu hari harus menambah role baru atau membuka akses lewat API terpisah, saya tidak perlu mengulik ulang tampilan satu per satu—cukup pastikan Policy dan permission-nya benar, sisanya otomatis konsisten.