← story.propek
STORY 9.7
Kommo Sync Periodico
Epic: Epic 9 — CRM Database Foundation
DONE
ACCEPTANCE CRITERIA (46/46)
AC1.1: Script em `apps/crm/scripts/kommo-sync.js` executavel via `node apps/crm/scripts/kommo-sync.js`
AC1.2: Le token e URL do Kommo de variaveis de ambiente (`KOMMO_ACCESS_TOKEN`, `KOMMO_BASE_URL`)
AC1.3: Le connection string do banco de variaveis de ambiente
AC1.4: Aceita flags CLI: `--dry-run`, `--verbose`, `--contacts-only`, `--leads-only`, `--force-full`
AC1.5: Mostra help com `--help`
AC1.6: Verifica conexao com API Kommo e banco antes de iniciar sync
AC2.1: Le `last_sync_at` de `crm_sync_state` (sync_type = 'kommo_contacts')
AC2.2: Puxa contatos de `GET /api/v4/contacts?filter[updated_at][from]={unix_ts}&limit=250&with=leads,companies` com paginacao
AC2.3: Respeita rate limit de 7 req/s (minimo 200ms entre requests)
AC2.4: Retry automatico com backoff exponencial (3 tentativas) em caso de erro 429/5xx
AC2.5: Para contatos novos (phone_number nao existe): INSERT no banco
AC2.6: Para contatos existentes: UPDATE campos vazios, NAO sobrescrever preenchidos
AC2.7: Respeita flag `manually_edited` no metadata — se true, NAO atualizar campos editados manualmente
AC2.8: Atualiza `last_sync_at` em `crm_sync_state` ao concluir com sucesso
AC3.1: Le `last_sync_at` de `crm_sync_state` (sync_type = 'kommo_leads')
AC3.2: Puxa leads de `GET /api/v4/leads?filter[updated_at][from]={unix_ts}&limit=250&with=contacts` com paginacao
AC3.3: Para leads novos: INSERT em `deals` + entry em `deal_stage_log`
AC3.4: Para leads existentes (match por `metadata->>'kommo_lead_id'`): UPDATE current_stage, estimated_value, closed_at, close_reason, updated_at
AC3.5: Respeita flag `manually_edited` no metadata do deal — se true, NAO atualizar
AC3.6: Linka novos deals ao customer_id correto via cache de contatos (mesmo padrao da Story 9.5)
AC3.7: Leads sem contato associado: registrar no log de erros, NAO importar
AC3.8: Quando stage muda (deal existente com stage diferente): criar nova entry em `deal_stage_log`
AC3.9: Atualiza `last_sync_at` em `crm_sync_state` ao concluir com sucesso
AC4.1: Mesmo mapeamento de contatos da Story 9.4 (nome, telefone, email, empresa, CNPJ, CPF, tipo)
AC4.2: Mesmo mapeamento de leads da Story 9.5 (stages, pipeline, valor, dates)
AC4.3: Reutiliza funcoes de normalizacao (telefone, CNPJ, CPF) dos scripts existentes
AC5.1: Com `--dry-run`, script NAO escreve no banco
AC5.2: Dry-run mostra: contatos novos/atualizados, leads novos/atualizados, erros
AC5.3: Dry-run gera relatorio em `apps/crm/data/kommo-sync-dryrun-{timestamp}.md`
AC6.1: Com `--force-full`, ignora `last_sync_at` e puxa todos os registros (como import inicial)
AC6.2: Full sync segue mesma logica de dedup (nao cria duplicatas)
AC6.3: Exibe aviso ao usuario: "Full sync pode demorar. Use --dry-run primeiro."
AC7.1: Script pode ser executado via cron sem interacao humana
AC7.2: Crontab sugerido: `0 6 * * * cd /root/propek-whatsapp-bot && NODE_PATH=./node_modules node apps/crm/scripts/kommo-sync.js >> /var/log/kommo-sync.log 2>&1`
AC7.3: Script retorna exit code 0 em sucesso, 1 em erro (para monitoramento cron)
AC7.4: Log file compativel com rotacao (logrotate)
AC8.1: Log estruturado em stdout: `[TIMESTAMP] [LEVEL] mensagem`
AC8.2: Erros incluem contexto: kommo_id, campo, motivo
AC8.3: Relatorio final em `apps/crm/data/kommo-sync-report-{timestamp}.md`
AC8.4: Relatorio inclui: periodo do sync, novos contatos, contatos atualizados, novos deals, deals atualizados, erros, tempo total
AC9.1: Usa parameterized queries ($1, $2) — NUNCA interpolacao SQL
AC9.2: Usa `crm_user` para conexao ao banco
AC9.3: Bot WhatsApp continua operando durante sync
AC9.4: Zero dependencias externas alem de Node.js stdlib + pg
AC9.5: Token do Kommo NUNCA logado ou exibido
AC9.6: CHECK constraints da tabela deals respeitados
TIMELINE
25/03/2026
feat: CRM Phase 3 — Kommo Sync + LGPD Exclusion [Story 9.7, 9.8] [Story 6.1-sales-intelligence-bot]
351a453
ARQUIVOS (3)
apps/crm/scripts/kommo-sync.js CREATE
apps/crm/data/kommo-sync-report-*.md CREATE
docs/stories/active/story-9.7-kommo-sync-periodico.md UPDATE
RETROSPECTIVA
Qualidade: ★★★☆☆
Incluir @qa no proximo ciclo
Rodar @cyber-chief antes do push