Skip to content

Latest commit

 

History

History
440 lines (340 loc) · 15.8 KB

README.pt-BR.md

File metadata and controls

440 lines (340 loc) · 15.8 KB

العربية • Deutsch • English • Español • Français • Italiano • 日本語 • 한국어 • Nederlands • Polski • Português (BR) • Русский • Türkçe • 简体中文

Escalated for Rails

Tests FOSSA Status Ruby Rails License: MIT

Um sistema de tickets de suporte completo e integrável para Rails. Adicione-o a qualquer aplicação — obtenha um helpdesk completo com rastreamento de SLA, regras de escalonamento, fluxos de trabalho de agentes e um portal do cliente. Nenhum serviço externo necessário.

escalated.dev — Saiba mais, veja demos e compare as opções Cloud vs Auto-hospedado.

Três modos de hospedagem. Execute totalmente auto-hospedado, sincronize com uma nuvem central para visibilidade multi-aplicação, ou redirecione tudo para a nuvem. Mude de modo com uma única alteração de configuração.

Funcionalidades

  • Ciclo de vida do ticket — Criar, atribuir, responder, resolver, fechar, reabrir com transições de status configuráveis
  • Motor de SLA — Metas de resposta e resolução por prioridade, cálculo de horário comercial, detecção automática de violações
  • Regras de escalonamento — Regras baseadas em condições que escalonam, repriorizam, reatribuem ou notificam automaticamente
  • Painel do agente — Fila de tickets com filtros, ações em massa, notas internas, respostas predefinidas
  • Portal do cliente — Criação de tickets em autoatendimento, respostas e acompanhamento de status
  • Painel de administração — Gerenciar departamentos, políticas de SLA, regras de escalonamento, tags e ver relatórios
  • Anexos de arquivos — Upload com arrastar e soltar, armazenamento configurável e limites de tamanho
  • Linha do tempo de atividades — Log de auditoria completo de cada ação em cada ticket
  • Notificações por email — Notificações configuráveis por evento com suporte a webhooks
  • Roteamento por departamento — Organizar agentes em departamentos com atribuição automática (round-robin)
  • Sistema de tags — Categorizar tickets com tags coloridas
  • Tickets de visitante — Envio anônimo de tickets com acesso por link mágico via token de visitante
  • Email de entrada — Criar e responder tickets por email (Mailgun, Postmark, AWS SES, IMAP)
  • Inertia.js + Vue 3 UI — Frontend compartilhado via @escalated-dev/escalated
  • Divisão de tickets — Dividir uma resposta em um novo ticket independente preservando o contexto original
  • Ticket snooze — Adiar tickets com predefinições (1h, 4h, amanhã, próxima semana); rake escalated:wake_snoozed_tickets os reativa automaticamente
  • Visualizações salvas / filas personalizadas — Salvar, nomear e compartilhar presets de filtros como visualizações de tickets reutilizáveis
  • Widget de suporte integrável — Widget leve <script> com busca na KB, formulário de tickets e verificação de status
  • Threading de email — Emails enviados incluem cabeçalhos In-Reply-To e References para threading correto em clientes de email
  • Templates de email com marca — Logo, cor primária e texto do rodapé configuráveis para todos os emails enviados
  • Real-time broadcasting — Broadcasting opcional via ActionCable com fallback automático de polling
  • Toggle da base de conhecimento — Habilitar ou desabilitar a base de conhecimento pública nas configurações de administração

Requisitos

  • Ruby 3.1+
  • Rails 7.1+
  • Node.js 18+ (para recursos do frontend)

Início Rápido

bundle add escalated
npm install @escalated-dev/escalated
rails generate escalated:install
rails db:migrate

Add the Ticketable concern to your User model:

class User < ApplicationRecord
  include Escalated::Ticketable
end

Define authorization in your ApplicationController or an initializer:

# config/initializers/escalated.rb
Escalated.configure do |config|
  config.admin_check = ->(user) { user.admin? }
  config.agent_check = ->(user) { user.agent? || user.admin? }
end

Visit /support — you're live.

Configuração do Frontend

O Escalated usa Inertia.js com Vue 3. Os componentes do frontend são fornecidos pelo pacote npm @escalated-dev/escalated.

Conteúdo Tailwind

Adicione o pacote Escalated à configuração content do Tailwind para que suas classes não sejam removidas:

// tailwind.config.js
content: [
    // ... your existing paths
    './node_modules/@escalated-dev/escalated/src/**/*.vue',
],

Resolvedor de Páginas

Adicione as páginas do Escalated ao seu resolver de páginas do Inertia:

// app/javascript/entrypoints/application.js
import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'

createInertiaApp({
  resolve: name => {
    if (name.startsWith('Escalated/')) {
      const escalatedPages = import.meta.glob(
        '../../../node_modules/@escalated-dev/escalated/src/pages/**/*.vue',
        { eager: true }
      )
      const pageName = name.replace('Escalated/', '')
      return escalatedPages[`../../../node_modules/@escalated-dev/escalated/src/pages/${pageName}.vue`]
    }

    const pages = import.meta.glob('../pages/**/*.vue', { eager: true })
    return pages[`../pages/${name}.vue`]
  },
  setup({ el, App, props, plugin }) {
    createApp({ render: () => h(App, props) })
      .use(plugin)
      .mount(el)
  },
})

Temas (Opcional)

Registre o EscalatedPlugin para renderizar as páginas do Escalated dentro do layout do seu aplicativo — sem necessidade de duplicação de páginas:

import { EscalatedPlugin } from '@escalated-dev/escalated'
import AppLayout from '@/layouts/AppLayout.vue'

createInertiaApp({
  setup({ el, App, props, plugin }) {
    createApp({ render: () => h(App, props) })
      .use(plugin)
      .use(EscalatedPlugin, {
        layout: AppLayout,
        theme: {
          primary: '#3b82f6',
          radius: '0.75rem',
        }
      })
      .mount(el)
  },
})

Your layout component must accept a #header slot and a default slot. Escalated will render its sub-navigation in the header and page content in the default slot. Without the plugin, Escalated uses its own standalone layout.

Consulte o README do @escalated-dev/escalated para documentação completa de temas e propriedades CSS personalizadas.

Modos de Hospedagem

Self-Hosted (padrão)

Tudo permanece no seu banco de dados. Sem chamadas externas. Autonomia total.

Escalated.configure do |config|
  config.mode = :self_hosted
end

Sincronizado

Banco de dados local + sincronização automática com cloud.escalated.dev para caixa de entrada unificada em múltiplas aplicações. Se a nuvem estiver inacessível, seu aplicativo continua funcionando — os eventos entram na fila e são reenviados.

Escalated.configure do |config|
  config.mode = :synced
  config.hosted_api_url = "https://cloud.escalated.dev/api/v1"
  config.hosted_api_key = ENV["ESCALATED_API_KEY"]
end

Nuvem

Todos os dados de tickets são proxy para a API na nuvem. Seu aplicativo lida com autenticação e renderiza a interface, mas o armazenamento fica na nuvem.

Escalated.configure do |config|
  config.mode = :cloud
  config.hosted_api_url = "https://cloud.escalated.dev/api/v1"
  config.hosted_api_key = ENV["ESCALATED_API_KEY"]
end

Os três modos compartilham os mesmos controllers, interface e lógica de negócios. O padrão de driver cuida do resto.

Configuração

Create or edit config/initializers/escalated.rb:

Escalated.configure do |config|
  config.mode = :self_hosted
  config.user_class = "User"
  config.table_prefix = "escalated_"
  config.route_prefix = "support"
  config.default_priority = :medium

  # Middleware
  config.middleware = [:authenticate_user!]
  config.admin_middleware = nil

  # Tickets
  config.allow_customer_close = true
  config.auto_close_resolved_after_days = 7
  config.max_attachments_per_reply = 5
  config.max_attachment_size_kb = 10240

  # SLA
  config.sla = {
    enabled: true,
    business_hours_only: true,
    business_hours: {
      start: 9, end: 17,
      timezone: "UTC",
      working_days: [1, 2, 3, 4, 5]
    }
  }

  # Notifications
  config.notification_channels = [:email]
  config.webhook_url = nil

  # Storage (ActiveStorage)
  config.storage_service = :local
end

Agendamento

Adicione estes ao seu agendador para automação de SLA e escalonamento:

# config/schedule.rb (whenever gem) or use solid_queue/sidekiq-cron
every 1.minute do
  runner "Escalated::CheckSlaJob.perform_now"
end

every 5.minutes do
  runner "Escalated::EvaluateEscalationsJob.perform_now"
end

every 1.day do
  runner "Escalated::CloseResolvedJob.perform_now"
end

every 1.week do
  runner "Escalated::PurgeActivitiesJob.perform_now"
end

Rotas

Routes are automatically mounted when the engine loads. By default they mount at /support.

Route Method Description
/support GET Customer ticket list
/support/create GET New ticket form
/support/{ticket} GET Ticket detail
/support/agent GET Agent dashboard
/support/agent/tickets GET Agent ticket queue
/support/agent/tickets/{ticket} GET Agent ticket view
/support/admin/reports GET Admin reports
/support/admin/departments GET Department management
/support/admin/sla-policies GET SLA policy management
/support/admin/escalation-rules GET Escalation rule management
/support/admin/tags GET Tag management
/support/admin/canned-responses GET Canned response management
/support/agent/tickets/bulk POST Bulk actions on multiple tickets
/support/agent/tickets/{ticket}/follow POST Follow/unfollow a ticket
/support/agent/tickets/{ticket}/macro POST Apply a macro to a ticket
/support/agent/tickets/{ticket}/presence POST Update presence on a ticket
/support/agent/tickets/{ticket}/pin/{reply} POST Pin/unpin an internal note
/support/{ticket}/rate POST Submit satisfaction rating

Eventos

Connect to ticket lifecycle events via ActiveSupport::Notifications:

ActiveSupport::Notifications.subscribe("escalated.ticket_created") do |event|
  ticket = event.payload[:ticket]
  # Handle new ticket
end

Email de Entrada

Create and reply to tickets from incoming emails. Supports Mailgun, Postmark, AWS SES webhooks, and IMAP polling.

Habilitar

# config/initializers/escalated.rb
Escalated.configure do |config|
  config.inbound_email_enabled = true
  config.inbound_email_adapter = :mailgun
  config.inbound_email_address = "support@yourapp.com"

  # Mailgun
  config.mailgun_signing_key = ENV["ESCALATED_MAILGUN_SIGNING_KEY"]

  # Postmark
  config.postmark_inbound_token = ENV["ESCALATED_POSTMARK_INBOUND_TOKEN"]

  # AWS SES
  config.ses_region = "us-east-1"
  config.ses_topic_arn = ENV["ESCALATED_SES_TOPIC_ARN"]

  # IMAP
  config.imap_host = ENV["ESCALATED_IMAP_HOST"]
  config.imap_port = 993
  config.imap_encryption = :ssl
  config.imap_username = ENV["ESCALATED_IMAP_USERNAME"]
  config.imap_password = ENV["ESCALATED_IMAP_PASSWORD"]
  config.imap_mailbox = "INBOX"
end

URLs dos Webhooks

Provider URL
Mailgun POST /support/inbound/mailgun
Postmark POST /support/inbound/postmark
AWS SES POST /support/inbound/ses

Polling IMAP

Schedule Escalated::PollImapJob with Solid Queue, Sidekiq, or whenever:

# config/recurring.yml (Solid Queue)
poll_imap:
  class: Escalated::PollImapJob
  schedule: every minute

Funcionalidades

  • Thread detection via subject reference and In-Reply-To / References headers
  • Guest tickets for unknown senders with auto-derived display names
  • Auto-reopen resolved/closed tickets on email reply
  • Duplicate detection via Message-ID headers
  • Attachment handling with configurable size and count limits
  • Audit logging of every inbound email
  • All settings configurable from admin panel with env fallback

SDK de Plugins

O Escalated suporta plugins agnósticos de framework construídos com o Plugin SDK. Os plugins são escritos uma vez em TypeScript e funcionam em todos os backends do Escalated.

Requisitos

  • Node.js 20+
  • @escalated-dev/plugin-runtime installed in your project

Instalando Plugins

npm install @escalated-dev/plugin-runtime
npm install @escalated-dev/plugin-slack
npm install @escalated-dev/plugin-jira

Habilitando Plugins SDK

# config/initializers/escalated.rb
Escalated.configure do |config|
  # ... existing config ...
  config.sdk_plugins_enabled = true
end

Como Funciona

SDK plugins run as a long-lived Node.js subprocess managed by @escalated-dev/plugin-runtime, communicating with Rails over JSON-RPC 2.0 via stdio. The subprocess is spawned lazily on first use and automatically restarted with exponential backoff if it crashes. Every ticket lifecycle event is dual-dispatched to both Rails event handlers and the plugin runtime.

Criando Seu Próprio Plugin

import { definePlugin } from '@escalated-dev/plugin-sdk'

export default definePlugin({
  name: 'my-plugin',
  version: '1.0.0',
  actions: {
    'ticket.created': async (event, ctx) => {
      ctx.log.info('New ticket!', event)
    },
  },
})

Recursos

Também Disponível Para

Mesma arquitetura, mesma interface Vue, mesmos três modos de hospedagem — para cada framework backend importante.

Testes

bundle exec rspec

Licença

MIT