Skip to content

Importação de Dados — Smart Migration Tool ​

Visão Geral ​

O Smart Migration Tool permite importar dados de sistemas legados (planilhas Excel, exports de PDV antigos, ERPs genéricos) para o PopinaFlow com zero retrabalho manual e 100% de integridade de dados.

CaracterísticaDetalhe
Rota/t/:slug/admin/migration
Viewfrontend-react/src/views/admin/MigrationView.tsx
Backendbackend/src/migration/
Formatos suportadosCSV, Excel (.xlsx), JSON
Tamanho máximo50 MB por arquivo
ProcessamentoAssíncrono via BullMQ (concorrência 2)
AtomicidadeMongoDB withTransaction() — tudo ou nada por domínio
TTL da sessão48h (arquivo S3 + documento MongoDB)
PermissãoAdmin ou Superadmin

Domínios Suportados ​

DomínioO que importaChave de deduplicação
CardápioItens de menu, categorias, preçosnome + categoria (case-insensitive)
EstoqueItens de estoque, quantidades iniciaisSKU único por tenant
FornecedoresCadastro de fornecedoresCNPJ (14 dígitos) ou nome
PedidosHistórico de vendas (status delivered)Gerado automaticamente
ContabilidadeLançamentos contábeis e DREentryNumber único por tenant

Ordem de dependência: Quando múltiplos domínios são selecionados, a importação respeita a ordem topológica obrigatória:

Fornecedores → Estoque → Cardápio → Pedidos → Contabilidade

Fluxo do Wizard (5 Etapas) ​

Etapa 1 — Selecionar Domínios ​

Selecione quais domínios importar. Múltiplos domínios podem ser selecionados simultaneamente — o sistema enfileira automaticamente na ordem correta.

Etapa 2 — Enviar Arquivo ​

Arraste ou selecione um arquivo por domínio. O sistema valida:

  • Formato (CSV/Excel/JSON via magic bytes)
  • Tamanho (≤ 50 MB)
  • Estrutura básica (pelo menos 1 linha de dados)

O arquivo é enviado para o S3 (armazenamento privado) e o processamento inicia imediatamente em background.

Etapa 3 — Mapear Campos ​

O FieldMapper analisa os cabeçalhos do arquivo e sugere automaticamente o mapeamento para os campos internos do PopinaFlow.

Algoritmo de mapeamento (duas fases):

FaseCondiçãoFonte
LevenshteinConfiança ≥ 70%Baseado em tabelas de aliases por domínio
Fallback IAConfiança < 70%AiProviderService com prompt estruturado
CacheTenant já importou antesRedis (TTL 30 dias) — zero custo de IA

Indicador de confiança:

BarraConfiançaAção do usuário
Verde sólido≥ 70%Mapeamento automático — clique "Editar" para sobrescrever
Âmbar< 70%Dropdown de seleção obrigatório

Exemplos de aliases reconhecidos para Cardápio:

Campo internoAliases aceitos
namenome, produto, item, descricao, item_name
pricepreco, valor, preco_venda, sale_price
categorycategoria, grupo, section
skucod, code, ref, codigo

Etapa 4 — Validar & Aplicar ​

Migration Pulse ​

Barra de progresso em tempo real com 5 estágios:

[ Enviando ] → [ Analisando ] → [ Mapeando ] → [ Validando ] → [ Pronto ]
  • Ativo: animação de carregamento
  • Concluído: ✓ verde
  • Falha: ✗ vermelho com mensagem de erro

Painel de Conflitos (Quiet Error Console) ​

Exibido quando há conflitos a resolver antes de aplicar. Um card por tipo de conflito:

TipoDescriçãoAções disponíveis
missing_requiredCampo obrigatório ausenteCampo de valor padrão + "Usar padrão" / "Ignorar"
duplicateRegistro já existeRadio: Substituir / Manter ambos / Ignorar
unresolved_fkEntidade relacionada não encontradaLink para criar a entidade / Ignorar
invalid_unitUnidade de medida não reconhecidaSelecionar unidade equivalente
currency_parse_failValor monetário não parseávelCampo de valor padrão

Preview de Impacto ​

ContadorDescrição
CriarRegistros novos que serão criados
AtualizarRegistros existentes que serão atualizados
IgnorarLinhas puladas (campos obrigatórios vazios)
ConflitosLinhas que requerem resolução manual

O botão "Aplicar importação" fica disponível somente quando todos os conflitos estão resolvidos.

Etapa 5 — Ledger de Sucesso ​

Resumo da importação aplicada com contadores finais, domínio, data e botão para nova importação.


Integração com Onboarding ​

O Smart Migration Tool está integrado ao Wizard de Onboarding, na Etapa 4 (Monte seu Cardápio):

Aba "🚀 Importar arquivo" → importa cardápio de um arquivo legado → avança automaticamente o onboarding ao concluir.

Isso permite que novos clientes migrem seus cardápios existentes sem sair do fluxo de configuração inicial.


API Endpoints ​

Guards: JwtAuthGuard → TenantGuard → RolesGuard(Admin, Superadmin)

MétodoRotaDescrição
POST/t/:slug/migrationUpload de arquivo + criação de sessão + enfileiramento
GET/t/:slug/migration/historyHistórico de sessões do tenant
GET/t/:slug/migration/:idPolling de status da sessão (2s no frontend)
PATCH/t/:slug/migration/:id/mappingAtualizar mapeamento de campos após edição
PATCH/t/:slug/migration/:id/conflictsSubmeter resoluções de conflito
POST/t/:slug/migration/:id/applyAplicar sessão pronta ao banco de dados
DELETE/t/:slug/migration/:idCancelar sessão + remover arquivo do S3

Estados da Sessão ​

uploading → parsing → mapping → validating → ready → applying → completed
                                                              ↓
                                                           failed
StatusDescrição
uploadingArquivo sendo enviado ao S3
parsingParser lendo o arquivo (CSV/Excel/JSON)
mappingFieldMapper inferindo cabeçalhos
validatingDomain service validando linhas (dry-run)
readyPronto para aplicar (sem conflitos, ou todos resolvidos)
applyingTransação MongoDB em andamento
completedImportação aplicada com sucesso
failedErro irrecuperável — errorMessage disponível

Segurança e Integridade ​

GarantiaImplementação
Isolamento de tenantToda query inclui { tenant: tenantId }
Atomicidadesession.withTransaction() — falha parcial = zero escrita
Duplo-applyCAS atômico: findOneAndUpdate({ status: 'ready' }) impede concorrência
PATCH em sessão ativaStatus guard: rejeita mutação em sessões applying/completed
Tamanho de arquivoMulter limits.fileSize = 50 MB — rejeita antes do upload ao S3
Limpeza de S3Arquivo removido ao cancelar ou ao expirar (TTL 48h via job separado)
Idempotência de retryBullMQ reprocessa com segurança — $setOnInsert em contabilidade, SKU upsert em estoque

Comportamento por Domínio ​

Cardápio ​

  • Cria categorias inexistentes automaticamente dentro da mesma transação
  • Converte preço para centavos (parseCurrency / 100)
  • Deduplicação por nome + categoria (case-insensitive)
  • Resolve inventoryItem via SKU se coluna presente

Estoque ​

  • Cria InventoryMovement de entrada apenas para registros novos (não atualizações)
  • Resolve nome do fornecedor → ObjectId de Supplier (requer importação de fornecedores primeiro)
  • SKU único por tenant como chave de upsert

Fornecedores ​

  • CNPJ normalizado para 14 dígitos (remove ./-)
  • Deduplicação por CNPJ ou nome quando CNPJ ausente

Pedidos (Histórico) ​

  • Criados com status: 'delivered' (histórico)
  • orderNumber gerado com crypto.randomUUID() (sem colisão)
  • createdAt legado preservado via collection.insertOne() (bypassa timestamps: true do Mongoose)

Contabilidade ​

  • Lançamentos marcados com { _legacyImport: true, _legacyFiscalNote: taxasOriginais }
  • createdAt legado preservado via collection.insertOne()
  • entryNumber gerado como IMPORT-{domain}-{timestamp}-{index}

Backend — Arquivos ​

backend/src/migration/
├── migration.module.ts
├── migration.controller.ts
├── migration-orchestrator.service.ts
├── migration.processor.ts               ← BullMQ WorkerHost, concorrência 2
├── migration.queue.ts                   ← MIGRATION_QUEUE + MigrationJobData
├── schemas/
│   └── migration-session.schema.ts      ← TTL 48h via índice MongoDB
├── parsers/
│   ├── csv-parser.service.ts            ← papaparse
│   ├── excel-parser.service.ts          ← xlsx
│   └── json-parser.service.ts           ← array/envelope/objeto único
├── fuzzy/
│   └── field-mapper.service.ts          ← Levenshtein + IA + cache Redis
└── domains/
    ├── menu-import.domain.ts
    ├── inventory-import.domain.ts
    ├── suppliers-import.domain.ts
    ├── orders-import.domain.ts
    └── accounting-import.domain.ts

Relacionados ​

Lançado sob a licença MIT.