Claude Code para correção de importação/exportação de dados: defina regras de validação, formatos de erro consistentes e testes de fuzz para importações CSV/JSON e reduza tickets por casos de borda.

As importações raramente falham porque o código está “errado”. Elas falham porque os dados reais são bagunçados, inconsistentes e produzidos por pessoas que nunca viram suas suposições.
Problemas com CSV costumam ser sobre formato e estrutura. Problemas com JSON costumam ser sobre significado e tipos. Ambos podem quebrar de formas que parecem pequenas, mas geram resultados confusos.
Essas questões aparecem repetidamente em tickets de suporte:
Correção não é só “foi importado”. Você precisa decidir quais resultados são permitidos, porque os usuários reparam mais em erros silenciosos do que em falhas barulhentas.
A maioria das equipes pode concordar em três desfechos:
Casos de borda viram retrabalho quando as pessoas não conseguem dizer o que deu errado ou como corrigir rapidamente. Um cenário comum: um cliente envia um CSV de 5.000 linhas, o importador diz “Invalid format”, e ele tenta de novo três vezes com edições aleatórias. Isso vira vários tickets além de alguém do seu time tentando reproduzir o arquivo localmente.
Defina metas que reduzam o ciclo: menos reenvios, correções mais rápidas, resultados previsíveis. Antes de escrever regras, decida o que “parcial” significa (e se você permite isso), como reportará problemas por linha, e o que os usuários devem fazer em seguida (editar o arquivo, mapear campos ou exportar uma versão corrigida). Se você está usando uma plataforma de geração como Koder.ai (koder.ai) para gerar validadores e testes rapidamente, o contrato de importação ainda é o que mantém esse comportamento consistente conforme o produto evolui.
Antes de escrever uma única regra de validação, decida o que “entrada válida” significa para seu produto. A maioria dos bugs de importação é um descompasso entre o que os usuários enviam e o que seu sistema assume silenciosamente.
Comece pelos formatos e seja explícito. “CSV” pode significar vírgula ou ponto-e-vírgula, uma linha de cabeçalho ou não, UTF-8 ou “o que o Excel gerou”. Para JSON, decida se aceita um único objeto, um array de registros ou JSON Lines (um objeto JSON por linha). Se aceitar JSON aninhado, defina quais caminhos você lê e quais ignora.
Depois trave o contrato de campos. Para cada campo, decida se é obrigatório, opcional ou opcional com padrão. Padrões fazem parte do contrato, não um detalhe de implementação. Se country faltar, você deixa vazio, escolhe um país específico ou rejeita a linha?
O comportamento de parsing é onde importações “tolerantes” criam dor no longo prazo. Decida desde o início quão estrito você é sobre remover espaços, normalizar caixa e aceitar variantes como "yes"/"true"/"1". Tolerância é aceitável se for previsível e documentada.
Duplicatas são outra decisão de contrato que afeta correção e confiança. Defina o que conta como duplicata (mesmo email, mesmo external_id, ou a combinação de campos), onde você detecta (dentro do arquivo, contra dados existentes, ou ambos) e o que faz quando acontece (manter primeiro, manter último, mesclar ou rejeitar).
Uma checklist de contrato que você pode colar numa especificação:
Exemplo: importando “customers.” Se email é a chave única, decida se " [email protected] " é igual a "[email protected]", se email ausente é permitido quando external_id existe, e se duplicatas dentro do arquivo devem ser rejeitadas mesmo que o banco não tenha correspondência. Uma vez que esse contrato esteja fixo, comportamento consistente entre UI e API fica muito mais fácil, seja implementado em Koder.ai ou em outro lugar.
Importações bagunçadas frequentemente começam com uma única função gigante validate(). Uma abordagem mais limpa é usar camadas de regras com nomes claros e funções pequenas. Isso torna mudanças mais fáceis de revisar e testes mais fáceis de escrever.
Comece com regras por campo: checam um único valor que pode passar ou falhar sozinho (tipo, intervalo, comprimento, valores permitidos, regex). Mantenha-as simples e previsíveis. Exemplos: email corresponde a um padrão básico, age é um inteiro entre 0 e 120, status é um de active|paused|deleted.
Adicione regras cruzadas apenas onde importam. Essas verificações dependem de múltiplos campos, e bugs se escondem aqui. Exemplos clássicos: startDate deve ser antes de endDate, ou total é igual a subtotal + tax - discount. Escreva essas regras para que possam apontar campos específicos, não apenas “registro inválido”.
Separe regras de nível de registro das de nível de arquivo. Uma regra de nível de registro checa uma linha (CSV) ou um objeto (JSON). Uma regra de nível de arquivo checa o upload inteiro: cabeçalhos necessários existem, uma chave única não se repete entre linhas, contagem de colunas bate com a expectativa, ou o arquivo declara uma versão suportada.
Normalização deve ser explícita, não “mágica”. Decida o que você normaliza antes de validar e documente isso. Exemplos comuns incluem remover espaços, normalização Unicode (para que caracteres visualmente idênticos comparem igual) e formatar telefones em um formato consistente de armazenamento.
Uma estrutura que se mantém legível:
Versione suas regras. Coloque um schemaVersion (ou perfil de importação) no arquivo ou na requisição da API. Quando você mudar o que “válido” significa, ainda poderá reimportar exports antigos usando a versão anterior. Essa escolha previne muitos tickets “funcionava ontem”.
Um bom importador falha de forma útil. Erros vagos levam a reenvios aleatórios e trabalho de suporte evitável. Um formato de erro claro ajuda usuários a corrigir o arquivo rapidamente e ajuda você a melhorar validações sem quebrar clientes.
Comece com um shape de objeto de erro estável e mantenha-o consistente entre CSV e JSON. Você pode usar Claude Code para propor um esquema e alguns exemplos realistas, depois consolidá-lo como parte do contrato de importação.
Trate cada erro como um pequeno registro com campos que não mudam. A mensagem pode evoluir, mas o código e a localização devem permanecer estáveis.
code: um identificador curto e estável como REQUIRED_MISSING ou INVALID_DATEmessage: uma frase amigável para a UIpath: onde está o problema (ponteiro JSON como /customer/email, ou nome da coluna como email)row ou line: para CSV, inclua número de linha 1-based (e opcionalmente a linha original)severity: pelo menos error e warningTorne os erros acionáveis. Inclua o que você esperava e o que você realmente viu, e quando possível mostre um exemplo que passaria. Por exemplo: esperado YYYY-MM-DD, recebido 03/12/24.
Mesmo que você retorne uma lista plana, inclua dados suficientes para agrupar erros por linha e por campo. Muitas UIs querem “Linha 12 tem 3 problemas” e então destacar cada coluna. Equipes de suporte gostam de agrupar porque padrões ficam óbvios (por exemplo, toda linha está sem country).
Uma resposta compacta pode ficar assim:
{
"importId": "imp_123",
"status": "failed",
"errors": [
{
"code": "INVALID_DATE",
"message": "Signup date must be in YYYY-MM-DD.",
"path": "signup_date",
"row": 12,
"severity": "error",
"expected": "YYYY-MM-DD",
"actual": "03/12/24"
},
{
"code": "UNKNOWN_FIELD",
"message": "Column 'fav_colour' is not recognized.",
"path": "fav_colour",
"row": 1,
"severity": "warning"
}
]
}
Planeje localização sem mudar os códigos de erro. Mantenha code neutro em idioma e durável, e trate message como texto substituível. Se depois você adicionar messageKey ou mensagens traduzidas, clientes antigos ainda podem confiar nos mesmos códigos para filtro, agrupamento e análise.
Para evitar “importações misteriosas”, sua resposta de API deve responder duas perguntas: o que aconteceu e o que o usuário deve fazer em seguida.
Mesmo quando há erros, retorne um resumo consistente para que a UI e as ferramentas de suporte lidem com qualquer importação do mesmo jeito.
Inclua:
created, updated, skipped, failedtotalRows (ou totalRecords para JSON)mode (por exemplo: "createOnly", "upsert" ou "updateOnly")startedAt e finishedAtcorrelationId que o suporte possa pedirEsse correlationId vale muito. Quando alguém relata “não importou”, você encontra a execução exata e o relatório de erros sem adivinhar.
Não despeje 10.000 erros de linha na resposta. Retorne uma amostra pequena (por exemplo 20) que mostre o padrão, e forneça um meio separado para recuperar o relatório completo se necessário.
Faça cada erro específico e estável:
Exemplo de shape de resposta (sucesso com algumas falhas por linha):
{
"importId": "imp_01HZY...",
"correlationId": "c_9f1f2c2a",
"status": "completed_with_errors",
"summary": {
"totalRows": 1200,
"created": 950,
"updated": 200,
"skipped": 10,
"failed": 40
},
"errorsSample": [
{
"row": 17,
"field": "email",
"code": "invalid_format",
"message": "Email must contain '@'.",
"value": "maria.example.com"
}
],
"report": {
"hasMore": true,
"nextPageToken": "p_002"
},
"next": {
"suggestedAction": "review_errors"
}
}
Note o campo next. Mesmo um payload mínimo de sucesso deve ajudar o produto a avançar: mostrar uma tela de revisão, oferecer uma nova tentativa ou abrir a coleção importada.
Pessoas reenviam. Redes falham. Se o mesmo arquivo for importado duas vezes, você quer resultados previsíveis.
Seja explícito sobre idempotência: aceite um idempotencyKey (ou calcule um hash do arquivo) e retorne o importId existente se a requisição for repetida. Se seu modo for upsert, defina a regra de correspondência (por exemplo, “email é a chave única”). Se for apenas create, retorne “skipped” para duplicatas, não “created again”.
Se a requisição inteira for inválida (auth ruim, content-type errado, arquivo ilegível), falhe rápido e retorne status: "rejected" com uma lista curta de erros. Se o arquivo é válido mas tem problemas por linha, trate como um job completo com failed > 0 para que os usuários possam consertar e reenviar sem perder o resumo.
Um hábito útil: faça o modelo escrever o contrato em formato estruturado, não em prosa. “Parágrafos úteis” muitas vezes pulam detalhes como regras de trim, valores padrão e se célula vazia significa “ausente” ou “vazia”.
Use um prompt que force uma tabela que um humano revise rapidamente e que um desenvolvedor possa transformar em código. Peça a regra de cada campo, exemplos de passe/falha e uma nota explícita para qualquer ambiguidade (por exemplo, string vazia vs null).
You are helping design an importer for CSV and JSON.
Output a Markdown table with columns:
Field | Type | Required? | Normalization | Validation rules | Default | Pass examples | Fail examples
Rules must be testable (no vague wording).
Then output:
1) A list of edge cases to test (CSV + JSON).
2) Proposed test names with expected result (pass/fail + error code).
Finally, list any contradictions you notice (required vs default, min/max vs examples).
Depois do rascunho inicial, aperfeiçoe pedindo um exemplo positivo e um negativo por regra. Isso força cobertura de cantos complicados como strings vazias, valores só com espaço, colunas faltando, null vs "null", inteiros muito grandes, notação científica, IDs duplicados e campos JSON extras.
Para um cenário concreto, imagine importar “customers” de CSV: email é obrigatório, phone é opcional, e signup_date tem padrão hoje se faltar. O modelo deve apontar contradição se você também marcar signup_date como obrigatório. Deve propor testes como import_customers_missing_email_returns_row_error e especificar o código de erro e o formato da mensagem que você retorna.
Faça mais uma revisão antes da implementação: peça ao modelo para reformular as regras como um checklist e apontar onde padrões, campos obrigatórios e normalização podem conflitar. Essa checagem captura muitos comportamentos que virariam tickets.
Fuzz testing impede que “arquivos estranhos” virem tickets de suporte. Comece com um pequeno conjunto de arquivos válidos, depois gere milhares de variações levemente quebradas e garanta que seu importador reaja de forma segura e clara.
Comece com um pequeno corpus seed de exemplos válidos que representem uso real: o menor arquivo válido, um arquivo típico e um arquivo grande. Para JSON, inclua um objeto, muitos objetos e estruturas aninhadas se você as suporta.
Depois adicione um mutador automatizado que mexa em uma coisa por vez. Mantenha as mutações reprodutíveis registrando a seed aleatória para poder reproduzir falhas.
Dimensões de fuzz que pegam a maioria dos problemas reais:
Não pare na sintaxe. Adicione fuzz semântico também: troque campos semelhantes (email vs username), datas extremas, IDs duplicados, quantidades negativas ou valores que violem enums.
Testes de fuzz só ajudam se critérios de passe forem rígidos. Seu importador nunca deve travar ou ficar pendente, e erros devem ser consistentes e acionáveis.
Um conjunto prático de regras de passe:
Execute esses testes no CI a cada mudança. Quando encontrar uma falha, salve o arquivo exato como fixture e adicione um teste de regressão para que nunca mais retorne.
Se usar Claude Code para esse trabalho, peça que gere fixtures seed que batam com seu contrato, um plano de mutações e os outputs de erro esperados. Você ainda escolhe as regras, mas obtém uma superfície de testes ampla rapidamente, especialmente para citações em CSV e cantos do JSON.
A maioria dos tickets de importação vem de regras pouco claras e feedback não útil.
Uma armadilha comum é parsing “best effort” que não está documentado. Se seu importador remove espaços silenciosamente, aceita vírgula e ponto-e-vírgula, ou adivinha formatos de data, usuários criam fluxos dependentes dessas suposições. Depois uma pequena mudança, ou um gerador de arquivos diferente, quebra tudo. Escolha o comportamento, documente e teste.
Outro causador frequente é mensagem genérica de erro. “Invalid CSV” ou “Bad request” força o usuário a adivinhar. Eles reenviam o mesmo arquivo cinco vezes e o suporte acaba pedindo o arquivo. Erros devem apontar linha, campo, motivo claro e um código estável.
Rejeitar todo o arquivo por uma linha ruim também é ponto de dor. Às vezes isso é correto (imports financeiros onde parcial é perigoso). Muitos imports de negócios podem continuar e reportar um sumário, desde que você ofereça uma escolha explícita como modo estrito vs importação parcial.
Problemas de codificação de texto geram tickets persistentes. UTF-8 é o padrão certo, mas CSVs reais frequentemente incluem BOM, aspas curvas ou espaços sem quebra copiados de planilhas. Trate isso de forma consistente e reporte o que foi detectado para que usuários ajustem suas configurações de exportação.
Por fim, mudar códigos de erro entre versões quebra clientes e automações. Melhore a redação se quiser, mas mantenha códigos e significados estáveis. Só versione quando realmente necessário.
Armadilhas a proteger desde o início:
Exemplo: um cliente exporta um CSV do Excel, que adiciona um BOM e formata datas como 03/04/2026. Seu importador adivinha MM/DD, mas o cliente esperava DD/MM. Se seu relatório de erro inclui o formato detectado, o campo exato e uma sugestão de correção, o usuário corrige sem ida-e-volta.
A maioria dos problemas de importação são pequenos descompassos entre o que os usuários pensam que o arquivo significa e o que seu sistema aceita. Trate isso como um gate de release.
Um teste prático: use um arquivo intencionalmente bagunçado. Exemplo: um CSV onde o cabeçalho aparece duas vezes (dois “email”), um campo booleano usa “Y” e uma data é “03/04/05”. Seu importador não deve adivinhar. Deve aplicar uma regra de mapeamento documentada ou rejeitar com um erro específico.
Duas checagens que times frequentemente pulam:
Primeiro, verifique se seu importador reporta erros com detalhe de localização suficiente para corrigir o arquivo fonte. “Invalid date” não é acionável. “Linha 42, coluna start_date: esperado YYYY-MM-DD, recebeu 03/04/05” é.
Segundo, rode o mesmo arquivo inválido duas vezes e compare resultados. Se a ordem dos erros muda, códigos mudam ou números de linha flutuam, usuários perdem confiança. Comportamento determinístico é chato, e esse é o objetivo.
Um import comum é pedidos de clientes vindo de export de planilha. Alguém exporta um CSV de um sistema antigo, edita no Excel e faz upload. A maioria dos tickets ocorre quando o importador “corrige” dados silenciosamente ou a mensagem de erro não diz o que mudar.
Imagine um arquivo chamado orders.csv com colunas: order_id,customer_email,order_date,currency,total_amount.
Aqui estão três linhas ruins realistas (como o usuário as veria):
order_id,customer_email,order_date,currency,total_amount
A-1001,[email protected],2026-01-05,USD,129.99
A-1002,not-an-email,01/06/2026,USD,49.00
,[email protected],2026-01-07,US, -10
Linha 2 tem email inválido e data ambígua. Linha 3 está sem order_id, tem um código de moeda não suportado (US em vez de USD) e um valor negativo.
Se sua API retorna erros, mantenha o formato consistente e específico. Aqui vai um exemplo de resposta que suporta sucesso parcial:
{
"correlation_id": "imp_20260109_7f3a9d",
"import_id": "ord_01HZZ...",
"status": "partial_success",
"summary": {
"total_rows": 3,
"imported_rows": 1,
"failed_rows": 2
},
"errors": [
{
"row_number": 2,
"field": "customer_email",
"code": "invalid_email",
"message": "Email must contain a valid domain.",
"value": "not-an-email"
},
{
"row_number": 2,
"field": "order_date",
"code": "invalid_date_format",
"message": "Use ISO-8601 (YYYY-MM-DD).",
"value": "01/06/2026"
},
{
"row_number": 3,
"field": "order_id",
"code": "required",
"message": "order_id is required.",
"value": ""
},
{
"row_number": 3,
"field": "currency",
"code": "unsupported_currency",
"message": "Allowed values: USD, EUR, GBP.",
"value": "US"
},
{
"row_number": 3,
"field": "total_amount",
"code": "must_be_positive",
"message": "total_amount must be greater than 0.",
"value": " -10"
}
],
"retry": {
"mode": "upload_failed_only",
"failed_row_numbers": [2, 3]
}
}
Sucesso parcial importa porque usuários não devem reenviar o arquivo inteiro. Um fluxo simples de retry é: conserte apenas as linhas com falha, exporte um CSV pequeno contendo as linhas 2 e 3 e reenvie. Seu importador deve tratar isso como idempotente quando order_id estiver presente, assim o “retry” atualiza os mesmos registros em vez de criar duplicatas.
Para suporte, correlation_id é o caminho mais rápido para diagnóstico. Um agente de suporte pode pedir esse único valor, encontrar a execução no log e confirmar se o parser viu colunas extras, delimitador errado ou codificação inesperada.
Próximos passos que tornam isso repetível:
A maioria das falhas vem de dados do mundo real bagunçados, não de “código ruim”. Problemas com CSV costumam ser sobre formato (cabeçalhos, delimitador, citação, codificação), enquanto problemas com JSON tendem a ser sobre significado (tipos, null vs vazio, aninhamentos inesperados). Trate ambos como entrada não confiável e valide contra um contrato explícito.
Defina três resultados desde o início:
Escolha um padrão (muitos produtos optam por parcial) e mantenha isso consistente na UI e na API.
Escreva um contrato de importação antes de implementar validações:
Isso evita surpresas do tipo “funcionava ontem” quando o comportamento muda.
Adote um formato inequívoco por campo (por exemplo, datas como YYYY-MM-DD). Se aceitar variantes, deixe isso explícito e previsível (por exemplo, aceite true/false/1/0, mas não todo palpite de planilha). Evite adivinhar datas ambíguas como 01/02/03; exija ISO ou rejeite com um erro claro.
Decida:
Combine isso com idempotência quando usuários puderem reenviar importações para evitar duplicações.
Use camadas em vez de uma única função gigante validate():
Retorne um formato de erro estável com:
Sempre retorne um resumo consistente, mesmo quando houver erros:
Suporte reenvios explicitamente:
idempotencyKey (ou use um hash do arquivo)importId existente se a mesma requisição for repetidaSem isso, reenvios normais de usuário podem criar duplicatas.
Comece com alguns arquivos seed conhecidos, depois gere muitas mutações pequenas (uma mudança por vez):
NaN/Infinity em JSON)Um teste de fuzz “passa” quando o importador nunca trava/fica pendente e sempre retorna erros determinísticos e acionáveis.
Regras pequenas e nomeadas são mais fáceis de testar e de alterar com segurança.
code (identificador estável)message (texto amigável)path/field (nome da coluna ou ponteiro JSON)row/line (para CSV)severity (error vs warning)Torne-o acionável incluindo o que era esperado e o que foi recebido sempre que possível.
created, updated, skipped, failed, mais totalRows/totalRecordsstatus (success, rejected, completed_with_errors)startedAt, finishedAt)correlationId para suporte/diagnósticoPara arquivos grandes, inclua uma pequena errorsSample e um meio de recuperar o relatório completo depois.