209 lines
5.3 KiB
Markdown
209 lines
5.3 KiB
Markdown
# MongoDB Setup for Gmail-Discord-Zammad Bridge
|
||
|
||
## Overview
|
||
|
||
The bridge uses **MongoDB only** for persistent storage (tickets, transcripts, counters, tags, close requests). SQLite has been removed; a backup of the old SQLite-based code and schema lives in `backup-sqlite/`. To migrate existing SQLite data to MongoDB, run `npm run migrate-from-sqlite` (see that script’s prerequisites).
|
||
|
||
## Files Created
|
||
|
||
1. **`db-connection.js`** - MongoDB connection module with reconnection logic
|
||
2. **`models.js`** - Updated with three new schemas:
|
||
- `Ticket` - Stores ticket information
|
||
- `TicketCounter` - Tracks ticket numbers per sender
|
||
- `Transcript` - Stores transcript message references
|
||
3. **`mongodb-example.js`** - Example usage patterns
|
||
|
||
## Configuration
|
||
|
||
### 1. Environment Variable
|
||
|
||
Add to your `.env` file:
|
||
|
||
```env
|
||
MONGODB_URI=mongodb://localhost:27018/indifferent_broccoli
|
||
```
|
||
|
||
**Note:** Uses port `27018` to match your existing Indifferent Broccoli setup (as defined in docker-compose.yml).
|
||
|
||
### 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');
|
||
```
|
||
|
||
### Replacing SQLite Operations
|
||
|
||
#### Old (SQLite):
|
||
```javascript
|
||
const ticket = await dbGet("SELECT * FROM tickets WHERE gmail_thread_id = ?", [threadId]);
|
||
```
|
||
|
||
#### New (MongoDB):
|
||
```javascript
|
||
const Ticket = mongoose.model('Ticket');
|
||
const ticket = await Ticket.findOne({ gmail_thread_id: threadId });
|
||
```
|
||
|
||
#### Old (SQLite):
|
||
```javascript
|
||
await dbRun("INSERT INTO tickets (gmail_thread_id, discord_thread_id, ...) VALUES (?, ?, ...)",
|
||
[threadId, channelId, ...]);
|
||
```
|
||
|
||
#### New (MongoDB):
|
||
```javascript
|
||
const Ticket = mongoose.model('Ticket');
|
||
await Ticket.create({
|
||
gmail_thread_id: threadId,
|
||
discord_thread_id: channelId,
|
||
...
|
||
});
|
||
```
|
||
|
||
#### Old (SQLite):
|
||
```javascript
|
||
await dbRun("UPDATE tickets SET status = ? WHERE gmail_thread_id = ?", ['closed', threadId]);
|
||
```
|
||
|
||
#### New (MongoDB):
|
||
```javascript
|
||
const Ticket = mongoose.model('Ticket');
|
||
await Ticket.updateOne(
|
||
{ gmail_thread_id: threadId },
|
||
{ $set: { status: 'closed' } }
|
||
);
|
||
```
|
||
|
||
## Schema Reference
|
||
|
||
### Ticket Schema
|
||
|
||
```javascript
|
||
{
|
||
gmail_thread_id: String (required, unique, indexed),
|
||
discord_thread_id: String,
|
||
zammad_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),
|
||
rename_window_start: Date
|
||
}
|
||
```
|
||
|
||
### 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
|
||
|
||
Run the example file to verify everything works:
|
||
|
||
```bash
|
||
node mongodb-example.js
|
||
```
|
||
|
||
Expected output:
|
||
```
|
||
Connecting to MongoDB...
|
||
✓ Connected to MongoDB
|
||
✓ Models loaded: Ticket, TicketCounter, Transcript
|
||
|
||
--- Example: Create Ticket ---
|
||
Created ticket: example_thread_123
|
||
...
|
||
✓ Example completed successfully
|
||
```
|
||
|
||
## 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);
|
||
});
|
||
```
|
||
|
||
## Migration Notes
|
||
|
||
- **No automatic data migration** from SQLite - starting fresh with MongoDB
|
||
- The existing `tickets.sqlite` and `discord_only.sqlite` files remain untouched
|
||
- You can manually export data from SQLite and import into MongoDB if needed
|
||
|
||
## 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` (lines 793-819)
|
||
2. Test the connection with `node mongodb-example.js`
|
||
3. Start replacing SQLite operations in `zammad-discord.js` with MongoDB operations
|
||
4. Monitor MongoDB connection in production logs
|
||
|
||
## Troubleshooting
|
||
|
||
### Connection refused
|
||
- Check MongoDB is running: `docker ps` or `systemctl status mongodb`
|
||
- Verify port 27018 is correct in `.env`
|
||
- Check MongoDB logs for errors
|
||
|
||
### Authentication failed
|
||
- If MongoDB requires auth, update URI: `mongodb://username:password@localhost:27018/indifferent_broccoli`
|
||
|
||
### Schema validation errors
|
||
- Check required fields are provided when creating documents
|
||
- Ensure `status` is either 'open' or 'closed' (enum validation)
|