Captura Rapida multimodal, fluxo completo de incidentes e reorganizacao de integracoes - #11
Conversation
Fecha as 3 lacunas apontadas antes de divulgar o projeto: build/CI visivel via badge, smoke test do backend (boot, /health, login e rota protegida) rodando a cada push/PR, e traducao completa do README para ampliar a base de contribuidores.
App.jsx importava de "./pages/auth/..." (minusculo), mas o diretorio estava como "Auth" (maiusculo) no disco. Funcionava por acaso em sistemas de arquivos case-insensitive (macOS/Windows), mas quebrava o build/dev server em Linux com "Failed to resolve import". Renomeado para "auth", em linha com o padrao das demais pastas (kb, incidents, gps, postmortem, settings).
A sidebar mostrava "v2.0" como string fixa, dessincronizada do package.json (que estava em 1.0.0) — o badge de versao do README, que le o backend/package.json, mostrava um numero diferente do que aparecia na tela. Agora a versao e injetada em build time a partir do package.json do frontend (vite.config.js define __APP_VERSION__), e os dois package.json (backend e frontend) foram alinhados em 2.0.0, que e a versao real do estado atual do projeto.
A causa nao era de cor por tema, e sim de layout: com a sidebar colapsada (70px), o icone (40px) e o botao (28px) nao cabiam lado a lado no espaco disponivel, entao o botao vazava para fora da caixa escura da sidebar e caia sobre o fundo do conteudo principal. Em modo escuro esse fundo tambem e escuro (o vazamento passava despercebido); em modo claro o fundo e branco, escondendo o botao translucido. Corrigido empilhando icone e botao em coluna quando colapsado, para que os dois caibam dentro da largura reduzida da sidebar.
A acao ja existia escondida no dropdown mobile, mas nao tinha atalho visivel no desktop -- ficava a dois cliques (abrir menu do usuario ou navegar pela sidebar) para uma funcionalidade central do produto (capturar incidente durante a emergencia). Agora aparece ao lado do "Novo KB" no header, com estilo outline para nao competir com a acao primaria.
… de tags/categorias A Captura Rapida so aceitava texto. Agora tambem aceita: - Ditado por voz (Web Speech API do navegador) para os campos de problema e solucao, com preview do trecho ainda nao finalizado. - Colar/anexar uma ou mais capturas de tela do erro (clique, arrastar ou Ctrl+V), com descricao automatica via IA (visao, gpt-4o-mini) que o usuario pode editar. - Colar logs/stack traces num campo dedicado. O backend usa esses dados para gerar um KB mais assertivo: logs e descricoes de imagem entram no prompt da IA, e uma secao de Evidencias e anexada automaticamente ao artigo com os links reais das imagens (nao dependendo da IA reproduzir URLs). Tambem: TagSelector e CategorySelector (usados na Captura Rapida, em KBCreate e em KBEdit) agora permitem criar uma tag ou categoria nova direto no seletor quando ela ainda nao existe, em vez de precisar sair do fluxo para cadastrar em Configuracoes. Novos endpoints: POST /api/ai/describe-image (legenda de screenshot via visao). Quick-capture agora aceita logs e images no corpo.
… paginas reais As paginas de Incidentes e Eventos eram stubs (botao "New Incident" nao fazia nada, listas sempre vazias), e o endpoint de conversao de evento em incidente tinha um bug real: referenciava uma variavel `objectId` nunca definida, quebrando com erro toda chamada. Reescrito seguindo o modelo de lifecycle mais comum em ferramentas de on-call (PagerDuty/Opsgenie): - Ingestao de eventos (Zabbix, Grafana, Datadog, Sentry, etc.) via POST /api/events/ingest, agora com gestao de tokens de verdade: criar/listar/revogar por fonte, cada um com um piso de severidade opcional para abrir incidente automaticamente (opt-in, evita fadiga de alerta abrindo incidente para todo ruido). O valor do token so e mostrado uma vez na criacao. - Maquina de estados do incidente: aberto -> reconhecido (pausa a notificacao enquanto alguem trabalha nele) -> resolvido, com timestamps e validacao de transicao (PATCH /:id/status). - Ao resolver, sugere (sem forcar) criar KB e, se a severidade justificar, criar post-mortem - ambos pre-preenchidos a partir do incidente e linkados de volta a ele. - IncidentList/IncidentView/EventList reescritas do zero: listagem real, criacao, timeline, notas, e o painel de fontes de eventos. Corrigido de quebra: <ToastContainer /> nunca estava montado - os 9 arquivos que chamam toast.success()/error() nao mostravam nada ao usuario. Endpoint de ingestao tambem nao tratava tenant sem assinatura ativa (comum em instancias self-hosted sem billing) - quebrava com TypeError em vez de simplesmente nao aplicar limite.
Cobre os tres estados do lifecycle de incidente (aberto, reconhecido, resolvido), um incidente aberto automaticamente a partir de um evento critico (simulando o /api/events/ingest de verdade), um incidente resolvido com KB vinculado (simulando o resultado da Captura Rapida disparada a partir dele), e 3 eventos ainda nao convertidos para testar o botao "Converter em incidente" na tela de Eventos. Reestruturado para checar cada colecao (records/incidents) de forma independente, em vez de um unico early-return que pulava tudo se o tenant ja tivesse KBs - agora da pra rodar de novo so pra popular incidentes numa instancia que ja tem KBs seedadas. Documentado no README (PT/EN), que nunca mencionava esse script.
…rada/Saida A gestao de tokens de ingestao (Zabbix/Grafana/Datadog/Sentry) estava na tela de Eventos, meio deslocada do resto da configuracao de integracoes. Movida para Integracoes, que agora tem duas abas: - Entrada: fontes que enviam dados PARA DENTRO da plataforma (o que antes era "Fontes de Eventos" em Eventos). - Saida: para onde a plataforma envia notificacoes (Slack, Teams, Email, Jira, PagerDuty - o que ja existia na aba unica anterior). Eventos agora so lista os eventos recebidos, com um link para Integracoes -> Entrada para configurar fontes. Tambem adicionado exemplo de `curl` pronto para copiar (com token e URL reais apos criar o token, e um exemplo generico com placeholder na descricao da secao) - antes so tinha o JSON do payload, sem o comando completo para testar via terminal ou colar na config de webhook da ferramenta de origem.
…/Datadog
A aba Entrada tinha um card unico e generico de "Fontes de Eventos",
destoando do catalogo em cards (icone, cor, descricao, lista de
recursos, badge de status) usado na aba Saida. Reescrita para o mesmo
padrao: um card por fonte (Zabbix, Grafana, Datadog, Sentry,
PagerDuty, Customizado), badge com a contagem de tokens ativos, e os
tokens daquela fonte listados dentro do proprio card.
PagerDuty e Datadog saem da lista de integracoes de Saida e entram
como fontes em Entrada - la, o "sendNotification" so tinha
implementacao real para Slack/Teams; PagerDuty e Datadog so validavam
credenciais (test connection) sem nenhum envio de fato, e a descricao
de ambos ja era essencialmente de ingestao de alerta/monitoramento
("Criar incidentes automaticamente", "Alertas baseados em dados"),
que e exatamente o papel de Entrada.
Minor version para a leva de mudancas desta sessao: Captura Rapida multimodal (voz, logs, imagens), fluxo completo de incidentes (ingestao automatica, lifecycle, paginas reais), integracoes reorganizadas em Entrada/Saida, CI/smoke test, README em ingles e correcoes de bugs (case-sensitivity no build, versao dessincronizada na UI, botao sumindo em modo claro, conversao de evento quebrada).
There was a problem hiding this comment.
🟡 Not ready to approve
Há pelo menos um problema de segurança confirmado (URLs de imagens não validadas sendo persistidas/embutidas no Markdown) e alguns ajustes necessários para evitar falhas/leaks em runtime.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Pull request overview
Atualiza a plataforma para suportar captura rápida multimodal (voz + logs + imagens), completar o fluxo de incidentes (status + conversão de eventos + sugestões pós-resolução) e reorganizar integrações em Entrada/Saída, além de adicionar CI com smoke test.
Changes:
- Expande a Captura Rápida para incluir ditado por voz, anexos de imagem com legenda automática e campo de logs, vinculando KBs a incidentes.
- Implementa fluxo funcional de Incidentes/Eventos (listas, visualização, conversão e máquina de estados com transições validadas).
- Adiciona CI com smoke test do backend e build do frontend; inclui README em inglês e ajustes de UI (ToastContainer, versão dinâmica, sidebar).
File summaries
| File | Description |
|---|---|
| README.md | Link para versão em inglês + badge de CI + scripts de seed/smoke test documentados. |
| README.en.md | Novo README em inglês com onboarding, configuração e scripts. |
| frontend/vite.config.js | Injeta __APP_VERSION__ via package.json no build. |
| frontend/src/services/api.js | Expande APIs de incidentes/eventos e adiciona ai.describeImage. |
| frontend/src/pages/postmortem/PostMortemList.jsx | Prefill via navigation state e auto-abertura do modal de criação. |
| frontend/src/pages/kb/QuickCapture.jsx | Quick Capture multimodal (voz/logs/imagens) + selectors reutilizáveis + vínculo a incidente. |
| frontend/src/pages/Integrations.jsx | Reorganiza UI em abas Entrada/Saída e inclui InboundEventSources. |
| frontend/src/pages/incidents/IncidentView.jsx | Tela de incidente completa (timeline, notas, transições de status, sugestões KB/postmortem). |
| frontend/src/pages/incidents/IncidentList.jsx | Lista funcional com filtro por status e modal de criação. |
| frontend/src/pages/events/EventList.jsx | Lista funcional de eventos + conversão para incidente e link para integrações de entrada. |
| frontend/src/pages/auth/Register.jsx | Nova tela de registro. |
| frontend/src/pages/auth/MagicLink.jsx | Nova tela de verificação de magic link. |
| frontend/src/pages/auth/Login.jsx | Nova tela de login com opção de magic link. |
| frontend/src/components/VoiceRecorderButton.jsx | Botão de ditado por voz via Web Speech API. |
| frontend/src/components/tags/TagSelector.jsx | Quick-create de tags/categorias no seletor. |
| frontend/src/components/Sidebar.jsx | Exibe versão via __APP_VERSION__. |
| frontend/src/components/Sidebar.css | Corrige layout do botão de colapsar em modo colapsado/tema claro. |
| frontend/src/components/Layout.jsx | Adiciona botão de acesso rápido à Captura Rápida no header. |
| frontend/src/components/integrations/InboundEventSources.jsx | Novo catálogo/gerenciamento de tokens para ingestão de eventos (Entrada). |
| frontend/src/components/ImageAttachments.jsx | Novo componente de anexos de imagem com upload + legenda via IA. |
| frontend/src/App.jsx | Monta ToastContainer globalmente. |
| frontend/package.json | Atualiza versão do frontend para 2.1.0. |
| CONTRIBUTING.md | Passo de smoke test (npm test) no backend antes de abrir PR. |
| backend/src/seeds/index.js | Seed atualiza token de ingestão para novo schema (label/source/...). |
| backend/src/modules/integrations/integrations.routes.js | Remove PagerDuty/Datadog da lista de “saída” (agora são “entrada”). |
| backend/src/modules/incidents/incidents.routes.js | Quick Capture passa a aceitar logs/imagens e adiciona status lifecycle + endpoint de transição. |
| backend/src/modules/events/events.routes.js | Ingestão por token + tokens CRUD + auto-abertura de incidente por threshold + conversão robusta. |
| backend/src/modules/ai/ai.routes.js | Adiciona endpoint de visão para descrever imagens (/ai/describe-image). |
| backend/scripts/smoke-test.js | Novo smoke test de boot/health/auth/rota protegida. |
| backend/scripts/seed-sample-data.js | Seed adicional agora inclui incidentes/eventos de exemplo cobrindo o lifecycle. |
| backend/package.json | Atualiza versão do backend para 2.1.0 e adiciona npm test/smoke-test. |
| backend/.env.example | Adiciona BACKEND_PUBLIC_URL para URLs públicas (uploads/ingest). |
| .github/workflows/ci.yml | Novo CI: backend (mongo+migrate+seed+smoke) e frontend (build). |
Review details
Suppressed comments (1)
frontend/src/components/ImageAttachments.jsx:111
- Ao remover uma imagem, o blob URL (preview) não é revogado. Isso mantém o objeto em memória mesmo após remoção do item.
const handleRemove = (localId) => {
setImages(prev => {
const img = prev.find(i => i.localId === localId);
if (img?.fileId) fileAPI.delete(img.fileId).catch(() => {});
return prev.filter(i => i.localId !== localId);
- Files reviewed: 30/33 changed files
- Comments generated: 6
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
| const cleanImages = Array.isArray(images) | ||
| ? images.filter(img => img && typeof img.url === 'string').slice(0, 10) | ||
| : []; |
| affected_services: affected_services || '', | ||
| logs: cleanLogs || undefined, | ||
| images: cleanImages.length ? cleanImages : undefined |
| try { | ||
| const { data } = await fileAPI.upload(file); | ||
| updateImage(entry.localId, { | ||
| fileId: data.fileId, | ||
| url: data.url, | ||
| uploading: false, | ||
| describing: true | ||
| }); |
| <td className="text-muted small"> | ||
| {formatDistanceToNow(new Date(ev.created_at), { addSuffix: true, locale: ptBR })} | ||
| </td> |
| <p className="text-muted small"> | ||
| Incidentes também podem ser abertos automaticamente a partir de eventos monitorados. | ||
| Veja <a href="/events">Eventos</a> para configurar as fontes. | ||
| </p> |
| import { formatDistanceToNow } from 'date-fns'; | ||
| import { ptBR } from 'date-fns/locale'; |
Adiciona um job rapido que falha o CI se backend/package.json e frontend/package.json estiverem com versoes diferentes - pega o esquecimento antes do merge, nao so na hora de tagear a release.
Espelha o que foi adicionado ao README.md (PT) no PR de automacao de release: badge de "release" e a secao explicando o fluxo de tag/release automatico.
Resumo
Captura Rápida multimodal
Fluxo completo de incidentes
POST /events/:id/convert-to-incidentquebrava comReferenceError(variável nunca definida)PATCH /incidents/:id/status)Integrações reorganizadas em Entrada/Saída
curlpronto para copiar, com token e URL reais após criar o tokenCorreções e infraestrutura
/health, login, rota protegida)README.en.md)<ToastContainer />nunca estava montado — 9 arquivos chamandotoast.*()não mostravam nada ao usuáriopages/authvspages/Auth) que quebrava o build em Linuxpackage.jsonbackend/scripts/seed-sample-data.jsagora também popula incidentes/eventos de exemploVersão:
2.0.0→2.1.0(backend e frontend).Test plan
cd backend && npm install && npm run migrate && npm run seed && npm testcd frontend && npm install && npm run buildnode backend/scripts/seed-sample-data.jse conferir os incidentes/eventos de exemplo em/incidentse/eventscurlde exemplo para/api/events/ingest