Builder
laravel-module-builder
Builds reusable domain modules - pure business logic without routes/views
Overview
The laravel-module-builder agent creates self-contained domain modules. Unlike features (which include routes, views, and controllers), modules are pure business logic packages with contracts, services, DTOs, and tests that can be shared across applications or extracted into packages.
Responsibilities
- Contract Definition - Interfaces for dependency inversion
- Service Classes - Business logic implementation
- DTOs - Data transfer objects for type safety
- Value Objects - Immutable domain objects
- Events - Domain events for decoupling
- Tests - Unit tests for the module
What It Creates
| Component | Location | Purpose |
|---|---|---|
| Contracts | app/Modules/{Name}/Contracts/ |
Interface definitions |
| Services | app/Modules/{Name}/Services/ |
Business logic |
| DTOs | app/Modules/{Name}/DTOs/ |
Data transfer objects |
| Events | app/Modules/{Name}/Events/ |
Domain events |
| Tests | tests/Unit/Modules/{Name}/ |
Unit tests |
Module Structure Example
app/Modules/Payment/
├── Contracts/
│ ├── PaymentGatewayInterface.php
│ └── PaymentResultInterface.php
├── Services/
│ └── PaymentService.php
├── DTOs/
│ ├── ChargeRequest.php
│ └── PaymentResult.php
├── Exceptions/
│ ├── PaymentFailedException.php
│ └── InvalidCardException.php
├── Events/
│ ├── PaymentSucceeded.php
│ └── PaymentFailed.php
└── PaymentServiceProvider.php
tests/Unit/Modules/Payment/
├── PaymentServiceTest.php
└── ChargeRequestTest.php
Generated Contract Example
<?php
namespace App\Modules\Payment\Contracts;
use App\Modules\Payment\DTOs\ChargeRequest;
use App\Modules\Payment\DTOs\PaymentResult;
interface PaymentGatewayInterface
{
/**
* Charge a payment method.
*
* @throws \App\Modules\Payment\Exceptions\PaymentFailedException
*/
public function charge(ChargeRequest $request): PaymentResult;
/**
* Refund a previous charge.
*/
public function refund(string $transactionId, int $amountInCents): PaymentResult;
/**
* Check if the gateway is available.
*/
public function isAvailable(): bool;
}
Generated DTO Example
<?php
namespace App\Modules\Payment\DTOs;
use Illuminate\Contracts\Support\Arrayable;
readonly class ChargeRequest implements Arrayable
{
public function __construct(
public int $amountInCents,
public string $currency,
public string $paymentMethodId,
public ?string $description = null,
public array $metadata = [],
) {}
public static function fromArray(array $data): self
{
return new self(
amountInCents: $data['amount_in_cents'],
currency: $data['currency'] ?? 'USD',
paymentMethodId: $data['payment_method_id'],
description: $data['description'] ?? null,
metadata: $data['metadata'] ?? [],
);
}
public function toArray(): array
{
return [
'amount_in_cents' => $this->amountInCents,
'currency' => $this->currency,
'payment_method_id' => $this->paymentMethodId,
'description' => $this->description,
'metadata' => $this->metadata,
];
}
}
Service Provider
<?php
namespace App\Modules\Payment;
use Illuminate\Support\ServiceProvider;
use App\Modules\Payment\Contracts\PaymentGatewayInterface;
use App\Modules\Payment\Services\StripeGateway;
class PaymentServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->bind(
PaymentGatewayInterface::class,
StripeGateway::class
);
}
public function boot(): void
{
// Publish config if needed
// $this->publishes([...]);
}
}
When to Use Modules vs Features
| Use Module When | Use Feature When |
|---|---|
| Business logic is reusable | Need CRUD with UI |
| May extract to package later | App-specific feature |
| No routes/views needed | Need controllers and views |
| Integration with external APIs | User-facing functionality |
Invoked By Commands
- /laravel-agent:module:make - Create domain modules
Called By
- laravel-architect - When building reusable domain logic
Guardrails
The module builder follows strict rules:
- ALWAYS define contracts (interfaces) first
- ALWAYS use DTOs for data transfer
- ALWAYS bind implementations in ServiceProvider
- NEVER add routes or controllers to modules
- NEVER couple to specific implementations
See Also
- laravel-feature-builder - For full-stack features
- laravel-service-builder - For single services