Omie Sync State é a projeção read-only no Bubble do estado da integração Omie. Modelo de dados completo do tipo que o backend mantém e Bubble apenas consome.
Cardinalidade: 1 Omie Sync State ↔ 1 Order (constraint: order field unique). Cria no primeiro POST /sync-omie. Dura toda vida do Order.
Order é dono dos dados comerciais (Bubble nativo); Omie Sync State carrega o estado técnico-fiscal escrito pelo backend. Separar evita churn de modified_date no Order e simplifica privacy rules.
Critério
Order (Bubble nativo)
Omie Sync State (novo)
Owner
Comercial · cliente
Backend orquestrador
Frequência update
Baixa (criação + cancel)
Alta (1 PATCH por mudança)
Fonte de verdade
Bubble Postgres
Backend Postgres → projetado pra Bubble
Escrita Bubble workflow
Sim (checkout, etc)
Não — só backend
Bubble Privacy Rule
Visibilidade comercial
Visibilidade Financeiro + Operação
modified_at churn
Reflete ação humana
Reflete sync técnico — separa sinal
Bind UI Repeating Group
”Pedidos do cliente"
"Pedidos com erro” / “Bloqueados dia 25” / “Em cooldown”
Omie Sync State é sempre escrito de dentro do reconciler — nunca em resposta a webhook Bubble→backend. Dois únicos pontos de chamada:
Cron cdc_tick (a cada 1h) — loop por order modificado desde o cursor; chama _reconcile_one(order) que, ao final, chama project_omie_sync_state(...).
Endpoint manual POST /v1/orders/{id}/sync-omie — chama o mesmo _reconcile_one(order) direto, sem mexer no cursor.
Ambos passam pelo helper único project_omie_sync_state. Não há outro caminho — endpoints /retry, /cancel-nf, /mark-nf-manual, /override-day25, /payment-confirmed foram removidos; suas semânticas foram consolidadas no reconciler (ver Integration).
1 PATCH por transição detectada no diff shadow → fresh (noop quando nada relevante mudou)
Idempotência
Backend usa bubble_order_id pra resolver o Omie Sync State do Bubble (busca via Data API Search). correlation_id derivado de cdc:{order_id}:{order.modified_date}
Criação
Primeira aparição do order no reconciler → POST /api/1.1/obj/omiesyncstate
Falha Bubble Data API
Não avança cursor naquele order → próximo tick reprocessa o range
Ordem dos campos
Sempre escreve last_sync_at + last_sync_endpoint + sync_correlation_id + os campos transicionais. Outros campos não tocados = não enviados.
Mapeamento Bubble Element → bind expression → comportamento. Cada linha é 1 widget concreto na tela de detalhe do pedido ou no Console Financeiro.
Elemento Bubble
Bind / Condicional
Comportamento
Badge “Status Faturamento”
Current Omie Sync State's status_faturamento's display + attr_cor
Cor automática via Option Set
Alerta topo “Bloqueado dia 25”
regra_dia25_aplicada is yes
”Postergado para [billing_scheduled_date]” + link “Editar data”
Banner “Omie em cooldown”
omie_ban_active is yes
”Omie bloqueou — libera em [omie_ban_expires_at - Current date and time] minutos”
Botão “Forçar sync agora”
status_faturamento is erro_faturamento AND omie_ban_active is no
Chama POST /v1/orders/{id}/sync-omie (mesmo handler do reconciler, parametrizado pra 1 order)
Botão “Override dia 25”
status_faturamento is bloqueado_dia25 AND Current User's role is Financeiro
Edita Order.billing_scheduled_date_override + Order.regra_dia25_override_motivo no Bubble. Reconciler propaga no próximo tick (ou clica “Forçar sync” pra imediato).
Card “Sincronização Omie” (4 colunas)
Group com 4 sub-grupos: cliente / projeto / OS / NFS-e
Cada um: check se omie_*_id is not empty, spinner se aguarda, x se last_sync_error_code mapeia
Cada delta detectado pelo reconciler (ou ação dentro da sequência Omie) gera um PATCH específico. Útil pra debugar “quem escreveu o quê e quando” via last_sync_endpoint + sync_correlation_id.
status_pedido=cancelado. Se NF emitida: dispara CancelarNFSe → status_faturamento=nf_cancelada. Se pré-NF: status_faturamento mantido + OS cancelada na Omie.
Reconciler detecta delta.billing_scheduled_date_override (operador editou no Bubble)