# Broccolini Bot A Node.js support-ticket bot that connects **Gmail**, **Discord**, and **MongoDB** into a unified ticketing system. Incoming support emails become Discord ticket channels; staff replies in Discord are sent back to the sender via Gmail. All ticket state is persisted in MongoDB. Built for game-server hosting support (Indifferent Broccoli), with game detection from email content, configurable automation (auto-close, reminders, auto-unclaim), and a full set of Discord slash commands, buttons, modals, and context menus. **Quick links:** [Installation](#installation) · [Configuration](#configuration) · [Discord Commands](#discord-commands) · [Documentation](#documentation) --- ## Table of Contents - [Features](#features) - [Architecture](#architecture) - [Prerequisites](#prerequisites) - [Installation](#installation) - [Configuration](#configuration) - [Discord](#discord) - [Google OAuth2 / Gmail](#google-oauth2--gmail) - [MongoDB](#mongodb) - [Branding & Messages](#branding--messages) - [Automation](#automation) - [Ticket Limits & Permissions](#ticket-limits--permissions) - [Priority Levels](#priority-levels) - [Claiming Options](#claiming-options) - [Button & Embed Customization](#button--embed-customization) - [Running the Bot](#running-the-bot) - [Test Environment](#test-environment) - [Discord Commands](#discord-commands) - [Tag System](#tag-system) - [Panel System](#panel-system) - [Project Structure](#project-structure) - [Database Schema](#database-schema) - [API Integrations](#api-integrations) - [Healthcheck](#healthcheck) - [Documentation](#documentation) - [Troubleshooting](#troubleshooting) - [References](#references) - [License](#license) --- ## Features ### Email-to-Discord Ticketing - Polls Gmail every 30 seconds for unread emails in the primary inbox - Creates a dedicated Discord channel per ticket (`ticket-{sender}-{number}`) - Detects the game from the email subject/body and tags the ticket accordingly - Sends a rich embed with ticket metadata and action buttons (Claim, Close) ### Discord-to-Email Replies - Staff messages in a ticket channel are forwarded to the original sender via Gmail - Replies are threaded in Gmail so the sender sees a continuous conversation ### Ticket Management - **Claim / Unclaim** -- Staff can claim tickets; optional auto-unclaim after inactivity - **Priority Levels** -- Low, Normal, High with color-coded embeds - **Escalation** -- Move urgent tickets to a dedicated escalation category - **Transfer / Move** -- Reassign tickets between staff or categories - **Close Confirmation** -- Prevents accidental closes with a confirmation prompt - **Transcripts** -- Full conversation transcripts posted to a dedicated channel on close - **Auto-Close** -- Automatically close tickets after configurable hours of inactivity - **Inactivity Reminders** -- Notify the channel when a ticket goes stale ### Panel System - Deploy a "Open Ticket" button panel to any channel with `/panel` - Users click the button, fill out a modal form, and a ticket is created ### Tag System (Saved Responses) - Set ticket category with `/tag` (dropdown); create reusable response templates with `/response create` - Dynamic template variables: `{ticket.user}`, `{staff.name}`, `{server.name}`, `{date}`, etc. - Autocomplete-enabled `/tag` command for instant use ### Account Info Lookup - `/accountinfo` searches website users by email or Discord ID - Results show linked servers, game details, and user metadata ### Analytics & Logging - In-memory tracking of command usage, button clicks, and errors - `/stats` shows uptime, interaction counts, and error rate - Configurable logging channel for ticket lifecycle events --- ## Architecture ``` ┌────────────────────────────────────────────────────────────────────┐ │ BROCCOLINI BOT │ ├────────────────────────────────────────────────────────────────────┤ │ │ │ ┌───────────┐ ┌────────────────┐ ┌──────────────────┐ │ │ │ Gmail │─────>│ gmail-poll.js │─────>│ Discord │ │ │ │ (inbox) │ │ (every 30s) │ │ (ticket channel)│ │ │ └───────────┘ └───────┬────────┘ └───────▲──────────┘ │ │ │ │ │ │ v │ │ │ ┌────────────────┐ ┌──────────────────┐ │ │ │ services/ │ │ handlers/ │ │ │ │ gmail.js │<────>│ messages.js │ │ │ │ tickets.js │ │ buttons.js │ │ │ │ guildSettings │ │ commands.js │ │ │ └───────┬────────┘ └──────────────────┘ │ │ │ │ │ v │ │ ┌────────────────┐ ┌──────────────────┐ │ │ │ MongoDB │ │ Express │ │ │ │ (Mongoose) │ │ (healthcheck) │ │ │ └────────────────┘ └──────────────────┘ │ │ │ │ Events: │ │ ready → Connect DB, register commands, start jobs │ │ interactionCreate → Buttons, slash commands, modals, menus │ │ messageCreate → Discord replies → Gmail │ └────────────────────────────────────────────────────────────────────┘ ``` **Ticket lifecycle:** 1. **Inbound email** -- Gmail poll detects a new unread message, creates a Discord channel and a MongoDB record. 2. **Staff reply** -- A message in the Discord ticket channel is forwarded to the sender via Gmail. 3. **Close** -- A transcript is generated, a closure email is sent, and the Discord channel is deleted. --- ## Prerequisites | Requirement | Version | |-------------|---------| | Node.js | ≥ 18.x | | npm | ≥ 9.x | | MongoDB | ≥ 5.x (Atlas or self-hosted) | You will also need: - A **Discord bot** with the following intents enabled: Guilds, Guild Messages, Message Content, Guild Members - A **Google Cloud project** with the Gmail API enabled and OAuth2 credentials (Client ID, Client Secret, Refresh Token) --- ## Installation Single-level repo: all commands run from the repo root. Create `.env` in the repo root (copy from `.env.example`). ```bash git clone cd broccolini-bot npm install cp .env.example .env # Edit .env with your Discord, Gmail, and MongoDB credentials (see Configuration). ``` --- ## Configuration Create a `.env` file in the repo root (same directory as this README). All configuration is loaded via environment variables. > **Important:** After changing `.env`, you must **restart the process** (`npm start` / `node broccolini-discord.js`) for new values to take effect. If you add or change **slash commands** (e.g. `/escalate`, `/email-routing`, `/panel` options), restart the bot so it can **re-register** commands with Discord; otherwise new or updated commands may not appear. > **Agent rule:** Changes to `.env` by an AI/agent must **require explicit user confirmation**. Prefer proposing changes to `.env.test` first and migrating to `.env` only after the user approves. See [ENV_AND_SECURITY.md](docs/setup/ENV_AND_SECURITY.md). ### Discord | Variable | Required | Description | |---|---|---| | `DISCORD_TOKEN` | Yes | Bot token from the Discord Developer Portal | | `DISCORD_GUILD_ID` | Yes | Server (guild) ID where the bot operates | | `DISCORD_APPLICATION_ID` | Yes | Application ID for registering slash commands | | `TICKET_CATEGORY_ID` | Yes | Channel category ID where email ticket channels are created | | `EMAIL_TICKET_OVERFLOW_CATEGORY_IDS` | No | Comma-separated category IDs; used when main email category has 50 channels | | `DISCORD_TICKET_CATEGORY_ID` | No | Category for Discord panel tickets (defaults to `TICKET_CATEGORY_ID`) | | `DISCORD_TICKET_OVERFLOW_CATEGORY_IDS` | No | Comma-separated category IDs; used when main Discord ticket category has 50 channels | | `ROLE_ID_TO_PING` | Yes | Role ID to ping when a new ticket arrives | | `TRANSCRIPT_CHANNEL_ID` | No | Channel ID for posting ticket transcripts | | `LOGGING_CHANNEL_ID` | No | Channel ID for lifecycle log messages | | `DEBUGGING_CHANNEL_ID` | No | Channel ID for error logs (escalate, deescalate, email-routing, Gmail poll, etc.) | | `BACKUP_EXPORT_CHANNEL_ID` | No | Channel ID where `/backup` and `/export` post ticket dump files | | `ACCOUNT_INFO_CHANNEL_ID` | No | Channel ID for account info lookups (and `/accountinfo` visibility) | | `EMAIL_ESCALATED_CATEGORY_ID` | No | Category ID for escalated email tickets (tier 2+) | | `DISCORD_ESCALATED_CATEGORY_ID` | No | Category ID for escalated Discord-origin tickets | | `ESCALATION_MESSAGE` | No | Message sent when a ticket is escalated (supports `{support_name}`) | ### Google OAuth2 / Gmail | Variable | Required | Description | |---|---|---| | `GOOGLE_CLIENT_ID` | Yes | OAuth2 Client ID from Google Cloud Console | | `GOOGLE_CLIENT_SECRET` | Yes | OAuth2 Client Secret | | `REFRESH_TOKEN` | Yes | OAuth2 Refresh Token for the support inbox | | `MY_EMAIL` | Yes | The support email address (e.g. `support@example.com`) | ### MongoDB | Variable | Required | Description | |---|---|---| | `MONGODB_URI` | Yes | MongoDB connection string (e.g. `mongodb+srv://user:pass@cluster/dbname`) | ### Branding & Messages | Variable | Default | Description | |---|---|---| | `SUPPORT_NAME` | -- | Display name for the support system | | `LOGO_URL` | -- | URL to the logo shown in embeds | | `EMAIL_SIGNATURE` | -- | HTML signature appended to outgoing emails (use `\n` for line breaks) | | `TICKET_CLOSE_SUBJECT_PREFIX` | `[Resolved]` | Prefix added to the subject of closure emails | | `TICKET_CLOSE_MESSAGE` | *(see config.js)* | Body of the ticket closure email | | `TICKET_CLOSE_SIGNATURE` | *(see config.js)* | Signature on the closure email | | `TICKET_WELCOME_MESSAGE` | *(see config.js)* | Message posted when a ticket channel is created | | `TICKET_CLAIMED_MESSAGE` | *(see config.js)* | Message posted when a ticket is claimed (supports `{staff_name}`) | | `TICKET_UNCLAIMED_MESSAGE` | *(see config.js)* | Message posted when a ticket is unclaimed | ### Automation | Variable | Default | Description | |---|---|---| | `AUTO_CLOSE_ENABLED` | `false` | Enable automatic ticket closure after inactivity | | `AUTO_CLOSE_AFTER_HOURS` | `72` | Hours of inactivity before auto-close triggers | | `AUTO_CLOSE_MESSAGE` | *(see config.js)* | Message sent when a ticket is auto-closed | | `REMINDER_ENABLED` | `false` | Enable inactivity reminder messages | | `REMINDER_AFTER_HOURS` | `24` | Hours of inactivity before a reminder is sent | | `REMINDER_MESSAGE` | *(see config.js)* | Reminder message (supports `{hours}` variable) | ### Ticket Limits & Permissions | Variable | Default | Description | |---|---|---| | `GLOBAL_TICKET_LIMIT` | `5` | Maximum concurrent open tickets globally | | `TICKET_LIMIT_PER_CATEGORY` | `3` | Maximum tickets per category | | `RATE_LIMIT_TICKETS_PER_USER` | `0` | Max tickets a user can create per window (0 = disabled) | | `RATE_LIMIT_WINDOW_MINUTES` | `60` | Window in minutes for per-user ticket creation limit | | `BLACKLISTED_ROLES` | -- | Comma-separated role IDs that cannot open tickets | | `ADDITIONAL_STAFF_ROLES` | -- | Comma-separated role IDs with staff-level permissions | ### Priority Levels | Variable | Default | Description | |---|---|---| | `PRIORITY_ENABLED` | `false` | Enable the priority system | | `DEFAULT_PRIORITY` | `normal` | Default priority for new tickets | | `PRIORITY_HIGH_EMOJI` | `🔴` | Emoji for high-priority tickets | | `PRIORITY_MEDIUM_EMOJI` | `🟡` | Emoji for normal/medium-priority tickets (default level is normal) | | `PRIORITY_LOW_EMOJI` | `🟢` | Emoji for low-priority tickets | ### Claiming Options | Variable | Default | Description | |---|---|---| | `AUTO_UNCLAIM_ENABLED` | `false` | Automatically unclaim tickets after inactivity | | `AUTO_UNCLAIM_AFTER_HOURS` | `24` | Hours before auto-unclaim triggers | | `ALLOW_CLAIM_OVERWRITE` | `false` | Allow claiming an already-claimed ticket | | `CLAIM_TIMEOUT_ENABLED` | `false` | Enable claim timeout | | `CLAIM_TIMEOUT_HOURS` | `48` | Hours before a claim times out | ### Channel rename rate limit Ticket channels are renamed automatically when you **claim**, **unclaim**, **escalate**, or **deescalate**. [Discord’s API](https://discord.com/developers/docs/topics/rate-limits) allows **2 channel renames per 10 minutes** per channel. The bot enforces this: if the limit is reached, the rename is skipped and the channel gets: **Channel renamed too quickly. Try again \.** The timestamp is a Discord relative-time marker (e.g. “in 8 minutes”). After the window resets, the next claim/unclaim/escalate/deescalate can rename again. ### Button & Embed Customization | Variable | Default | Description | |---|---|---| | `BUTTON_LABEL_CLOSE` | `Close Ticket` | Label for the close button | | `BUTTON_LABEL_CLAIM` | `Claim` | Label for the claim button | | `BUTTON_LABEL_UNCLAIM` | `Unclaim` | Label for the unclaim button | | `BUTTON_EMOJI_CLOSE` | `🔒` | Emoji on the close button | | `BUTTON_EMOJI_CLAIM` | `📌` | Emoji on the claim button | | `BUTTON_EMOJI_UNCLAIM` | `🔓` | Emoji on the unclaim button | | `EMBED_COLOR_OPEN` | `0x00FF00` | Embed color for open tickets | | `EMBED_COLOR_CLOSED` | `0xFF0000` | Embed color for closed tickets | | `EMBED_COLOR_CLAIMED` | `0xFFFF00` | Embed color for claimed tickets | | `EMBED_COLOR_ESCALATED` | `0xFF6600` | Embed color for escalated tickets | | `EMBED_COLOR_INFO` | `0x1e2124` | Embed color for info messages (and embeds next to ticket buttons) | ### Game List Set `GAME_LIST` to a comma-separated list of game names. The bot uses this list for auto-detection from email subjects/bodies: ```env GAME_LIST=Project Zomboid, Satisfactory, Palworld, Minecraft, Valheim, ... ``` --- ## Running the Bot ```bash # Start the bot npm start # Or directly node broccolini-discord.js ``` On startup the bot will: 1. Validate required environment variables 2. Connect to MongoDB (with automatic reconnection) 3. Register all slash commands to the configured guild 4. Begin polling Gmail every 30 seconds 5. Start background jobs (auto-close, reminders, auto-unclaim) 6. Launch an Express healthcheck server **Note:** Changing `.env` requires restarting the bot. Slash commands are registered on startup; if commands don’t update, restart the bot to re-register. ### Test Environment To try config changes without affecting production, use a **test env**. Copy `.env.test.example` to `.env.test`, fill it with test-only values (e.g. test guild, test MongoDB database), and run: ```bash npm run start:test ``` Other test scripts: `npm run test-mongodb:test`. After confirming behavior in test, migrate only the desired variables to `.env`. See **[ENV_AND_SECURITY.md](docs/setup/ENV_AND_SECURITY.md)** for the full workflow, security checklist, and agent rules. To test the MongoDB connection from the repo root: `npm run test-mongodb`. --- ## Discord Commands ### Ticket Management | Command | Description | |---|---| | `/claim` | Claim the current ticket | | `/unclaim` | Release your claim on the current ticket | | `/close` | Close the current ticket (with confirmation) | | `/force-close` | Close the current ticket without confirmation | | `/priority ` | Set ticket priority (`low`, `normal`, `medium`, `high`). Posts: *upgraded to [Emoji][Level][Emoji]*, *downgraded to...*, or *returned to Normal*. Email sent when set to **high**. | | `/topic ` | Set the ticket channel topic | | `/escalate [reason] [tier]` | Escalate the ticket to tier 2 or 3 (optional tier; buttons also available) | | `/deescalate` | De-escalate the ticket one step | ### User & Channel Management | Command | Description | |---|---| | `/add ` | Add a user to the current ticket channel | | `/remove ` | Remove a user from the current ticket channel | | `/transfer ` | Transfer the ticket to another staff member | | `/move ` | Move the ticket to a different category | ### Tags & Saved Responses | Command | Description | |---|---| | `/tag` | Set ticket category (dropdown: ⬇️ Server Down, ⏳ Stuck Restarting, 📵 Can't Connect, 🐌 Server Lag, 💳 Billing, 💸 Refund Request, 🔧 Mod Help, 💾 Backup Restore, 🌍 World / Save, ⚙️ Server Config). Posts: *Your ticket has been categorized as [Emoji][Tag][Emoji].* | | `/response send ` | Send a saved response (autocomplete-enabled) | | `/response create ` | Create a new saved response | | `/response edit ` | Edit an existing saved response | | `/response delete ` | Delete a saved response | | `/response list` | List all saved responses | ### Utilities | Command | Description | |---|---| | `/panel [channel] [type] [title] [description]` | Deploy a ticket-creation panel (type: thread, category, or both) | | `/email-routing` | Switch where new email tickets are created (threads or category channels) | | `/accountinfo ` | Look up a user's account information | | `/search ` | Search tickets | | `/stats` | Show bot statistics and analytics | | `/backup` | Export full ticket list to a .txt file in the backup/export channel | | `/export [status] [limit]` | Export tickets (optional filter and limit) to a .txt file in the backup/export channel | | `/help` | Display the command reference | ### Context Menus | Menu | Description | |---|---| | **Create Ticket From Message** | Right-click a message to create a ticket from it | --- ## Tag & Response System ### Ticket category (`/tag`) Use `/tag` in a ticket channel and pick a category from the dropdown (e.g. ⬇️ Server Down, 💳 Billing, 🔧 Mod Help). The bot posts: *Your ticket has been categorized as [Emoji][Tag][Emoji].* Channel name is not changed. ### Saved response tags (`/response`) Saved responses are reusable templates stored in MongoDB. Use `/response send`, `/response create`, etc. They support dynamic variables that are replaced at send time: | Variable | Resolves To | |---|---| | `{ticket.user}` | Ticket sender's name | | `{ticket.email}` | Ticket sender's email | | `{ticket.number}` | Ticket number | | `{ticket.subject}` | Ticket subject line | | `{staff.name}` | Current staff member's display name | | `{staff.mention}` | Current staff member's mention | | `{server.name}` | Discord server name | | `{date}` | Current date | | `{time}` | Current time | **Example:** ``` /response create name:greeting content:Hi {ticket.user}! Thanks for reaching out about "{ticket.subject}". I'm {staff.name} and I'll be helping you today. ``` --- ## Panel System The panel system allows users to create tickets directly from Discord without sending an email. 1. Deploy a panel: `/panel #support title:Need Help? description:Click below to open a ticket!` 2. Users click the **Open Ticket** button 3. A modal form appears asking for subject, description, and priority 4. On submission, a ticket channel is created with all the same features as email tickets --- ## Project Structure ``` broccolini-bot/ ├── broccolini-discord.js # Entry point - initializes bot, events, and jobs ├── config.js # Environment variable loading and CONFIG export ├── db-connection.js # MongoDB connection with reconnect logic ├── models.js # Mongoose schemas (Ticket, User, Tag, etc.) ├── utils.js # Text processing, game detection, template vars ├── gmail-poll.js # Gmail polling loop and ticket creation ├── game-options.json # Game configuration data │ ├── commands/ │ └── register.js # Slash command and context menu registration │ ├── handlers/ │ ├── accountinfo.js # /accountinfo command and button handler │ ├── analytics.js # In-memory analytics and error tracking │ ├── buttons.js # Button interactions (claim, close, priority, etc.) │ ├── commands.js # All slash command handlers │ ├── messages.js # Discord → Gmail reply forwarding │ └── setup.js # Guild setup / configuration flow │ ├── services/ │ ├── debugLog.js # Structured debug logging │ ├── gmail.js # Gmail OAuth2, send replies, closure emails │ ├── guildSettings.js # Guild-specific settings (DB + cache) │ └── tickets.js # Ticket CRUD, auto-close, reminders, auto-unclaim │ ├── scripts/ │ ├── backup-env.js # Copy .env to .env.backup │ └── test-mongodb.js # MongoDB connection test │ ├── docs/ # Additional documentation (QUICKSTART, MONGODB_SETUP, ENV_AND_SECURITY, etc.) ├── .env # Environment variables (not committed) ├── package.json └── package-lock.json ``` --- ## Database Schema The bot uses MongoDB via Mongoose. Key collections: | Collection | Purpose | |---|---| | `Ticket` | Core ticket data: Gmail thread ID, Discord channel ID, sender info, status, priority, claimed-by, timestamps | | `TicketCounter` | Auto-incrementing ticket numbers per sender | | `Transcript` | Transcript message references for closed tickets | | `Tag` | Saved response templates (name, content, creator) | | `CloseRequest` | Tracks pending close confirmations | | `User` | Website user accounts (email, Discord ID, linked servers) | | `Host` | Game server/host metadata and metrics | | `DashboardMetrics` | Aggregated dashboard statistics | | `ErrorLog` | Persisted error records | --- ## API Integrations ### Gmail API - **Authentication:** OAuth2 with Client ID, Client Secret, and Refresh Token - **Polling:** `users.messages.list` for unread messages in the primary inbox - **Reading:** `users.messages.get` to fetch full message content - **Sending:** `users.messages.send` for threaded replies and closure emails ### Discord API (discord.js v14) - **Intents:** Guilds, GuildMessages, MessageContent, GuildMembers - **Interactions:** Slash commands, buttons, modals, context menus, autocomplete - **Channels:** Create/delete ticket channels, manage permissions per user ## Healthcheck An Express server runs on the port defined by `DISCORD_ONLY_PORT` (default: `5000`). ``` GET / → "Active" ``` Use this endpoint for uptime monitoring or container health probes. Optional: set `HEALTHCHECK_HOST=127.0.0.1` in `.env` to bind the healthcheck server to localhost only; omit to listen on all interfaces. --- ## Documentation Additional guides and reference docs live in **`docs/`**. See [docs/README.md](docs/README.md) for the full index. | Doc | Description | |-----|-------------| | [QUICKSTART](docs/setup/QUICKSTART.md) | Get started in a few minutes: first response, panel, tags, priority | | [ENV_AND_SECURITY](docs/setup/ENV_AND_SECURITY.md) | Test env workflow, security checklist, agent rules | | [MONGODB_SETUP](docs/setup/MONGODB_SETUP.md) | MongoDB connection, schemas, and testing | | [PROJECT_STRUCTURE](docs/setup/PROJECT_STRUCTURE.md) | File and directory layout | | [PROPOSAL](docs/features/PROPOSAL.md) | Roadmap and possible next steps | | [PHASE_FEATURES](docs/features/PHASE_FEATURES.md) | Phased feature list and variables | | [FEATURES_SUMMARY](docs/features/FEATURES_SUMMARY.md) · [NEW_FEATURES](docs/features/NEW_FEATURES.md) | Feature overview and changelog | | [DISCORD_API_IMPROVEMENTS](docs/api/DISCORD_API_IMPROVEMENTS.md) · [DISCORD_API_VALIDATION](docs/api/DISCORD_API_VALIDATION.md) | Discord API implementation notes | --- ## Troubleshooting ### Slash commands not appearing in Discord - Commands are registered per-guild on startup. Wait up to one hour for Discord to propagate. - Verify `DISCORD_APPLICATION_ID` and `DISCORD_GUILD_ID` are correct. - Restart the bot. ### Gmail polling not working - Ensure `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`, and `REFRESH_TOKEN` are set correctly. - The refresh token may have expired -- regenerate it via the Google OAuth2 Playground. - Check that the Gmail API is enabled in your Google Cloud Console project. ### MongoDB connection failures - Verify `MONGODB_URI` is correct and the database is accessible. - Run `npm run test-mongodb` from the repo root to test the connection. - If using MongoDB Atlas, ensure your IP is whitelisted. - The bot has automatic reconnection -- check logs for retry attempts. ### Tickets not creating - Check that `TICKET_CATEGORY_ID` points to a valid Discord category. - Ensure the bot has `Manage Channels` and `View Channel` permissions in that category. - Review the logging channel for error messages. ### Modal not appearing when clicking "Open Ticket" - Verify the bot has proper guild permissions. - Try in a different channel. - Restart the bot. --- ## References This project builds on or references the following: | Technology | Description | Links | |------------|-------------|--------| | **discord.js** | Node.js library for the Discord API; used for the bot, slash commands, buttons, and embeds. | [discord.js](https://discord.js.org/) · [GitHub](https://github.com/discordjs/discord.js) | | **Discord Tickets** | Open-source ticket bot; referenced for patterns and feature inspiration (panels, tags, transcripts). | [Discord Tickets](https://discordtickets.app/) · [GitHub](https://github.com/discord-tickets/bot) | | **Node.js** | JavaScript runtime used to run the bot. | [Node.js](https://nodejs.org/en) | | **MongoDB** | Database for tickets, transcripts, and persistence (via Mongoose). | [MongoDB](https://www.mongodb.com/) | | **Express** | HTTP server for the healthcheck endpoint. | [Express](https://expressjs.com/) | | **Mongoose** | MongoDB ODM used for schemas and connection handling. | [Mongoose](https://mongoosejs.com/) | | **Google APIs (googleapis)** | Gmail API client for polling and sending email. | [Google APIs Node.js](https://github.com/googleapis/google-api-nodejs-client) | --- ## License ISC