العربية • Deutsch • English • Español • Français • Italiano • 日本語 • 한국어 • Nederlands • Polski • Português (BR) • Русский • Türkçe • 简体中文
Embedded helpdesk module for NestJS applications. Drop-in ticketing, SLA management, knowledge base, and more.
- Ticket Management -- Full CRUD with lifecycle tracking, priorities, departments, tags, and custom fields
- SLA Policies -- Configurable response/resolution targets with business hours support
- Automations -- Time-based processing via
@nestjs/schedule(SLA checks, snooze wake-up, webhook retries) - Escalation Rules -- Automatic reassignment and notifications on SLA breach
- Macros & Canned Responses -- One-click multi-action macros and templated replies
- Custom Fields -- Dynamic fields with validation (text, number, select, checkbox, date)
- Knowledge Base -- Articles with categories, search, view tracking, and helpfulness ratings
- Webhooks -- HMAC-signed delivery with exponential backoff retry
- API Tokens -- Bearer token authentication with scoped abilities
- Roles & Permissions -- Granular permission system with NestJS guards
- Audit Logging -- Interceptor-based activity tracking for all mutations
- Import System -- Bulk import for tickets, tags, and departments
- Side Conversations -- Threaded discussions within a ticket
- Ticket Merging & Linking -- Merge duplicates, link related tickets
- Ticket Splitting -- Break a ticket into separate issues
- Ticket Snooze -- Snooze with automatic wake-up via cron
- Saved Views -- Personal and shared filtered views
- Widget API -- Public endpoints for embeddable support widget with rate limiting
- Public Ticket System -- Unauthenticated submission via widget form or inbound email, Contact-based identity with email dedupe, configurable guest policy, signed Reply-To for threaded email conversations
- Workflow Engine -- Admin-configured rules fire on ticket/reply events (conditions + actions: assign, tag, set priority/status/department, insert canned reply, etc.); evaluation logs per execution
- Real-time Broadcasting -- Socket.IO gateway for live updates (opt-in)
- Capacity Management -- Per-agent ticket limits with real-time tracking
- Skill-based Routing -- Assign tickets based on agent skills and availability
- CSAT Ratings -- Post-resolution satisfaction surveys with token-based submission
- 2FA (TOTP) -- Two-factor authentication for agents via
otplib - Guest Access -- Token-based ticket access without authentication
- Internationalization -- Translations sourced from the central
@escalated-dev/localepackage vianestjs-i18n, with a chained overlay loader for plugin-local and host-app overrides (seesrc/i18n/overrides/README.md)
- Node.js 18+
- NestJS 10+
- TypeORM 0.3+
- Any TypeORM-supported database (PostgreSQL, MySQL, SQLite, etc.)
npm install @escalated-dev/escalated-nestjsimport { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { EscalatedModule } from '@escalated-dev/escalated-nestjs';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
host: 'localhost',
port: 5432,
database: 'myapp',
username: 'user',
password: 'pass',
autoLoadEntities: true,
synchronize: true, // disable in production
}),
EscalatedModule.forRoot({
routePrefix: 'escalated',
appName: 'My App',
appUrl: 'https://myapp.com',
enableWebsockets: false,
enableKnowledgeBase: true,
enableCsat: true,
enable2fa: false,
}),
],
})
export class AppModule {}| Option | Type | Default | Description |
|---|---|---|---|
routePrefix |
string |
'escalated' |
URL prefix for all routes |
enableWebsockets |
boolean |
false |
Enable Socket.IO real-time broadcasting |
enableKnowledgeBase |
boolean |
true |
Enable KB articles and categories |
enableCsat |
boolean |
true |
Enable satisfaction surveys |
enable2fa |
boolean |
false |
Enable TOTP 2FA for agents |
appName |
string |
'Escalated' |
Branding name for emails |
appUrl |
string |
-- | Base URL for links |
maxFileSize |
number |
10485760 |
Max upload size in bytes |
webhookMaxRetries |
number |
3 |
Webhook retry attempts |
widgetOrigins |
string[] |
['*'] |
CORS origins for widget |
adminGuard |
class |
-- | Custom guard for admin routes |
agentGuard |
class |
-- | Custom guard for agent routes |
customerGuard |
class |
-- | Custom guard for customer routes |
userResolver |
function |
-- | Extract user from request |
mail |
object |
-- | Outbound email config (see below) |
inbound |
object |
-- | Inbound email config (see below) |
guestPolicy |
object |
unassigned | Guest identity policy (see below) |
EscalatedModule.forRoot({
mail: {
from: 'support@example.com',
transport: {
host: 'smtp.example.com',
port: 587,
auth: { user: 'x', pass: 'y' },
},
},
});When mail is absent, the MailerModule is not registered and EmailService silently no-ops — modules boot cleanly without a transport.
EscalatedModule.forRoot({
inbound: {
replyDomain: 'reply.example.com', // domain in our Message-ID + Reply-To
replySecret: '32-byte-hex-secret', // HMAC key for signed reply-to
webhookSecret: 'shared-secret', // X-Escalated-Inbound-Secret header value
provider: 'postmark', // parser adapter
},
});Webhook endpoint: POST /escalated/webhook/email/inbound. Guard requires X-Escalated-Inbound-Secret header to match webhookSecret (constant-time compare).
Controls the identity assigned to a ticket submitted via the public form or inbound email.
// Default: no host-app user, contact carries identity
{ mode: 'unassigned' }
// Assign all guest tickets to a shared "guest" user in the host app
{ mode: 'guest_user', guestUserId: 42 }
// Ticket stays unassigned until the guest accepts a signup invite
{ mode: 'prompt_signup', signupUrlTemplate: 'https://app.example.com/signup?token={token}' }Admins can override at runtime via PUT /escalated/admin/settings:
{ "key": "guest_policy", "type": "json", "value": { "mode": "guest_user", "guestUserId": 99 } }With synchronize: true, TypeORM auto-creates tables. For production, generate migrations:
npx typeorm migration:generate -n EscalatedSetup
npx typeorm migration:runAll tables are prefixed with escalated_ to avoid conflicts.
| Method | Path | Description |
|---|---|---|
| GET | /tickets |
List tickets with filters |
| POST | /tickets |
Create ticket |
| GET | /tickets/:id |
Show ticket with replies |
| PUT | /tickets/:id |
Update ticket |
| DELETE | /tickets/:id |
Delete ticket |
| POST | /tickets/:id/replies |
Add reply |
| POST | /tickets/:id/merge/:targetId |
Merge tickets |
| POST | /tickets/:id/split |
Split ticket |
| POST | /tickets/:id/snooze |
Snooze ticket |
| GET | /tickets/:ticketId/links |
List ticket links |
| POST | /tickets/:ticketId/links |
Link tickets |
| GET | /tickets/:ticketId/side-conversations |
List side conversations |
| POST | /tickets/:ticketId/side-conversations |
Create side conversation |
| GET | /macros |
List macros |
| POST | /macros/:macroId/execute/:ticketId |
Execute macro |
| GET | /canned-responses |
List canned responses |
| GET | /saved-views |
List saved views |
| POST | /saved-views |
Create saved view |
| Method | Path | Description |
|---|---|---|
| GET/PUT | /settings |
Manage settings |
| CRUD | /departments |
Manage departments |
| CRUD | /tags |
Manage tags |
| CRUD | /custom-fields |
Manage custom fields |
| CRUD | /roles |
Manage roles |
| CRUD | /sla/policies |
Manage SLA policies |
| CRUD | /sla/escalation-rules |
Manage escalation rules |
| CRUD | /sla/schedules |
Manage business schedules |
| CRUD | /webhooks |
Manage webhooks |
| CRUD | /api-tokens |
Manage API tokens |
| CRUD | /agents |
Manage agent profiles |
| CRUD | /macros |
Manage macros |
| CRUD | /canned-responses |
Manage canned responses |
| CRUD | /kb/categories |
Manage KB categories |
| CRUD | /kb/articles |
Manage KB articles |
| POST | /import/tickets |
Bulk import tickets |
| POST | /2fa/generate |
Generate 2FA secret |
| POST | /2fa/enable |
Enable 2FA |
| GET | /audit-logs |
View audit logs |
| Method | Path | Description |
|---|---|---|
| GET | /tickets |
List own tickets |
| POST | /tickets |
Create ticket |
| GET | /tickets/:id |
View own ticket |
| POST | /tickets/:id/replies |
Reply to own ticket |
| POST | /tickets/:id/rate |
Submit CSAT rating |
| GET | /kb/categories |
Browse KB categories |
| GET | /kb/articles |
Browse KB articles |
| GET | /kb/search |
Search KB |
| Method | Path | Description |
|---|---|---|
| POST | /tickets |
Create ticket (public) |
| GET | /tickets/:id |
View ticket (guest token) |
| POST | /tickets/:id/replies |
Reply (guest token) |
| GET | /kb/search |
Search KB |
| POST | /rate/:token |
Submit CSAT |
All services are exported and can be injected into your own code:
import { Injectable } from '@nestjs/common';
import { TicketService, AgentService } from '@escalated-dev/escalated-nestjs';
@Injectable()
export class MyService {
constructor(
private readonly ticketService: TicketService,
private readonly agentService: AgentService,
) {}
async assignToAvailableAgent(ticketId: number) {
const agent = await this.agentService.findAvailableAgent();
if (agent) {
await this.ticketService.update(ticketId, { assigneeId: agent.userId }, 0);
}
}
}The module emits events via @nestjs/event-emitter:
import { OnEvent } from '@nestjs/event-emitter';
import { ESCALATED_EVENTS, TicketCreatedEvent } from '@escalated-dev/escalated-nestjs';
@Injectable()
export class NotificationService {
@OnEvent(ESCALATED_EVENTS.TICKET_CREATED)
handleTicketCreated(event: TicketCreatedEvent) {
// Send notification, update external system, etc.
}
}Events: TICKET_CREATED, TICKET_UPDATED, TICKET_ASSIGNED, TICKET_STATUS_CHANGED, TICKET_REPLY_CREATED, TICKET_MERGED, TICKET_SPLIT, SLA_BREACHED.
Enable WebSocket broadcasting for live ticket updates:
EscalatedModule.forRoot({
enableWebsockets: true,
});Client-side (Socket.IO):
const socket = io('/escalated');
socket.emit('join:ticket', { ticketId: 1 });
socket.on('ticket:updated', (data) => console.log('Updated:', data));
socket.on('ticket:reply', (data) => console.log('New reply:', data));git clone https://github.com/escalated-dev/escalated-nestjs.git
cd escalated-nestjs
npm install --legacy-peer-deps
npm test
npm run buildAll 32 entities are exported and prefixed with escalated_:
Core: Ticket, TicketStatus, Reply, Attachment, TicketActivity, Tag, Department, TicketLink, SatisfactionRating
SLA: SlaPolicy, EscalationRule, BusinessSchedule, Holiday
Agents: AgentProfile, AgentCapacity, Skill
Messaging: CannedResponse, Macro, SideConversation, SideConversationReply
Admin: Role, Permission, ApiToken, Webhook, WebhookDelivery, AuditLog
Custom: CustomField, CustomFieldValue
Config: EscalatedSettings, SavedView
Knowledge Base: KbCategory, KbArticle
MIT