a2zwebltd/laravel-customer-support
Portable Laravel helpdesk engine with ticketing, threaded replies, attachments, internal notes, agent assignment, SLA tracking, mail notifications, a Livewire + Flux UI, and optional Nova admin resources.
1. Whether to ship a support surface at all — and what "v1" means. This package collapses the minimum-lovable helpdesk into a scope you can defend in a single planning session: create ticket → threaded replies → attachments → internal notes → status/priority → agent assignment → SLA due date → transactional mail. That is the whole v1. Everything else (macros, CSAT, knowledge base, reporting) becomes an explicit "not yet" rather than an omission. If the decision is "we need a support inbox this quarter," this package is a roughly half-day install plus a restyle, not a two-sprint build.
2. Setting SLA policy as a config decision, not an engineering one.
SLA targets live in sla_hours keyed by priority (low/normal/high/urgent) and due_at is stamped at creation. That means "Urgent = 4h, High = 8h, Normal = 24h, Low = 72h" is a product/ops decision you can change and re-evaluate without a release. Be honest in the commitment you publish, though: the clock is wall-clock only — no business hours, no holidays, no pause while AwaitingCustomer. If you promise SLAs to customers on the back of this, either soften the language or budget custom work.
3. Sequencing the roadmap around events instead of around the core.
TicketCreated, TicketReplied, TicketStatusChanged and TicketAssigned are dispatched inside the action's transaction. That makes each downstream integration an independently scoped roadmap item rather than a fork: Slack/Teams ping for Urgent tickets, first-response-time capture for the ops dashboard, CSAT survey on Resolved, escalation webhook to an on-call tool. You can prioritise those against each other on value, and ship or drop them without touching vendor code. Treat this as the primary extensibility contract when you're deciding what's in the quarter.
4. Choosing channels deliberately.
The TicketData / MessageData DTOs plus the actions mean an inbound-email adapter or a signature-verified webhook is a ten-line adapter plus auth. So "support only from inside the app" versus "support from email too" is a product scoping choice with a small, known cost — not an architecture decision. Decide it before you size the launch, because email-as-a-channel changes your staffing and your response-time expectations far more than it changes the codebase.
5. Build vs buy, framed on the right axis. The build alternative is not zero — it's models, migrations, policies, attachment handling on a private disk, six statuses, four priorities, queued markdown mail, an agent dashboard and a customer form. Borrowing this gets you there in days. But the honest buy-side comparison is against a hosted helpdesk (Zendesk/Intercom/Freshdesk), and the axis there is capability, not effort: hosted tools bring reporting, CSAT, macros, omnichannel and business-hours SLAs on day one. This package wins when the requirement is "support inside our product, on our data, with our branding, no per-seat line item" — and loses when the requirement is "a support operation."
6. Budgeting the ownership, not just the install.
The bundled Livewire + Flux UI is a scaffold, not a design system. The realistic plan is: install, restyle the ticket views to your design language, write your own sidebar/navigation entry (the host owns nav), and decide whether to keep or replace the agent dashboard. Keep any replacement queries on the shipped scopes (open, unassigned, mine, overdue) so a package upgrade doesn't silently redefine your backlog numbers. Add a queue worker and the hourly escalation schedule as launch prerequisites — every mail is queued, so without a worker notifications silently never arrive and it reads as a package bug.
7. Instrumentation you'll want and will half-build.
A ticket has last_activity_at, due_at, status, priority, assigned_to — enough to derive first-response time, resolution time, backlog-by-status and overdue count without asking the vendor for a report. There is no reporting UI, so plan a small internal dashboard or a nightly extract to your BI tool. Decide before launch which three support metrics you'll actually review weekly; the data is there, the reporting isn't.
Adopt when all of these are true:
--color-accent tokens; without Flux you're defining those variables in light and dark yourself, and the "ready-made UI" value largely evaporates.Look elsewhere when any of these are true:
Launch risks to write down (they fail quietly, which is worse than loudly):
manage-support-tickets) must be defined — an undefined gate means nobody is an agent, and the admin dashboard just looks empty rather than erroring.attachments.disk must point at a private disk (local or private S3). Attachments are streamed through an authenticated route; don't generate public URLs.layout view must actually exist, or the Livewire pages fail on render.@source the package views, or the dashboard renders unstyled. Verify in the built CSS, don't assume.categories keys must match the TicketCategory enum values — unknown keys save as other in the form but throw in Nova.after_commit queue setting + the hourly support:escalate-overdue schedule are launch prerequisites, not nice-to-haves.To executives — one paragraph: We can stand up an in-product customer support inbox — ticket form, threaded conversation, attachments, internal agent notes, assignment, priority-based SLA timers, and queued email notifications — in days rather than a sprint or two, using an MIT-licensed Laravel package that runs entirely inside our own application. No per-seat SaaS cost, no customer data leaving our database, no new vendor in procurement. The trade-off is deliberate and worth stating plainly: we get the ticket workflow, not a support platform. Reporting, CSAT surveys, canned responses, a self-service knowledge base and business-hours SLA contracts are ours to add or to buy later. The right framing is "internal accelerator we own," not "helpdesk vendor selected." The decision I need is approval to build the minimum inbox this quarter, with the explicit understanding that SLA language we publish to customers must match what a wall-clock timer can actually measure.
To engineering — the short version:
Laravel 11/12/13, PHP 8.2+, Livewire 3/4, Tailwind v4, spatie/laravel-medialibrary for attachments, optional Nova 5 resources that auto-register. Four wiring steps: trait on User, gate definition, a layout view, Tailwind @source entries — then a queue worker and one scheduled command. The public API is five action classes (CreateTicket, ReplyToTicket, AddInternalNote, ChangeTicketStatus, AssignTicket) plus two DTOs; do not create tickets or messages directly, because SLA dates, domain events and notifications all fire from the actions. Extend via the four domain events and queue any external calls — listeners run inside the action's transaction. Attachments go to a private disk and are served through an authenticated route. Enums, factories with useful states (overdue(), urgent(), unassigned()), and model scopes for the agent tabs are all shipped, so the surface we write ourselves is: restyle the views, our own navigation entry, our own tests, and whatever reporting we want. Nothing here is a black box — worst case we read five action classes and a short config file.
How can I help you explore Laravel packages today?