204 lines
4.9 KiB
Markdown
204 lines
4.9 KiB
Markdown
# 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=<strong password>
|
||
JWT_SECRET=<output of: openssl rand -hex 64>
|
||
CLIENT_URL=http://tickets.thewrightserver.net
|
||
PORT=3080
|
||
```
|
||
|
||
Point NPM at `http://<host-ip>: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_<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:
|
||
|
||
```bash
|
||
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
|
||
```
|