Project Structure / Struktur Proyek
Directory Layout
sutomo-school-management/
├── app/
│ ├── Filament/ # Filament panel resources
│ │ ├── Clusters/ # Panel clusters (Recruitment, System, etc.)
│ │ ├── Forms/ # Custom form components
│ │ │ ├── Components/
│ │ │ │ ├── Inputs/ # Custom input fields
│ │ │ │ ├── Selects/ # Custom select fields
│ │ │ │ └── Media/ # File upload, video, voice recorder
│ │ ├── Pages/ # Custom Filament pages
│ │ ├── Resources/ # CRUD resources (per domain)
│ │ │ ├── DomainName/
│ │ │ │ ├── ResourceNameResource.php
│ │ │ │ ├── Schemas/ # Form + Infolist schemas
│ │ │ │ ├── Tables/ # Table definitions
│ │ │ │ └── Pages/ # List, Create, Edit, View
│ │ └── Schemas/ # Shared schema components
│ ├── Http/
│ │ ├── Controllers/ # Web controllers
│ │ ├── Middleware/ # Custom middleware
│ │ └── Requests/ # Form request validation
│ ├── Models/ # Eloquent models (grouped by domain)
│ │ └── DomainName/
│ │ └── EntityName/
│ │ ├── EntityName.php
│ │ └── Concerns/
│ │ ├── HasRelations.php
│ │ ├── HasAttributes.php
│ │ ├── HasScopes.php
│ │ └── HasActions.php
│ ├── Providers/ # Service providers
│ │ └── Filament/ # Panel providers (Portal, Education, KB)
│ ├── Services/ # Business logic services
│ │ └── DomainName/ # Per-domain services
│ │ └── Screening/ # Sub-services
│ ├── Enums/ # PHP enums
│ ├── Events/ # Events
│ ├── Listeners/ # Event listeners
│ ├── Jobs/ # Queue jobs
│ ├── Mail/ # Mailables
│ ├── Notifications/ # Notification classes
│ └── Observers/ # Model observers
├── bootstrap/
│ └── providers.php # Service provider registration
├── config/ # Laravel config files
├── database/
│ ├── factories/ # Model factories
│ ├── migrations/ # Versioned migrations (v1_0_0, v1_1_0, etc.)
│ └── seeders/ # Database seeders
├── docker/ # Docker config
├── docs/ # Knowledge Base articles (Filament KB plugin)
├── handbooks/ # Vitepress technical docs
├── resources/
│ ├── css/ # Stylesheets
│ └── views/ # Blade templates
├── routes/ # Route definitions
├── tests/ # PHP tests (Pest)
│ ├── Feature/ # Feature tests
│ └── Unit/ # Unit tests
└── docker-compose*.yml # Docker Compose filesCreating a New Domain
Each domain follows a consistent pattern. To create a new domain:
1. Create the Model:
php
// app/Models/NewDomain/NewEntity/NewEntity.php
namespace App\Models\NewDomain\NewEntity;
use App\Models\NewDomain\NewEntity\Concerns\HasRelations;
use App\Models\NewDomain\NewEntity\Concerns\HasScopes;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Model;
#[Fillable(['name', 'description'])]
class NewEntity extends Model
{
use HasRelations, HasScopes, HasUuids;
protected $table = 'new_entities';
protected $casts = [
'meta' => 'array',
];
}2. Create the Relations trait:
php
// app/Models/NewDomain/NewEntity/Concerns/HasRelations.php
namespace App\Models\NewDomain\NewEntity\Concerns;
use App\Models\User;
trait HasRelations
{
public function creator()
{
return $this->belongsTo(User::class, 'created_by');
}
}3. Create the Filament Resource:
app/Filament/Resources/NewDomain/
├── NewEntityResource.php
├── Schemas/NewEntityForm.php
├── Schemas/NewEntityInfolist.php
├── Tables/NewEntityTable.php
└── Pages/
├── ListNewEntities.php
├── CreateNewEntity.php
├── ViewNewEntity.php
└── EditNewEntity.php4. Create a Migration:
database/migrations/v1_4_0/001_create_new_entities.phpModel Pattern
Every model in this project follows this pattern:
- Model: Eloquent model in
app/Models/Domain/Entity/ - Concerns: Traits for
HasRelations,HasAttributes,HasScopes - UUID: All models use
HasUuidstrait - Fillable: Attributes defined via
#[Fillable]attribute - Casts: JSON columns cast to
array, dates todate/datetime, enums - Table name: Explicit
$tableproperty (snake_case plural)
Filament Resource Pattern
Every resource follows:
php
class EntityResource extends Resource
{
protected static ?string $model = Entity::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedIcon;
protected static string|UnitEnum|null $navigationGroup = 'Group Name';
protected static ?int $navigationSort = 1;
public static function form(Schema $schema): Schema { ... }
public static function table(Table $table): Table { ... }
public static function getPages(): array { ... }
}Service Pattern
Business logic lives in app/Services/ and is injected via constructor:
php
class SomeService
{
public function __construct(
private readonly DependencyService $dependency,
) {}
public function handle(array $data): Result
{
// Business logic here
}
}Further Reading
| Topic | Link |
|---|---|
| Laravel Documentation | https://laravel.com/docs/13.x |
| Filament Documentation | https://filamentphp.com/docs/5.x/panels |
| Pest Testing | https://pestphp.com/docs |
| FrankenPHP / Octane | https://frankenphp.dev |