# Feature Specification: Desk Assist & Takeover — Intervenção Técnica (010) **Criado:** 2026-06-10 **Solicitado por:** Roger **Status:** 📋 **Draft — decisões fechadas, pronta para plano** **Prioridade:** **P0** (bloqueia operação humana no onboarding) **Depende de:** Spec 001 (webhooks VM112), Spec 003 (auth/RBAC) **Relacionada:** Spec 007 (push escalada), Spec 008 (Kanban/SLA), Spec 011 (OTRS futuro) **API alvo:** `0.9.0-desk-assist` (VM122) + contratos VM112 `assist-v1` --- ## Resumo Hoje o **Ligbox Ops Desk** é **observacional**: técnicos veem funil, tickets e timeline, mas **não podem intervir** quando o onboarding trava ou o cliente pede ajuda. **Objetivo Spec 010:** transformar o Desk no **control plane de assistência humana** — com escalada bidirecional (cliente ou técnico), **modo ASM** (técnico substitui o cliente no wizard), pausa de sessão, ticket atribuído e **ações operacionais só via Desk** (nunca embed Proxmox/Carbonio). O **wizard continua no VM112**; o **Desk (VM122)** orquestra escalada, atribuição, audit e acções API. --- ## Decisões confirmadas (Roger — 2026-06-10) | # | Pergunta | Decisão | |---|----------|---------| | 1 | Quem inicia escalada? | **Cliente** (botão no wizard) **e técnico** (puxar sessão activa no Desk) | | 2 | Visibilidade do técnico | **Não cego total** — observa até etapa simples; **intervenção relevante a partir de `domain.validated`**; takeover pleno especialmente após `account.created` | | 3 | Takeover vs co-browse | **ASM — técnico substitui o cliente** (não co-browse guia). Cliente pausado durante assistência | | 4 | Consoles externos | **Links em nova aba** (Proxmox, Carbonio, Traefik, Cloudflare) — **acções operacionais só no Desk** via API | | 5 | OTRS | Escalada **fica no Desk (VM122)** por agora. Integração OTRS → **Spec 011** (VM112 ↔ OTRS, futuro) | --- ## Dois modos de operação ```mermaid stateDiagram-v2 [*] --> Observador: onboarding normal Observador --> Escalado: cliente pede ajuda OU técnico puxa OU failed OU stale Escalado --> Assistindo: técnico assume ASM takeover Assistindo --> Observador: handoff / resolvido note right of Observador Etapas started até antes de domain: funil mínimo, sem takeover end note note right of Assistindo Cliente pausado Técnico actua no wizard VM112 Acções API via Desk end note ``` ### Modo Observador (default) - Técnico vê **funil + sessões activas** (domínio, etapa, `session_id`, stale). - Até **`onboarding.started`**: visibilidade mínima — processo deve correr sozinho. - A partir de **`domain.validated`**: ticket pode ser criado/atualizado; técnico **pode** escalar ou ser alertado. - **Sem acção** no wizard do cliente. ### Modo Assistência activa (ASM) - Cliente **pausado** — wizard bloqueado com mensagem pt-BR. - Técnico **substitui** o cliente no wizard (token takeover VM112). - Ticket: `assisting` + `assigned_to`. - Desk expõe **Console de assistência**: passo, timeline, acções permitidas, links externos (nova aba). - **Handoff**: técnico encerra assistência → cliente retoma. --- ## Etapas do funil e regras de visibilidade/intervenção Alinhado a `FUNNEL_EVENT_RANK` (Spec 001): | Rank | Evento | Etapa | Observador | Escalar | Takeover ASM | |------|--------|-------|------------|---------|--------------| | 1 | `onboarding.started` | started | ✅ mínimo | ❌ | ❌ **+ ticket no «Criar conta»** (Spec 012 — Roger 2026-06-10) | | 2 | `domain.validated` | domain_validated | ✅ | ✅ | ✅ (técnico puxa) | | 3 | `dns.applied` | dns_applied | ✅ | ✅ | ✅ | | 4 | `account.created` | account_created | ✅ + nota no ticket | ✅ | ✅ **principal** | | 5+ | infra, completed, company, webmail | … | ✅ | ✅ | ✅ | | 99 | `onboarding.failed` | failed | ✅ + ticket auto | ✅ auto | ✅ | **Regra PII:** técnico **não fica totalmente cego** — vê domínio e etapa cedo; dados sensíveis (e-mail conta, perfil empresa) **reforçados após `account.created`** no console de assistência. --- ## Quem inicia escalada | Origem | Actor | Acção | |--------|-------|-------| | Wizard VM112 | Cliente | Botão **«Preciso de ajuda técnica»** → webhook `onboarding.escalated` | | Desk VM122 | Técnico / ops_lead | **«Assumir sessão»** em sessão ≥ `domain.validated` | | Automático | Sistema | `onboarding.failed` · sessão stale 24h (já detectada) | | Automático | Sistema | Push Spec 007 — «funil travado» (fase posterior) | **Ambos** (cliente e técnico) podem iniciar. Primeiro a completar takeover **ganha** a sessão (lock optimista). --- ## Arquitetura ```mermaid flowchart TB subgraph VM112["VM112 — Wizard"] W[Wizard cliente] WA[Wizard ASM takeover] API112[Assist API] end subgraph VM122["VM122 — Desk"] DESK[Desk UI Console] API122[Assist orchestrator] DB[(SQLite tickets + assist_log)] end W -->|webhooks| API122 DESK -->|JWT| API122 API122 -->|service token| API112 API112 --> WA API112 -->|pause/resume| W DESK -->|links nova aba| EXT[Proxmox · Carbonio · Traefik · CF] API122 -->|acções API| API112 ``` **Princípio:** VM122 **nunca** embeda Proxmox/Carbonio. Links são referência; **botões de acção** chamam API (VM112 ou integrações futuras 005/006). --- ## Estados de ticket (novo) | Status | Significado | |--------|-------------| | `open` | Ticket criado, ninguém a assistir | | `escalated` | Cliente ou sistema pediu ajuda | | `assisting` | Técnico em ASM takeover activo | | `resolved` | Problema resolvido, aguarda fecho | | `closed` | Encerrado | Transições: ``` open → escalated → assisting → resolved → closed open → assisting (técnico puxa directo, se ≥ domain.validated) assisting → open (handoff cancelado — raro) qualquer → closed (ops_lead / super_admin) ``` --- ## Data model (VM122) ### `tickets` (alteração) | Campo | Tipo | Uso | |-------|------|-----| | `status` | TEXT | + `escalated`, `assisting`, `resolved` | | `session_id` | TEXT | FK lógica onboarding VM112 | | `assist_mode` | TEXT | `null` \| `asm` | | `assisted_by` | TEXT | username técnico em takeover | | `assisted_at` | TEXT | ISO timestamp | | `client_paused` | INTEGER | 1 se wizard pausado | ### `assist_sessions` (nova) ```sql CREATE TABLE assist_sessions ( id INTEGER PRIMARY KEY, session_id TEXT NOT NULL, ticket_id INTEGER, initiated_by TEXT NOT NULL, -- 'client' | 'technician' | 'system' initiated_by_user TEXT, -- desk username se técnico status TEXT NOT NULL, -- 'active' | 'handoff' | 'ended' funnel_stage TEXT, domain TEXT, takeover_token_hash TEXT, -- token VM112 (não plain text) started_at TEXT NOT NULL, ended_at TEXT, audit_summary TEXT ); ``` ### `assist_actions` (audit log) ```sql CREATE TABLE assist_actions ( id INTEGER PRIMARY KEY, assist_session_id INTEGER NOT NULL, actor TEXT NOT NULL, action TEXT NOT NULL, -- 'escalate' | 'takeover' | 'action.dns_retry' | 'handoff' payload TEXT, created_at TEXT NOT NULL ); ``` --- ## API VM122 (Desk — orchestrator) | Método | Endpoint | Auth | Descrição | |--------|----------|------|-----------| | GET | `/api/v1/assist/sessions` | JWT | Sessões activas + estado assistência | | GET | `/api/v1/assist/sessions/{session_id}` | JWT | Detalhe + timeline + ticket | | POST | `/api/v1/assist/sessions/{session_id}/escalate` | JWT | Técnico escala manualmente | | POST | `/api/v1/assist/sessions/{session_id}/takeover` | JWT | Inicia ASM — chama VM112 | | POST | `/api/v1/assist/sessions/{session_id}/handoff` | JWT | Devolve controlo ao cliente | | POST | `/api/v1/assist/sessions/{session_id}/actions/{action}` | JWT | Acção Desk (ver catálogo) | | GET | `/api/v1/assist/sessions/{session_id}/links` | JWT | Deep links externos (nova aba) | **Webhook ingress (VM112 → VM122):** | Evento | Efeito | |--------|--------| | `onboarding.escalated` | Ticket `escalated` + notificação | | `onboarding.assist.started` | Confirma takeover | | `onboarding.assist.ended` | Handoff confirmado | --- ## API VM112 (wizard — contrato `assist-v1`) *Implementação no repo VM112 (SUP-4). Desk consome.* | Método | Endpoint | Auth | Descrição | |--------|----------|------|-----------| | POST | `/api/onboarding/sessions/{id}/pause` | service + desk JWT | Pausa wizard cliente | | POST | `/api/onboarding/sessions/{id}/takeover` | desk JWT | Retorna URL wizard ASM + token | | POST | `/api/onboarding/sessions/{id}/resume` | desk JWT | Retoma cliente | | GET | `/api/onboarding/sessions/{id}/state` | service | Etapa, erros, campos permitidos | | POST | `/api/onboarding/sessions/{id}/actions/{action}` | desk JWT | Executa acção no passo actual | **Resposta takeover:** ```json { "takeover_url": "https://onboard.ligbox.com.br/assist/{session_id}?token=...", "expires_in": 3600, "client_paused": true } ``` --- ## Catálogo de acções (só Desk — MVP) Acções invocam VM112 ou integrações; **nunca** abrem shell Proxmox. | Acção | Etapa mínima | Efeito | |-------|--------------|--------| | `dns.revalidate` | dns_applied | Revalida DNS / Cloudflare via VM112 | | `dns.reapply` | dns_applied | Re-aplica registos | | `account.retry_sync` | account_created | Re-sync Carbonio | | `infra.resync` | infra_synced | Re-sync Proxmox/Traefik via VM112 | | `onboarding.mark_step_complete` | assisting | Avança passo (com confirmação) | | `onboarding.abort` | assisting | Encerra sessão com motivo (ops_lead+) | Links externos (GET `/links`) — **nova aba**, sem acção automática: | Sistema | URL template | |---------|--------------| | Proxmox | `https://proxmox.../?node=...` (contexto tenant) | | Carbonio | Admin domain | | Traefik | Dashboard route | | Cloudflare | Zone DNS | --- ## UI Desk — Console de assistência ### Dashboard / Funil - Sessões **clicáveis** (hoje read-only). - Badge: `observando` · `escalado` · `assistindo`. - Botão **«Assumir sessão»** se etapa ≥ `domain.validated` e não locked. ### Vista ticket / sessão | Bloco | Conteúdo | |-------|----------| | **Cabeçalho** | Domínio · etapa · `session_id` · assignee | | **Estado** | Observador / Escalado / Assistindo (ASM) | | **Timeline** | Webhooks existentes | | **Acções Desk** | Botões catálogo (disabled se não assisting) | | **Links** | Proxmox, Carbonio, Traefik, CF — `target=_blank` | | **Takeover** | «Assumir sessão» → abre wizard ASM nova aba | | **Handoff** | «Devolver ao cliente» | ### Permissões RBAC | Role | Escalar | Takeover | Acções | Handoff | Ver links | |------|---------|----------|--------|---------|-----------| | super_admin | ✅ | ✅ | ✅ todas | ✅ | ✅ | | ops_lead | ✅ | ✅ | ✅ todas | ✅ | ✅ | | technician | ✅ | ✅ | ✅ N1/N2 | ✅ própria sessão | ✅ | | noc | 👁️ | ❌ | ❌ | ❌ | 👁️ | --- ## Fluxo ASM (takeover) ```mermaid sequenceDiagram participant C as Cliente VM112 participant D as Desk VM122 participant W as Wizard VM112 participant T as Técnico alt Cliente pede ajuda C->>W: Clica ajuda técnica W->>D: webhook onboarding.escalated else Técnico puxa T->>D: POST takeover end D->>W: POST pause + takeover W-->>C: Wizard pausado W-->>D: takeover_url + token D-->>T: Console + link ASM T->>W: Actua no wizard ASM T->>D: Acções API (dns.reapply, etc.) T->>D: POST handoff D->>W: POST resume W-->>C: Retoma onboarding ``` --- ## User stories ### US1 — Cliente pede ajuda (P0) Como cliente no wizard, quero pedir ajuda técnica para destravar o onboarding. **Aceite:** botão no VM112 · sessão pausada · ticket escalado no Desk · push/e-mail ops (007). ### US2 — Técnico assume sessão (P0) Como técnico, quero assumir uma sessão após domínio validado e actuar no wizard em nome do cliente. **Aceite:** ASM takeover · cliente pausado · audit log · handoff funcional. ### US3 — Acções só no Desk (P0) Como técnico, quero revalidar DNS ou re-sync infra **pelo Desk**, sem aceder Proxmox directamente. **Aceite:** botões acção chamam API · links externos só referência nova aba. ### US4 — Observação pré-domínio (P1) Como ops, quero que etapas antes de domínio corram sem intervenção humana. **Aceite:** takeover disabled antes de `domain.validated`. ### US5 — Conflito de takeover (P1) Como ops_lead, quero que apenas um técnico assista por sessão. **Aceite:** segundo takeover recebe 409 + nome do assignee. --- ## Critérios de aceite MVP - [ ] Escalada cliente (VM112) + webhook `onboarding.escalated` - [ ] Escalada técnico no Desk (≥ `domain.validated`) - [ ] ASM takeover — técnico substitui cliente, cliente pausado - [ ] Handoff — cliente retoma - [ ] Estados ticket: escalated, assisting, resolved - [ ] Console Desk: timeline + acções + links nova aba - [ ] Catálogo acções MVP (dns.revalidate, account.retry_sync, infra.resync) - [ ] Audit log `assist_actions` - [ ] RBAC conforme tabela - [ ] pt-BR em toda UI/mensagens - [ ] **Sem** embed Proxmox/Carbonio - [ ] OTRS **fora** — Spec 011 --- ## Fora de escopo (010) - Co-browse / pointer mode (Roger escolheu ASM puro) - Embed de consoles externos - OTRS (→ Spec 011) - Kanban visual (→ Spec 008, após 010) - Acções directas Proxmox API no Desk (→ integrações 005/006 encapsuladas depois) --- ## Dependências e ordem | Spec | Relação | |------|---------| | **001** | Webhooks + funil + session_id | | **003** | RBAC + assigned_to | | **007** | Push «sessão escalada» (paralelo ok) | | **008** | Kanban usa estados 010 | | **011** | OTRS VM112 — futuro, não bloqueia 010 | **Prioridade backlog:** 010 **antes** de 005/006 para onboarding operacional. --- ## Referências - SAP Commerce **Assisted Service Mode (ASM)** — emulação sessão agente - Chatbase **Takeover** — escalada humano assume controlo - BACKLOG **DESK-3**, **SUP-4.1/4.2** - `specs/010-desk-assist-takeover/tasks.md` - `specs/010-desk-assist-takeover/quickstart.md` - `specs/011-integration-otrs/spec.md` (stub) --- ## Fases de entrega | Fase | Entrega | Onde | |------|---------|------| | **A** | Webhook escalada + estados ticket + UI «Assumir» (sem takeover ainda) | VM122 | | **B** | VM112 pause/takeover/resume + wizard ASM | VM112 | | **C** | Console acções Desk + audit | VM122 + VM112 | | **D** | Push escalada (007) + links contextuais | VM122 |