laravel-specialist

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Laravel Specialist

Laravel 专家指南

Overview

概述

Design, build, and maintain production-grade Laravel applications following the framework's conventions and best practices. This skill covers the full Laravel ecosystem: Eloquent ORM with advanced relationship patterns, Blade templating and Livewire interactivity, queue and event systems, middleware pipelines, service providers, Pest testing at every layer, and Artisan tooling for migrations, seeders, and factories.
Apply this skill whenever Laravel is the application framework, whether greenfield or brownfield.
遵循框架约定和最佳实践,设计、构建并维护生产级Laravel应用。本技能覆盖完整的Laravel生态:支持高级关系模式的Eloquent ORM、Blade模板与Livewire交互能力、队列与事件系统、中间件管道、服务提供者、全层级Pest测试,以及用于迁移、数据填充、工厂类的Artisan工具。
无论新项目还是存量项目,只要使用Laravel作为应用框架都可应用本技能。

Multi-Phase Process

多阶段流程

Phase 1: Context Discovery

阶段1:上下文梳理

  1. Identify Laravel version (
    composer.json
    ->
    laravel/framework
    )
  2. Scan
    config/
    for enabled packages and custom configuration
  3. Map existing models, relationships, and migration history
  4. Review
    routes/
    for API, web, console, and channel definitions
  5. Catalog installed first-party packages (Sanctum, Horizon, Telescope, Pulse, Pennant, Scout, Cashier)
  6. Check for Livewire, Inertia, or Blade-only frontend stack
STOP — Do NOT begin architecture review without knowing the Laravel version and installed packages.
  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版本和已安装包之前,请勿开始架构评审。

Documentation Verification Protocol

文档校验规则

[HARD-GATE] When uncertain about any Laravel API — verify, don't guess. Use
mcp__context7__resolve-library-id
then
mcp__context7__query-docs
(preferred). Fallback: fetch from
https://github.com/laravel/docs
. For Livewire, Pest, Inertia — resolve each via context7 separately. Returned docs override memorized knowledge.
[强制校验] 当对任意Laravel API存在疑问时,一定要校验不要猜测。优先使用
mcp__context7__resolve-library-id
然后调用
mcp__context7__query-docs
查询文档,备选方案是从
https://github.com/laravel/docs
获取文档。对于Livewire、Pest、Inertia,需要分别通过context7查询。返回的文档优先级高于记忆中的知识。

Phase 2: Architecture Review

阶段2:架构评审

  1. Verify directory structure follows Laravel conventions (see section below)
  2. Assess service provider registrations and deferred loading
  3. Review middleware stack ordering and grouping
  4. Evaluate queue connection configuration and worker topology
  5. Check caching strategy (config, route, view, application-level)
STOP — Do NOT begin implementation until architecture gaps are documented.
  1. 确认目录结构符合Laravel约定(参考后续章节)
  2. 评估服务提供者注册和延迟加载逻辑
  3. 检查中间件栈的顺序和分组配置
  4. 评估队列连接配置和worker拓扑结构
  5. 检查缓存策略(配置、路由、视图、应用级缓存)
注意 — 架构差距未记录完成前,请勿开始开发实现。

Phase 3: Implementation

阶段3:开发实现

  1. Write migrations first — schema is the source of truth
  2. Build Eloquent models with relationships, scopes, casts, and accessors
  3. Implement business logic in dedicated Action or Service classes
  4. Create controllers (single-action or resourceful) bound to routes
  5. Add Form Requests for validation, Policies for authorization
  6. Wire events, listeners, and jobs for asynchronous workflows
STOP — Do NOT skip Form Requests and Policies. Inline validation and authorization are anti-patterns.
  1. 优先编写迁移文件:数据库 schema 是唯一数据基准
  2. 构建Eloquent模型,包含关联关系、查询作用域、类型转换和访问器
  3. 在专门的Action或Service类中实现业务逻辑
  4. 创建绑定到路由的控制器(单动作或资源型控制器)
  5. 新增表单请求做验证,策略类做权限控制
  6. 关联事件、监听器和任务实现异步工作流
注意 — 请勿跳过表单请求和策略类编写,内联验证和权限控制是反模式。

Phase 4: Testing

阶段4:测试

  1. Unit tests for isolated logic (Actions, Value Objects, Casts)
  2. Feature tests for HTTP endpoints and middleware behavior
  3. Browser tests with Laravel Dusk for critical user flows
  4. Database assertions with
    assertDatabaseHas
    ,
    assertSoftDeleted
  5. Queue and event fakes for side-effect verification
STOP — Do NOT proceed to optimization without passing tests at all layers.
  1. 为隔离逻辑编写单元测试(Action、值对象、类型转换)
  2. 为HTTP接口和中间件行为编写功能测试
  3. 用Laravel Dusk为核心用户流程编写浏览器测试
  4. 使用
    assertDatabaseHas
    assertSoftDeleted
    做数据库断言
  5. 使用队列和事件伪造验证副作用逻辑
注意 — 所有层级测试未通过前,请勿进入优化阶段。

Phase 5: Optimization

阶段5:性能优化

  1. Apply eager loading to eliminate N+1 queries
  2. Cache expensive computations and config/route/view
  3. Index frequently-queried columns; use
    EXPLAIN
    to verify
  4. Profile with Telescope or Debugbar in development
  5. Configure Horizon for production queue monitoring
  1. 应用预加载消除N+1查询问题
  2. 缓存耗时计算结果、配置/路由/视图编译结果
  3. 为高频查询字段加索引,使用
    EXPLAIN
    校验索引生效情况
  4. 开发环境用Telescope或Debugbar做性能分析
  5. 生产环境配置Horizon做队列监控

Eloquent Patterns

Eloquent 设计模式

Relationships

关联关系

RelationshipMethodInverseUse Case
One-to-One
hasOne
belongsTo
User -> Profile
One-to-Many
hasMany
belongsTo
Post -> Comments
Many-to-Many
belongsToMany
belongsToMany
User <-> Roles (pivot)
Has-Many-Through
hasManyThrough
Country -> Posts (through Users)
Polymorphic
morphMany
/
morphTo
morphTo
Comments on Posts and Videos
Many-to-Many Polymorphic
morphToMany
morphedByMany
Tags on Posts and Videos
关系类型方法名反向关联适用场景
一对一
hasOne
belongsTo
用户 -> 用户资料
一对多
hasMany
belongsTo
文章 -> 评论
多对多
belongsToMany
belongsToMany
用户 <-> 角色(中间表)
远程一对多
hasManyThrough
国家 -> 文章(通过用户关联)
多态关联
morphMany
/
morphTo
morphTo
同时关联文章和视频的评论
多态多对多
morphToMany
morphedByMany
同时关联文章和视频的标签

Scopes

查询作用域

php
// 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');
    });
}
php
// 本地作用域 — 可复用的查询约束
public function scopeActive(Builder $query): Builder
{
    return $query->where('status', 'active');
}

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

// 全局作用域 — 模型的所有查询都会自动应用
protected static function booted(): void
{
    static::addGlobalScope('published', function (Builder $builder) {
        $builder->whereNotNull('published_at');
    });
}

Accessors, Mutators, and Casts

访问器、修改器和类型转换

php
// 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,
    ];
}
php
// 属性访问器/修改器(Laravel 11+ 语法)
protected function fullName(): Attribute
{
    return Attribute::make(
        get: fn () => "{$this->first_name} {$this->last_name}",
    );
}

// 自定义类型转换
protected function casts(): array
{
    return [
        'options'    => AsCollection::class,
        'address'    => AddressCast::class,
        'status'     => OrderStatus::class,  // 枚举类型
        'metadata'   => 'array',
        'is_active'  => 'boolean',
        'amount'     => MoneyCast::class,
    ];
}

Query Optimization with Eager Loading

预加载查询优化

php
// 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());
php
// 反面案例 — N+1问题:1次查询查文章 + N次查询查作者
$posts = Post::all();
foreach ($posts as $post) {
    echo $post->author->name;  // 每次循环都会触发懒加载
}

// 正确写法 — 预加载:总共仅2次查询
$posts = Post::with('author')->get();

// 嵌套预加载
$posts = Post::with(['author', 'comments.user'])->get();

// 带条件的预加载
$posts = Post::with(['comments' => function ($query) {
    $query->where('approved', true)->latest()->limit(5);
}])->get();

// 开发环境禁用懒加载
Model::preventLazyLoading(! app()->isProduction());

Blade Templates and Livewire Components

Blade 模板与 Livewire 组件

Blade Conventions

Blade 开发约定

  • Layouts:
    resources/views/layouts/app.blade.php
    using
    @yield
    /
    @section
    or component-based
    <x-app-layout>
  • Components:
    resources/views/components/
    — anonymous or class-based
  • Partials:
    @include('partials.sidebar')
    for reusable fragments
  • Use
    {{ }}
    for escaped output,
    {!! !!}
    only when HTML is explicitly trusted
  • Prefer Blade directives (
    @auth
    ,
    @can
    ,
    @env
    ) over raw PHP conditionals
  • 布局文件:
    resources/views/layouts/app.blade.php
    可使用
    @yield
    /
    @section
    或组件式写法
    <x-app-layout>
  • 组件文件:存放在
    resources/views/components/
    ,支持匿名组件或类组件
  • 局部模板:使用
    @include('partials.sidebar')
    引入可复用片段
  • 输出内容使用
    {{ }}
    做自动转义,仅当明确信任HTML内容时才使用
    {!! !!}
  • 优先使用Blade指令(
    @auth
    @can
    @env
    )而非原生PHP条件语句

Livewire Patterns

Livewire 设计模式

php
// 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');
    }
}
php
// 全页面Livewire组件(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');
    }
}

Frontend Stack Decision Table

前端技术栈选型表

DecisionChoose LivewireChoose Inertia
Existing Blade codebaseYesNo
SPA-like experience requiredPartial (with wire:navigate)Yes
Team has Vue/React expertiseNoYes
Server-side rendering priorityYesDepends on adapter
Real-time reactivityYes (polling, streams)Requires Echo setup
SEO-critical pagesEither worksEither works (SSR adapter)
选型维度选择Livewire选择Inertia
现有Blade代码栈
需要类SPA的交互体验部分支持(配合wire:navigate)
团队具备Vue/React开发能力
服务端渲染优先级高取决于适配器
需要实时响应能力是(轮询、流式推送)需要额外配置Echo
SEO高优先级页面两者均可两者均可(使用SSR适配器)

Queue, Job, and Event Patterns

队列、任务和事件模式

Job Design

任务设计规范

php
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
    }
}
php
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
    {
        // 通知管理员,上报到错误追踪系统
    }
}

Event / Listener Pattern

事件/监听器模式

php
// 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));
    }
}
php
// 触发事件
OrderPlaced::dispatch($order);

// 异步监听器
class SendOrderConfirmation implements ShouldQueue
{
    public function handle(OrderPlaced $event): void
    {
        Mail::to($event->order->user)->send(new OrderConfirmationMail($event->order));
    }
}

Sync vs Async Decision Table

同步/异步选型表

TaskQueuedSynchronous
Sending emails / notificationsYesNever in request cycle
PDF generationYesOnly if < 2s and user waits
Payment processingDepends — webhook-driven preferredIf gateway responds < 5s
Cache warmingYesNever
Audit loggingYes (high-volume) or Sync (low-volume)If guaranteed delivery needed
Search indexingYesNever
任务类型异步队列同步执行
发送邮件/通知禁止在请求周期内同步执行
PDF生成仅当生成耗时<2s且用户需要等待时使用
支付处理优先使用webhook驱动的异步方案仅当网关响应<5s时可同步
缓存预热禁止同步执行
审计日志高并发场景用异步,低并发场景可同步需要保证投递可靠性时用同步
搜索索引更新禁止同步执行

Middleware and Service Providers

中间件与服务提供者

Middleware Stack Ordering

中间件栈顺序配置

Middleware order matters. The default stack in
bootstrap/app.php
(Laravel 11+):
php
->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,
    ]);
})
中间件顺序会影响执行逻辑,Laravel 11+的默认栈配置在
bootstrap/app.php
中:
php
->withMiddleware(function (Middleware $middleware) {
    $middleware->web(append: [
        HandleInertiaRequests::class,  // 会话之后,响应生成之前执行
    ]);

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

    $middleware->alias([
        'role'     => EnsureUserHasRole::class,
        'verified' => EnsureEmailIsVerified::class,
    ]);
})

Service Provider Best Practices

服务提供者最佳实践

  • Register bindings in
    register()
    , never resolve from the container there
  • Boot logic (event listeners, route model binding, macros) goes in
    boot()
  • Use deferred providers for bindings that are not needed on every request
  • Avoid heavy logic in providers — delegate to dedicated classes
  • 绑定逻辑放在
    register()
    方法中,不要在此方法中从容器解析实例
  • 启动逻辑(事件监听器、路由模型绑定、宏定义)放在
    boot()
    方法中
  • 非每次请求都需要的绑定使用延迟服务提供者
  • 避免在服务提供者中编写复杂逻辑,委托给专门的类实现

Testing with Pest

使用Pest进行测试

Unit Test

单元测试

php
test('order total calculates tax correctly', function () {
    $order = Order::factory()->make(['subtotal' => 10000, 'tax_rate' => 0.08]);

    expect($order->total)->toBe(10800);
});
php
test('order total calculates tax correctly', function () {
    $order = Order::factory()->make(['subtotal' => 10000, 'tax_rate' => 0.08]);

    expect($order->total)->toBe(10800);
});

Feature Test

功能测试

php
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',
    ]);
});
php
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',
    ]);
});

Queue and Event Fakes

队列与事件伪造测试

php
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;
    });
});
php
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;
    });
});

Browser Test (Dusk)

浏览器测试(Dusk)

php
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');
    });
});
php
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 Commands, Migrations, Seeders, Factories

Artisan命令、迁移、数据填充、工厂类

Migration Conventions

迁移开发约定

php
// 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']);
    });
}
php
// 必须编写down()方法支持回滚
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');          // 金额以分为单位存储
        $table->string('currency', 3);
        $table->string('status')->default('draft');
        $table->timestamp('due_at')->nullable();
        $table->timestamps();
        $table->softDeletes();

        $table->index(['user_id', 'status']);
    });
}

Factory Patterns

工厂类设计模式

php
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),
        ]);
    }
}
php
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 Directory Structure Conventions

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
app/
├── Actions/              # 单用途Action类
├── Casts/                # 自定义Eloquent类型转换类
├── Console/Commands/     # Artisan命令类
├── Enums/                # PHP枚举类
├── Events/               # 事件类
├── Exceptions/           # 自定义异常类
├── Http/
│   ├── Controllers/      # 资源型或单动作控制器
│   ├── Middleware/        # 请求/响应中间件
│   └── Requests/         # 表单请求验证类
├── Jobs/                 # 队列任务类
├── Listeners/            # 事件监听器类
├── Mail/                 # 邮件类
├── Models/               # Eloquent模型类
├── Notifications/        # 通知类
├── Observers/            # 模型观察者类
├── Policies/             # 授权策略类
├── Providers/            # 服务提供者类
├── Rules/                # 自定义验证规则类
├── Services/             # 领域服务类
└── View/Components/      # Blade视图组件类
database/
├── factories/            # 模型工厂类
├── migrations/           # 带时间戳的schema迁移文件
└── seeders/              # 数据库填充类
resources/views/
├── components/           # Blade组件
├── layouts/              # 布局模板
├── livewire/             # Livewire组件视图
└── mail/                 # 邮件模板
routes/
├── api.php               # API路由
├── channels.php          # 广播通道
├── console.php           # Artisan闭包命令
└── web.php               # Web路由
tests/
├── Feature/              # 功能(集成)测试
├── Unit/                 # 单元测试
└── Browser/              # Dusk浏览器测试

Decision Tables

选型表

Authentication Strategy

认证方案选型

ScenarioRecommended Approach
SPA + same domainSanctum (cookie-based, CSRF)
SPA + different domainSanctum (token-based)
Mobile appSanctum (token-based)
Third-party API consumersPassport (OAuth2)
Simple API tokensSanctum (plaintext hash)
Social loginSocialite + Sanctum
场景推荐方案
同域SPASanctum(基于Cookie,CSRF防护)
跨域SPASanctum(基于Token)
移动端应用Sanctum(基于Token)
第三方API消费者Passport(OAuth2)
简单API令牌验证Sanctum(明文哈希)
社交登录Socialite + Sanctum

Caching Layer

缓存层选型

Data TypeCache DriverTTLInvalidation
Config / routes / viewsFile (artisan cache)Until next deploy
artisan optimize:clear
Database query resultsRedis / Memcached5-60 minEvent-driven or TTL
Full-page / fragmentRedis1-15 minCache tags
Session dataRedisSession lifetimeAutomatic
Rate limitingRedisWindow durationAutomatic
数据类型缓存驱动过期时间失效策略
配置/路由/视图编译文件(artisan cache)到下次部署前
artisan optimize:clear
数据库查询结果Redis / Memcached5-60分钟事件驱动或自动过期
整页/页面片段缓存Redis1-15分钟缓存标签
会话数据Redis会话生命周期自动失效
限流数据Redis限流窗口时长自动失效

File Storage

文件存储选型

ScenarioDiskDriver
User uploads (production)
s3
Amazon S3 / compatible
User uploads (local dev)
local
Local filesystem
Public assets
public
Local with symlink
Temporary files
local
Local, pruned by schedule
场景磁盘名驱动
生产环境用户上传
s3
Amazon S3 / 兼容S3的存储服务
本地开发用户上传
local
本地文件系统
公开静态资源
public
带软链的本地存储
临时文件
local
本地存储,通过定时任务清理

Anti-Patterns / Common Mistakes

反模式/常见错误

Anti-PatternWhy It FailsWhat To Do Instead
Fat controllersUntestable, unmaintainable business logicMove logic to Action or Service classes
Raw SQL in controllersSQL injection risk, not portableUse Eloquent or Query Builder
Missing mass-assignment protectionData manipulation vulnerabilitiesAlways define
$fillable
or
$guarded
Inline validation in controllersCouples validation to HTTP layerUse Form Requests
Jobs without retry/backoff configSilent failures, no recoveryConfigure
$tries
,
$backoff
,
failed()
Over-using global scopesHidden query behavior surprises developersPrefer local scopes
Storing money as floatsFloating-point precision errorsUse integer cents, convert at presentation
Missing database indexesSlow queries at scaleAdd composite indexes for WHERE + ORDER BY
Secrets in config filesCredential leaks in version controlUse
.env
exclusively
Testing against production DBData corruption, unreliable testsUse SQLite in-memory or dedicated test DB
Lazy loading in API responsesN+1 queries, slow API responsesEnable
preventLazyLoading()
in dev
反模式问题所在正确做法
胖控制器业务逻辑不可测试、难以维护将逻辑迁移到Action或Service类
控制器中写原生SQL存在SQL注入风险,兼容性差使用Eloquent或查询构造器
缺失批量赋值保护存在数据篡改漏洞始终定义
$fillable
$guarded
控制器中内联验证验证逻辑与HTTP层耦合使用表单请求验证
任务未配置重试/退避策略静默失败,无恢复能力配置
$tries
$backoff
failed()
方法
过度使用全局作用域隐藏查询逻辑,给开发带来意料之外的问题优先使用本地作用域
金额用浮点数存储存在浮点精度误差用整数存储单位为分的金额,展示层再转换
缺失数据库索引规模扩大后查询变慢为WHERE和ORDER BY的组合字段添加联合索引
配置文件中写密钥版本控制泄露凭证仅通过
.env
文件存储敏感信息
针对生产库进行测试数据损坏,测试结果不可靠使用SQLite内存库或专用测试库
API响应中使用懒加载出现N+1查询,API响应变慢开发环境开启
preventLazyLoading()

Anti-Rationalization Guards

禁止规避规则

  • Do NOT skip migrations and edit the database directly -- migrations are the source of truth.
  • Do NOT put business logic in controllers because "it's faster" -- use Action classes.
  • Do NOT skip Form Requests because "the validation is simple" -- it always grows.
  • Do NOT disable
    preventLazyLoading()
    because "it's annoying" -- fix the N+1 queries.
  • Do NOT store money as floats because "the amounts are small" -- precision errors compound.
  • 请勿跳过迁移直接修改数据库 —— 迁移是唯一的schema基准
  • 请勿为了「开发更快」把业务逻辑写在控制器中 —— 使用Action类
  • 请勿因为「验证逻辑简单」跳过表单请求编写 —— 逻辑总会迭代变复杂
  • 请勿因为「太麻烦」关闭
    preventLazyLoading()
    —— 修复N+1查询问题
  • 请勿因为「金额很小」用浮点数存储金额 —— 精度误差会累积

Integration Points

关联技能

SkillHow It Connects
php-specialist
Modern PHP 8.x patterns underpin all Laravel code
laravel-boost
AI-assisted development guidelines and MCP tooling
senior-backend
API design, caching strategies, event-driven architecture
test-driven-development
Pest testing workflow with RED-GREEN-REFACTOR
database-schema-design
Migration planning, indexing strategy, data modeling
security-review
Sanctum/Passport configuration, CSRF, input validation
performance-optimization
Query profiling, cache tuning, queue worker scaling
deployment
Forge/Vapor/Envoyer deployment,
artisan optimize
context7 MCP
Fetches up-to-date Laravel docs when information is uncertain
laravel/docs
GitHub
Authoritative source for Laravel API reference
技能关联关系
php-specialist
现代PHP 8.x语法是所有Laravel代码的基础
laravel-boost
AI辅助开发指南和MCP工具
senior-backend
API设计、缓存策略、事件驱动架构
test-driven-development
基于Pest的红-绿-重构测试工作流
database-schema-design
迁移规划、索引策略、数据建模
security-review
Sanctum/Passport配置、CSRF防护、输入验证
performance-optimization
查询分析、缓存调优、队列worker扩容
deployment
Forge/Vapor/Envoyer部署、
artisan optimize
配置
context7 MCP
信息不确定时获取最新Laravel文档
laravel/docs
GitHub
Laravel API参考的权威来源

Skill Type

技能类型

FLEXIBLE — Adapt the multi-phase process to the scope of work. A single model change may skip Phase 2 entirely, while a new module should follow all five phases. Core conventions (eager loading, Form Requests, Pest tests, migration-first schema changes) are non-negotiable regardless of scope.
灵活适配 —— 可根据工作范围调整多阶段流程。单个模型修改可以直接跳过阶段2,而新模块开发应该遵循完整的五个阶段。核心约定(预加载、表单请求、Pest测试、迁移优先的schema变更)无论项目规模大小都是必须遵守的。