Skip to content

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 files

Creating 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.php

4. Create a Migration:

database/migrations/v1_4_0/001_create_new_entities.php

Model 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 HasUuids trait
  • Fillable: Attributes defined via #[Fillable] attribute
  • Casts: JSON columns cast to array, dates to date/datetime, enums
  • Table name: Explicit $table property (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

TopicLink
Laravel Documentationhttps://laravel.com/docs/13.x
Filament Documentationhttps://filamentphp.com/docs/5.x/panels
Pest Testinghttps://pestphp.com/docs
FrankenPHP / Octanehttps://frankenphp.dev