Skip to content
lukalulPublic

About

🎫 Self-hosted Discord support ticket bot β€” panels, claiming, staff threads, ratings, and gorgeous auto-generated HTML transcripts.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

9 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🎫 Ticket Bot

A full-featured, self-hosted Discord support ticket bot β€” panel-based ticket creation, staff claiming with channel locking, scheduled close/delete, staff discussion threads, ratings, and gorgeous auto-generated HTML transcripts (attachments, avatars, and animated GIFs included).

Drop it into any server and make it yours: the bot's name and logo are rebrandable straight from Discord with /setup, no code or redeploy required. Every message the bot sends is built with Discord's Components V2 UI system rather than classic embeds β€” same information, a more flexible layout.

License: MIT Node discord.js


✨ Features

  • 🎟️ Panel-based tickets β€” Discord Support / Website Support buttons, customizable per-post
  • πŸ™‹ Claiming & locking β€” staff claim a ticket to lock it, /unlock or /transfer to hand it off
  • πŸ›‘οΈ Rank-aware /add / /remove β€” higher-ups always bypass, basic staff can't touch a higher-up
  • 🧡 Staff discussion threads β€” private per-ticket threads, merged into the same transcript
  • ⏰ Auto-unclaim & escalation β€” idle claims release themselves, ignored tickets ping higher-ups
  • πŸ”’ Scheduled close/delete β€” 5-second cancel window, or schedule a close for later (in: 2h)
  • πŸ“„ Discord-authentic HTML transcripts β€” grouped messages, markdown, embeds, avatars (animated GIFs stay animated!), all generated from the bot's own message cache β€” no live channel fetch required, so deleted messages and deleted channels are both handled correctly
  • ⭐ Ratings & stats β€” DM rating prompts, /stats leaderboard, /staffstats deep-dive
  • 🚫 Ticket bans, full /history, canned /reply replies
  • 🎨 Rebrandable β€” name + logo image, both set live via /setup, no restart needed
  • 🧩 Components V2 UI β€” every panel, announcement, and menu is built from Discord's modern component system instead of classic embeds
  • πŸ” Single-admin gate β€” one Discord user ID in config.js controls all of /setup and /test, not editable from Discord itself

πŸ“‹ Requirements

  • Node.js 22.5.0+ (uses Node's built-in SQLite driver β€” no external database)
  • A Discord account that can create applications and manage your server

πŸš€ Quick start

1. Create the Discord application

  1. Head to the Discord Developer Portal β†’ New Application.
  2. Open the Bot tab:
    • Click Reset Token and copy it β€” you'll need it in step 3. πŸ”‘ Keep it secret.
    • Under Privileged Gateway Intents, enable both:
      • βœ… Server Members Intent
      • βœ… Message Content Intent

2. Invite the bot

  1. OAuth2 β†’ URL Generator β†’ check bot and applications.commands.
  2. Under Bot Permissions, check: Manage Channels, Manage Roles, View Channels, Send Messages, Read Message History, Attach Files, Embed Links, Manage Messages, Create Public Threads, Send Messages in Threads.
  3. Open the generated URL and add the bot to your server.
  4. ⚠️ Drag the bot's role above your staff roles in Server Settings β†’ Roles β€” it locks/unlocks tickets by editing permissions on those roles, which only works on roles below its own.

3. Configure it

npm run setup

This copies config.example.js β†’ config.js for you (or do it manually: cp config.example.js config.js). Then open config.js and fill in the 3 fields β€” each is explained with a comment right above it:

Field What it is
token Your bot token from step 1
guildId Your server ID (enable Developer Mode β†’ right-click server icon β†’ Copy Server ID)
adminUserId Your Discord user ID β€” the only person who can run /setup and /test

config.js is gitignored and never committed β€” it's yours alone. Everything else (channels, roles, cooldowns, branding) is not file-based β€” you configure it live in Discord in step 5.

4. Install & run

npm install
npm start

The bot registers its slash commands, runs a permissions health check, and logs anything wrong to the console.

5. Finish setup in Discord

As the adminUserId account, run /setup β€” it opens a dropdown menu covering everything:

🎨 Branding Β· 🎨 Color scheme Β· πŸ—‚οΈ Panel & ticket types Β· πŸ“„ Transcript channel Β· πŸ“ Log channel Β· πŸ“Š Stats channel Β· πŸ” Staff-stats channel Β· 🧡 Staff threads channel Β· πŸ‘₯ Staff team role Β· πŸ›‘οΈ Staff roles Β· ⭐ Higher-up roles Β· ⏳ Panel cooldown Β· 🚨 Escalation time

Then post the panel with /panel wherever you want it. πŸŽ‰


πŸ•ΉοΈ Commands

Command Who What
/panel [title] [description] Manage Server Posts the ticket panel β€” optionally override its text for this post
/claim Staff Claim the ticket, locking it to other staff
/unlock Claimer / higher-up Unlock so another staff member can /claim
/transfer user: Claimer / higher-up Hand a claimed ticket straight to someone else
/add user:/role: Staff Add a user or role to the ticket
/remove user:/role: Staff Remove a user/role (rank-checked β€” higher-ups bypass)
/rename name: Staff Renames the channel, its staff thread, and the transcript together
/close [reason] [in] Staff / opener Closes with a 5s cancel window; in: schedules it (30m, 2h, 1d)
/delete [reason] Staff Deletes with a 5s cancel window, transcript generated first
/open Staff Cancels a pending close/delete, or reopens a closed ticket
/reply name: Staff (in a ticket) Sends a canned reply β€” edit src/messages.js to add your own
/stats [period] [sort] Anyone (stats channel) πŸ† Leaderboard β€” claims, closes, response time, rating
/staffstats user: Higher-ups Full per-staff breakdown + every bad review
/ticketban user: reason: Higher-ups 🚫 Bans a user from opening tickets
/ticketunban user: Higher-ups Lifts a ticket ban
/history user: Staff Past tickets + ban status for a user
/setup πŸ” Bot admin The dropdown-driven configuration menu
/test πŸ” Bot admin Previews every message/embed the bot can send, plus a live avatar-in-transcript demo

🧠 How it all works

🎟️ Tickets & claiming
  • Pressing a panel button opens a short form asking why the ticket is being opened. Tickets are named ticket-0001, ticket-0002, … and created as top-level channels (no category).
  • Opening a ticket pings the opener and the staff team role.
  • Claiming a ticket removes Send Messages from the staff team role in that channel β€” the claimer, higher-ups, the opener, and anyone /add-ed can still chat. Another staff member can only take over after /unlock.
  • Staff can never claim (or be transferred) a ticket they opened themselves.
  • Higher-ups are never locked out β€” they can override claims, unlock anything, and remove anyone.
  • One open ticket per user at a time, plus a per-user anti-spam cooldown (default 60s, configurable).
πŸ”’ Closing, deleting & scheduling
  • /close archives the ticket: renamed to closed-XXXX, opener's access removed, staff keep it, transcript generated.
  • /delete removes the channel entirely (transcript generated first).
  • Both start a 5-second countdown any staff member can cancel with /open. /close in: 2h schedules the close for later instead.
  • A custom /rename sticks through the whole close β†’ reopen cycle β€” billing-issue becomes closed-billing-issue on close and goes right back to billing-issue on reopen, instead of falling back to ticket-0007.
πŸ“„ Transcripts
  • Generated automatically on close, on delete, and even if the channel is deleted manually (messages are cached live, so nothing is lost).
  • Staff-only β€” posted to the transcript channel and saved to data/transcripts/. The ticket opener never receives it.
  • Discord-authentic dark UI: grouped consecutive messages (one avatar/header per burst), full markdown, rich embed cards, and role/thread/bot/edited/deleted badges (shown once per burst, not spammed on every message).
  • Strictly chronological ordering (snowflake-ID tiebreak) even when merging the ticket channel with its staff thread.
  • Avatars are downloaded and embedded as base64 β€” animated GIF avatars stay animated. Falls back to a colored initial circle if unavailable.
  • Hand-built rather than using a live-fetch transcript library, since those can't recover deleted messages or run after a channel is already gone β€” both cases this bot has to handle.
🧡 Staff discussion threads
  • If a staff threads channel is configured, every new ticket spawns a same-named thread there, cross-linked with the ticket both ways.
  • That channel must be staff-only β€” threads inherit its visibility, and the health check warns if @everyone can see it.
  • Thread messages (including edits/deletions) are logged into the same transcript tagged STAFF THREAD, but never count as a staff "response" for auto-unclaim/escalation.
  • The thread mirrors the ticket completely: renamed, archived, reopened, and deleted right along with it.
⭐ Ratings & stats
  • On close, the opener is DM'd a 1–5 ⭐ rating prompt; picking a rating opens an optional feedback form.
  • If DMs are disabled, the prompt is posted in the closed channel instead (opener gets read-only access back).
  • One rating per ticket, only the opener can submit it. Feeds /stats and /staffstats.
🎨 Branding & customization
  • /setup β†’ Branding sets the bot's display name and an optional logo image URL, applied instantly everywhere (embed footers, welcome messages, transcripts) β€” no restart needed.
  • Defaults to "Ticket Bot" with no image if never set.
  • /setup β†’ Color scheme picks the accent color used across every message (purple/blue/teal/monochrome, defined in src/messages.js) β€” applies instantly, no restart. Success/error/warning colors never change, so a warning can never visually read as a success regardless of scheme.
  • /setup β†’ Panel & ticket types adds, edits, or removes the ticket-type buttons shown on /panel (label, emoji, and short description per type) β€” applies instantly to the panel, ticket titles, channel topics, transcripts, and /history, no restart needed. At least one type must always remain.
  • /panel accepts title:/description: options to override the panel text per-post without touching code.
  • All other bot text lives in src/messages.js β€” edit it freely, including the /reply canned-reply library.
πŸ” Admin gate & permissions
  • adminUserId in config.js is the sole gate for /setup and /test β€” no Discord permission, not even Administrator, grants access on its own. It's intentionally not editable through any bot command, only by editing the file directly, so it can't be self-granted. Since it's one person, they're also the only one who can change staff/higher-up roles.
  • Mention policy: the bot may ping users and staff roles only. It can never ping @everyone/@here, even if one ends up in a canned reply β€” that's enforced at the client level.
  • On startup and every minute, the bot verifies its own permissions and that configured channels/roles still exist, logging any problems.
βš™οΈ Reliability
  • SQLite storage (data/bot.db, Node's built-in driver β€” no extra install).
  • Every state change (claim, transfer, close, delete, open, add/remove) runs through a per-channel mutex, and ticket creation through a per-user one β€” two staff can't win a race on the same click, and double-submitting the open form can't create two tickets.
  • Attachments are downloaded to disk as they arrive (Discord kills the URLs once a channel is deleted); images ≀2MB are embedded directly in the transcript, everything is archived under data/transcripts/files/<ticket>/ when the ticket ends.
  • Requires the Server Members and Message Content privileged intents β€” the bot exits at startup with clear instructions if they're missing, instead of failing silently.

πŸ“ Project structure

index.js                 β†’ slash command definitions, event routing, bot login
config.example.js        β†’ committed config template (copy to config.js)
config.js                β†’ your real config (gitignored, created by you)

src/
  config.js               β†’ merges config.js with live /setup overrides from the DB
  db.js                   β†’ SQLite schema + one-time JSON migration
  store.js                β†’ all database reads/writes
  stats.js                β†’ leaderboard/rating aggregation
  messages.js             β†’ every piece of user-facing bot text
  tickets.js              β†’ panel, ticket lifecycle, claiming, closing, threads
  extras.js                β†’ /setup, /test, /stats, /staffstats, /history, bans, ratings
  transcript.js             β†’ hand-built Discord-authentic HTML transcript renderer
  attachments.js             β†’ attachment/avatar download + archival engine

data/                         β†’ SQLite DB + generated transcripts/attachments/avatars (gitignored)

🀝 Contributing

Issues and PRs are welcome! Adding a new setting is easy and follows one pattern throughout the codebase:

  1. Add a default in src/config.js
  2. Add a menu entry to MENU_OPTIONS in src/extras.js
  3. Read it live as config.<yourKey> wherever it's needed

No caching to worry about β€” /setup changes apply instantly everywhere.


πŸ“„ License

MIT β€” do whatever you want with it.

About

🎫 Self-hosted Discord support ticket bot β€” panels, claiming, staff threads, ratings, and gorgeous auto-generated HTML transcripts.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages