olakunlevpn-filament-skills について
Filament v5 の管理パネルを構築する PHP 開発者向けのコーディング規約スキルです。アーキテクチャ、UI 設計、認可、テスト、デプロイまで、バージョン固有のルールをまとめています。
主な機能
- 01Resource、Schema、Table の構成規則
- 02フォームとテーブルの設計指針
- 03マルチテナントと複数パネルのパターン
- 04認可と Livewire テストの指針
- 05本番デプロイとパフォーマンスの実践
活用シーン
- 01Filament 管理リソースの構成を計画
- 02テナント対応フォームとデータ範囲を実装
- 03Filament ページやアクションのテストを作成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ olakunlevpn/ olakunlevpn-filament-skills --skill olakunlevpn-filament-skillsインストール後、Claude Code で/olakunlevpn-filament-skillsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
LICENSE.mdREADME.mdREFERENCE.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 は使用しません) Heroiconenum を使用し、文字列のアイコン名は使用しません- すべてのアクションは
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()を設定します - 条件付きロジックには
Operationenum を使用します: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 フックのみを使っている