Route panel yang mengembalikan 404
URL panel yang mengembalikan 404 hampir selalu berarti route tidak pernah diregistrasikan, bukan route yang menolak akses. Route table panel dibangun saat boot dari tiga sumber—daftar panel di config, registry masing-masing panel, dan cache yang tersedia di disk—dan salah satunya dapat hilang atau stale tanpa menghasilkan pesan di log. Halaman ini membahas penyebab dalam urutan yang biasanya terjadi, beserta command untuk memperbaikinya.
Mulai dari sini
php artisan route:list --name=panel.Satu command tersebut langsung membagi masalah menjadi dua bagian:
| Hasil | Arti | Lanjut ke |
|---|---|---|
| Tidak ada output sama sekali | Tidak ada panel yang diregistrasikan, atau registrasi route nonaktif | 1, 2, 9 |
| Route panel tersedia, tetapi route resource tidak | Registry tidak berisi resource tersebut | 3, 5 |
| Route tercantum tetapi URL tetap 404 | Compiled route table berbeda, atau record tidak berhasil di-resolve | 4, 7 |
| Route tercantum pada path yang berbeda dari yang Anda ketik | Ada cluster, slug, atau singular resource | 8 |
Tiga diagnostic tambahan, jalankan dalam urutan berikut:
php artisan panel:cache # discovery once, reported by count
php artisan panel:clear # drop the manifest, so discovery runs again
php artisan optimize:clear # config, routes, views, events — and the panel manifest2
3
use PandaPanel\Facades\PandaPanel;
PandaPanel::resources('admin')->all(); // list<class-string> — what the panel actually holds
PandaPanel::pages('admin')->all();
PandaPanel::widgets('admin')->all();2
3
4
5
1. Panel tidak ada di config/panda-panel.php
Gejala. /admin mengembalikan 404. File provider tersedia. make:panel melaporkan berhasil. route:list --name=panel. kosong.
Penyebab. Panel didaftarkan melalui list, bukan discovery. Urutan registrasi menentukan panel mana yang menjadi tujuan user ketika request tidak menentukan panel, dan penambahan panel seharusnya merupakan perubahan yang disengaja, bukan efek samping filesystem. Karena itu provider yang tidak tercantum di list tidak diregistrasikan, tidak memiliki route group, dan tidak memiliki URL. Ini adalah penyebab paling umum setelah instalasi terlihat "tidak bekerja".
// config/panda-panel.php
'panels' => [
App\Panels\Admin\AdminPanelProvider::class,
],2
3
4
php artisan panel:install --no-panel --no-user --no-interaction # re-runs every check
php artisan route:list --name=panel.2
panel:install mencoba menulis baris tersebut secara otomatis. Ketika tidak dapat melakukannya, installer menjelaskan salah satu dari dua penyebab berikut:
1. Add App\Panels\Admin\AdminPanelProvider::class to 'panels' in config/panda-panel.php.
(The config has not been published)2
(The config has been reshaped, so it was left alone)Kasus kedua adalah PandaPanel\Support\Installer\PanelRegistrar yang menolak mengedit key panels ketika nilainya dibangun dari variable atau function call, bukan literal array. Tidak ada config yang ditulis ulang berdasarkan tebakan; installer hanya mencetak baris yang perlu Anda tambahkan.
make:panel sendiri hanya menampilkan baris tersebut, karena generator yang diam-diam mengedit config dapat membuat project kehilangan kontrol terhadap urutan panel.
2. Provider yang tertulis di config tidak lagi dapat di-resolve
Gejala. Sama seperti sebelumnya: route:list kosong, tetapi array panels terlihat benar.
Penyebab. Nama class yang tidak lagi dapat di-resolve akan dilewati, bukan dibuat fatal. Fatal error saat boot akan mematikan seluruh route aplikasi, termasuk route yang seharusnya membantu Anda melihat masalah.
// PandaPanelServiceProvider::configuredPanels()
foreach ($configured as $provider) {
if (is_string($provider) && is_subclass_of($provider, PanelProvider::class)) {
$panels[] = $provider;
}
}2
3
4
5
6
Karena itu dua kesalahan terlihat seperti entry yang hilang: typo pada nama class, atau class yang tidak extend PandaPanel\Core\PanelProvider.
Pastikan langsung.
class_exists(App\Panels\Admin\AdminPanelProvider::class); // false — typo
is_subclass_of(App\Panels\Admin\AdminPanelProvider::class, PandaPanel\Core\PanelProvider::class);2
composer dump-autoload -o
php artisan panel:cache # prints the panels it actually found2
INFO Panels cached: 2 panels, 1 resources, 5 pages, 4 widgets.Jumlah 0 panels memberikan jawaban yang sama dengan route:list, tetapi dalam konteks yang lebih jelas.
3. Manifest panel sudah stale
Gejala. Resource, page, atau widget yang baru ditambahkan tidak terlihat. Tidak ada route, navigation entry, atau error. Semua yang sudah ada sebelumnya tetap bekerja.
Penyebab. php artisan panel:cache menulis bootstrap/cache/panels.php, dan ketika manifest tersedia, discovery sama sekali tidak dijalankan—tidak ada filesystem scan, reflection, atau discovery per request. Itu memang tujuan cache dan sekaligus jebakannya: class yang ditambahkan setelah manifest dibuat tidak menjadi bagian dari panel.
Pastikan. Pada environment development framework menampilkan warning saat boot:
[panel] The cached panel manifest is out of date: the classes under the discovery paths have
changed since `php artisan panel:cache` last ran. Until you run `php artisan panel:clear`,
anything added since then is invisible — no route, no navigation entry, and no error to say so.2
3
use PandaPanel\Cache\PanelManifest;
app(PanelManifest::class)->exists(); // true — a manifest is in charge
PanelManifest::path(); // '/var/www/app/bootstrap/cache/panels.php'2
3
4
Perbaikan.
php artisan panel:clear # development: go back to discovering on every boot
php artisan panel:cache # deploy time: rebuild it, after the code is in place2
Cara warning mengetahui manifest sudah stale
PandaPanel\Cache\DiscoveryFingerprint merangkum setiap discovery path sebagai count:newest-mtime—satu stat per file PHP untuk mendeteksi kegagalan yang gejala utamanya hanya "tidak muncul".
| Member | Signature | Catatan |
|---|---|---|
of | static of(array $panels): string | xxh128 dari seluruh discovery path panel, diurutkan |
isStale | static isStale(array $panels, ?string $recorded): bool | false jika kondisi tidak dapat dipastikan |
use PandaPanel\Cache\DiscoveryFingerprint;
DiscoveryFingerprint::of([panel('admin')]); // '9f0c…'2
3
Fingerprint dihitung hanya di development—ketika app()->hasDebugModeEnabled() true, atau environment local/testing—dan hanya saat manifest memang tersedia. Di production manifest menjadi source of truth dan filesystem tidak disentuh, sesuai tujuan cache. Path yang hilang dirangkum sebagai missing, sehingga directory yang diganti nama juga dianggap perubahan penting: panel yang menunjuk directory yang tidak ada akan menemukan nol class tanpa error.
Member PanelManifest | Signature |
|---|---|
path | static path(): string — melalui bootstrapPath(), sehingga cache directory yang dipindahkan tetap ditemukan |
exists | exists(): bool |
for | for(Panel $panel): array{resources: list<string>, pages: list<string>, widgets: list<string>} |
write | write(PanelRegistry $registry): array — atomic dan merekam fingerprint |
clear | clear(): bool — manifest yang tidak ada tetap dianggap berhasil |
warnIfStale | warnIfStale(PanelRegistry $registry): void |
4. route:cache dijalankan sebelum panel tersedia
Gejala. URL 404 di server tetapi bekerja lokal. route:list di server tidak menampilkan route panel atau menampilkan versi yang lebih lama.
Penyebab. Ketika compiled route table tersedia, Laravel menggunakan hasil compile tersebut alih-alih route yang diregistrasikan provider saat boot. PanelRouteRegistrar::registerAll() tetap berjalan—karena itu method boot() provider—tetapi route yang dihasilkannya bukan route table yang melayani request.
Perbaikan.
php artisan route:clear
php artisan route:cache2
Atau jalankan seluruh optimasi setelah code deployment selesai:
php artisan optimize # config, routes, events, views — and panel:cache
php artisan optimize:clear # and panel:clear2
panel:cache dan panel:clear diregistrasikan sebagai hook optimize dengan key panels, sehingga deployment yang sudah menjalankan optimize mendapatkan panel manifest secara otomatis.
Dua cache menghasilkan dua jenis kegagalan diam-diam yang berbeda. Jika hanya salah satunya fresh:
| State | Gejala |
|---|---|
| Route cache fresh, panel manifest stale | URL dapat diakses, tetapi resource tidak ada di sidebar—navigation dibangun dari registry |
| Route cache stale, panel manifest fresh | Sidebar menampilkan link yang 404—route tidak pernah ikut di-compile |
Keduanya tidak menulis log di production. Bangun ulang keduanya pada deployment yang sama terhadap code tree yang sama.
Cached route table dapat hidup lebih lama daripada code deployment. Pada deployment berbasis release directory, bootstrap/cache harus menjadi bagian dari release, bukan shared directory. Jika tidak, rollback dapat melayani route table milik versi code yang sudah tidak ada.
route:cache sendiri tidak pernah gagal karena package ini: seluruh route panel menunjuk ke controller method, invokable controller class, atau pair [class, method], dan satu-satunya route default hanyalah class name dalam bentuk string. Jika route:cache menolak, closure berada di route file milik aplikasi Anda.
5. Discovery path tidak sesuai dengan lokasi class
Gejala. panel:cache melaporkan 0 resources, atau jumlah lebih sedikit daripada file resource yang tersedia di disk.
Penyebab, dari yang paling umum:
$panel
->discoverResources(app_path('Panels/Admin/Resources'))
->discoverPages(app_path('Panels/Admin/Pages'))
->discoverWidgets(app_path('Panels/Admin/Widgets'));2
3
4
| Penyebab | Gejalanya |
|---|---|
| Directory tidak ada | tidak berkontribusi apa pun secara diam-diam; panel boleh menunjuk directory yang modulnya belum dibuat |
| Class berada di luar seluruh PSR-4 root | ClassResolver::forPath() mengembalikan null dan file dilewati |
| Autoloader belum diregenerasi | gejala sama, biasanya setelah memindahkan atau menambahkan namespace |
| Class abstract atau interface | dilewati; directory secara sah dapat memiliki base class |
| Class tidak mengimplementasikan contract | dilewati; form, table, exporter, dan enum dapat berada di directory yang sama |
| Class berada di discovery path panel lain | class diregistrasikan pada panel tersebut |
use PandaPanel\Discovery\ClassResolver;
use PandaPanel\Discovery\PanelDiscoverer;
panel('admin')->getResourceDiscoveryPaths(); // list<string> — absolute directories, accumulated
ClassResolver::forPath(app_path('Panels/Admin/Resources/Users/UserResource.php'));
// 'App\Panels\Admin\Resources\Users\UserResource'
ClassResolver::forPath('/tmp/Orphan.php'); // null — outside every PSR-4 root
app(PanelDiscoverer::class)->resources(panel('admin'));
// [App\Panels\Admin\Resources\Users\UserResource::class]2
3
4
5
6
7
8
9
10
11
12
Perbaikan.
composer dump-autoload -o
php artisan panel:clear
php artisan panel:cache2
3
| Member | Signature | Contract yang dibutuhkan |
|---|---|---|
Panel::discoverResources | discoverResources(string ...$paths): self | PandaPanel\Contracts\ResourceContract |
Panel::discoverPages | discoverPages(string ...$paths): self | PandaPanel\Contracts\PageContract |
Panel::discoverWidgets | discoverWidgets(string ...$paths): self | PandaPanel\Contracts\WidgetContract |
Panel::getResourceDiscoveryPaths | getResourceDiscoveryPaths(): list<string> | — |
PanelDiscoverer::resources | resources(Panel $panel): list<class-string<ResourceContract>> | — |
ClassResolver::forPath | static forPath(string $path): ?class-string | — |
Setiap method discover* bersifat akumulatif, bukan menggantikan nilai sebelumnya, sehingga modul dapat menambahkan directory tanpa perubahan pada core. Path discan secara recursive, jadi resource di Resources/Users/UserResource.php ditemukan tanpa harus mendaftarkan Resources/Users secara terpisah.
Register class secara eksplisit jika class tersebut berada di luar tree milik panel. Registrasi eksplisit digabungkan dengan hasil discovery, bukan menggantikannya:
use App\Panels\Admin\Resources\Users\UserResource;
$panel
->resources([UserResource::class])
->discoverResources(app_path('Panels/Admin/Resources'));
// registered once — the registries are keyed by slug2
3
4
5
6
6. Nested resource tidak memiliki parent yang ter-bind
Gejala. /admin/posts 404 tetapi /admin/users/3/posts bekerja, atau seluruh URL nested resource mengembalikan 404.
Penyebab. Nested resource tidak memiliki index mandiri. Setiap halaman berada di bawah parent record, dan registrar membangun seluruh group di bawah segment milik parent:
final class PostResource extends Resource
{
protected static string $model = Post::class;
/** @var class-string<PandaPanel\Resources\Resource>|null */
protected static ?string $parentResource = UserResource::class;
/** The relation on the parent holding these records. Defaults to the plural slug, camelised. */
protected static ?string $parentRelationship = 'posts';
}2
3
4
5
6
7
8
9
10
prefix: users/{parentRecord}/posts
middleware: ResolveParentRecord:App\Panels\Admin\Resources\Posts\PostResource2
Dengan demikian /admin/posts memang tidak tersedia dan tidak pernah dimaksudkan tersedia—itulah bentuk fitur nested resource, bukan error.
Empat penyebab nested URL mengembalikan 404 saat request, seluruhnya berasal dari PandaPanel\Http\Middleware\ResolveParentRecord:
$parentResource = $resource::parentResource();
abort_if($parentResource === null, 404); // 1. not actually nested
$key = $request->route(ParentRecord::routeParameter());
abort_unless(is_string($key), 404); // 2. no {parentRecord} segment matched
$parent = ParentRecord::resolve($parentResource, $key);
abort_if($parent === null, 404); // 3. no such parent, or not viewable
ParentRecord::bind($parent);2
3
4
5
6
7
8
9
10
11
12
13
Poin ketiga perlu dipahami: parent di-resolve melalui query() milik parent resource dan diautorisasi dengan canView(), sehingga parent yang tidak dapat dibuka user juga menghasilkan 404. Tanpa mekanisme ini, /users/9/posts dapat menjadi jalan untuk membaca child milik user 9 meskipun /users/9 sendiri ditolak.
Member PandaPanel\Support\ParentRecord | Signature |
|---|---|
routeParameter | static routeParameter(): string — 'parentRecord' |
resolve | static resolve(string $parentResource, int|string $key): ?Model |
bind | static bind(Model $record): void |
current | static current(): ?Model |
require | static require(string $resource): Model — melempar exception alih-alih query tanpa scope |
assertRegistered | static assertRegistered(string $resource, string $parent): void |
Kegagalan saat boot dibuat lebih keras, dan itu lebih baik. Parent yang tidak terdaftar di panel yang sama akan menghasilkan path berdasarkan default slug tetapi menunjuk route yang tidak ada:
PandaPanel\Exceptions\PanelRegistrationException
[App\Panels\Admin\Resources\Posts\PostResource] is nested under
[App\Panels\Admin\Resources\Users\UserResource], which is not registered in the same panel.2
3
4
Register parent di panel yang sama, atau hapus $parentResource.
Bangun URL nested melalui resource, jangan menulis manual. Parent berasal dari record yang sudah ter-bind pada request, sehingga link antarhalaman nested resource tidak memerlukan argument tambahan:
PostResource::url('edit', $post); // '/admin/users/3/posts/7/edit'
PostResource::url('edit', $post, parent: $otherUser);2
Di luar request—console command atau queued job—tidak ada parent yang ter-bind, sehingga ParentRecord::require() melempar:
[PostResource] is a nested resource, so it can only be reached under a parent record.
None is bound to this request.2
7. Route cocok tetapi record tidak berhasil di-resolve
Gejala. /admin/users/41/edit mengembalikan 404 sementara /admin/users menampilkan data.
Penyebab. Lookup record selalu melewati Resource::query(), satu funnel yang dipakai seluruh read: list, record page, action, bulk endpoint, global search, dan export. Key yang tidak berada di query tersebut tidak dapat di-resolve, dan record yang tidak boleh dijangkau panel adalah 404, bukan 403.
Empat narrowing dapat mengeluarkan record dari query:
| Narrowing | Sumber |
|---|---|
| Query per-panel | ResourceConfiguration::applyQuery() |
| Tenant scope | $tenantRelationship — lihat kebocoran tenant scope |
| Parent relation | nested resource, bagian 6 |
| Soft delete | trashed record berada di luar scope sampai $softDeletes diaktifkan |
use App\Panels\Admin\Resources\Users\UserResource;
UserResource::query()->whereKey(41)->exists(); // false — this is why the page 404s2
3
Out-of-scope key sengaja menghasilkan 404, bukan 403: status 403 akan mengonfirmasi bahwa record tersebut memang ada.
8. Route tersedia pada path yang berbeda
route:list menampilkan route, tetapi URL yang Anda ketik berbeda. Empat hal dapat memindahkan path tanpa mengubah route name:
| Penyebab | Path | Route name |
|---|---|---|
protected static ?string $slug = 'people'; | /admin/people | panel.admin.resources.people.* |
| Cluster | /admin/{cluster-slug}/users | panel.admin.resources.users.* — tidak berubah |
| Nested resource | /admin/users/{parentRecord}/posts | panel.admin.resources.posts.* |
protected static bool $singular = true; | {record} dihapus dari setiap path | tidak berubah |
Cluster hanya menambahkan prefix pada path dan tidak mengubah route name. Karena itu memindahkan resource ke cluster merupakan perubahan yang tidak mematahkan penggunaan Resource::url(); seluruh pemanggilan tetap bekerja dan hanya URL hasilnya yang berpindah.
Selalu bangun URL dari route name, bukan secara manual:
public static function routeName(string $page = 'index', Panel|string|null $panel = null): string
public static function url(
string $page = 'index',
Model|int|string|null $record = null,
Panel|string|null $panel = null,
Model|int|string|null $parent = null,
): string2
3
4
5
6
7
8
UserResource::url(); // '/admin/users'
UserResource::url('edit', $user); // '/admin/users/3/edit'
UserResource::routeName('index', 'admin'); // 'panel.admin.resources.users.index'2
3
Dua kegagalan berikut berupa exception, bukan tebakan, dan keduanya menjelaskan masalah secara langsung:
UserResource::url(); // outside a panel: 'There is no current panel for this request…'
UserResource::url(panel: 'app'); // 'The resource […] is not registered in the panel [app]…'2
Page yang tidak tercantum di pages() tidak memiliki route. Empat key standar memiliki bentuk route tetap dan key lainnya dianggap custom page—satu GET pada ResourcePage::routePath($key):
public static function pages(): array
{
return [
'index' => ListUsers::class,
'create' => CreateUser::class,
'view' => ViewUser::class,
'edit' => EditUser::class,
'activity' => UserActivity::class, // GET {record}/activity, named …resources.users.activity
];
}2
3
4
5
6
7
8
9
10
Menghapus 'view' dari array tersebut adalah cara resource tidak memiliki view page, sehingga /admin/users/3 akan 404. Pada singular resource, index dan view sama-sama menjadi /, sehingga hanya salah satunya yang dideklarasikan.
9. register_routes bernilai false
// config/panda-panel.php
'register_routes' => true,2
Jika nonaktif, tidak ada route yang diregistrasikan dan tidak ada yang di-cache. Registry tetap dibangun, sehingga PandaPanel::resources('admin')->all() tetap mengembalikan data—itulah alasan kondisi ini sulit dikenali hanya dari PHP. Jika memang disengaja, register route group sendiri:
use PandaPanel\Core\PanelManager;
use PandaPanel\Routing\PanelRouteRegistrar;
app(PanelRouteRegistrar::class)->register(app(PanelManager::class)->get('admin'));2
3
4
| Member | Signature |
|---|---|
registerAll | registerAll(): void — seluruh panel yang terdaftar |
register | register(Panel $panel): void — satu panel |
Opsi ini berguna untuk test harness yang melakukan boot panel tanpa HTTP, atau aplikasi yang membutuhkan route group pada posisi tertentu di route file. Deployment normal tidak perlu menyentuhnya.
10. Panel dipasang pada domain tertentu
$panel->path('admin')->domain('admin.example.test');Panel dengan domain() meregistrasikan route group pada domain tersebut, sehingga path yang sama di host lain tidak memiliki route. PanelManager::resolveFromRequest() juga melewati panel ketika domain() tidak cocok dengan request host. Itulah sebabnya guest pada host yang salah diarahkan ke login aplikasi, bukan login panel.
php artisan route:list --name=panel.admin --columns=domain,uri,name11. Halaman integrations mengembalikan 404
Penyebab. Route integration hanya diregistrasikan untuk resource yang mengaktifkan integration. Resource yang tidak pernah opt-in tidak mendaftarkan apa pun, sehingga URL integrations 404, bukan 403—tidak ada screen yang dapat ditolak.
use PandaPanel\Integrations\Integrations;
public static function integrations(Integrations $integrations): Integrations
{
return $integrations->isEnabled(true);
}2
3
4
5
6
UserResource::integrationSettings()->enabled(); // bool — what the registrar asks12. Dua route mengklaim path yang sama
Ini bukan 404—ini adalah kegagalan yang sengaja dibuat lebih awal sebelum berubah menjadi 404 yang membingungkan. Laravel memilih route pertama untuk sebuah path dan diam-diam mengabaikan sisanya, sehingga registrar menormalisasi setiap bentuk path yang diklaim (nama parameter dihapus: {record} dan {parentRecord} dianggap sama) lalu menolak klaim kedua saat boot:
The path [projects/{record}/tasks] is registered by both
[App\Panels\Admin\Resources\Projects\ProjectResource] and
[App\Panels\Admin\Resources\Tasks\TaskResource]. Only the first would ever match.
Give one of them a different slug or route path.2
3
4
ManageRelatedRecords page pada projects/{record}/tasks dan nested resource pada projects/{parentRecord}/tasks adalah path yang sama bagi router; collision ini merupakan kasus yang paling sering tertangkap.
Claim dilacak per panel, karena dua panel berada pada prefix berbeda dan tidak dapat saling menutupi.
Daftar command
| Command | Fungsi |
|---|---|
php artisan route:list --name=panel. | menampilkan seluruh route yang diregistrasikan package |
php artisan route:clear | menghapus compiled route table |
php artisan route:cache | membangun compiled route table dari boot saat ini |
php artisan panel:cache | menjalankan discovery sekali dan menulis bootstrap/cache/panels.php |
php artisan panel:clear | menghapus manifest; manifest yang tidak ada tetap dianggap sukses |
php artisan optimize | config, routes, events, views—dan panel:cache |
php artisan optimize:clear | menghapus semuanya, termasuk panel:clear |
php artisan panel:install --no-panel --no-user --no-interaction | menjalankan ulang seluruh pemeriksaan instalasi tanpa mengubah apa pun |
composer dump-autoload -o | membangun ulang PSR-4 map yang digunakan discovery |
Catatan
- 404 adalah masalah route; 403 adalah aturan akses. Guest tidak diberikan 403 untuk URL panel, dan signed-in user tidak diarahkan sebagai pengganti 403. Jika statusnya 403, gunakan response 403.
- Resource yang hilang dari sidebar lebih sering disebabkan policy daripada route.
Gate::allows()menolak saat policy tidak ada, dan hasilnya tidak dapat dibedakan dari policy yang memang memutuskan menolak. Coba URL secara langsung sebelum menyimpulkan route tidak tersedia. panel:cachebukanroute:cache, dan keduanya bukan frontend cache. Ada tiga state berbeda;optimizemenangani dua yang pertama, sementaranpm run buildmenangani frontend.- Provider yang dicantumkan dua kali tetap diregistrasikan sekali. Registry menggunakan panel id sebagai key, dan registrasi ulang hanya akan mengulang discovery tanpa mengubah hasil.
- Dua panel dengan id yang sama, atau path yang sama pada domain yang sama, gagal saat boot dengan
PanelRegistrationException, bukan saling menutupi secara diam-diam. - Route name adalah sumber yang digunakan Wayfinder untuk generate. Jaga route name stabil; path adalah bagian yang aman untuk dipindahkan. Mengganti panel id mengubah seluruh nama
panel.{id}.*sekaligus. register_web_middleware => falsetidak memengaruhi routing, hanya empat middlewareweb. Jika route panel tersedia tetapi halaman kehilangan shared props, periksa config key tersebut, bukan halaman ini.
Lihat juga
- Routing — route table lengkap per group
- Discovery, caching, siklus request
- Route cache, panel cache, Composer dan autoloading, production checklist
panel:cache,panel:clear,panel:install,make:panel- Konfigurasi registrasi route,
config/panda-panel.php - Nested resources, URL dan route, resource query, singular resources, konvensi directory
- Cluster, page discovery
- Response 403, kebocoran tenant scope, redirect login
- Masalah instalasi umum