Skip to content

A full-featured AdonisJS v6 package with Lucid models, service providers, and Inertia rendering. TypeScript-native with full type safety.

Notifications You must be signed in to change notification settings

escalated-dev/escalated-adonis

Repository files navigation

@escalated-dev/escalated-adonis

An embeddable support ticket system for AdonisJS v6 applications. Drop-in customer support with tickets, SLA management, departments, escalation rules, canned responses, macros, inbound email processing, satisfaction ratings, and a full admin panel -- all rendered via Inertia.js with Vue 3.

Requirements

  • AdonisJS v6 (Core ^6.0)
  • @adonisjs/lucid ^21.0
  • @adonisjs/auth ^9.0
  • @adonisjs/inertia ^1.0
  • @adonisjs/drive ^3.0 (for file attachments)
  • @adonisjs/mail ^9.0 (optional, for notifications)
  • Node.js 20+

Installation

npm install @escalated-dev/escalated-adonis

Then run the configure command:

node ace configure @escalated-dev/escalated-adonis

This will:

  1. Publish config/escalated.ts to your application
  2. Register the EscalatedProvider in your .adonisrc.ts
  3. Copy all database migration files to your database/migrations/ directory

Run the migrations:

node ace migration:run

Configuration

Edit config/escalated.ts to customize behavior:

const escalatedConfig: EscalatedConfig = {
  // Hosting mode: 'self-hosted' | 'synced' | 'cloud'
  mode: 'self-hosted',

  // Your app's user model import path
  userModel: '#models/user',

  // Route configuration
  routes: {
    enabled: true,
    prefix: 'support',
    middleware: ['auth'],
    adminMiddleware: ['auth'],
  },

  // Authorization callbacks
  authorization: {
    isAgent: (user) => user.isEscalatedAgent ?? false,
    isAdmin: (user) => user.isEscalatedAdmin ?? false,
  },

  // ... see config file for full options
}

Authorization

The isAgent and isAdmin callbacks determine role-based access. You can use boolean properties, methods, or any async logic:

authorization: {
  isAgent: async (user) => {
    // Check a database column
    return user.role === 'agent' || user.role === 'admin'
  },
  isAdmin: async (user) => {
    return user.role === 'admin'
  },
}

Features

v0.1.x - Core Ticket System

  • Tickets: Create, view, update, close, reopen tickets with status machine
  • Replies: Threaded conversations with rich text
  • Departments: Organize tickets by team with agent assignments
  • Tags: Label and categorize tickets
  • SLA Policies: First response and resolution time tracking with breach detection
  • Escalation Rules: Automated ticket escalation based on configurable conditions
  • Canned Responses: Pre-written reply templates (shared or per-agent)
  • Activity Log: Full audit trail of all ticket changes

v0.2.x - Enhanced Features

  • Attachments: File uploads on replies with configurable storage
  • Notifications: Webhook-based notifications with HMAC signing
  • Admin Settings: Runtime-configurable settings stored in the database
  • Guest Tickets: Anonymous ticket creation with 64-character token access

v0.3.x - Inbound Email

  • Mailgun Adapter: Receive emails via Mailgun webhooks
  • Postmark Adapter: Receive emails via Postmark inbound
  • SES Adapter: Receive emails via Amazon SES
  • Auto-threading: Emails matched to existing tickets via subject patterns and In-Reply-To headers
  • Attachment Processing: Inbound email attachments with blocked extension filtering
  • Spam Detection: Mark emails as spam

v0.4.0 - Full Feature Parity

  • Three Role Types: Customer, Agent, Admin with separate dashboards
  • Bulk Actions: Batch status/priority/assignment/tag/department changes
  • Macros: Multi-step automated actions (status + priority + reply in one click)
  • Followers: Subscribe to ticket updates
  • CSAT Ratings: Post-resolution satisfaction surveys (1-5 scale)
  • Pinned Notes: Pin important replies for quick reference
  • Quick Filters: Pre-built filter shortcuts (My Tickets, Unassigned, Breached SLA, etc.)
  • Presence Indicators: See who is viewing a ticket in real time
  • Enhanced Dashboard: Agent dashboard with workload stats and quick filters

Architecture

Models (14)

Model Table Description
Ticket escalated_tickets Core ticket with status machine, guest support
Reply escalated_replies Threaded replies with pinning and internal notes
Department escalated_departments Team organization with agent pivot
Tag escalated_tags Ticket categorization
SlaPolicy escalated_sla_policies SLA time targets per priority
EscalationRule escalated_escalation_rules Automated escalation conditions/actions
CannedResponse escalated_canned_responses Reply templates
TicketActivity escalated_ticket_activities Audit log entries
Attachment escalated_attachments File attachments (polymorphic)
Macro escalated_macros Multi-step action sequences
SatisfactionRating escalated_satisfaction_ratings CSAT ratings
InboundEmail escalated_inbound_emails Inbound email log
EscalatedSetting escalated_settings Key-value runtime settings

Services (8)

Service Description
TicketService Create, update, transition status, reply, add notes, manage tags/departments
AssignmentService Assign/unassign agents, auto-assign (least-workload strategy)
SlaService Attach policies, check breaches, calculate due dates with business hours
EscalationService Evaluate rules, find matching tickets, execute automated actions
NotificationService Send webhook notifications with HMAC-SHA256 signing
AttachmentService Store/delete file attachments via AdonisJS Drive
MacroService Execute multi-step macro actions on tickets
InboundEmailService Process inbound emails, match to tickets, create replies

Controllers (16)

Controller Role Description
CustomerTicketsController Customer List, create, view, reply, close, reopen
AgentDashboardController Agent Dashboard with stats and quick filters
AgentTicketsController Agent Full ticket management with all actions
AdminTicketsController Admin Same as agent plus delete capability
AdminDepartmentsController Admin CRUD for departments
AdminTagsController Admin CRUD for tags
AdminSlaPoliciesController Admin CRUD for SLA policies
AdminEscalationRulesController Admin CRUD for escalation rules
AdminCannedResponsesController Admin CRUD for canned responses
AdminMacrosController Admin CRUD for macros
AdminReportsController Admin Reporting dashboard
AdminSettingsController Admin Runtime settings management
BulkActionsController Agent/Admin Batch ticket operations
SatisfactionRatingController Customer Submit CSAT ratings
GuestTicketsController Public Anonymous ticket creation and viewing
InboundEmailController Webhook Process inbound email from adapters

Middleware (3)

Middleware Description
EnsureIsAgent Verifies user is an agent (or admin) via config callback
EnsureIsAdmin Verifies user is an admin via config callback
ResolveTicket Resolves ticket by reference or ID, attaches to context

Inertia Page Components

All controllers render Inertia pages with the Escalated/ prefix. Your Vue app must provide these page components:

Customer Pages

  • Escalated/Customer/Index - Ticket list
  • Escalated/Customer/Create - New ticket form
  • Escalated/Customer/Show - Ticket detail with replies

Agent Pages

  • Escalated/Agent/Dashboard - Agent dashboard
  • Escalated/Agent/Tickets/Index - Ticket list with filters
  • Escalated/Agent/Tickets/Show - Ticket detail with all actions

Admin Pages

  • Escalated/Admin/Tickets/Index - Admin ticket list
  • Escalated/Admin/Tickets/Show - Admin ticket detail
  • Escalated/Admin/Departments/Index - Departments list
  • Escalated/Admin/Departments/Create - New department
  • Escalated/Admin/Departments/Edit - Edit department
  • Escalated/Admin/Tags/Index - Tags management
  • Escalated/Admin/SlaPolicies/Index - SLA policies list
  • Escalated/Admin/SlaPolicies/Create - New SLA policy
  • Escalated/Admin/SlaPolicies/Edit - Edit SLA policy
  • Escalated/Admin/EscalationRules/Index - Escalation rules list
  • Escalated/Admin/EscalationRules/Create - New escalation rule
  • Escalated/Admin/EscalationRules/Edit - Edit escalation rule
  • Escalated/Admin/CannedResponses/Index - Canned responses
  • Escalated/Admin/Macros/Index - Macros management
  • Escalated/Admin/Reports - Reports dashboard
  • Escalated/Admin/Settings - Settings management

Guest Pages

  • Escalated/Guest/Create - Guest ticket form
  • Escalated/Guest/Show - Guest ticket view

Route Names

All routes are named with the escalated. prefix:

# Customer
escalated.customer.tickets.index
escalated.customer.tickets.create
escalated.customer.tickets.store
escalated.customer.tickets.show
escalated.customer.tickets.reply
escalated.customer.tickets.close
escalated.customer.tickets.reopen
escalated.customer.tickets.rate

# Agent
escalated.agent.dashboard
escalated.agent.tickets.index
escalated.agent.tickets.bulk
escalated.agent.tickets.show
escalated.agent.tickets.update
escalated.agent.tickets.reply
escalated.agent.tickets.note
escalated.agent.tickets.assign
escalated.agent.tickets.status
escalated.agent.tickets.priority
escalated.agent.tickets.tags
escalated.agent.tickets.department
escalated.agent.tickets.macro
escalated.agent.tickets.follow
escalated.agent.tickets.presence
escalated.agent.tickets.pin

# Admin
escalated.admin.reports
escalated.admin.tickets.index
escalated.admin.tickets.bulk
escalated.admin.tickets.show
escalated.admin.tickets.reply
escalated.admin.tickets.note
escalated.admin.tickets.assign
escalated.admin.tickets.status
escalated.admin.tickets.priority
escalated.admin.tickets.tags
escalated.admin.tickets.department
escalated.admin.tickets.macro
escalated.admin.tickets.follow
escalated.admin.tickets.presence
escalated.admin.tickets.pin
escalated.admin.settings
escalated.admin.settings.update
escalated.admin.departments.index
escalated.admin.departments.create
escalated.admin.departments.store
escalated.admin.departments.edit
escalated.admin.departments.update
escalated.admin.departments.destroy
escalated.admin.sla-policies.index
escalated.admin.sla-policies.create
escalated.admin.sla-policies.store
escalated.admin.sla-policies.edit
escalated.admin.sla-policies.update
escalated.admin.sla-policies.destroy
escalated.admin.escalation-rules.index
escalated.admin.escalation-rules.create
escalated.admin.escalation-rules.store
escalated.admin.escalation-rules.edit
escalated.admin.escalation-rules.update
escalated.admin.escalation-rules.destroy
escalated.admin.tags.index
escalated.admin.tags.store
escalated.admin.tags.update
escalated.admin.tags.destroy
escalated.admin.canned-responses.index
escalated.admin.canned-responses.store
escalated.admin.canned-responses.update
escalated.admin.canned-responses.destroy
escalated.admin.macros.index
escalated.admin.macros.store
escalated.admin.macros.update
escalated.admin.macros.destroy

# Guest (no auth)
escalated.guest.tickets.create
escalated.guest.tickets.store
escalated.guest.tickets.show
escalated.guest.tickets.reply
escalated.guest.tickets.rate

# Inbound Email (no auth)
escalated.inbound.webhook

Ticket Status Machine

Tickets follow a strict state machine:

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

Database Tables (14)

All tables use the escalated_ prefix by default (configurable):

  1. escalated_departments + escalated_department_agent pivot
  2. escalated_sla_policies
  3. escalated_tickets
  4. escalated_replies
  5. escalated_attachments
  6. escalated_tags + escalated_ticket_tag pivot
  7. escalated_ticket_activities
  8. escalated_escalation_rules
  9. escalated_canned_responses
  10. escalated_settings
  11. escalated_inbound_emails
  12. escalated_macros
  13. escalated_ticket_followers
  14. escalated_satisfaction_ratings

Shared Inertia Data

The provider automatically shares the following data via Inertia on every request:

{
  escalated: {
    prefix: 'support',           // Route prefix
    is_agent: false,             // Whether current user is an agent
    is_admin: false,             // Whether current user is an admin
    guest_tickets_enabled: true, // Whether guest tickets are enabled
  }
}

Events

The package emits the following events that you can listen to:

Event Description
escalated:ticket:created New ticket created
escalated:ticket:updated Ticket fields updated
escalated:ticket:status_changed Status transition
escalated:ticket:assigned Agent assigned
escalated:ticket:unassigned Agent unassigned
escalated:ticket:priority_changed Priority changed
escalated:ticket:department_changed Department changed
escalated:ticket:tags_added Tags added
escalated:ticket:tags_removed Tags removed
escalated:ticket:escalated Ticket escalated
escalated:ticket:resolved Ticket resolved
escalated:ticket:closed Ticket closed
escalated:ticket:reopened Ticket reopened
escalated:reply:created Reply added
escalated:note:created Internal note added
escalated:sla:breached SLA target breached
escalated:rating:created CSAT rating submitted

Inbound Email

Enable inbound email processing by setting inboundEmail.enabled: true in your config. Point your email provider's webhook to:

POST /support/inbound/mailgun
POST /support/inbound/postmark
POST /support/inbound/ses

The system will:

  1. Parse incoming email from the adapter's format
  2. Match to existing tickets via subject pattern ([ESC-00001]) or In-Reply-To/References headers
  3. Create a reply on existing tickets or create a new ticket
  4. Process attachments (with blocked extension filtering)
  5. Log the inbound email for audit trail

Using Services Directly

You can resolve services from the container for custom logic:

import app from '@adonisjs/core/services/app'

const ticketService = await app.container.make('escalated.ticketService')
const ticket = await ticketService.create({
  subject: 'Help needed',
  description: 'I have a question...',
  priority: 'medium',
  channel: 'api',
}, { id: 1, type: 'User' }) // requester

const assignmentService = await app.container.make('escalated.assignmentService')
await assignmentService.autoAssign(ticket)

Frontend Package

This package serves only the backend API via Inertia.js. The shared Vue 3 frontend components are provided by the @escalated-dev/escalated package, which is framework-agnostic and works with all Escalated backends (AdonisJS, Laravel, Rails, Django).

npm install @escalated-dev/escalated

Also Available For

Same architecture, same Vue UI, same three hosting modes — for every major backend framework.

License

MIT

About

A full-featured AdonisJS v6 package with Lucid models, service providers, and Inertia rendering. TypeScript-native with full type safety.

Resources

Stars

Watchers

Forks

Packages

No packages published