a2zwebltd/laravel-customer-support
Portable Laravel helpdesk engine: support tickets with threaded replies, internal notes, attachments (Spatie MediaLibrary), agent assignment, SLA due dates and escalation, mail notifications, events, policies, Livewire + Flux UI, and optional Nova resources.
Install the Package
composer require a2zwebltd/laravel-customer-support
php artisan migrate
php artisan vendor:publish --tag=customer-support-config
Add the Trait to Your User Model
// app/Models/User.php
use A2ZWeb\CustomerSupport\Concerns\HasSupportTickets;
class User extends Authenticatable implements HasMedia
{
use HasSupportTickets;
}
Define Agent Gate
// app/Providers/AppServiceProvider.php
public function boot()
{
Gate::define('manage-support-tickets', fn (User $user) => $user->is_admin);
}
Schedule SLA Escalation (Optional but Recommended)
// routes/console.php
use Illuminate\Support\Facades\Schedule;
Schedule::command('support:escalate-overdue')->hourly();
Test the UI
/support to see the public ticket interface./support/admin (if authenticated as an agent) to access the admin dashboard.Customer Submits a Ticket
/support/new and fill out the form (title, description, category, priority).SupportTicket record.mail.admin_recipients).Agent Responds
/support/admin.// In a controller or Livewire component
$ticket = auth()->user()->createTicket([
'title' => 'Issue with payment',
'description' => 'My order #12345 failed to process.',
'category_id' => 1, // e.g., "Payments"
'priority' => 'high',
]);
// Assign a ticket to an agent
$ticket->assignTo($agentUser);
// Reply to a ticket
$ticket->reply('We are investigating this issue.', [
'is_internal' => false, // Visible to customer
]);
config/customer-support.php:
'sla_hours' => [
'low' => 72, // 3 days
'normal' => 24, // 1 day
'high' => 8, // 8 hours
'urgent' => 2, // 2 hours
],
EscalateOverdueTickets command.$ticket->addMediaFromRequest('file')->toMediaCollection('ticket-attachments');
resources/views/vendor/customer-support/emails.Mail::to($ticket->user)->queue(new TicketCreated($ticket));
resources/views/vendor/customer-support/livewire.// config/customer-support.php
'theme' => [
'accent' => 'teal-500',
],
SupportTicket and SupportTicketMessage.php artisan vendor:publish --tag=customer-support-nova
// routes/api.php
Route::apiResource('tickets', \A2ZWeb\CustomerSupport\Http\Controllers\Api\TicketController::class);
// app/Models/SupportTicket.php
protected static function booted()
{
static::addGlobalScope(new TenantScope(function (Builder $builder) {
$builder->where('tenant_id', auth()->user()->tenant_id);
}));
}
Schema::table('support_tickets', function (Blueprint $table) {
$table->string('custom_field')->nullable();
});
SupportTicket model to include the new field.// app/Providers/EventServiceProvider.php
protected $listen = [
\A2ZWeb\CustomerSupport\Events\TicketCreated::class => [
\App\Listeners\LogTicketCreation::class,
],
];
// routes/console.php
Schedule::call(function () {
$overdueTickets = SupportTicket::where('due_at', '<', now())
->where('status', '!=', 'resolved')
->get();
foreach ($overdueTickets as $ticket) {
// Send escalation email or notify Slack
}
})->hourly();
Livewire Dependency
SLA Configuration Quirks
Sla model or use a package like spatie/laravel-holidays to adjust due dates dynamically.Attachment Storage
config/filesystems.php is properly configured.Email Delays
failed_jobs table and set up retries for critical emails.Nova Auto-Registration
'nova' => false in the config.Threaded Replies Pagination
SupportTicketMessage model may return large datasets if not paginated.cursor() or simplePaginate() when fetching messages in Livewire.Gate Misconfiguration
manage-support-tickets gate must be defined correctly; otherwise, agents won’t have access.php artisan gate:test manage-support-tickets.Time Zone Handling
Carbon::setToStringFormat() or middleware to standardize time zones.Ticket Not Showing in Admin Dashboard
manage-support-tickets gate.assigned_to field is populated or the ticket is unassigned.Attachments Not Uploading
config/customer-support.php for attachment settings.SLA Not Triggering
EscalateOverdueTickets command is scheduled.due_at field is calculated correctly (e.g., created_at + sla_hours).Livewire Component Errors
php artisan livewire:discover
Email Notifications Failing
php artisan queue:work
failed_jobs table for errors.How can I help you explore Laravel packages today?