mcpField
O
olakunlevpn-filament-skills

olakunlevpn-filament-skills

github.com/olakunlevpn開発25323 回インストール30 週間前に更新
リポジトリ

olakunlevpn-filament-skills について

Filament v5 の管理パネルを構築する PHP 開発者向けのコーディング規約スキルです。アーキテクチャ、UI 設計、認可、テスト、デプロイまで、バージョン固有のルールをまとめています。

主な機能

  1. 01Resource、Schema、Table の構成規則
  2. 02フォームとテーブルの設計指針
  3. 03マルチテナントと複数パネルのパターン
  4. 04認可と Livewire テストの指針
  5. 05本番デプロイとパフォーマンスの実践

活用シーン

  1. 01Filament 管理リソースの構成を計画
  2. 02テナント対応フォームとデータ範囲を実装
  3. 03Filament ページやアクションのテストを作成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/olakunlevpn/olakunlevpn-filament-skills --skill olakunlevpn-filament-skills

インストール後、Claude Code で/olakunlevpn-filament-skillsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

LICENSE.md
README.md
REFERENCE.md

詳細

Filament PHP v5 コーディング規約

本番環境に対応した Filament v5 管理パネルを構築するための包括的な規約です。Filament v5 には PHP 8.3 以降、Laravel 13 以降、Livewire 4 以降、Tailwind CSS 4.1 以降が必要です。これらのルールに正確に従ってください。詳細なコード例については、REFERENCE.md を参照してください。

適用範囲

Filament に関するすべての作業に適用してください。リソース、フォーム、テーブル、インフォリスト、アクション、ウィジェット、ダッシュボード、パネル、リレーションマネージャー、インポート/エクスポート、カスタムページ、マルチテナンシー、テスト、デプロイが対象です。


1. プロジェクト構成

ディレクトリ構成
  • ドメインごとにグループ化し、複数形の名前を付けます:Resources/Shop/、Resources/Blog/、Resources/HR/
  • リソースは複数形のディレクトリに配置します:Resources/Shop/Products/ProductResource.php
  • スキーマを切り出します:Resources/Shop/Products/Schemas/ProductSchema.php
  • テーブルを切り出します:Resources/Shop/Products/Tables/ProductsTable.php
  • 複数のパネル:Providers/Filament/AdminPanelProvider.php、AppPanelProvider.php
リソースの複雑さの段階
  • シンプル(ManageRecords)-- モーダル形式の CRUD、単一ページ、リレーションマネージャーなし
  • 標準(List+Create+Edit)-- ページを分けた基本的な CRUD
  • フル(List+Create+Edit+View)-- サブナビゲーション、リレーションマネージャー、ウィジェット
命名規則
  • リソースディレクトリ名は複数形にします:Products/。Product/ ではありません
  • ファイル名はクラス名と一致させます:ProductResource.php
  • スラッグはケバブケースにします:order-items
  • 名前空間はディレクトリパスと正確に一致させます

2. リソースのアーキテクチャ

委譲パターン

リソースは専用の Schema クラスと Table クラスに処理を委譲します。リソースクラスは簡潔に保ちます。

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);
    }
}
主なルール
  • グローバル検索用に、必ず $recordTitleAttribute を設定します
  • ナビゲーションアイコンには必ず Heroicon::Outlined* を使用します(ナビゲーションに Solid は使用しません)
  • Heroicon enum を使用し、文字列のアイコン名は使用しません
  • すべてのアクションは Filament\Actions\* 名前空間からのみインポートします
  • テーブルのメソッドには、actions() ではなく recordActions()、bulkActions() ではなく groupedBulkActions() を使用します

3. フォーム設計

  • 最上位では、Section で囲んだ $schema->components([...]) を使用します
  • Section は Filament\Schemas\Components\Section から使用します
  • レイアウトコンポーネント(Section、Grid、Tabs、Flex)は Filament\Schemas\Components\* から使用します
  • スラッグフィールドには ->live(onBlur: true) を使用します。作成時のみの場合は Operation::Create を使い、->disabled()->dehydrated() を指定します
  • リレーションを使う Select には、必ず ->searchable() と ->preload() を指定します
  • ファイルアップロードには ->disk()、->directory()、->visibility() を設定します
  • 条件付きロジックには Operation enum を使用します:Operation::Create、Operation::Edit
  • 計算フィールドを含む明細には Repeater を使用します
  • 複数のセクションからなる複雑なフォームには Tabs を使用します
  • すべてのテキストラベルは言語ファイルで管理し、ハードコードしません

4. テーブル設計

  • カラム:TextColumn、IconColumn(真偽値)、BadgeColumn(enum)、ImageColumn
  • 重要度の低いカラムには、切り替え可能なカラムとして ->toggleable(isToggledHiddenByDefault: true) を指定します
  • フィルター:SelectFilter、TernaryFilter(真偽値)、カスタムフィルターによる日付範囲
  • アクションは ActionGroup でまとめます:View、Edit、Delete
  • 一括アクションには groupedBulkActions() を使用します:削除、エクスポート、ステータス変更
  • ツールバーアクションには toolbarActions() を使用します:作成、インポート、エクスポート
  • デフォルトの並べ替え:->defaultSort('created_at', 'desc')
  • 主要なテキストカラムには ->searchable() を指定します
  • 金額には ->money('USD')、またはカスタム書式設定に ->formatStateUsing() を使用します

5. インフォリスト(表示)パターン

  • エントリーの種類:TextEntry、IconEntry(真偽値)、ImageEntry、BadgeEntry(enum)
  • コンパクトに表示するにはインラインラベルを使用します:->inlineLabel()
  • リッチコンテンツには、書式付きテキスト用の ->prose()->markdown() を使用します
  • 複雑な表示ページには Tabs を使用します
  • 表示ページでは、表示条件を設定したコンテキストに応じたアクションを使用します
  • メタデータにはキーと値のエントリーを使用します

6. Enum 設計システム

すべてのステータス/タイプ/カテゴリには、Filament のコントラクトを実装する PHP 8.1 の文字列 backed enum を使用します。

  • HasLabel -- 表示名
  • HasColor -- セマンティックカラー
  • HasIcon -- Heroicon

セマンティックカラー: success(肯定)、danger(否定)、warning(注意)、info(新規)、primary(特別)、gray(中立)

命名規則: case 名には PascalCase、backed value には snake_case を使用します。モデルでのキャスト:'status' => OrderStatus::class


7. アクションと通知

  • すべてのアクションには、Filament\Actions\Action、Filament\Actions\CreateAction などを使用します。
  • Filament\Tables\Actions\* からはインポートしないでください(v5 で削除されています)。
  • アクションモーダルでは ->form() ではなく ->schema() を使用します。
  • ActionGroup の順序:View、Edit、Delete(最もよく使うものを先頭にします)。
  • 通知:Notification::make()->title()->success()->send()
  • アクション後の更新:$this->dispatch('$refresh') を使用するか、リダイレクトを返します。
  • 一括アクション:ポリシーで制御する一括操作には ->authorizeIndividualRecords() を使用します。

8. リレーションマネージャー

  • 標準:RelationManager を継承し、form() と table() を定義します。
  • 代替案:複雑なリレーションには ManageRelatedRecords ページを使用します。
  • アクションの配置:headerActions(作成)、recordActions(各行)、groupedBulkActions(選択したレコード)
  • 同じリレーションが複数の場所に表示される場合は、リソース間で再利用します。
  • 関連レコードにはデフォルトの並べ替え順を設定します。

9. ウィジェットとダッシュボード

  • StatsOverview:複数の統計カード、任意のインラインチャート、説明、アイコンに対応します。
  • チャートウィジェット:折れ線、棒、ドーナツ、円グラフ -- ChartWidget を継承します。
  • 遅延読み込み:デフォルトで有効です($isLazy = true)。
  • ポーリング:デフォルトは 5s です。$pollingInterval でカスタマイズするか、null で無効にできます。
  • ダッシュボードのフィルター:フィルター可能なダッシュボードには HasFiltersForm を実装します。
  • リソースページのウィジェット:ExposesTableToWidgets トレイトを使用します。
  • ウィジェットの並べ替え順は $sort プロパティで指定します。

10. マルチテナンシー

  • パネル:PanelProvider で ->tenant(Team::class) を指定します。
  • ユーザーモデル:HasTenants を実装し、getTenants() と canAccessTenant() を定義します。
  • すべてのリソースでクエリが自動的にスコープされます($isScopedToTenant = false で無効にできます)。
  • 重要:フォームのセレクトは自動的にスコープされません。Filament::getTenant() を使って modifyQueryUsing を追加してください。
  • バリデーション:テナントを考慮したルールには ->scopedUnique() と ->scopedExists() を使用します。
  • ドメインベース:->tenantDomain('{tenant:slug}.example.com')
  • スラッグを使ったパスベース:->tenant(Team::class, slugAttribute: 'slug')
  • 登録ページ:RegisterTenant を継承します。
  • プロフィールページ:EditTenantProfile を継承します。

11. マルチパネルアーキテクチャ

  • パネルごとに PanelProvider を分けます(admin、app、vendor)。
  • 各パネルは、独自の認証、リソース、ページ、ウィジェット、ミドルウェア、テーマを持ちます。
  • FilamentUser::canAccessPanel() でパネルごとのアクセスを制御します。
  • Plugin クラスまたは静的ヘルパーを使って設定を共有します。
  • デフォルト以外のパネルをテストするには Filament::setCurrentPanel('app') を使用します。

12. カスタムページとクラスター

  • カスタムページ:php artisan make:filament-page Settings
  • アクセス制御:canAccess() メソッド
  • ヘッダーアクション、ヘッダー/フッターウィジェット、ウィジェットへのデータ渡し
  • クラスター:関連するページをサブナビゲーションの下にまとめます。
  • 水平タブには SubNavigationPosition::Top を使用します。
  • リソースのサブナビゲーション:表示/編集/関連ページには getRecordSubNavigation() を使用します。

13. テスト(Pest + Livewire)

  • livewire(PageClass::class) を使ってテストします。ページは Livewire コンポーネントです。
  • 認証:beforeEach で actingAs(User::factory()->create()) を使います。
  • マルチテナント:Filament::setTenant($team) + Filament::bootCurrentPanel() を使います。
  • マルチパネル:Filament::setCurrentPanel('admin') を使います。

主なテストパターン:

  • 一覧:->assertCanSeeTableRecords()、->searchTable()、->sortTable()、->filterTable()
  • 作成:->fillForm([...])->call('create')->assertHasNoFormErrors()->assertNotified()
  • 編集:->assertSchemaStateSet([...])->fillForm([...])->call('save')
  • アクション:->callAction(TestAction::make('send')->table($record))
  • 一括操作:->selectTableRecords($ids)->callAction(TestAction::make('delete')->table()->bulk())
  • リレーション:livewire(RelationManager::class, ['ownerRecord' => $record, 'pageClass' => EditPage::class])

14. インポートとエクスポート

  • エクスポーター:ExportColumn の定義を app/Filament/Exports/ に配置します。
  • インポーター:ルール、例、キャスト、リレーションの解決に対応した ImportColumn を使います。
  • アクション:ツールバーで ExportAction::make()、ImportAction::make() を使います。
  • レコードの解決:firstOrNew、new Model、またはスキップする場合は null を使います。

15. 認可

  • 本番環境(APP_ENV != local)では FilamentUser インターフェースが必要です。
  • モデルポリシーは自動検出されます:viewAny、create、update、delete、restore、forceDelete、reorder
  • 認可をスキップするには、$shouldSkipAuthorization = true を設定します。
  • 一括アクションの認可:->authorizeIndividualRecords()
  • パネルごとのアクセス:パネル ID を確認する canAccessPanel(Panel $panel)

16. パフォーマンスとデプロイ

本番環境:

php artisan optimize
php artisan filament:optimize

パネル設定:

  • SPA モードには ->spa() を使います。
  • データ保護には ->unsavedChangesAlerts() を使います。
  • アクションの安全性を確保するには ->databaseTransactions() を使います。

ウィジェット: デフォルトで遅延読み込みされます。ポーリング間隔を設定するか、無効にするには null を指定します。API の読み込みを遅延させるには wire:init を使います。

ローカル開発環境では filament:optimize を実行しないでください。新しいコンポーネントが検出されなくなります。

Tailwind v4: Vite プラグイン経由の CSS ベース設定です。tailwind.config.js はありません。@source ディレクティブを使います。


17. Livewire 4 の機能(Filament v5 経由)

  • アイランド:@island ディレクティブによる、独立して再レンダリングされる領域
  • 非同期アクション:#[Async] 属性による、完了を待たずに実行する処理(分析、ログ記録)
  • wire:model.deep:子要素のイベントバブリングに依存する場合に必要です。
  • wire:sort:外部パッケージを使わずに利用できる組み込みのドラッグ&ドロップ機能
  • 並列リクエスト:wire:model.live がブロックしなくなりました。
  • 自己終了タグが必須:<livewire:component />

18. 厳守事項

  • Blade ビューを公開しないでください。fi- プレフィックス付きの CSS フックを使います。
  • ブランド名、ロゴ、通貨をハードコードしないでください。動的な設定を使います。
  • ユーザーに表示するテキストはすべて、言語ファイルと翻訳キーを通じて指定します。
  • すべてのリソースで $recordTitleAttribute を設定します。
  • アクションモーダルでは ->form() ではなく ->schema() を使います。
  • テーブルでは actions() ではなく recordActions() を、bulkActions() ではなく groupedBulkActions() を使います。
  • スキーマの最上位では $schema->components([...]) を使います。
  • アイコンには Heroicon:: enum のみを使い、文字列名は使いません。
  • 操作には Operation::Create、Operation::Edit を使い、文字列比較はしません。

要約チェックリスト

  • リソースが Schema クラスと Table クラスに処理を委譲している
  • すべてのリソースで $recordTitleAttribute が設定されている
  • すべてのアイコンに Heroicon:: enum を使い、ナビゲーションには Outlined を使っている
  • すべてのアクションが Filament\Actions\* 名前空間を使っている
  • テーブルで recordActions()、groupedBulkActions()、toolbarActions() を使っている
  • enum が HasLabel、HasColor、HasIcon を実装し、意味に沿った色を使っている
  • フォームのセレクトが検索可能で、事前読み込みされている
  • マルチテナントのフォームのセレクトが、テナントに合わせて手動でスコープされている
  • FilamentUser インターフェースを実装し、canAccessPanel() を定義している
  • すべてのリソースの認可にモデルポリシーを使用している
  • 本番環境のデプロイスクリプトで filament:optimize を実行している
  • テストで livewire() を使い、マルチテナントでは Filament::setTenant() を使っている
  • テキストをハードコードせず、すべて言語ファイルを通じて指定している
  • Blade ビューを公開せず、CSS フックのみを使っている

コメント