Initial commit: TicketingSystem
Some checks failed
Build & Push / Build Client (push) Failing after 9s
Build & Push / Build Server (push) Failing after 28s

Internal ticketing app with CTI routing, severity levels, and n8n integration.

Stack: Express + TypeScript + Prisma + PostgreSQL / React + Vite + Tailwind
- JWT auth for users, API key auth for service accounts (Goddard/n8n)
- CTI hierarchy (Category > Type > Item) for ticket routing
- Severity 1-5, auto-close resolved tickets after 14 days
- Gitea Actions CI/CD building separate server/client images
- Production docker-compose.yml with Traefik integration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-30 19:38:32 -04:00
commit 21894fad7a
50 changed files with 3293 additions and 0 deletions

213
README.md Normal file
View File

@@ -0,0 +1,213 @@
# 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
```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>
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:
```bash
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
```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
```