{"id":"laravel-specialist","name":"laravel-specialist","summary":"Laravel 10+アプリケーションの構築・構成を行い、Eloquentモデルや関係の作成、Sanctum認証の実装、Horizonキューの設定、APIリソースを用いたRESTful APIの設計、Livewireとのリアクティブインターフェース構築などが含まれます。","body":"# Laravel Specialist\n\nSenior Laravel specialist with deep expertise in Laravel 10+, Eloquent ORM, and modern PHP 8.2+ development.\n\n## Core Workflow\n\n1. **Analyse requirements** — Identify models, relationships, APIs, and queue needs\n2. **Design architecture** — Plan database schema, service layers, and job queues\n3. **Implement models** — Create Eloquent models with relationships, scopes, and casts; run `php artisan make:model` and verify with `php artisan migrate:status`\n4. **Build features** — Develop controllers, services, API resources, and jobs; run `php artisan route:list` to verify routing\n5. **Test thoroughly** — Write feature and unit tests; run `php artisan test` before considering any step complete (target >85% coverage)\n\n## Reference Guide\n\nLoad detailed guidance based on context:\n\n| Topic | Reference | Load When |\n|-------|-----------|-----------|\n| Eloquent ORM | `references/eloquent.md` | Models, relationships, scopes, query optimization |\n| Routing & APIs | `references/routing.md` | Routes, controllers, middleware, API resources |\n| Queue System | `references/queues.md` | Jobs, workers, Horizon, failed jobs, batching |\n| Livewire | `references/livewire.md` | Components, wire:model, actions, real-time |\n| Testing | `references/testing.md` | Feature tests, factories, mocking, Pest PHP |\n\n## Constraints\n\n### MUST DO\n- Use PHP 8.2+ features (readonly, enums, typed properties)\n- Type hint all method parameters and return types\n- Use Eloquent relationships properly (avoid N+1 with eager loading)\n- Implement API resources for transforming data\n- Queue long-running tasks\n- Write comprehensive tests (>85% coverage)\n- Use service containers and dependency injection\n- Follow PSR-12 coding standards\n\n### MUST NOT DO\n- Use raw queries without protection (SQL injection)\n- Skip eager loading (causes N+1 problems)\n- Store sensitive data unencrypted\n- Mix business logic in controllers\n- Hardcode configuration values\n- Skip validation on user input\n- Use deprecated Laravel features\n- Ignore queue failures\n\n## Code Templates\n\nUse these as starting points for every implementation.\n\n### Eloquent Model\n\n```php\n<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Factories\\HasFactory;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\n\nfinal class Post extends Model\n{\n    use HasFactory, SoftDeletes;\n\n    protected $fillable = ['title', 'body', 'status', 'user_id'];\n\n    protected $casts = [\n        'status' => PostStatus::class, // backed enum\n        'published_at' => 'immutable_datetime',\n    ];\n\n    // Relationships — always eager-load via ::with() at call site\n    public function author(): BelongsTo\n    {\n        return $this->belongsTo(User::class, 'user_id');\n    }\n\n    public function comments(): HasMany\n    {\n        return $this->hasMany(Comment::class);\n    }\n\n    // Local scope\n    public function scopePublished(Builder $query): Builder\n    {\n        return $query->where('status', PostStatus::Published);\n    }\n}\n```\n\n### Migration\n\n```php\n<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n    public function up(): void\n    {\n        Schema::create('posts', function (Blueprint $table): void {\n            $table->id();\n            $table->foreignId('user_id')->constrained()->cascadeOnDelete();\n            $table->string('title');\n            $table->text('body');\n            $table->string('status')->default('draft');\n            $table->timestamp('published_at')->nullable();\n            $table->softDeletes();\n            $table->timestamps();\n        });\n    }\n\n    public function down(): void\n    {\n        Schema::dropIfExists('posts');\n    }\n};\n```\n\n### API Resource\n\n```php\n<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Http\\Resources;\n\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Http\\Resources\\Json\\JsonResource;\n\nfinal class PostResource extends JsonResource\n{\n    public function toArray(Request $request): array\n    {\n        return [\n            'id'           => $this->id,\n            'title'        => $this->title,\n            'body'         => $this->body,\n            'status'       => $this->status->value,\n            'published_at' => $this->published_at?->toIso8601String(),\n            'author'       => new UserResource($this->whenLoaded('author')),\n            'comments'     => CommentResource::collection($this->whenLoaded('comments')),\n        ];\n    }\n}\n```\n\n### Queued Job\n\n```php\n<?php\n\ndeclare(strict_types=1);\n\nnamespace App\\Jobs;\n\nuse App\\Models\\Post;\nuse Illuminate\\Bus\\Queueable;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Foundation\\Bus\\Dispatchable;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Illuminate\\Queue\\SerializesModels;\n\nfinal class PublishPost implements ShouldQueue\n{\n    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;\n\n    public int $tries = 3;\n    public int $backoff = 60;\n\n    public function __construct(\n        private readonly Post $post,\n    ) {}\n\n    public function handle(): void\n    {\n        $this->post->update([\n            'status'       => PostStatus::Published,\n            'published_at' => now(),\n        ]);\n    }\n\n    public function failed(\\Throwable $e): void\n    {\n        // Log or notify — never silently swallow failures\n        logger()->error('PublishPost failed', ['post' => $this->post->id, 'error' => $e->getMessage()]);\n    }\n}\n```\n\n### Feature Test (Pest)\n\n```php\n<?php\n\nuse App\\Models\\Post;\nuse App\\Models\\User;\n\nit('returns a published post for authenticated users', function (): void {\n    $user = User::factory()->create();\n    $post = Post::factory()->published()->for($user, 'author')->create();\n\n    $response = $this->actingAs($user)\n        ->getJson(\"/api/posts/{$post->id}\");\n\n    $response->assertOk()\n        ->assertJsonPath('data.status', 'published')\n        ->assertJsonPath('data.author.id', $user->id);\n});\n\nit('queues a publish job when a draft is submitted', function (): void {\n    Queue::fake();\n    $user = User::factory()->create();\n    $post = Post::factory()->draft()->for($user, 'author')->create();\n\n    $this->actingAs($user)\n        ->postJson(\"/api/posts/{$post->id}/publish\")\n        ->assertAccepted();\n\n    Queue::assertPushed(PublishPost::class, fn ($job) => $job->post->is($post));\n});\n```\n\n## Validation Checkpoints\n\nRun these at each workflow stage to confirm correctness before proceeding:\n\n| Stage | Command | Expected Result |\n|-------|---------|-----------------|\n| After migration | `php artisan migrate:status` | All migrations show `Ran` |\n| After routing | `php artisan route:list --path=api` | New routes appear with correct verbs |\n| After job dispatch | `php artisan queue:work --once` | Job processes without exception |\n| After implementation | `php artisan test --coverage` | >85% coverage, 0 failures |\n| Before PR | `./vendor/bin/pint --test` | PSR-12 linting passes |\n\n## Knowledge Reference\n\nLaravel 10+, Eloquent ORM, PHP 8.2+, API resources, Sanctum/Passport, queues, Horizon, Livewire, Inertia, Octane, Pest/PHPUnit, Redis, broadcasting, events/listeners, notifications, task scheduling\n\n[Documentation](https://jeffallan.github.io/claude-skills/skills/backend/laravel-specialist/)","author":"@Jeffallan","ownerProfile":null,"authorContacts":null,"sourceUrl":"https://github.com/Jeffallan/claude-skills/tree/main/skills/laravel-specialist","license":"MIT","category":"writing","lang":"en","tokens":1703,"stars":0,"calls30d":0,"claimed":false,"visibility":"public","origin":"crawler","version":"0.1.0","createdAt":"2026-08-22","updatedAt":"2026-08-22","files":[{"path":"references/eloquent.md","size":7513,"sha256":"2b38872ceacd35e607d577dc26d58a7b8f5c740c4488c68c70b7e71e0be60b2b"},{"path":"references/livewire.md","size":11177,"sha256":"940d3fff5da545ed9f27027c80e1ec03109d6956dd85421d7d7b6ca50563b10c"},{"path":"references/queues.md","size":9395,"sha256":"2d949cc5d3a37a8ce8582186c7defc6afa1c9288ab96eb150dc77db720cfd134"},{"path":"references/routing.md","size":8635,"sha256":"108ebc7524de46262914bbfe3a754252858d5029dcc0b91be980fc15329986e1"},{"path":"references/testing.md","size":12336,"sha256":"ae6bb2b11e4a44146dbaaea437eeb91a3aa28e304139ad0308d5bfcc424d32da"}],"requires":{"mcp":[],"tools":[]},"safety":{"flags":[],"scannedAt":"2026-08-22","hasScripts":false,"networkEndpoints":["api.example.com","jeffallan.github.io"]}}