mirror of
https://github.com/melgarafael/DeskcommCRM.git
synced 2026-10-02 01:28:34 +08:00
Issue #752: o handler apagava `messages` e `conversations` e só então tentava `contacts`. Contato com registro em `calendar_appointments` (`on delete restrict`, migração 0177) nunca sai — e a tentativa levava o histórico junto: `DELETE messages 204`, `DELETE conversations 204`, `DELETE contacts 403`. No caso relatado, 90 mensagens destruídas para devolver "Erro interno" com a ficha de pé. E nada em `api_audit_log`: a linha do sucesso só era escrita no fim, e quem consultasse a auditoria concluía que nada havia sido apagado. A lista de vínculos `RESTRICT` que este handler NÃO apaga de propósito (`VINCULOS_RESTRICT_NAO_APAGADOS`) passa a ser conferida ANTES do primeiro DELETE: conta `calendar_appointments` do contato (e da organização) e, havendo vínculo, devolve o mesmo 409 do caminho de FK — com o histórico intacto. Quem recusa continua sendo o banco, com o 23503 do `restrict`; a contagem existe só para saber disso antes de apagar. Falha da própria contagem não autoriza seguir: vira 500, que é reversível — mensagem apagada não volta. O ramo de falha passa a ser auditado: `contact.delete_blocked` com `metadata.motivo` (`vinculo_restrict` | `falha_ao_apagar`) e `metadata.apagados`, a lista do que já saiu quando parou. `contact.deleted` segue sendo a linha do sucesso; as duas juntas separam "ninguém excluiu" de "tentei, um vínculo barrou e a ficha ficou". Não vira RPC transacional (sugestão 1 da issue) de propósito: a de menor alcance que resolve a perda de histórico é a 2+3 — checar antes de apagar e auditar o desfecho — e é a que este commit faz. Falha no meio dos DELETEs pode deixar estado parcial; agora ele sai auditado, com o que já tinha saído. Catraca: tests/unit/contato-delete.test.ts. O caso do compromisso na agenda exige `chamadas` VAZIO (nada apagado antes do 409) e auditoria `contact.delete_blocked` com `apagados: []`; o caso do 23503 na ficha exige a auditoria do parcial com `apagados: ["messages","conversations"]`. Vermelho na base, verde com o fix. Fragmento: .changes/excluir-contato-nao-destroi-historico.md (nada_mudou). O `ctx` do teste é tipado como `HandlerCtx` (lib/api/handlers/types.ts), no estilo dos vizinhos: sob `tsc --noEmit` estrito o `Actor` é união discriminada e o retorno inline não atribuía. O `test:unit` passava assim mesmo — o vitest transpila sem checar tipos; quem pega é o gate `typecheck`.