- packages/database: Campaign, LeadImport, Lead, DialAttempt,
CallDisposition, Callback, SuppressionEntry (agente.md secao 53)
- packages/shared: normalizePhone (BR, E.164) com 7 testes unitarios
- apps/api/src/campaigns: CRUD completo (todos os campos da secao 24) com
maquina de estados validada (DRAFT/READY/RUNNING/PAUSED/DRAINING/
STOPPED/COMPLETED) — edicao bloqueada com campanha RUNNING
- apps/api/src/leads: import CSV via streaming multipart (deteccao
automatica de delimitador, mapeamento de coluna por header, validacao+
normalizacao+dedupe em lotes de 500, CSV de rejeitados com motivo, modo
dryRun para preview)
- apps/api/src/suppression: CRUD + import CSV da lista de bloqueio,
remocao sempre exige motivo e e auditada, isSuppressed() pronto para o
dialer-worker checar antes de originar
- apps/api/src/dispositions: CRUD de disposicoes de chamada
Testado ponta a ponta: campanha criada com defaults corretos, import de
CSV real (3 validos/1 invalido/1 duplicado, contadores batendo), leads
persistidos com telefone normalizado, transicoes de estado da campanha
rejeitando movimentos invalidos (PAUSED->PAUSED = 400).