agentsclimarketplace

Olakunlevpn filament skills

Skill olakunlevpn/olakunlevpn-filament-skills

Filament PHP v5 coding standards agent skill. Resources, forms, tables, multi-tenancy, testing, and 18 areas covered. Works with Claude Code, Cursor, Cline, Gemini CLI and 40+ AI agents.

Install
npx -y skills add olakunlevpn/olakunlevpn-filament-skills

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 19 stars19 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use when writing, reviewing, or refactoring Filament PHP v5 code -- resources, forms, tables, infolists, actions, widgets, panels, relation managers, multi-tenancy, testing, or plugin development. Always apply these standards to all Filament work.

SKILL.md

11.5 KB, as published. Nobody here has run it

Filament PHP v5 Coding Standards

Comprehensive standards for building production-grade Filament v5 admin panels. Filament v5 requires PHP 8.3+, Laravel 13+, Livewire 4+, Tailwind CSS 4.1+. Follow these rules exactly. For detailed code examples, see REFERENCE.md.

When to Apply

Apply to ALL Filament work: resources, forms, tables, infolists, actions, widgets, dashboards, panels, relation managers, imports/exports, custom pages, multi-tenancy, testing, and deployment.


1. Project Structure

Directory Layout

  • Domain-grouped, plural-named: Resources/Shop/, Resources/Blog/, Resources/HR/
  • Resources in plural directories: Resources/Shop/Products/ProductResource.php
  • Schemas extracted: Resources/Shop/Products/Schemas/ProductSchema.php
  • Tables extracted: Resources/Shop/Products/Tables/ProductsTable.php
  • Multiple panels: Providers/Filament/AdminPanelProvider.php, AppPanelProvider.php

Resource Complexity Tiers

  • Simple (ManageRecords) -- modal CRUD, single page, no relation managers
  • Standard (List+Create+Edit) -- separate pages, basic CRUD
  • Full (List+Create+Edit+View) -- sub-navigation, relation managers, widgets

Naming Rules

  • Plural resource directories: Products/, not Product/
  • File names match class names: ProductResource.php
  • Slugs kebab-case: order-items
  • Namespace matches directory path exactly

2. Resource Architecture

Delegation Pattern

Resources delegate to dedicated Schema and Table classes. Keep resource classes slim.

class ProductResource extends Resource
{
    protected static ?string $model = Product::class;
    protected static ?string $slug = 'products';
    protected static ?string $recordTitleAttribute = 'name';
    protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedShoppingBag;
    protected static ?string $navigationGroup = 'Shop';
    protected static ?int $navigationSort = 1;

    public static function form(Schema $schema): Schema
    {
        return ProductSchema::configure($schema);
    }

    public static function table(Table $table): Table
    {
        return ProductsTable::configure($table);
    }
}

Key Rules

  • Always set $recordTitleAttribute for global search
  • Navigation icons: always Heroicon::Outlined* (not Solid for nav)
  • Use Heroicon enum, never string icon names
  • All actions import from Filament\Actions\* namespace only
  • Table methods: recordActions() not actions(), groupedBulkActions() not bulkActions()

3. Form Design

  • Top-level: $schema->components([...]) with Section wrapping
  • Section from Filament\Schemas\Components\Section
  • Layout components (Section, Grid, Tabs, Flex) from Filament\Schemas\Components\*
  • Slug fields: ->live(onBlur: true), create-only via Operation::Create, ->disabled()->dehydrated()
  • Selects with relationships: always ->searchable() and ->preload()
  • File uploads: set ->disk(), ->directory(), ->visibility()
  • Use Operation enum for conditional logic: Operation::Create, Operation::Edit
  • Repeaters for line items with calculated fields
  • Tabs for complex multi-section forms
  • All text labels via language files, never hardcoded

4. Table Design

  • Columns: TextColumn, IconColumn (booleans), BadgeColumn (enums), ImageColumn
  • Toggleable columns: ->toggleable(isToggledHiddenByDefault: true) for less important columns
  • Filters: SelectFilter, TernaryFilter (boolean), date range via custom filter
  • Actions wrapped in ActionGroup: View, Edit, Delete grouped
  • Bulk actions via groupedBulkActions(): delete, export, status change
  • Toolbar actions via toolbarActions(): create, import, export
  • Default sort: ->defaultSort('created_at', 'desc')
  • Searchable columns: ->searchable() on key text columns
  • Money: ->money('USD') or ->formatStateUsing() for custom formatting

5. Infolist (View) Patterns

  • Entry types: TextEntry, IconEntry (boolean), ImageEntry, BadgeEntry (enum)
  • Inline labels for compact display: ->inlineLabel()
  • Rich content: ->prose()->markdown() for formatted text
  • Tabs for complex view pages
  • Contextual actions on view pages with visibility conditions
  • Key-value entries for metadata

6. Enum Design System

Every status/type/category uses a PHP 8.1 backed string enum implementing Filament contracts:

  • HasLabel -- display name
  • HasColor -- semantic color
  • HasIcon -- Heroicon

Semantic colors: success (positive), danger (negative), warning (caution), info (new), primary (special), gray (neutral)

Naming: PascalCase case names, snake_case backed values. Cast in model: 'status' => OrderStatus::class


7. Actions & Notifications

  • All actions: Filament\Actions\Action, Filament\Actions\CreateAction, etc.
  • Never import from Filament\Tables\Actions\* (removed in v5)
  • Action modals use ->schema() not ->form()
  • ActionGroup ordering: View, Edit, Delete (most common first)
  • Notifications: Notification::make()->title()->success()->send()
  • Refresh after action: $this->dispatch('$refresh') or return redirect
  • Bulk actions: ->authorizeIndividualRecords() for policy-gated bulk operations

8. Relation Managers

  • Standard: extend RelationManager, define form() and table()
  • Alternative: ManageRelatedRecords page for complex relations
  • Action placement: headerActions (create), recordActions (per row), groupedBulkActions (selected)
  • Reuse across resources when the same relation appears in multiple places
  • Default sort on related records

9. Widgets & Dashboards

  • StatsOverview: multiple stat cards, optional inline charts, descriptions, icons
  • Chart widgets: line, bar, doughnut, pie -- extend ChartWidget
  • Lazy loading: on by default ($isLazy = true)
  • Polling: default 5s, customize via $pollingInterval or null to disable
  • Dashboard filters: implement HasFiltersForm for filterable dashboards
  • Resource page widgets: use ExposesTableToWidgets trait
  • Widget sort order via $sort property

10. Multi-Tenancy

  • Panel: ->tenant(Team::class) in PanelProvider
  • User model: implement HasTenants with getTenants() and canAccessTenant()
  • Automatic query scoping on all resources (opt-out with $isScopedToTenant = false)
  • CRITICAL: Form selects are NOT auto-scoped -- add modifyQueryUsing with Filament::getTenant()
  • Validation: use ->scopedUnique() and ->scopedExists() for tenant-aware rules
  • Domain-based: ->tenantDomain('{tenant:slug}.example.com')
  • Path-based with slug: ->tenant(Team::class, slugAttribute: 'slug')
  • Registration page: extend RegisterTenant
  • Profile page: extend EditTenantProfile

11. Multi-Panel Architecture

  • Separate PanelProvider per panel (admin, app, vendor)
  • Each panel: own auth, resources, pages, widgets, middleware, theme
  • FilamentUser::canAccessPanel() controls per-panel access
  • Shared config via Plugin class or static helper
  • Filament::setCurrentPanel('app') for testing non-default panels

12. Custom Pages & Clusters

  • Custom pages: php artisan make:filament-page Settings
  • Access control: canAccess() method
  • Header actions, header/footer widgets, widget data passing
  • Clusters: group related pages under sub-navigation
  • SubNavigationPosition::Top for horizontal tabs
  • Resource sub-navigation: getRecordSubNavigation() for View/Edit/Related pages

13. Testing (Pest + Livewire)

  • Test via livewire(PageClass::class) -- pages are Livewire components
  • Auth: actingAs(User::factory()->create()) in beforeEach
  • Multi-tenant: Filament::setTenant($team) + Filament::bootCurrentPanel()
  • Multi-panel: Filament::setCurrentPanel('admin')

Key test patterns:

  • List: ->assertCanSeeTableRecords(), ->searchTable(), ->sortTable(), ->filterTable()
  • Create: ->fillForm([...])->call('create')->assertHasNoFormErrors()->assertNotified()
  • Edit: ->assertSchemaStateSet([...])->fillForm([...])->call('save')
  • Actions: ->callAction(TestAction::make('send')->table($record))
  • Bulk: ->selectTableRecords($ids)->callAction(TestAction::make('delete')->table()->bulk())
  • Relations: livewire(RelationManager::class, ['ownerRecord' => $record, 'pageClass' => EditPage::class])

14. Import & Export

  • Exporter: ExportColumn definitions, placed in app/Filament/Exports/
  • Importer: ImportColumn with rules, examples, casting, relationship resolution
  • Actions: ExportAction::make(), ImportAction::make() in toolbar
  • Record resolution: firstOrNew, new Model, or null to skip

15. Authorization

  • FilamentUser interface required in production (APP_ENV != local)
  • Model policies auto-discovered: viewAny, create, update, delete, restore, forceDelete, reorder
  • Skip authorization: $shouldSkipAuthorization = true
  • Bulk action authorization: ->authorizeIndividualRecords()
  • Per-panel access: canAccessPanel(Panel $panel) with panel ID check

16. Performance & Deployment

Production:

php artisan optimize
php artisan filament:optimize

Panel config:

  • ->spa() for SPA mode
  • ->unsavedChangesAlerts() for data protection
  • ->databaseTransactions() for action safety

Widgets: Lazy by default. Set polling interval or null to disable. Use wire:init for deferred API loads.

Never run filament:optimize in local dev -- new components won't be discovered.

Tailwind v4: CSS-based config via Vite plugin. No tailwind.config.js. Use @source directives.


17. Livewire 4 Features (via Filament v5)

  • Islands: isolated re-render regions with @island directive
  • Async actions: #[Async] attribute for fire-and-forget (analytics, logging)
  • wire:model.deep: required when relying on child element event bubbling
  • wire:sort: built-in drag-and-drop without external packages
  • Parallel requests: wire:model.live no longer blocks
  • Self-closing tags required: <livewire:component />

18. Strict Rules

  • Never publish Blade views. Use CSS hooks with fi- prefix.
  • Never hardcode brand names, logos, currency. Use dynamic settings.
  • All user-facing text through language files and translation keys.
  • $recordTitleAttribute set on every resource.
  • Action modals: ->schema() not ->form()
  • Table: recordActions() not actions(), groupedBulkActions() not bulkActions()
  • Schema: $schema->components([...]) at top level
  • Icons: Heroicon:: enum only, never string names
  • Operation: Operation::Create, Operation::Edit, never string comparisons

Summary Checklist

  • Resource delegates to Schema and Table classes
  • $recordTitleAttribute set on every resource
  • Heroicon:: enum for all icons, Outlined for navigation
  • All actions from Filament\Actions\* namespace
  • Table uses recordActions(), groupedBulkActions(), toolbarActions()
  • Enums implement HasLabel, HasColor, HasIcon with semantic colors
  • Form selects are searchable and preloaded
  • Multi-tenant form selects manually scoped to tenant
  • FilamentUser interface implemented with canAccessPanel()
  • Model policies for authorization on every resource
  • filament:optimize in production deploy script
  • Tests use livewire() with Filament::setTenant() for multi-tenant
  • No hardcoded text -- all through language files
  • No published Blade views -- CSS hooks only

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.