feat(enterprise-import): reconcile de emails em sessão persistida#19
Open
daniloleonecarneiro wants to merge 2 commits into
Open
feat(enterprise-import): reconcile de emails em sessão persistida#19daniloleonecarneiro wants to merge 2 commits into
daniloleonecarneiro wants to merge 2 commits into
Conversation
a4cc4bc to
f9fa3ab
Compare
… match por created_at Reescreve o fluxo super-admin de conciliação de emails mascarados (export Enterprise) para operar em lotes sobre uma sessão server-side, viável para bases reais (350k contatos, CSV 20MB, dezenas de milhares de colisões de máscara): - Sessão persistida (email_reconcile_sessions/_items): CSV parseado e matched UMA vez; depois tudo é incremental — apply-auto em chunks, fila de ambíguos paginada com busca, resolve em lote (best-name / skip-remaining) e progresso derivado dos status dos itens. - Match em camadas: created_at como sinal forte (tier minuto exato tolerando offset fixo de timezone, tier mesma data) antes do desempate por similaridade de nome (Jaccard, pontuação/ordem insensível); import preserva o created_at da origem, então o par (máscara, created_at) funciona como chave natural. - Colunas obrigatórias (email, created_at e sinal de nome — coluna name OU par first_name/last_name) validadas nos headers antes de processar; formulário de upload trava as obrigatórias e permite ignorar opcionais. - Email tratado como chave única por conta em todo o fluxo: dedup de auto-picks disputando a mesma linha, pré-checagem amigável no apply (em vez do erro cru do índice único), candidatos já usados desabilitados na UI e estratégias automáticas nunca consomem email já aplicado (item permanece pendente para decisão manual). - Tabela "itens da sessão" (quem casou com o quê) com busca por nome/email e filtros de tipo/status; badges de concordância de data nos candidatos; toggle de seleção nos ambíguos. - Cadeia de limites de upload alinhada (nginx 64m/300s no /api, body-parser 64mb escopado em /imports, Joi 50MB) para o CSV viajar embutido no JSON.
…scarar As rotas de leitura (detalhe por id/uuid, listagem paginada e findAll) reescreviam o email com maskEmail() na resposta. Como a máscara do email real é idêntica ao placeholder importado do Enterprise, contatos reconciliados pareciam continuar mascarados — e consumidores da API não tinham como obter o endereço utilizável para o fluxo de envios. Agora o email retorna como está no banco: reconciliado = endereço real; pendente de reconcile = placeholder (que é o valor armazenado mesmo). O campo derivado maskedEmail segue disponível no payload e a lista de supressões permanece mascarada.
f9fa3ab to
fd0e2c6
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Reescreve o fluxo super-admin de conciliação de emails mascarados (import Enterprise) para operar em lotes sobre uma sessão server-side, viável para exports grandes (centenas de milhares de contatos, com milhares de colisões de máscara):
email_reconcile_sessions/_items, migration1783000000000): CSV parseado e matched uma vez; depois tudo é incremental — apply-auto em chunks, fila de ambíguos paginada, resolve em lote (best-name / skip-remaining), progresso derivado dos status.created_at: o import preserva o timestamp da origem e o export CSV carrega o mesmo campo, então (máscara, created_at) age como chave natural. Tier de minuto exato (segundos/ms ignorados, tolerância a offset fixo de timezone) > mesma data > desempate por similaridade de nome (Jaccard, insensível a pontuação/ordem).email,created_ate sinal de nome — colunanameou parfirst_name/last_name); formulário de upload trava as obrigatórias e permite ignorar opcionais.client_max_body_size 64m+proxy_read_timeout 300sno/api, body-parser 64mb escopado em/imports, Joi 50MB.Test plan
email-reconcile.service.spec.ts: 26 testes cobrindo colunas obrigatórias (ambas as formas de nome), desambiguação por created_at (minuto/data/timezone), CSV parcial vs colisões de máscara, dedup de linha disputada, guarda de email em uso e o apply legado.hashed_email(listener@BeforeUpdate), auditoria registrada, busca e tabela de itens exercitadas contra a sessão viva.tscde backend e frontend nos baselines; locales pt-BR/en-US/es-ES válidos.