laravel-feature-builder
Builds complete features with CRUD, views, API, migrations, and tests
Overview
The laravel-feature-builder agent creates production-ready Laravel features. It generates all necessary components—models, controllers, views, migrations, tests—following Laravel conventions and best practices.
What It Creates
A complete feature includes all of these components:
| Component | Location | What's Included |
|---|---|---|
| Model | app/Models/ |
Fillable, casts, relationships, scopes, accessors |
| Migration | database/migrations/ |
Schema with indexes, foreign keys, proper types |
| Controller | app/Http/Controllers/ |
Resource methods, authorization, flash messages |
| Form Requests | app/Http/Requests/ |
Store/Update validation with authorization |
| Views | resources/views/ |
Index, create, edit, show Blade templates |
| Routes | routes/web.php |
Resource routes with middleware |
| Factory | database/factories/ |
Model factory with realistic fake data |
| Seeder | database/seeders/ |
Database seeder using factory |
| Policy | app/Policies/ |
Authorization policy (if auth requested) |
| Tests | tests/Feature/ |
Pest PHP tests for all CRUD operations |
Generation Process
- Analyze Requirements - Parse feature description and identify components
- Check Existing Code - Look for related models, avoid duplication
- Generate Schema - Create migration with appropriate columns and indexes
- Build Model - Add relationships based on schema analysis
- Create Controller - Generate CRUD methods with validation
- Generate Views - Create Blade templates matching your app's style
- Write Tests - Generate Pest tests covering all operations
- Register Routes - Add resource routes to web.php
Example Output
For a request like "Invoice management with line items and PDF export":
app/
├── Models/
│ ├── Invoice.php # With hasMany(InvoiceLineItem::class)
│ └── InvoiceLineItem.php # With belongsTo(Invoice::class)
├── Http/
│ ├── Controllers/
│ │ └── InvoiceController.php
│ └── Requests/
│ ├── StoreInvoiceRequest.php
│ └── UpdateInvoiceRequest.php
├── Services/
│ └── InvoicePdfService.php
database/
├── migrations/
│ ├── 2024_01_15_create_invoices_table.php
│ └── 2024_01_15_create_invoice_line_items_table.php
└── factories/
└── InvoiceFactory.php
resources/views/invoices/
├── index.blade.php
├── create.blade.php
├── edit.blade.php
└── show.blade.php
tests/Feature/
└── InvoiceTest.php
Generated Model Example
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
class Invoice extends Model
{
use HasFactory, SoftDeletes;
protected $fillable = [
'customer_id',
'invoice_number',
'issued_at',
'due_at',
'status',
'notes',
];
protected $casts = [
'issued_at' => 'date',
'due_at' => 'date',
];
// Relationships
public function customer(): BelongsTo
{
return $this->belongsTo(Customer::class);
}
public function lineItems(): HasMany
{
return $this->hasMany(InvoiceLineItem::class);
}
// Accessors
public function getTotalAttribute(): float
{
return $this->lineItems->sum(fn ($item) => $item->quantity * $item->unit_price);
}
// Scopes
public function scopeOverdue($query)
{
return $query->where('due_at', '<', now())
->where('status', '!=', 'paid');
}
public function scopePending($query)
{
return $query->where('status', 'pending');
}
}
Generated Controller Example
<?php
namespace App\Http\Controllers;
use App\Http\Requests\StoreInvoiceRequest;
use App\Http\Requests\UpdateInvoiceRequest;
use App\Models\Invoice;
class InvoiceController extends Controller
{
public function index()
{
$invoices = Invoice::with('customer')
->latest()
->paginate(15);
return view('invoices.index', compact('invoices'));
}
public function create()
{
return view('invoices.create');
}
public function store(StoreInvoiceRequest $request)
{
$invoice = Invoice::create($request->validated());
return redirect()
->route('invoices.show', $invoice)
->with('success', 'Invoice created successfully.');
}
public function show(Invoice $invoice)
{
$invoice->load('lineItems', 'customer');
return view('invoices.show', compact('invoice'));
}
public function edit(Invoice $invoice)
{
return view('invoices.edit', compact('invoice'));
}
public function update(UpdateInvoiceRequest $request, Invoice $invoice)
{
$invoice->update($request->validated());
return redirect()
->route('invoices.show', $invoice)
->with('success', 'Invoice updated successfully.');
}
public function destroy(Invoice $invoice)
{
$invoice->delete();
return redirect()
->route('invoices.index')
->with('success', 'Invoice deleted successfully.');
}
}
Customization Options
Include these in your request to customize output:
- with soft deletes - Add SoftDeletes trait
- with API - Also generate API controller and routes
- with authorization - Generate policy and gates
- without views - Skip Blade template generation
- without tests - Skip test generation (not recommended)
- with Livewire - Use Livewire components instead of Blade
Called By
- laravel-architect - When building complete features
Invoked By Commands
- /laravel-agent:feature:make - Direct invocation
- /laravel-agent:build - Via architect delegation
Package Integration
The feature builder automatically integrates with installed packages:
| Package | Integration |
|---|---|
spatie/laravel-tags |
Adds HasTags trait to models |
spatie/laravel-sluggable |
Configures slug generation on models |
spatie/laravel-activitylog |
Adds LogsActivity trait for audit trails |
spatie/laravel-medialibrary |
Configures media collections on models |
laravel/cashier |
Adds Billable trait for subscriptions |
maatwebsite/excel |
Creates Import/Export classes |
barryvdh/laravel-dompdf |
Generates PDF service for exports |
Post-Build Commands
After creating a feature, these commands are run:
# Required
composer dump-autoload
# If IDE Helper installed
php artisan ide-helper:models -N
# If Laravel Pint installed
vendor/bin/pint app/Features/<Name>/
# Run migrations
php artisan migrate:status
php artisan migrate --pretend
php artisan migrate
# Run tests
vendor/bin/pest --filter=<Name>
Guardrails
The feature builder enforces strict rules:
- NEVER mass-assign
created_for_idorcreated_by_id - NEVER skip tests
- ALWAYS use strict types and return types
- ALWAYS run migrations with safety checks first
- ALWAYS register ServiceProvider in config/app.php
Output Format
The builder produces a standardized completion report:
## laravel-feature-builder Complete
### Summary
- **Type**: Feature
- **Name**: Invoices
- **Status**: Success
### Files Created
- app/Features/Invoices/InvoicesServiceProvider.php
- app/Features/Invoices/Domain/Models/Invoice.php
- app/Features/Invoices/Http/Controllers/InvoicesController.php
- ...
### Routes
- Web: /invoices (resource routes)
- API: /api/v1/invoices (delegated to api-builder)
### Permissions (Laratrust)
- read-invoices, create-invoices, update-invoices, delete-invoices
See Also
- laravel-module-builder - For reusable domain modules
- laravel-service-builder - For standalone services
- laravel-feature skill - Auto-invoked for feature building