mcpField
L
laravel-specialist

laravel-specialist

github.com/pixel-process-ug開発380 回インストール34 週間前に更新
リポジトリ

laravel-specialist について

Laravelアプリケーションの設計、構築、保守を支援するスキルです。アーキテクチャ、実装、テスト、最適化を扱い、Eloquent、Blade、Livewire、キュー、イベント、Pestの実践方法をまとめています。

主な機能

  1. 01Laravelプロジェクトと構成のレビュー
  2. 02Eloquentモデルとリレーション
  3. 03BladeとLivewireのパターン
  4. 04キュー、ジョブ、イベント、ミドルウェア
  5. 05各層のPestテスト
  6. 06マイグレーション、シーダー、Artisan

活用シーン

  1. 01新規Laravelアプリの設計
  2. 02既存プロジェクトの構成レビュー
  3. 03データモデルと非同期ジョブの実装
  4. 04ルート、DB動作、ユーザーフローのテスト

インストール

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

$npx skills add https://github.com/pixel-process-ug/superkit-agents --skill laravel-specialist

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

詳細

Laravel スペシャリスト

概要

フレームワークの規約とベストプラクティスに従って、本番環境に対応した Laravel アプリケーションを設計、構築、保守します。このスキルでは、Eloquent ORM の高度なリレーションシップパターン、Blade テンプレートと Livewire によるインタラクティブ機能、キューおよびイベントシステム、ミドルウェアパイプライン、サービスプロバイダー、あらゆるレイヤーでの Pest テスト、マイグレーション、シーダー、ファクトリーのための Artisan ツールなど、Laravel エコシステム全体を扱います。

新規開発か既存アプリケーションの改修かを問わず、アプリケーションフレームワークが Laravel の場合は、このスキルを適用してください。

複数フェーズのプロセス

フェーズ 1:コンテキストの把握
  1. Laravel のバージョンを特定します(composer.json -> laravel/framework)
  2. config/ を調べ、有効なパッケージとカスタム設定を確認します
  3. 既存のモデル、リレーションシップ、マイグレーション履歴を把握します
  4. routes/ を確認し、API、Web、コンソール、チャネルの定義を調べます
  5. インストール済みのファーストパーティパッケージ(Sanctum、Horizon、Telescope、Pulse、Pennant、Scout、Cashier)を一覧にします
  6. Livewire、Inertia、または Blade のみのフロントエンドスタックを確認します

停止 — Laravel のバージョンとインストール済みパッケージを確認するまでは、アーキテクチャのレビューを開始しないでください。

ドキュメント確認プロトコル

[HARD-GATE] Laravel API に不確かな点がある場合は、推測せずに確認してください。mcp__context7__resolve-library-id に続けて mcp__context7__query-docs を使用します(推奨)。代替手段として、https://github.com/laravel/docs から取得してください。Livewire、Pest、Inertia については、それぞれを context7 で個別に解決してください。取得したドキュメントは、記憶している知識より優先されます。

フェーズ 2:アーキテクチャのレビュー
  1. ディレクトリ構造が Laravel の規約に従っていることを確認します(下記のセクションを参照)
  2. サービスプロバイダーの登録と遅延読み込みを評価します
  3. ミドルウェアスタックの順序とグループを確認します
  4. キュー接続の設定とワーカーのトポロジーを評価します
  5. キャッシュ戦略(設定、ルート、ビュー、アプリケーションレベル)を確認します

停止 — アーキテクチャ上の課題を文書化するまでは、実装を開始しないでください。

フェーズ 3:実装
  1. 最初にマイグレーションを作成します — スキーマが信頼できる唯一の情報源です
  2. リレーションシップ、スコープ、キャスト、アクセサーを備えた Eloquent モデルを構築します
  3. 専用の Action クラスまたは Service クラスにビジネスロジックを実装します
  4. ルートにバインドするコントローラー(単一アクションまたはリソースコントローラー)を作成します
  5. バリデーションには Form Request を、認可には Policy を追加します
  6. 非同期ワークフローのためにイベント、リスナー、ジョブを連携させます

停止 — Form Request と Policy を省略しないでください。インラインでのバリデーションと認可はアンチパターンです。

フェーズ 4:テスト
  1. 分離されたロジック(Action、値オブジェクト、Cast)のユニットテスト
  2. HTTP エンドポイントとミドルウェアの動作に対するフィーチャーテスト
  3. 重要なユーザーフローに対する Laravel Dusk を使ったブラウザーテスト
  4. assertDatabaseHas、assertSoftDeleted を使ったデータベースアサーション
  5. 副作用の検証に使うキューとイベントのフェイク

停止 — すべてのレイヤーでテストに合格するまでは、最適化に進まないでください。

フェーズ 5:最適化
  1. Eager Loading を適用して N+1 クエリを解消します
  2. コストの高い計算と設定/ルート/ビューをキャッシュします
  3. 頻繁にクエリされるカラムにインデックスを付与し、EXPLAIN で検証します
  4. 開発環境で Telescope または Debugbar を使ってプロファイリングします
  5. 本番環境のキュー監視用に Horizon を設定します

Eloquent のパターン

リレーションシップ
リレーションシップメソッド逆方向使用例
1 対 1hasOnebelongsToUser -> Profile
1 対多hasManybelongsToPost -> Comments
多対多belongsToManybelongsToManyUser <-> Roles(中間テーブル)
Has-Many-ThroughhasManyThrough—Country -> Posts(Users 経由)
ポリモーフィックmorphMany / morphTomorphToPosts と Videos に対する Comments
多対多ポリモーフィックmorphToManymorphedByManyPosts と Videos に付与する Tags
スコープ
// Local scope — reusable query constraint
public function scopeActive(Builder $query): Builder
{
    return $query->where('status', 'active');
}

// Usage: User::active()->where('role', 'admin')->get();

// Global scope — applied to all queries on the model
protected static function booted(): void
{
    static::addGlobalScope('published', function (Builder $builder) {
        $builder->whereNotNull('published_at');
    });
}
アクセサー、ミューテーター、キャスト
// Attribute accessor/mutator (Laravel 11+ syntax)
protected function fullName(): Attribute
{
    return Attribute::make(
        get: fn () => "{$this->first_name} {$this->last_name}",
    );
}

// Custom cast
protected function casts(): array
{
    return [
        'options'    => AsCollection::class,
        'address'    => AddressCast::class,
        'status'     => OrderStatus::class,  // Backed enum
        'metadata'   => 'array',
        'is_active'  => 'boolean',
        'amount'     => MoneyCast::class,
    ];
}
Eager Loading によるクエリ最適化
// BAD — N+1 problem: 1 query for posts + N queries for authors
$posts = Post::all();
foreach ($posts as $post) {
    echo $post->author->name;  // Triggers lazy load each iteration
}

// GOOD — Eager load: 2 queries total
$posts = Post::with('author')->get();

// Nested eager loading
$posts = Post::with(['author', 'comments.user'])->get();

// Constrained eager loading
$posts = Post::with(['comments' => function ($query) {
    $query->where('approved', true)->latest()->limit(5);
}])->get();

// Prevent lazy loading in development
Model::preventLazyLoading(! app()->isProduction());

Blade テンプレートと Livewire コンポーネント

Blade の規約
  • レイアウト:@yield/@section を使用する resources/views/layouts/app.blade.php、またはコンポーネントベースの <x-app-layout>
  • コンポーネント:resources/views/components/ — 匿名クラスまたはクラスベース
  • パーシャル:再利用可能な断片には @include('partials.sidebar') を使用します
  • エスケープされた出力には {{ }} を使用し、HTML が明示的に信頼できる場合に限り {!! !!} を使用します
  • 生の PHP 条件分岐より、Blade ディレクティブ(@auth、@can、@env)を優先します
Livewire のパターン
// Full-page Livewire component (Livewire 3+)
#[Layout('layouts.app')]
#[Title('Dashboard')]
class Dashboard extends Component
{
    public string $search = '';

    #[Computed]
    public function users(): LengthAwarePaginator
    {
        return User::where('name', 'like', "%{$this->search}%")->paginate(15);
    }

    public function render(): View
    {
        return view('livewire.dashboard');
    }
}
フロントエンドスタックの選択表
判断基準Livewire を選択Inertia を選択
既存の Blade コードベースはいいいえ
SPA のような操作性が必要部分的(wire:navigate を使用)はい
チームに Vue/React の経験があるいいえはい
サーバーサイドレンダリングを優先はいアダプターによります
リアルタイムのリアクティブ性はい(ポーリング、ストリーム)Echo の設定が必要
SEO が重要なページどちらでも対応可能どちらでも対応可能(SSR アダプター)

キュー、ジョブ、イベントのパターン

ジョブの設計
class ProcessInvoice implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public int $tries = 3;
    public int $backoff = 60;
    public int $timeout = 120;
    public string $queue = 'invoices';

    public function __construct(public readonly Invoice $invoice) {}

    public function handle(PdfGenerator $generator): void
    {
        $generator->generate($this->invoice);
    }

    public function failed(Throwable $exception): void
    {
        // Notify admin, log to error tracker
    }
}
イベント/リスナーのパターン
// Dispatch event
OrderPlaced::dispatch($order);

// Listener (queued)
class SendOrderConfirmation implements ShouldQueue
{
    public function handle(OrderPlaced $event): void
    {
        Mail::to($event->order->user)->send(new OrderConfirmationMail($event->order));
    }
}
同期処理と非同期処理の選択表
タスクキュー処理同期処理
メール/通知の送信はいリクエストサイクル内では行いません
PDF の生成はい2 秒未満で、ユーザーが待つ場合に限ります
決済処理場合によります — Webhook 駆動を推奨ゲートウェイが 5 秒未満で応答する場合
キャッシュのウォームアップはい行いません
監査ログの記録はい(大量の場合)、または同期(少量の場合)確実な配信が必要な場合
検索インデックスの作成はい行いません

ミドルウェアとサービスプロバイダー

ミドルウェアのスタック順序

ミドルウェアの順序は重要です。bootstrap/app.php のデフォルトスタック(Laravel 11 以降):

->withMiddleware(function (Middleware $middleware) {
    $middleware->web(append: [
        HandleInertiaRequests::class,  // After session, before response
    ]);

    $middleware->api(prepend: [
        EnsureFrontendRequestsAreStateful::class,  // Sanctum SPA auth
    ]);

    $middleware->alias([
        'role'     => EnsureUserHasRole::class,
        'verified' => EnsureEmailIsVerified::class,
    ]);
})
サービスプロバイダーのベストプラクティス
  • バインディングは register() に登録し、そこでコンテナから解決しないでください
  • 起動時の処理(イベントリスナー、ルートモデルバインディング、マクロ)は boot() に記述します
  • すべてのリクエストで必要になるわけではないバインディングには、遅延プロバイダーを使用します
  • プロバイダーに重い処理を記述せず、専用クラスに委譲します

Pest によるテスト

ユニットテスト
test('order total calculates tax correctly', function () {
    $order = Order::factory()->make(['subtotal' => 10000, 'tax_rate' => 0.08]);

    expect($order->total)->toBe(10800);
});
フィーチャーテスト
test('authenticated user can create a post', function () {
    $user = User::factory()->create();

    $response = $this->actingAs($user)
        ->postJson('/api/posts', [
            'title' => 'My Post',
            'body'  => 'Content here.',
        ]);

    $response->assertCreated()
        ->assertJsonPath('data.title', 'My Post');

    $this->assertDatabaseHas('posts', [
        'user_id' => $user->id,
        'title'   => 'My Post',
    ]);
});
キューとイベントのフェイク
test('placing an order dispatches confirmation job', function () {
    Queue::fake();

    $order = Order::factory()->create();
    PlaceOrder::dispatch($order);

    Queue::assertPushed(SendOrderConfirmation::class, function ($job) use ($order) {
        return $job->order->id === $order->id;
    });
});
ブラウザーテスト(Dusk)
test('user can complete checkout flow', function () {
    $this->browse(function (Browser $browser) {
        $browser->loginAs(User::factory()->create())
            ->visit('/cart')
            ->press('Checkout')
            ->waitForText('Order Confirmed')
            ->assertSee('Thank you');
    });
});

Artisan コマンド、マイグレーション、シーダー、ファクトリー

マイグレーションの規約
// Always include down() for rollback capability
public function up(): void
{
    Schema::create('invoices', function (Blueprint $table) {
        $table->id();
        $table->foreignId('user_id')->constrained()->cascadeOnDelete();
        $table->string('number')->unique();
        $table->integer('amount');          // Store money as cents
        $table->string('currency', 3);
        $table->string('status')->default('draft');
        $table->timestamp('due_at')->nullable();
        $table->timestamps();
        $table->softDeletes();

        $table->index(['user_id', 'status']);
    });
}
ファクトリーのパターン
class InvoiceFactory extends Factory
{
    public function definition(): array
    {
        return [
            'user_id'  => User::factory(),
            'number'   => $this->faker->unique()->numerify('INV-####'),
            'amount'   => $this->faker->numberBetween(1000, 100000),
            'currency' => 'USD',
            'status'   => 'draft',
            'due_at'   => now()->addDays(30),
        ];
    }

    public function paid(): static
    {
        return $this->state(fn () => ['status' => 'paid']);
    }

    public function overdue(): static
    {
        return $this->state(fn () => [
            'status' => 'sent',
            'due_at' => now()->subDays(7),
        ]);
    }
}

Laravel のディレクトリー構成の規約

app/
├── Actions/              # Single-purpose action classes
├── Casts/                # Custom Eloquent casts
├── Console/Commands/     # Artisan commands
├── Enums/                # PHP backed enums
├── Events/               # Event classes
├── Exceptions/           # Custom exception classes
├── Http/
│   ├── Controllers/      # Resourceful or single-action controllers
│   ├── Middleware/        # Request/response middleware
│   └── Requests/         # Form Request validation
├── Jobs/                 # Queued job classes
├── Listeners/            # Event listener classes
├── Mail/                 # Mailable classes
├── Models/               # Eloquent models
├── Notifications/        # Notification classes
├── Observers/            # Model observers
├── Policies/             # Authorization policies
├── Providers/            # Service providers
├── Rules/                # Custom validation rules
├── Services/             # Domain service classes
└── View/Components/      # Blade view components
database/
├── factories/            # Model factories
├── migrations/           # Schema migrations (timestamped)
└── seeders/              # Database seeders
resources/views/
├── components/           # Blade components
├── layouts/              # Layout templates
├── livewire/             # Livewire component views
└── mail/                 # Email templates
routes/
├── api.php               # API routes
├── channels.php          # Broadcast channels
├── console.php           # Artisan closures
└── web.php               # Web routes
tests/
├── Feature/              # Feature (integration) tests
├── Unit/                 # Unit tests
└── Browser/              # Dusk browser tests

選択表

認証方式
シナリオ推奨される方法
SPA + 同一ドメインSanctum(Cookie ベース、CSRF)
SPA + 異なるドメインSanctum(トークンベース)
モバイルアプリSanctum(トークンベース)
サードパーティーの API 利用者Passport(OAuth2)
シンプルな API トークンSanctum(プレーンテキストのハッシュ)
ソーシャルログインSocialite + Sanctum
キャッシュ層
データの種類キャッシュドライバーTTL無効化
設定/ルート/ビューFile(artisan cache)次回のデプロイまでartisan optimize:clear
データベースのクエリー結果Redis / Memcached5~60 分イベント駆動または TTL
全ページ/フラグメントRedis1~15 分キャッシュタグ
セッションデータRedisセッションの有効期間自動
レート制限Redisウィンドウの期間自動
ファイルストレージ
シナリオディスクドライバー
ユーザーのアップロード(本番環境)s3Amazon S3/互換サービス
ユーザーのアップロード(ローカル開発環境)localローカルファイルシステム
公開アセットpublicシンボリックリンクを使用したローカル
一時ファイルlocalスケジュールにより整理されるローカル

アンチパターン/よくある間違い

アンチパターン失敗する理由代わりに行うこと
肥大化したコントローラービジネスロジックのテストや保守が困難になりますロジックをアクションまたはサービスクラスに移します
コントローラー内の生 SQLSQL インジェクションのリスクがあり、移植性もありませんEloquent またはクエリビルダーを使用します
マスアサインメント保護の欠如データ改ざんの脆弱性につながります必ず $fillable または $guarded を定義します
コントローラー内のインラインバリデーションバリデーションが HTTP 層に結び付きますフォームリクエストを使用します
再試行/バックオフ設定のないジョブ失敗が通知されず、復旧できません$tries、$backoff、failed() を設定します
グローバルスコープの過剰な使用クエリの挙動が隠れ、開発者を困惑させますローカルスコープを優先します
金額を浮動小数点数で保存する浮動小数点数の精度誤差が発生します整数のセント単位で保存し、表示時に変換します
データベースインデックスの欠如規模が大きくなるとクエリが遅くなりますWHERE と ORDER BY 用の複合インデックスを追加します
設定ファイル内のシークレットバージョン管理で認証情報が漏えいします.env のみを使用します
本番データベースに対するテストデータ破損や不安定なテストにつながりますSQLite のインメモリデータベースまたは専用のテストデータベースを使用します
API レスポンスでの遅延読み込みN+1 クエリが発生し、API レスポンスが遅くなります開発環境で preventLazyLoading() を有効にします

不合理な正当化を防ぐ

  • マイグレーションを省略してデータベースを直接編集してはいけません。マイグレーションが信頼できる唯一の情報源です。
  • 「その方が速いから」といってビジネスロジックをコントローラーに記述してはいけません。アクションクラスを使用してください。
  • 「バリデーションが簡単だから」といってフォームリクエストを省略してはいけません。バリデーションは必ず増えていきます。
  • 「面倒だから」といって preventLazyLoading() を無効にしてはいけません。N+1 クエリを修正してください。
  • 「金額が小さいから」といって金額を浮動小数点数で保存してはいけません。精度誤差は積み重なります。

連携ポイント

スキル連携方法
php-specialist最新の PHP 8.x のパターンが、すべての Laravel コードの基盤となります
laravel-boostAI 支援開発のガイドラインと MCP ツール
senior-backendAPI 設計、キャッシュ戦略、イベント駆動アーキテクチャ
test-driven-developmentRED-GREEN-REFACTOR による Pest テストのワークフロー
database-schema-designマイグレーション計画、インデックス戦略、データモデリング
security-reviewSanctum/Passport の設定、CSRF、入力バリデーション
performance-optimizationクエリのプロファイリング、キャッシュの調整、キューワーカーのスケーリング
deploymentForge/Vapor/Envoyer によるデプロイ、artisan optimize
context7 MCP情報が不確かな場合に、最新の Laravel ドキュメントを取得します
laravel/docs GitHubLaravel API リファレンスの信頼できる情報源

スキルの種類

FLEXIBLE — 作業の範囲に応じて、複数フェーズのプロセスを調整します。モデルを 1 つ変更するだけならフェーズ 2 全体を省略できますが、新しいモジュールでは 5 つすべてのフェーズに従う必要があります。熱心な読み込み、フォームリクエスト、Pest テスト、マイグレーションを優先したスキーマ変更といった中核的な規約は、作業範囲にかかわらず必ず守ってください。

コメント