ui/.ai/skills/laravel-routes-best-practices/SKILL.md
Keep routes clean and focused on mapping requests to controllers; avoid business logic, validation, or database operations in route files
npx skillsauth add noartem/kawa laravel-routes-best-practicesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Keep your route files clean and focused on mapping requests to controllers. Routes should never contain business logic, validation, or database operations.
// BAD: Business logic directly in routes
Route::post('/order/{order}/cancel', function (Order $order) {
if ($order->status !== 'pending') {
return response()->json(['error' => 'Cannot cancel'], 400);
}
$order->status = 'cancelled';
$order->cancelled_at = now();
$order->save();
Mail::to($order->user)->send(new OrderCancelled($order));
return response()->json(['message' => 'Order cancelled']);
});
// BAD: Validation in routes
Route::post('/users', function (Request $request) {
$validated = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users',
]);
return User::create($validated);
});
// GOOD: Routes only map to controllers
Route::post('/order/{order}/cancel', [OrderController::class, 'cancel']);
Route::post('/users', [UserController::class, 'store']);
// GOOD: Use route groups for organization
Route::prefix('api/v1')->group(function () {
Route::apiResource('orders', OrderController::class);
Route::post('orders/{order}/cancel', [OrderController::class, 'cancel']);
});
// GOOD: Named routes for maintainability
Route::post('/order/{order}/cancel', [OrderController::class, 'cancel'])
->name('orders.cancel');
// GOOD: Middleware in routes, logic in controllers
Route::middleware(['auth', 'verified'])->group(function () {
Route::resource('admin/users', AdminUserController::class);
});
// app/Http/Controllers/OrderController.php
class OrderController extends Controller
{
public function __construct(
private readonly OrderCancellationService $cancellationService
) {}
public function cancel(CancelOrderRequest $request, Order $order)
{
$this->cancellationService->cancel($order);
return response()->json([
'message' => 'Order cancelled successfully'
]);
}
}
// app/Http/Requests/CancelOrderRequest.php
class CancelOrderRequest extends FormRequest
{
public function authorize(): bool
{
return $this->user()->can('cancel', $this->route('order'));
}
public function rules(): array
{
return [
'reason' => 'nullable|string|max:500',
];
}
}
// routes/web.php - Keep it minimal
Route::get('/', [HomeController::class, 'index']);
Route::get('/about', [PageController::class, 'about']);
require __DIR__ . '/auth.php';
require __DIR__ . '/admin.php';
// routes/admin.php - Separate concerns
Route::prefix('admin')
->middleware(['auth', 'admin'])
->name('admin.')
->group(function () {
Route::get('/dashboard', [AdminDashboardController::class, 'index'])
->name('dashboard');
Route::resource('users', AdminUserController::class);
});
// routes/api.php - API routes
Route::prefix('v1')->group(function () {
Route::apiResource('products', Api\ProductController::class);
Route::post('products/{product}/reviews', [Api\ReviewController::class, 'store']);
});
Routes are declarations, not implementations
Use route model binding
// Laravel automatically resolves the Order model
Route::put('/orders/{order}', [OrderController::class, 'update']);
Group related routes
Route::controller(OrderController::class)->group(function () {
Route::get('/orders', 'index');
Route::get('/orders/{order}', 'show');
Route::post('/orders', 'store');
});
Use resource controllers when appropriate
Route::resource('photos', PhotoController::class)
->only(['index', 'show'])
->names('gallery.photos');
Leverage route caching in production
sail artisan route:cache
Route closures are acceptable only for:
// Acceptable for simple static views
Route::view('/terms', 'legal.terms');
Route::view('/privacy', 'legal.privacy');
// Or simple redirects
Route::redirect('/home', '/dashboard');
Route::permanentRedirect('/old-about', '/about');
test('order cancellation route requires authentication', function () {
$order = Order::factory()->create();
$response = $this->postJson("/orders/{$order->id}/cancel");
$response->assertUnauthorized();
});
test('route names are properly defined', function () {
expect(route('orders.cancel', ['order' => 1]))
->toBe('http://localhost/orders/1/cancel');
});
Remember: If you're writing more than one line of code in a route definition, it belongs in a controller!
development
Use this skill any time a spreadsheet file is the primary input or output. This means any task where the user wants to: open, read, edit, or fix an existing .xlsx, .xlsm, .csv, or .tsv file (e.g., adding columns, computing formulas, formatting, charting, cleaning messy data); create a new spreadsheet from scratch or from other data sources; or convert between tabular file formats. Trigger especially when the user references a spreadsheet file by name or path — even casually (like "the xlsx in my downloads") — and wants something done to it or produced from it. Also trigger for cleaning or restructuring messy tabular data files (malformed rows, misplaced headers, junk data) into proper spreadsheets. The deliverable must be a spreadsheet file. Do NOT trigger when the primary deliverable is a Word document, HTML report, standalone Python script, database pipeline, or Google Sheets API integration, even if tabular data is involved.
tools
Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.
development
Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices".
tools
Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn/ui). Use for complex artifacts requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX artifacts.