- POST /tickets now returns { ticket, scrip_results } matching PATCH pattern
- createTicket API function returns UpdateResult instead of Ticket
- Update call site to use data.ticket.id
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- src/db/seed.ts: comprehensive seed data with idempotent upserts
- 5 users (system, gjermund, operator, technician, analyst)
- 5 queues (Support Desk, Operations, IT Infrastructure, Facilities, Field Ops)
- 1 lifecycle (Demo service lifecycle with new→open→in_progress→resolved→closed)
- 5 custom fields (impact, location, channel, urgency, outcome) with short keys
- 10 realistic support tickets with varied statuses, custom fields, and history
- 3 scrips (OnCreate email, OnResolve custom field, customer notification)
- 2 templates (auto-response, resolve notification)
- --reset flag to truncate all data before seeding
- scripts/smoke-test.ts: API smoke tests
- scripts/watch-frontend.sh: frontend dev helper
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New routes:
- GET /users — list all users
- GET/POST /templates — list and create templates
- PATCH /templates/:id — update template
- POST /templates/preview — render template with ticket/demo context
Enhanced routes:
- tickets: custom field support on create, status classification helper
- custom-fields: PATCH endpoint, auto-generate short key from name
- lifecycles: PATCH endpoint
- queues: PATCH endpoint
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- SendEmail: real nodemailer transport with SMTP config, dynamic recipient resolution
(static + ticket creator/owner lookup), Handlebars template support
- Webhook: HTTP POST/any method with configurable headers and JSON body
- FetchMetadata: external HTTP fetch, Handlebars URL/body templating,
auto-adds result as comment/correspondence on ticket
- RunScript: arbitrary async JS execution with helpers (addComment,
createTransaction, updateTicket, touchTicket), ticket context, and
Drizzle ORM access
- SetCustomField: lookup by id/key/name, clear+insert value, record
CustomFieldChange transaction
- CreateTransaction: insert arbitrary transaction record
- Add OnCustomFieldChange condition
- Pass condition_config to evaluator in engine
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Add npm scripts for dev, migrate, seed, smoke
- Add key column to scrips table (unique short identifier)
- Register users and templates routes in server
- Set development: false in Bun.serve for production mode
- Add description and custom_fields to CreateTicketSchema
- Make owner_id nullable/optional for unassigned tickets
- Add migration for custom field key column
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Backend:
- POST /:id/comment endpoint accepting {body, internal?, creator_id?}
- internal=false → Correspond (public reply), internal=true → Comment
- Runs scrip engine on the new transaction so notifications fire
- CommentSchema zod validation
Frontend:
- sendComment() API function in lib/api.ts
- Send button wired with onClick, sending spinner, disabled state
- Error display below reply box, clears on new typing
- Refreshes transaction list after successful send
- Reply/Internal note mode passed as internal flag
- Remove three-column layout, inline detail panel, and properties sidebar
- Click a ticket navigates to /tickets/[id] via router.push
- Redesign TicketRow as inbox-style: status dot, bold subject on top line,
muted ID/queue/owner meta on second line, time right-aligned
- Cleaner visual hierarchy with increased padding and gap
Backend returns PascalCase (Create, StatusChange, SetOwner, Comment, Correspond).
Frontend was checking lowercase, causing transaction rendering to fall through to raw type strings.
- layout.tsx: ThemeProvider from next-themes, light mode DEFAULT, JetBrains_Mono font
- globals.css: font-mono pointing to correct variable, font-feature-settings cv01+ss03 on body
- next-themes package installed
- Build passes with zero errors
- config.ts: add SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, SMTP_FROM
- engine.ts: prepare() queries real scrips from DB, matches by queue_id + condition_type, loads lifecycle for OnResolve context, renders Handlebars templates, builds PreparedScrip. commit() dispatches to real action executors.
- actions.ts: SendEmail via nodemailer SMTP, Webhook via fetch POST, SetCustomField writes to custom_field_values table
- conditions.ts: OnResolve uses LifecycleValidator.isResolvedStatus()
- tickets.ts: updated to pass lifecycleDef context to scrip engine
- nodemailer installed
- Port changed to 9876 (8080 occupied by Apache)
Verification: bun run src/index.ts starts server, GET /health returns {"status":"ok","version":"0.1.0"}