AI Skill Report Card
Building Laravel Applications
YAML--- name: building-laravel-applications description: Builds production-grade websites and platforms using Laravel and MySQL, covering architecture design, database schema design, Eloquent modeling, API development, authentication, and performance optimization. Use when building new Laravel features, designing database schemas, reviewing Laravel code, debugging Eloquent queries, or architecting a Laravel/MySQL platform from scratch. --- # Building Laravel Applications
Quick Start14 / 15
New feature request → follow this pattern:
Bashphp artisan make:model Order -mfsc # -m migration, -f factory, -s seeder, -c controller php artisan make:request StoreOrderRequest php artisan make:policy OrderPolicy --model=Order
PHP// Migration: define schema with proper types/indexes Schema::create('orders', function (Blueprint $table) { $table->id(); $table->foreignId('user_id')->constrained()->cascadeOnDelete(); $table->string('status')->index(); $table->decimal('total', 10, 2); $table->timestamps(); $table->softDeletes(); }); // Model: relationships, casts, scopes class Order extends Model { use HasFactory, SoftDeletes; protected $fillable = ['user_id', 'status', 'total']; protected $casts = ['total' => 'decimal:2']; public function user(): BelongsTo { return $this->belongsTo(User::class); } public function scopePending(Builder $query): Builder { return $query->where('status', 'pending'); } } // Controller: thin, delegate to Form Request + Resource class OrderController extends Controller { public function store(StoreOrderRequest $request): OrderResource { $order = Order::create($request->validated()); return new OrderResource($order); } }
Recommendation▾
Add more concrete examples with clear input/output pairs showing bad vs good code, not just correct patterns—currently there's no 'anti-pattern then fix' example
Workflow14 / 15
Progress checklist for a new feature/module:
- Design database schema (tables, foreign keys, indexes, cascade rules)
- Write migration with proper types (avoid
stringfor money/enum where possible) - Build Eloquent model (fillable/guarded, casts, relationships, scopes)
- Create Form Request for validation (never validate in controller directly)
- Create Policy/Gate for authorization
- Build Controller (thin — logic goes to Service/Action classes for complex flows)
- Create API Resource for response shaping (never return models raw)
- Write feature test (
php artisan make:test --feature) - Add database indexes for query patterns used in the feature
- Check N+1 queries with
DB::enableQueryLog()or Laravel Debugbar/Telescope
Recommendation▾
The examples section mixes languages (Indonesian input, English elsewhere); ensure consistency for clarity and broader usability
Database Design Principles (MySQL)
- Use
foreignId()->constrained()for FKs; decidecascadeOnDelete()vsnullOnDelete()explicitly per relation. - Index every column used in
WHERE,ORDER BY, or as a FK if not auto-indexed. - Use
decimalfor money, neverfloat/double. - Use
enumor a lookup table for fixed status values — prefer lookup table if values may grow. - Normalize to 3NF by default; denormalize only for measured read-heavy bottlenecks (e.g., cached counters via
withCountor observers). - Use
unsignedBigIntegerconsistently for IDs (Laravel default withid()/foreignId()handles this). - Always add
timestamps(); addsoftDeletes()only when data must be recoverable/audited.
Best Practices
- Fat models/services, skinny controllers. Controllers only orchestrate: validate → authorize → call service/action → return resource.
- Form Requests always for validation; never
$request->validate()inline in non-trivial controllers. - API Resources always for output; never
return $modelorModel::all()directly in JSON APIs. - Eager load explicitly:
Order::with('user', 'items.product')->get()— never let Blade/API loop trigger lazy loads. EnableModel::preventLazyLoading()inAppServiceProviderfor local/testing. - Use Policies/Gates, not manual
if ($user->id !== ...)checks scattered in controllers. - Queue anything slow: emails, exports, webhooks, image processing — use
ShouldQueue. - Use database transactions (
DB::transaction()) for multi-table writes that must be atomic. - Use Actions/Services for business logic reused across controllers, jobs, and commands (e.g.,
App\Actions\Orders\CreateOrder). - Config over hardcoding: use
.env+config/*.php, never hardcode credentials or magic numbers. - Test the critical paths: feature tests for auth, payments, and anything touching money or permissions.
Common Pitfalls
- N+1 queries — looping relations without
with()/load(). Always check query count in dev. - Mass assignment vulnerabilities — using
$fillable = ['*']orguarded = []carelessly on user-facing forms. - Storing money as float — causes rounding errors; always
decimal. - Business logic in controllers — makes testing and reuse hard; extract to Actions/Services.
- Not indexing foreign keys or filter columns — silently kills performance as tables grow.
- Overusing global scopes — makes debugging queries confusing; prefer explicit local scopes.
- Ignoring migrations rollback path — always implement
down()correctly, testmigrate:rollback. - Returning raw models from API — leaks unintended fields (passwords, internal flags); always use Resources.
- Not using queues for slow operations — blocks HTTP response time unnecessarily.
- Skipping database transactions on multi-step writes — leaves data inconsistent on partial failure.
Examples14 / 20
Example 1:
Input: "Buatkan relasi many-to-many antara Product dan Category dengan pivot tambahan (misalnya is_featured)."
Output:
PHP// Migration Schema::create('category_product', function (Blueprint $table) { $table->id(); $table->foreignId('product_id')->constrained()->cascadeOnDelete(); $table->foreignId('category_id')->constrained()->cascadeOnDelete(); $table->boolean('is_featured')->default(false); $table->timestamps(); }); // Model class Product extends Model { public function categories(): BelongsToMany { return $this->belongsToMany(Category::class) ->withPivot('is_featured') ->withTimestamps(); } }
Example 2:
Input: "Query produk lambat karena banyak relasi, gimana cara optimasi?"
Output: Cek dengan DB::enableQueryLog() lalu dd(DB::getQueryLog()) untuk hitung jumlah query. Tambahkan eager loading Product::with(['categories', 'reviews.user'])->get(), tambahkan index pada kolom FK/filter (product_id, category_id), pertimbangkan cache hasil query yang jarang berubah dengan Cache::remember(), dan gunakan pagination (paginate()) alih-alih get() untuk dataset besar.
Recommendation▾
Include a troubleshooting/debugging example for a failing migration or a complex API resource transformation to round out the workflow coverage