> ## Documentation Index
> Fetch the complete documentation index at: https://help.treble.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Sincronização Incremental

> Mantenha uma cópia dos seus dados da Treble nos seus próprios sistemas, de forma confiável, usando o watermark synced_at.

# Sincronizando o warehouse com os seus próprios sistemas

Se você se conecta via JDBC/ODBC para replicar os dados do warehouse no seu próprio banco de dados ou lake, **você não precisa de re-downloads completos periódicos**. Todas as tabelas expõem `synced_at` — o momento em que cada linha foi gravada ou corrigida pela última vez — projetado exatamente para extração incremental.

## O padrão

Mantenha um watermark (`T_prev`) por tabela no seu sistema e, a cada ciclo de sincronização:

```text theme={null}
1. Congele o corte:     T = max(synced_at) da tabela   (uma query, use o NOSSO relógio)
2. Extraia o delta:     WHERE synced_at > {T_prev} AND synced_at <= {T}
3. UPSERT pela chave:   insira linhas novas, substitua as existentes pelo seu id
4. Atualize a janela quente: re-extraia os últimos 3 dias por data do evento e substitua
                        essa fatia por completo na sua cópia
5. Avance:              T_prev = T   (somente depois que os passos 2–4 tiverem sucesso)
```

### Por que cada passo importa

* **Congele `T` uma única vez (passo 1).** Usar `now()` dentro das suas queries faz com que cada página de uma extração longa veja um instante diferente. Congelar um único timestamp torna a extração inteira um snapshot consistente.
* **UPSERT, nunca INSERT cego (passo 3).** Quando o warehouse corrige uma linha (um status de entrega chega, um id de CRM atrasado aparece), ele reemite a **mesma chave de negócio** com um `synced_at` novo. Um upsert substitui a sua versão desatualizada; um insert cego a duplicaria. A chave de cada tabela é sua coluna `*_id` (`session_id`, `message_id`, `deployment_id`, …).
* **Substitua a janela quente (passo 4).** Em casos raros, uma linha pode *desaparecer* de uma tabela (por exemplo, uma duplicata criada por uma correção interna sendo limpa). Uma query pode retornar o que existe — ela não pode te dizer o que deixou de existir. Re-extrair uma janela recente curta por data do evento (`created_at` / `scheduled_at`) e substituir essa fatia na sua cópia garante que seus dados batam com os nossos, incluindo remoções. Três dias é uma janela confortável; todas as correções acontecem em até 48 horas.

### Ciclo de referência (exemplo: envios de campanha)

```sql theme={null}
-- passo 1
SELECT max(synced_at) FROM fact_campaign_sends;   -- => {T}

-- passo 2 (depois faça UPSERT por deployment_id do seu lado)
SELECT *
FROM fact_campaign_sends
WHERE synced_at > {T_prev} AND synced_at <= {T};

-- passo 4 (substitua esta fatia por completo na sua cópia)
SELECT *
FROM fact_campaign_sends
WHERE scheduled_at >= today() - 3 AND synced_at <= {T};
```

## Carga inicial

A primeira sincronização é o mesmo mecanismo com `T_prev` em zero: extraia tudo com `synced_at <= T`, em blocos delimitados por data se a tabela for grande, e então comece a ciclar. Sem caso especial.

## O que não fazer

* **Não re-baixe o histórico de forma programada** — dados consolidados (com mais de 48 horas) são imutáveis; re-extraí-los é puro custo.
* **Não construa cortes a partir do seu próprio relógio** — sempre compare contra valores de `synced_at` lidos do warehouse.
* **Não pule o upsert** — correções são um recurso, não uma anomalia; sua cópia deve absorvê-las.

## Escolhendo uma cadência

Qualquer cadência funciona — o watermark torna os ciclos independentes. A cada 15–60 minutos acompanha a própria atualização do warehouse; de hora em hora ou diariamente é suficiente para cópias de relatórios. O custo de cada ciclo é proporcional ao que mudou, não ao tamanho do seu histórico.
