πŸ›‘οΈ

Nomanur Laravel Starter Kit

A premium, highly secure, and pre-integrated Laravel blueprint for speed-of-light administrative development.

Filament v5 Shield v4 Pest v4 Livewire V3 Format PHP 8.4 Laravel 13

πŸš€ Recent Improvements

Role Management

Integrated Filament Shield for dynamic, UI-driven permission and role management.

Queue Monitoring

Added Filament Jobs Monitor to track background job execution and failures in real-time.

Modern Livewire

Standardized on the Livewire V3 class format for all dynamic components.

User Resource

Refactored User administration with multi-role support and styled status badges.

⚑ Quick Installation & Seeding

Setting up your new application is completely automated. Run a single command to touch databases, install packages, and seed administrative access control:

# Create and boot a new project blueprint
composer create-project nomanur/nomanur-starter-kit my-app

# Boot up the concurrent dev environment (HTTP server, queues, pail log tailing)
composer run dev

πŸ”‘ Admin Login

The installation seeder creates a pre-configured Super Admin account for instant administrative dashboard access.

Login URL /admin
Username admin@admin.com
Password 12345678

*Click any value above to copy it instantly to your clipboard.

πŸ“¦ Built-in Stack Features

The starter kit combines modern packages configured with security best practices:

  • Filament PHP Panel

    A responsive dashboard designed with Filament v5.

  • Filament Shield Integration

    Dynamic role & permission management. Secured by Spatie under the hood.

  • Jobs & Queue Monitor

    Real-time queue job monitoring using Croustibat Jobs Monitor.

  • Premium User Resource

    Form-level role management and table display with primary badges.

πŸ›‘οΈ Standard Auditing & Verification

We ensure that the starter kit stays perfectly healthy, styled, and secure. Run composer test to trigger all audits:

βœ“
Pint Linting
Clean style structures
βœ“
Rector Upgrades
PHP 8.4 compliance
βœ“
PHPStan
0 errors level analysis
βœ“
Pest Tests
100% type coverage

πŸ“Έ Spatie Media Library Integration

Spatie Media Library is fully configured and integrated into the starter kit. The storage symlink is automatically generated on installation via automated composer scripts, making media immediately visualizable.

Public Previews Enabled Autolinked Symlink Demo Route: /photo

1. Enable Your Model

Implement HasMedia and use InteractsWithMedia on any Eloquent model:

// app/Models/User.php
class User extends Authenticatable implements HasMedia {
    use InteractsWithMedia;

    public function registerMediaCollections(): void {
        $this->addMediaCollection('avatars')
            ->singleFile();
    }
}

2. Upload Files via Livewire

Handle temporary files easily and attach them directly to media collections:

// app/Livewire/Test.php
class Test extends Component {
    use WithFileUploads;
    public $photo;

    public function save(): void {
        $this->validate(['photo' => 'image|max:5120']);
        $this->user->addMedia($this->photo->getRealPath())
            ->toMediaCollection('avatars');
    }
}

βœ‚οΈ Image Cropping System

The starter kit ships with a fully integrated client-side image cropping system powered by Cropper.js and Alpine.js. Users can select an image, crop it to a desired aspect ratio, and upload the cropped result β€” all before the file ever touches the server.

Client-Side Cropping Cropper.js v1.6 Alpine.js Plugin Livewire Upload Ready

How It Works

The cropping pipeline runs entirely on the client side:

  • File Selection

    User picks an image via a file input.

  • Crop Interface

    A glassmorphic modal opens with the image loaded into Cropper.js. User adjusts the crop area.

  • Canvas Extraction

    On "Apply Crop", getCroppedCanvas() extracts the selection as a canvas, then toBlob() produces a JPEG File blob.

  • Livewire Upload

    An image-cropped custom event dispatches the file. Livewire's @this.upload() receives it as a temporary upload.

  • Media Library Save

    The Livewire component validates and persists the cropped file to Spatie Media Library.

Quick Usage

Drop the Alpine component into any Livewire Blade view. The minimal setup:

<!-- resources/views/livewire/test.blade.php -->
<div
    x-data="imageCropper({ cropping: true, aspectRatio: 1 })"
    @image-cropped.window="@this.upload('photo', $event.detail.file)"
    wire:ignore
>
    <input type="file" x-ref="fileInput" @change="onFileChange" />

    <x-cropping-modal />
</div>

Click Copy full code above to copy the complete code including the reusable <x-cropping-modal /> component.

Alpine Component API

The imageCropper component accepts a config object:

// Config properties
{
  cropping: true,      // bool, default false
  aspectRatio: 1,      // number, default NaN (freeform)
}
// Methods
onFileChange(event)  // Read file & show modal
saveCrop()             // Apply, dispatch event, close
cancelCrop()           // Discard, close, clear input
clearInput()            // Reset file input value
// Events
@image-cropped="handler"
// $event.detail = { file: File, dataUrl: string }

Livewire Component

Listen for the cropped file and save to Spatie Media Library:

// app/Livewire/Test.php
class Test extends Component
{
    use WithFileUploads;

    public ?TemporaryUploadedFile $photo = null;

    public function save(): void
    {
        $this->validate([
            'photo' => ['required', 'image', 'max:5120'],
        ]);

        $this->user->addMedia($this->photo->getRealPath())
            ->toMediaCollection('avatars');
    }
}

Visit /photo on your local server to see the full cropping + upload workflow in action. The crop modal is a reusable Blade component β€” use <x-cropping-modal /> anywhere with customizable title, cancelText, and applyText props.

πŸͺ΅ Opcodes Log Viewer Integration

Opcodes Log Viewer provides a comprehensive, interactive administrative interface for inspecting application log files in real-time. Access is secured natively at the service level and dynamic in Filament sidebars.

Restricted to Super Admin Spatie Permissions Integration Sidebar Link: System > Log Viewer

1. Route Authorization

Authorized exclusively for the super_admin role inside the AppServiceProvider class:

// app/Providers/AppServiceProvider.php
private function configureLogViewer(): void {
    LogViewer::auth(function (Request $request): bool {
        return $request->user()?->hasRole('super_admin') ?? false;
    });
}

2. Filament Sidebar Permission

Visible in Filament via the view_log_viewer custom permission inside the admin panel provider:

// app/Providers/Filament/AdminPanelProvider.php
NavigationItem::make('Log Viewer')
    ->url(fn (): string => url('log-viewer'))
    ->icon('heroicon-o-document-text')
    ->group('System')
    ->visible(fn (): bool => auth()->user()?->can('view_log_viewer') ?? false)

🌐 Laravel Socialite OAuth Integration

The starter kit is fully integrated with Laravel Socialite to enable passwordless OAuth logins. The system dynamically auto-detects active providers via the SocialiteProvider enum and renders a styled list of options using a premium Livewire component.

Dynamic Auto-Detection Passwordless Login Ready Component: <livewire:socialite />

1. Add Credentials & Config

Fill in credentials inside your .env file, then uncomment the matching array inside config/services.php:

// config/services.php
'github' => [
    'client_id' => env('GITHUB_CLIENT_ID'),
    'client_secret' => env('GITHUB_CLIENT_SECRET'),
    'redirect' => '/auth/github/callback',
],

2. Drop Into Any Blade View

Use the Livewire component anywhere on your login/register pages with options to customize columns, size, and labels:

// resources/views/auth/login.blade.php
<livewire:socialite
    heading="Or continue with"
    :columns="2"
    size="md"
    :showLabels="true"
/>

🌍 Multilingual Translation & Localization System

The starter kit features a pre-configured, end-to-end multilingual and geo-location translation architecture. Combining Spatie's laravel-translatable with local Geo-IP services, administrators can manage content across multiple languages in the Filament Panel, while visitors are automatically served pages in their native tongue based on their geolocation or browser preference.

Multi-Language Tabs Geo-IP Detection Locale-Scoped Search Settings-Driven Locales Manual Switch Overrides

1. Define Translatable Models

Implement Spatie's HasTranslations trait on your Eloquent model and list the translatable columns in the $translatable property:

// app/Models/Post.php
use Illuminate\Database\Eloquent\Model;
use Spatie\Translatable\HasTranslations;

class Post extends Model {
    use HasTranslations;

    protected $fillable = ['title', 'content'];
    public array $translatable = ['title', 'content'];
}

2. Build Tabbed Forms & Search

Wrap your input schema using the custom Translatable helper. It generates beautiful, localized tabs based on active locales:

// app/Filament/Resources/Posts/Schemas/PostForm.php
use App\Filament\Forms\Components\Translatable;
use Filament\Forms\Components\TextInput;

Translatable::make(function (string $locale): array {
    return [
        TextInput::make("title.{$locale}")
            ->required(),
    ];
})

3. Geo-IP & Browser Locale Detection

The global SetLocaleMiddleware automatically intercepts web requests, queries the user's IP address, and maps country codes to active languages:

// app/Http/Middleware/SetLocaleMiddleware.php
// 1. Checks session for active locale override.
// 2. Uses laravelGeoGenius() to detect country:
$countryCode = laravelGeoGenius()->geo()
    ->getCountryCode(); // e.g., 'BD'

// 3. Fallback: Browser headers or config default.
$locale = $this->countryToLocaleMap[$countryCode]
    ?? $request->getPreferredLanguage();

4. Dynamic Admin Settings

Locales are entirely dynamic. Manage supported languages via System > Settings > Translatable Locales in the Filament Sidebar:

// Updates .env key in the dashboard
TRANSLATABLE_LOCALES=en,bn,es,fr

// Handled via AppServiceProvider & SettingsPage
config('app.translatable_locales');

// Renders locale tabs instantly in forms!

5. Implementing a Manual Language Selector

Provide manual language selection anywhere on the frontend. Define a session-setting route and display selector links:

// routes/web.php
Route::get('/language/{locale}', function ($locale) {
    if (in_array($locale, config('app.translatable_locales', ['en']))) {
        session(['locale' => $locale]);
    }
    return back();
})->name('language.switch');
// resources/views/welcome.blade.php
<div class="flex gap-4">
    <a href="{{ route('language.switch', 'en') }}">English</a>
    <a href="{{ route('language.switch', 'bn') }}">Bengali</a>
</div>

// The SetLocaleMiddleware respects this session override
// across all requests automatically!

πŸ“₯ CSV/Excel Export & Import

The starter kit ships with a reusable ExportImport trait that adds export and import buttons to any Filament resource table. It supports CSV and Excel (XLSX) formats with styled output and column selectionβ€”no additional setup required for CSV.

Zero-Dependency CSV Column Selection Modal Styled XLSX Headers Auto-Sized Columns

1. Add Trait to Resource

Use the trait in any Filament resource and override columns/query if needed:

// app/Filament/Resources/Posts/PostResource.php
class PostResource extends Resource {
    use ExportImport;

    public static function getExportColumns(): array {
        return [
            'id' => 'ID',
            'title' => 'Title',
            'content' => 'Content',
        ];
    }
}

2. Wire Actions to Table

Add export and import action buttons to the table toolbar in your table schema:

// app/Filament/Resources/Posts/Tables/PostsTable.php
public static function configure(Table $table): Table {
    return $table
        ->toolbarActions([
            PostResource::getExportAction(),
            PostResource::getImportAction(),
        ]);
}

See EXPORT_IMPORT_TRAIT.md for full documentation, including custom query filters, import file format specs, and handling translatable columns.

βš™οΈ Core Application Configurations

The AppServiceProvider is meticulously tuned for developer productivity, data integrity, and production safety. We encapsulate these configurations into dedicated, descriptive methods (configureModels, configureCommands, configureDates) to ensure global application behavior is predictable, centralized, and easy to maintain.

  • Strict Eloquent Models

    Enforced via Model::shouldBeStrict(). This prevents lazy loading, accessing missing attributes, and silent failures, catching common bugs early in development.

  • Unguarded Models

    Models are unguarded to streamline data handling. We shift safety responsibility to the entry points like Form Requests and Filament Schemas.

  • Super Admin Permissions

    An implicit Gate::before check ensures that any user with the super_admin role bypasses all permission checks, simplifying admin access management.

  • Production Protection

    We use DB::prohibitDestructiveCommands() to lock down commands like migrate:fresh in production, adding a critical safety layer against data loss.

  • Immutable Dates

    By defaulting to CarbonImmutable, we eliminate entire classes of bugs where date objects are accidentally mutated during formatting or math.

  • Architectural Clarity

    Centralizing these defaults in AppServiceProvider ensures every developer on the team follows the same rigorous standards without manual overhead.

Copied to clipboard! πŸ“‹