laravel-cleanarchitecture-cqrs maintained by adityapratamaf
# Laravel Clean Architecture + CQRS Starter Template
Starter template Laravel 12 yang menggunakan **Clean Architecture + CQRS** dengan struktur yang sederhana, scalable, rapi, dan tidak over-engineered.
Template ini dirancang agar bisa digunakan untuk:
* REST API
* Web UI (Blade)
* Proyek menengah sampai terbesar
* Starter untuk microservice atau modular monolith
* Senior laravel architecture template
---
## ✨ Features
* ✅ Laravel 12
* ✅ Clean Architecture
* ✅ CQRS Pattern
* ✅ DTO-based data transfer
* ✅ CommandBus & QueryBus
* ✅ Global API Exception Handler
* ✅ Support **API** dan **Web Blade**
* ✅ Laravel Sanctum Authentication
* ✅ Custom Pagination Helper
* ✅ Custom Crypto Helper
* ✅ Modular folder structure
* ✅ Routes berada di `app/Presentation/Routes`
* ✅ Views berada di `app/Presentation/Views`
* ✅ Contoh module: **User** dan **Product** + migration + seeder
* ✅ Create new module with artisan
* ✅ Ready for Packagist template usage
---
## 📋 Requirements
* PHP `^8.2`
* Composer
* Database (MySQL/PostgreSQL/SQLite)
---
## 🧠 Clean Architecture & CQRS
### 🏛 Clean Architecture
Diperkenalkan oleh **Robert C. Martin (Uncle Bob)**.
Tujuan:
* Memisahkan business logic dari framework
* Meningkatkan testability
* Mengurangi ketergantungan pada database & UI
* Membuat sistem lebih scalable
#### 🔁 Dependency Rule
> Dependensi hanya boleh mengarah ke dalam (ke Domain).
```text
Framework / DB / UI
↓
Infrastructure
↓
Application
↓
Domain (Core Business)
```
Domain:
* Tidak tahu Laravel
* Tidak tahu HTTP
* Tidak tahu database
---
### ⚡ CQRS
Diperkenalkan oleh **Greg Young**.
Memisahkan:
* ✍ Command → Mengubah state
* 📖 Query → Mengambil data
Tujuan:
* Optimasi read & write
* Mengurangi kompleksitas
* Memudahkan scaling
---
## 🚌 CommandBus & QueryBus
Untuk menghindari tight coupling antara Controller dan Handler, digunakan mediator pattern:
* 🚌 CommandBus
* 🚌 QueryBus
### 🚌 CommandBus
Menangani operasi yang **mengubah state**.
Flow:
```text
Controller → Command → CommandBus → Handler → Repository → Database
```
Contoh:
```php
$command = new CreateUserCommand($name, $email, $password);
$this->commandBus->dispatch($command);
```
Karakteristik:
* Fokus pada perubahan data
* Tidak untuk mengambil data kompleks
* 1 Command = 1 Handler
---
### 🚌 QueryBus
Menangani operasi **read-only**.
Flow:
```text
Controller → Query → QueryBus → Handler → Read Model → Response
```
Contoh:
```php
$query = new ListUsersQuery($search, $page, $perPage);
$result = $this->queryBus->ask($query);
```
Karakteristik:
* Tidak mengubah state
* Return DTO / array / pagination
* Terpisah dari write logic
---
## 🔄 Flow CQRS
### ✍ Write Flow
1. Controller menerima request
2. Validasi via FormRequest
3. Membuat Command
4. Dispatch ke CommandBus
5. Handler memanggil Repository
6. Simpan ke database
### 📖 Read Flow
1. Controller menerima request
2. Membuat Query
3. QueryBus ask ke Handler
4. Handler ambil data
5. Return data + meta pagination
---
## 🧠 Architecture Overview
Project ini menggunakan pendekatan **Clean Architecture** dengan pembagian layer berikut:
```text
app
├── Domain
│
├── Application
│ ├── Shared
│ │ └── Bus
│ ├── User
│ │ ├── DTOs
│ │ ├── Commands
│ │ └── Queries
│ └── Product
│ ├── DTOs
│ ├── Commands
│ └── Queries
│
├── Infrastructure
│ ├── Persistence
│ │ ├── Eloquent
│ │ │ ├── Models
│ │ │ └── Repositories
│ └── Providers
│
├── Presentation
│ ├── Http
│ │ ├── Controllers
│ │ │ ├── Api
│ │ │ └── Web
│ │ ├── Requests
│ │ └── Resources
│ ├── Routes
│ │ ├── api.php
│ │ └── web.php
│ └── Views
│
└── Support
└── Helpers
🚀 1) Membuat Project dari Nol
1.1 Create Laravel project
composer create-project laravel/laravel Laravel-CleanArchitecture-CQRS-Starter-Template
cd Laravel-CleanArchitecture-CQRS-Starter-Template
1.2 Setup environment
cp .env.example .env
php artisan key:generate
1.3 Configure database
Edit .env, contoh MySQL:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=starter_template
DB_USERNAME=root
DB_PASSWORD=
🧱 2) Membuat Struktur Clean Architecture + CQRS
Jalankan perintah berikut untuk membuat folder layer dan module:
mkdir -p app/{Domain,Application,Infrastructure,Presentation,Support}
mkdir -p app/Domain/User/{Entities,Contracts}
mkdir -p app/Domain/Product/{Entities,Contracts}
mkdir -p app/Application/Shared/Bus
mkdir -p app/Application/User/{DTOs,Commands,Queries}
mkdir -p app/Application/User/Commands/{CreateUser,UpdateUser,DeleteUser}
mkdir -p app/Application/User/Queries/{GetUserById,ListUsers}
mkdir -p app/Application/Product/{DTOs,Commands,Queries}
mkdir -p app/Application/Product/Commands/{CreateProduct,UpdateProduct,DeleteProduct}
mkdir -p app/Application/Product/Queries/{GetProductById,ListProducts}
mkdir -p app/Infrastructure/Persistence/Eloquent/{Models,Repositories}
mkdir -p app/Infrastructure/Providers
mkdir -p app/Presentation/Routes
mkdir -p app/Presentation/Views/{users,products}
mkdir -p app/Presentation/Http/{Controllers,Requests,Resources}
mkdir -p app/Presentation/Http/Controllers/{Api,Web}
mkdir -p app/Presentation/Http/Requests/{User,Product}
mkdir -p app/Support/Helpers
🛣️ 3) Routing & Views dari app/Presentation
Template ini tidak menggunakan routes/web.php dan routes/api.php default.
Sebagai gantinya:
- ✅ Routes:
app/Presentation/Routes/web.phpdanapp/Presentation/Routes/api.php - ✅ Views:
app/Presentation/Views/...
3.1 Load routes dari app/Presentation/Routes
Edit file: app/Providers/RouteServiceProvider.php
Ubah method boot():
public function boot(): void
{
$this->routes(function () {
\Illuminate\Support\Facades\Route::middleware('api')
->prefix('api')
->group(app_path('Presentation/Routes/api.php'));
\Illuminate\Support\Facades\Route::middleware('web')
->group(app_path('Presentation/Routes/web.php'));
});
}
3.2 Load views dari app/Presentation/Views
Buat provider:
php artisan make:provider PresentationServiceProvider
Isi app/Infrastructure/Providers/PresentationServiceProvider.php:
<?php
namespace App\Infrastructure\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\View;
class PresentationServiceProvider extends ServiceProvider
{
public function boot(): void
{
View::addLocation(app_path('Presentation/Views'));
}
}
Daftarkan di config/app.php pada bagian providers:
App\Infrastructure\Providers\PresentationServiceProvider::class,
🚌 4) CQRS Pattern
Project ini menggunakan Command Query Responsibility Segregation (CQRS).
4.1 Command
Command digunakan untuk operasi yang mengubah data.
Contoh:
CreateUserCommand
UpdateUserCommand
DeleteUserCommand
CreateProductCommand
UpdateProductCommand
DeleteProductCommand
Setiap command akan diproses oleh handler terkait, misalnya:
CreateUserCommandHandler
CreateProductCommandHandler
4.2 Query
Query digunakan untuk operasi membaca data.
Contoh:
ListUsersQuery
GetUserByIdQuery
ListProductsQuery
GetProductByIdQuery
Setiap query akan diproses oleh handler terkait, misalnya:
ListUsersQueryHandler
GetProductByIdQueryHandler
4.3 Convention
Convention yang dipakai:
SomeCommand->SomeCommandHandlerSomeQuery->SomeQueryHandler
📦 5) DTO (Data Transfer Object)
DTO digunakan untuk mentransfer data antar layer tanpa bergantung langsung pada request atau model.
Contoh:
CreateUserDTO
UpdateUserDTO
CreateProductDTO
UpdateProductDTO
DTO membantu menjaga layer Application tetap bersih dari framework dependency.
🔄 6) Command Bus & Query Bus
Command dan Query tidak dipanggil langsung.
Controller akan menggunakan:
app/Application/Shared/Bus/CommandBus.phpapp/Application/Shared/Bus/QueryBus.php
Contoh penggunaan:
$commandBus->dispatch(new CreateUserCommand($dto));
$queryBus->ask(new ListUsersQuery());
CQRS bus pada template ini dibuat sederhana, scalable, dan mudah dipahami.
🧰 7) Helpers (Tools reusable)
Letak helper:
app/Support/Helpers/Pagination.php→ meta paginationapp/Support/Helpers/Crypto.php→ encrypt/decrypt string
Helper ini dipakai berulang kali tanpa overengineering.
Contoh helper lain yang bisa dikembangkan:
PaginationLinks
CryptoHelper
ApiResponse
🛡️ 8) API Error Handling
Project ini menggunakan Global Exception Handler untuk API.
Semua error API akan otomatis diformat menjadi struktur yang konsisten.
Contoh server error:
{
"result": false,
"code": 500,
"message": "server error",
"errors": null
}
Contoh validation error:
{
"result": false,
"code": 422,
"message": "validation error",
"errors": {
"email": ["The email field is required"]
}
}
🌐 9) Kenapa API beda dengan Web?
9.1 Web
Di Web UI, controller biasanya menggunakan try-catch.
Tujuannya:
- redirect kembali ke halaman sebelumnya
- mengirim flash message
session('error') - menampilkan alert di Blade
Contoh:
try {
$commandBus->dispatch(new CreateProductCommand($dto));
return redirect('/products')->with('success', 'Product created');
} catch (DomainException $e) {
return back()->withInput()->with('error', $e->getMessage());
}
Karena web UI perlu memberikan feedback visual ke user.
9.2 API
Pada API, exception tidak perlu ditangkap di controller.
Jika semua exception ditangkap di controller, maka akan menyebabkan:
- code menjadi repetitif
- banyak boilerplate
- response error tidak konsisten
Sebagai gantinya, project ini menggunakan Global Exception Handler.
Controller API cukup fokus pada:
- menerima request
- membuat DTO
- menjalankan command/query
- mengembalikan response sukses
Contoh:
$p = $commandBus->dispatch(new CreateProductCommand($dto));
return response()->json([
'id' => $p->id,
'name' => $p->name
]);
Jika terjadi error, global handler akan otomatis menangani response JSON.
🗃️ 10) Migrations + Seeders
10.1 Migration users & products
Buat migration jika belum ada:
php artisan make:migration create_products_table
# users table biasanya sudah ada di Laravel default
10.2 Seeder users & products
php artisan make:seeder UserSeeder
php artisan make:seeder ProductSeeder
Daftarkan di database/seeders/DatabaseSeeder.php:
public function run(): void
{
$this->call([
UserSeeder::class,
ProductSeeder::class,
]);
}
Jalankan migration dan seeder:
php artisan migrate
php artisan db:seed
Atau sekaligus fresh + seed:
php artisan migrate:fresh --seed
▶️ 11) Menjalankan Project
Clear cache dan autoload:
composer dump-autoload
php artisan optimize:clear
Jalankan server:
php artisan serve
🔐 12) Authentication
API authentication menggunakan Laravel Sanctum.
Login endpoint
POST /api/auth/login
Response contoh:
{
"token_type": "Bearer",
"token": "xxxxxx"
}
Gunakan token pada header:
Authorization: Bearer TOKEN
🌐 13) Endpoint yang tersedia
13.1 Web (Blade)
👤 Users
GET /usersGET /users/createPOST /usersGET /users/{id}GET /users/{id}/editPUT /users/{id}DELETE /users/{id}
📦 Products
GET /productsGET /products/createPOST /productsGET /products/{id}GET /products/{id}/editPUT /products/{id}DELETE /products/{id}
🔑 Auth
GET /loginPOST /logout
13.2 API (JSON)
Base prefix: /api
👤 Users
Dokumentasi Users API tetap dipertahankan dan tidak dihapus.
GET /api/usersPOST /api/usersGET /api/users/{id}PUT /api/users/{id}DELETE /api/users/{id}
📦 Products
GET /api/productsPOST /api/productsGET /api/products/{id}PUT /api/products/{id}DELETE /api/products/{id}
🔐 Auth
POST /api/auth/loginPOST /api/auth/logout
Contoh body JSON create product:
{
"name": "New Product",
"sku": "SKU-NEW-001",
"price": 150000,
"stock": 5,
"description": "test"
}
📘 14) Dokumentasi API Auth + Products (Sanctum)
Base URL:
http://localhost:8000
Kalau kamu pakai domain lain, tinggal ganti.
Catatan: Dokumentasi Users API di atas tetap berlaku dan tidak dihapus. Bagian ini adalah tambahan dokumentasi untuk Auth dan Products dengan Bearer Token.
14.1 Login (ambil token)
Endpoint
POST /api/auth/login
cURL
curl -X POST "http://localhost:8000/api/auth/login" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"email": "admin@example.com",
"password": "password123",
"device_name": "postman"
}'
Response contoh
{
"token_type": "Bearer",
"token": "1|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
Simpan nilai token untuk dipakai di request berikutnya.
14.2 Products (pakai Bearer Token)
Bagian ini berlaku jika route products dimasukkan ke group middleware auth:sanctum.
📄 14.2.1 List products
Endpoint
GET /api/products
cURL
curl -X GET "http://localhost:8000/api/products" \
-H "Accept: application/json" \
-H "Authorization: Bearer 1|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
➕ 14.2.2 Create product
Endpoint
POST /api/products
cURL
curl -X POST "http://localhost:8000/api/products" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer 1|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{
"name": "New Product",
"sku": "SKU-N-999",
"price": 150000,
"stock": 5,
"description": "test product"
}'
🔍 14.2.3 Show product
Endpoint
GET /api/products/{id}
cURL
curl -X GET "http://localhost:8000/api/products/1" \
-H "Accept: application/json" \
-H "Authorization: Bearer 1|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
✏️ 14.2.4 Update product
Endpoint
PUT /api/products/{id}
cURL
curl -X PUT "http://localhost:8000/api/products/1" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer 1|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{
"name": "Product A Updated",
"sku": "SKU-A-001",
"price": 175000,
"stock": 30,
"description": "updated"
}'
🗑️ 14.2.5 Delete product
Endpoint
DELETE /api/products/{id}
cURL
curl -X DELETE "http://localhost:8000/api/products/1" \
-H "Accept: application/json" \
-H "Authorization: Bearer 1|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
14.3 Logout (revoke token yang sedang dipakai)
Endpoint
POST /api/auth/logout
cURL
curl -X POST "http://localhost:8000/api/auth/logout" \
-H "Accept: application/json" \
-H "Authorization: Bearer 1|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Response contoh
{ "message": "Logged out" }
🧩 15) Cara Menambah Module Baru (Pattern cepat)
Checklist module baru X:
15.1 Domain
app/Domain/X/Entitiesapp/Domain/X/Contracts
15.2 Application
- DTOs:
CreateXDTO,UpdateXDTO,XDTO,PagedXDTO - Commands + Handlers: Create/Update/Delete
- Queries + Handlers: GetById/List
15.3 Infrastructure
- Eloquent model + repository implementation
15.4 Presentation
- Requests: Store/Update
- Controllers: Api + Web
- Routes: tambah di
app/Presentation/Routes/api.phpdanweb.php - Views: tambah di
app/Presentation/Views/x
15.5 Bindings
- bind repository interface → eloquent repository di
CQRSServiceProvider
📦 16) Installation
Clone project:
git clone https://github.com/your-repo/Laravel-CleanArchitecture-CQRS-Starter-Template.git
Install dependency:
composer install
Copy env:
cp .env.example .env
Generate key:
php artisan key:generate
Run migration dan seed:
php artisan migrate --seed
Run server:
php artisan serve
## 🧪 17) Menjalankan Unit Test
Project ini sudah siap untuk pengujian menggunakan **PHPUnit / Pest** bawaan Laravel.
### 17.1 Jalankan semua test
```bash
php artisan test
atau:
vendor/bin/phpunit
17.2 Jalankan test tertentu
Contoh menjalankan file test tertentu:
php artisan test tests/Feature/ProductTest.php
Atau berdasarkan nama test:
php artisan test --filter=ProductTest
17.3 Jalankan test dengan environment testing
Pastikan file .env.testing sudah disiapkan.
APP_ENV=testing
APP_KEY=base64:your-app-key
APP_DEBUG=true
DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=${DB_SECRET_DATABASE}
DB_USERNAME=${DB_SECRET_USERNAME}
DB_PASSWORD=${DB_SECRET_PASSWORD}
Generate key
php artisan key:generate --env=testing
Set secret key Database, Username & Password di terminal
export DB_SECRET_DATABASE=YOUR_NAME_DATABASE_TESTING
export DB_SECRET_USERNAME=YOUR_USERNAME_DATABASE_TESTING
export DB_SECRET_PASSWORD=YOUR_PASSWORD_DATABASE_TESTING
Contoh:
export DB_SECRET_DATABASE=db_project
export DB_SECRET_USERNAME=postgres
export DB_SECRET_PASSWORD=M3lisaMenariDiMenar@
Check key yang di buat
echo $DB_SECRET_DATABASE
echo $DB_SECRET_USERNAME
echo $DB_SECRET_PASSWORD
Lalu jalankan:
php artisan test
Laravel akan otomatis memakai environment testing saat test dijalankan.
17.4 Jalankan test setelah migrate fresh
Jika test membutuhkan database yang bersih, gunakan trait seperti:
use Illuminate\Foundation\Testing\RefreshDatabase;
Contoh:
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
class ProductTest extends TestCase
{
use RefreshDatabase;
public function test_can_list_products(): void
{
$response = $this->getJson('/api/products');
$response->assertStatus(200);
}
}
Trait RefreshDatabase akan membantu me-refresh database untuk setiap test agar data tetap konsisten.
17.5 Menjalankan test dengan coverage
Jika environment PHP kamu sudah mendukung coverage (Xdebug atau PCOV), jalankan:
php artisan test --coverage
Atau:
vendor/bin/phpunit --coverage-text
17.6 Rekomendasi struktur test
Untuk menjaga konsistensi dengan Clean Architecture + CQRS, pengujian bisa dipisah menjadi:
tests/Unit→ untuk test DTO, helper, service, handler, dan logic keciltests/Feature→ untuk test endpoint API, controller, auth, dan integrasi flow
Contoh:
tests
├── Unit
│ ├── Helpers
│ ├── DTOs
│ └── Handlers
└── Feature
├── Auth
├── User
└── Product
17.7 Contoh alur testing yang disarankan
Urutan yang umum dipakai saat development:
composer dump-autoload
php artisan optimize:clear
php artisan test
Kalau ingin memastikan database testing benar-benar bersih:
php artisan config:clear
php artisan test
📦 18) Publishing ke Packagist (Create Project)
Agar orang bisa install template ini dengan nama project custom:
composer create-project vendor/laravel-cleanarchitecture-cqrs-starter-template MyProjectName
18.1 composer.json minimal untuk template
Pastikan di root composer.json:
"type": "project""name": "vendor/laravel-cleanarchitecture-cqrs-starter-template"
Contoh:
{
"name": "vendor/laravel-cleanarchitecture-cqrs-starter-template",
"type": "project",
"description": "Laravel 12 Clean Architecture + CQRS starter template (API + Blade)",
"license": "MIT",
"require": {
"php": "^8.2",
"laravel/framework": "^12.0"
},
"autoload": {
"psr-4": {
"App\\": "app/"
}
},
"scripts": {
"post-create-project-cmd": [
"@php artisan key:generate --ansi",
"@php artisan optimize:clear --ansi"
]
}
}
18.2 Steps publish
- Push repository ke GitHub
- Daftarkan repository ke Packagist
- Buat tag release, misalnya
v1.0.0 - Packagist akan auto update
📝 19) Notes
- CQRS di template ini simple & scalable: Command/Query selalu punya Handler dan DTO.
- Tidak menggunakan package CQRS eksternal agar mudah dipahami dan minim dependency.
- Views & routes sengaja dipindah ke
app/Presentationagar konsisten dengan Clean Architecture. - Dokumentasi API Users, Auth Login/Logout, dan Products bisa dipakai sebagai dasar testing di Postman atau cURL.
- Template ini cocok dipakai sebagai base project maupun starter template open source.
📄 20) Artisan Module Generator
make:module adalah custom Artisan command untuk membantu membuat struktur module baru dengan pola:
- Clean Architecture
- CQRS
- DTO
- API Controller
- Web Controller
- Form Request
- Blade Views
Command ini dibuat untuk mempercepat pembuatan module baru tanpa harus membuat folder dan file satu per satu secara manual.
--fields--test--migration- atau tanpa opsi sama sekali
🎯 Tujuan
Generator ini membantu membuat struktur dasar module agar konsisten di seluruh project.
Cocok untuk module seperti:
- Product
- Category
- Brand
- Customer
- Supplier
- Order
Generator ini sengaja dibuat tetap sederhana, supaya:
- mudah dipahami
- mudah diubah
- tidak over-engineering
- tetap scalable untuk project besar
Karena tujuan utama template ini adalah:
- memberikan fondasi arsitektur yang rapi
- mempercepat bootstrap module
- tetap mudah dipahami oleh developer lain
- menghindari generator yang terlalu pintar tapi sulit dirawat
⚙️ Command
Basic
Membuat module tanpa migration, fields, atau test.
php artisan make:module Product
Generator akan membuat:
Domain
Application
Infrastructure
Presentation
tanpa migration dan test.
🧱 Generate Module + Fields
Jika ingin langsung membuat struktur dengan field entity.
php artisan make:module Product \
--fields="name:string,sku:string,price:decimal,stock:int"
Contoh field yang didukung:
| Type | Example |
|---|---|
| string | name:string |
| int | stock:int |
| decimal | price:decimal |
| text | description:text |
| nullable | description:text? |
Nullable menggunakan tanda ?.
Contoh:
description:text?
🧪 Generate Module + Test
Untuk membuat module sekaligus test:
php artisan make:module Product --test
Generator akan membuat:
tests/
├ Feature
│ ├ Api
│ │ └ ProductApiTest.php
│
│ └ Web
│ └ ProductWebTest.php
│
└ Unit
└ Product
└ CreateProductCommandHandlerTest.php
🗄 Generate Module + Migration
Untuk membuat module sekaligus migration:
php artisan make:module Product --migration
File migration akan dibuat di:
database/migrations
Contoh:
create_products_table.php
🚀 Generate Module Lengkap (Recommended)
Module + Fields + Test + Migration:
php artisan make:module Product \
--fields="name:string,sku:string,price:decimal,stock:int" \
--test \
--migration
Ini akan membuat:
Domain
Application
Infrastructure
Presentation
Migration
Feature Test
Unit Test
📁 Struktur yang Dibuat
Contoh struktur setelah generate module Product:
app
├ Domain
│ └ Product
│ ├ Contracts
│ │ └ ProductRepository.php
│ │
│ └ Entities
│ └ Product.php
│
├ Application
│ └ Product
│ ├ DTOs
│ ├ Commands
│ └ Queries
│
├ Infrastructure
│ └ Persistence
│ └ Eloquent
│ ├ Models
│ └ Repositories
│
└ Presentation
├ Http
│ ├ Controllers
│ │ ├ Api
│ │ └ Web
│ │
│ └ Requests
│
├ Routes
│ └ products.php
│
└ Views
└ products
🧠 Tips Penggunaan
Gunakan nama module dalam bentuk singular.
Benar:
php artisan make:module Product
Hindari:
php artisan make:module Products
Karena generator akan otomatis membuat bentuk plural untuk:
- views
- routes
- table migration
🔧 Setelah Generate Module
Setelah module dibuat, lakukan langkah berikut.
1️⃣ Tambahkan Binding Repository
Tambahkan binding di CQRSServiceProvider.
use App\Domain\Product\Contracts\ProductRepository;
use App\Infrastructure\Persistence\Eloquent\Repositories\EloquentProductRepository;
$this->app->bind(
ProductRepository::class,
EloquentProductRepository::class
);
2️⃣ Tambahkan Routes
Copy route dari:
app/Presentation/Routes/products.php
ke file:
routes/api.php
atau
routes/web.php
3️⃣ Jalankan Migration
Jika menggunakan --migration:
php artisan migrate
4️⃣ Jalankan Test
Jika menggunakan --test:
php artisan test
⚠️ Catatan
Generator ini tidak dimaksudkan menggantikan desain domain.
Gunakan generator sebagai:
- starter structure
- bootstrap module
- template awal
Setelah itu silakan:
- tambah field
- tambah business rule
- tambah validation
- tambah logic domain
sesuai kebutuhan project.
🧩 Filosofi Template Ini
Template ini dibuat dengan prinsip:
- Clean Architecture
- CQRS
- Explicit DTO
- Simple Repository Pattern
- No Magic
Dengan tujuan:
- mudah dipahami
- mudah di-scale
- mudah dirawat
- tidak over-engineered
📄 21) License
MIT License © 2026 Aditya Pratama Febriono This project is open-sourced software licensed under the MIT license.