Files
broccolini-bot/docs/MONGODB_ZAMMAD_LINK.md
root 519788c633 Initial commit
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-10 08:22:19 -06:00

103 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MongoDB Bridge ↔ Zammad Schema Mapping
Reference for linking the gmail-bridge (MongoDB) with Zammad's PostgreSQL schema. Source: [schema zammad.txt](schema%20zammad.txt).
## Primary link: Ticket ↔ Zammad ticket
| MongoDB (Ticket) | Zammad (tickets) | Notes |
|--------------------|------------------|--------|
| `zammadTicketId` | `id` (serial) | Primary link; set when we create a Zammad ticket via API. |
| `gmailThreadId` | — | Bridge-only; Gmail thread ID. |
| `discordThreadId` | — | Bridge-only; Discord channel ID. |
| `senderEmail` | `customer_id` → users.email | Zammad creates/finds user by email when we POST ticket. |
| `subject` | `title` | Ticket title. |
| `status` (open/closed) | `state_id` → ticket_states | We PATCH state to closed on force-close. |
## Zammad tables we touch via API
- **tickets** Create (POST), update state (PATCH). Key columns: `id`, `group_id`, `priority_id`, `state_id`, `title`, `customer_id`, `owner_id`, `number`, `discordusername`, `gameid`.
- **ticket_articles** Create (POST) when staff reply in Discord. Key columns: `ticket_id`, `type_id` (e.g. note), `sender_id`, `body`, `content_type`, `internal`, `subject`, `from`.
- **users** Zammad creates/finds customer by email on ticket create. If the sender email matches a MongoDB **User** (website user) with `discordID`, the bridge PATCHes the Zammad user with `discord_id` so the customer in Zammad has the Discord ID. Requires adding a custom attribute **discord_id** on the **User** object in Zammad (Admin → Object Manager → User).
## Zammad custom fields on tickets (from schema)
- **discordusername** (limit 120) Can store Discord display name for the ticket.
- **gameid** (limit 255) We already send this when creating a ticket (game key from bridge).
## Important MongoDB fields → Zammad custom attributes
These MongoDB Ticket fields matter for Zammad; the schema only has two custom columns on `tickets`, so we map into those or would need new attributes in Zammad.
| MongoDB (Ticket) | Zammad today | Action |
|-------------------|--------------|--------|
| **gameKey** (from email/game) | **gameid** | Already sent on ticket create. |
| **claimedBy** (Discord display name) | **discordusername** | Not set today. Should PATCH ticket when someone claims (e.g. set `discordusername` to `claimedBy` on claim, clear on unclaim). |
| **priority** (low/normal/medium/high) | **priority_id** (core) | Not synced. We could PATCH ticket when `/priority` is used so Zammad shows same priority. |
| **gmailThreadId** | — | No column in Zammad. If you add a custom attribute (e.g. `gmail_thread_id`) in Zammad, we can send it on create/update. |
| **discordThreadId** | — | No column in Zammad. Same: add e.g. `discord_channel_id` in Zammad if you want it there. |
| **escalated** | — | No column in Zammad. Add a custom attribute (e.g. `escalated` boolean) in Zammad if you want it visible in Zammad. |
**Recommended now (no Zammad schema change):**
1. **Set `discordusername` on claim** When a staff member claims the ticket in Discord, PATCH the Zammad ticket with `discordusername: claimedBy` so Zammad shows who is handling it on Discord. Clear it on unclaim.
2. **Sync priority to Zammad** When priority changes in Discord via `/priority`, PATCH the Zammad ticket with the matching priority (e.g. Zammad uses `1` low, `2` normal, `3` high or similar; check your Zammad priority_id values).
**Optional (requires adding custom attributes in Zammad):**
- **gmail_thread_id** Useful for agents to open or reference the Gmail thread.
- **discord_channel_id** Useful for deep links to the Discord thread.
- **escalated** If you want Zammad to show that the ticket was escalated from Discord.
## Email ticket → Zammad user with discord_id
When an email ticket comes in, the bridge:
1. Extracts sender email (`sEmail`).
2. Looks up **MongoDB User** (website user) by `email` (case-insensitive). If that user has a `discordID`, it is stored for the next step.
3. Creates the Zammad ticket (Zammad creates or finds the customer user by email).
4. If the ticket response has `customer_id` and we have a `discordID` from step 2, the bridge **PATCHes the Zammad user** with `discord_id: discordID`.
**Requirement:** In Zammad, add a custom attribute **discord_id** (text) on the **User** object: Admin → Object Manager → User → add attribute `discord_id`. Without it, the PATCH will fail (the bridge logs the error and continues).
## Discord ticket → ensure Zammad user exists
When a **Discord ticket** is created (modal “Create Support Ticket” or “Create ticket from message”):
1. The bridge looks up **MongoDB User** (website user) by the creators Discord ID (`interaction.user.id` or `message.author.id`).
2. If a User is found with an **email**, the bridge calls **ensureZammadUserForDiscordUser**:
- Searches Zammad for a user with that email (`GET /api/v1/users/search?query=...`).
- If none exists, **creates** a Zammad user (Customer) with email, firstname, lastname, and `discord_id`.
- If a user exists, optionally sets `discord_id` on them via PATCH.
3. No Zammad **ticket** is created for Discord-only tickets; only the Zammad **user** is ensured so they exist when you later create tickets or link them.
**Requirement:** Same as above: add **discord_id** on the User object in Zammad Object Manager if you want Discord ID stored. User create will still work without it; only the `discord_id` field will be skipped.
## Flow summary
1. **New email → new ticket**
Bridge creates MongoDB `Ticket` and calls Zammad `POST /api/v1/tickets`; stores returned `id` in `Ticket.zammadTicketId`.
2. **Staff reply in Discord**
Bridge sends reply to Gmail and calls Zammad `POST /api/v1/ticket_articles` with `ticket_id: ticket.zammadTicketId`.
3. **Force-close in Discord**
Bridge sets MongoDB `status: 'closed'` and calls Zammad `PATCH /api/v1/tickets/:id` with `state: 'closed'`.
## Creating Zammad objects to match the bridge
To ensure Zammad has the groups (and reference data) the bridge expects, run from `gmail-bridge`:
```bash
npm run create-zammad-objects
```
This script (see [scripts/create-zammad-objects.js](../scripts/create-zammad-objects.js)) uses the same `.env` as the bridge and:
- Creates the groups **Email Users** and **Discord Users** if they do not exist (from `ZAMMAD_EMAIL_GROUP` and `ZAMMAD_DISCORD_GROUP`).
- Lists **ticket priorities** and **ticket states** so you can verify IDs (e.g. for future priority sync).
Custom attributes (e.g. `gmail_thread_id`, `discord_channel_id`, `escalated`) must be added in Zammads admin UI (Object Manager) if you want them; the API for creating object attributes is admin-only.
## Optional improvements
- **Store Zammad customer id** If we ever need to reference the same customer across tickets, add `zammadCustomerId` to MongoDB Ticket and set it from the Zammad ticket create response.
- **Set discordusername on ticket** When adding an article from Discord, we could PATCH the ticket to set `discordusername` to the repliers display name (if Zammad API supports updating that field).