5.1 KiB
5.1 KiB
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
// 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:
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:
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
- Operador/edita →
salvar_fechamento→ SQLite (sempre funciona) - Operador/edita →
sb_salvar_fechamento→ Supabase (só se online) - Se offline: o fechamento fica no SQLite com
sync_status = "local" - Quando conecta:
pendentes_syncretorna os pendentes → sync automático
O sync automático é controlado por sync_automatico na config da app.