vaibhavpandeyvpz/laravel-crud
vaibhavpandeyvpz/laravel-crud is a Laravel package for quickly building CRUD features. It provides reusable base classes and conventions to reduce boilerplate for creating, reading, updating, and deleting Eloquent records, helping developers ship admin panels and data management screens faster.
This is a starter kit more than a package — you don't composer require it into an existing app, you clone it and build on top. Treat the first hour as "read the repo, not the docs" because docs are thin and the value is in the generated code.
Minimal path:
docker compose up -d), then exec into the app container for all artisan/composer/npm commands. Running artisan on the host against a Dockerized DB is the most common first-day stumble.docker-compose.yml / Dockerfile — understand what services exist (app, db, likely queue/scheduler) and which ports are exposed.routes/web.php — see how CRUD routes and RBAC middleware are wired.app/Console/Commands or a service provider) — this is the actual product surface.app/Http/Livewire (or app/Livewire) — the shipped components you'll copy/customize.spatie/laravel-permission under the hood; confirm before assuming.Post) end-to-end — generate, migrate, open the index, create/edit/delete one row. This shows you the full loop (component, view, form partials, validation, policy) before you commit to the architecture.If you can't get the generator to produce a working resource in that first session, stop and evaluate whether the boilerplate is worth the archaeology — at 18 stars the community support won't rescue you.
Generator-first, then own the code. The core workflow is: run the CRUD command, inspect the four or five files it emits (Livewire component, Blade views, form partial, migration), then edit them like hand-written code. Don't expect to "regenerate" later — treat output as a one-shot scaffold. This is the single most important mental model for day-to-day use.
Wire Select2 and Flatpickr inside Livewire's lifecycle, not on document.ready. Because Livewire morphs the DOM, plugin instances get destroyed on re-render. The reliable pattern:
// wire:ignore on the <select>, then re-init on Livewire navigation & component updates
document.addEventListener('livewire:navigated', initPlugins);
Livewire.hook('morph.updated', ({ el }) => initPlugins(el));
For Select2 backed by wire:model, keep wire:ignore on the select and push changes back explicitly via $wire.set('field', value) inside Select2's change handler. Flatpickr is more forgiving but still needs re-init if the input is inside a conditional block.
RBAC at three layers. Day-to-day you'll touch:
role: / permission:) for coarse gating.$this->authorize(...)).@can so the interface matches the policy.Centralize the permission names in a seeder or enum; string-typo'd permissions that silently return false are a classic time sink.
Table/index pattern. Livewire list components with public $search, public $sortField, public $sortDirection, and WithPagination. Add debounced search (wire:model.live.debounce.300ms) — the boilerplate often ships wire:model only, which means a query-per-keystroke.
Docker env separation. Keep a .env.docker (or compose environment: block) distinct from host .env so DB host is the service name (db) rather than 127.0.0.1. Use the same image for local and prod; only override APP_ENV, volumes, and queue worker replicas.
Integrating into an existing app (rather than greenfield): cherry-pick — copy the Livewire component + form partial + the relevant JS init into your app, and reuse your existing auth and layout. Do not drag the whole repo in; the Bootstrap auth views will fight with Tailwind/Breeze.
composer.lock / package.json. That is your upgrade path.<select> after a re-render, or the selected value resets. Fix is always wire:ignore + explicit $wire.set. Check the browser console for "Select2 already initialized" too — dispose before re-init.php artisan permission:cache-reset (or cache:forget spatie.permission.cache). Newly-seeded permissions that "don't work" are almost always this.chown -R www-data:www-data storage bootstrap/cache inside the container or run as a mapped UID.${DB_PORT:-3307}:3306 rather than editing in place.$this->dispatch('...') events not firing are usually because the listener component was conditionally rendered. Use Livewire::test(Component::class)->call('save')->assertHasErrors() for fast regression tests on generated components.$this->validate([...]). For reusable rules, extract to a Rules array or a dedicated Form object; don't assume the boilerplate wired a FormRequest you can find in app/Http/Requests.How can I help you explore Laravel packages today?