Actividad del ticket
Cada ticket de soporte registra su propia línea de tiempo de cambios (audit log), puede marcarse como inválido sin perderse (soft-delete) y admite la generación de un plan de mejora con IA a partir de su contenido. Estas tres capacidades viven sobrechat_tickets y su tabla de historial chat_ticket_status_history.
Audit log / actividad
Toda la actividad del ticket se guarda enchat_ticket_status_history, una tabla append-only (migración 107). Cada fila describe un único cambio: qué campo cambió, su valor anterior y nuevo, cuándo, quién lo hizo y de qué fuente proviene.
Qué se registra
- Creación del ticket — al crear un ticket se escribe una entrada con
field = 'created'. - Cambios de campo — el
update()del ticket compara contraAUDITABLE_FIELDSy escribe una entrada por cada campo que cambió, junto con el actor. Campos auditados:title,status,priority,assignee,resolution_team,zone,category,destination,payer,repair_status,estimated_cost_range,actual_cost,expected_resolution_ateinternal_notes. - Transiciones desde Zendesk — el webhook, la importación y el backfill escriben las transiciones venidas de Zendesk con su
sourcecorrespondiente (webhook/import/backfill). - Alta/baja de solicitantes adicionales — sumar o quitar un solicitante adicional (t2) escribe una entrada con
field = 'requester_added'|'requester_removed'. Ver Tickets → Varios solicitantes.
status, priority y assignee se editan desde el detalle (sección Gestión, guardado inmediato). Ya estaban en AUDITABLE_FIELDS, así que estos cambios manuales quedan registrados con source = 'manual' y el actor que los hizo.La escritura del historial es best-effort: si falla
recordFieldChanges el update() del ticket no se rompe, solo se loguea el error.Endpoint
{ entries: [...] } ordenado por changed_at. Solo accesible para Admin/Moderator. El servicio resuelve el nombre del actor (changedByName) con un join contra users (usa display_name, nombre completo o email); este campo no es una columna, se calcula en la respuesta.
Frontend
TicketHistoryTimeline muestra la actividad como un feed estilo WhatsApp, ordenado del más reciente al más antiguo:
"X creó el ticket"(eventocreated)."X dio la primera respuesta"(eventofirst_response)."X cambió <Campo>: valor anterior → valor nuevo"para cambios de campo.
Zendesk, Sincronización).
La métrica automática de primera respuesta y los dashboards de actividad por equipo/persona son follow-up.
Notificaciones al creador y al asignado
Cada cambio auditable emite además un eventoticket.* al motor de notificaciones, para que el creador y el asignado se enteren de todo lo que le pasa a “su” ticket por buzón interno de Tools + email (VIV-2080 emite los eventos; VIV-2081 siembra flows + plantillas).
- El choke point
writeStatusHistoryemiteticket.updated/ticket.assigned(solosource ∈ {manual, webhook}),create()emiteticket.created, y los comentarios (Tools + webhook de Zendesk) emitenticket.comment_added. ticket.resolvedtiene identidad propia: cuando una transición destatusentra en un estado resuelto (resolved/closed),writeStatusHistoryemiteticket.resolveden lugar deticket.updatedpara esa transición (nunca ambos). Usa la misma definición de “resuelto” que las columnas derivadas (resolved_at/reopened_count). Un reopen (resuelto → abierto) sigue saliendo comoticket.updatednormal. Plantillas + flow: migración178_seed_ticket_resolved_notification_flow.sql.- Los flows suprimen la auto-notificación (no te avisan de tu propio cambio) y deduplican cuando creador == asignado. Detalle del mecanismo en Automatizaciones → Avisos de tickets.
- Los avisos ad-hoc del buzón que existían antes (self-ack al crear, aviso al asignado al crear y al reasignar) se retiraron: ahora los cubren estos flows, con email añadido.
- El buzón interno (
/app/notificationsy el sidebar de Tools) pinta estos mensajes con una card enriquecida (TicketMessageCard) leyendometadata.ticketsin hacer fetch al ticket — ver Inbox → Tickets via Automation Engine.
Best-effort: la emisión de eventos nunca rompe ni frena la mutación del ticket. La entrega corre por el cron de Windmill (30s), así que el aviso puede llegar con unos segundos de latencia respecto al cambio.
Soft-delete de tickets inválidos
En Zendesk los tickets no se pueden eliminar. Para que CX pueda “borrar” tickets de basura, pruebas o duplicados, se implementa un soft-delete sobrechat_tickets (migración 135): se marcan inválidos, se ocultan de listas y KPIs, pero quedan recuperables. No toca Zendesk.
Endpoints
invalidateseteainvalid = truecon el motivo, el timestamp y el usuario actual.restorerevierte los cuatro campos a su estado inicial (vuelve a mostrar el ticket).
invalid = false por defecto. Para revisar los inválidos se usa el filtro onlyInvalid. Un índice parcial sobre invalid = true mantiene esas consultas baratas.
UI
Acción “Marcar inválido” (con motivo opcional), banner en el detalle del ticket inválido con opción de restaurar, y filtro “Solo inválidos” en la lista.Planes de mejora con IA
CX puede pedir que la IA genere un plan de mejora por ticket a partir de su contenido. Se persiste el último plan generado sobrechat_tickets (migración 136), de uso libre y sin tabla de cuotas.
Endpoint
AiService (Claude). El prompt pide 3-5 viñetas accionables en español: causa raíz probable, acción correctiva y cómo prevenir que se repita. Devuelve { plan, generatedAt } y guarda ambos valores en el ticket. Cada llamada reemplaza el plan anterior.
UI
TicketImprovementPlanCard muestra el último plan persistido con un botón Generar / Regenerar. Tras generar, el plan recién creado se muestra de inmediato (antes del refetch) y se indica la fecha de generación.