# TicketingSystem Internal ticketing system with CTI-based routing, severity levels, and automation integration. ## Features - **CTI routing** — tickets are categorised by Category → Type → Item, reroutable at any time - **Severity 1–5** — 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 - Nginx Proxy Manager pointed at the host port (default `3080`) - Access to your Gitea container registry ### 1. Copy files to your server ```bash scp docker-compose.yml .env.example user@your-server:~/ticketing/ ``` ### 2. Configure environment ```bash cd ~/ticketing cp .env.example .env ``` Edit `.env`: ```env REGISTRY=gitea.thewrightserver.net TAG=latest POSTGRES_PASSWORD= JWT_SECRET= CLIENT_URL=http://tickets.thewrightserver.net PORT=3080 ``` Point NPM at `http://:3080` for the proxy host. ### 3. Deploy ```bash docker compose pull docker compose up -d ``` ### 5. Seed (first deploy only) ```bash 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 ```bash 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 ```bash 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 ```bash 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_ Content-Type: application/json { "title": "[Plex] Backup - 2026-03-30T02:00:00", "overview": "Automated nightly Plex backup completed.", "severity": 5, "categoryId": "", "typeId": "", "itemId": "", "assigneeId": "" } ``` CTI IDs can be fetched from: - `GET /api/cti/categories` - `GET /api/cti/types?categoryId=` - `GET /api/cti/items?typeId=` 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`, `` | | `$REGISTRY/josh/ticketing-client` | `latest`, `` | **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: ```bash TAG= 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 ```