AI-ready development

AI Task Patterns

AI Task Patterns

Practical prompt templates for common Laravolt v7 tasks. Each pattern includes the prompt, expected output, verification steps, and common pitfalls.

How to use these patterns

  1. Copy the prompt template
  2. Replace {placeholders} with your values
  3. Include /llms.txt context reference
  4. Specify expected deliverables
  5. Verify the output with provided commands

Pattern 1: Generate CRUD for table

Prompt template

Plain Text
Read /llms.txt for Laravolt v7 conventions.
Task: Generate CRUD module for {table_name}
Steps:
1. Create migration for {table_name} with fields:
- {field_1}: {type}, {constraints}
- {field_2}: {type}, {constraints}
- ...
2. Run migration: php artisan migrate
3. Generate module: php artisan laravolt:clap --table={table_name} --module={ModuleName}
4. Register ServiceProvider in config/app.php
5. Verify routes: php artisan route:list --name={route_prefix}
6. Run tests: php artisan test --filter={ModuleName}Test
Deliverables:
- Migration file
- Generated module structure
- Route list output
- Test results

Example: Product CRUD

Plain Text
Read /llms.txt for Laravolt v7 conventions.
Task: Generate CRUD module for products
Steps:
1. Create migration for products with fields:
- name: string, required, max 255
- sku: string, required, unique, max 50
- description: text, nullable
- price: decimal(10,2), required
- is_active: boolean, default true
2. Run migration: php artisan migrate
3. Generate module: php artisan laravolt:clap --table=products --module=Product
4. Register ServiceProvider in config/app.php
5. Verify routes: php artisan route:list --name=product
6. Run tests: php artisan test --filter=ProductTest
Deliverables:
- Migration file
- Generated module structure
- Route list output
- Test results

Expected output

Plain Text
✓ Migration created: database/migrations/2024_01_15_create_products_table.php
✓ Migration run successfully
✓ Module generated: modules/Product/
✓ ServiceProvider registered
✓ Routes verified (7 routes)
✓ Tests passed (4 tests)
Files created:
- modules/Product/Controllers/ProductController.php
- modules/Product/Models/Product.php
- modules/Product/Requests/StoreProductRequest.php
- modules/Product/Requests/UpdateProductRequest.php
- modules/Product/resources/views/index.blade.php
- modules/Product/resources/views/create.blade.php
- modules/Product/resources/views/edit.blade.php
- modules/Product/resources/views/show.blade.php
- modules/Product/resources/views/form.blade.php
- modules/Product/TableView.php
- modules/Product/routes/web.php
- modules/Product/config/config.php
- modules/Product/ServiceProvider.php
- modules/Product/Tests/Feature/ProductTest.php

Verification

Bash
php artisan route:list --name=product
php artisan test --filter=ProductTest
php artisan serve
# Visit: http://localhost:8000/product

Common pitfalls

  • ❌ Forgetting to register ServiceProvider → routes not found
  • ❌ Not running migration before laravolt:clap → table not found error
  • ❌ Using wrong table name (plural vs singular) → model mismatch
  • ✅ Always verify routes after generation
  • ✅ Run tests before customizing

Pattern 2: Add approval workflow

Prompt template

Plain Text
Read /llms.txt for Laravolt v7 conventions.
Task: Add approval workflow to {ModuleName}
Requirements:
1. Add status field to {table_name}: enum('draft', 'submitted', 'approved', 'rejected')
2. Add submitted_at, approved_at, rejected_at timestamps
3. Add approver_id foreign key (references users)
4. Add approval actions to controller:
- submit() - change status to 'submitted'
- approve() - change status to 'approved', set approved_at and approver_id
- reject() - change status to 'rejected', set rejected_at and approver_id
5. Add routes for approval actions
6. Add action buttons to show page (conditional on status)
7. Add permissions: {resource}.submit, {resource}.approve, {resource}.reject
8. Add policy checks for each action
9. Add feature tests for approval workflow
Files to modify:
- New migration: add_approval_fields_to_{table_name}
- {ModuleName}Controller.php
- routes/web.php
- resources/views/show.blade.php
- {ModuleName}Policy.php (create if not exists)
- Tests/Feature/{ModuleName}ApprovalTest.php (new)
Deliverables:
- Migration file
- Updated controller with approval methods
- Updated routes
- Updated show view with action buttons
- Policy with approval rules
- Test results

Example: Purchase Order approval

Plain Text
Read /llms.txt for Laravolt v7 conventions.
Task: Add approval workflow to PurchaseOrder
Requirements:
1. Add status field to purchase_orders: enum('draft', 'submitted', 'approved', 'rejected')
2. Add submitted_at, approved_at, rejected_at timestamps
3. Add approver_id foreign key (references users)
4. Add approval actions to controller:
- submit() - change status to 'submitted'
- approve() - change status to 'approved', set approved_at and approver_id
- reject() - change status to 'rejected', set rejected_at and approver_id
5. Add routes for approval actions
6. Add action buttons to show page (conditional on status)
7. Add permissions: purchase-order.submit, purchase-order.approve, purchase-order.reject
8. Add policy checks for each action
9. Add feature tests for approval workflow
Files to modify:
- New migration: add_approval_fields_to_purchase_orders
- PurchaseOrderController.php
- routes/web.php
- resources/views/show.blade.php
- PurchaseOrderPolicy.php (create if not exists)
- Tests/Feature/PurchaseOrderApprovalTest.php (new)
Deliverables:
- Migration file
- Updated controller with approval methods
- Updated routes
- Updated show view with action buttons
- Policy with approval rules
- Test results

Expected output

Plain Text
✓ Migration created and run
✓ Controller updated with submit/approve/reject methods
✓ Routes added: purchase-order.submit, purchase-order.approve, purchase-order.reject
✓ Show view updated with conditional action buttons
✓ Policy created with approval rules
✓ Tests created and passing
New routes:
POST purchase-order/{purchase_order}/submit ... purchase-order.submit
POST purchase-order/{purchase_order}/approve ... purchase-order.approve
POST purchase-order/{purchase_order}/reject ... purchase-order.reject

Verification

Bash
php artisan migrate
php artisan route:list --name=purchase-order
php artisan test --filter=PurchaseOrderApprovalTest
# Manual test:
# 1. Create purchase order (status: draft)
# 2. Click "Submit" (status: submitted)
# 3. Login as approver
# 4. Click "Approve" (status: approved, approved_at set)

Common pitfalls

  • ❌ Not adding policy checks → unauthorized users can approve
  • ❌ Not validating status transitions → can approve already approved orders
  • ❌ Forgetting to set timestamps → approved_at remains null
  • ❌ Not testing negative cases → missing "cannot approve draft" test
  • ✅ Always check current status before transition
  • ✅ Use policy gates, not just UI hiding
  • ✅ Test both allowed and denied paths

Pattern 3: Customize form with validation

Prompt template

Plain Text
Read /llms.txt for Laravolt v7 conventions.
Task: Customize {ModuleName} form with validation
Requirements:
1. Update form fields in form.blade.php:
- {field_1}: {field_type}, {attributes}
- {field_2}: {field_type}, {attributes}
- ...
2. Update validation in StoreRequest and UpdateRequest:
- {field_1}: {rules}
- {field_2}: {rules}
- ...
3. Add custom validation messages if needed
4. Add input masks for formatted fields (phone, currency, etc.)
Files to modify:
- resources/views/form.blade.php
- Requests/Store{ModuleName}Request.php
- Requests/Update{ModuleName}Request.php
Use PrelineForm API for fields.
Use Laravel validation rules.
Deliverables:
- Updated form view
- Updated validation rules
- Test command to verify validation

Example: Product form customization

Plain Text
Read /llms.txt for Laravolt v7 conventions.
Task: Customize Product form with validation
Requirements:
1. Update form fields in form.blade.php:
- name: text input, required, max 255, help text "Product display name"
- sku: text input, required, max 50, uppercase, help text "Format: PROD-XXXX"
- description: textarea, 5 rows, max 1000, optional
- price: number input, required, min 0.01, currency mask (IDR)
- category_id: select dropdown, required, load from categories table
- is_active: checkbox, default checked
2. Update validation in StoreRequest and UpdateRequest:
- name: required, string, max 255, unique
- sku: required, string, max 50, unique, uppercase, regex:/^PROD-[A-Z0-9]+$/
- description: nullable, string, max 1000
- price: required, numeric, min 0.01
- category_id: required, exists:categories,id
- is_active: boolean
3. Add custom validation messages for SKU format
4. Add currency input mask for price field
Files to modify:
- resources/views/form.blade.php
- Requests/StoreProductRequest.php
- Requests/UpdateProductRequest.php
Use PrelineForm API for fields.
Use Laravel validation rules.
Deliverables:
- Updated form view
- Updated validation rules
- Test command to verify validation

Expected output

Form view with PrelineForm:

Blade
{!! PrelineForm::text('name')
->label('Product Name')
->required()
->maxlength(255)
->help('Product display name') !!}
{!! PrelineForm::text('sku')
->label('SKU')
->required()
->maxlength(50)
->help('Format: PROD-XXXX')
->attributes(['style' => 'text-transform: uppercase']) !!}
{!! PrelineForm::textarea('description')
->label('Description')
->rows(5)
->maxlength(1000) !!}
{!! PrelineForm::number('price')
->label('Price (IDR)')
->required()
->min(0.01)
->step(0.01)
->inputmask(['alias' => 'currency', 'prefix' => 'Rp ', 'digits' => 0]) !!}
{!! PrelineForm::select('category_id', $categories)
->label('Category')
->required()
->placeholder('-- Select Category --') !!}
{!! PrelineForm::checkbox('is_active', 1)
->label('Active')
->checked(old('is_active', $product->is_active ?? true)) !!}

Validation rules:

PHP
// StoreProductRequest.php
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255', 'unique:products,name'],
'sku' => ['required', 'string', 'max:50', 'unique:products,sku', 'uppercase', 'regex:/^PROD-[A-Z0-9]+$/'],
'description' => ['nullable', 'string', 'max:1000'],
'price' => ['required', 'numeric', 'min:0.01'],
'category_id' => ['required', 'exists:categories,id'],
'is_active' => ['boolean'],
];
}
public function messages(): array
{
return [
'sku.regex' => 'SKU must start with PROD- followed by uppercase letters and numbers.',
];
}

Verification

Bash
# Test validation
php artisan test --filter=ProductTest
# Manual test:
# 1. Try invalid SKU format (e.g., "prod-123") → expect error
# 2. Try duplicate SKU → expect error
# 3. Try negative price → expect error
# 4. Try valid data → expect success

Common pitfalls

  • ❌ Not syncing validation rules between Store and Update requests
  • ❌ Forgetting unique rule exception for Update request
  • ❌ Not testing validation errors in browser
  • ❌ Using wrong PrelineForm method names
  • ✅ Always test both positive and negative validation cases
  • ✅ Use help() for user guidance
  • ✅ Use inputmask() for formatted inputs

Pattern 4: Add search and filter to listing

Prompt template

Plain Text
Read /llms.txt for Laravolt v7 conventions.
Task: Add search and filter to {ModuleName} listing
Requirements:
1. Add search on fields: {field_1}, {field_2}, ...
2. Add filters:
- {filter_1}: {type} (e.g., select, checkbox, date range)
- {filter_2}: {type}
- ...
3. Update TableView query to apply search and filters
4. Add filter UI to index page
Files to modify:
- {ModuleName}TableView.php
- resources/views/index.blade.php (if custom filters needed)
Use Suitable searchable() and query() methods.
Deliverables:
- Updated TableView with search and filters
- Verification command

Example: Product listing with search and filters

Plain Text
Read /llms.txt for Laravolt v7 conventions.
Task: Add search and filter to Product listing
Requirements:
1. Add search on fields: name, sku, description
2. Add filters:
- category_id: select dropdown (all categories)
- is_active: select (all/active/inactive)
- price_range: min/max inputs
3. Update ProductTableView query to apply search and filters
4. Suitable will handle filter UI automatically
Files to modify:
- ProductTableView.php
Use Suitable searchable() and query() methods.
Deliverables:
- Updated TableView with search and filters
- Verification command

Expected output

PHP
// ProductTableView.php
use Laravolt\Suitable\Columns\Text;
use Laravolt\Suitable\Columns\Boolean;
use Laravolt\Suitable\Columns\Number;
use App\Models\Category;
public function columns(): array
{
return [
Text::make('name', 'Product Name')->sortable(),
Text::make('sku', 'SKU')->sortable(),
Text::make('category.name', 'Category'),
Number::make('price', 'Price')->sortable()->prefix('Rp ')->decimal(0),
Boolean::make('is_active', 'Active'),
];
}
public function searchable(): array
{
return ['name', 'sku', 'description'];
}
public function query()
{
$query = Product::with('category');
// Filter by category
if (request('category_id')) {
$query->where('category_id', request('category_id'));
}
// Filter by active status
if (request('is_active') !== null && request('is_active') !== '') {
$query->where('is_active', request('is_active'));
}
// Filter by price range
if (request('price_min')) {
$query->where('price', '>=', request('price_min'));
}
if (request('price_max')) {
$query->where('price', '<=', request('price_max'));
}
return $query;
}
public function filters(): array
{
return [
'category_id' => [
'label' => 'Category',
'type' => 'select',
'options' => Category::pluck('name', 'id')->prepend('All Categories', ''),
],
'is_active' => [
'label' => 'Status',
'type' => 'select',
'options' => [
'' => 'All',
'1' => 'Active',
'0' => 'Inactive',
],
],
'price_min' => [
'label' => 'Min Price',
'type' => 'number',
],
'price_max' => [
'label' => 'Max Price',
'type' => 'number',
],
];
}

Verification

Bash
php artisan serve
# Visit: http://localhost:8000/product
# Test:
# 1. Type in search box → results filter by name/sku/description
# 2. Select category → results filter by category
# 3. Select "Active" status → only active products shown
# 4. Enter price range → results within range
# 5. Combine filters → all filters apply together

Common pitfalls

  • ❌ Not handling empty filter values → query breaks
  • ❌ Forgetting to eager load relationships → N+1 query problem
  • ❌ Not testing filter combinations → filters conflict
  • ❌ Using = for text search instead of LIKE
  • ✅ Always check request('filter') !== null && request('filter') !== ''
  • ✅ Use with() for relationships shown in columns
  • ✅ Test each filter individually and in combination

Pattern 5: Add row actions with policy checks

Prompt template

Plain Text
Read /llms.txt for Laravolt v7 conventions.
Task: Add row actions to {ModuleName} listing
Requirements:
1. Add row actions:
- View: route to show page
- Edit: route to edit page (if user can update)
- Delete: delete action (if user can delete)
- {Custom action}: route/action (if user can {permission})
2. Add policy checks for each action
3. Update TableView with action column
Files to modify:
- {ModuleName}TableView.php
- {ModuleName}Policy.php (if not exists, create it)
Use Suitable action columns.
Use Laravel policy gates.
Deliverables:
- Updated TableView with actions
- Policy with action rules
- Verification command

Example: Product listing with actions

Plain Text
Read /llms.txt for Laravolt v7 conventions.
Task: Add row actions to Product listing
Requirements:
1. Add row actions:
- View: route to show page
- Edit: route to edit page (if user can update)
- Delete: delete action (if user can delete)
- Duplicate: custom action to duplicate product (if user can create)
2. Add policy checks for each action
3. Update ProductTableView with action column
Files to modify:
- ProductTableView.php
- ProductPolicy.php (create if not exists)
Use Suitable action columns.
Use Laravel policy gates.
Deliverables:
- Updated TableView with actions
- Policy with action rules
- Verification command

Expected output

Policy:

PHP
// app/Policies/ProductPolicy.php
namespace App\Policies;
use App\Models\Product;
use App\Models\User;
class ProductPolicy
{
public function viewAny(User $user): bool
{
return $user->can('product.read');
}
public function view(User $user, Product $product): bool
{
return $user->can('product.read');
}
public function create(User $user): bool
{
return $user->can('product.create');
}
public function update(User $user, Product $product): bool
{
return $user->can('product.update');
}
public function delete(User $user, Product $product): bool
{
return $user->can('product.delete');
}
public function duplicate(User $user, Product $product): bool
{
return $user->can('product.create');
}
}

TableView with actions:

PHP
// ProductTableView.php
use Laravolt\Suitable\Columns\Action;
use Laravolt\Suitable\Columns\DropdownAction;
public function columns(): array
{
return [
Text::make('name', 'Product Name')->sortable(),
Text::make('sku', 'SKU')->sortable(),
Number::make('price', 'Price')->sortable()->prefix('Rp ')->decimal(0),
Boolean::make('is_active', 'Active'),
DropdownAction::make('Actions')
->actions(function ($row) {
$actions = [];
if (auth()->user()->can('view', $row)) {
$actions[] = [
'label' => 'View',
'url' => route('product.show', $row),
];
}
if (auth()->user()->can('update', $row)) {
$actions[] = [
'label' => 'Edit',
'url' => route('product.edit', $row),
];
}
if (auth()->user()->can('duplicate', $row)) {
$actions[] = [
'label' => 'Duplicate',
'url' => route('product.duplicate', $row),
'method' => 'POST',
];
}
if (auth()->user()->can('delete', $row)) {
$actions[] = [
'label' => 'Delete',
'url' => route('product.destroy', $row),
'method' => 'DELETE',
'confirm' => 'Are you sure you want to delete this product?',
];
}
return $actions;
}),
];
}

Verification

Bash
# Register policy in AuthServiceProvider
# app/Providers/AuthServiceProvider.php
protected $policies = [
Product::class => ProductPolicy::class,
];
php artisan serve
# Visit: http://localhost:8000/product
# Test as different users:
# 1. User with product.read only → see View action only
# 2. User with product.update → see View, Edit actions
# 3. User with product.delete → see View, Edit, Delete actions
# 4. User with product.create → see View, Edit, Duplicate actions

Common pitfalls

  • ❌ Not registering policy in AuthServiceProvider → policy not applied
  • ❌ Using UI hiding instead of policy checks → security hole
  • ❌ Not testing with different user roles → unauthorized access
  • ❌ Forgetting CSRF token for POST/DELETE actions
  • ✅ Always use auth()->user()->can() for action visibility
  • ✅ Add confirm for destructive actions
  • ✅ Test with users having different permissions

Summary

These patterns cover the most common Laravolt v7 tasks:

  1. Generate CRUD - Bootstrap from table to working module
  2. Add approval workflow - Status transitions with permissions
  3. Customize form - Validation, input masks, field types
  4. Add search/filter - Query customization for listings
  5. Add row actions - Policy-protected actions in tables

For each task:

  • ✅ Use concrete prompts with exact file paths
  • ✅ Specify verification commands
  • ✅ Include expected output
  • ✅ List common pitfalls
  • ✅ Reference /llms.txt for context
Previous
Task Recipes