josh ecaf17bf9f
All checks were successful
Build & Push / Build Server (push) Successful in 58s
Build & Push / Build Client (push) Successful in 42s
Add @types/node-cron to fix TypeScript build
node-cron v3 does not ship its own type declarations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 19:45:32 -04:00
2026-03-30 19:38:32 -04:00
2026-03-30 19:38:32 -04:00
2026-03-30 19:38:32 -04:00

TicketingSystem

Internal ticketing system with CTI-based routing, severity levels, and n8n/automation integration.

Features

  • CTI routing — tickets are categorised by Category → Type → Item, reroutable at any time
  • Severity 15 — SEV 1 (critical) through SEV 5 (minimal); dashboard sorts by severity
  • Status lifecycle — Open → In Progress → Resolved → Closed; resolved tickets auto-close after 14 days
  • Comments — threaded comments per ticket with author attribution
  • Roles — Admin, Agent, Service (API key auth for automation accounts)
  • Admin panel — manage users and the full CTI hierarchy via UI
  • n8n ready — service accounts authenticate via X-Api-Key header

Production Deployment

Prerequisites

  • Docker + Docker Compose
  • Traefik running with a proxy Docker network
  • Access to your Gitea container registry

1. Copy files to your server

scp docker-compose.yml .env.example user@your-server:~/ticketing/

2. Configure environment

cd ~/ticketing
cp .env.example .env

Edit .env:

REGISTRY=gitea.thewrightserver.net
TAG=latest
POSTGRES_PASSWORD=<strong password>
JWT_SECRET=<output of: openssl rand -hex 64>
DOMAIN=tickets.thewrightserver.net

3. Create the initial database migration

Run this once on your local dev machine before first deploy, then commit the result:

cd server
npm install
# point at your local postgres or use DATABASE_URL from .env
npm run db:migrate   # creates prisma/migrations/

Commit the generated server/prisma/migrations/ folder — prisma migrate deploy in the container will apply it on startup.

4. Deploy

docker compose pull
docker compose up -d

5. Seed (first deploy only)

docker compose exec server npm run db:seed

This creates:

  • admin user (password: admin123) — change this immediately
  • goddard service account — API key is printed to the console; copy it now

Development

Requirements

  • Node.js 22+
  • PostgreSQL (local or via Docker)

Start Postgres

docker run -d \
  --name ticketing-pg \
  -e POSTGRES_DB=ticketing \
  -e POSTGRES_USER=postgres \
  -e POSTGRES_PASSWORD=postgres \
  -p 5432:5432 \
  postgres:16-alpine

Server

cd server
cp .env.example .env        # set DATABASE_URL and JWT_SECRET
npm install
npm run db:migrate          # creates tables + migration files
npm run db:seed             # seeds admin + Goddard + sample CTI
npm run dev                 # http://localhost:3000

Client

cd client
npm install
npm run dev                 # http://localhost:5173 (proxies /api to :3000)

n8n Integration (Goddard)

The goddard service account authenticates via API key — no login flow needed.

Create a ticket from n8n:

POST https://tickets.thewrightserver.net/api/tickets
X-Api-Key: sk_<goddard api key>
Content-Type: application/json

{
  "title": "[Plex] Backup - 2026-03-30T02:00:00",
  "overview": "Automated nightly Plex backup completed.",
  "severity": 5,
  "categoryId": "<TheWrightServer category ID>",
  "typeId": "<Automation type ID>",
  "itemId": "<Backup item ID>",
  "assigneeId": "<Goddard user ID>"
}

CTI IDs can be fetched from:

  • GET /api/cti/categories
  • GET /api/cti/types?categoryId=<id>
  • GET /api/cti/items?typeId=<id>

To regenerate the Goddard API key: Admin → Users → refresh icon next to Goddard.


CI/CD

Push to main triggers .gitea/workflows/build.yml, which builds and pushes two images in parallel:

Image Tag
$REGISTRY/josh/ticketing-server latest, <git sha>
$REGISTRY/josh/ticketing-client latest, <git sha>

Gitea repository secrets/variables required:

Name Type Value
REGISTRY Variable gitea.thewrightserver.net
REGISTRY_TOKEN Secret Gitea personal access token with write:packages

Set these under Repository → Settings → Actions → Variables / Secrets.

To deploy a specific commit SHA instead of latest:

TAG=<sha> docker compose up -d

Environment Variables

Variable Required Description
DATABASE_URL Yes PostgreSQL connection string
JWT_SECRET Yes Secret for signing JWTs — use openssl rand -hex 64
CLIENT_URL Yes Allowed CORS origin (your domain)
PORT No Server port (default: 3000)
REGISTRY Deploy Container registry hostname
POSTGRES_PASSWORD Deploy Postgres password
DOMAIN Deploy Public domain for Traefik routing
TAG Deploy Image tag to deploy (default: latest)

Ticket Severity

Level Label Meaning
1 SEV 1 Critical — immediate action required
2 SEV 2 High — significant impact
3 SEV 3 Medium — standard priority
4 SEV 4 Low — minor issue
5 SEV 5 Minimal — informational / automated

Tickets are sorted SEV 1 → SEV 5 on the dashboard. Paging by severity is planned for a future release.


Ticket Status Lifecycle

OPEN → IN_PROGRESS → RESOLVED ──(14 days)──→ CLOSED
                         ↑
                    re-opens reset
                    the 14-day timer
Description
Internal ticketing system with CTI-based routing, severity levels, role-based access, and automation integration.
Readme 338 KiB
Languages
TypeScript 98%
CSS 1.1%
Dockerfile 0.5%
HTML 0.2%
JavaScript 0.2%