@startuml uml-sequence-ticket-escalacion-l1-l2-l3 !include _style.iuml title 5. Ticket de soporte: escalación L1 -> L2 -> L3 ' Fuente: apps/web/src/lib/dashboard/actions/tickets-escalate.ts:1-133 ' Fuente: migrations/006_support_itsm.sql:178-273 (escalation_log_ticket, ticket_sla_state) ' Fuente: migrations/006_support_itsm.sql:551-614 (triggers auto_assign + bootstrap_sla) ' Fuente: migrations/006_support_itsm.sql:728-761 (RLS policies) autoactivate on actor "Cliente" as Cli actor "Agente L1" as AL1 actor "Agente L2" as AL2 actor "Dev L3" as AL3 box "Web Admin / API mobile" #F0F0F0 participant "Server action\nescalarTicket()" as Act end box box "Persistencia Postgres" #EAEAEA database "tickets_soporte" as DBTk entity "trg auto_assign_grupo" as TrgA entity "trg bootstrap_sla" as TrgS database "ticket_sla_state\n(FRT, TTR)" as DBSla database "escalation_log_ticket" as DBEsc end box == Apertura del ticket (L1) == Cli ->> DBTk ++ : INSERT tickets_soporte\n(tier_actual='l1' default) DBTk -> TrgA ++ : BEFORE INSERT TrgA -> TrgA : grupo_asignado := \nCASE categoria ... note right of TrgA migrations/006:551-569 cobro_incorrecto -> finanzas_l2 no_show -> operaciones_l1 default -> soporte_l1 end note TrgA --> DBTk -- : NEW.grupo_asignado DBTk -> TrgS ++ : AFTER INSERT TrgS -> DBSla ++ : INSERT ticket_sla_state\n(frt_due_at, ttr_due_at) note right of TrgS migrations/006:572-614 Phase 2: calendar-aware. Hoy: wall-clock por policy. end note DBSla --> TrgS -- TrgS --> DBTk -- : ok DBTk --> Cli -- : ticket_id (estatus='nuevo', tier='l1') == Toma por L1 == AL1 -> DBTk ++ : UPDATE asignado_a = AL1 DBTk --> AL1 -- AL1 -> DBSla ++ : UPDATE primer_respuesta_at = NOW() DBSla --> AL1 -- alt FRT cumplido y resoluble en L1 AL1 -> DBTk : UPDATE estatus='resuelto' note over AL1 #FEF3C7 Caso ideal, sin escalación. end note else fuera de alcance L1 == Escalación L1 -> L2 == AL1 -> Act ++ : escalarTicket({toTier:'l2',\n motivo:'fuera_alcance', hipotesis}) Act -> Act : tienePermiso('soporte.tickets.escalar_l2') Act -> DBTk ++ : SELECT FOR UPDATE tier_actual DBTk --> Act -- : tier='l1' Act -> DBEsc ++ : INSERT escalation_log_ticket\n(from='l1', to='l2', motivo, hipotesis) DBEsc --> Act -- Act -> DBTk ++ : UPDATE tier_actual='l2'\ngrupo='soporte_l2'\nestatus='escalado' DBTk --> Act -- Act --> AL1 -- : ok AL2 -> DBTk ++ : Toma ticket DBTk --> AL2 -- alt L2 resuelve AL2 -> DBTk : UPDATE estatus='resuelto' AL2 -> DBSla : UPDATE resuelto_at=NOW() else requiere dev == Escalación L2 -> L3 == AL2 -> Act ++ : escalarTicket({toTier:'l3',\n motivo:'requiere_dev'}) Act -> DBEsc ++ : INSERT escalation_log_ticket\n(from='l2', to='l3') DBEsc --> Act -- Act -> DBTk ++ : UPDATE tier_actual='l3'\ngrupo='dev_l3' DBTk --> Act -- Act --> AL2 -- : ok AL3 -> DBTk ++ : Investiga + fix AL3 -> DBTk : UPDATE estatus='resuelto'\nresolucion_codigo='resuelto_directo' DBTk --> AL3 -- end end footer Fuente: apps/web/src/lib/dashboard/actions/tickets-escalate.ts | migrations/006_support_itsm.sql L178-L614 @enduml