167 lines
4.8 KiB
Markdown
167 lines
4.8 KiB
Markdown
# MongoDB Setup for Broccolini Bot
|
|
|
|
## Overview
|
|
|
|
Broccolini Bot uses **MongoDB only** for persistent storage (tickets, transcripts, counters, tags, close requests). Run all commands from the repo root; create `.env` there (copy from `.env.example`) and set `MONGODB_URI`. For test runs, use `.env.test` (copy from `.env.test.example`) and `npm run test-mongodb:test`; see [ENV_AND_SECURITY.md](./ENV_AND_SECURITY.md).
|
|
|
|
## Files
|
|
|
|
1. **`db-connection.js`** - MongoDB connection module with reconnection logic
|
|
2. **`models.js`** - Mongoose schemas including:
|
|
- `Ticket` - Stores ticket information
|
|
- `TicketCounter` - Tracks ticket numbers per sender
|
|
- `Transcript` - Stores transcript message references
|
|
3. **`scripts/test-mongodb.js`** - Connection test script (run via `npm run test-mongodb`; use `npm run test-mongodb:test` with `.env.test`)
|
|
|
|
## Configuration
|
|
|
|
### 1. Environment Variable
|
|
|
|
Add to your `.env` file:
|
|
|
|
```env
|
|
MONGODB_URI=mongodb://broccoli_bot:CHANGE_ME@localhost:27017/broccoli_db?authSource=broccoli_db
|
|
```
|
|
|
|
**Note:** Mongo runs self-hosted on the same host as the bot. A **dedicated user per database** is required — create `broccoli_bot` with `readWrite` on `broccoli_db` only (no admin/root, no cross-DB access). For test, create a separate user with `readWrite` on `broccoli_db_test` only.
|
|
|
|
Example mongosh setup:
|
|
|
|
```javascript
|
|
use broccoli_db
|
|
db.createUser({
|
|
user: "broccoli_bot",
|
|
pwd: "CHANGE_ME",
|
|
roles: [ { role: "readWrite", db: "broccoli_db" } ]
|
|
})
|
|
```
|
|
|
|
Bind Mongo to loopback (`bindIp: 127.0.0.1`) or the internal docker network only; firewall `27017` from public interfaces.
|
|
|
|
### 2. Install Dependencies
|
|
|
|
```bash
|
|
npm install
|
|
```
|
|
|
|
This will install `mongoose@^6.12.0`.
|
|
|
|
## Usage in Your Code
|
|
|
|
### Basic Connection
|
|
|
|
```javascript
|
|
const { connectMongoDB, closeMongoDB, mongoose } = require('./db-connection');
|
|
|
|
// In your Discord client.once('ready', ...) event:
|
|
await connectMongoDB(process.env.MONGODB_URI);
|
|
console.log('Connected to MongoDB');
|
|
|
|
// Get models:
|
|
const Ticket = mongoose.model('Ticket');
|
|
const TicketCounter = mongoose.model('TicketCounter');
|
|
const Transcript = mongoose.model('Transcript');
|
|
```
|
|
|
|
## Schema Reference
|
|
|
|
### Ticket Schema
|
|
|
|
```javascript
|
|
{
|
|
gmail_thread_id: String (required, unique, indexed),
|
|
discord_thread_id: String,
|
|
broccolini_ticket_id: Number,
|
|
sender_email: String (required),
|
|
subject: String,
|
|
created_at: Date (default: now),
|
|
status: String (enum: ['open', 'closed'], default: 'open'),
|
|
claimed_by: String (Discord user ID),
|
|
escalated: Boolean (default: false),
|
|
ticket_number: Number,
|
|
rename_count: Number (default: 0), // orphan: no longer read/written (see CLAUDE.md)
|
|
rename_window_start: Date // orphan: no longer read/written
|
|
}
|
|
```
|
|
|
|
### TicketCounter Schema
|
|
|
|
```javascript
|
|
{
|
|
sender_local: String (required, unique),
|
|
counter: Number (default: 1)
|
|
}
|
|
```
|
|
|
|
### Transcript Schema
|
|
|
|
```javascript
|
|
{
|
|
gmail_thread_id: String (required),
|
|
transcript_message_id: String,
|
|
created_at: Date (default: now)
|
|
}
|
|
```
|
|
|
|
## Testing the Connection
|
|
|
|
From the repo root, run:
|
|
|
|
```bash
|
|
npm run test-mongodb
|
|
```
|
|
|
|
Expected output:
|
|
```
|
|
Pinged your deployment. You successfully connected to MongoDB!
|
|
```
|
|
|
|
## Graceful Shutdown
|
|
|
|
Add this to your main file for clean shutdown:
|
|
|
|
```javascript
|
|
process.on('SIGTERM', async () => {
|
|
console.log('SIGTERM received, closing connections...');
|
|
await closeMongoDB();
|
|
await client.destroy(); // Discord client
|
|
process.exit(0);
|
|
});
|
|
|
|
process.on('SIGINT', async () => {
|
|
console.log('SIGINT received, closing connections...');
|
|
await closeMongoDB();
|
|
await client.destroy();
|
|
process.exit(0);
|
|
});
|
|
```
|
|
|
|
## Connection Features
|
|
|
|
- **Auto-reconnection**: If MongoDB connection drops, Mongoose will automatically attempt to reconnect
|
|
- **Connection events**: Logs when connected, disconnected, and reconnected
|
|
- **Error handling**: Graceful error messages with stack traces
|
|
- **Timeouts**: Configured with reasonable defaults (5s server selection, 45s socket timeout)
|
|
|
|
## Next Steps
|
|
|
|
1. Review the schemas in `models.js`
|
|
2. Test the connection with `npm run test-mongodb`
|
|
3. Start the bot with `npm start` (uses MongoDB throughout)
|
|
4. Monitor MongoDB connection in production logs
|
|
|
|
## Troubleshooting
|
|
|
|
### Connection refused
|
|
- Check MongoDB is running: `docker ps` or `systemctl status mongodb`
|
|
- Verify port 27017 is correct in `.env` (or whatever port your mongod is bound to)
|
|
- Check MongoDB logs for errors
|
|
|
|
### Authentication failed
|
|
- Verify the user exists in the correct DB's `authSource` (URI must include `?authSource=broccoli_db`)
|
|
- Confirm the user has `readWrite` on `broccoli_db`: `db.getUser("broccoli_bot")` in mongosh
|
|
|
|
### Schema validation errors
|
|
- Check required fields are provided when creating documents
|
|
- Ensure `status` is either 'open' or 'closed' (enum validation)
|