Service
What the getodden/crm-service help desk module adds on top of Core, its models, and where to read next.
getodden/crm-service is Odden's help desk module. It adds support tickets with threaded conversations, SLA policies with business hours, automatic ticket routing, canned responses, ticket merging, a public knowledge base, a token-based customer portal with CSAT surveys, an embeddable chat widget, and an email-to-ticket webhook.
The package is headless: it ships models, actions, Artisan commands, notifications, and a small set of public Blade pages and JSON endpoints for customers. It has no agent-facing UI of its own. You build agent screens in your application (or use the Filament admin, see Installation) and call the package's actions from them.
Requirements
- PHP 8.3 or later
- Laravel 12 or 13
getodden/crm-core, which provides theContactandCompanymodels, the activity timeline, and the shared route, token, and rate limit helpers. See Core.
composer require getodden/crm-service
php artisan migrateThe service provider, Odden\Service\ServiceHubServiceProvider, is auto-discovered. It loads the package migrations, registers the public routes, the odden-service:: view namespace, and two Artisan commands. See Installation for publishing config and migrations and for scheduling the commands.
What it adds to Core
Service works on Core's records rather than defining its own customers:
- Every ticket can belong to a Core
ContactandCompany. The service provider adds atickets()relationship to both models at runtime, so$contact->ticketsand$company->ticketswork without changes to Core. - When Core merges two contacts or two companies, Service moves the duplicate's tickets (soft-deleted ones included) to the surviving record, and on a contact merge its ticket messages too.
- Ticket owners, message authors, and article authors are your application's user model, resolved through Core's user model setting (see Configuration).
- Creating, routing, replying to, and resolving tickets writes notes and tasks to the contact's activity timeline.
- Customers who submit a ticket, start a chat, or email support are matched to an existing contact by email address, or a new contact is created.
Ticketuses Core'sHasCustomPropertiestrait, so you can store extra data in itspropertiescolumn withgetProperty(),setProperty(), and thewhereProperty()scope.
Models
All models are in the Odden\Service\Models namespace. Table names come from odden-service.tables (see Configuration reference).
| Model | Default table | Purpose |
|---|---|---|
Ticket |
odden_service_tickets |
A support request: number, subject, status, priority, source, contact, company, owner, SLA deadlines, CSAT rating, portal token. Soft deletes. |
TicketMessage |
odden_service_ticket_messages |
One entry in a ticket's thread: a customer message, agent reply, system message, or internal note. |
SlaPolicy |
odden_service_sla_policies |
First response and resolution targets per priority, with optional business hours and holidays. |
TicketRoutingRule |
odden_service_routing_rules |
Criteria plus a pool of users for round-robin assignment. |
CannedResponse |
odden_service_canned_responses |
A reusable reply with a title, shortcut, and category. |
KnowledgeArticle |
odden_service_articles |
A help center article with view, vote, and deflection counters. |
Enums
All enums are string-backed and live in Odden\Service\Enums.
| Enum | Cases (value) |
|---|---|
TicketStatus |
New (new), Open (open), WaitingOnCustomer (waiting_on_customer), WaitingOnAgent (waiting_on_agent), Resolved (resolved), Closed (closed) |
TicketPriority |
Low (low), Medium (medium), High (high), Urgent (urgent) |
TicketSource |
WebPortal (web_portal), Email (email), Phone (phone), Chat (chat), Api (api) |
MessageSenderType |
Agent (agent), Customer (customer), System (system) |
Each enum has a label() method. TicketStatus and TicketPriority also have color() (a Filament-style color name), and TicketPriority has weight() (1 for Low to 4 for Urgent). TicketStatus::isClosed() returns true for Resolved and Closed.
Actions
Business logic lives in action classes in Odden\Service\Actions. Resolve them from the container with app() or inject them.
| Action | What it does |
|---|---|
CreateTicketAction |
Creates a ticket, seeds the first message, routes it, logs to the contact timeline, and emails the customer. |
ReplyTicketAction |
Adds a reply or internal note and emails the customer on public agent replies. |
ResolveTicketAction |
Resolves a ticket and sends the CSAT survey email. |
RouteTicketAction |
Assigns an owner using the active routing rules. |
MergeTicketsAction |
Moves a duplicate ticket's messages into a primary ticket and closes the duplicate. |
CheckSlaBreachesAction |
Flags overdue tickets, alerts owners, and escalates unassigned tickets. |
RunServiceAutomationsAction |
Closes stale and long-resolved tickets. |
DeflectTicketAction |
Finds knowledge base articles matching a customer's question. |
Artisan commands
| Command | Purpose |
|---|---|
service:check-sla |
Runs CheckSlaBreachesAction. See SLA policies. |
service:run-automations |
Runs RunServiceAutomationsAction. See Tickets. |
Neither command is scheduled by the package. Add both to your scheduler as described in Installation.
Pages in this section
- Tickets and conversations: the ticket model, statuses, creating and replying to tickets, notifications, and automatic closing.
- SLA policies and business hours: due dates, business-hours calculation, breach checks, and alerts.
- Routing, canned responses, and merging: tools for agents working the queue.
- Email to ticket: the inbound email webhook and its API token.
- Support portal and CSAT: the public ticket form, token-based ticket pages, and satisfaction surveys.
- Chat widget: embedding the messenger and its JSON API.
- Knowledge base and deflection: articles, the help center, and article suggestions.
- Configuration reference: every config key, environment variable, route, and publish tag.