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.