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

Creators Ticketing Laravel Package

daacreators/creators-ticketing

A Laravel ticketing package from DaaCreators that adds a lightweight, ready-made support helpdesk to your app. Create tickets, thread replies, track statuses, and manage customer conversations via a simple, framework-friendly API—no need to build ticketing from scratch.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and wire it up in five minutes.

composer require daacreators/creators-ticketing
php artisan vendor:publish --provider="Daacreators\CreatorsTicketing\CreatorsTicketingServiceProvider"
php artisan migrate

The vendor publish is the one step people skip and then spend an hour debugging. Publish both the config and the migrations — the service provider typically exposes tags like creators-ticketing-config, creators-ticketing-migrations, and often creators-ticketing-views. List them first rather than guessing:

php artisan vendor:publish --list | grep -i ticketing

Then register the Filament plugin on the panel that should host the helpdesk. The package is a Filament plugin, so registration happens in your PanelProvider, not in config/app.php:

public function panel(Panel $panel): Panel
{
    return $panel
        ->plugin(\Daacreators\CreatorsTicketing\CreatorsTicketingPlugin::make());
}

Where to look first, in this order:

  1. config/creators-ticketing.php — this is the real contract of the package. Anything it exposes (user model, agent model, table prefix, disks, notification channels, route prefix) is your extension surface. Read it end to end before writing a single line of code.
  2. database/migrations/ in the published folder — tells you the actual schema (tickets, ticket_messages/replies, ticket_categories, attachment tables) and therefore what you can query and report on.
  3. src/ — specifically Resources/, Models/, Policies/, and Events/. Events are where you'll hang most of your integration work.
  4. README.md — check the Filament version constraint (composer.json → filament/filament) before anything else. A ticketing plugin built against Filament v2 will not load on a v3 panel.

The first use case to ship: an internal helpdesk on your existing admin panel. One TicketResource listing tickets, a create form for end users, a reply thread, and status transitions (open → in progress → resolved → closed). Don't start with email ingestion or SLA automation — get the CRUD loop working against your real User model first, because that's where the config mismatches surface.

If the package ships a separate customer-facing panel page, resist the urge to enable both at once. Wire the admin side first, confirm the plugin registers cleanly, then expose the requester side.

Implementation Patterns

Keep the panel registration environment-aware. Ticketing UIs are usually internal. Register the plugin conditionally so you don't accidentally ship an agent-facing resource list on a public panel:

->plugin(
    CreatorsTicketingPlugin::make()
        ->visible(fn () => auth()->user()?->can('viewAny', Ticket::class))
)

Extend the models, don't fork the package. Publish the models (if supported by the publish tags) or subclass them, then point the config at your class. This is the difference between a package you can composer update and one you've permanently pinned. Typical reasons to extend: adding a team_id/tenant_id scope, adding a customer_id relationship to your own Customer model, or overriding getFilamentName().

Authorization belongs in policies, not in the resource. If the package ships a TicketPolicy, publish/override it and enforce three questions: can this user see the ticket (requester, assignee, or agent), can they reply (open, not closed), can they transition status (agent only). Multi-tenant panels leak tickets most often through the list query, not the detail view — verify the resource's getEloquentQuery() applies your tenant scope.

Automate via events, not by editing views. Look for TicketCreated, TicketReplied/MessageCreated, TicketStatusChanged, TicketAssigned. Register listeners in a small TicketingEventServiceProvider:

Event::listen(TicketCreated::class, NotifyAgentsOfNewTicket::class);
Event::listen(TicketReplied::class, SendReplyNotification::class);

Keep listeners ShouldQueue — a ticket creation request should not block on outbound mail or a Slack webhook.

Wrap the domain in a service layer for anything non-Filament. If you need an API endpoint, an artisan command, or an inbound-email webhook, don't call Filament resources or Livewire components. Create a thin TicketService that the package models support:

class TicketService
{
    public function open(User $requester, string $subject, string $body, array $attrs = []): Ticket
    {
        return DB::transaction(function () use ($requester, $subject, $body, $attrs) {
            $ticket = Ticket::create([...$attrs, 'subject' => $subject, 'user_id' => $requester->id]);
            $ticket->messages()->create(['user_id' => $requester->id, 'body' => $body]);
            event(new TicketCreated($ticket));
            return $ticket;
        });
    }
}

This is also the seam you'll use for tests, imports from an old system, and any future API.

Attachments: configure the disk explicitly. Ticketing attachments are user-uploaded and often sensitive. Set a private disk (local or S3 with no public ACL) in the config, and serve downloads through a signed route or a policy-checked controller rather than Storage::url(). Check whether the package's FileUpload component respects the config disk or hardcodes public.

Custom fields: if the package exposes a "custom fields" or metadata JSON column, prefer that over schema changes for things like environment, browser, order ID, or severity. It survives upgrades and doesn't complicate the package's migrations.

Dashboards: register the package's widgets explicitly if they aren't auto-discovered. A "tickets by status" and "unassigned tickets" widget is usually enough — don't build a BI suite on top of a 36-star package.

Testing: check whether the package ships factories (Database\Factories or src/Database/Factories). If not, write your own minimal factory against the published migrations. Tests that create a ticket through TicketService and assert the TicketCreated event fired give you far more confidence than snapshotting the Filament page.

Gotchas and Tips

Pin the version and read the source before production. 36 stars and zero dependents means the blast radius of a breaking patch release is entirely yours. Use "daacreators/creators-ticketing": "^1.0" (or an exact version), commit composer.lock, and skim src/ for anything you're depending on heavily. Budget for the possibility that you maintain a fork.

Filament major-version mismatch is the single most common install failure. Symptom: panel loads but the plugin's resources 404, or Livewire throws on a missing component class. Verify composer show daacreators/creators-ticketing against your Filament version before debugging anything else.

After any config or plugin change, clear everything. Filament caches components and icons; Livewire caches rendered components:

php artisan config:clear && php artisan cache:clear && php artisan view:clear
php artisan filament:optimize-clear   # if you've run filament:optimize

Frontend assets are a separate step — php artisan filament:assets — and a missing vendor publish is a very common "styles look broken" cause.

Migration ordering and table prefixes. Publish migrations before running migrate, and if the package's migrations reference users with a foreign key, they must run after your users table. If you have a non-standard users table name or UUID keys, expect to edit the published migrations by hand. Also check for a global table prefix in config/database.php — some packages hardcode table names.

Tenant scoping leaks. On multi-tenant panels, confirm the ticket list is scoped. The dangerous shape is a TicketResource that filters by relationship to the current user but has an agent "view all" permission path that bypasses the scope. Write one test per role that asserts the query returns only expected rows.

Polling and the reply thread. If the conversation view polls for new messages, Livewire component keys matter — a stale wire:key on the messages loop causes duplicated or missing replies after a status change. If you see "reply appears twice," it's a morph/render issue, not a database bug.

N+1 on the ticket index. The list usually eager-loads nothing by default. Add ->modifyQueryUsing(fn ($q) => $q->with(['user', 'assignee', 'latestMessage'])) on the table if the package doesn't already. A 50-row ticket list firing 150 queries is a normal finding here.

Status and priority are probably enums or constants. Find them before writing UI logic; adding a status means updating the enum, the transition rules, any badge color map, and possibly the package's own filters. Prefer adding metadata to a status over adding new statuses.

Notifications are your extension point, not the package's. Most ticketing packages notify on create and reply but not on assignment or SLA breach. Hook the events and own the notification layer — that keeps you off the package's config surface and out of its upgrade path.

Where it will fall short (plan for it): inbound email threading, SLA timers/escalation, and a real knowledge base are typically out of scope for a package this size. If your requirements include "reply by email lands in the thread," assume you'll build the inbound parser yourself and use the package only as the storage and UI layer. That's a reasonable architecture — just decide it upfront rather than discovering it in week three.

Debugging checklist when the plugin won't register: config not published → php artisan vendor:publish --list; plugin class name/FQCN wrong → composer show and grep src/*Plugin.php; panel provider not reloaded → your PanelProvider is cached by Octane/config:cache; assets missing → filament:assets; permission denied on every page → a policy is registered against a different model class than the resource uses.

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.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel