Skip to content

v0.7.4

Choose a tag to compare

@mpge mpge released this 21 Oct 17:55
bf59e20

Upgrading

  • Run the migrations (0032_verified_guest_access) and configure outbound
    email. Use a shared cache across workers for the code budgets.
  • Existing permanent guest links (guest/<guest_token>/, the widget's old
    guest_token) stop working. Guests renew them with the lookup form (email
    code plus ticket reference). ESCALATED["GUEST_ACCESS"]["LEGACY_TOKENS"] = True keeps the old links working during a transition.
  • Clients that do not send verification_id and verification_code can no
    longer create guest tickets or start widget chats. The widget's create
    responses now carry the grant (with expires_at) where they carried the
    permanent token.
  • The new URL does not make files already in MEDIA private. Stop your web
    server or CDN from serving MEDIA_ROOT/escalated/attachments/ publicly; see
    docs/private-attachments.md. Links expire, so clients that cached
    attachment URLs must refetch the ticket.
  • Webhooks saved under the old names keep receiving those events, now under
    the new names in the delivery's event field and X-Escalated-Event
    header. Receivers that switch on the event name should accept the new
    names. The edit form shows (and saving stores) the canonical names.
  • Stored names are read as aliases, not rewritten: ticket.replied,
    internal_note.added, internal_note.created, tag.added,
    ticket.tagged, tag.removed, ticket.untagged, chat.session_started
    and chat.session_ended. A workflow saved with the ticket.replied
    trigger is stored and shown as reply.created and keeps firing on replies.

Added

  • Live chat events (ADR 2026-10-21): chat.started, chat.assigned,
    chat.transferred, chat.message and chat.ended are now sent to
    outbound webhooks and run workflows, and the webhook form and the workflow
    builder offer them. Before this, chat events reached neither. The webhook
    payload is {"chat": {"session_id", "ticket_id", "status", "agent_id", "department_id"}}, plus from_agent_id/to_agent_id/to_department_id
    (always null; transfers are agent to agent) for a transfer,
    reply_id/author_type (agent or visitor) for a message and
    ended_by (agent or customer) for an end. It never carries the
    visitor's chat token (customer_session_id), the visitor's email or the
    message body. Workflows on chat events run against the chat's ticket. A new
    chat_assigned signal is sent when an agent takes a chat (accepted from the
    queue or routed at start). Webhooks and workflows saved under
    chat.session_started / chat.session_ended receive chat.started /
    chat.ended. Upgrade: run python manage.py migrate escalated
    (0033_workflow_chat_triggers only updates the trigger choices; no schema
    change).

Security

  • Verified guest access, as in escalated-laravel (docs/guest-access.md).
    Guest tickets (browser and widget), widget live chats and ticket lookup now
    need an eight-digit code emailed to the guest (10-minute expiry, five
    guesses, single use; at most 3 codes per mailbox per client IP and 10 per
    mailbox per hour). POST verification and POST lookup are served under
    guest/, widget/ and <API_PREFIX>/mobile/guest/. New tickets get an
    expiring grant (default 24 hours, GUEST_ACCESS["TTL_MINUTES"]) whose nonce
    is stored only as a hash, instead of the permanent guest_token.
    /widget/config sends guest_verification_required: true and
    status_lookup_enabled: true, and GET widget/tickets/<reference> returns
    the ticket's status for a matching Authorization: Bearer <grant>.
    Guest/Create receives verification_url and lookup_url, and the guest
    ticket page no longer carries ticket or reply metadata, the requester
    record or agent emails.
  • Attachments are delivered privately, as in escalated-laravel. Serialized
    attachments (AttachmentSerializer, ApiAttachmentSerializer) no longer
    carry the file's MEDIA URL. Their url is a signed link to the new
    escalated:attachment_download view (<prefix>/attachments/<id>/), valid
    for ATTACHMENT_DOWNLOAD_TTL_MINUTES (default 10). The view checks current
    ticket access: agents and admins who can view the ticket, the requester for
    attachments on the ticket and its public replies, and guests holding a link
    issued by their guest page (bound to the ticket's active guest grant, so
    renewing or revoking the grant revokes them). Internal-note attachments are only served to agents
    and admins. Responses are Content-Disposition: attachment with a safe
    filename, application/octet-stream except for a few inert types,
    X-Content-Type-Options: nosniff and Cache-Control: private, no-store.
    API clients send their Escalated bearer token with the download.

Changed

  • Webhooks use the shared event vocabulary (escalated-developer-context ADR
    2026-10-21): internal notes go out as note.created (was
    internal_note.added) and tag changes as ticket.tag_added /
    ticket.tag_removed (were tag.added / tag.removed). The admin Webhooks
    form offers only the canonical names. The names live in
    escalated/event_names.py.