464 lines
22 KiB
Markdown
464 lines
22 KiB
Markdown
# Broccolini Bot
|
||
|
||
A **Node.js** Discord bot that unifies **Gmail**, **Discord**, and **MongoDB** for support ticketing. Incoming emails become Discord ticket channels; staff messages in those channels are sent back to customers via Gmail. Discord-originated tickets (panels, context menu) live entirely in Discord. State is stored in MongoDB via Mongoose.
|
||
|
||
Built for game-server hosting support (Indifferent Broccoli), with game detection from email content, tiered escalation, optional staff “mirror” channels per claimer, saved responses, `/tag` categorization, and automation (auto-close, reminders, auto-unclaim).
|
||
|
||
**Jump to:** [Features](#features) · [Quick start](#quick-start) · [Configuration](#configuration) · [Staff categories](#staff-personal-categories--mirror-channels) · [Commands](#discord-commands) · [Project layout](#project-structure)
|
||
|
||
---
|
||
|
||
## Table of contents
|
||
|
||
- [Features](#features)
|
||
- [Architecture](#architecture)
|
||
- [Prerequisites](#prerequisites)
|
||
- [Quick start](#quick-start)
|
||
- [Installation](#installation)
|
||
- [Configuration](#configuration)
|
||
- [Staff personal categories & mirror channels](#staff-personal-categories--mirror-channels)
|
||
- [Running the bot](#running-the-bot-test-and-docker)
|
||
- [Discord commands](#discord-commands)
|
||
- [Ticket UI (buttons & modals)](#ticket-ui-buttons--modals)
|
||
- [Tag & response system](#tag--response-system)
|
||
- [Panel system](#panel-system)
|
||
- [Channel renames & moves (rate limits)](#channel-renames--moves-rate-limits)
|
||
- [Project structure](#project-structure)
|
||
- [Database collections](#database-collections)
|
||
- [HTTP: healthcheck & bOSScord API](#http-healthcheck--bosscord-api)
|
||
- [Gmail OAuth refresh token](#gmail-oauth-refresh-token)
|
||
- [Documentation in `docs/`](#documentation-in-docs)
|
||
- [Troubleshooting](#troubleshooting)
|
||
- [References](#references)
|
||
- [License](#license)
|
||
|
||
---
|
||
|
||
## Features
|
||
|
||
### Email → Discord
|
||
|
||
- Polls Gmail about every **30 seconds** for new mail.
|
||
- Creates a **Discord text channel** per email ticket (with overflow category support when a category is full).
|
||
- Detects **game** from subject/body using `GAME_LIST`.
|
||
- Posts welcome + action **buttons** (Close, Claim, Escalate / De-escalate where applicable).
|
||
|
||
### Discord → Gmail
|
||
|
||
- For **email-sourced** tickets, staff messages in the ticket channel are **forwarded** to the customer via Gmail (threaded).
|
||
- **Discord-only** tickets (`gmailThreadId` prefix `discord-` / `discord-msg-`) do not use Gmail for replies; conversation stays in Discord.
|
||
|
||
### Ticket management
|
||
|
||
- **Claim / Unclaim** via buttons (not slash commands); optional claim overwrite and auto-unclaim.
|
||
- **Priority** (`low` / `normal` / `medium` / `high`) with configurable emojis and `/priority`.
|
||
- **Escalation**: tier 2 and tier 3 categories (separate IDs for email vs Discord where configured); slash `/escalate` and in-channel buttons.
|
||
- **De-escalation** one step at a time (`/deescalate` or button).
|
||
- **Close** with confirmation; **force-close** for admins.
|
||
- **Transcripts** posted to a configured channel; closure email for email tickets.
|
||
- **Auto-close**, **inactivity reminders**, **auto-unclaim** (all optional via env).
|
||
|
||
### Staff personal categories (optional)
|
||
|
||
- Per-staff Discord **category map** so when someone **claims**, the main ticket channel can move into their category and a **mirror channel** can be created with a pinned embed linking back to the real ticket.
|
||
- When a **non-claimer** posts in the ticket channel, the mirror channel can be **pinged** with a quote and jump link; optional **DM** via `/notifydm`.
|
||
- Unclaim and close clean up mirror channels when configured.
|
||
|
||
See [Staff personal categories](#staff-personal-categories--mirror-channels).
|
||
|
||
### Extras
|
||
|
||
- **`/panel`**: “Open ticket” UI (modal collects email, game, description).
|
||
- **`/tag`**: ticket category dropdown; **`/response`**: saved templates with variable substitution.
|
||
- **`/setup`**: setup wizard for guild defaults.
|
||
- **`/accountinfo`**: website account lookup (email or Discord user).
|
||
- **`/stats`**, **`/search`**, **`/backup`**, **`/export`**, **`/email-routing`**.
|
||
- **Context menus**: create ticket from message; view user tickets.
|
||
- **Optional REST API** under `/api` for the bOSScord cockpit when `BOSSCORD_API_KEY` is set.
|
||
|
||
---
|
||
|
||
## Architecture
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ BROCCOLINI BOT │
|
||
├─────────────────────────────────────────────────────────────────┤
|
||
│ Gmail (inbox) ──► gmail-poll.js ──► Discord ticket channels │
|
||
│ │ ▲ │
|
||
│ ▼ │ │
|
||
│ services/gmail.js ◄── handlers/messages.js │
|
||
│ services/tickets.js handlers/buttons.js │
|
||
│ services/channelQueue.js handlers/commands.js│
|
||
│ services/staffChannel.js │
|
||
│ │ │
|
||
│ ▼ │
|
||
│ MongoDB (Mongoose) ◄── models.js │
|
||
│ │
|
||
│ Express: GET / → "Active" ; optional /api → routes/bosscord.js │
|
||
└─────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
**Typical email ticket lifecycle**
|
||
|
||
1. New unread mail → poll creates Discord channel + `Ticket` document.
|
||
2. Staff reply in channel → message handler sends Gmail reply (email tickets only).
|
||
3. Close confirmed → transcript, optional closure email, channel delete; DB marked closed.
|
||
|
||
---
|
||
|
||
## Prerequisites
|
||
|
||
| Requirement | Notes |
|
||
|-------------|--------|
|
||
| **Node.js** | **18+** recommended (Dockerfile uses 20). |
|
||
| **npm** | Install dependencies with `npm install`. |
|
||
| **MongoDB** | Atlas or self-hosted; connection string in `MONGODB_URI`. |
|
||
| **Discord application** | Bot token, application ID, privileged intents: **Message Content**, **Server Members**; also Guilds + Guild Messages. |
|
||
| **Google Cloud** | Gmail API enabled; OAuth2 client ID/secret + refresh token for the support mailbox. |
|
||
|
||
---
|
||
|
||
## Quick start
|
||
|
||
```bash
|
||
git clone <your-repo-url>
|
||
cd broccolini-bot
|
||
npm install
|
||
cp .env.example .env
|
||
```
|
||
|
||
1. Fill **Discord** (`DISCORD_TOKEN` or `DISCORD_BOT_TOKEN`, `DISCORD_APPLICATION_ID`, `DISCORD_GUILD_ID`, categories, `ROLE_ID_TO_PING`, transcript/log channels).
|
||
2. Fill **MongoDB** (`MONGODB_URI`).
|
||
3. Fill **Google** OAuth (`GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`, `REFRESH_TOKEN`, `MY_EMAIL`) — use `node get-refresh-token.js` once if needed.
|
||
4. Run `npm start`.
|
||
5. In Discord, use **`/setup`** or verify categories and roles manually.
|
||
|
||
Restart after **any** `.env` change. After changing **slash command definitions**, restart so **`registerCommands()`** re-registers with Discord.
|
||
|
||
---
|
||
|
||
## Installation
|
||
|
||
Same as quick start. Optional:
|
||
|
||
- **Test env:** copy `.env.test.example` → `.env.test`, run `npm run start:test` (sets `ENV_FILE`).
|
||
- **1Password CLI:** `npm run start:1p` / `start:test:1p` inject secrets (see `docs/setup/1PASSWORD.md`).
|
||
|
||
**Do not commit** `.env` or `.env.test`. AI/agents should not edit production `.env` without explicit approval; see [ENV_AND_SECURITY.md](docs/setup/ENV_AND_SECURITY.md).
|
||
|
||
---
|
||
|
||
## Configuration
|
||
|
||
Configuration is **environment variables** only, loaded in [`config.js`](config.js) as `CONFIG`. Discord env names in tables below match `.env.example`.
|
||
|
||
### Discord (core)
|
||
|
||
| Variable | Required | Description |
|
||
|----------|----------|-------------|
|
||
| `DISCORD_TOKEN` | Yes* | Bot token (*or `DISCORD_BOT_TOKEN`, first non-empty wins after trim). |
|
||
| `DISCORD_APPLICATION_ID` | Yes | Used as `CLIENT_ID` for REST command registration. |
|
||
| `DISCORD_GUILD_ID` | Yes | Guild where slash commands are registered. |
|
||
| `TICKET_CATEGORY_ID` | Yes | Default category for **email** tickets (startup also validates this). |
|
||
| `DISCORD_TICKET_CATEGORY_ID` | No | Category for **Discord** panel/context tickets (falls back to `TICKET_CATEGORY_ID`). |
|
||
| `EMAIL_THREAD_CHANNEL_ID` / `DISCORD_THREAD_CHANNEL_ID` | No | Parent **text** channels for thread-style tickets, if you use threads. |
|
||
| `EMAIL_TICKET_OVERFLOW_CATEGORY_IDS` | No | Comma-separated extra categories when the main is full (50 channels). |
|
||
| `DISCORD_TICKET_OVERFLOW_CATEGORY_IDS` | No | Same for Discord ticket category. |
|
||
| `ROLE_ID_TO_PING` | Yes | Support role pinged on new tickets; aliases include `ROLE_TO_PING_ID` in code paths. |
|
||
| `ADDITIONAL_STAFF_ROLES` | No | Extra role IDs treated as staff for commands. |
|
||
| `BLACKLISTED_ROLES` | No | Roles blocked from opening tickets. |
|
||
| `TRANSCRIPT_CHANNEL_ID` | No | Where transcripts are posted on close. |
|
||
| `LOGGING_CHANNEL_ID` | No | Ticket lifecycle logs. |
|
||
| `DEBUGGING_CHANNEL_ID` | No | Optional error/debug forwarding. |
|
||
| `BACKUP_EXPORT_CHANNEL_ID` | No | Target for `/backup` and `/export`. |
|
||
| `ACCOUNT_INFO_CHANNEL_ID` | No | Account info flows. |
|
||
|
||
### Escalation categories
|
||
|
||
| Variable | Description |
|
||
|----------|-------------|
|
||
| `EMAIL_ESCALATED_CATEGORY_ID` | Legacy fallback; alias `ESCALATED_CATEGORY_ID`. |
|
||
| `DISCORD_ESCALATED_CATEGORY_ID` | Discord fallback tier-2–style bucket. |
|
||
| `DISCORD_ESCALATED2_CHANNEL_ID` | Tier **2** placement for Discord tickets (or + fallback category). |
|
||
| `EMAIL_ESCALATED2_CHANNEL_ID` | Tier **2** for email tickets (env name says CHANNEL for legacy reasons). |
|
||
| `DISCORD_ESCALATED3_CHANNEL_ID` | Tier **3** Discord. |
|
||
| `EMAIL_ESCALATED3_CHANNEL_ID` | Tier **3** email. |
|
||
|
||
Slash `/escalate` and buttons require the appropriate tier IDs for **non-thread** channels (threads skip category moves).
|
||
|
||
### Staff personal categories & mirror channels
|
||
|
||
Optional organizational layer: **main ticket channel** stays where customers and staff talk; **mirror channel** is per-staffer category for notes + pings.
|
||
|
||
| Variable | Description |
|
||
|----------|-------------|
|
||
| `STAFF_CATEGORIES` | Map: `discordUserId:categoryId,discordUserId2:categoryId2`. If a claimer has **no** entry, **no** mirror channel is created (silent skip). |
|
||
| `STAFF_T1_CATEGORY` | Category for **unclaimed** “normal” tickets after unclaim (rename uses 🟢 prefix when rename limits allow). |
|
||
| `STAFF_T2_CATEGORY` | Pool category for **unclaimed tier-2** escalated tickets (used when moving after escalation / de-escalation flows). |
|
||
| `STAFF_T3_CATEGORY` | Pool category for **unclaimed tier-3** escalated tickets. |
|
||
| `UNCLAIMED_CATEGORY_ID` | Reserved in config for future/general fallback (currently not wired in code beyond `CONFIG`). |
|
||
|
||
If any of `STAFF_T1_CATEGORY` / `STAFF_T2_CATEGORY` / `STAFF_T3_CATEGORY` is unset, the corresponding **move is skipped** (no error).
|
||
|
||
### Google / Gmail
|
||
|
||
| Variable | Required | Description |
|
||
|----------|----------|-------------|
|
||
| `GOOGLE_CLIENT_ID` | Yes | OAuth2 client ID. |
|
||
| `GOOGLE_CLIENT_SECRET` | Yes | OAuth2 secret. |
|
||
| `REFRESH_TOKEN` | Yes | Long-lived refresh for the inbox account. |
|
||
| `MY_EMAIL` | Yes | Canonical support address (lowercased in config). |
|
||
|
||
### MongoDB
|
||
|
||
| Variable | Required |
|
||
|----------|----------|
|
||
| `MONGODB_URI` | Yes |
|
||
|
||
Test: `npm run test-mongodb` (or with `ENV_FILE=.env.test`).
|
||
|
||
### Server & optional API
|
||
|
||
| Variable | Default | Description |
|
||
|----------|---------|-------------|
|
||
| `DISCORD_ONLY_PORT` | `5000` | Express listen port (`CONFIG.PORT`). |
|
||
| `HEALTHCHECK_HOST` | *(all interfaces)* | e.g. `127.0.0.1` for local-only bind. |
|
||
| `BOSSCORD_API_KEY` | — | If set, mounts **`/api`** (bOSScord); use a strong random key. |
|
||
| `BOSSCORD_CORS_ORIGIN` | `*` | Optional CORS for the API. |
|
||
|
||
### Messaging & branding
|
||
|
||
See `.env.example` for defaults: `ESCALATION_MESSAGE` (`{support_name}`), `TICKET_WELCOME_MESSAGE`, `TICKET_CLAIMED_MESSAGE` / `TICKET_UNCLAIMED_MESSAGE` (`{staff_mention}`, `{staff_name}`), `DISCORD_CLOSE_MESSAGE`, `DISCORD_TRANSCRIPT_MESSAGE` (`{channel_name}`, `{email}`, `{date_opened}`, `{date_closed}`), `EMAIL_SIGNATURE` (`\n` → `<br>`), embed color hex vars, button labels/emojis, `SUPPORT_NAME`, `LOGO_URL`.
|
||
|
||
### Automation & limits
|
||
|
||
- **Auto-close:** `AUTO_CLOSE_ENABLED`, `AUTO_CLOSE_AFTER_HOURS`, `AUTO_CLOSE_MESSAGE`.
|
||
- **Reminders:** `REMINDER_ENABLED`, `REMINDER_AFTER_HOURS`, `REMINDER_MESSAGE` (`{ping}`, `{hours}`).
|
||
- **Limits:** `GLOBAL_TICKET_LIMIT`, `TICKET_LIMIT_PER_CATEGORY`, `RATE_LIMIT_TICKETS_PER_USER`, `RATE_LIMIT_WINDOW_MINUTES`.
|
||
- **Claim:** `ALLOW_CLAIM_OVERWRITE`, `AUTO_UNCLAIM_*`, `CLAIM_TIMEOUT_*`.
|
||
- **Priority:** `PRIORITY_ENABLED`, `DEFAULT_PRIORITY`, `PRIORITY_*_EMOJI`.
|
||
|
||
### Game list
|
||
|
||
`GAME_LIST=comma,separated,names` — used for detection/normalization in email handling.
|
||
|
||
---
|
||
|
||
## Staff personal categories & mirror channels
|
||
|
||
When configured:
|
||
|
||
1. **Claim:** DB stores `claimerId` (Discord user id) and optional `staffChannelId`. Main channel may **move** to `STAFF_CATEGORIES.get(claimerId)`. A **mirror** text channel may be created under that staffer’s category, with a **pinned embed** (ticket number, customer, game, subject, link to original channel).
|
||
2. **Customer / other user messages** in the real ticket channel: mirror channel gets a **ping**, quote (truncated), and **jump link**; if the claimer enabled **`/notifydm`**, they also get a **DM** (`StaffSettings` in MongoDB).
|
||
3. **Unclaim:** mirror channel is **deleted**; `claimerId` / `staffChannelId` cleared; channel may rename with 🟢 and move to `STAFF_T1_CATEGORY` if set.
|
||
4. **Escalation / de-escalation:** slash and button flows may apply **priority emojis** to names and move channels to `STAFF_T2_CATEGORY` / `STAFF_T3_CATEGORY` / `STAFF_T1_CATEGORY` when configured; mirror channels can move with the tier category.
|
||
5. **Close:** mirror channel is **deleted** when the ticket closes.
|
||
|
||
---
|
||
|
||
## Running the bot (test and Docker)
|
||
|
||
```bash
|
||
npm start
|
||
# or
|
||
node broccolini-discord.js
|
||
```
|
||
|
||
**Test:**
|
||
|
||
```bash
|
||
npm run start:test
|
||
npm run test-mongodb:test
|
||
```
|
||
|
||
**Docker** (see [`Dockerfile`](Dockerfile)):
|
||
|
||
```bash
|
||
docker build -t broccolini-bot .
|
||
docker run --env-file .env -p 5000:5000 broccolini-bot
|
||
```
|
||
|
||
Ensure `MONGODB_URI` and Discord token are available inside the container.
|
||
|
||
---
|
||
|
||
## Discord commands
|
||
|
||
Most commands require **staff** (`ROLE_ID_TO_PING` or `ADDITIONAL_STAFF_ROLES`). **`/help`** is available more broadly per registration.
|
||
|
||
| Command | Description |
|
||
|---------|-------------|
|
||
| **`/setup`** | Guild setup wizard (panel, role, category, transcript channel, etc.). |
|
||
| **`/panel`** | Post a ticket **Open** button in a channel (optional `type`: thread / category / both; custom title/description). |
|
||
| **`/email-routing`** | Choose whether **new email** tickets create **threads** vs **category channels** (`GuildSettings` in DB). |
|
||
| **`/escalate`** | **Required:** `level` (Tier 2 or Tier 3), `action` (`unclaim` clears `claimedBy` + `claimerId` after escalation, `keep` preserves claim). |
|
||
| **`/deescalate`** | Step down one tier (tier 3 → 2 → normal). |
|
||
| **`/notifydm`** | `on` / `off` — DM when a **non-claimer** replies in a ticket you claimed (mirror ping still applies). |
|
||
| **`/add`**, **`/remove`** | Add/remove user overwrites on the current ticket channel. |
|
||
| **`/transfer`** | Set `claimedBy` to another staff member (must have staff role). |
|
||
| **`/move`** | Move channel to another **category** (direct `setParent`). |
|
||
| **`/force-close`** | Close without button confirmation (still archives transcript best-effort). |
|
||
| **`/topic`** | Set Discord channel topic. |
|
||
| **`/priority`** | `low` / `normal` / `medium` / `high`. |
|
||
| **`/tag`** | Set ticket tag category from dropdown. |
|
||
| **`/response`** | Subcommands: `send`, `create`, `edit`, `delete`, `list` (saved responses). |
|
||
| **`/accountinfo`** | Subcommands: `email`, `discord`. |
|
||
| **`/search`** | Search tickets by email, subject, or number. |
|
||
| **`/stats`** | Bot analytics snapshot. |
|
||
| **`/backup`**, **`/export`** | Post TSV exports to `BACKUP_EXPORT_CHANNEL_ID`. |
|
||
| **`/help`** | In-bot command summary embed. |
|
||
|
||
**Context menus**
|
||
|
||
- **Create Ticket From Message** — opens a ticket prefilled from a message.
|
||
- **View User Tickets** — lists recent tickets for a user (by sender tag match).
|
||
|
||
---
|
||
|
||
## Ticket UI (buttons & modals)
|
||
|
||
- **Open ticket** (panel): modal fields are **account email**, **game**, **description** (not “priority” in the modal).
|
||
- In ticket channels: **Close**, **Claim/Unclaim**, **Escalate** (tier choice), **De-escalate** as built in [`utils/ticketComponents.js`](utils/ticketComponents.js) / [`handlers/buttons.js`](handlers/buttons.js).
|
||
- **Email routing** and **tag delete** confirmations use additional button custom IDs.
|
||
|
||
---
|
||
|
||
## Tag & response system
|
||
|
||
### `/tag`
|
||
|
||
Sets `ticketTag` from a fixed list (Server Down, Billing, etc.). Channel naming may incorporate tag/priority emojis via ticket naming logic.
|
||
|
||
### `/response`
|
||
|
||
Templates support variables such as `{ticket.user}`, `{ticket.email}`, `{ticket.number}`, `{ticket.subject}`, `{staff.name}`, `{staff.mention}`, `{server.name}`, `{date}`, `{time}` (see [`utils.js`](utils.js) / handler docs).
|
||
|
||
---
|
||
|
||
## Panel system
|
||
|
||
1. Run **`/panel`** targeting a channel (and optional style: thread-only, category-only, or both buttons).
|
||
2. User clicks **Open ticket** → modal → bot creates thread or channel per configuration.
|
||
3. Welcome embeds + action row are posted; `Ticket` stores `discordThreadId`, `ticketNumber`, etc.
|
||
|
||
---
|
||
|
||
## Channel renames & moves (rate limits)
|
||
|
||
Discord allows **two renames per 10 minutes** per channel. The bot serializes renames/moves through [`services/channelQueue.js`](services/channelQueue.js) (`p-queue`). If rename is blocked, staff see a message with a **relative time** to retry.
|
||
|
||
---
|
||
|
||
## Project structure
|
||
|
||
```
|
||
broccolini-bot/
|
||
├── broccolini-discord.js # Entry: Discord client, Express, Gmail poll interval, jobs
|
||
├── config.js # Env → CONFIG (+ STAFF_CATEGORIES map, game lists)
|
||
├── db-connection.js # Mongo connect + require models
|
||
├── models.js # Mongoose schemas (Ticket, Tag, StaffSettings, …)
|
||
├── utils.js # Email/game helpers, template variables
|
||
├── utils/ticketComponents.js # Action row builders
|
||
├── gmail-poll.js # Ingest Gmail → Discord ticket creation
|
||
├── get-refresh-token.js # One-shot OAuth refresh token helper
|
||
├── commands/register.js # Slash + context menu registration (discord.js v14)
|
||
├── handlers/
|
||
│ ├── buttons.js # Claim/close/modals/escalate buttons, ticket create modal
|
||
│ ├── commands.js # Slash handlers, runEscalation/runDeescalation
|
||
│ ├── messages.js # Staff ↔ Gmail relay; mirror pings + notifydm
|
||
│ ├── accountinfo.js
|
||
│ ├── analytics.js
|
||
│ └── setup.js
|
||
├── services/
|
||
│ ├── gmail.js
|
||
│ ├── tickets.js # Auto-close, reminders, auto-unclaim, naming helpers
|
||
│ ├── channelQueue.js # enqueueRename / enqueueMove
|
||
│ ├── staffChannel.js # Mirror create/ping/move/delete
|
||
│ ├── staffSettings.js # notifydm prefs
|
||
│ ├── guildSettings.js
|
||
│ └── debugLog.js
|
||
├── routes/bosscord.js # Optional /api routes
|
||
├── api/bosscordClient.js
|
||
├── scripts/ # Maintenance / one-off utilities
|
||
├── docs/ # Deeper guides (setup, security, MongoDB, API notes)
|
||
├── Dockerfile
|
||
├── package.json
|
||
└── .env.example / .env.test.example
|
||
```
|
||
|
||
---
|
||
|
||
## Database collections
|
||
|
||
| Model / collection | Role |
|
||
|--------------------|------|
|
||
| **Ticket Gmail thread id, Discord channel/thread id, status, priority, claim (`claimedBy` display name), `claimerId`, `staffChannelId`, escalation tier, `welcomeMessageId`, `ticketTag`, etc.** |
|
||
| **TicketCounter** | Per-sender local counters (legacy paths). |
|
||
| **Transcript** | Links closed tickets to transcript message IDs. |
|
||
| **Tag** | Saved response name + content. |
|
||
| **GuildSettings** | e.g. `emailRouting`: `thread` \| `category`. |
|
||
| **StaffSettings** | Per-user `notifyDm` (+ `guildId`, `updatedAt`). |
|
||
| **CloseRequest** | Pending close workflow if used. |
|
||
| **User**, **Host**, **DashboardMetrics**, **ErrorLog** | Shared / website-era schemas in the same `models.js` file. |
|
||
|
||
---
|
||
|
||
## HTTP: healthcheck & bOSScord API
|
||
|
||
- **`GET /`** → plain text **`Active`** (intended for load balancers / Docker `HEALTHCHECK`).
|
||
- **`/api/*`** is registered **only after** `ready` when `BOSSCORD_API_KEY` is set. JSON body parsing enabled. See [`routes/bosscord.js`](routes/bosscord.js) for routes.
|
||
|
||
---
|
||
|
||
## Gmail OAuth refresh token
|
||
|
||
```bash
|
||
node get-refresh-token.js
|
||
```
|
||
|
||
Requires `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET` in `.env`, and redirect URI **`http://localhost:3000/oauth2callback`** registered on the Google OAuth client. Paste the printed refresh token into `.env` as `REFRESH_TOKEN`.
|
||
|
||
---
|
||
|
||
## Documentation in `docs/`
|
||
|
||
Index: **[docs/README.md](docs/README.md)**. Highlights:
|
||
|
||
| Doc | Topic |
|
||
|-----|--------|
|
||
| [ENV_AND_SECURITY.md](docs/setup/ENV_AND_SECURITY.md) | Secrets, test env, agent rules |
|
||
| [MONGODB_SETUP.md](docs/setup/MONGODB_SETUP.md) | Database |
|
||
| [QUICKSTART.md](docs/setup/QUICKSTART.md) | First-time orientation |
|
||
| [PROJECT_STRUCTURE.md](docs/setup/PROJECT_STRUCTURE.md) | Layout (may overlap this README) |
|
||
|
||
---
|
||
|
||
## Troubleshooting
|
||
|
||
| Symptom | Checks |
|
||
|---------|--------|
|
||
| **Commands missing** | Correct `DISCORD_APPLICATION_ID` + `DISCORD_GUILD_ID`; **restart** bot; Discord can take time to sync. |
|
||
| **Gmail not ingesting** | `REFRESH_TOKEN`, API enablement, inbox auth; regenerate token if revoked. |
|
||
| **MongoDB errors** | `MONGODB_URI`, Atlas IP allowlist, `npm run test-mongodb`. |
|
||
| **Channels not creating** | Bot **Manage Channels** in ticket categories; category not full (50) unless overflow set. |
|
||
| **Modal / button no response** | Intents + permissions; bot online; check `DEBUGGING_CHANNEL_ID` / console. |
|
||
| **Renames “too quickly”** | Discord rename cooldown; wait for channel queue / timestamp in bot message. |
|
||
|
||
---
|
||
|
||
## References
|
||
|
||
| Technology | Link |
|
||
|------------|------|
|
||
| discord.js v14 | [discord.js guide](https://discordjs.guide/) |
|
||
| Google APIs (Gmail) | [googleapis Node](https://github.com/googleapis/google-api-nodejs-client) |
|
||
| Mongoose | [mongoosejs.com](https://mongoosejs.com/) |
|
||
| Express | [expressjs.com](https://expressjs.com/) |
|
||
|
||
---
|
||
|
||
## License
|
||
|
||
ISC
|