mehedi250/laravel-structure-kit
A browser-based scaffolding panel for Laravel that generates models, controllers, services, repositories, and migrations in one click. No terminal needed—open the UI, pick your components, and hit Generate to build a clean layered structure fast.
Install and open the panel:
composer require mehedi250/laravel-structure-kit
php artisan serve
# visit http://localhost:8000/structure-kit
No config publishing, no provider registration — auto-discovery handles it. If the panel 404s, run php artisan route:list | grep structure to confirm the routes registered, and php artisan optimize:clear if you have cached routes.
The gate that catches everyone first: the panel returns 403 unless APP_ENV is exactly local. If your machine runs development, dev, or you're on a shared staging box, the UI is dead. Use the Artisan equivalent instead:
php artisan structure-kit Product mcsrt --dry-run
Your first use case should be a full-stack dry run, not a real feature. Scaffold a throwaway Product with all five components selected, then read every generated file before writing business logic. The value of this package isn't the file creation — it's seeing how the interface, service, repository, and controller are wired together. Ten minutes of reading that output teaches you the contract shape you'll be living with: getAll, find, create, update, delete, count, paginate.
Where to look in the vendor tree (read-only reference):
src/Stubs/ — the templates that produce every file. This is the real documentation of what you're getting.src/StructureKitServiceProvider.php — routes, version constant, and (check this) whether repository interfaces are bound to implementations in the container.Scaffold → commit → customize. Run the generator, commit the raw output as an isolated commit, then edit. This gives you a clean diff and a rollback point when the generated controller base class or namespace turns out wrong for your app. Never generate on top of uncommitted work.
The layered flow that actually pays off:
mcsrt).create_table. Define your columns before you run php artisan migrate.$fillable, $casts, relationships, scopes. The stub has none of this.routes/).Pick your mode deliberately. Service + Repository when you need a swappable data source, heavy query logic, or interfaces you'll mock in tests. Service without Repository (select service, deselect repository) for straightforward CRUD — it generates a service that talks to the model directly and saves you an indirection layer you'd never swap. Don't select both by reflex.
Bind the interfaces in a dedicated provider. Whether the package binds them for you is worth verifying with php artisan tinker — resolve App\Services\Contracts\ProductServiceInterface and see what you get. If it fails, add explicit bindings in your own AppServiceProvider (or a RepositoryServiceProvider). This also gives you a natural place to swap in fakes during tests:
$this->app->bind(ProductRepositoryInterface::class, InMemoryProductRepository::class);
Team consistency is a documentation problem, not a tooling problem. "Remember current path" saves to localStorage, which is per-browser, per-machine — a new teammate gets defaults, not your team's paths. Put the canonical path table in your project README alongside the structure-kit invocation.
Use the CLI for anything repeatable. The web panel is for interactive one-offs; the CLI is for scripted setup, seeding a fresh local DB, or CI checks. --dry-run first, always.
Existing files are skipped, never overwritten. This is mostly a safety feature, but it means a botched generation can't be re-run — you must delete the bad files first. The web controller hardcodes force => false, so raw form manipulation can't overwrite either. Only the CLI --force flag will clobber, and only since v0.1.6.
Pin ^0.1.6 or later. That release fixed a cluster of bugs you would have hit within an hour: service interfaces that were verbatim copies of repository interfaces, repositories declaring : bool returns on Eloquent update()/delete() (which return int — a TypeError under strict_types), and singleton state accumulating across requests (relevant if you run Octane). Below 0.1.6, the generated layers are semantically wrong.
Path validation blocks non-app/ layouts. The UI refuses any path not starting with app/, so modular monoliths (Modules/Product/...) and app/Domain/... DDD layouts can't be expressed visually. The v0.1.6 ns() fix made custom namespaces pass through unprefixed, but the UI gate still stands in the way — test the CLI path before assuming it works, and don't hand-edit namespaces in the generated files without grepping for stragglers.
Generated controllers extend Illuminate\Routing\Controller, not your App\Http\Controllers\Controller. This is deliberate (Laravel 11 removed the app-level base class), but it means you lose any shared traits, $middleware arrays, or authorize() helpers you keep in your own base controller. Re-point the extends in each generated controller — or better, standardize this with a project-level convention before you generate twenty of them.
Stubs are not publishable. There's no vendor:publish tag documented and no config file. To change the boilerplate — add declare(strict_types=1), inject your own base classes, include a #[UseFactory] attribute — you either fork the package or edit files under vendor/, which are wiped on composer update. If you need heavy customization, fork it and point your composer.json at your fork. Otherwise accept the boilerplate and fix it post-generation.
The flag letters are counterintuitive. m is model, t is migration. mcsrt is muscle memory you'll get wrong once. When a generate call "does nothing," check flags against --dry-run output before touching anything else.
Untested edges: nested model names (Admin/User), irregular plurals, and non-Latin table names. Run --dry-run and inspect the derived migration filename (create_products_table) before committing.
What you don't get: FormRequests, policies, factories, seeders, tests, route registration, or DTOs. The migration stub is skeletal. Budget real time for all of it.
Maturity context: 9 stars, one maintainer, 0.1.x semver, zero dependents. It has no runtime footprint after generation — files are plain code in your app/ tree — so the risk is contained to dev-time annoyance. Read the changelog of the version you install; several fixed bugs indicate the generator was silently producing broken code for a while.
How can I help you explore Laravel packages today?