Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Service Desk Laravel Package

jeffersongoncalves/filament-service-desk

A Filament plugin for laravel-service-desk that adds Admin, Agent, and User panels for full service desk management—departments, tickets, SLA policies, email channels, knowledge base, and a service catalog.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a UI layer, not a standalone app. filament-service-desk renders Filament panels on top of jeffersongoncalves/laravel-service-desk, which owns the models, migrations, and business logic. Install the core package first and confirm its tables exist before touching panel providers — otherwise you will get resource pages that boot but blow up on query.

composer require jeffersongoncalves/laravel-service-desk
composer require jeffersongoncalves/filament-service-desk:"^3.0"
php artisan vendor:publish --tag="filament-service-desk-config"
php artisan migrate

Pin the major version against your Filament install. The matrix is strict and unforgiving:

Package Filament Livewire Laravel PHP
1.x ^3.0 v3 ^10.0 ^8.1
2.x ^4.0 v3 ^11.0 ^8.2
3.x ^5.0 v4 ^11.28+ ^8.2

For most teams starting today on Filament 3 or 4, ^1.0 or ^2.0 is the practical choice; ^3.0 assumes you are already on Filament 5.

Where to look first, in order:

  1. config/filament-service-desk.php after publishing — this is the real API surface. Panel-scoped admin / agent / user keys, each with navigation, resources, widgets, plus top-level features and attachments.
  2. resources/boost/skills/filament-service-desk-development/SKILL.md and resources/boost/guidelines/core.blade.php — the maintainer ships AI-guidelines that are updated per release and are more current than the README in places.
  3. src/Admin/, src/Agent/, src/User/ — the folder split is deliberate (it fixed duplicate slug collisions in 1.0.1) and tells you exactly which resources belong to which audience.

First use case — internal desk, two panels. Do not try to ship all three panels on day one. Register an Admin panel and an Agent panel, seed a department, a category, and one SLA policy, then file a ticket from the Agent panel and watch it round-trip. That single loop exercises tickets, SLA attachment, comments, and history — the four things that break first.

// app/Providers/Filament/AdminPanelProvider.php
public function panel(Panel $panel): Panel
{
    return $panel
        ->id('admin')
        ->path('admin')
        ->plugins([
            ServiceDeskAdminPlugin::make()
                ->sla(true)
                ->emailChannels(false)   // turn on only when inbound mail is wired
                ->serviceCatalog(false)  // turn on after the catalog is seeded
                ->navigationGroup('Service Desk'),
        ]);
}

Leaving emailChannels and serviceCatalog off until the underlying data exists keeps the nav honest. Empty resource pages erode trust in a new panel faster than missing features do.

Implementation Patterns

One plugin per panel, one panel per audience. The three plugin classes are not composable — registering ServiceDeskAdminPlugin and ServiceDeskAgentPlugin on the same panel produces slug collisions on TicketResource, since each panel's resource registers its own tickets route. Use separate panel providers with distinct ->path() values (/admin, /agent, /support) and separate login flows. This also lets you apply different middleware, 2FA policies, and branding per audience — which you will want, because agents and end users have very different session-lifetime expectations.

Keep feature toggles in config, not in code. The fluent methods on the plugin and the features block in the config file both exist, and drift between them is the most likely source of "why is this nav item back?" bugs. Pick one home:

// config/filament-service-desk.php
'features' => [
    'knowledge_base'  => true,
    'sla'             => true,
    'email_channels'  => env('SERVICE_DESK_EMAIL', false),
    'service_catalog' => true,
],

Then in the panel provider use the plugin with no arguments, so environment-driven rollout (staging off, prod on) is a .env change rather than a deploy. Reserve the fluent methods for genuinely per-panel differences.

Widgets are configured as class lists, per panel. This is the cleanest extension point in the package and the one you will reach for most often. Drop the stock widgets and substitute your own:

'agent' => [
    'widgets' => [
        \App\Filament\Widgets\MyQueueBacklogWidget::class,
        \JeffersonGoncalves\FilamentServiceDesk\Agent\Widgets\SlaBreachWidget::class,
    ],
],

Set 'widgets' => [] to blank a dashboard entirely — useful for the User panel where a ticket list plus the KB is usually enough, and three stat cards are noise. Remember php artisan config:cache after edits, or you will debug a change that never loaded.

Seed in dependency order. The admin panel exposes a lot of interlinked reference data, and creating it through the UI in the wrong order is painful. Departments → categories → tags → business hours schedules (with time slots and holidays) → SLA policies (targets and escalation rules) → email channels. SLA policies reference business hours; tickets reference departments, categories, and policies. Do this in a seeder, not by hand, and reuse the seeder for tests.

Attachments need a serving story. Defaults are disk => 'local' and 10 MB, with extensions resolved to MIME types via Symfony's MimeTypes. local is not web-accessible, which is correct for support attachments but means downloads must route through a controller or a signed temporary URL. If you are on S3, switch the disk — but check whether the core package generates temporary URLs or assumes a public disk before you commit.

'attachments' => [
    'allowed_extensions' => ['jpg', 'png', 'pdf', 'docx', 'xlsx', 'csv', 'txt', 'zip'],
    'max_file_size'      => 5120,   // KB — halve the default unless you truly need 10 MB
    'disk'               => 's3',
],

Separate responsibilities by panel rather than by policy. The package already draws the lines: the Agent panel gets a Ticket Queue page for claiming unassigned tickets, and canned responses are read-only there. That means canned-response authoring is an admin activity — plan a weekly admin task or a lightweight review step, otherwise agents will ask for responses that nobody creates. Likewise, the User panel's Service Request wizard reads its fields from the Service definition, so catalog changes are admin-side work with immediate end-user impact; treat them like form schema changes.

Localization is a real feature, use it. 19 locales ship in recent 1.x releases, including pt_BR, de, fr, es, zh_CN, ar, and fa. Publish and override rather than hardcoding strings:

php artisan vendor:publish --tag="filament-service-desk-translations"

If you serve RTL locales, verify the panel's layout direction early — Filament handles it, but custom widgets that hardcode margins or icon placement usually do not.

Gotchas and Tips

The 3.2.0 rename will bite you on upgrade, and it is silent-ish. ServiceDeskPlugin became ServiceDeskAdminPlugin, the plugin ID changed from filament-service-desk to filament-service-desk-admin, and the config shape moved from feature-scoped (navigation.admin, resources.admin, widgets.admin) to panel-scoped (admin.*, agent.*, user.*). If you published the config before 3.2.0 and only updated the class name, your widgets and resources keys are silently ignored — everything falls back to defaults and nothing errors. Always republish with --force and diff:

php artisan vendor:publish --tag="filament-service-desk-config" --force
git diff config/filament-service-desk.php

Authorize the panels yourself. There is no role or permission system in this package. Filament's canAccessPanel() on your User model is the only gate, and if you leave it permissive, every authenticated user can reach /admin. Implement it explicitly before the first deploy:

public function canAccessPanel(Panel $panel): bool
{
    return match ($panel->getId()) {
        'admin' => $this->hasRole('service-desk-admin'),
        'agent' => $this->hasAnyRole(['service-desk-admin', 'service-desk-agent']),
        'user'  => true,
        default => false,
    };
}

SLA escalation and email ingestion need a running scheduler and queue. Business hours schedules, escalation rules, and email channels all imply background work living in the core package. Confirm the console kernel has the schedule registered and that schedule:run is actually executing in your environment — a container that never got a cron entry produces SLAs that never breach, which looks like "the feature works" until an auditor asks. Test it by setting a 1-minute SLA target and watching a ticket escalate.

Extensions are mapped to MIME types, so typos fail closed and quietly. Listing jpeg instead of jpg is fine, but docxx or a leading dot (.pdf) will not resolve and uploads of that type will be rejected with a validation error that points at the MIME type, not your config. Keep the list minimal and test one upload per extension after any change.

Config caching plus published translations plus panel discovery is three caches. When something "disappears," clear all of them before reading source:

php artisan config:clear && php artisan view:clear && php artisan filament:optimize-clear

Treat this as a small, single-maintainer dependency. 18 stars, zero dependents, and a version history with three breaking major bumps in a short window. Pin exact-ish constraints (^3.0 not *), commit the lock file, and write your own feature tests around the flows you depend on — ticket creation, SLA assignment, agent claim — rather than relying on the package's composer test suite to protect your upgrade path. The changelog is your early-warning system; read it before every composer update.

Extend by replacement, not by patching. Because resources are plain Filament classes registered via config, the supported customization route is: extend the resource class, override getPages() / form / table, and swap the class in the panel-scoped resources config key. Same for widgets. Avoid vendor/ edits — with this release cadence you will lose them.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log