# Changelog — Não Conformidades > Histórico específico desta aplicação, extraído de `plano.md`. > > **Formato**: uma entrada por rodada, `### Rodada N — Título`; quando a rodada não tem número registrado, `### Título` só. **A numeração de rodada não é global** — cada aplicação conta as próprias, e o mesmo número designa trabalhos diferentes em arquivos diferentes. Ao citar uma rodada, sempre nomear o arquivo. Ver o topo de `plano.md`. ### Rodada 88 — Não Conformidades (Relatórios > Qualidade) Pedido: a área de Qualidade tinha uma skill do Claude (`analise-ncs`, ver `projects/Controladoria - Analise NCs/`) que gerava, sob demanda, um Excel de 7 abas a partir de dois arquivos exportados do Sigsistem (ocorrências .xlsx + ações .xls, esse último na verdade HTML). O usuário pediu uma aplicação dentro do Portal que evoluísse essa skill pra uma gestão **contínua**: identificar com facilidade novas ocorrências sem análise (cobrança), análises novas sem ação aberta, acompanhamentos de ação recentes ainda sem tratativa da Qualidade, e priorizar ações vencidas/vencendo em 7 dias — com a possibilidade de marcar manualmente o que já foi tratado, e um dashboard quantitativo (ações abertas, motivos de abertura, clientes/colaboradores com maior incidência). Decisões de negócio confirmadas com o usuário antes de implementar: - O status de "tratado" pela Qualidade é um controle **interno do Portal**, sem escrita de volta no Sigsistem (sistema externo, sem integração) — mas precisa **reabrir sozinho** quando uma importação nova trouxer algo diferente do que existia no momento em que foi tratado (ex.: novo acompanhamento numa ação já marcada tratada). - Guardar o **histórico completo** de acompanhamentos de cada ação, não só o último (diferente da skill original). - "Colaborador com maior incidência" no dashboard = coluna `Indicado para Descrever Análise da Ocorrência`; "motivo de abertura" = `Tipo(s) de Causa(s) da Ocorrência` (não `Tipo de Ocorrência`). - Permissão de toggle único (mesmo padrão de Indicador de Desempenho/Importação de Plano de Saúde), **restrita por padrão** — só "Integração e Inovação" nasce com acesso, diferente de "Relatório Setorial" (que herda automático via `SECTORAL_KEYS`). O que foi construído: pacote Python puro `portal_api/nao_conformidades/` (parsing sem pandas, mesmo padrão de `planos_saude`/`indicadores` — validado que o volume real, ~236 ocorrências/290 ações/929 acompanhamentos, não justifica introduzir pandas como dependência direta), portando a lógica de referência do script `gerar_relatorio.py` da skill (inclusive o parsing por regex do `.xls`-que-é-HTML, com uma diferença: aqui se guarda TODAS as entradas de acompanhamento, não só a última). 4 models novos (`NaoConformidadeImportacao`, `NCOcorrencia`, `NCAcao`, `NCAcompanhamento`, migrações `0052`/`0053`), 3 `ModelViewSet` + 1 function view de dashboard, subgrupo `qualidade` novo em `catalogo.MODULE_APPS["relatorios"]` (mesmo formato de subgrupo-com-uma-tool já usado em Auditorias), override em `seed_portal.py` pra restringir o acesso por padrão, e uma tela nova com 3 abas (Gestão/Dashboard/Importar). **Núcleo técnico — reabertura automática por diff** (`nao_conformidades/diff.py`): cada `NCOcorrencia`/`NCAcao` guarda um `snapshot_tratativa` (congelado no momento em que a Qualidade marca como tratada); a cada importação nova, se o item já estava tratado, o snapshot congelado é comparado contra o estado recém-extraído — ação reabre por comparação de **data** do último acompanhamento (robusto contra reformatação cosmética do export); ocorrência reabre por hash de texto da análise (normalizado) ou por uma ação nova ter sido aberta. Validado contra a amostra real (`projects/Controladoria - Analise NCs/ocorrencias_pa_27082026.xlsx`/`acoes_27082026.xls`) via chamada direta da função de diff simulando um acompanhamento mais recente — reproduziu o motivo textual esperado. **Validação end-to-end com dados reais**: subiu o servidor local, logou como `gabriel`, fez upload dos dois arquivos de amostra pela API — os totais bateram com o relatório de referência da skill (`Relatorio_Qualidade_20260827.xlsx`) em todos os indicadores (236 ocorrências, 13 sem análise, 8 análise sem ação, 38 NCs sem ação corretiva, 2 ações vencidas, 130 vencendo em ≤7 dias), **exceto** "Total de Ações Abertas" (290 aqui vs. 311 na skill) — a skill original contava também linhas de ocorrência sem nenhuma ação de fato aberta (artefato do script de referência, `todas = v.copy()` sem filtrar por `Código da Ação` presente); esta ferramenta conta só ações reais, decisão deliberada de manter (documentada em `CLAUDE.md`). Reimportar o mesmo arquivo é idempotente (0 novos, tudo "atualizado", 0 acompanhamentos duplicados via hash). Endpoints de marcar-tratado/reabrir (ocorrência e ação) testados via API. Dois bugs de robustez corrigidos durante a validação com dados reais: (1) `assunto` estourava `CharField(max_length=255)` — um export real trouxe um valor com 395 caracteres (texto livre do Sigsistem, sem limite aparente); virou `TextField`, migração `0053`. (2) o serializer de ocorrência tentava ler `obj.sem_analise` (propriedade que só existe no dataclass `OcorrenciaExtraida`, não no model Django `NCOcorrencia`) — corrigido pra computar `not obj.descricao_analise.strip()` direto no `SerializerMethodField`. **Não testado nesta rodada**: a interação real em navegador (não havia ferramenta de automação de browser disponível ainda neste ambiente) — a tela foi construída seguindo rigorosamente os padrões visuais/estruturais já validados de `importacao-plano-saude.html`/`indicador-desempenho.html`, o parsing/pipeline/API foram validados de ponta a ponta com dados reais via chamadas HTTP diretas, e o HTML renderizado pelo Django foi conferido — mas o fluxo de clique/preenchimento na tela em si ainda precisava de uma primeira conferência visual. Resolvido na rodada seguinte (ver abaixo). ### Rodada 89 — Redesign de Dashboard e Gestão, a partir de teste real na tela Depois de testar a tela construída na rodada 88, o usuário deu uma lista concreta de feedback de UX/design. Mudanças: **Dashboard**: - Vira a aba padrão ao abrir a tela (era Gestão) — dá o resumo geral primeiro. - Cards ("Ações vencidas", "Vence em ≤7 dias", "Ocorrências sem análise", "Análises sem ação") viram clicáveis: levam pra Gestão já com o filtro/seção correspondente aplicado (drill-down). "Ocorrências abertas"/"Ações abertas" (totais) e "NCs sem ação corretiva" continuam só informativos — decisão do usuário, sem lista equivalente pra este último. - Linhas dos 3 rankings (Motivos/Clientes/Colaboradores) também ficam clicáveis: preenchem a busca da Gestão (ver abaixo) com aquele valor. - Rankings de Clientes/Colaboradores passam a mostrar 3 contagens (NC vermelho, Reclamação de Cliente dourado, Outros neutro) + um total, em vez de um número só — decisão explícita do usuário depois de perguntado se devia restringir o filtro a NC/Reclamação (como "Clientes" já fazia) ou mostrar tudo com clareza visual: "pode trazer tudo nos dois casos... tratar com cores o tipo de ocorrência e depois um totalizador". Um botão `?`/tooltip + legenda (3 bolinhas coloridas) explicam o critério. Endpoint `/dashboard/` mudou o formato de `clientes_maior_incidencia`/`colaboradores_maior_incidencia` de `{..., quantidade}` pra `{..., nc, reclamacao, outros, total}` (`Count` condicional por tipo na mesma `.values().annotate()`); o filtro `tipo_ocorrencia__in=TIPOS_NC` que só "Clientes" tinha antes foi removido (os dois rankings agora agrupam todos os tipos). - Dois KPIs de tempo médio novos, não interativos, sobre todo o histórico (sem filtro de período): "Preenchimento da análise" (`Avg(data_analise - data_emissao)` em `NCOcorrencia`) e "Abertura da ação" (`Avg(acao.data_emissao - ocorrencia.data_analise)` em `NCAcao`), via `ExpressionWrapper`+`DurationField`+`Avg`. Validado contra a amostra real: ~2,7 e ~18,7 dias. **Sem um terceiro KPI de "tempo médio de resolução"** — checado antes de implementar: `Data de Finalização`/`Dias para Finalização` estão 100% em branco no export real (confirma o que já estava documentado — todas as ações exportadas estão em aberto), e o usuário confirmou explicitamente pra não criar um card pra um dado que não existe ("pode não fazer o card, pois não temos esta informação"). - Seletor de período virou uma fileira de chips (`.ncf-chip`/`.ncf-chip-row`, mesmo padrão visual de `.ind-departamento-chip` de `indicador-desempenho.css`, duplicado aqui porque essa folha não é carregada nesta página) — antes era um `