edrisaturay / filament-starter-minimal
Minimal Filament v5 starter plugin: essential panel plugins only (Shield-first, extensible registry).
Package info
github.com/edrisaturay/filament-starter-minimal
pkg:composer/edrisaturay/filament-starter-minimal
Requires
- php: ^8.3
- bezhansalleh/filament-language-switch: ^4.3.0
- bezhansalleh/filament-panel-switch: ^3.1.0
- bezhansalleh/filament-shield: ^4.2.0
- charrafimed/global-search-modal: ^5.0.0
- filament/filament: ^5.0
- filament/spatie-laravel-media-library-plugin: ^5.0
- guava/filament-knowledge-base: ^3.1.0
- illuminate/contracts: ^11.28|^12.0|^13.0
- illuminate/database: ^11.28|^12.0|^13.0
- illuminate/support: ^11.28|^12.0|^13.0
- jeffgreco13/filament-breezy: ^3.2.5
- shuvroroy/filament-spatie-laravel-backup: ^3.4.0
- shuvroroy/filament-spatie-laravel-health: ^3.3.0
- stechstudio/filament-impersonate: ^5.0
Requires (Dev)
- orchestra/testbench: ^9.0|^10.0|^11.0
- pestphp/pest: ^4.7.0
- pestphp/pest-plugin-laravel: ^4.1.0
Suggests
- awcodes/filament-quick-create: Topbar quick-create dropdown for Filament resources.
- bezhansalleh/filament-exceptions: View Laravel exceptions inside a Filament resource.
- datlechin/filament-menu-builder: Drag-and-drop navigation menu builder.
- filament/spatie-laravel-settings-plugin: Settings pages backed by spatie/laravel-settings (component package).
- filament/spatie-laravel-tags-plugin: Filament form components for spatie/laravel-tags (component package).
- kenepa/resource-lock: Prevent two users from editing the same record simultaneously.
- owen-it/laravel-auditing: Eloquent auditing trait — wire into your models, not registered as a Filament plugin.
- pxlrbt/filament-spotlight: Cmd+K spotlight launcher for Filament panels.
- ralphjsmit/laravel-filament-components: Collection of handy Filament form/table components (component package).
- rawand201/filament-connection-badge: Show the active database connection in the Filament topbar.
- riodwanto/filament-ace-editor: Ace code-editor form field for Filament (component package).
- rupadana/filament-api-service: Generate REST API endpoints from your Filament resources.
- tomatophp/filament-media-manager: Full media-manager UI with folders and uploads.
- ysfkaya/filament-phone-input: International phone-number form field (component package).
- z3d0x/filament-logger: Activity logger UI for Filament (uses spatie/laravel-activitylog).
README
A Laravel package that ships a small, Filament v5-compatible “starter” layer: a panel plugin (FilamentStarterMinimalPlugin), a plugin registry (Shield-first), database-backed overrides, cached plugin state, and Filament resources for platform administration (plugin management, panel snapshots, audit log).
It is intentionally minimal compared to edrisaturay/filament-starter: fewer bundled plugins, no multi-plugin publish wizard, and a smaller doctor surface—but it still ships Artisan commands in the same spirit as the full starter (install, update, doctor, safe-mode).
Artisan commands
These mirror the full starter commands with a minimal-starter: prefix and lighter behavior.
Full starter (edrisaturay/filament-starter) |
This package |
|---|---|
php artisan starter:install |
php artisan minimal-starter:install |
php artisan starter:update |
php artisan minimal-starter:update |
php artisan starter:doctor |
php artisan minimal-starter:doctor |
php artisan starter:safe-mode on|off |
php artisan minimal-starter:safe-mode on|off |
minimal-starter:install
- Optionally publishes config (
--publish-config, or interactive confirm when not--no-interaction). - Runs
php artisan migrate --force. - Calls
PanelSnapshotManager::snapshot()(snapshots + plugin override sync).
php artisan minimal-starter:install php artisan minimal-starter:install --publish-config --no-interaction
minimal-starter:update
Runs migrate --force, then PanelSnapshotManager::snapshot(). Use after deploy or dependency updates.
php artisan minimal-starter:update
minimal-starter:doctor
Runs health checks: database connectivity, minimal migrations present, Filament / Shield classes, snapshot row count, each managed_panels id registered with Filament, and that each registry plugin class exists.
Exit codes:
0— every check passed or onlywarning-level findings1— at least onecriticalfinding (DB unreachable, Filament missing, registered plugin's class not autoloadable, etc.)
warning-level findings (e.g. a managed panel id that isn't registered with Filament yet, zero snapshots) are reported but do not fail the command — operators can wire CI on doctor || exit 1 without false negatives.
php artisan minimal-starter:doctor
minimal-starter:safe-mode
When on, plugins marked dangerous_to_disable in the registry are forced enabled in resolved state (same idea as the full starter). Implemented via cache key starter_minimal_safe_mode_active, optional env STARTER_MINIMAL_SAFE_MODE, or config filament-starter-minimal.safe_mode. Toggling clears plugin state cache for all Filament panels.
php artisan minimal-starter:safe-mode on php artisan minimal-starter:safe-mode off
Note: In testing env, safe mode reads as inactive (matches full starter behavior for tests).
Requirements
- PHP ^8.3
- Laravel 12 (
illuminate/support^12) - Filament ^5 (
filament/filament) - Filament Shield ^4 (
bezhansalleh/filament-shield)
Your app should use a Spatie-style role on the authenticated user (e.g. hasRole('super_admin')) for the built-in Platform resources.
Installation
Composer
composer require edrisaturay/filament-starter-minimal
Or add a path repository while developing:
{
"repositories": [
{
"type": "path",
"url": "packages/edrisaturay/filament-starter-minimal",
"options": { "symlink": true }
}
],
"require": {
"edrisaturay/filament-starter-minimal": "dev-main"
}
}
The package auto-registers FilamentStarterMinimalServiceProvider via Composer’s extra.laravel.providers.
Configuration (optional)
Publish the config file to customize panel IDs, defaults, or the super-admin role:
php artisan vendor:publish --tag=filament-starter-minimal-config
Migrations
Migrations are loaded from the package automatically (loadMigrationsFrom). Run:
php artisan migrate
If you prefer copies of migration files in your app (e.g. for customization), publish them:
php artisan vendor:publish --tag=filament-starter-minimal-migrations php artisan migrate
Quick start
1. Register the panel plugin
In your PanelProvider (or wherever you configure the panel), add one plugin entry. Do not also register FilamentShieldPlugin::make() separately unless you intend to load Shield twice.
use EdrisaTuray\FilamentStarterMinimal\Filament\FilamentStarterMinimalPlugin; use Filament\Panel; public function panel(Panel $panel): Panel { return $panel // ... ->plugins([ FilamentStarterMinimalPlugin::make(), ]); }
2. Align config with your panel ID
Edit config/filament-starter-minimal.php (or the merged defaults):
- Set
managed_panelsto every Filament panel id that should use the registry and receive registry-driven plugins (e.g.['admin', 'staff']). - Under
plugin_defaults, add a block for each of those panel IDs and each plugin key returned byPluginRegistry::getPlugins()(see Extending the registry).
If a panel’s id is not in managed_panels, PlatformPanelFactory will not attach registry plugins to that panel (but the Filament resources are still registered on whichever panels load FilamentStarterMinimalPlugin—restrict access with policies / canViewAny() as needed).
3. Seed snapshots and plugin override rows
The Plugin Management UI expects panel snapshots (and sync populates overrides). After your panels are registered, call:
use EdrisaTuray\FilamentStarterMinimal\Support\PanelSnapshotManager; PanelSnapshotManager::snapshot();
Typical places: AppServiceProvider::boot() (after Filament is ready), a dedicated Artisan command, or your deployment hook once per environment.
4. Filament Shield
Follow Shield’s own docs: run shield:install, configure config/filament-shield.php, generate permissions, and assign the super admin role configured in filament-starter-minimal.superadmin.role (default super_admin) to users who should access Platform resources.
What this package provides
| Area | Description |
|---|---|
FilamentStarterMinimalPlugin |
Filament Plugin (getId(): 'filament-starter-minimal'). Registers Platform resources and runs PlatformPanelFactory::build() for registry plugins. |
PluginRegistry |
Declares plugins (key, label, installer closure, defaults, dangerous_to_disable, Composer package name, plugin class). |
PluginStateResolver |
Merges config defaults with DB overrides, caches result per panel (starter_minimal_plugins_{panelId}). |
PluginSyncManager |
Ensures every registry key has a row per managed panel; removes stale rows; writes audit entries; clears cache. |
PanelSnapshotManager |
Stores panel metadata JSON; triggers PluginSyncManager::sync(). |
| Filament resources | Plugin Management, Panel Snapshots, Audit Log (super-admin gated). |
Configuration reference
File: config/filament-starter-minimal.php (merged as filament-starter-minimal.*).
| Key | Purpose |
|---|---|
safe_mode |
When true (or env STARTER_MINIMAL_SAFE_MODE=true), dangerous registry plugins are forced on. Usually toggled via minimal-starter:safe-mode (cache). |
superadmin.role |
Role name checked by Platform resources (hasRole()). Default: super_admin. |
managed_panels |
Panel IDs that receive registry installers via PlatformPanelFactory. |
plugin_defaults |
Nested: panel_id → plugin_key → enabled, options. Used before DB overrides. |
Example for two panels:
'managed_panels' => ['admin', 'staff'], 'plugin_defaults' => [ 'admin' => [ 'filament-shield' => [ 'enabled' => true, 'options' => [], ], ], 'staff' => [ 'filament-shield' => [ 'enabled' => true, 'options' => [], ], ], ],
Database schema
All tables use the starter_minimal_ prefix so this package can coexist with edrisaturay/filament-starter (which uses starter_* without _minimal_).
| Table | Purpose |
|---|---|
starter_minimal_panel_plugin_overrides |
Per-panel, per-plugin enabled, is_dangerous, options. Also options_version (currently always 1, reserved for future schema migrations) and updated_by_user_id (reserved; not yet auto-set by sync — populate manually if needed). Unique on (panel_id, plugin_key). |
starter_minimal_panel_snapshots |
Latest known Filament panel metadata (path, domains, middleware, and the consumer panel's hasTenancy() flag — informational only; this package itself is not multi-tenant aware). |
starter_minimal_audit_logs |
Append-only log for plugin sync and override changes. Immutable — update/delete throw at the model layer. actor_user_id is auto-injected from auth()->id() and is not mass-assignable. |
Dangerous plugins: If is_dangerous is true, the PanelPluginOverride model forces enabled to stay true (same behavior as the full starter).
Filament resources (navigation: Platform)
| Resource | Access | Notes |
|---|---|---|
| Plugin Management | Super admin only | CRUD overrides; Sync from Registry; Clear Plugin Cache. |
| Panel Snapshots | Super admin only | Read-only meta; Refresh snapshots header action. |
| Audit Log | Super admin only | Read-only list, newest first. |
canViewAny() / edit / create / delete use auth()->user()->hasRole(config('filament-starter-minimal.superadmin.role')).
Bundled plugin catalog
The default catalog is registered for you in Registry\DefaultPluginCatalog. Every entry is disabled by default (except filament-shield) and every installer is class_exists-guarded — so the package can list a plugin without forcing you to composer require it. Toggle plugins on per-panel from Plugin Management in the admin UI, or pre-configure in config/filament-starter-minimal.php.
| Key | Package (composer require ...) |
Notes |
|---|---|---|
filament-shield |
bezhansalleh/filament-shield |
RBAC. dangerous_to_disable — safe-mode forces it on. |
filament-panel-switch |
bezhansalleh/filament-panel-switch |
Configures globally via PanelSwitch::configureUsing(). |
filament-exceptions |
bezhansalleh/filament-exceptions |
Adds an Exceptions resource. |
filament-language-switch |
bezhansalleh/filament-language-switch |
Configures globally. Pass options.locales to set available locales. |
filament-breezy |
jeffgreco13/filament-breezy |
Profile + 2FA flows. |
filament-logger |
z3d0x/filament-logger |
Activity log UI. |
filament-connection-badge |
rawand201/filament-connection-badge |
DB connection indicator. |
filament-media-manager |
tomatophp/filament-media-manager |
Folder/file media manager. |
filament-menu-builder |
datlechin/filament-menu-builder |
Drag-and-drop navigation builder. |
filament-api-service |
rupadana/filament-api-service |
Generates REST endpoints from Resources. |
filament-resource-lock |
kenepa/resource-lock |
Prevents concurrent edits on a resource. |
filament-spatie-health |
shuvroroy/filament-spatie-laravel-health |
UI for spatie/laravel-health. |
filament-spatie-backup |
shuvroroy/filament-spatie-laravel-backup |
UI for spatie/laravel-backup. |
filament-global-search-modal |
charrafimed/global-search-modal |
Richer global search UI. |
filament-knowledge-base |
guava/filament-knowledge-base |
Markdown docs panel (KnowledgeBasePlugin). Enable on your knowledge-base panel id only. |
filament-knowledge-base-companion |
guava/filament-knowledge-base |
Links admin (and other) panels to the KB (KnowledgeBaseCompanionPlugin). |
filament-spotlight |
pxlrbt/filament-spotlight |
⌘K spotlight launcher. |
filament-quick-create |
awcodes/filament-quick-create |
Topbar quick-create dropdown. Options: excludes, includes, sort_by. |
Run php artisan minimal-starter:doctor after composer require to confirm the class autoloads — if a vendor renames their plugin class between versions, override the entry via withPlugin() (next section).
Knowledge Base (Guava)
This package requires guava/filament-knowledge-base ^3.x (Filament v5). You need two Filament panels:
- A dedicated knowledge-base panel with
KnowledgeBasePlugin(registry keyfilament-knowledge-base). - Your main panel(s) with
KnowledgeBaseCompanionPlugin(registry keyfilament-knowledge-base-companion).
Defaults in the published config enable the KB plugin on knowledge-base and leave the companion off on admin until you toggle it in Plugin Management or plugin_defaults.
After install:
php artisan filament:assets
npm install -D @tailwindcss/typography # if not already present
In each custom Filament theme used by the KB panel and companion panel(s), add:
@plugin "@tailwindcss/typography"; @source '../../../../vendor/guava/filament-knowledge-base/src/**/*'; @source '../../../../vendor/guava/filament-knowledge-base/resources/views/**/*';
Store markdown under docs/{panel-id}/{locale}/ and scaffold pages with php artisan docs:make.
Companion packages (not panel plugins)
These packages don't implement Filament's Plugin contract — they ship form components, traits, or action classes you compose into your own Resources. They're not in the registry. Two of them are bundled as hard dependencies (always installed), the rest are opt-in composer require:
Bundled (auto-installed) — class is autoloadable everywhere this starter runs:
filament/spatie-laravel-media-library-plugin— media library form fields (use inside your Resources viaSpatieMediaLibraryFileUpload::make(...))stechstudio/filament-impersonate— table/page action class. Auto-wired into the shippedUserResource(see Shipped UserResource below). If you ship your ownUserResource, add manually:use STS\FilamentImpersonate\Actions\Impersonate; // In your UserResource::table() $table->recordActions([Impersonate::make(), /* ... */]); // In your EditUser::getHeaderActions() return [Impersonate::make()->record($this->getRecord())];
If your panel uses->spa(), chain->withoutSpa()when redirecting outside Filament.
Shipped UserResource
The package ships a default UserResource (EdrisaTuray\FilamentStarterMinimal\Filament\Resources\UserResource) with the Impersonate action pre-wired — so a fresh install gets a working users CRUD with row-level impersonation out of the box.
- Model resolves dynamically from
config('filament-starter-minimal.users.model'), falling back toconfig('auth.providers.users.model')(soApp\Models\Userby default). - Authorization is left to Laravel policies (Filament Shield generates them automatically when you run
php artisan shield:install). - Disable when the consuming app already registers its own UserResource (e.g.
tomatophp/filament-users):STARTER_MINIMAL_USER_RESOURCE=false
Or inconfig/filament-starter-minimal.php:'users' => [ 'enabled' => false, 'model' => null, ],
Optional (composer require as needed):
filament/spatie-laravel-settings-plugin— Spatie-Settings-backed pagesfilament/spatie-laravel-tags-plugin— tag form componentsriodwanto/filament-ace-editor— Ace code editor form fieldralphjsmit/laravel-filament-components— assorted helper componentsysfkaya/filament-phone-input— international phone-number form fieldowen-it/laravel-auditing— model trait, not Filament-specific
Extending the registry
The plugin registry is bound to the container as PluginRegistryContract. Register additional plugins (or override package-shipped ones with the same key) via the fluent withPlugin() / withPlugins() API on the panel plugin:
use EdrisaTuray\FilamentStarterMinimal\Filament\FilamentStarterMinimalPlugin; use EdrisaTuray\FilamentStarterMinimal\Registry\PluginDefinition; use Filament\Panel; use Vendor\MyPlugin\MyPlugin; $panel->plugins([ FilamentStarterMinimalPlugin::make() ->withPlugin(new PluginDefinition( key: 'my-plugin', label: 'My Plugin', installer: fn (Panel $p, array $options): Panel => $p->plugin(MyPlugin::make()), defaultEnabled: false, dangerousToDisable: false, defaultOptions: [], class: MyPlugin::class, package: 'vendor/my-plugin', )), ]);
You can also resolve the contract directly anywhere in the app (e.g. in another service provider's boot()):
use EdrisaTuray\FilamentStarterMinimal\Contracts\PluginRegistryContract; app(PluginRegistryContract::class)->register(new PluginDefinition(...));
After registering new definitions, run Sync from Registry in the admin UI or call PluginSyncManager::sync() so override rows are created.
Protected dangerous flag
If the package's default catalog ships a definition with dangerousToDisable: true (e.g. filament-shield), PluginRegistryContract::register() will throw when a same-key registration tries to silently demote it to false. To intentionally override this, pass the explicit opt-in:
app(PluginRegistryContract::class)->register($definition, allowDangerousOverride: true);
This blocks the chained-takeover path where a third-party plugin could redefine filament-shield with dangerousToDisable=false and then disable RBAC.
isDangerous() semantics
PluginRegistry::isDangerous(string $key, ?string $panelId = null) returns true only if the registry definition for $key has dangerousToDisable=true. The $panelId parameter is accepted for API compatibility but ignored — the registry is the single source of truth. The is_dangerous DB column is a denormalized cache maintained by the model's saving hook; reading it is unnecessary and risks drift.
Caching and invalidation
- Resolved state is cached forever per panel under key
starter_minimal_plugins_{panelId}_v{registry-signature}. The signature changes whenever aPluginDefinitionis added, removed, or has itsdefaultEnabled/dangerousToDisablemodified — so registering a plugin viawithPlugin()automatically misses the old cache. - Saving or deleting a
PanelPluginOverridecallsPluginStateResolver::invalidate()for that panel. - The Clear Plugin Cache action in Plugin Management clears the resolver cache for all registered Filament panels.
- When safe mode is active, resolved state forces
dangerous_to_disableplugins on before the result is cached; useminimal-starter:safe-mode on|offso caches are invalidated automatically.
How sync works
PluginSyncManager::sync() is the write path that reconciles your code-level registry against the per-panel override rows in the database. Triggered from the Sync from Registry button, the install/update commands, or programmatically.
For every (managed_panel × registry_plugin) pair it:
- Acquires a 60-second
Cache::lock('starter_minimal_sync')(other concurrent calls block up to 10 seconds — prevents racing inserts during a deploy). - Inside a single
DB::transaction(), callsPanelPluginOverride::updateOrCreate()for each pair so model events (audit log + cache invalidation) fire. - Deletes any override row whose
plugin_keyis no longer in the registry or whosepanel_idis no longer inmanaged_panels. Each deletion writes an audit row. - After commit, invalidates
PluginStateResolvercaches for every registered panel.
Calling sync() twice in a row is a no-op on the second call — updateOrCreate only writes when fields differ from their defaults.
Shipped defaults
Out of the box, with zero published config:
managed_panelsis['admin']— only a panel with idadminreceives registry plugins fromPlatformPanelFactory.superadmin.roleissuper_admin— the role name checked by every Platform resource. Your User model must havespatie/laravel-permission'sHasRolestrait (or another implementation that exposes ahasRole(string $role)method), and a role with that name must exist and be assigned. If neither is true, the resources are simply invisible to all users (closed-default).safe_modeisfalse.- This package is single-tenant. The override / snapshot / audit tables key by
panel_idonly. The consumer's individual Filament panels may use Filament tenancy themselves — that's orthogonal. - The registry seeds
filament-shield(enabled = true,dangerous_to_disable = true); every other plugin in the catalog is registered asenabled = false. Toggle them on per-panel via Plugin Management or viaplugin_defaultsin the published config.
Troubleshooting
| Symptom | Likely cause / fix |
|---|---|
| Platform resources invisible to all users | The User model is missing the role trait, or no user has the configured super_admin role. Doctor cannot detect this — check $user->hasRole('super_admin') directly. |
| Plugin Management UI is empty | No snapshots yet. Run php artisan minimal-starter:install (or :update) to populate starter_minimal_panel_snapshots and the override table. |
| Toggling a plugin in the UI does nothing | Check that the panel id is in managed_panels. PlatformPanelFactory short-circuits non-managed panels even though the resources still appear. |
Cache::rememberForever returns stale state in production |
The cache driver must be persistent (redis, database, file). The resolver caches forever; with array driver the cache is recreated cold every request. |
Doctor reports a plugin's class missing after composer require |
The vendor renamed its plugin class. Override the entry via FilamentStarterMinimalPlugin::make()->withPlugin(new PluginDefinition(...)) with the correct FQCN, then run Sync from Registry. |
| Shield resources appearing twice | You registered both FilamentStarterMinimalPlugin::make() and FilamentShieldPlugin::make() on the same panel. Drop the bare Shield registration; this starter installs Shield via the registry. |
Commands reference
| Command | Purpose | Exits non-zero on |
|---|---|---|
minimal-starter:install |
Publish config (optional), migrate --force, snapshot + sync |
migrate non-zero exit OR any Throwable from snapshot/sync |
minimal-starter:update |
migrate --force, snapshot + sync. Re-runnable. |
Same |
minimal-starter:doctor |
Health checks (see above) | Any critical finding |
minimal-starter:safe-mode {on|off} |
Toggle the safe-mode cache flag, invalidate plugin caches | Invalid argument |
All commands accept --no-interaction and respect Laravel's standard verbosity flags.
Coexistence with edrisaturay/filament-starter
- Different DB tables (
starter_minimal_*vsstarter_*). - Different Filament plugin id (
filament-starter-minimalvsfilament-starter). - Different config file (
filament-starter-minimal.phpvsfilament-starter.php).
You should not load both starter panel plugins on the same panel if they both register Shield or duplicate resources—pick one package per panel.
Package layout
config/
filament-starter-minimal.php
database/
migrations/
*_create_starter_minimal_tables.php
src/
FilamentStarterMinimalServiceProvider.php
Contracts/
PluginRegistryContract.php
Registry/
DefaultPluginCatalog.php
PluginDefinition.php
Filament/
FilamentStarterMinimalPlugin.php
PlatformPanelFactory.php
Resources/
AuditLogResource.php
PanelPluginOverrideResource.php
PanelSnapshotResource.php
...
Models/
AuditLog.php
PanelPluginOverride.php
PanelSnapshot.php
Support/
MinimalDoctor.php
MinimalSafeMode.php
PanelSnapshotManager.php
PluginRegistry.php
PluginStateResolver.php
PluginSyncManager.php
Testing (in a consuming app)
The reference application includes Pest tests under tests/Unit/FilamentStarterMinimalTest.php that assert registry shape, config resolution, DB merge behavior (with a targeted migrate --path when needed), and plugin id stability.
License
MIT. See the package composer.json for author metadata.
Support
Issues and source: see the monorepo or package repository you publish from. For Filament or Shield behavior, refer to the official Filament v5 and Filament Shield documentation.