dsolodev/wirekit

A very opinionated starter kit for Laravel with Filament as the admin panel.

Maintainers

Package info

github.com/dsolodev/wirekit

Type:project

pkg:composer/dsolodev/wirekit

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 2

1.0.1 2026-07-29 13:56 UTC

This package is auto-updated.

Last update: 2026-08-05 08:54:39 UTC


README

Build Status Total Downloads Latest Stable Version License

WireKit is an opinionated starter kit for Laravel with Filament as the admin panel.

✨ Features

  • Filament 5 admin panel pre-configured
  • Rector, Pint, Prettier for automated code quality
  • PHPStan Level Max (maximum strictness)
  • 100% Type Coverage with Pest
  • Filament Shield roles and permissions, with the first user as super admin
  • One-command install that creates the database and seeds an administrator

🚀 Installation

Starting a new project — the whole sequence

laravel new my-app --using=dsolodev/wirekit   # runs wirekit:install for you
cd my-app
npm install && npm run build
composer dev                                   # http://localhost:8000/admin

# then, in the new repo's Settings -> Secrets and variables -> Actions, add:
#   FILAMENT_COMPOSER_USERNAME     your@email.com
#   FILAMENT_COMPOSER_LICENSE_KEY  your-license-key

That last step is the one that is easy to forget and the reason CI goes red on a brand new repo. See The Filament licence for why, and for the gh one-liners.

Prerequisites: PHP 8.5, a running MySQL, Node, and the Filament licence already configured globally on this machine.

Quick Start with Laravel Installer

You can use the Laravel Installer to install this starter kit.

laravel new my-app --using=dsolodev/wirekit
cd my-app

Alternative: Using Composer

composer create-project dsolodev/wirekit --prefer-dist my-app
cd my-app

Both commands run php artisan wirekit:install, which:

  1. Names the app after the project directory (my-app becomes My App).
  2. Creates the MySQL database named after the project directory (my-app becomes my_app).
  3. Generates the application key and runs the migrations.
  4. Generates Shield's policies and permissions, and grants them to the super_admin role.
  5. Seeds the first administrator, who is promoted to super_admin.

You can then build the assets and start the server:

npm install && npm run build
composer dev

Sign in at /admin with:

Email Password
admin@my-app.test password

That user is created first, so it receives the super_admin role automatically.

The email follows the project name, so a project in blog seeds admin@blog.test. Change this password before deploying anywhere.

Database requirements

The installer expects a reachable MySQL server and connects with the credentials in your .env file, defaulting to root with no password on 127.0.0.1:3306. Edit DB_USERNAME / DB_PASSWORD in .env before installing if your server differs.

If the installer cannot reach MySQL, it says so and stops without touching anything else. Create the database yourself and finish the install with:

php artisan migrate --seed

To use a different driver, set DB_CONNECTION in .env before installing. Only MySQL databases are created automatically; other drivers are migrated as-is.

🔑 The Filament licence (read this when something 401s)

filament/blueprint sits in require-dev and is a paid package served from packages.filamentphp.com, which answers HTTP 401 to anyone unauthenticated. Two places need the licence key, and they are configured separately.

On a new machine — once, ever

composer config --global --auth http-basic.packages.filamentphp.com "your@email.com" "your-license-key"

This writes ~/.composer/auth.json, outside any project, so it covers every project at once and can never be committed by accident. Verify it took:

composer config --global --list | grep filamentphp

The key itself is in your Filament account at https://filamentphp.com/dashboard.

In every new repo — once per project

GitHub Actions cannot see ~/.composer/auth.json, and personal accounts have no account-wide Actions secrets, so each repo built from this kit needs its own two secrets.

In the browser: Settings → Secrets and variables → Actions → New repository secret, twice.

Or with the GitHub CLI (brew install gh && gh auth login first), from inside the project:

gh secret set FILAMENT_COMPOSER_USERNAME    --body "your@email.com"
gh secret set FILAMENT_COMPOSER_LICENSE_KEY --body "your-license-key"

.github/workflows/tests.yml folds them into the COMPOSER_AUTH environment variable, which Composer reads in place of an auth.json. Nothing is written to disk, so no later step can print the key, and GitHub masks both values in the logs.

Forget this step and CI fails on composer install with a 401 on filament/blueprint — that is the symptom to recognise, and this section is the fix.

🛠️ Pre-configured Development Tools

Available Commands

# Setup
composer setup                  # Install dependencies, create the database, migrate, seed, and build assets
php artisan wirekit:install     # Re-run the installer on its own (safe to run repeatedly)

# Development
composer dev                    # Start development server with hot reloading, queue worker, and log monitoring

# Code quality
composer lint                   # Auto-fix code style issues and refactoring with Pint, Rector, Prettier
composer test:lint              # Check code style issue and refactoring (dry-run) for CI/CD pipeline

# Testing
composer test:unit              # Run the Pest test suite
composer test:type-coverage     # Check type coverage using Pest
composer test:types             # Run PHPStan analysis at max level
composer test                   # Run everything above: lint, static analysis, type coverage, and tests

# Maintenance
composer update:requirements    # Update all PHP and NPM dependencies to the latest versions

composer update:requirements is deliberately a manual command. Bumping every constraint is a decision you make before a release, not a side effect of installing a single package.

⚙️ Application defaults

AppServiceProvider sets a handful of opinionated global defaults. Two of them are worth understanding before you build on this kit.

Mass assignment is disabled

Model::unguard();

Every write in a Filament panel goes through a schema, and Filament only ever saves the fields declared in that schema. $fillable therefore protects nothing here while costing you a list to maintain on every model, so it is turned off globally.

This trade-off stops holding the moment request data reaches a model from anywhere else. If you add an API controller, a public-facing form, or anything resembling Model::create($request->all()), you no longer have mass assignment protection: a caller could set is_active, id, or any other column by adding it to the payload. In that case either drop Model::unguard() and declare $fillable, or validate first and pass an explicit array:

$user->update($request->safe()->only(['name', 'email']));

Strict mode is development-only

Model::shouldBeStrict(! $this->app->isProduction());

Strict mode turns lazy loading, reading a missing attribute, and discarding an unfillable attribute into exceptions. That is exactly what you want while developing and exactly what you do not want in front of real users, where a single unloaded column would become a 500 instead of a null.

This matters for authorization in particular. User::canAccessPanel() returns $this->is_active, so a user loaded without that column throws in development (loudly telling you to fix the query) and denies access in production (failing closed). Both behaviours are correct for their environment.

The rest

Default Effect
Date::use(CarbonImmutable::class) Dates are immutable, matching Pint's date_time_immutable rule. $date->addDay() returns a new instance instead of mutating.
DB::prohibitDestructiveCommands(...) migrate:fresh, db:wipe and friends refuse to run in production.
URL::forceHttps(...) Generated URLs use HTTPS in production regardless of what the proxy reports.
Password::defaults(...) Minimum 12 characters with mixed case and numbers; also checked against known breaches in production.

🛡️ Roles and permissions

Filament Shield provides role-based access control on top of spatie/laravel-permission. Roles are managed from the Roles resource inside the panel.

The first user is the super admin

Somebody has to be able to hand out roles before any roles exist, so UserObserver promotes the first user created to the super_admin role — whether that user comes from the seeder, from php artisan make:filament-user, or from your own code. Every user created afterwards starts with no roles and must be granted them from the panel.

To promote somebody else later:

php artisan shield:super-admin

After adding a resource

The panel runs with ->strictAuthorization(), which means Filament throws rather than silently denying when a model has no policy. Shield writes those policies for you, so after creating a resource run:

php artisan shield:generate --all

This generates the missing policies, creates the matching permissions, and grants them all to super_admin. The installer already does this for you on a fresh install.

If you forget, you will see a clear LogicException naming the model and the missing ability — that is strict authorization doing its job, not a bug.

Panel access versus permissions

These are two different switches:

Question Decided by
May this user open the panel at all? User::canAccessPanel(), i.e. the is_active column
What may they see and do once inside? Their roles and the Shield generated policies

A user who is active but holds no roles can sign in and will simply find an empty panel.

📋 Logs

Log Viewer is available at /log-viewer and linked from the panel sidebar. Access is gated by the viewLogViewer ability defined in AppServiceProvider, which allows any active user. Tighten it before you deploy if not every user should read your logs.

🎨 Theming

The panel uses Filament's default stylesheet, and the panel font is set once via ->font('Public Sans') in AdminPanelProvider.

Filament's stylesheet is compiled ahead of time, without visibility of your code, so Tailwind classes written in your own Filament pages and views are not included in it. If you start writing them, generate a custom theme:

php artisan make:filament-theme admin
npm run build

That command creates the theme, adds it to vite.config.js, and registers ->viteTheme() for you. Until you need it, the default stylesheet is one less thing to build.

📖 Resources

Official Documentation

Packages Used

📝 License

WireKit is open-sourced software licensed under the MIT license.