Skip to content

Repository files navigation

Helpdesk

Service-ticket application for the Stone-Age.io ecosystem: 816tech (the platform operator / MSP) runs it to support customer organizations. One Go binary embedding PocketBase (system of record, REST API, auth) and a Vue 3 SPA (staff app + requester portal).

The differentiating capability is machine-generated tickets: things and rule-router publish events inside a customer org's NATS account on helpdesk.>, the platform's managed-org export delivers them into the operator hub account as helpdesk.{platformOrgId}.> with unforgeable subject-based provenance, and the helpdesk's durable JetStream consumer turns them into tickets. Humans use the portal, staff app, or the authenticated webhook.

Features (v1)

  • Two identity classes: staff (agents/admins, cross-customer) and requesters (users, scoped to one customer). One login page; the router shows the right shell.
  • Staff workspace: a dashboard landing (queue counts, backlog aging, weekly inflow); a ticket queue with search, status/priority/assignee/customer/category filters, saved views, bulk assign/status, and CSV export; a reports view (time & visits by tech/customer, ticket volume by category and source); and admin for customers, requesters, staff, categories, and notification templates.
  • Requester portal: a company dashboard, a searchable list of their own tickets, threaded ticket detail with attachments, a new-ticket form, and a read-only visit schedule.
  • Ticketing core: sequential ticket numbers, status/priority/assignee, admin-managed categories + free-text asset/location, comment threads with staff-only internal notes, time entries, site visits.
  • Activity & files: workflow changes (status/priority/assignee) recorded to a staff-only audit timeline; file attachments on tickets and comments; a public requester reply on a resolved/closed ticket auto-reopens it.
  • Lite dispatch: promote a ticket to on-site work with a requested visit (no tech/time yet), schedule it from the staff Dispatch view (needs-scheduling bucket + day-grouped list), free-text visit location. Requesters see their visits read-only in the portal.
  • Customers directory: platform-org mapping for NATS ingestion, per-customer webhook tokens (admin reveal/rotate).
  • Outbound email: DB-stored templates (Go text/template, editable in the SPA) fired from record hooks — created / assigned / commented / status changed / visit scheduled / rescheduled / canceled — with per-event recipient specs, a send log, and day-keyed dedupe. No SMTP configured = clean no-op. See docs/notifications.md.
  • Inbound machine tickets: NATS durable consumer + authenticated webhook (POST /api/helpdesk/inbound/{token}), both idempotent via dedupe_key. See docs/protocol.md.
  • Throughout the SPA: live updates (PocketBase realtime subscriptions), light/dark themes, keyboard shortcuts, responsive table-to-card layouts, and self-service profile edits + forgot-password reset.

Build & run

The SPA is //go:embed-ed at compile time; the committed internal/webui/public means a fresh checkout builds without npm — but rebuild and re-commit it whenever ui/ changes.

cd ui && npm ci                 # once
npm run build                   # vue-tsc + vite → ../internal/webui/public (commit the output)
cd .. && go build ./cmd/helpdesk
./helpdesk serve                # UI at http://127.0.0.1:8090/ · PocketBase admin at /_

First start seeds a bootstrap staff admin (admin@helpdesk.local) and prints its password once. Configuration is helpdesk.yaml + HELPDESK_* env overrides — see docs/configuration.md. SMTP (outbound email) and the application URL (ticket links in emails) are configured in the PocketBase dashboard, not the YAML.

The UI is rebrandable at runtime without a rebuild: point branding.dir (env HELPDESK_BRANDING_DIR) at a host directory of theme.css / logo.svg / branding.json to override the app name, logo, and theme — see docs/configuration.md and the branding.example/ template.

go test ./...

Repo layout

cmd/helpdesk/        PB bootstrap, OnServe wiring, embedded UI, retention cron
config/              viper Config (HELPDESK_ env prefix)
migrations/          Go schema-as-code (collections, rules, seeds)
internal/
  authz/             access-rule vocabulary shared by migrations + routes
  tickets/           ticket-number assignment + field defaults, auto-reopen
  visits/            visit status defaulting + scheduled-visit invariant
  activity/          ticket_events audit trail (status/priority/assignee)
  authfix/           auth-default fixups (email visibility on create)
  notifications/     notifier core, templates, lifecycle hooks, editor API
  subjects/          NATS subject grammar (helpdesk.{org}.tickets.{verb})
  natsx/             NATS connect (creds file) + inbox stream helper
  ingest/            durable consumer → ticket projection
  inbound/           webhook route + webhook-token reveal/rotate
  webui/             //go:embed all:public (committed SPA dist)
  testutil/          real-PB-against-t.TempDir() test harness
ui/                  Vue 3 + Vite + Pinia + Tailwind + daisyUI SPA
docs/                plan, data model, wire protocol, notifications, config

Architecture notes

  • Standalone sibling app (kiosk / access-control pattern), deliberately not a platform feature: helpdesk agents never hold control-plane credentials, and the tenancy axes differ (platform tenant = customer org; helpdesk tenant = the MSP).
  • Tenancy is plain collection rules — customers + users.customer + staff roles (internal/authz). No pb-tenancy. See docs/data-model.md.
  • NATS is best-effort: the app boots and serves portal/webhook traffic without a broker; the durable consumer resumes where it left off.
  • The org id in a machine ticket comes from the subject (rewritten by the operator-signed platform import), never the payload.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages