# 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 creator’s 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 Zammad’s 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 replier’s display name (if Zammad API supports updating that field).