P1.1 · Conector Nuvemshop
Depende de P0.3. App `conectores` no repo `radar`.
O prompt
Implemente o primeiro conector de plataforma. Ele é a porta de entrada de todo lead e a fonte do faturamento real que qualifica a venda — precisa ser confiável.
1. Base abstrata
class ConectorBase(ABC):
plataforma: str
def url_autorizacao(self, state: str) -> str: ...
def trocar_codigo(self, code: str) -> CredenciaisLoja: ...
def sync_produtos(self, desde: datetime | None) -> Iterator[ProdutoCanonico]: ...
def sync_pedidos(self, desde: datetime | None) -> Iterator[PedidoCanonico]: ...
def sync_clientes(self, desde: datetime | None) -> Iterator[ClienteCanonico]: ...
def registrar_webhooks(self) -> None: ...
def tratar_webhook(self, payload: dict, headers: dict) -> None: ...
2. Modelo canônico — não negocie isto
Todo módulo lê só o canônico. Nenhum código fora de conectores/ conhece o formato da Nuvemshop.
- Produto:
loja,externo_id,sku,nome,url,imagem_url,preco_centavos,preco_promocional_centavos,estoque,ativo,categorias,atualizado_em - Cliente:
loja,externo_id,email,email_hash(SHA-256),telefone,nome,primeiro_pedido_em,criado_em - Pedido:
loja,externo_id,cliente,numero,status,total_centavos,frete_centavos,desconto_centavos,moeda,criado_em,pago_em,cancelado_em,canal - ItemPedido:
pedido,produto,sku,nome,quantidade,preco_unitario_centavos
Índices em (loja, criado_em), (loja, cliente) e (loja, sku). Vai haver milhões de linhas.
3. OAuth
- App no Partners da Nuvemshop;
client_ideclient_secretno Secretradar-conectores /conectar/nuvemshop/redireciona comstateassinado contendo osessao_idda atribuição- Callback troca o code por
access_tokeneuser_id - Escopos mínimos de leitura: pedidos, produtos, clientes, loja. Nada de escrita — acelera a aprovação do app no P7.1
- Token cifrado no banco, chave vinda de env
- No callback, crie
Loja,Usuarioe vincule oLeadpelosessao_id
4. Sincronização
sync_inicial(loja_id): 12 meses de pedidos, todos os clientes e produtos. Paginação com cursor, lendo o header de rate limit e fazendo backoff exponencial. Nunca mais de 2 requisições simultâneas por lojasync_incremental(loja_id): de hora em hora, só o que mudou- Webhooks
order/created,order/paid,order/cancelled,product/updated,app/uninstalled, com HMAC validado SyncJobcometapa,percentual,itens_processados,erro— o front mostra barra de progresso durante os 3 minutos- Idempotência por
upsertem(loja, externo_id)
5. Robustez
- Loja com 100 mil pedidos não pode estourar memória: iteradores e
bulk_createem lotes de 500 - Falha de API grava em
SyncJob.erroe reagenda com backoff, até 5 tentativas app/uninstalledmarca a Loja como desconectada e para os syncs, sem apagar dados — o lead continua valendo
Critérios de aceite
- Testes com fixtures reais anonimizadas em
tests/fixtures/, cobrindo paginação e rate limit - Rodar
sync_inicialduas vezes gera exatamente os mesmos registros - Pedidos da loja A nunca aparecem em query escopada na loja B
- Conexão real ponta a ponta com loja de teste, mostrando
SyncJobcompleto e as contagens sync_inicialde 5.000 pedidos em menos de 3 minutos
Shopify e Tray seguem a mesma interface depois. Não os implemente agora.