Point NPM at `http://<host-ip>:3080` for the proxy host.
Point NPM at `http://<host-ip>:3080` for the proxy host.
@@ -71,6 +88,8 @@ docker compose pull
docker compose up -d
docker compose up -d
```
```
The server exposes an unauthenticated `GET /healthz` that returns `{"status":"ok"}` and is polled by the compose healthcheck.
### 4. Seed (first deploy only)
### 4. Seed (first deploy only)
```bash
```bash
@@ -82,6 +101,17 @@ This creates:
-`admin` user (password: `admin123`) — **change this immediately**
-`admin` user (password: `admin123`) — **change this immediately**
-`goddard` service account — API key is printed to the console; copy it now
-`goddard` service account — API key is printed to the console; copy it now
### Upgrading from v0.9
v1.0 is drop-in for existing deployments — the schema changes are all additive (new tables for attachments, webhooks, notifications, saved views; new columns for notification prefs and search vectors). No data migration is required.
```bash
docker compose pull
docker compose up -d
```
`npm run start:prod` runs `prisma db push` on boot, which applies the new tables and the search-index migration automatically. Set the new `SMTP_*` env vars if you want email notifications — otherwise they're silently skipped.
---
---
## Development
## Development
@@ -109,9 +139,11 @@ docker run -d \
cd server
cd server
cp .env.example .env # set DATABASE_URL and JWT_SECRET
cp .env.example .env # set DATABASE_URL and JWT_SECRET
| `severity` | number | Filter by severity: `1`–`5` |
| `severity` | number | Filter by severity: `1`–`5`|
| `categoryId` | string | Filter by category (queue) |
| `categoryId` | string | Filter by category (queue) |
| `assigneeId` | string | Filter by assignee user ID |
| `assigneeId` | string | Filter by assignee user ID |
| `search` | string | Full-text search on title, overview, and display ID |
| `createdById`| string | Filter by author |
| `search` | string | Full-text search (tsvector) on title, overview, and display ID |
| `page` | number | Page number, 1-indexed. When omitted the endpoint returns a bare array (v0.9 shape) |
| `pageSize` | number | Page size (default 25, max 100) |
**Response:** Array of ticket objects with nested `category`, `type`, `item`, `assignee`, `createdBy`, and `_count.comments`.
**Response (paginated):**
```json
{
"data":[/*tickets*/],
"total":134,
"page":1,
"pageSize":25
}
```
**Response (unpaginated — `page` omitted):** Array of ticket objects with nested `category`, `type`, `item`, `assignee`, `createdBy`, and `_count.comments`. This preserves compatibility with v0.9 clients and the Goddard integration.
---
---
@@ -222,32 +274,116 @@ Update a ticket. Accepts any combination of fields. Requires **Agent**, **Admin*
> Setting `status` to `CLOSED` requires **Admin** role.
> Setting `status` to `CLOSED` requires **Admin** role.
**Body (all fields optional):**
```json
{
"title":"string",
"overview":"string (markdown)",
"severity":3,
"status":"IN_PROGRESS",
"assigneeId":"string | null",
"categoryId":"string",
"typeId":"string",
"itemId":"string"
}
```
All changes are recorded in the audit log automatically.
All changes are recorded in the audit log automatically.
**Response:** Updated ticket object.
---
---
#### `DELETE /api/tickets/:id`
#### `DELETE /api/tickets/:id`
Delete a ticket and all associated comments and audit logs. **Admin only.**
Delete a ticket and all associated comments, audit logs, and attachments. **Admin only.**
**Response:** 204 No Content.
---
#### `POST /api/tickets/bulk`
Apply an action to many tickets at once. **Agent** or **Admin**.
| `GET` | `/api/notifications` | Caller's notifications, newest first |
| `POST` | `/api/notifications/read` | Mark specific or all — returns `{ updated }` |
Notifications are created on assignment, @mention, and status → RESOLVED. Email delivery is attempted when SMTP is configured and the target user has email notifications enabled in `User.notificationPrefs`.
| `POST` | `/api/tickets/:id/attachments` | Upload (multipart, field `file`) |
| `POST` | `/api/comments/:id/attachments` | Upload on a comment |
| `GET` | `/api/attachments/:id` | Stream with original filename |
| `DELETE` | `/api/attachments/:id` | Uploader or Admin |
Size limit 25 MB per file. Storage path is controlled by `UPLOADS_DIR` (defaults to `./uploads` in dev, `/data/uploads` in the Docker image backed by the `uploads` volume).
---
### Webhooks
Admin-only. Outgoing webhooks fire on `ticket.created`, `ticket.status_changed`, `ticket.assigned`, and `comment.created`.
**Signature:** each delivery includes `X-Ticketing-Signature: sha256=<hex>`, which is the HMAC-SHA256 of the raw request body using the webhook's secret. Retries up to 3× with exponential backoff on non-2xx responses.
---
---
@@ -255,23 +391,15 @@ Delete a ticket and all associated comments and audit logs. **Admin only.**
#### `POST /api/tickets/:id/comments`
#### `POST /api/tickets/:id/comments`
Add a comment to a ticket. Supports markdown. All authenticated roles may comment.
Add a comment. Markdown body. @mentions are parsed and fire notifications to matched users.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.