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.

  1. 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.
  2. POST /sync/v1/{entidade}/batch — upsert por ON CONFLICT (chave) DO UPDATE. Chave é app_id, exceto embalagem, que usa chv_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.
  3. 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.