Primeira carga de dados
Depois do flx-onboarding, a organização existe e está vazia. Esta é a jornada que a
enche: o sincronizador do cliente empurra lotes para o espelho sync_<slug> pela API de
ingestão. Princípio que a governa: adr-003-erp-nunca-ao-vivo.
flowchart LR ERP[(ERP do cliente)] --> AG[Sincronizador<br/>agente ou ETL] AG -->|X-Sync-Token| E["GET /sync/v1/entities<br/>descobre o contrato"] E --> B["POST /sync/v1/{entidade}/batch<br/>até 1000 registros"] B --> M[(sync_slug<br/>espelho da org)] M --> APP[AppStock lê<br/>read-only] AG -.-> H["POST /sync/v1/heartbeat"] style H stroke-dasharray: 5 5
Como funciona
A organização vem sempre do token, nunca do JWT nem da organização padrão — é a única
família de rotas do produto com essa regra (route_sync_ingest.py). O X-Sync-Token é
comparado por SHA-256 contra ent-sync-token e carimba last_used_at.
GET /sync/v1/entities— devolve o contrato vivo: para cada entidade alimentável, a chave de upsert e as colunas lidas por introspecção do banco real da organização. Não é uma lista fixa em código: é o que aquele banco aceita hoje.POST /sync/v1/{entidade}/batch— upsert porON CONFLICT (chave) DO UPDATE. Chave éapp_id, excetoembalagem, que usachv_reg. Limite de 1000 registros por lote (413 acima disso). Coluna desconhecida é erro (422), não descarte silencioso — decisão deliberada para o cliente descobrir o erro de mapeamento na hora.POST /sync/v1/heartbeat— sinal de vida.
Estado real
O caminho feliz funciona e é o que popula a organização demo hoje. A introspecção de colunas com cache de 300s é boa engenharia: o contrato não mente sobre o banco.
Quatro buracos que impedem um cliente novo de operar:
1. Três entidades do contrato são impossíveis de ingerir [P]
O upsert exige app_id, mas app_estoque_chpben, app_metadata_dictionary e app_sync_control
não têm essa coluna (usam chv_reg e id). O catálogo anuncia as três; o batch responde
422 “todo registro precisa da chave ‘app_id’“. Verificado ao vivo com token da santonio.
É por isso que app_sync_control está zerada: o heartbeat responde ok e não grava execução
nenhuma.
2. Faltam 19 tabelas no contrato [M]
INGESTABLE_TABLES tem 32 entradas; o sync_template.sql tem 51 tabelas. Ficaram de fora
todo o faturamento e notas fiscais: faturamento, fat_item_det, fat_nf_lote,
fat_ajuste_log, titulos, dim_lote, mercado, mercado_pais, vendedor e as tb_aux_*.
Consequência: Faturamento e Notas Fiscais só funcionam na organização demo, que foi carregada
por script. sync_santonio tem 0 linhas em faturamento e em vendedor, e não existe caminho
suportado para mudar isso.
3. Sem cursores, sem reconciliação [M]
Todo ciclo é carga cheia empurrada pelo cliente. Não há marca d’água de última sincronização por entidade nem comparação de contagem com o ERP — ninguém detecta registro perdido ou apagado na origem.
4. O cliente é cego [G]
/settings/sync/erp é mockup: mostra execuções, volumes e falhas fictícios. Na produção isso
é pior do que não mostrar nada. O dado para a tela real teria que vir de app_sync_control — que,
pelo buraco 1, nunca é preenchida.
Depois disto
A carga enche o espelho e o AppStock passa a ler. Escrever de volta no ERP é outro assunto e
não existe: a fila de writeback (outbox) foi apagada na migration 0067 e é o bloqueador que
mantém 24 endpoints em 501.
Lacunas
Rastreadas na fase-1-onboarding.