feat(tickets): preserve requester/assignee/company snapshots + timeline fallbacks; chore: add requester index\n\n- Add requesterSnapshot, assigneeSnapshot, companySnapshot to tickets\n- Use snapshots as fallback in list/get/play\n- Update snapshots on assignee changes/startWork\n- Preserve snapshots before deleting users/companies\n- Add index tickets.by_tenant_requester\n- Add migrations.backfillTicketSnapshots\n\nchore(convex): upgrade to ^1.28.0 and run codegen\nchore(next): upgrade Next.js to 15.5.6 and update React/eslint-config-next\nfix: remove any and lint warnings; tighten types across API routes and components\ndocs: add docs/ticket-snapshots.md

This commit is contained in:
Esdras Renan 2025-10-20 10:13:37 -03:00
parent 0d82162a0e
commit 216feca971
16 changed files with 884 additions and 552 deletions

View file

@ -0,0 +1,71 @@
# Desktop (Tauri) — Handshake, Sessão de Máquina e Antivírus
Este documento consolida as orientações e diagnósticos sobre o fluxo do agente desktop, handshake na web e possíveis interferências de antivírus.
## Sintomas observados
- Ao clicar em “Registrar máquina”, o antivírus aciona (ex.: ATC.SuspiciousBehavior) e o processo é interrompido.
- Após o registro, ao abrir a UI web: cabeçalho mostra “Cliente / Sem email definido” e o Portal não permite abrir chamados.
- No passado, mesmo quando o app “entrava direto”, o Portal não refletia o colaborador/gestor vinculado (sem assignedUser); receio de repetir o problema.
## Causas prováveis
1) O antivírus interrompe o processo durante o handshake
- O app salva token/config, inicia heartbeat e abre `GET /machines/handshake?token=...&redirect=...` para gravar cookies de sessão.
- Se o processo cai neste momento, os cookies não são gravados e a UI fica sem sessão “machine”.
2) Endpoint de contexto sem ler a sessão adequadamente
- O Portal preenche o colaborador/gestor via `GET /api/machines/session`.
- Em alguns ambientes, é mais estável rodar esse endpoint no runtime `nodejs` para ler `cookies()` do Next sem inconsistências.
## O que já foi aplicado no projeto
- Middleware permite `GET /machines/handshake` sem exigir login (rota pública).
- Frontend preenche `machineContext` chamando `GET /api/machines/session` (assignedUserId/email/nome/persona) e usa esse ID ao abrir chamados.
- UI oculta “Sair” quando a sessão é de máquina (portal e shell interno).
- DevTools habilitado no desktop (F12, Ctrl+Shift+I ou botão direito com Ctrl/Shift).
- Desktop salva dados em `C:\\Raven\\data\\machine-agent.json` (ou equivalente ao lado do executável), com fallback para AppData se a pasta do app não permitir escrita.
## Validação rápida (após “Registrar máquina”)
1) No executável, com DevTools:
```js
fetch('/api/machines/session').then(r => r.status).then(console.log)
// Esperado: 200
fetch('/api/machines/session').then(r => r.json()).then(console.log)
// Deve conter: persona (collaborator|manager), assignedUserEmail/nome/Id
```
2) Na UI (Portal/Topo):
- Mostrar nome/email do colaborador/gestor (não “Cliente / Sem email definido”).
- Sem botão “Sair” (sessão de máquina).
3) No Portal, o formulário “Abrir chamado” deve habilitar normalmente (usa `machineContext.assignedUserId`).
Se `GET /api/machines/session` retornar 403:
- Verificar se o antivírus barrou o processo na hora do handshake.
- Adicionar exceção para `C:\\Raven\\appsdesktop.exe` e `C:\\Raven\\data\\`.
- Opcional: forçar `export const runtime = 'nodejs'` no endpoint de sessão para leitura consistente de cookies (Next `cookies()`).
## Fluxo atual do desktop
- Antes de registrar: tela de onboarding (sem “Abrir sistema”).
- Após registrar: salva token/config, inicia heartbeat e mostra as abas com “Abrir sistema” e “Reprovisionar”.
- Autoabrir: o app já tenta abrir o sistema quando detecta token; pode ser reforçado chamando `openSystem()` ao fim do `register()`.
## Melhorias opcionais
- Autoabrir imediatamente após `register()` (reforça o comportamento atual e reduz a janela para interferência do AV).
- Diagnóstico no desktop: exibir caminho completo do arquivo de dados e botão “Abrir pasta de dados”.
- Forçar `nodejs` no `GET /api/machines/session` para estabilidade total na leitura de cookies.
## Notas sobre antivírus
- Apps Tauri não assinados com certificado de code signing do Windows são frequentemente marcados como “desconhecidos”.
- A assinatura Minisign (updater) não substitui o code signing do executável.
- Recomendações:
- Adicionar exceções para o executável e a pasta de dados.
- Avaliar aquisição de um certificado de code signing (EV/OV) para distribuição ampla sem alertas.
## Checklist quando “não mudou nada” após registro
- Confirmar `GET /api/machines/session` (status 200 + JSON contendo assignedUser). Caso 403, tratar AV/endpoint runtime.
- Verificar cookies no navegador (DevTools → Application → Cookies): presença da sessão e `machine_ctx`.
- Validar que o Portal mostra o colaborador/gestor e permite abrir chamado.
- Conferir arquivo de dados:
- Preferencial: `C:\\Raven\\data\\machine-agent.json`.
- Fallback: AppData local do usuário (buscar por `machine-agent.json`).
---
Última atualização: automatização do handshake no middleware, ocultação de “Sair” em sessão de máquina, dados persistidos junto ao executável e DevTools habilitado.

33
docs/ticket-snapshots.md Normal file
View file

@ -0,0 +1,33 @@
Ticket snapshots e histórico
Este projeto agora preserva o “lastro” de dados sensíveis em tickets através de snapshots gravados no momento da criação e atualizações chave:
- requesterSnapshot: nome, email, avatar e equipes do solicitante no momento da abertura.
- assigneeSnapshot: nome, email, avatar e equipes do responsável atribuído.
- companySnapshot: nome, slug e flag isAvulso da empresa associada ao ticket.
Benefícios
- Tickets continuam exibindo nome do solicitante/empresa mesmo após exclusões ou renomeações.
- Comentários já utilizavam authorSnapshot; a lógica foi mantida e ampliada para tickets.
Fluxos atualizados
- Criação de ticket: snapshots do solicitante, responsável inicial (se houver) e da empresa são persistidos.
- Reatribuição e início de atendimento: atualizam o assigneeSnapshot.
- Exclusão de usuário: preenche requesterSnapshot de todos os tickets onde a pessoa é solicitante, antes da remoção.
- Exclusão de empresa: preenche companySnapshot de tickets vinculados, antes da remoção.
Consultas e hidratação
- Resolvers de lista e detalhes de tickets passaram a usar os snapshots como fallback quando o documento relacionado não existe mais (sem “Solicitante não encontrado”, salvo ausência total de dados).
Índices novos
- tickets.by_tenant_requester: otimiza buscas por histórico de um solicitante.
Backfill
- Há uma mutation de migração para preenchimento retroativo de snapshots: convex.migrations.backfillTicketSnapshots.
- Execute com um tenant por vez (e opcionalmente um limite) se necessário.