Skip to main content

GitHub Issues Integration

Status: Production Ready

Overview

End users in QRY can report issues from the Help menu. With the GitHub integration enabled, every report is automatically created as a GitHub issue in a configured repository — typically pueteam/QRY for QRY's own bug tracker, or a customer-owned internal repo for tenant-specific reporting.

The sync is bidirectional, with deliberately asymmetric latency:

  • QRY → GitHub — immediate. The moment a user submits a report, QRY creates the GitHub issue.
  • GitHub → QRY — on-demand. Admins trigger a sync to pull updated state (status, labels, comments) back into QRY's local mirror.

The on-demand pattern (instead of GitHub webhooks) avoids the operational overhead of exposing a public webhook ingress and managing webhook secrets — and it's enough for almost all tenants.

Architecture

┌──────────────┐   POST /issues          ┌──────────────┐
│ QRY │ ─────────────────────→ │ GitHub │
│ backend │ │ API │
│ │ ←───── sync (cron) ──────│ │
└──────────────┘ └──────────────┘

│ stores

┌──────────────┐
│ qry_issues │
│ table (PG) │
└──────────────┘

A local qry_issues table mirrors GitHub state. Users see the local state in Admin > Issues (admins) and My issues (any user, scoped to their own reports).

Data flow

QRY → GitHub (on report submission)

  1. User opens Help > Report Issue, fills the form (title, description, optional conversation attachment).
  2. Backend creates a record in qry_issues with state pending.
  3. Backend calls POST /repos/{owner}/{repo}/issues with:
    • Title (with optional tenant prefix configured by the admin).
    • Body — formatted with description, user email, conversation id, tenant id.
    • Labels — configured defaults plus any tags from the user.
  4. On success, the local record's state moves to synced and stores the GitHub issue number / URL.
  5. The user sees the confirmation with a clickable link.

If the GitHub call fails (token invalid, rate-limited, network), the local record stays in pending. The next periodic sync retries.

GitHub → QRY (on demand)

  1. Admin clicks Sync from GitHub in Admin > Issues, or the nightly cronjob fires.
  2. Backend calls GET /repos/{owner}/{repo}/issues?state=all&since=<last_sync>.
  3. For each issue with a matching qry_issues mirror, update local state:
    • state (open / closed)
    • labels (added / removed)
    • comments count
    • closed_at timestamp
  4. Issues created directly in GitHub (not from QRY) are imported as external issues if the integration is configured to import them — controlled by a setting.

Configuration

In Admin > System Settings > GitHub:

SettingDescription
Repositoryowner/repo slug (e.g. pueteam/QRY)
Personal access tokenStored Fernet-encrypted; needs repo scope
Default labelsApplied to every issue QRY creates
Tenant prefixOptional; prepended to issue title (e.g. [acme])
Sync scheduleCron expression for the on-demand-but-cronjobbed sync (default daily)
Import externalWhether to import issues created directly in GitHub

Token security

The personal access token is the most sensitive piece of the integration. Considerations:

  • Use a dedicated bot account, not a real user's PAT.
  • Scope the token to the single repo the integration uses.
  • Rotate periodically; the integration's last-sync log shows authentication failures.
  • The token is encrypted at rest with the same Fernet key (JWT_SECRET_KEY-derived) used for datasource credentials.

User experience

End users see issues only as their own report and follow-up — they don't see other users' reports. My issues in their navbar is the entry point.

Admins see everything in Admin > Issues, with filters by user, tenant, state, and label.

Operational signals

  • qry_github_sync_failures_total — counter; alerts on rising trend.
  • qry_github_pending_reports — gauge; should drop to zero quickly after submission. If it stays >0 for minutes, the sync worker is stuck.
  • qry_github_last_sync_seconds_ago — gauge; alerts if no successful sync in N hours (cron is broken).

Limits

  • GitHub issue body is capped at 65 KB. Large conversation attachments are truncated with a …truncated, see QRY conversation <url> link.
  • GitHub API rate limits are 5,000 requests/hour for authenticated tokens. At normal report volume this is never hit; bulk sync of historical issues might.

See Also


Last updated: 2026-05-04

QRYA product of IXEN.