From laravel-toolkit
Define a arquitetura limpa de projetos Laravel com Actions, DTOs, Policies e Service Layer. Use quando precisar organizar estrutura de diretórios, definir padrões arquiteturais, ou planejar a organização de um projeto Laravel.
How this skill is triggered — by the user, by Claude, or both
Slash command
/laravel-toolkit:architectureThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Define e mantém arquitetura limpa em projetos Laravel usando Actions, DTOs e Policies.
Define e mantém arquitetura limpa em projetos Laravel usando Actions, DTOs e Policies.
| Skill | Quando usar junto |
|---|---|
coder | Para implementar seguindo a arquitetura |
actions | Para Actions, Events e Jobs |
models | Para Models e relações |
exceptions | Para exceções de domínio |
testing | Para testar Actions e Policies |
planner | Para planejar arquitetura de features |
Use esta skill sempre que:
Exemplo de stack — ajuste ao seu projeto: Laravel 11+ + React + Inertia.js + Filament 4.x + Tailwind 4
declare(strict_types=1);DB::, use Model::query()env() fora de arquivos de configuração.gitkeep ao adicionar arquivosapp/Console/Commands/config('app.name') não env('APP_NAME')app/
├── Actions/ # Lógica de negócio (NÃO Services!) — subpastas por domínio (exemplos)
│ ├── Domain1/
│ ├── Domain2/
│ └── Domain3/
├── DataObjects/ # Value Objects (DTOs) — subpastas por domínio (exemplos)
│ ├── Domain1/
│ ├── Domain2/
│ └── Domain3/
├── Enums/ # Todos os enums (nomes descritivos, sem sufixo)
├── Events/ # Eventos de domínio (past tense)
├── Listeners/ # Event listeners (imperative)
├── Models/ # Eloquent models (thin, sem lógica de negócio)
├── Observers/ # Model lifecycle observers
├── Http/
│ ├── Controllers/ # Thin orchestrators
│ └── Requests/ # Form Requests (validation)
└── Policies/ # Authorization logic
Nota: os exemplos de código nas seções a seguir usam um domínio ilustrativo (SaaS multi-tenant —
Business,Order,Tenant) apenas para demonstração; mapeie-os aos domínios reais do seu projeto.
Este projeto segue clean architecture com clara separação de responsabilidades:
┌─────────────────────────────────────────────────────────────┐
│ HTTP REQUEST │
└──────────────────────┬──────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ CONTROLLER (Thin Orchestrator) │
│ ├─ Validate (FormRequest) │
│ ├─ Authorize (Policy) │
│ ├─ Build Value Object │
│ └─ Call Action │
└──────────────────────┬──────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ VALUE OBJECT (Data Transfer) │
│ ├─ Type-safe data structure │
│ ├─ Immutable (readonly) │
│ └─ Factory methods (fromRequest, toArray) │
└──────────────────────┬──────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ ACTION (Business Logic) │
│ ├─ Single responsibility │
│ ├─ Database operations │
│ ├─ Business rules & calculations │
│ ├─ Call other Actions if needed │
│ └─ Dispatch Events │
└──────────────────────┬──────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ MODEL (Data + Relationships) │
│ ├─ Eloquent relationships │
│ ├─ Accessors & Mutators │
│ ├─ Scopes │
│ └─ NO business logic │
└──────────────────────┬──────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ OBSERVER / EVENT (Side Effects) │
│ ├─ Model lifecycle hooks (Observer) │
│ ├─ Send notifications │
│ ├─ Update related records │
│ └─ Log activities │
└─────────────────────────────────────────────────────────────┘
| Camada | Responsabilidade | ✅ Deve | ❌ Não Deve |
|---|---|---|---|
| Controller | Orquestração HTTP | Validate, Authorize, Delegate, Respond | Lógica de negócio, Queries de database |
| Value Object | Transferência de dados | Type safety, Imutabilidade | Validação, Lógica de negócio |
| Action | Lógica de negócio | CRUD, Cálculos, Regras, Eventos | Preocupações HTTP, Validação |
| Model | Dados + Relações | Relações, Casts, Scopes | Lógica de negócio, Cálculos complexos |
| Observer | Side effects | Lifecycle hooks, Events | Lógica de negócio core |
| Event/Listener | Side effects desacoplados | Notifications, Logging, Async tasks | Fluxo de negócio principal |
| Tipo | Convenção | Exemplo |
|---|---|---|
| Enum | Sem sufixo (Spatie) | BusinessType, UserRole |
| Action | Sufixo Action | CreateBusinessAction, UpdateOrderAction |
| Value Object | Sufixo Data | CreateBusinessData, UpdateOrderData |
| Controller | Plural + Controller | BusinessesController, OrdersController |
| Event | Past tense, sem sufixo | BusinessCreated, OrderPlaced |
| Listener | Imperativo, sem sufixo | SendWelcomeEmail, NotifyAdmin |
| Observer | Sufixo Observer | BusinessObserver, OrderObserver |
| Policy | Sufixo Policy | BusinessPolicy, OrderPolicy |
| Form Request | Sufixo Request | StoreBusinessRequest, UpdateOrderRequest |
NOTA: NUNCA use sufixo Service - use Actions!
php artisan make:model Product -mf
php artisan make:action CreateProduct
php artisan make:class DataObjects/Product/CreateProductData
php artisan make:request StoreProductRequest
php artisan make:policy ProductPolicy --model=Product
php artisan make:observer ProductObserver --model=Product
php artisan make:test --pest ProductTest
Antes de finalizar QUALQUER feature:
composer test)composer fix)final class BusinessController
{
public function store(StoreBusinessRequest $request): RedirectResponse
{
// ✅ GOOD: Thin controller - delega para Action
$business = CreateBusinessAction::run(
tenant: auth()->user()->tenant,
data: $request->validated()
);
return redirect()
->route('owner.businesses.index')
->with('success', __('messages.business_created'));
}
}
final class CreateBusinessAction
{
use AsAction;
public function handle(Tenant $tenant, CreateBusinessData $data): Business
{
// Check limits
if (!$tenant->isWithinLimit('businesses')) {
throw new BusinessLimitExceededException();
}
// Create business
$business = $tenant->businesses()->create($data->toArray());
// Increment usage
$tenant->incrementUsage('businesses');
// Dispatch event
event(new BusinessCreated($business));
return $business;
}
}
final readonly class CreateBusinessData
{
public function __construct(
public string $name,
public string $type,
public ?string $email = null,
public ?string $phone = null,
) {}
public static function fromRequest(array $data): self
{
return new self(
name: $data['name'],
type: $data['type'],
email: $data['email'] ?? null,
phone: $data['phone'] ?? null,
);
}
public function toArray(): array
{
return [
'name' => $this->name,
'type' => $this->type,
'email' => $this->email,
'phone' => $this->phone,
];
}
}
final class BusinessPolicy
{
public function view(User $user, Business $business): bool
{
return $user->tenant_id === $business->tenant_id;
}
public function create(User $user): bool
{
return $user->tenant->isWithinLimit('businesses');
}
public function update(User $user, Business $business): bool
{
return $user->tenant_id === $business->tenant_id;
}
public function delete(User $user, Business $business): bool
{
return $user->tenant_id === $business->tenant_id;
}
}
i18n para traduções de Enums, mensagens e interfacesexceptions para exceções de domínio e regras de negóciotesting para testes de Actions e Policiesactions para patterns avançados de eventosnpx claudepluginhub aronpc/aiCreates structured, bite-sized implementation plans from specs or requirements before writing code. Useful for breaking down multi-step tasks into testable steps with file structure and task boundaries.