webticketer

Updates

Every release of the bot and the panel, newest first. Currently on v0.20.1.

v0.20.1

Assignment notices in small type.

  • webAssignment notices are now sent as Discord subtext (small grey type), so they read as a status line in the ticket channel rather than a message from staff.
  • webThe webticketer logo now leads to the public website everywhere it appears: the sidebar, sign-in, Inbox, About, My tickets and the no-servers page.
v0.20.0

Data protection: members can download or delete their own data.

  • webMy tickets has a Your data card showing how many tickets are held about you across all servers, whether or not a server shares transcripts.
  • webDownload my data returns a JSON file of every ticket you opened: your messages, the replies you were sent and the names of attached files. Internal notes and the staff timeline are never included.
  • webDelete my data permanently removes every ticket you opened, in every server, after a confirmation: messages, notes, timeline, archive and files, plus the Discord channel of any ticket still open.
  • webAdmins get a Delete this member's data button on a member's page, for deletion requests made to a server's staff. It is limited to that server.
  • webDeletion is one transaction per ticket with files removed afterwards, so an interruption never leaves half a ticket.
v0.19.0

Optional notices to the member when a ticket changes hands.

  • webNew admin toggle in Server settings, off by default: when a ticket is assigned, reassigned or unassigned from the panel, the bot posts a one-line notice in the ticket's Discord channel naming the agent now handling it.
  • webNotices are only sent when the assignee actually changes and the ticket is open. If Discord refuses the message, the assignment still goes through and the timeline records that the member was not told.
  • webThe panel's browser tab icon is now the webticketer mark, the same one the public website uses.
v0.18.2

Refresh roles button in Server settings.

  • webServer settings has a Refresh roles button beside Save. The panel remembers a server's roles for a minute; the button drops that copy and reads them from Discord again, so a role created moments ago can be ticked straight away.
v0.18.1

Privacy and terms pages, linked from sign-in.

  • webThe sign-in page now says that sign-in happens on discord.com and what the panel receives, and links to the new privacy and terms pages on the public website.
  • webEvery other page links to them too: the sidebar footer in the panel, and the foot of My tickets, Inbox, About and the no-servers page.
  • webFixed Discord sign-in failing with a server error: Discord now names itself as the issuer in its response, and the sign-in library was comparing that against a placeholder.
v0.18.0

Ready to deploy: one container image, and separate addresses for staff and end users.

  • webThe panel can answer on two hostnames: one for staff and one for the end-user ticket history. A request proxy sends each path to the right address; sign-in and About work on both. With only one address configured nothing changes.
  • webDiscord sign-in now builds its callback address from the configured public addresses, so it works behind a reverse proxy on either hostname.
  • webTranscript links in close DMs point at the end-user address when one is set.
  • webProduction setup added: a container image built by GitHub Actions, and a Docker Compose stack with PostgreSQL, a one-shot schema step and Caddy for HTTPS.
  • botRuns from the same container image as the panel, sharing the attachments volume.
  • botTranscript links in close DMs point at the end-user address when one is set.
v0.17.2

Add-server link pinned to a server install.

  • webThe Add server link now asks Discord for a server install explicitly, so it matches the invite link generated in the developer portal.
v0.17.1

The webticketer logo across the panel.

  • webNew logo, a ticket with its stub torn off, drawn as an inline graphic that switches to a lighter blue in the dark theme.
  • webThe logo and name sit at the top of the sidebar. The server switcher moved from there into the panel header, where the server name used to be; on phones it shows only the server's icon, and its menu ticks the current server.
  • webThe sign-in page, About, Inbox, the no-servers page and the My tickets header carry the logo at the top.
v0.17.0

Phone layouts across the panel.

  • webTicket lists show a card per ticket on phones, with one search box, instead of a wide table that had to be scrolled sideways. The table with column filters and sorting remains from tablet width up.
  • webOn phones the ticket's Details panel sits above the conversation in two compact columns, so status and assignee are reachable without scrolling to the bottom.
  • webThe dashboard chart is drawn at its real on-screen width, so its text and lines are legible on a phone, with fewer date labels when space is tight.
  • webMy tickets (the end-user history) uses cards on phones.
  • webDashboard tiles for active tickets, triage and closed tickets link to their queues.
  • webThe header search drops its keyboard hint on phones; page padding is tighter on small screens.
v0.16.1

The attachments dropdown remembers whether it is open.

  • webThe open or hidden state of the ticket Attachments section is saved in the browser (localStorage), so it stays the way each agent left it across tickets, reloads and other tabs.
  • webThe saved state is applied straight after the page loads; with storage blocked the section still works but is not remembered.
  • webThe ticket Details panel now stays in view while the conversation scrolls, and scrolls on its own when it is taller than the window.
v0.16.0

Attachments both ways, an attachments list on each ticket, and compressed files for archived tickets.

  • webAgents can attach files to a reply (up to 5 files, 8 MB each). They are sent to the user in Discord with the reply, and the panel keeps its own copy like it does for files users send. A reply can be files only, with no text.
  • webEach ticket's details panel has an Attachments list: every file sent by the user or by staff as a link (images included), with its size and sender. The list can be hidden and shown with its dropdown button.
  • webWhen a ticket is archived its files are compressed with Brotli. A file is only replaced when the compressed copy is at least 5% smaller, so photos, videos and zips, which are compressed already, are left as they are. Files are decompressed transparently when opened, re-sent on reopen, or downloaded.
  • webFile storage moved into one shared module used by the panel, the bot and the archive commands, which also finds the attachments folder regardless of where a command is started from.
  • webThe request size limit for panel actions was raised to allow uploads.
  • webReplying to a ticket that has no Discord channel now says so, instead of claiming it is closed.
  • botIncoming files are stored through the shared module.
  • botThe start-up sweep and npm run db:archive also compress files of tickets archived earlier.
v0.15.0

Closed tickets can be reopened.

  • webAgents get a Reopen ticket button on closed tickets, with a confirmation.
  • webReopening creates a new private Discord channel for the user and a fresh reply webhook, restores the conversation from the compressed archive back into ordinary rows, and sets the ticket to Open.
  • webThe user is sent a DM saying the ticket is open again, with a button straight to the channel; a failed DM is noted in the timeline and they are also pinged in the channel.
  • webThe earlier public conversation (the user's messages and staff replies, not deleted ones) is posted into the new channel by the bot, packed into as few messages as possible, with times shown in each reader's own zone. Internal notes and the staff timeline are never posted.
  • webAttachments from the earlier conversation are uploaded again from the panel's stored copies (up to 8 MB each).
  • webReopening is refused if the user has left the server. If Discord or the database fails part-way, the ticket stays closed and no channel is left behind.
  • botNo change needed: the bot picks up the new channel like any ticket channel, and ignores the history it did not write as a user.
v0.14.0

Weekly and monthly views on the dashboard chart.

  • webThe opened/closed chart has three tabs: Daily (last 14 days), Weekly (last 5 weeks, Monday to Sunday) and Monthly (each month of the year so far).
  • webThe current week and month are marked 'so far' in the hover readout, since they are incomplete.
  • webThe daily view still uses the viewer's own time zone. The weekly and monthly views are counted in UTC days: the server sends one total per day rather than a year of individual times.
v0.13.1

Smoother chart, and the dashboard can be locked to admins.

  • webThe opened/closed chart is redrawn as smooth curves that pass through every day's value (monotone interpolation, so they never dip below zero or overshoot), over soft gradient fills, with a lighter grid.
  • webRemoved the 'show these numbers as a table' toggle under the chart.
  • webFixed a crash when the chart was hovered while it had no measurable width.
  • webNew Server settings switch: 'Only admins can see the dashboard'. When on, the Dashboard link disappears from agents' sidebars and the page itself returns not found for them.
v0.13.0

Analytics dashboard.

  • webNew Dashboard page per server, linked at the top of the sidebar above the queues.
  • webHeadline figures: active tickets, tickets waiting in triage, opened and closed in the last 7 days (with the 7 days before for comparison), average response wait and average time to close.
  • webA 14-day chart of tickets opened and closed per day, drawn in the viewer's own time zone, as smooth curves over soft gradient fills, with a hover readout for each day.
  • webActive tickets broken down by status and by ticket panel, each row linking to that filtered list, and a per-agent table of tickets held now and closed in the last 7 days.
  • webAll figures come from the ticket records themselves, so archived (closed) tickets are counted without decompressing anything.
v0.12.0

Optional response and close-time averages on ticket panels in Discord.

  • webEach ticket panel has two independent switches in its editor: show the average response wait time, and show the average time to close a ticket.
  • webBoth are worked out from that panel's own tickets over the last 7 days and appear as fields on the panel's Discord message, with a footer saying what they cover and when they were last updated. With no tickets in the period the field reads 'No data yet'.
  • webPosting or updating a panel from settings includes fresh figures straight away.
  • webTickets now record when staff first replied, since the messages themselves are archived on close.
  • botRefreshes the figures on every posted panel that shows a statistic once they are 24 hours old. It checks hourly, so the daily schedule survives restarts.
  • botA reply typed by an admin directly in the Discord channel counts as the first staff response.
  • botThe panel message is now built by code shared with the web app, so both produce the same message and buttons.
v0.11.1

Removed a bundler warning printed on every page.

  • webThe shared database package re-exported the whole Prisma client, which made the bundler add runtime shims and warn on each compile. It now re-exports the types only.
v0.11.0

Closed tickets are stored compressed, about ten times smaller.

  • webClosing a ticket now archives it: its messages, internal notes and timeline are packed into one Brotli-compressed record and the individual rows are deleted, in a single transaction.
  • webMeasured on 200 generated tickets of 40 messages each: about 24 KB per ticket as rows against about 2.5 KB archived, with every message read back intact.
  • webClosed tickets read exactly as before in the ticket view and in user transcripts, and attachments still open. Internal notes inside the archive stay staff-only and hidden from the ticket's opener.
  • webSearch still finds closed tickets by message and note text, through a small word list kept beside each archive; only matching archives are decompressed.
  • webClosing still deletes the ticket's Discord channel; if Discord refuses, the timeline now says so instead of failing silently.
  • webNew command to archive any closed ticket that was missed: npm run db:archive.
  • webMentions on a ticket are removed from the inbox when it is closed.
  • botTickets closed by deleting their channel in Discord are archived the same way.
  • botOn start-up the bot archives any closed ticket that is not archived yet.
  • botAttachments are linked to their ticket as well as their message, so they survive archiving.
v0.10.3

Internal notes sealed off from ticket openers; custom scrollbars everywhere.

  • webInternal notes are now hidden from whoever opened the ticket even when that person is staff: the notes are not loaded for them, they cannot add notes to their own ticket, and search neither matches nor shows them.
  • webA mention can no longer deliver note text to the ticket's opener, or to anyone who is not staff at that moment: recipients are re-checked live against Discord rather than trusted from the stored staff list.
  • webMentions on a ticket the reader opened are left out of the inbox and the unread badge.
  • webAll scrollbars are styled by the panel: thin, trackless, tinted from the text colour and slightly stronger on hover, in both themes. The browser is also told the active colour scheme so its built-in parts match.
v0.10.2

Fixes from a full code review.

  • webDates and times now show in each viewer's own time zone instead of the server's; the server sends UTC and the browser converts it on load.
  • webSaving in the signature editor no longer jumps the staff picker back to yourself, and saving one ticket panel no longer discards unsaved edits to the others. Both editors now follow saved changes without being rebuilt.
  • webUpdating a posted panel only reposts when the old Discord message is really gone; any other failure is reported instead of leaving two copies in the channel.
  • webAccess checks no longer write to the database on every page load and refresh, and the staff list sync runs in the background instead of holding up the page on large servers.
  • webThe sidebar's unread badge counts only servers you can still open, matching the inbox.
  • webHardening: the post-login redirect rejects control characters, and the guild-locked database client also covers bulk update-and-return.
  • webHeader search closes on navigation without an extra render pass.
  • botLink previews no longer mark a message as edited: Discord's preview update carries no edit time and is now ignored.
  • botA member can have at most 3 open tickets per server; further attempts get a clear message instead of a new channel.
  • botIf saving a new ticket fails after its channel was created, the channel is removed instead of being left orphaned.
  • botMessages written in a ticket channel by anyone other than its opener (server admins) are recorded as staff, and no longer flip the ticket to User updated.
v0.10.1

Filter closed tickets by panel.

  • webThe Closed queue has a row of panel chips with counts, like the status chips on All tickets: All, one per ticket panel, and No panel when some closed tickets have no type.
  • webThe filter is applied on the server, so it reaches beyond the 200 most recent closed tickets.
v0.10.0

Admins can stop agents changing their own signature.

  • webNew per-server toggle under Server settings, Staff signatures: 'Let agents change their own signature' (on by default).
  • webWhen off, an agent's signature editor is read-only with its toolbar and buttons switched off, and a tooltip explains it is disabled by an admin. The preview still shows their signature.
  • webThe save action enforces the setting on the server, so it cannot be bypassed from the browser. Admins can always edit any signature, including their own.
v0.9.2

No browser-native dropdowns left in the panel.

  • webNew shared picker component: a custom menu in the panel's style with a tick on the current choice.
  • webThe Discord channel picker in the panel editor and the staff picker in the signature editor now use it; the staff picker shows avatars.
v0.9.1

Development servers reload themselves after database changes; theme no longer uses a script.

  • webThe demo and development launchers now watch the generated database client and restart the panel when it changes, instead of crashing pages until restarted by hand. The demo also updates its own database on restart.
  • webTheme rewritten without any script: with no choice made, CSS follows the operating system; a choice from the toggle is stored in a cookie and rendered by the server. This removes the script-tag warning that accompanied every development crash.
v0.9.0

Multiple ticket panels, ticket types, and a queue per panel.

  • webAdmins can create any number of ticket panels under Server settings. Each has a name, a Discord channel, message text and up to ten ticket types, and is posted to or updated in Discord from the panel.
  • webTickets carry the type chosen when they were opened. Ticket lists gained a Type column (type and panel) that can be filtered and sorted like the others.
  • webThe sidebar has a Panels section with one queue per panel and its active count. My tickets, the staff queues, Triage and All tickets still list every panel's tickets together.
  • webAgents can move a ticket to another type or another panel from the ticket's details panel, for tickets opened in the wrong place; the move is logged in the timeline.
  • webDeleting a panel or a type keeps its tickets, which simply lose the type. Editing a posted panel updates the existing Discord message; moving it to another channel reposts it and removes the old one.
  • webThe single built-in ticket panel was replaced by this editor.
  • botPanel buttons carry their ticket type; the type is checked against the server when the form is submitted and stored on the ticket.
  • botThe ticket channel's topic and opening message show the type.
  • botButtons from the earlier single panel still work and open a ticket without a type.
v0.8.1

Sortable columns on every ticket list.

  • webColumn names are clickable: first click sorts lowest to highest, second highest to lowest, third returns to the queue's default order. An arrow shows the active sort.
  • webText columns sort alphabetically ignoring case, ticket numbers numerically, Last activity by time, and Status in workflow order; unassigned tickets always sort last under Assigned to.
  • webSorting combines with the column filters and runs in the browser.
v0.8.0

Column filters on every ticket list.

  • webEach column heading in the ticket lists (Triage, All tickets, My tickets, staff queues, Closed, user pages, inbox) has a filter icon.
  • webSubject, Opened by and Ticket open a search box: the list narrows on every keystroke and matching values are offered to pick from.
  • webAssigned to, Status and (in the inbox) Server open tick lists with a count beside each value; options reflect the other active filters.
  • webActive filters highlight their icon, show a 'Showing N of M' line and can be cleared together.
  • webFiltering runs in the browser over the rows already loaded, so it is instant and survives the 5-second refresh.
v0.7.4

Change status and assignee straight from the ticket details panel.

  • webStatus and Assigned to in the details panel are now clickable menus: pick a status badge, or pick an agent (yourself listed first) or unassign.
  • webThey use the same server actions as the action bar, so changes are logged in the timeline the same way.
v0.7.3

Status pickers show the status colours.

  • webThe composer's status picker is now a custom menu instead of the browser's plain dropdown: each option is the same coloured badge used in the queues, with a tick on the current choice.
  • webThe Status menu in the ticket action bar uses the same badges.
v0.7.2

Set the ticket status while sending a reply or saving a note.

  • webThe reply and internal-note composer has a status picker. Replies default to With user; choosing anything else overrides that automatic change.
  • webNotes default to leaving the status alone, and can set one in the same step.
  • webA status chosen in the composer is recorded in the timeline; the automatic With user change is not.
  • webFormatting fix: underscores inside a word (snake_case, IDs) are no longer treated as italics, matching Discord.
v0.7.1

Theme switcher no longer depends on a library.

  • webReplaced the theme library with a small built-in implementation; the no-flash script now sits in the document head.
  • webBehaviour is unchanged: follows the operating system by default, remembers a manual choice per browser, and toasts follow the active theme.
  • webKnown and harmless in development: if a page crashes, the error overlay also lists a script-tag warning for the theme script, because the crash makes the layout re-render in the browser.
v0.7.0

More ticket statuses, each with its own colour.

  • webNew statuses alongside Open and Closed: In progress, User updated, With user, Escalation and On hold.
  • webEach status has its own badge colour; the ones needing staff action (Open, User updated, Escalation) are solid and saturated, the rest are soft tints.
  • webStatus menu in the ticket action bar; changes are recorded in the timeline.
  • webSending a reply sets the ticket to With user automatically.
  • webQueues, sidebar counts, the inbox and search now treat every status except Closed as active; All tickets gained a filter by status with counts.
  • webEnd users still see only Open or Closed in My tickets.
  • botA message from the user moves a ticket that was With user, On hold or In progress to User updated.
  • botMessages in a closed ticket's channel are no longer ingested.
v0.6.0

Transcripts for end users, and a My tickets area where anyone can read their own closed tickets.

  • webPer-server admin toggle (off by default) under Server settings to share transcripts with the people who open tickets.
  • webClosing a ticket DMs the opener a link to its transcript when the toggle is on; delivery or failure is recorded in the ticket timeline.
  • webNew My tickets area: any Discord user can sign in and see the tickets they opened, across all servers or filtered to one, and read the closed ones.
  • webTranscript queries are locked to the signed-in user's own tickets and select user messages and staff replies only: internal notes, assignment history and deleted messages are never included.
  • webSign-in now returns to the page that asked for it (same-site paths only), so the DM link lands on the transcript after the OAuth round trip.
  • webAttachment serving shared between the staff and user routes, each with its own access check.
  • botA ticket closed by deleting its channel in Discord also sends the opener the transcript link when the server has transcripts on.
v0.5.2

Demo mode can preview the panel as an ordinary staff member.

  • webDemo mode accepts DEMO_AS=staff to render the panel with staff-level rather than admin-level access, used to verify that Server settings is withheld from non-admins.
v0.5.1

Settings split into User settings and Server settings tabs.

  • webSettings page now has two tabs: User settings (your own signature) and Server settings (staff signatures, staff and admin roles, ticket panel).
  • webThe Server settings tab is only shown to admins; the sidebar link is renamed to Settings.
v0.5.0

Agent signatures with a formatting toolbar and live preview; replies always carry the agent's picture.

  • webPer-agent, per-server signatures appended to every reply sent to the user. Agents edit their own in Server settings; admins can edit anyone's.
  • webSignature editor with a formatting toolbar (bold, italic, underline, strikethrough, code, spoiler, link, quote, small text) and a Discord-style live preview beside it.
  • web{name} and {role} placeholders, filled in at send time from the agent's current display name and highest Discord role.
  • webReplies now read the agent's name and picture live from Discord (server avatar, then account avatar, then Discord's default), so a reply is never sent without a profile picture.
  • webThe ticket timeline renders Discord formatting through a safe element-based renderer instead of showing raw markup.
  • webServer settings is now visible to all staff; the role and ticket-panel sections remain admin-only.
v0.4.0

Global search for users and tickets in the header bar.

  • webSearch bar in the panel header (Ctrl+K) with live results as you type and a full results page on Enter.
  • webFinds users (ticket openers, by name or Discord ID) and tickets, open and closed; users are always listed first.
  • webTickets are matched on number, subject, opener, user messages, staff replies and internal notes, with the matching excerpt shown and search words highlighted.
  • webRanking: tickets containing every search word beat partial matches; subject and name hits outweigh body text; word-start and whole-phrase matches score higher; recent and open tickets get a small boost.
  • webNew user page listing all of one user's tickets, linked from search results and the ticket details panel.
  • webThe Closed queue's own search box was removed in favour of the header search.
v0.3.0

Closed queue with search.

  • webNew Closed queue in the sidebar: closing a ticket moves it there, ordered by most recently closed.
  • webSearch bar on the Closed queue matching ticket number, subject, opener name and message text (case-insensitive, server-side).
  • webAll tickets now lists open tickets only; its Open/Closed/All filter was replaced by the Closed queue.
v0.2.0

Dark mode.

  • webToggleable dark mode: follows the operating system by default, with a sun/moon switch in the panel header and on the login, inbox and about pages. The choice is stored per browser.
v0.1.1

Demo mode for previewing the panel without Discord, plus a font fix.

  • webDevelopment-only demo mode: seeded servers, staff and tickets in a separate database, with sign-in and Discord lookups stubbed. Disabled in production builds.
  • webFixed the sans-serif font variable so the panel no longer falls back to a serif face.
  • webHid the framework's development overlay, which covered the sidebar footer.
v0.1.0

First concept build: tickets open in Discord and are worked from the panel.

  • webDiscord OAuth sign-in (identify scope only); staff and admin levels are derived from guild roles through the bot.
  • webMulti-server support with a server switcher; every tenant query runs through a guild-locked database client.
  • webQueues: Triage, All tickets, My tickets and one per staff member, with open counts in the sidebar.
  • webTicket view with an action bar (reply, internal note, assign, close), a newest-first timeline and a details panel.
  • webStaff replies are delivered through a per-ticket webhook under the staff member's name and avatar.
  • webInternal notes with @mentions; mentioned staff get a bot DM linking to the ticket, with an in-panel fallback.
  • webCross-server inbox for assigned tickets and mentions.
  • webServer settings: staff and admin role selection, and posting the ticket panel to a channel.
  • webMirrored attachments are served through an access-checked route; only known image types render inline.
  • webPages refresh by polling every 5 seconds.
  • webAbout page and devlog.
  • botRegisters each server it joins and marks it inactive when removed; optional server allowlist.
  • botTicket panel button opens a subject and description form, then creates a private ticket-NNNN channel.
  • botPer-server ticket numbering allocated atomically.
  • botIngests messages, edits and deletions from ticket channels into PostgreSQL.
  • botCopies attachments to local storage on arrival, since Discord CDN links expire.
  • botDeleting a ticket channel by hand closes the ticket.