Tickets

TICKETING — PAID PLUGIN

Built-in ITIL-style incident and request tracking. Every ticket has a state machine, a priority, an audit trail, and an optional SLA timer. Workflows are GitOps-declared in Helm values — there is no in-app editor.

What is a ticket

A ticket is the unit of work in ITOps. It can be opened by a user from the UI, automatically created when a monitored service flips to DOWN, or pushed in via the GraphQL API. Each ticket carries a title, description, priority, assignee, status, optional SLA target, and a chronological audit log of every state change.

Tickets are scoped to the Ticketing plugin: the plugin is enabled per-installation by the license, and can be toggled at runtime via the togglePlugin GraphQL mutation. When disabled, ticket-related menus disappear from the sidebar; when enabled, the existing data is preserved.

Lifecycle — the state machine

Every ticket moves through a fixed set of states:

OPEN  ->  IN_PROGRESS  ->  RESOLVED  ->  CLOSED
                  ^_________________|
              (re-open if the fix did not stick)

Allowed transitions are restricted by the configured workflow (see Default Workflows). Anything outside the allowed transitions is rejected with a 403 forbidden_transition error and never silently accepted.

Priority

Four levels, mapped to colours in the UI and to default SLA targets when the ticket is opened from a catalog item:

PriorityDefault responseDefault resolutionTypical use
CRITICAL5 min2 hProduction outage, payment system down
HIGH30 min8 hMajor degradation, big customer impact
MEDIUM2 h1 dayStandard request, single-user impact
LOW1 day5 daysNice-to-have, cosmetic, internal

The defaults above are baked into the plugin and overridable per catalog item (see Service Catalog).

Workflow — GitOps declared

There is no graphical workflow editor in the UI. Workflows live in Helm values, get applied on chart upgrade, and are versioned in Git like everything else. This is intentional: workflows are infrastructure, not user data, so they belong with the rest of your configuration.

ticketing:
  enabled: true
  workflows:
    - name: incident_response
      displayName: "Incident Response"
      transitions:
        - {from: OPEN,        to: IN_PROGRESS, role: assignee}
        - {from: IN_PROGRESS, to: RESOLVED,    role: assignee}
        - {from: RESOLVED,    to: CLOSED,      role: requester}
        - {from: RESOLVED,    to: IN_PROGRESS, role: any}

Each transition declares who is allowed to perform it (assignee, requester, or any). On chart upgrade the platform reconciles the declared workflows against the database: new workflows are added, existing ones updated in place, and tickets that reference a removed workflow keep their last known transitions but cannot transition further until a matching workflow is re-declared.

For the full set of 5 default workflows shipped with the plugin see Default Workflows.

How tickets are created

Three entry points, all funnelled through the same backend creation path:

Audit trail

Every state change, assignee change, and comment is recorded in ticket_status_history with a timestamp, the actor (user ID or system for auto-events), the old value, and the new value. The history is rendered as a timeline on the ticket detail page, and is exported to YAML by /api/v1/templates/export for backup.

The history table is append-only — rows cannot be edited or deleted via the API, only via direct database access (which is itself logged at the platform level).

Example — ticket payload

A typical ticket fetched via GraphQL:

{
  "data": {
    "ticket": {
      "id": "tk_4f8e29",
      "title": "Payment API returning 503",
      "description": "Stripe webhook timing out, /v1/charge 503 since 14:02 CET.",
      "status": "IN_PROGRESS",
      "priority": "CRITICAL",
      "workflow": "incident_response",
      "requester": {"id": "u_b1", "name": "Anna K."},
      "assignee":  {"id": "u_c4", "name": "Marton P."},
      "assigneeGroup": "payment-team",
      "sla": {
        "responseDueAt":   "2026-04-28T14:07:00Z",
        "resolutionDueAt": "2026-04-28T16:02:00Z",
        "responseBreached":   false,
        "resolutionBreached": false
      },
      "createdAt":   "2026-04-28T14:03:00Z",
      "updatedAt":   "2026-04-28T14:05:21Z",
      "history": [
        {"at": "2026-04-28T14:03:00Z", "actor": "system",  "from": null,           "to": "OPEN"},
        {"at": "2026-04-28T14:05:21Z", "actor": "u_c4",    "from": "OPEN",         "to": "IN_PROGRESS"}
      ]
    }
  }
}

See also