العربية • Deutsch • English • Español • Français • Italiano • 日本語 • 한국어 • Nederlands • Polski • Português (BR) • Русский • Türkçe • 简体中文
An embeddable support ticket system for Symfony applications. Drop-in helpdesk with tickets, replies, departments, tags, SLA policies, and role-based access control.
- PHP 8.2+
- Symfony 6.4 or 7.x
- Doctrine ORM 2.17+ / 3.x
- Doctrine Migrations Bundle
composer require escalated-dev/escalated-symfonyIf Symfony Flex is installed, the bundle is registered automatically. Otherwise, add it to config/bundles.php:
return [
// ...
Escalated\Symfony\EscalatedBundle::class => ['all' => true],
];Create config/packages/escalated.yaml:
escalated:
user_class: App\Entity\User
route_prefix: /support
ui_enabled: true
table_prefix: escalated_
tickets:
allow_customer_close: true
default_priority: medium
sla:
enabled: true
business_hours_only: false
business_hours:
start: '09:00'
end: '17:00'
timezone: UTC
days: [1, 2, 3, 4, 5]php bin/console doctrine:migrations:migrateThe migration creates all necessary tables (escalated_tickets, escalated_replies, escalated_departments, escalated_tags, escalated_sla_policies, escalated_ticket_activities, escalated_agent_profiles).
Add the ROLE_ESCALATED_ADMIN role to admin users in your user provider. Agent access is determined by the presence of an AgentProfile entity linked to the user.
# config/packages/security.yaml
security:
role_hierarchy:
ROLE_ESCALATED_ADMIN: ROLE_USERFor the built-in frontend UI, install an Inertia bundle:
composer require rompetomp/inertia-bundle
# or
composer require skipthedragon/inertia-bundleSet ui_enabled: false if you want to use only the API and services with a custom frontend.
- Ticket lifecycle — Create, assign, reply, resolve, close, reopen with configurable status transitions
- SLA engine — Per-priority response and resolution targets, business hours calculation, automatic breach detection
- Agent dashboard — Ticket queue with filters, internal notes, canned responses
- Customer portal — Self-service ticket creation, replies, and status tracking
- Admin panel — Manage departments, SLA policies, tags, and view reports
- File attachments — Drag-and-drop uploads with configurable storage and size limits
- Activity timeline — Full audit log of every action on every ticket
- Email notifications — Configurable per-event notifications
- Department routing — Organize agents into departments with auto-assignment
- Tagging system — Categorize tickets with colored tags
- Ticket splitting — Split a reply into a new standalone ticket while preserving the original context
- Ticket snooze — Snooze tickets with presets (1h, 4h, tomorrow, next week);
php bin/console escalated:wake-snoozed-ticketsConsole command auto-wakes them on schedule - Saved views / custom queues — Save, name, and share filter presets as reusable ticket views
- Embeddable support widget — Lightweight
<script>widget with KB search, ticket form, and status check - Email threading — Outbound emails include proper
In-Reply-ToandReferencesheaders for correct threading in mail clients - Branded email templates — Configurable logo, primary color, and footer text for all outbound emails
- Real-time broadcasting — Opt-in broadcasting via Mercure with automatic polling fallback
- Knowledge base toggle — Enable or disable the public knowledge base from admin settings
| Entity | Description |
|---|---|
Ticket |
Support ticket with status, priority, SLA tracking |
Reply |
Public reply or internal note on a ticket |
Department |
Organizational grouping for tickets and agents |
Tag |
Labels for categorizing tickets |
SlaPolicy |
First response and resolution time targets per priority |
TicketActivity |
Audit log of all ticket changes |
AgentProfile |
Agent metadata (type, capacity) |
| Service | Description |
|---|---|
TicketService |
Create, update, transition, reply to tickets |
AssignmentService |
Assign/unassign agents, check workload |
SlaService |
Attach SLA policies, check for breaches |
Routes are organized into four groups, all under the configured route_prefix:
- Customer (
/customer/tickets) -- Ticket CRUD for authenticated end-users - Agent (
/agent) -- Dashboard and ticket management for support agents - Admin (
/admin) -- Full management of tickets, departments, tags, settings - API (
/api/v1) -- JSON REST API for external integrations
The admin area includes a runtime settings page at /admin/settings/public-tickets (PublicTicketsSettingsController) for switching the guest-policy mode — unassigned, guest_user, or prompt_signup — without a redeploy. See docs.escalated.dev/public-tickets.
Two Symfony voters control access:
ESCALATED_AGENT-- Granted when the user has anAgentProfilerecordESCALATED_ADMIN-- Granted when the user has theROLE_ESCALATED_ADMINrole
Controllers use UiRendererInterface to render pages. The default InertiaUiRenderer delegates to whichever Inertia bundle is installed. To use Twig or another renderer, implement UiRendererInterface and override the service in your container config:
services:
Escalated\Symfony\Rendering\UiRendererInterface:
class: App\Rendering\TwigUiRendererTickets follow a state machine with these transitions:
open -> in_progress, waiting_on_customer, waiting_on_agent, escalated, resolved, closed
in_progress -> waiting_on_customer, waiting_on_agent, escalated, resolved, closed
waiting_on_customer -> open, in_progress, resolved, closed
waiting_on_agent -> open, in_progress, escalated, resolved, closed
escalated -> in_progress, resolved, closed
resolved -> reopened, closed
closed -> reopened
reopened -> in_progress, waiting_on_customer, waiting_on_agent, escalated, resolved, closed
Escalated bundles ship their UI strings from a single source of truth:
escalated-dev/locale.
The package is pulled in as a Composer dependency and its translations/
directory is prepended onto framework.translator.paths automatically by
the bundle's prependExtension hook.
The plugin-local translations/ directory and your application's
translations/ directory both override the central package on a key-by-key
basis. To override a single string, drop a messages.<locale>.yaml file
into your app's translations/ directory with only the keys you want to
change — Symfony will merge the rest from the central package.
vendor/bin/phpunitMIT