rappasoft/laravel-5-boilerplate
A full-featured Laravel 5 starter kit with authentication, user management, roles and permissions, an admin panel, localization, and frontend/backend scaffolding. It provides a production-ready foundation for building Laravel applications faster.
This is not a package you composer require into an existing app — it is a full application skeleton (auth, users, roles/permissions, 2FA, social login, activity log, localization, admin theme). Day one means forking it, not installing it.
composer create-project rappasoft/laravel-boilerplate myapp # or git clone + composer install
cp .env.example .env
php artisan key:generate
# set DB_* in .env
php artisan migrate --seed
npm install && npm run dev
The latest tag is v8.3.1, whose only stated change is "Updated dependencies". Treat that as a maintenance/patch bump, not a feature release: no new APIs, no documented breaking changes, so the integration surface described below is unchanged. What it does mean is that the lockfile and transitive versions moved — which is exactly where the archived-state risk lives.
Before you run anything, check the archived state and the platform pin. If you're on PHP 8.2+ and composer install fails or resolves oddly, add "config": {"platform": {"php": "8.0"}} to composer.json or run under a matching Docker image — and re-verify that workaround against v8.3.1 rather than assuming the earlier advice still holds, since the dependency graph just changed. Do not start a greenfield project on this without an explicit "we accept an unmaintained base" decision — a dependency-bump release is not the same as active maintenance. For new work, the maintained successor on a current Laravel is the intended path.
Where to look first, in this order:
routes/backend/ — routes are split per domain (auth.php, user.php, role.php, permission.php) and included from a parent file. This is the map of the admin surface.app/Http/Controllers/Backend/ — mirrors the route split (Auth/User/UserController, Auth/Role/RoleController, …).resources/views/backend/ — Blade views plus includes/sidebar.blade.php, which is your navigation menu.app/Models/Traits/ — the models are thin; attributes, relationships and scopes live in per-concern traits (User/Attribute.php, User/Relationship.php, User/Scope.php).database/seeders/ — roles and permissions are seeded data, not config. This is where you add a new permission.First use case: log in with the seeded administrator (credentials come from the user seeder — check database/seeders before guessing), create a role, tick permissions, create a user, then confirm the sidebar and route middleware actually reflect the new role.
Adding a module (the standard recipe). Every domain in the app follows the same shape, so copy an existing one rather than inventing structure:
app/Models/, with behaviour pushed into app/Models/Traits/<Model>/{Attribute,Relationship,Scope}.php.app/Http/Controllers/Backend/<Domain>/<Thing>Controller.php, extending the base Controller, using the existing form-request pattern for validation.routes/backend/<thing>.php plus a require line in the parent backend routes file.resources/views/backend/<domain>/<thing>/ (index, create, edit, show).view things, create things, …), then re-seed.resources/views/backend/includes/sidebar.blade.php, wrapped in a permission check so it disappears for unauthorized roles.Authorization. Roles/permissions come from spatie/laravel-permission; the boilerplate's contribution is the seeded matrix and the route middleware wiring. Guard routes with role: / permission: middleware, and gate UI with the Blade directives. Never hand-write if ($user->role === 'admin') — roles are data, and permission names are your stable contract.
Route::group(['middleware' => ['permission:view things']], function () { ... });
Index tables. Backend list screens use Yajra DataTables with server-side processing. The controller method returns the query builder and the view renders the table; if you return HTML in a column (badges, action buttons) you must whitelist it with rawColumns(), otherwise it renders escaped.
Events and listeners. Registration, login and password-change flows fire events under app/Events/ with listeners registered in EventServiceProvider. Hook business logic there (welcome mail, provisioning, audit) instead of editing controllers — it survives when you merge upstream changes.
Localization. A locale middleware plus a config array of supported languages drives a /{locale}/ route prefix and a switcher. Add a language by adding the config entry and the resources/lang/<code> directory; don't hardcode locale lists in views.
2FA and social login are opt-in per user / per provider. 2FA is a profile action backed by Google2FA with its own middleware; social login is Laravel Socialite driven by config/services.php plus a SocialLoginController. Both are good examples of extending the boilerplate without touching its core — copy that pattern.
composer audit on every dependency change, and isolate boilerplate code from your domain code so you can eventually extract.composer.lock diff (or diff the tag against your current HEAD) before merging; a transitive major inside a patch release is a real possibility on an old skeleton. Re-run your suite and the build on the new lockfile rather than trusting the version number.composer update your way to fixes. Upstream changes arrive as merge conflicts, so keep your diff small: add new files and override views rather than editing boilerplate files in place. Pulling v8.3.1 should ideally touch only composer.json/composer.lock for you.node-sass breaks on Node 16+. Updated PHP dependencies do not fix that. Build with Node 14/16 in a container, or migrate the build to sass (dart-sass) before doing anything else.php artisan permission:cache-reset, or forget the spatie.permission.cache key) whenever a role change "doesn't take". Also ensure production deploys seed permissions, not just roles.route:cache may fail. The split route files and any closures in them will break route caching. If your deploy pipeline caches routes, convert closures to controller actions first.migrate --seed on an existing DB re-seeds and can duplicate permissions/roles; use db:seed --class=PermissionTableSeeder for targeted refreshes and migrate:fresh only locally..env mail settings are placeholders; a silent "reset link sent" screen with no email is almost always MAIL_*, not the code. Same for queues — set QUEUE_CONNECTION=sync locally unless you're running a worker.RefreshDatabase plus a seeded permission set, otherwise authorization tests pass vacuously because no permissions exist. Test the middleware path, not just the controller.$user->getAllPermissions()) before touching middleware — nine times out of ten the role simply lacks the seeded permission name, or the name differs by a word from what the route middleware checks.How can I help you explore Laravel packages today?