Managing support queries efficiently is crucial for any SaaS or product-based application. If you’re building an internal tool, customer portal, or admin dashboard, a support ticket system is often a necessary feature. In this comprehensive tutorial, we’ll walk through how to build a Support Ticket System in Laravel using Filament — a powerful and elegant admin panel built on top of Laravel.
By the end of this guide, you’ll have a full-featured ticket management system with support for priorities, statuses, admin assignment, and threaded replies.
✅ Why Laravel Filament? Before diving in, here’s why Filament is a perfect choice:
🔹 Fully reactive and Tailwind-based admin UI 🔹 Fast setup with pre-built table, form, and relation managers 🔹 Highly customizable and developer-friendly 🔹 Ideal for internal tools and custom CMS interfaces🧱 Step 1: Create Models and Migrations We’ll need two models:
Ticket
– represents the main support query.TicketReply
– stores replies to a ticket.🎯 Run Artisan Commands Open your terminal and run:
Plain Bash C++ C# CSS Diff HTML/XML Java JavaScript Markdown PHP Python Ruby SQL php artisan make:model Ticket -m
php artisan make:model TicketReply -m
This will generate the models and their respective migrations.
🧾 Ticket Model Plain Bash C++ C# CSS Diff HTML/XML Java JavaScript Markdown PHP Python Ruby SQL
namespace App \Models ;
use Illuminate \Database \Eloquent \Model ;
class Ticket extends Model
{
protected $guarded = [];
public function user()
{
return $this ->belongsTo (User ::class );
}
public function assignedAdmin()
{
return $this ->belongsTo (User ::class , 'assigned_admin_id' );
}
public function replies()
{
return $this ->hasMany (TicketReply ::class );
}
}
🧾 TicketReply Model Plain Bash C++ C# CSS Diff HTML/XML Java JavaScript Markdown PHP Python Ruby SQL
namespace App \Models ;
use Illuminate \Database \Eloquent \Model ;
class TicketReply extends Model
{
protected $guarded = [];
public function ticket()
{
return $this ->belongsTo (Ticket ::class );
}
public function user()
{
return $this ->belongsTo (User ::class );
}
}
🧱 Migrations create_tickets_table.php
Plain Bash C++ C# CSS Diff HTML/XML Java JavaScript Markdown PHP Python Ruby SQL Schema ::create ('tickets' , function (Blueprint $table ) {
$table ->id ();
$table ->foreignId ('user_id' )->constrained ()->onDelete ('cascade' );
$table ->foreignId ('assigned_admin_id' )->nullable ()->constrained ('users' )->nullOnDelete ();
$table ->string ('title' );
$table ->text ('description' );
$table ->enum('status', ['open', 'in_progress', 'closed'])->default('open');
$table->enum('priority', ['low', 'medium', 'high'])->default('medium');
$table->timestamps();
});
create_ticket_replies_table.php
Plain Bash C++ C# CSS Diff HTML/XML Java JavaScript Markdown PHP Python Ruby SQL Schema ::create ('ticket_replies' , function (Blueprint $table ) {
$table ->id ();
$table ->foreignId ('ticket_id' )->constrained ()->onDelete ('cascade' );
$table ->foreignId ('user_id' )->constrained ()->onDelete ('cascade' );
$table ->text ('message' );
$table ->string ('attachment' )->nullable ();
$table ->timestamps ();
});
Run the migrations:
Plain Bash C++ C# CSS Diff HTML/XML Java JavaScript Markdown PHP Python Ruby SQL php artisan migrate
🧩 Step 2: Generate the Filament Resource Use the following command to scaffold the resource:
Plain Bash C++ C# CSS Diff HTML/XML Java JavaScript Markdown PHP Python Ruby SQL php artisan make:filament-resource Ticket
This command will generate:
TicketResource.php
Pages for listing, creating, editing Stub for relation managers🎨 Step 3: Configure Ticket Resource Update TicketResource.php
to include:
Form Schema Plain Bash C++ C# CSS Diff HTML/XML Java JavaScript Markdown PHP Python Ruby SQL public static function form(Form $form): Form
{
return $form ->schema ([
TextInput ::make ('title' )->required (),
Textarea ::make ('description' )->required ()->rows (5 ),
Select ::make ('priority' )
->options ([
'low' => 'Low' ,
'medium' => 'Medium' ,
'high' => 'High' ,
])
->default ('medium' )->required (),
Select ::make ('status' )
->options ([
'open' => 'Open' ,
'in_progress' => 'In Progress' ,
'closed' => 'Closed' ,
])
->default ('open' )->required (),
Select ::make ('assigned_admin_id' )
->label ('Assigned To' )
->relationship ('assignedAdmin' , 'name' )
->searchable ()
->preload ()
->nullable (),
]);
}
Table Columns and Reply Action Plain Bash C++ C# CSS Diff HTML/XML Java JavaScript Markdown PHP Python Ruby SQL public static function table(Table $table): Table
{
return $table
->columns ([
TextColumn ::make ('title' )->searchable ()->sortable (),
TextColumn ::make ('priority' )->badge (),
TextColumn ::make ('status' )->badge (),
TextColumn ::make ('assignedAdmin.name' )->label ('Assigned To' ),
TextColumn ::make ('created_at' )->dateTime (),
])
->actions ([
EditAction ::make (),
Action ::make ('reply' )
->label ('Reply' )
->icon ('heroicon-o-chat-bubble-left-right' )
->form ([
Textarea ::make ('message' )->label ('Your Reply' )->required ()->rows (4 ),
])
->action (function (array $data , Ticket $record ): void {
$record ->replies ()->create ([
'message' => $data ['message' ],
'user_id' => auth ()->id (),
]);
})
->modalHeading ('Reply to Ticket' )
->modalSubmitActionLabel ('Send Reply' ),
])
->bulkActions ([
DeleteBulkAction ::make (),
]);
}
➕ Step 4: Assign User on Ticket Creation Update the CreateTicket
page:
Plain Bash C++ C# CSS Diff HTML/XML Java JavaScript Markdown PHP Python Ruby SQL
class CreateTicket extends CreateRecord
{
protected static string $resource = TicketResource ::class ;
protected function mutateFormDataBeforeCreate(array $data): array
{
$data ['user_id' ] = auth ()->id ();
return $data ;
}
}
This ensures the logged-in user is automatically assigned as the ticket creator.
🔁 Step 5: Create RepliesRelationManager.php
at the below path app/Filament/Resources/TicketResource/RelationManagers/RepliesRelationManager.php
Then add the below code to it:
Plain Bash C++ C# CSS Diff HTML/XML Java JavaScript Markdown PHP Python Ruby SQL namespace App\Filament\Resources\TicketResource\RelationManagers;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables;
use Filament\Tables\Table;
class RepliesRelationManager extends RelationManager
{
protected static string $relationship = 'replies' ;
public function form(Form $form): Form
{
return $form ->schema ([
Forms\Components\Textarea ::make ('message' )
->required ()
->label ('Reply Message' ),
Forms\Components\FileUpload ::make ('attachment' )
->directory ('ticket-attachments' )
->label ('Attachment' )
->nullable (),
]);
}
public function table(Table $table): Table
{
return $table
->columns ([
Tables\Columns\TextColumn ::make ('message' )->wrap ()->limit (100 ),
Tables\Columns\TextColumn ::make ('created_at' )->dateTime ()->label ('Replied At' ),
])
->filters ([])
->headerActions ([
Tables\Actions\CreateAction ::make ()
->mutateFormDataUsing (function (array $data ): array {
$data ['user_id' ] = auth ()->id (); // Automatically assign current user to reply
return $data ;
}),
])
->actions ([
Tables\Actions\EditAction ::make (),
Tables\Actions\DeleteAction ::make (),
]);
}
}
This will allow users to post replies and attach files via the relation manager.
🔁 Step 6: Go to TicketResource.php and add the below function in that file Plain Bash C++ C# CSS Diff HTML/XML Java JavaScript Markdown PHP Python Ruby SQL public static function getRelations(): array
{
return [
\App\Filament\Resources\TicketResource\RelationManagers\RepliesRelationManager ::class ,
];
}
📖 Summary ✅ In this tutorial, we built a Laravel Filament Support Ticket System with the following features:
Ticket creation and listing Priority and status labels Admin assignment of tickets Inline ticket replies with modal forms Threaded replies with attachments via the relation manager🚀 GitHub Repository Want to explore the complete source code? Clone or star the GitHub repo below:
🔗 GitHub: https://github.com/codehunger-team/support-ticket-system-using-laravel-filament
Feel free to fork the repo, customize it, and contribute by submitting pull requests. Star ⭐ the project if it helped you!
💼 About CodeHunger Pvt Ltd This project is proudly created by CodeHunger Pvt Ltd , a Laravel and custom software development company focused on building practical and powerful web solutions.
🌐 Website: https://www.codehunger.in 📧 Contact Us: https://www.codehunger.in/contact-us 🧠 Blog: https://www.codehunger.in/blog 💬 LinkedIn: https://www.linkedin.com/company/104989660/admin/dashboard
Below I have added the screenshots of the code, how it will looks when you create one ticket system for you.
Edit and Reply Part
VIDEO