> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ravenna.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Ticket mirrors

> Ticket mirrors are interactive Ravenna ticket Adaptive Cards in Microsoft Teams that update in real time as assignees, status, and priority change.

Ticket mirrors are interactive representations of Ravenna tickets that appear in Microsoft Teams as Adaptive Cards. They update automatically as the ticket changes so you can track and manage tickets without leaving Teams.

<View title="Human" icon="user">
  ## How ticket mirrors work

  Ticket mirrors sync in real time between Teams and Ravenna. When the assignee, status, or priority changes anywhere, every mirror of that ticket updates within seconds.

  ### Where mirrors appear

  * **Request thread**: the channel thread or chat where the ticket was created.
  * **Triage channel**: a new top-level post in the configured Teams triage channel (when forwarding is enabled for the source Channel).
  * **Direct messages**: a card sent to specific users for events that target them, such as approval requests.

  ### What you can do from a card

  Ticket cards include action buttons for the most common operations:

  * Open the ticket in Ravenna via a deep link
  * Assign or reassign the ticket
  * Change status (resolve, close, reopen)
  * Update priority
  * Add or remove tags

  All actions sync immediately back to Ravenna and to every other mirror.

  ***

  ## Card types

  <AccordionGroup>
    <Accordion title="Ticket published card" icon="ticket">
      Posted when a ticket is published in a connected request channel or triage channel. Shows the ticket number, title, status, priority, assignee, requester, description, and a link back to Ravenna.
    </Accordion>

    <Accordion title="Status change card" icon="circle-check">
      Posted when a ticket's status changes. Shows who made the change and what the new status is.
    </Accordion>

    <Accordion title="Assignment card" icon="user-plus">
      Posted when a ticket is assigned, reassigned, or unassigned.
    </Accordion>

    <Accordion title="Approval request card" icon="check">
      Sent as a DM to each approver added to an approval round. Approvers can approve or decline (with an optional reason) directly from the card.
    </Accordion>

    <Accordion title="Form card" icon="clipboard-list">
      Sent when a request type or workflow form needs input. Rendered as an interactive Adaptive Card with the configured form fields. Submitting the form updates the ticket and progresses the workflow.
    </Accordion>

    <Accordion title="Authored message card" icon="message-circle">
      Wraps a human-authored message from Ravenna in a card with an avatar and the author's name above the message text. This is how Ravenna attributes outbound messages to the original Ravenna user. Bot Framework does not allow posting on behalf of an arbitrary user.
    </Accordion>
  </AccordionGroup>
</View>

<View title="Agent" icon="bot">
  ## Mental model

  A Teams ticket mirror is an Adaptive Card representation of a Ravenna ticket attached to a `ChatMessage` row. There can be many mirrors per ticket (request thread, triage thread, DM to approvers, etc.), and Ravenna keeps each in sync by tracking the underlying Bot Framework `activityId` per mirror.

  Outbound updates route through a delivery chooser:

  * **Bot path**: when a `ChatConversation` exists for the ticket with a known `serviceUrl`, Ravenna sends via the Bot Framework Connector using a cached bot token (client credentials flow).
  * **Graph path**: when no conversation exists yet, the integration would create one via Microsoft Graph. This path is currently deferred and the event is skipped.

  ***

  ## Event → card mapping

  | Ticket event                                                                      | Behavior                                                                                                                                                                                                    |
  | --------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | `TICKET_PUBLISHED`                                                                | Post a ticket card. If the source Channel has triage forwarding enabled, also post a card to the workspace's Teams triage channel.                                                                          |
  | `TICKET_UPDATED`, `TICKET_ARCHIVED`, `TICKET_UNARCHIVED`, `MOVED`, `SET_PRIORITY` | Update existing ticket cards in place using the stored `activityId`.                                                                                                                                        |
  | `MESSAGE_CREATED`                                                                 | Send the message via the outbound renderer (form card, authored card, or plain Teams markdown depending on the message type). Skipped for private messages and for inbound messages echoed back from Teams. |
  | `MESSAGE_EDITED`                                                                  | Update the previously-sent activity.                                                                                                                                                                        |
  | `MESSAGE_DELETED`                                                                 | Delete the previously-sent activity.                                                                                                                                                                        |
  | `SET_STATUS`                                                                      | Post or update a status change card.                                                                                                                                                                        |
  | `ASSIGN`, `UNASSIGN`                                                              | Post or update an assignment card.                                                                                                                                                                          |
  | `APPROVAL_ROUND_APPROVER_ADDED`                                                   | DM each newly-added approver an approval request card. Does not require an existing conversation.                                                                                                           |
  | `TICKET_APPROVAL_COMPLETED`                                                       | Post or update an approval-completed card showing the outcome.                                                                                                                                              |

  ***

  ## Outbound content pipeline

  Outbound rendering is owned by `TeamsOutboundRenderer`:

  1. **Mention translation**: Ravenna user mentions in the message are resolved to Teams users via the integration user store. Mapped users become `<at>Display Name</at>` tokens; unmapped users degrade to bold text.
  2. **Content conversion**: RavMarkdown is converted to Teams markdown via `RavMarkdownToTeamsMarkdownAdapter`, preserving `<at>` tokens.
  3. **Activity assembly**: `buildSendActivity` attaches Bot Framework `entities[]` for each mention so Teams renders the mention chip and notifies the user. The `<at>` token text must match the entity's `text` field exactly.
  4. **Author attribution**: Human-authored messages are wrapped in an authored-message Adaptive Card (avatar + name header). AI-generated messages keep the plain-text path. `<at>` resolution inside cards is handled via `msteams.entities` on the card body, because activity-level entities don't resolve mentions inside Adaptive Card content.

  ***

  ## Idempotency

  Each mirror is keyed by `(chatConversationId, ticketId, messageType)`. The triage mirror in particular checks for an existing ticket card before posting, so re-publishing a ticket never creates duplicates.

  ***

  ## Deep links

  Ravenna constructs Teams deep links to channel messages from the inbound activity rather than calling the Graph API. The link format is:

  ```
  https://teams.microsoft.com/l/message/{channelId}/{messageId}?tenantId=...&groupId=...&parentMessageId=...
  ```

  Deep links are only generated for **channel** messages. 1:1 and group chats don't have a reliable public deep-link format, so Ravenna omits the link rather than producing a broken one.

  ***

  ## Constraints and gotchas

  * The bot path requires a `serviceUrl` recorded on the `ChatConversation`. If it's missing, the event is skipped (Graph path is deferred).
  * Private messages are not mirrored to Teams.
  * Messages that originated in Teams are not echoed back to Teams (unless `aiGenerated` is true).
  * Bot Framework activities are always sent as the bot. There is no API to post as another user, so author attribution uses authored-message cards instead.
</View>
