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 Help Desk Laravel Package

jeffersongoncalves/filament-help-desk

Filament plugins that add User, Operator, and Admin panels for ticket management on top of jeffersongoncalves/laravel-help-desk. Includes publishing for config, views, and translations. Requires PHP 8.3, Laravel 11.28, and Filament 5.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Confirm compatibility before touching composer. The plugin tracks Filament majors aggressively: 3.x requires Filament 5 / Laravel 11.28 / PHP 8.3, while 2.x is Filament 4 and 1.x is Filament 3. Match the plugin version to the Filament version already in your app — do not let Composer resolve "latest" and accidentally drag Filament forward. Features also ship per branch: the 1.10.0 release (company names, category hierarchy) landed on the 1.x line, so check the CHANGELOG.md of your own branch before assuming parity.

composer require jeffersongoncalves/filament-help-desk:^3.0

2. Install the core domain package first. This repo is only the UI layer; tickets, messages, categories, and policies live in jeffersongoncalves/laravel-help-desk. Publish and run its migrations/config before registering any panels. Some UI features have a hard floor on the core version — company names in 1.10.0 require core ^1.13, and that upgrade brings its own migration (the denormalised company_name on tickets):

composer require "jeffersongoncalves/laravel-help-desk:^1.13"
php artisan vendor:publish --tag="help-desk-migrations"   # verify the exact tag in the core README
php artisan migrate

3. Where to look first. Open the package's src/ and identify whether it ships panel providers (standalone User/Operator/Admin panels) or a Filament plugin class you attach to an existing panel. The README's Installation section is the source of truth; the class names below are typical for this author's packages, so verify them with composer show --tree jeffersongoncalves/filament-help-desk and the source tree before copying. Then register either the providers in bootstrap/providers.php, or the plugin in your panel:

// bootstrap/providers.php (if standalone panels are shipped)
return [
    App\Providers\AppServiceProvider::class,
    JeffersonGoncalves\FilamentHelpDesk\Providers\UserPanelProvider::class,
    JeffersonGoncalves\FilamentHelpDesk\Providers\OperatorPanelProvider::class,
    JeffersonGoncalves\FilamentHelpDesk\Providers\AdminPanelProvider::class,
];
// app/Providers/Filament/AdminPanelProvider.php (if it exposes a plugin)
use JeffersonGoncalves\FilamentHelpDesk\HelpDeskPlugin;

public function panel(Panel $panel): Panel
{
    return $panel->plugin(HelpDeskPlugin::make());
}

4. First use case — the three-lane workflow. End users open and reply to their own tickets in the User panel, support staff triage and respond in the Operator panel, and admins manage categories, SLAs, canned responses, and assignments in the Admin panel. Boot all three, log in as a seeded user in each, and create one ticket end-to-end. That single walkthrough will surface 90% of configuration issues (guards, panel access, policies, migrations) at once. If you support multiple companies, extend the walkthrough: seed two companies, one user with company_name and one without, and file a ticket as each — the Admin/Operator list, the company filter, and the ticket detail should all show a readable name, not a raw id.

Implementation Patterns

Separate panels, separate guards. Give each panel a distinct path (/support, /agent, /admin) and, ideally, distinct route middleware/domains. If all three share the web guard, you must implement FilamentUser::canAccessPanel() on your User model to differentiate roles:

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

Otherwise every authenticated user can reach every panel. Use spatie/laravel-permission or a single role column — the plugin does not invent a role system for you.

Multi-company portals: expose company_name on your User model. The Admin and Operator panels render the company name in the column, the filter, and the ticket detail. Provide it either as a real column or as an accessor over company_id — the accessor route is the low-effort option when you already have a Company relation:

// app/Models/User.php
protected $appends = ['company_name'];

public function getCompanyNameAttribute(): ?string
{
    return $this->company?->name;
}

Treat the ticket's company_name as a snapshot, not a lookup. The value is copied onto each ticket at creation time. That is deliberate — a ticket's history should not silently change when a company is renamed — but it means reports grouped by company name will contain both old and new spellings after a rebrand. If you need stable grouping, filter/report on company_id, and normalise the display string in a one-off backfill when you rename. Users without a company fall back to showing the raw company_id, which is your signal that data is missing rather than a rendering bug.

Lean on the category hierarchy instead of a flat taxonomy. Since 1.10, child categories are grouped under their parent in the ticket form, grandchildren render as Child › Grandchild, and a parent with active children can no longer be selected — enforced both in the form and in the plugin's server-side validation. So model your categories as: parent = grouping/display node, leaf = the only thing a user can actually file against. Seed accordingly, and give every parent at least one child, otherwise it stays selectable as a leaf. Existing tickets filed under a now-parent category are left alone on edit rather than being invalidated — keep that in mind when you re-run a category seeder on a live database.

Reuse the admin panel instead of standing up a third one. Many teams only need Operator + User panels and prefer to fold ticket administration into their existing Filament admin. Register the plugin (or just the TicketResource / CategoryResource classes) into the panel you already have, then ->navigationGroup('Help Desk') and ->navigationBadge() for open-ticket counts. This avoids three themes, three asset builds, and three login pages.

Scope widgets per panel. The bundled stats widgets are the most-edited files in real deployments. Override the query scope so the User panel only shows my tickets and the Operator panel shows my assigned queue vs. unassigned. Subclass the widget or publish views and adjust the base query; the plugin's widgets are generic by design. Multi-company installations usually want a further company_id scope here so operators don't see cross-tenant counts.

Wire notifications through Laravel, not the panel. Trigger TicketCreated / TicketReplied notifications from observers on the core models (or listen to core events) and let Filament's database notifications display them in the bell. Keep mail/queued notifications in the domain package layer so they survive an operator using the API instead of the panel.

Extend resources via configuration before subclassing. Look for configureUsing() hooks or a config file that lets you swap the resource's model, form schema, or table columns. If you need a tenant/organization filter, add a global scope on the Ticket model rather than editing the resource — it will apply everywhere (widgets, relation managers, policies) at once. Prefer that scope over hand-editing the company column/filter the plugin now ships.

Authorize with the core policies. Filament respects TicketPolicy / CategoryPolicy if they are registered and namespaced correctly. Confirm Gate::policy() bindings in the core service provider before writing custom ->authorize() closures; duplicate authorization logic is the usual cause of "operators can see tickets they shouldn't."

Gotchas and Tips

  • Low maturity — pin everything. 12 stars and 0 dependents means no community backstop. Pin both the plugin and the core package to exact minors in composer.json, and read CHANGELOG.md before every bump. Note that pinning cuts both ways: 1.10.0's company-name feature requires core ^1.13, so a plugin bump forces a coordinated core bump and migration. Be prepared to fork resources rather than wait for a fix.
  • The plugin does not ship your database. If you see "table not found" or "column not found" on the ticket list, you skipped a core migration or published a tag that doesn't exist. Upgrading core for the company-name feature but forgetting php artisan migrate is the most likely source of a new error after this release. Run php artisan vendor:publish with no tag and inspect the list of available tags.
  • Programmatic ticket creation bypasses category validation. The "parent with active children can't be picked" rule is enforced in the Filament form and the plugin's request validation — not in the model. Imports, seeders, Artisan commands, and API endpoints that create tickets directly can still file against a parent. Validate in your own form request or add a model-level guard/observer if that path exists in your app.
  • Editing a "grandfathered" ticket. Tickets filed under a category that later gained children keep it on edit, but the option won't appear in the grouped select. Test that edit-and-save flow on a real legacy ticket before assuming the category survives a round trip; if it doesn't, you'll need a fallback option or a data migration.
  • company_name missing shows the id. If Admin/Operator displays something like 42 in the company column, your User model has neither a company_name column nor an accessor. This is a display fallback, not an exception — add the accessor rather than patching the resource.
  • Panel IDs and paths collide. Filament defaults every panel to admin. If two providers both register /admin, only one wins silently. Explicitly set ->id() and ->path() on each panel.
  • canAccessPanel returning true by default. Filament's default is permissive. Always override it, and test with a non-staff account; "operator can access admin panel" is the classic first-day bug.
  • Cache and asset issues after install. Run php artisan filament:assets, php artisan optimize:clear, and php artisan filament:cache-components. If a resource disappears from navigation after a config change, clear the component cache before debugging further.
  • Version 1 → 2 → 3 are not drop-in upgrades. Each major tracks a Filament major with breaking schema/API changes. Treat migrations between them as a small project, not a composer update — and check whether a feature you're relying on (like the category grouping or company name) has been ported forward yet.
  • Debugging panels: php artisan about lists registered panel providers; an empty or duplicated entry tells you immediately that the provider wasn't autoloaded or a panel ID clashed.
  • Publish before overriding. Publish config (--tag=filament-help-desk-config) and views (--tag=filament-help-desk-views) even if you only plan to tweak one widget — it makes upgrades a diff instead of a rewrite.
  • Queue and mail must be working for ticket notifications. A silently failing MAIL_* config looks like "the plugin doesn't notify," but the panel has no involvement. Check failed_jobs first.
  • Extension points to reach for: resource subclassing, model observers, TicketPolicy, widget query overrides, and published Blade views — in that order. Avoid editing vendor/; with this package's release cadence, your patch will be overwritten.
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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings