Search by

focalcrm / service

do-io

Customer Service, Help Desk, Tickets, SLAs, and Knowledge Base for Focal CRM

v0.2.3 2026-10-02 00:53 UTC

This package is auto-updated.

Last update: 2026-10-02 01:14:00 UTC


README

This is a read-only split of the focalcrm/focal monorepo. Please open issues and pull requests there.

The customer support, helpdesk, and SLA orchestration engine for the Focal RevOps platform. Delivers multi-channel ticketing (Email, Web, Chat, API), business-hours SLA policy enforcement, knowledge deflection, automated ticket routing, thread merging, and an embeddable customer portal.

Architecture & Capabilities

+-------------------------------------------------------------------------+
|                               FOCAL SERVICE                             |
|                                                                         |
|  +--------------------+   +--------------------+   +-----------------+  |
|  | Multi-Channel      |   | Inbound Webhooks & |   | Embeddable Help |  |
|  | Ticketing (Email)  |   | Thread Parsers     |   | Widget & Portal |  |
|  +--------------------+   +--------------------+   +-----------------+  |
|             \                       |                       /           |
|              v                      v                      v            |
|       +---------------------------------------------------------+       |
|       |             SLA Engine & Breach Watchdogs               |       |
|       |    (Business hours calendar, First Response & Resolv)   |       |
|       +---------------------------------------------------------+       |
|             |                       |                       |           |
|             v                       v                       v           |
|  +--------------------+   +--------------------+   +-----------------+  |
|  | Skill-Based Ticket |   | Canned Responses & |   | Knowledge Base  |  |
|  | Routing Rules      |   | Private Agent Notes|   | & Deflections   |  |
|  +--------------------+   +--------------------+   +-----------------+  |
+-------------------------------------------------------------------------+

Core Features

  • Multi-Channel Ticketing: Ingest and manage tickets from Email, Web forms, Chat widgets, Phone, or API, complete with threaded messaging and private internal notes.
  • Business-Hours SLA Policies: Configure tiered response and resolution time commitments by priority (Urgent, High, Medium, Low). Supports customizable operating hours (e.g., 9-to-5 weekdays) and holiday calendar pauses.
  • Automated SLA Breach Watchdog: Background monitor calculating time-to-first-response and time-to-resolution, dispatching proactive escalation notifications before commitments fail.
  • Intelligent Ticket Routing: Automatically assign incoming requests to the best available agent or team using keyword matching, language requirements, customer tier, or round-robin balancing.
  • Knowledge Base & Deflection Engine: Deliver customer self-service articles with keyword search. Track deflected ticket counts when articles resolve customer issues prior to submission.
  • Customer Self-Service Portal: Zero-login, tokenized customer portal allowing end-users to check status, review conversations, upload attachments, and post replies securely.
  • Embeddable Chat & Support Widget (widget.js): Lightweight, zero-dependency JavaScript drawer embeddable on any web property for on-site help, knowledge lookups, and ticket creation.
  • Thread Merging & Deduplication: Merge duplicate tickets into a primary thread while preserving all historical messages, attachments, and timestamps.
  • CSAT Survey Automation: Automatically trigger 1-click CSAT surveys upon ticket resolution to gauge customer satisfaction scores.

Installation

composer require focalcrm/service

Publish configuration and migrations:

php artisan vendor:publish --tag=focal-service-migrations
php artisan vendor:publish --tag=focal-service-config

Run migrations:

php artisan migrate

Quick Start & Code Examples

1. Creating a Ticket with SLA Assignment

use Focal\Service\Actions\CreateTicketAction;
use Focal\Service\Enums\TicketPriority;
use Focal\Service\Enums\TicketSource;

$ticket = app(CreateTicketAction::class)->execute([
    'contact_id' => $contact->id,
    'subject' => 'Production API returning 504 Gateway Timeout',
    'body' => 'Our billing batch failed at 03:00 UTC due to gateway timeouts.',
    'priority' => TicketPriority::Urgent,
    'source' => TicketSource::Email,
]);

// SLA response deadlines are automatically calculated based on the priority policy
echo "First response due: " . $ticket->first_response_due_at->toIso8601String();

2. Replying to a Ticket (Public Message vs. Private Note)

use Focal\Service\Actions\ReplyTicketAction;
use Focal\Service\Enums\MessageSenderType;

// Public response to customer (stops SLA first-response clock)
app(ReplyTicketAction::class)->execute(
    ticket: $ticket,
    body: 'We have identified an upstream cache lock and applied a hotfix. Please retry.',
    senderType: MessageSenderType::Agent,
    senderId: auth()->id(),
    isPrivate: false
);

// Private internal note between support engineers
app(ReplyTicketAction::class)->execute(
    ticket: $ticket,
    body: 'Escalated to DevOps on-call. Redis connection pool exhausted during cron.',
    senderType: MessageSenderType::Agent,
    senderId: auth()->id(),
    isPrivate: true
);

3. Merging Duplicate Tickets

use Focal\Service\Actions\MergeTicketsAction;

// Merges $duplicateTicket into $primaryTicket, moving all messages and closing the duplicate
app(MergeTicketsAction::class)->execute(
    primaryTicket: $primaryTicket,
    secondaryTicket: $duplicateTicket,
    agentId: auth()->id()
);

4. Running SLA Breach Audits

use Focal\Service\Actions\CheckSlaBreachesAction;

// Identified tickets nearing or past breach deadline; dispatches SlaBreachAlertNotification
$breachedTickets = app(CheckSlaBreachesAction::class)->execute();

// Or run via Artisan in cron:
// php artisan focal:service-check-sla

5. Embedding the Help Widget

Point the widget at the chat API base URL, including any configured prefix (defaults to the same-origin /api/service), then load resources/js/widget.js:

<script>
    window.FOCAL_CHAT_API_URL = 'https://crm.yourcompany.com/api/service';
</script>
<script src="/js/focal-chat-widget.js" async></script>

Routes

The help center (/help) and support portal (/support) are registered in the web group with no prefix by default. The inbound email webhook, knowledge deflection and chat widget APIs are registered in the api group under /api/service.

Configure them in config/focal-service.php (publish with php artisan vendor:publish --tag=focal-service-config) or through environment variables:

FOCAL_SERVICE_PREFIX=care               # /help becomes /care/help
FOCAL_SERVICE_API_PREFIX=api/service
FOCAL_SERVICE_DOMAIN=support.example.com # optional, applies to both groups
FOCAL_SERVICE_ROUTES_ENABLED=true

Each group also accepts middleware. To register the routes yourself, set routes.enabled to false and define routes with the same names (focal.help.*, focal.support.*, focal.service.*), because models, emails and notifications generate links from those names.

API tokens and rate limits

The inbound email webhook (POST /api/service/inbound-email) requires the service API token. Until FOCAL_SERVICE_API_TOKEN is set, it responds with 403 and creates no tickets.

FOCAL_SERVICE_API_TOKEN=   # e.g. php -r "echo bin2hex(random_bytes(32));"

Send it as Authorization: Bearer <token>, an X-Focal-Token header, or a ?token=<token> query parameter (for email providers that only accept a webhook URL).

The chat widget, help center votes, knowledge deflection, and support portal submissions stay public and are rate limited per IP (FOCAL_PUBLIC_RATE_LIMIT, requests per minute; see config/focal-core.php).

Data Models & Schema Reference

Model Table Responsibility
Ticket service_tickets Support tickets with priority, status, SLA deadlines, CSAT rating, and portal tokens.
TicketMessage service_ticket_messages Threaded customer messages, agent replies, and private internal notes.
SlaPolicy service_sla_policies Target resolution and response durations with business-hour definitions.
TicketRoutingRule service_ticket_routing_rules Assignment rules mapping priority, language, and keywords to agents.
KnowledgeArticle service_knowledge_articles Public self-service troubleshooting guides with deflection tracking.
CannedResponse service_canned_responses Reusable response snippets with dynamic variable interpolation.

Testing

vendor/bin/pest packages/service/tests --compact