tomatophp/laravel-tomato
tomatoPHP is a Laravel admin panel and CRUD generator that scaffolds resources, forms, and tables from your models. It bundles a ready-made dashboard UI, roles and permissions, menus, and settings so you can build management interfaces quickly without writing boilerplate code.
tomatophp/laravel-tomato is a scaffold-style package: it gives you an admin/CRUD layer (config, migrations, resources, stubs, assets) that you generate once and then own. Treat the first hour as an installation and reconnaissance exercise rather than a coding one.
composer require tomatophp/laravel-tomato. Now that v1.0.0 exists, constrain to "^1.0" in composer.json — the jump to 1.0 is the project's signal that the public surface is considered stable, so you want minor updates without surprise breaks from a floating constraint.php artisan vendor:publish and select the package's provider/tags (config, migrations, assets, stubs, lang). Publishing is the single most important step — if you skip a tag you'll be debugging "why is my config change ignored" for an hour.php artisan migrate followed by any package seeder for roles/permissions/menu records. Confirm the tables land in the order the package expects (see Gotchas).bootstrap/providers.php (Laravel 11+) or config/app.php, and confirm the route prefix and auth guard match your app. Check php artisan route:list | grep -i tomato before touching any UI.Where to look first: config/tomato.php (feature flags and guard/route settings), the package service provider (what it registers and when), src/ for the base resource/form classes you'll be extending, and the published stubs/ directory, which is the real contract for generated code.
Scaffold, then own. The generated resources, forms, and tables should be committed to your app/ tree and edited freely. The package's classes stay in vendor/ untouched. This is the intended workflow and the reason the stubs are publishable — resist the urge to subclass vendor classes just to keep a clean diff, because the package will not track your customizations.
One resource per domain model, generated in dependency order. Generate the parent model's resource before the child's so relation managers and select fields resolve. Keep a short internal doc of which resources were generated versus hand-written; after a few months nobody remembers, and upgrades get scary.
Use the config as an integration seam. Guard name, route prefix, middleware stack, enabled modules, and UI toggles should live in config/tomato.php rather than being hardcoded into generated classes. That way staging and production can differ without code drift, and config caching stays safe.
Integrate rather than replace. If you already have authentication, policies, or a Filament/Livewire panel, keep them. Register the package's routes under your existing guard and map authorization to your existing policies; don't let the package introduce a second user table or a parallel permission system.
Test the generated surface, not the package. Feature-test the routes the generator produced (actingAs an authorized user, assert the index page and one create/store path). You don't need to test vendor code, but you absolutely need a canary for the day a minor release changes a generated table's expectations.
Localization early. If the package ships translation files and you're not an English-only app, publish lang on day one and add keys as you generate. Retrofitting translation keys across dozens of generated resources is tedious and error-prone.
vendor:publish --force will overwrite your customizations.config:cache will lie to you. Changes to config/tomato.php are invisible until php artisan config:clear. Same for routes and views during development. When something "isn't registering," clear all three caches before reading source code.composer update.^1.0 plus a read of each minor's changelog is the right cadence.route:list (is it registered?), config('tomato') via tinker (did the config publish?), php artisan about (correct provider loaded?), then the database (migrate:status). Ninety percent of issues resolve in the first three.vendor/ and avoid class ... extends TomatoBase unless the package documents it as public API — that's the code most likely to break at the next minor.->modifyQueryUsing(fn ($q) => $q->with([...])) to the generated table rather than reaching for pagination tweaks first.How can I help you explore Laravel packages today?