nomanur / nomanur-starter-kit
The skeleton application for the Laravel framework.
Package info
Type:project
pkg:composer/nomanur/nomanur-starter-kit
Requires
- php: ^8.3
- bezhansalleh/filament-shield: ^4.2
- croustibat/filament-jobs-monitor: ^4.4
- devrabiul/laravel-geo-genius: ^1.6
- filament/filament: ^5.0
- laravel/framework: ^13.8
- laravel/socialite: ^5.27
- laravel/tinker: ^3.0
- opcodesio/log-viewer: ^3.24
- phpoffice/phpspreadsheet: ^5.7
- spatie/laravel-medialibrary: ^11.23
- spatie/laravel-translatable: ^6.14
- spatie/laravel-translation-loader: ^2.8
Requires (Dev)
- fakerphp/faker: ^1.23
- laravel/boost: ^2.0
- laravel/pail: ^1.2.5
- laravel/pao: ^1.0.6
- laravel/pint: ^1.27
- mockery/mockery: ^1.6
- nunomaduro/collision: ^8.6
- pestphp/pest: ^4.7
- pestphp/pest-plugin-laravel: ^4.1
- pestphp/pest-plugin-type-coverage: ^4.0
- phpstan/phpstan: ^2.2
- rector/rector: ^2.4
README
Nomanur Laravel Starter Kit π
Welcome to the Nomanur Laravel Starter Kitβa pre-configured, battle-tested, and production-ready Laravel application blueprint. Designed to kickstart your next application, this starter kit compiles modern admin panel tooling, dynamic role-based access control, real-time background queues monitoring, and clean testing architectures out of the box.
Key Features & Stack π¦
This starter kit comes pre-integrated with premium, industry-standard packages, configured and wired to work seamlessly together:
- Laravel 13 & PHP 8.4: Operating on the state-of-the-art core framework.
- Filament PHP v5: A beautiful, blazing-fast, and responsive administrative panel.
- Filament Shield v4: Granular role-based access control (RBAC) powered by Spatie Laravel Permission, managed entirely from the Filament dashboard.
- Filament Jobs Monitor v4: Real-time visualization and log tracking of background jobs and queue workers.
- Livewire v4 (V3 Class Format): Utilizing the stable and familiar Livewire V3 class-based component structure for dynamic interfaces.
- Pre-Built User Resource: A custom, fully secure admin interface for user accounts. Displays active roles as styled primary badges in the user table, and allows assigning/revoking roles with a multi-select interface in the user editor form.
- Pest Testing 4: Fully configured test suite with type coverage, architecture rules, and functional feature tests.
- Laravel Boost v2: Advanced AI agent capabilities for streamlined copilot development.
- Spatie Laravel Media Library v11: Battle-tested file attachments, uploads, and media collection associations on Eloquent models (e.g. User Profile Avatars).
- Opcodes Log Viewer v3: A beautiful, highly secure log-monitoring interface integrated into the Filament sidebar. Restricts access natively to Super Admins.
- CSV/Excel Export & Import: A reusable trait that adds export/import buttons to any Filament resource table, supporting CSV and XLSX formats with column selection and styled output.
π Recent Updates
- Role Management Integration: Successfully integrated Filament Shield, enabling dynamic permission and role management directly through the UI.
- Queue Monitoring: Added Filament Jobs Monitor to provide a real-time dashboard for background job execution and failure tracking.
- Enhanced User Administration: Refactored the User Resource to support multi-role assignments and improved visual representation of user status in the dashboard.
- Documentation Site: Initialized a local documentation site accessible via
docs/index.html. - Livewire Modernization: Standardized on the Livewire V3 class format to ensure long-term maintainability and performance.
- Media Library Demo Page: Fully functional Livewire and Spatie Media Library upload/gallery demo integrated at
/photowith a premium glassmorphic UI. - Secure Log Viewer: Integrated the Opcodes Log Viewer package, exposing it only to
super_adminusers via dynamic navigation sidebar elements in the Filament admin panel. - CSV/Excel Export & Import: Added a reusable
ExportImporttrait for Filament resources. Export supports CSV/XLSX with column selection; import parses uploaded files into new records with success/failure notifications.
π Spatie Media Library Integration & Demo πΈ
The starter kit comes with Spatie Media Library pre-configured and automated out of the box. The symbolic storage link (php artisan storage:link) is automatically created during installation via composer scripts.
Live Demo
Visit the route /photo on your local server to experience a premium, glassmorphic dark-theme UI featuring real-time drag-and-drop file uploads, image previews, size/mime inspections, and deletion hooks.
βοΈ 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 touches the server.
π Key Features
- Client-Side Cropping: Images are cropped entirely in the browser using Canvas API β no server round-trip needed.
- Alpine.js Integration: The cropping logic is encapsulated in a reusable
imageCropperAlpine component, making it trivial to add to any Livewire form. - Cropper.js Powered: Full-featured crop control with drag handles, zoom, aspect ratio locking, and rotation support.
- Custom Aspect Ratio: Pass any aspect ratio (e.g.,
1for square,16/9for landscape) via the Alpine component config. - Seamless Livewire Upload: The cropped file is dispatched as a standard
Fileblob via a customimage-croppedevent, which Livewire's@this.upload()picks up effortlessly. - Beautiful Crop Modal: A glassmorphic dark-theme modal overlay with smooth transitions for the crop interface.
π¨ How It Works
- User selects an image file via
<input type="file">. - The
imageCropperAlpine component reads the file as a Data URL and initializes Cropper.js on it inside a full-screen modal. - User adjusts the crop area and clicks Apply Crop.
saveCrop()usesCropper.getCroppedCanvas().toBlob()to produce a cropped JPEGFileblob.- The component dispatches an
image-croppedevent with the cropped file. - Livewire's
@this.upload('photo', $event.detail.file)uploads the cropped temporary file to the server. - The Livewire
save()method validates and persists the file to Spatie Media Library.
β‘ Quick Usage
Drop the Alpine component into any Livewire Blade view. The minimal setup:
<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>
The crop modal is a reusable Blade component at
resources/views/components/cropping-modal.blade.phpwith customizabletitle,cancelText, andapplyTextprops.
π§© Alpine Component API
The imageCropper component accepts a config object and exposes the following:
| Config | Type | Default | Description |
|---|---|---|---|
cropping |
boolean | false |
Whether to show the crop modal on load |
aspectRatio |
number | NaN |
Aspect ratio for the crop box (freeform) |
| Method | Description |
|---|---|
onFileChange(event) |
Read a file input and show the crop modal |
saveCrop() |
Apply the crop, dispatch image-cropped event, close modal |
cancelCrop() |
Discard the crop, close modal, clear input |
clearInput() |
Reset the file input value |
| Event | Detail | Description |
|---|---|---|
image-cropped |
{ file: File, dataUrl: string } |
Dispatched after crop is applied |
πΊοΈ Livewire Integration
In your Livewire component, listen for the image-cropped event and save to Spatie Media Library:
use Livewire\WithFileUploads; use Livewire\Component; 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()) ->usingFileName($this->photo->getClientOriginalName()) ->toMediaCollection('avatars'); } }
π§ Under the Hood
Alpine Plugin (resources/js/alpine-cropper.js):
- Registers an
imageCropperAlpine data component. - Manages
cropping,imageUrl, andcropperreactive state. init()watchescroppingβ whentrueandimageUrlis set, it callsinitCropper()which instantiates a newCropperinstance on the<img x-ref="cropperImage">element.onFileChange(event)reads the selected file viaFileReader, setsimageUrl, and triggers the crop modal.saveCrop()callscropper.getCroppedCanvas(), converts to blob, creates aFile, then dispatches theimage-croppedcustom event with{ file, dataUrl }.cancelCrop()destroys the cropper, hides the modal, and clears the input.
JavaScript Bootstrap (resources/js/app.js):
- Imports and registers the
imageCropperPluginviaAlpine.plugin(imageCropperPlugin).
Blade Component (resources/views/components/cropping-modal.blade.php):
- Encapsulates the glassmorphic crop modal as a reusable Laravel Blade component.
- Accepts customizable props:
title(default: "Crop Your Profile Photo"),cancelText(default: "Cancel"),applyText(default: "Apply Crop"). - Wire it into any form with
<x-cropping-modal />inside the Alpinex-data="imageCropper(...)"scope.
NPM Dependency (package.json):
"cropperjs": "^1.6.2"β the underlying crop library.
πΌοΈ Live Demo
Visit /photo on your local server to see the full cropping + upload workflow in action with a polished glassmorphic UI.
Implementation Guide & Example
1. Prepare your Eloquent Model
To allow a model to accept file attachments, implement HasMedia and use the InteractsWithMedia trait:
namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\InteractsWithMedia; class User extends Authenticatable implements HasMedia { use HasFactory, InteractsWithMedia; // Optional: Define collections public function registerMediaCollections(): void { $this->addMediaCollection('avatars') ->singleFile(); // Replaces old avatars with new uploads automatically } }
2. Livewire Component Usage
Handle incoming temporary uploads and attach them directly to your model's media collection:
namespace App\Livewire; use App\Models\User; use Livewire\Component; use Livewire\WithFileUploads; class Test extends Component { use WithFileUploads; public $photo; // Holds the TemporaryUploadedFile public User $user; public function save(): void { $this->validate([ 'photo' => ['required', 'image', 'max:5120'], // 5MB Limit ]); // Attach file to Spatie Media Library $this->user->addMedia($this->photo->getRealPath()) ->usingFileName($this->photo->getClientOriginalName()) ->toMediaCollection('avatars'); $this->photo = null; // Clear state } }
πͺ΅ Opcodes Log Viewer Integration π
The starter kit comes with Opcodes Log Viewer pre-installed and secured. It enables real-time visual inspection of application logs directly inside the Filament Admin Sidebar or at /log-viewer.
Security & Authentication
By default, the route is secured in AppServiceProvider and only accessible to users with the super_admin role. In addition, the Sidebar Navigation link is governed by Filament Shield's granular permission framework.
- Custom Permission:
view_log_vieweris registered in Filament Shield config. - Sidebar Visibility: The navigation link is hidden unless the user has the explicit
view_log_viewerpermission (which Super Admins inherit implicitly).
Direct Access
Log in to Filament as the default administrator (admin@admin.com) and navigate to System > Log Viewer in the sidebar, or go directly to:
http://127.0.0.1:8000/log-viewer
π Laravel Socialite OAuth Integration π
The starter kit comes with Laravel Socialite pre-installed and seamlessly integrated to support modern OAuth authentication. Out of the box, we support a wide range of social login providers with fully-secured backend controller handling, a dynamic SocialiteProvider Enum, and a premium Livewire utility component that auto-detects active integrations.
Supported Providers
- GitHub (
github) - Google (
google) - Facebook (
facebook) - X / Twitter (
twitter-oauth-2) - LinkedIn (
linkedin-openid) - GitLab (
gitlab) - Bitbucket (
bitbucket) - Slack (
slack-openid)
π Setup & Activation in 2 Steps
1. Add API Credentials to .env
Uncomment and populate the client IDs and secrets in your local .env file (based on the templates provided in .env.example):
# Example: Enabling GitHub Login GITHUB_CLIENT_ID=your_github_client_id GITHUB_CLIENT_SECRET=your_github_client_secret
2. Uncomment Services Configuration
Open services.php and uncomment the relevant provider array. The starter kit automatically manages redirect paths to standard callback endpoints (/auth/{provider}/callback):
'github' => [ 'client_id' => env('GITHUB_CLIENT_ID'), 'client_secret' => env('GITHUB_CLIENT_SECRET'), 'redirect' => '/auth/github/callback', ],
π¨ Livewire Component Usage
To display a stunning, fully-styled list of all configured and activated social login buttons, simply drop the Livewire component into any Blade login view:
<livewire:socialite />
Customization Options:
Customize visual layouts directly via Livewire properties:
<livewire:socialite heading="Login with your social profile" :showLabels="true" :columns="2" size="lg" />
π οΈ Architecture & Under the Hood
Key database updates and unified routing patterns power the passwordless authentication lifecycle cleanly. Active integrations are listed dynamically in view elements.
π Multilingual Spatie Translatable & Localization System π
The starter kit features a pre-wired, high-performance multilingual translation and localization architecture. Combining Spatie's laravel-translatable with automated Geo-IP services and browser-header detection, administrators can manage content dynamically in the Filament Panel, while visitors are automatically served pages in their native tongue based on their location or browser preference.
π Key Features
- Geo-IP Language Detection: The application queries the visitor's IP address dynamically using
devrabiul/laravel-geo-geniusto detect their country and auto-serve pages in their native language (e.g., visitors from Bangladesh automatically see Bengali content). - Preferred Browser Fallback: If the geolocation lookup is inconclusive, the system seamlessly inspects browser headers to detect preferred languages, falling back gracefully to the application default (
en). - Session-Persistent Overrides: Manual language switching is fully supported. Toggling a language updates the user's session locale (
locale), which takes full precedence over automatic detection. - Tabbed Form Interface: The custom
Translatablecomponent automatically partitions inputs (like Title, Content) into beautiful language tabs based on active locales. - Settings-Driven Locales: Manage the list of active translation languages dynamically inside
.envor from System > Settings > Translatable Locales in the Filament Sidebar. - Locale-Scoped Search: Column search is fully localized. Searching in Filament tables scopes filters to the current user's active locale's JSON database path (
title->en), preventing invalid language matches and SQL performance issues.
π¨ How to Use
1. Define Translatable Models
Use the HasTranslations trait and specify which columns support translations in your Eloquent model:
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Spatie\Translatable\HasTranslations; class Post extends Model { use HasTranslations; protected $fillable = ['title', 'content']; // Define translatable columns public array $translatable = ['title', 'content']; }
2. Configure Form Fields
Wrap your input fields inside the custom Translatable::make component in your Filament form schema:
use App\Filament\Forms\Components\Translatable; use Filament\Forms\Components\Textarea; use Filament\Forms\Components\TextInput; Translatable::make(function (string $locale): array { $suffix = ' (' . strtoupper($locale) . ')'; return [ TextInput::make("title.{$locale}") ->label('Title' . $suffix) ->required() ->maxLength(255), Textarea::make("content.{$locale}") ->label('Content' . $suffix) ->rows(5), ]; })
3. Enable Locale-Scoped Search in Tables
To ensure high-performance, locale-isolated table searches, configure the searchable method with a scoped query:
use Filament\Tables\Columns\TextColumn; use Illuminate\Database\Eloquent\Builder; TextColumn::make('title') ->searchable(query: function (Builder $query, string $search): Builder { return $query->where('title->' . app()->getLocale(), 'like', "%{$search}%"); })
4. Automatic Localization Middleware (SetLocaleMiddleware)
The global SetLocaleMiddleware is automatically appended to the web middleware group inside bootstrap/app.php. It handles country-to-locale mapping, browser header inspections, and session persistence:
// app/Http/Middleware/SetLocaleMiddleware.php protected array $countryToLocaleMap = [ 'BD' => 'bn', // Bangladesh -> Bengali 'IN' => 'hi', // India -> Hindi 'US' => 'en', // United States -> English // ... easily expandable country-to-locale array ];
5. Implementing a Manual Language Selector
To allow users to manually switch languages on the frontend, define a session-setting route and display selector links:
Step A: Define the route in routes/web.php:
use Illuminate\Support\Facades\Route; Route::get('/language/{locale}', function (string $locale) { if (in_array($locale, config('app.translatable_locales', ['en']))) { session(['locale' => $locale]); } return back(); })->name('language.switch');
Step B: Add a language selector component in your blade template:
<div class="flex gap-4 items-center"> <a href="{{ route('language.switch', 'en') }}" class="{{ app()->getLocale() === 'en' ? 'font-bold' : '' }}">English</a> <a href="{{ route('language.switch', 'bn') }}" class="{{ app()->getLocale() === 'bn' ? 'font-bold' : '' }}">বাΰ¦ΰ¦²ΰ¦Ύ</a> </div>
The SetLocaleMiddleware automatically intercepts all incoming requests, detects the session key, and sets the active application locale globally.
π₯ CSV/Excel Export & Import π€
The starter kit includes a reusable ExportImport trait (app/Traits/ExportImport.php) that adds export and import buttons to any Filament resource table. It supports CSV and Excel (XLSX) formats with styled output and column selection.
π Key Features
- Export: Modal dialog with format selection (CSV/XLSX) and column checklist. Exported rows are streamed directly to the browser.
- Import: File upload modal supporting CSV and XLSX files. Headers auto-map to database columns. Records are created with per-row error handling.
- Customizable Columns: Override
getExportColumns()to define which columns appear in the export modal. - Customizable Query: Override
getExportQuery()to filter which records are exported (e.g. only published posts). - UTF-8 & Styling: CSV files include a UTF-8 BOM; Excel files get auto-sized columns with styled headers (bold + gray background).
- Excel Fallback: If
phpoffice/phpspreadsheetis not installed, Excel exports gracefully fall back to CSV.
π¨ How to Use
1. Add the Trait to Your Resource
use App\Traits\ExportImport; class PostResource extends Resource { use ExportImport; }
2. Wire Actions to Your Table
use App\Filament\Resources\Posts\PostResource; public static function configure(Table $table): Table { return $table ->toolbarActions([ PostResource::getExportAction(), PostResource::getImportAction(), ]); }
3. Customize Export Columns (Optional)
public static function getExportColumns(): array { return [ 'id' => 'ID', 'title' => 'Title', 'content' => 'Content', 'created_at' => 'Created At', 'updated_at' => 'Updated At', ]; }
4. Customize Export Query (Optional)
public static function getExportQuery() { return static::getModel()::query()->where('status', 'published'); }
π Import CSV Format
Headers in your CSV/XLSX file should match the database column names. Example:
title,content My First Post,This is the content of the post. My Second Post,More content here.
β‘ Quick Installation
You can create a new project using this starter kit with a single Composer command:
composer create-project nomanur/nomanur-starter-kit my-app
During installation, the project automatically runs the setup scripts to:
- Copy the
.env.examplefile to.envdynamically. - Generate the application encryption key.
- Automatically touch and initialize a local SQLite database (
database/database.sqlite). - Run all database migrations and seeds, including Filament Shield registration, creating default admin credentials, and seeding fake users.
π Default Credentials
Once the installation finishes, you can immediately log into the Filament administrative dashboard at /admin using these default credentials:
- Dashboard URL:
http://127.0.0.1:8000/admin - Username:
admin@admin.com - Password:
12345678
Note: In addition to the main administrator, the setup seeder automatically seeds 2 additional fake users for immediate local data visualization in the User Resource table.
π οΈ Developer Commands
Use these built-in Composer script commands to manage your local environment:
Run Local Development Server
Start the HTTP server, queue listener, log tailing, and frontend bundlers concurrently:
composer run dev
Run Tests and Quality Audits
Verify Pint formatting, Rector refactoring rules, PHPStan static analyses, type coverage, and all unit/feature tests:
composer test
Auto-Format Code Styles
Run Laravel Pint to automatically clean up and align formatting:
composer lint
Auto-Refactor Code
Run Rector to safely upgrade PHP codebases in line with modern programming features:
composer refactor
π‘οΈ License
The Nomanur Laravel Starter Kit is open-sourced software licensed under the MIT license.