Shows a separator and centered "Clear selection" at the bottom of the dropdown
when any statuses are selected. Clearing shows all tickets regardless of status.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Status filtering now supports selecting multiple statuses via a dropdown with checkboxes.
Backend updated to accept comma-separated status values using Prisma `in` operator.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Split the dense single-row filter bar into two rows: search + saved views on top,
filter selectors below. Fix CTI selectors to use design system tokens instead of
hardcoded dark classes, and upgrade the saved views button with an icon and badge count.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- .gitignore: add coverage/, .vscode/, .idea/
- .env.example files: add header comments clarifying production vs dev,
add SMTP vars to server dev template
- Validate SavedView filters on load with safeParse fallback
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extracted TicketFilters, BulkActions, and TicketListItem into
client/src/pages/tickets/. The main Tickets.tsx remains as the
page orchestrator with state management and pagination.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extracted TicketComments, TicketAuditLog, and TicketSidebar into
client/src/pages/ticket-detail/. The main TicketDetail.tsx remains
as the page orchestrator. Router import unchanged via index.ts
re-export.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replaced loose Record<string, unknown> types on useCreateTicket,
useUpdateTicket, useCreateUser, useUpdateUser, useUpdateWebhook,
and useCreateSavedView with their corresponding shared schema types.
Fixed three type errors this surfaced at call sites.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
STATUS_LABELS was defined in the server, AUDIT_LABELS and AUDIT_COLORS
in the client. Both layers now import from a single shared source.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Severity-to-color mapping was duplicated in SeverityBadge, Tickets,
and MyTickets. Consolidated into lib/severityColors.ts with both
solid-bg (for stripes) and badge-style (for badges) variants.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Removes the blue tint from all dark-mode surfaces by switching CSS
variables to zinc-based neutrals, and replaces decorative blue classes
with indigo across buttons, focus rings, tabs, and links. Semantic blue
(severity badges, status badges, role badges, timeline markers) is
preserved.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dashboard now opts into `wide`, and the wide container scales from 1400
to 1800px at the 2xl breakpoint so content uses the extra room on big
monitors. Queue-load grid gains xl/2xl column counts for the new width.
Below 1536px nothing changes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Every AGENT now gets an auto-generated API key on creation, shown once
in a modal. AGENTs log in with password and authenticate to the API
with X-Api-Key. pre-push.sql defensively migrates any residual SERVICE
rows to AGENT before Prisma rewrites the enum. Goddard is no longer
baked into the seed — create agents via Admin → Users.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Command palette (cmd+K) with fuzzy nav, ticket search, people lookup
and action entries (new ticket, logout, show shortcuts). Opens from
keyboard or user dropdown.
Global keyboard shortcuts via a small useShortcut/useLeaderShortcut
hook: `?` help overlay, `c` new ticket, `g d|t|m|n|s` leader nav.
Tickets list: j/k cursor, Enter open, x toggle select. TicketDetail:
`e` edit, `r` focus comment composer. All guarded against firing
inside text fields.
@mention autocomplete in the comment composer (MentionTextarea) with
arrow-key nav and Tab/Enter insert. Rendered comments and audit log
rewrite @username tokens to links pointing at that user's assignee
filter; unknown usernames left as plain text.
Mobile sweep: TicketDetail sidebar stacks below content on <md,
Settings profile grid collapses to one column, admin tables get
horizontal scroll with a 640px min width, CTI 3-column grid stacks
vertically on <md, New ticket severity/assignee grid same.
PWA: manifest.webmanifest, SVG icon, minimal network-first service
worker for the app shell (never caches /api/*), registered in
production builds only. Theme-color meta + manifest link in index.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Both forms use useForm with zodResolver against shared schemas
(loginSchema, createTicketSchema)
- Field-level errors rendered inline under inputs
- isSubmitting drives button disabled state
- NewTicket: severity registered with valueAsNumber; CTISelect wrapped in
nested Controllers (one per categoryId/typeId/itemId) since it controls
three form fields as a single compound input
- Admin forms stay on useState for now — they get redesigned with shadcn
dialogs in Phase 3, RHF migration lands with that
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- components.json, @/* path alias in tsconfig + vite config
- Tailwind config: CSS-variable-backed color tokens, animation plugin
- index.css: :root (light) and .dark token blocks (slate base) — currently
pinned to dark via class on <html> so visual appearance is unchanged
- src/lib/utils.ts: cn() helper (clsx + tailwind-merge)
- src/components/ui/: 16 primitives — button, input, label, textarea, badge,
avatar, separator, skeleton, dialog, dropdown-menu, select, tabs, tooltip,
sonner, alert-dialog, popover
- Nothing replaced yet; existing components still in place. Used in Phase 3.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Each comment is a bordered card with a distinct header bar (author name,
clickable relative timestamp, hover-to-reveal delete) and a body section
- Subtle spine line connects comments in the avatar column
- Composer matches card style: same header bar for Write/Preview tabs,
transparent textarea inside, submit row with border-top
- Comment timestamps default to relative, click to toggle absolute
(mirrors sidebar date toggle pattern)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Routes and links now use /:id (e.g. /V675409888) instead of /tickets/:id.
API calls are unaffected as they go through /api/tickets/.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Delete the now-unused SidebarField component from TicketDetail.tsx
- Add typecheck-client CI job that runs tsc --noEmit on the client before
the Docker build, so TypeScript errors surface fast with a clear message
- build-client now depends on typecheck-client passing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Defaults to relative time (e.g. '5 hours ago'); clicking switches to
absolute timestamp and back.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Status and Severity now match CTI style (full-width button, hover bg, no chevron)
- Remove 'Change routing' hint text from CTI block
- Replace Assignee dropdown with clickable block that opens a modal picker with avatars
- Add Assignee modal consistent with Status/Severity modal pattern
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Rename 'Details' card to 'Ticket Summary'
- Replace status/severity dropdowns with badge displays that open small modal pickers on click
- Show Category, Type, Issue as separate labeled rows that together act as one clickable unit opening the routing modal
- Reorganize into sections: status/severity, CTI routing, dates (created/modified/resolved), people (assignee + requester)
- Add Requester field showing the ticket creator with avatar
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- My Tickets: exclude RESOLVED and CLOSED, show active tickets only
- Queue filter: cascading Category > Type > Item picker — each leaf is
a distinct queue (e.g. TheWrightServer > Automation > Backup vs Sync)
- Server: support typeId and itemId as ticket list filter params
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Dark UI across all pages and components (gray-950/900/800 palette)
- New Ticket is now a centered modal (triggered from sidebar), not a separate page
- Add USER role: view and comment only; AGENT and SERVICE can create/edit tickets
- Only admins can set ticket status to CLOSED (enforced server + UI)
- Add My Tickets page (/my-tickets) showing tickets assigned to current user
- Add queue (category) filter to Dashboard
- Audit log entries are clickable to expand detail; comment body shown as markdown
- Resolved date now includes time (HH:mm) in ticket sidebar
- Store comment body in audit log detail for COMMENT_ADDED and COMMENT_DELETED
- Clarify role descriptions in Admin Users modal
- Remove CI/CD section from README; add full API reference documentation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Tickets get a random display ID (V + 9 digits, e.g. V325813929)
- Ticket detail page has Overview / Comments / Audit Log tabs
- Audit log records every action (create, status, assignee, severity,
reroute, title/overview edit, comment add/delete) with who and when
- Comments redesigned: avatar (initials + color), markdown rendering
via react-markdown + remark-gfm, Write/Preview toggle
- Dashboard shows displayId and assignee avatar
- URLs now use displayId (/tickets/V325813929)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>