# Integração Frontend ↔ Tauri (Rust) ↔ Supabase ## Visão geral da comunicação ``` ┌─────────────────┐ ┌─────────────────┐ ┌──────────────────┐ │ JavaScript │ invoke │ Tauri/Rust │ HTTP │ Supabase │ │ (index.html) │────────▶│ commands │────────▶│ (cloud) │ │ │◀────────│ │◀────────│ │ └─────────────────┘ response└─────────────────┘ response└──────────────────┘ ``` O frontend **nunca faz requisições HTTP direto** para o Supabase. Toda comunicação passa pelos comandos Tauri (Rust). --- ## Comandos Tauri disponíveis ### App | Comando | O que faz | |---------|-----------| | `get_loja` | Retorna a loja configurada | | `get_loja_fixa` | Retorna `"Uniao"`, `"Alianca"` ou `null` (se build fixa) | | `set_loja(loja)` | Define a loja (bloqueado se build fixa) | | `get_config` | Retorna config completo `{ loja, pdv_nome, operador_default, ... }` | | `set_config(cfg)` | Salva config | ### Storage (SQLite local) | Comando | O que faz | |---------|-----------| | `salvar_fechamento(estado)` | Salva estado completo no SQLite local | | `carregar_rascunho(loja, data)` | Retorna último rascunho para loja+data | | `listar_fechamentos(loja, limite)` | Lista fechamentos de uma loja | | `buscar_fechamento_por_id(id)` | Busca por ID local | | `pendentes_sync` | Retorna fechamentos que ainda não foram syncados | ### Supabase | Comando | O que faz | |---------|-----------| | `sb_salvar_fechamento(estado)` | Upsert no Supabase via service_role JWT | | `sb_carregar_rascunho(loja, data)` | Busca rascunho mais recente | | `sb_listar_recentes(loja, limite)` | Lista fechamentos recentes | | `sb_buscar_por_id(id)` | Busca por ID | | `sb_buscar_por_uuid(uuid)` | Busca por UUID | | `sb_buscar_por_id_fechamento(id_fechamento)` | Busca por chave natural | | `sb_atualizar_fechamento(id_fechamento, updates)` | PATCH campos específicos | | `sb_salvar_listas(loja, listas)` | Salva operadores/gerentes customizados | | `sb_carregar_listas(loja)` | Carrega listas salvas | | `sb_online` | Retorna `true`/`false` se Supabase está acessível | ### Printer | Comando | O que faz | |---------|-----------| | `detectar_impressora` | Detecta EPSON TM-T20 USB | | `configurar_impressora(caminho)` | Define caminho da impressora | | `caminho_impressora` | Retorna caminho configurado | | `imprimir_recibo(html)` | Envia HTML puro para impressora | | `teste_impressora` | Imprime página de teste | | `ativar_modo_teste_impressao` | Ativa modo teste (salva PDF em vez de imprimir) | --- ## Fluxo de salvar um fechamento ```javascript // No frontend (index.html), quando operador clica "Salvar": async function salvarFechamento() { const estado = buildEstado(); // coleta todos os campos do formulário // 1. Salva localmente (sempre funciona offline) await invoke('salvar_fechamento', { estado }); // 2. Tenta sync com Supabase try { await invoke('sb_salvar_fechamento', { estado }); toast('✅ Salvo e sincronizado'); } catch(e) { // Supabase offline — fica pendente no SQLite toast('💾 Salvo localmente (sync pendente)'); } } ``` --- ## Como o Rust conversa com o Supabase Em `supabase.rs`, o plugin usa `reqwest` (HTTP client) com: ```rust fn headers(&self, use_service: bool) -> reqwest::header::HeaderMap { let key = if use_service { &self.service_role_key } else { &self.anon_key }; let mut headers = reqwest::header::HeaderMap::new(); headers.insert( reqwest::header::AUTHORIZATION, format!("Bearer {}", key).parse().unwrap(), ); headers } ``` - **`use_service = true`:** para INSERT/UPDATE (salvar fechamento) - **`use_service = false`:** para GET (listar, buscar) --- ## Upsert — salvar sem duplicar O Supabase não tem UPSERT nativo via REST. O plugin usa um truque: ```http POST /fechamentos_web HTTP/1.1 Prefer: resolution=merge-duplicates ``` Se o `id_fechamento` já existe, o PostgREST faz um UPDATE em vez de INSERT. Se não existe, faz INSERT. --- ## UUID vs id_fechamento | Campo | O que é | Quem gera | |-------|---------|-----------| | `id` | ID sequencial do PostgreSQL | Supabase (auto) | | `uuid` | UUID único do registro local | Frontend JS (`crypto.randomUUID()`) | | `id_fechamento` | Chave natural: `{loja}_{data}_{operador}` | Frontend JS (construído na hora) | O `id_fechamento` é a chave de negócio. O `uuid` é para rastrear registros entre local e cloud. --- ## Offline first — como funciona 1. **Operador/edita** → `salvar_fechamento` → SQLite (sempre funciona) 2. **Operador/edita** → `sb_salvar_fechamento` → Supabase (só se online) 3. **Se offline:** o fechamento fica no SQLite com `sync_status = "local"` 4. **Quando conecta:** `pendentes_sync` retorna os pendentes → sync automático O sync automático é controlado por `sync_automatico` na config da app.