Working with Tickets

Creating, managing, and resolving support tickets.

Creating a ticket

Click New ticket from the dashboard or ticket list. Staff and admins can create tickets on behalf of any user. Users create tickets for themselves.

Required fields

Optional fields

CTI cascade behavior

The three dropdowns are chained:

Fields by role

FieldGuestUser (logged in)Staff / Admin
Name, email, phoneName + email required; phone optional— (uses account)
CategoryActive onlyActive onlyAll
TypeNot shownActive onlyAll
ItemNot shownNot shownAll
PriorityDefaults to MediumDefaults to MediumSelectable
AttachmentsNot availableYesYes

Guest ticket submission

When guest submission is enabled (Admin → Settings), the public form at /submit is accessible without logging in. Required fields: name, email, subject, and category. Phone number is optional. Type, Item, and priority fields are not shown to guests — the server enforces this regardless of what is submitted. On success, the form shows the ticket's tracking number, which can be used as a reference when following up by phone or email.

Ticket lifecycle

A ticket moves through statuses over the course of its life. The default lifecycle is:

New → In Progress → Pending → Resolved → [reopen window] → Closed
                                  ↑              |
                                  └── Reopened ──┘

Statuses are customizable — admins can add intermediate statuses. The system statuses (New, Resolved, Closed) have fixed behavior regardless of their display name.

Status transitions

TransitionWho can trigger itNotes
Any status → any statusStaff, AdminNo restrictions except Closed (see below).
Any → ResolvedStaff, AdminOptionally captures resolution notes. Starts the reopen window timer.
Resolved → ClosedSystem (automatic)Triggered when the reopen window expires. A background job runs every hour to check.
Resolved → Reopened (via reply)UserOnly within the reopen window. Automatically transitions the ticket back to New.
Closed → anyStaff, Admin onlyUsers cannot interact with Closed tickets.
Resolved or Closed → Reopened (manual)Staff, AdminBypasses the reopen window restriction.

Resolution notes

When marking a ticket Resolved, staff are prompted to optionally enter resolution notes — a brief summary of what was done and how the issue was fixed. These notes are visible to the submitter and are preserved when the ticket is reopened. They're useful for building a history of known fixes.

The reopen window

After a ticket is Resolved, the submitter has a configurable number of days to reopen it by replying. The default is 7 days. When a user adds a reply to a Resolved ticket within the window:

  1. The reply is saved.
  2. The ticket status is automatically changed back to New.
  3. The ticket is flagged in the staff queue as reopened.
  4. The original assignee (if any) receives an email notification.

After the window expires, the ticket transitions to Closed automatically. Users can still view Closed tickets but cannot add replies. Staff can reopen Closed tickets manually at any time.

Replies & internal notes

Public replies

Public replies are the standard response mechanism. They are visible to:

Email notifications are sent to all participants when a public reply is added.

Internal notes

Staff and admins can add internal notes to any ticket. Internal notes are:

Use internal notes for:

Markdown support

Both replies and notes support a subset of Markdown:

HTML is not supported and is escaped before rendering.

Editing and deleting replies

Users can edit or delete their own replies within 15 minutes of posting. Staff and admins can edit any reply at any time. Deletions are soft — a "deleted reply" placeholder is shown to staff. The original content is preserved in the audit log.

Any ticket can be linked to any other ticket, regardless of status. Links are always bidirectional — adding a link on ticket A automatically creates the reverse link on ticket B.

Link types

TypeMeaningWhen to use
related_to These tickets are related in some way. They affect similar systems, came from the same user, or are otherwise connected but neither caused the other.
parent_of / child_of One ticket is a sub-issue of another. A "batch laptop deployment" parent ticket with individual "setup laptop for [user]" children. Or a widespread network outage parent with individual "I can't access the VPN" children.
caused_by This ticket was caused by another ticket's issue. A failed Windows update ticket caused several "Outlook won't open" tickets.
duplicate_of This ticket is a duplicate of another. A user submitted the same request twice. Mark the newer one as a duplicate of the original.

Adding a link

From the ticket detail view, click Add link in the Linked tickets section. Search for the target ticket by ID or by subject keywords. Select the link type and confirm.

Removing a link

Click the × next to any linked ticket. This removes the link in both directions. Staff and admin only — users cannot modify links.

Bulk operations on linked tickets

From a parent ticket, staff can resolve all child tickets at once using Resolve all children. Each child receives the same resolution notes as the parent. This is useful for closing out many individual duplicate or child tickets after resolving the root cause.

Tags

Tags are free-form labels that staff can attach to any ticket. They appear in the ticket detail sidebar and are useful for grouping tickets by theme, campaign, affected system, or any other dimension that doesn't fit the formal Category/Type/Item hierarchy.

Adding a tag

In the Tags section of the ticket sidebar, type a tag name and press Enter — or pick a suggestion from the autocomplete dropdown. Tags are stored lowercase regardless of how they're typed.

Removing a tag

Click the × on a tag pill to remove it from the ticket. This does not delete the tag globally — it only removes the association with this ticket. Staff and admins only.

Autocomplete

As you type, existing active tags that match the prefix are shown as suggestions. Select a suggestion to apply it, or press Enter to create a new tag with the text you've typed. Tags with no matching suggestions show a "Press Enter to create…" hint.

Tag visibility

Tags are visible to all users who can view the ticket, including the ticket submitter. Only staff and admins can add or remove tags.

Admin tag management

Admins can deactivate inappropriate tags or restore previously deactivated ones from Admin → Tags. See Tags in the Admin Guide for details.

Assignment

A ticket can be assigned to:

Who can assign

Staff and admins can assign tickets to any staff member or group, regardless of scope. This is intentional — cross-team escalation should not be blocked by routing rules. A ticket can be assigned to staff outside their normal scope, and it will appear in the assignee's queue.

Self-assignment

Staff can click Assign to me to take ownership of an unassigned ticket immediately.

Reassignment

Reassigning a ticket (changing from one assignee to another) generates an email notification to the new assignee. The old assignee does not receive a notification unless they are also a participant (i.e. they added a reply).

Assignment and scope

Scope controls what tickets a staff member sees in their default queue. Assignment overrides this for the assignee — if you are assigned a ticket outside your scope, it appears in your queue. You can always find any ticket by its ID using the search bar, regardless of scope or assignment.

Custom fields

Admins can define additional fields (text, textarea, number, or select) and assign them to CTI nodes. When you create a ticket and select a Category, Type, or Item, any fields assigned at those levels with visible on new enabled will appear on the form. Required fields must be filled before submitting.

After a ticket is created, custom field values appear in the Custom Fields sidebar card on the ticket detail page:

Custom fields are configured by admins under Admin → Custom Fields and assigned to CTI nodes in Admin → Categories. See the Admin Guide for details.

Attachments

Any logged-in user (including regular users) can attach files when creating a ticket. Attachments are listed on the ticket detail page and served through the API. Authentication is required to download.

Limits

LimitValue
Maximum file size25 MB per file
Total per ticketUnlimited

Allowed file types

Only the following extensions are accepted. The server validates both the extension and magic bytes — mismatched content is rejected.

FormatExtension(s)
PDF.pdf
Word document.docx
Excel spreadsheet.xlsx
Plain text / log.txt, .log
JPEG image.jpg, .jpeg
PNG image.png
BMP image.bmp

Image recompression

Uploaded images (JPEG, PNG, BMP) are decoded and re-encoded as both JPEG (quality 85) and PNG. Whichever produces the smaller file is stored. The original filename is preserved in the database regardless of the stored format.

Virus scanning

If a ClamAV daemon address is configured via the CLAMAV_ADDR environment variable, all uploads are scanned before being written to disk. Infected files are rejected and the user is shown the detected virus name. If ClamAV is unreachable or not configured, a warning is logged and the upload proceeds normally — virus scanning is intentionally non-fatal.

The Docker Compose setup runs a ClamAV container automatically and wires everything up — no configuration needed. For bare-metal or Kubernetes installs, point CLAMAV_ADDR at your own daemon (tcp://host:port or unix:///path/to/clamd.sock).

Storage

Files are stored under ATTACHMENT_DIR/tickets/<ticketID>/ with UUID-based filenames to prevent enumeration. The original filename is preserved in the database and shown in the UI and Content-Disposition headers on download.

Live search

The search bar at the top of the ticket list searches across tracking number, subject, and description. Results appear after you type at least 2 characters (with a short debounce). A spinner is shown while results load.

Jump to ticket (staff and admin)

Staff and admins can submit the search form (press Enter or click Jump to ticket) to navigate directly to a ticket by its exact tracking number or UUID. If no match is found, an inline error is shown.

← Admin Guide REST API →