7.5 KiB
Modular Architecture
This template uses a modular architecture to organize features into self-contained modules. Each module has its own admin panel, routes, views, and permissions.
Quick Start
# Create a new module
php artisan make:module StockManagement
# Create with a model
php artisan make:module StockManagement --model=Product
# Create with API routes
php artisan make:module StockManagement --api
# Skip Filament admin
php artisan make:module StockManagement --no-filament
Module Structure
app/Modules/StockManagement/
├── Config/
│ └── stock_management.php # Module configuration
├── Database/
│ ├── Migrations/ # Module-specific migrations
│ └── Seeders/
│ └── StockManagementPermissionSeeder.php
├── Filament/
│ └── Resources/ # Admin panel resources
│ ├── StockManagementDashboardResource.php
│ └── ProductResource.php # If --model used
├── Http/
│ ├── Controllers/
│ │ └── StockManagementController.php
│ ├── Middleware/
│ └── Requests/
├── Models/
│ └── Product.php # If --model used
├── Policies/
├── Services/ # Business logic
├── Routes/
│ ├── web.php # Frontend routes
│ └── api.php # API routes (if --api)
├── Resources/
│ ├── views/
│ │ ├── index.blade.php # Module landing page
│ │ ├── layouts/
│ │ └── filament/
│ ├── css/
│ │ └── stock-management.css # Module-specific styles
│ └── lang/en/
├── Permissions.php # Module permissions
└── StockManagementServiceProvider.php
How Modules Work
Auto-Loading
The ModuleServiceProvider automatically:
- Discovers all modules in
app/Modules/ - Registers each module's service provider
- Loads routes, views, migrations, and translations
Routes
Module routes are prefixed and named automatically:
// Routes/web.php
Route::prefix('stock-management')
->name('stock-management.')
->middleware(['web', 'auth'])
->group(function () {
Route::get('/', [StockManagementController::class, 'index'])
->name('index');
});
Access: http://localhost:8080/stock-management
Views
Module views use a namespace based on the module slug:
// In controller
return view('stock-management::index');
// In Blade
@include('stock-management::partials.header')
Filament Admin
Each module gets its own navigation group in the admin panel:
📦 Stock Management
├── Dashboard
├── Products
└── Inventory
Resources are automatically discovered from Filament/Resources/.
Permissions
Defining Permissions
Each module has a Permissions.php file:
// app/Modules/StockManagement/Permissions.php
return [
'stock_management.view' => 'View Stock Management',
'stock_management.create' => 'Create stock records',
'stock_management.edit' => 'Edit stock records',
'stock_management.delete' => 'Delete stock records',
'stock_management.export' => 'Export stock data',
];
Seeding Permissions
After creating a module, run:
php artisan db:seed --class=PermissionSeeder
This registers all module permissions and assigns them to the admin role.
Using Permissions
In Blade:
@can('stock_management.view')
<a href="{{ route('stock-management.index') }}">Stock Management</a>
@endcan
In Controllers:
public function index()
{
$this->authorize('stock_management.view');
// ...
}
In Filament Resources:
public static function canAccess(): bool
{
return auth()->user()?->can('stock_management.view') ?? false;
}
Module Assets
App-Wide CSS/JS
Use the main resources/css/app.css and resources/js/app.js for shared styles.
Module-Specific Styles
Each module has its own CSS file at Resources/css/{module-slug}.css.
Include in Blade:
@push('module-styles')
<link href="{{ asset('modules/stock-management/css/stock-management.css') }}" rel="stylesheet">
@endpush
Or inline in the view:
@push('module-styles')
<style>
.stock-table { /* ... */ }
</style>
@endpush
Creating Models
With Module Command
php artisan make:module StockManagement --model=Product
Creates:
Models/Product.php- Migration in
Database/Migrations/ - Filament resource with CRUD pages
Adding Models Later
# From project root
php artisan make:model Modules/StockManagement/Models/Inventory -m
Then create the Filament resource:
php artisan make:filament-resource Inventory \
--model=App\\Modules\\StockManagement\\Models\\Inventory
Move the resource to your module's Filament/Resources/ directory.
Example: Stock Management Module
1. Create the Module
php artisan make:module StockManagement --model=Product --api
2. Edit the Migration
// Database/Migrations/xxxx_create_products_table.php
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('sku')->unique();
$table->text('description')->nullable();
$table->decimal('price', 10, 2);
$table->integer('quantity')->default(0);
$table->timestamps();
});
3. Update the Model
// Models/Product.php
protected $fillable = [
'name',
'sku',
'description',
'price',
'quantity',
];
protected $casts = [
'price' => 'decimal:2',
];
4. Update Filament Resource
// Filament/Resources/ProductResource.php
public static function form(Form $form): Form
{
return $form->schema([
Forms\Components\TextInput::make('name')->required(),
Forms\Components\TextInput::make('sku')->required()->unique(ignoreRecord: true),
Forms\Components\Textarea::make('description'),
Forms\Components\TextInput::make('price')->numeric()->prefix('$'),
Forms\Components\TextInput::make('quantity')->numeric()->default(0),
]);
}
5. Run Migrations & Seed
php artisan migrate
php artisan db:seed --class=PermissionSeeder
6. Access
- Frontend:
http://localhost:8080/stock-management - Admin:
http://localhost:8080/admin→ Stock Management section
Best Practices
- Keep modules independent - Avoid tight coupling between modules
- Use services - Put business logic in
Services/not controllers - Define clear permissions - One permission per action
- Use policies - For complex authorization rules
- Module-specific migrations - Keep data schema with the module
- Test modules - Create tests in
tests/Modules/ModuleName/
Troubleshooting
Module not loading
- Check service provider exists and is named correctly
- Clear cache:
php artisan config:clear && php artisan cache:clear - Check
ModuleServiceProvideris inbootstrap/providers.php
Views not found
- Verify view namespace matches module slug (kebab-case)
- Check views are in
Resources/views/
Permissions not working
- Run
php artisan db:seed --class=PermissionSeeder - Clear permission cache:
php artisan permission:cache-reset - Verify user has role with permissions
Filament resources not showing
- Check resource is in
Filament/Resources/ - Verify
canAccess()returns true for your user - Clear Filament cache:
php artisan filament:cache-components