Files
broccolini-bot/README.md
indifferentketchup 6b94791813 cleanup and simplify
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 02:15:18 +00:00

92 lines
4.1 KiB
Markdown

# Broccolini Bot
A Node.js Discord bot that bridges **Gmail ↔ Discord** for support ticketing, with **MongoDB** for state. Built for Indifferent Broccoli (game-server hosting).
- Inbound email → Discord ticket channel.
- Staff messages in that channel → Gmail reply (threaded).
- Discord-originated tickets (panel / context menu) live entirely in Discord.
For an architectural overview, see [HOWITWORKS.md](HOWITWORKS.md). For agent/contributor conventions, see [CLAUDE.md](CLAUDE.md).
---
## Quick start
```bash
git clone <repo-url>
cd broccolini-bot
npm install
cp .env.example .env
# fill DISCORD_TOKEN, DISCORD_APPLICATION_ID, DISCORD_GUILD_ID, TICKET_CATEGORY_ID,
# ROLE_ID_TO_PING, MONGODB_URI, GOOGLE_CLIENT_ID/SECRET, REFRESH_TOKEN, MY_EMAIL
npm start
```
Need a Gmail refresh token? `node get-refresh-token.js` (redirect URI `http://localhost:3000/oauth2callback`). Probe Mongo with `npm run test-mongodb`.
Restart the bot after any `.env` change. Restart also re-registers slash commands.
## Deploy (Docker)
```bash
docker compose up --build -d
docker logs broccolini --tail 50 -f
```
Host port `8892` → container `5000` (`DISCORD_ONLY_PORT`).
## Configuration
All config is environment variables loaded by `config.js` into `CONFIG`. The full list — with descriptions and defaults — lives in [`.env.example`](.env.example). Highlights:
| Variable | Notes |
|----------|-------|
| `DISCORD_TOKEN` / `DISCORD_BOT_TOKEN` | Bot token. First non-empty after trim wins. |
| `DISCORD_APPLICATION_ID`, `DISCORD_GUILD_ID` | Required for slash command registration. |
| `TICKET_CATEGORY_ID` | Default category for email tickets. Validated at startup. |
| `DISCORD_TICKET_CATEGORY_ID` | Category for Discord panel/context tickets (falls back to `TICKET_CATEGORY_ID`). |
| `ROLE_ID_TO_PING` | Support role pinged on new tickets. |
| `MONGODB_URI` | Mongo connection string. |
| `GOOGLE_CLIENT_ID` / `GOOGLE_CLIENT_SECRET` / `REFRESH_TOKEN` / `MY_EMAIL` | Gmail OAuth + canonical inbox address. |
| `RENAMER_BOT` | Optional secondary token used for channel renames. |
| `INTERNAL_API_SECRET` / `INTERNAL_API_PORT` | Enable the internal config API used by the settings UI. |
## Slash commands
| Command | Purpose |
|---------|---------|
| `/escalate`, `/deescalate` | Move ticket between tier 2/3 categories. |
| `/add`, `/remove` | Add/remove user from current ticket channel. |
| `/transfer` | Hand the claim to another staff member. |
| `/move` | Reparent the channel to another category. |
| `/force-close`, `/cancel-close`, `/closetimer` | Force-close flow with cancellable countdown. |
| `/topic` | Set channel topic. |
| `/response` | Saved reply templates (`send`, `create`, `edit`, `delete`, `list`). |
| `/panel` | Post an "Open ticket" panel button (thread / category / both). |
| `/notifydm` | Toggle DM alerts when a customer replies in your claimed ticket. |
| `/signature` | Personal email signature (valediction, display name, tagline). |
| `/staffthread` | Toggle / configure staff-only threads on tickets. |
| `/pinmessages` | Auto-pin welcome / escalation messages. |
| `/gmailpoll` | Set the Gmail poll interval at runtime. |
| `/help` | In-bot summary. |
Plus context menus: **Create Ticket From Message**, **View User Tickets**.
## Settings UI (optional)
`settings-site/` is a separate Express app that talks to the bot's internal config API over the `broccoli-net` Docker network using `INTERNAL_API_SECRET`. It is **not** part of this bot's process. See [`settings-site/CLAUDE.md`](settings-site/CLAUDE.md).
## Troubleshooting
| Symptom | Check |
|---------|-------|
| Slash commands missing | Correct `DISCORD_APPLICATION_ID` + `DISCORD_GUILD_ID`; restart; Discord can take a minute to sync. |
| Gmail not ingesting | `REFRESH_TOKEN` valid? Auth failure halts polling — re-auth and restart. |
| Mongo errors at startup | `MONGODB_URI` reachable? `npm run test-mongodb` to confirm. |
| Channel rename "too quickly" | Discord limit is 2 renames/10 min per channel — the queue serializes; wait it out. |
| Modal/button no response | Bot online + intents enabled; check `DEBUGGING_CHANNEL_ID` / container logs. |
## License
ISC