# Tickets

Boards, pipelines, statuses, and conversation-to-ticket conversion


Manage pipelines, statuses, tickets, activities, notes, and per-workspace ticket configs, including survey-driven ticket automation and client portal access.

Code lives in [`frontline_api/src/modules/ticket`](https://github.com/erxes/erxes/tree/f91e8c6f4714c910a32c6b6e14fe085f6435c89e/backend/plugins/frontline_api/src/modules/ticket) (backend) and [`frontline_ui/src/modules/{ticket,pipelines,status}`](https://github.com/erxes/erxes/tree/f91e8c6f4714c910a32c6b6e14fe085f6435c89e/frontend/plugins/frontline_ui/src/modules) (frontend, served at `/frontline/tickets`).

## Concepts

### Pipelines

A `Pipeline` is a named ticket workflow bound to a channel (`channelId`) with `memberIds`, `visibility` (public/private), optional `branchIds`/`departmentIds`, and ordering/numbering config (`isCheckDate`, `isCheckUser`, `isCheckDepartment`, `isCheckBranch`, `isHideName`, `excludeCheckUserIds`, `propertyIds`, name/number fields). `propertyIds` selects which properties appear on tickets in the pipeline. The `ticket` property type is registered through `meta` with `systemFields`. Private pipelines require membership; `isCheckUser`/`isCheckBranch`/`isCheckDepartment`/`isCheckDate` further restrict which tickets a member sees.

### Statuses

A `Status` belongs to a pipeline and carries `visibilityType`, `memberIds`, `canEditMemberIds`, `canMoveMemberIds`, and `type`. Status visibility feeds `PermissionValidator.getHiddenStatusIds`: a private status whose `memberIds` excludes you hides its tickets from lists, and `canEditMemberIds`/`canMoveMemberIds` gate edits and status moves per user.

### Ticket records

A `Ticket` carries `name`, `description`, `pipelineId`, `statusId`, `priority`, `assigneeId`, `assignedMembers`, `labelIds`, `tagIds`, `branchId`, `departmentId`, `channelId`, `number`, `state` (`active`, `archived`, `deleted`), `propertiesData`, `attachments`, `companyId`/`customerIds`, dates, and `sourceSurvey` (the survey snapshot written by ticket automation). Filters on `getTickets` include search, status/pipeline/channel, assignee, ownership, and `state`.

### Activities, notes, configs

- `Activity` rows record ticket events; `getTicketActivities` lists them.
- `Note` rows are user-authored ticket notes: `ticketGetNote`, `ticketGetNotes`, `ticketCreateNote`, `ticketUpdateNote`, `ticketDeleteNote`, plus client portal equivalents.
- `TicketConfig` records hold per-pipeline/per-ticket settings via `ticketConfigs`, `ticketConfigDetail`, `ticketConfig`, `ticketSaveConfig`, `ticketRemoveConfig`.

## Queries and mutations

Schema: [`modules/ticket/graphql/schemas/ticket.ts`](https://github.com/erxes/erxes/blob/f91e8c6f4714c910a32c6b6e14fe085f6435c89e/backend/plugins/frontline_api/src/modules/ticket/graphql/schemas/ticket.ts).

| Operation | Kind | Purpose |
| --- | --- | --- |
| `getTickets` / `getTicket(_id)` | query | Filtered list / detail |
| `getTicketPipelines` / `getTicketPipeline(_id)` | query | Pipeline reads |
| `getTicketStatus(_id)` / `getAccessibleTicketStatuses` / `getTicketStatusesChoicesPipeline` / `getTicketStatusesByType` | query | Status reads respecting visibility |
| `getTicketActivities` / `ticketGetNote` / `ticketGetNotes` | query | Activity and note reads |
| `ticketConfigs` / `ticketConfigDetail` / `ticketConfig` | query | Config reads |
| `createTicket` / `updateTicket` / `removeTicket` | mutation | Ticket writes |
| `createPipeline` / `updatePipeline` / `removePipeline` | mutation | Pipeline management |
| `addTicketStatus` / `updateTicketStatus` / `deleteTicketStatus` | mutation | Status management |
| `ticketCreateNote` / `ticketUpdateNote` / `ticketDeleteNote` | mutation | Note writes |
| `ticketSaveConfig` / `ticketRemoveConfig` | mutation | Config writes |
| `cpGetTickets` / `cpGetTicket` / `cpGetTicketTotalCount` / `cpGetTicketStatus` / `cpTicketGetNotes` | query | Client portal reads |
| `cpCreateTicket` / `cpUpdateTicket` / `cpTicketCreateNote` | mutation | Client portal writes |

The widget also exposes `widgetTicketCreated`, `widgetTicketCheckProgress`, `widgetTicketCheckProgressForget`, `widgetTicketCommentAdd`, `widgetTicketCommentRemove`, and `widgetTicketsByCustomer` for embedded ticket widgets (see [Inbox & Channels](https://erxes.io/docs/frontline-inbox-channels)).

```graphql
mutation {
  createTicket(
    name: "Follow-up: billing dispute"
    pipelineId: "pipe_1"
    statusId: "status_1"
    assigneeId: "user_1"
    channelId: "chan_1"
  ) {
    _id
    number
  }
}
```

## Survey-driven ticket automation

Survey options can arm ticket creation (`ticketCreationEnabled`, `ticketCreationThreshold`, `ticketPipelineId`, `ticketStatusId`). When a vote lands, `runSurveyTicketAutomation` ([`modules/survey/ticketAutomation.ts`](https://github.com/erxes/erxes/blob/f91e8c6f4714c910a32c6b6e14fe085f6435c89e/backend/plugins/frontline_api/src/modules/survey/ticketAutomation.ts)) counts `SurveyVotes` for the option, atomically claims it (`ticketClaimedAt`, 5-minute stale-claim window), and creates exactly one ticket named `"<survey title> — <option text>"` with a `sourceSurvey` snapshot. See [Forms & Surveys](https://erxes.io/docs/frontline-forms-surveys).

## Import and export

`main.ts` registers import/export producers for content type `frontline:ticket.ticket` (permissions `ticketsImportManage` / `ticketsExportManage`). Form submissions export separately under `frontline:formSubmission.formSubmission` (`formSubmissionsExportManage`).

## tRPC

- `ticket.create`: service-side ticket creation (`doc` + `userId`), used by the survey automation and inbox conversion.
- `relation.onRelationAdded`: when a relation is added to a conversation, its form submissions are logged onto the related entity.

## Permissions

The `ticket` permission module covers `showTickets` (always granted), `createTicket`, `updateTicket`, `removeTicket`, `ticketStatusesManage`, `ticketsImportManage`, and `ticketsExportManage`. There are no pipeline-level permission actions. Pipeline access is enforced by `visibility`/`memberIds` and `PermissionValidator` ([`modules/ticket/utils/permissionValidator.ts`](https://github.com/erxes/erxes/blob/f91e8c6f4714c910a32c6b6e14fe085f6435c89e/backend/plugins/frontline_api/src/modules/ticket/utils/permissionValidator.ts)), which also applies per-status view/edit/move gates on top of those.

> [!WARNING]
> Edits and status moves fail with `PermissionError` when the status's `canEditMemberIds`/`canMoveMemberIds` excludes the caller.

