Agent Skills by ALSEL
Anthropic Claudeソフトウェア開発⭐ リポ 0品質スコア 50/100

laravel-patterns

Laravelのアーキテクチャパターン、ルーティング/コントローラー、Eloquent ORM、サービスレイヤー、キュー、イベント、キャッシュ、APIリソースなど、本番アプリ構築に必要な設計・実装スキルを提供します。

description の原文を見る

Laravel architecture patterns, routing/controllers, Eloquent ORM, service layers, queues, events, caching, and API resources for production apps.

SKILL.md 本文

Laravel 開発パターン

スケーラブルで保守性の高いアプリケーションのための本番レベルの Laravel アーキテクチャパターン。

いつ使うか

  • Laravel ウェブアプリケーションまたは API を構築する
  • Controller、サービス、ドメインロジックを構成する
  • Eloquent モデルとリレーションシップを扱う
  • リソースとページネーションで API を設計する
  • キュー、イベント、キャッシング、バックグラウンドジョブを追加する

どのように機能するか

  • 明確な境界を中心にアプリケーションを構成する(Controller → サービス/Action → モデル)
  • ルーティングを予測可能に保つために明示的バインディングと scope バインディングを使用する。アクセス制御のために認可は引き続き適用する
  • ドメインロジックの一貫性のため、型付きモデル、キャスト、スコープを優先する
  • IO が重い処理はキュー内に保管し、コストの高い読み取りはキャッシュする
  • config/* で設定を一元化し、環境を明確に分離する

プロジェクト構造

明確なレイヤー境界(HTTP、サービス/Action、モデル)を持つ従来の Laravel レイアウトを使用する。

推奨レイアウト

app/
├── Actions/            # 単一目的のユースケース
├── Console/
├── Events/
├── Exceptions/
├── Http/
│   ├── Controllers/
│   ├── Middleware/
│   ├── Requests/       # フォームリクエストバリデーション
│   └── Resources/      # API リソース
├── Jobs/
├── Models/
├── Policies/
├── Providers/
├── Services/           # ドメインサービスをコーディネート
└── Support/
config/
database/
├── factories/
├── migrations/
└── seeders/
resources/
├── views/
└── lang/
routes/
├── api.php
├── web.php
└── console.php

Controllers → Services → Actions

Controller は薄く保つ。オーケストレーションはサービスに、単一目的のロジックは Action に配置する。

final class CreateOrderAction
{
    public function __construct(private OrderRepository $orders) {}

    public function handle(CreateOrderData $data): Order
    {
        return $this->orders->create($data);
    }
}

final class OrdersController extends Controller
{
    public function __construct(private CreateOrderAction $createOrder) {}

    public function store(StoreOrderRequest $request): JsonResponse
    {
        $order = $this->createOrder->handle($request->toDto());

        return response()->json([
            'success' => true,
            'data' => OrderResource::make($order),
            'error' => null,
            'meta' => null,
        ], 201);
    }
}

ルーティングと Controller

明確性のため、route-model バインディングとリソース controller を優先する。

use Illuminate\Support\Facades\Route;

Route::middleware('auth:sanctum')->group(function () {
    Route::apiResource('projects', ProjectController::class);
});

Route Model Binding(スコープ済み)

クロステナントアクセスを防ぐため、scope バインディングを使用する。

Route::scopeBindings()->group(function () {
    Route::get('/accounts/{account}/projects/{project}', [ProjectController::class, 'show']);
});

ネストされたルートとバインディング名

  • ダブルネストを避けるため、prefix と path を一貫性のあるものに保つ(例:conversation vs conversations
  • バインドされたモデルに一致する単一のパラメータ名を使用する(例:Conversation には {conversation}
  • ネスト時に親子関係を強制するため、scope バインディングを優先する
use App\Http\Controllers\Api\ConversationController;
use App\Http\Controllers\Api\MessageController;
use Illuminate\Support\Facades\Route;

Route::middleware('auth:sanctum')->prefix('conversations')->group(function () {
    Route::post('/', [ConversationController::class, 'store'])->name('conversations.store');

    Route::scopeBindings()->group(function () {
        Route::get('/{conversation}', [ConversationController::class, 'show'])
            ->name('conversations.show');

        Route::post('/{conversation}/messages', [MessageController::class, 'store'])
            ->name('conversation-messages.store');

        Route::get('/{conversation}/messages/{message}', [MessageController::class, 'show'])
            ->name('conversation-messages.show');
    });
});

パラメータを異なるモデルクラスに解決させたい場合は、明示的バインディングを定義する。カスタムバインディングロジックには Route::bind() を使用するか、モデルで resolveRouteBinding() を実装する。

use App\Models\AiConversation;
use Illuminate\Support\Facades\Route;

Route::model('conversation', AiConversation::class);

Service Container バインディング

明確な依存性の解決のため、service provider でインターフェースを実装に バインドする。

use App\Repositories\EloquentOrderRepository;
use App\Repositories\OrderRepository;
use Illuminate\Support\ServiceProvider;

final class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->bind(OrderRepository::class, EloquentOrderRepository::class);
    }
}

Eloquent モデルパターン

モデル構成

final class Project extends Model
{
    use HasFactory;

    protected $fillable = ['name', 'owner_id', 'status'];

    protected $casts = [
        'status' => ProjectStatus::class,
        'archived_at' => 'datetime',
    ];

    public function owner(): BelongsTo
    {
        return $this->belongsTo(User::class, 'owner_id');
    }

    public function scopeActive(Builder $query): Builder
    {
        return $query->whereNull('archived_at');
    }
}

カスタムキャストと Value Object

厳密な型付けのため、enum または value object を使用する。

use Illuminate\Database\Eloquent\Casts\Attribute;

protected $casts = [
    'status' => ProjectStatus::class,
];
protected function budgetCents(): Attribute
{
    return Attribute::make(
        get: fn (int $value) => Money::fromCents($value),
        set: fn (Money $money) => $money->toCents(),
    );
}

N+1 を防ぐための Eager Loading

$orders = Order::query()
    ->with(['customer', 'items.product'])
    ->latest()
    ->paginate(25);

複雑なフィルタのための Query Object

final class ProjectQuery
{
    public function __construct(private Builder $query) {}

    public function ownedBy(int $userId): self
    {
        $query = clone $this->query;

        return new self($query->where('owner_id', $userId));
    }

    public function active(): self
    {
        $query = clone $this->query;

        return new self($query->whereNull('archived_at'));
    }

    public function builder(): Builder
    {
        return $this->query;
    }
}

グローバルスコープと Soft Delete

デフォルトフィルタリングにはグローバルスコープを、復旧可能なレコードには SoftDeletes を使用する。 階層化された動作を望まない場合は、同じフィルタに対してグローバルスコープまたは named scope どちらか一方を使用し、両方同時には使用しない。

use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Builder;

final class Project extends Model
{
    use SoftDeletes;

    protected static function booted(): void
    {
        static::addGlobalScope('active', function (Builder $builder): void {
            $builder->whereNull('archived_at');
        });
    }
}

再利用可能なフィルタのための Query スコープ

use Illuminate\Database\Eloquent\Builder;

final class Project extends Model
{
    public function scopeOwnedBy(Builder $query, int $userId): Builder
    {
        return $query->where('owner_id', $userId);
    }
}

// サービス、リポジトリなど内で
$projects = Project::ownedBy($user->id)->get();

複数ステップの更新のためのトランザクション

use Illuminate\Support\Facades\DB;

DB::transaction(function (): void {
    $order->update(['status' => 'paid']);
    $order->items()->update(['paid_at' => now()]);
});

マイグレーション

ネーミング規則

  • ファイル名はタイムスタンプを使用:YYYY_MM_DD_HHMMSS_create_users_table.php
  • マイグレーションは匿名クラスを使用(命名クラスではない)。ファイル名が目的を伝える
  • テーブル名はデフォルトで snake_case で複数形

マイグレーション例

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('orders', function (Blueprint $table): void {
            $table->id();
            $table->foreignId('customer_id')->constrained()->cascadeOnDelete();
            $table->string('status', 32)->index();
            $table->unsignedInteger('total_cents');
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('orders');
    }
};

Form Request とバリデーション

バリデーションを form request 内に保ち、入力を DTO に変換する。

use App\Models\Order;

final class StoreOrderRequest extends FormRequest
{
    public function authorize(): bool
    {
        return $this->user()?->can('create', Order::class) ?? false;
    }

    public function rules(): array
    {
        return [
            'customer_id' => ['required', 'integer', 'exists:customers,id'],
            'items' => ['required', 'array', 'min:1'],
            'items.*.sku' => ['required', 'string'],
            'items.*.quantity' => ['required', 'integer', 'min:1'],
        ];
    }

    public function toDto(): CreateOrderData
    {
        return new CreateOrderData(
            customerId: (int) $this->validated('customer_id'),
            items: $this->validated('items'),
        );
    }
}

API リソース

リソースとページネーションで API レスポンスの一貫性を保つ。

$projects = Project::query()->active()->paginate(25);

return response()->json([
    'success' => true,
    'data' => ProjectResource::collection($projects->items()),
    'error' => null,
    'meta' => [
        'page' => $projects->currentPage(),
        'per_page' => $projects->perPage(),
        'total' => $projects->total(),
    ],
]);

イベント、ジョブ、キュー

  • 副作用のためにドメインイベントを発行する(メール、分析)
  • 遅い処理にはキュー入りジョブを使用する(レポート、エクスポート、webhook)
  • リトライとバックオフで冪等ハンドラを優先する

キャッシング

  • 読み取りが多いエンドポイントと高コストなクエリをキャッシュする
  • モデルイベント(created/updated/deleted)でキャッシュを無効化する
  • 簡単な無効化のため、関連データをキャッシュする際にタグを使用する

設定と環境

  • 機密情報を .env に、設定を config/*.php に保つ
  • 環境固有の設定オーバーライドを使用し、本番環境では config:cache を使用する

ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ

詳細情報

作者
affaan-m
リポジトリ
affaan-m/everything-claude-code
ライセンス
MIT
最終更新
不明

Source: https://github.com/affaan-m/everything-claude-code / ライセンス: MIT

関連スキル

汎用ソフトウェア開発⭐ リポ 39,967

doubt-driven-development

重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 1,175

apprun-skills

TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。

by yysun
OpenAIソフトウェア開発⭐ リポ 797

desloppify

コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。

by Git-on-my-level
汎用ソフトウェア開発⭐ リポ 39,967

debugging-and-error-recovery

テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 39,967

test-driven-development

テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 39,967

incremental-implementation

変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。

by addyosmani
本サイトは GitHub 上で公開されているオープンソースの SKILL.md ファイルをクロール・インデックス化したものです。 各スキルの著作権は原作者に帰属します。掲載に問題がある場合は info@alsel.co.jp または /takedown フォームよりご連絡ください。
原作者: affaan-m · affaan-m/everything-claude-code · ライセンス: MIT