Informe seu e-mail e enviaremos um link para criar uma nova senha.
Dashboard
DoPampa3D Manager
⚙️ Configuração do Supabase
Cole as credenciais do seu projeto Supabase para conectar o sistema ao banco de dados na nuvem.
🔔 Notificações de Estoque Baixo
Quando algum filamento estiver em nível crítico, o navegador pode te avisar com uma notificação — mesmo se o app estiver em outra aba (mas precisa estar aberto em algum lugar; não funciona com o app fechado). Verificação feita 1x por dia, ao carregar os dados.
💸 Taxas de Marketplace (Shopee / Mercado Livre)
Usadas na aba Análise de Mercado para calcular quanto realmente sobra de um preço anunciado. Estrutura escalonada por faixa de preço, vigente desde a reforma de mar/2026. Essas taxas mudam de tempos em tempos — atualize aqui quando precisar.
🛍️ Shopee — comissão por faixa de preço
Abaixo de R$8
sem taxa fixa (é % do preço)
R$8 – R$79,99
R$80 – R$99,99
R$100 – R$199,99
Acima de R$200
🟡 Mercado Livre
A comissão real varia por categoria (Clássico ~11–14%, Premium ~16–19%). Os valores abaixo são uma média de mercado — confirme a % exata da sua categoria no Seller Center quando puder.
Acima de R$79,99 o ML não cobra custo fixo, mas o frete grátis passa a ser por sua conta — por isso esse campo separado.
💾 Backup Completo dos Dados
Baixa um arquivo .json com tudo o que está no sistema: filamentos, catálogo, clientes, pedidos e dados de expositores (se o módulo estiver ativo). Guarde esse arquivo periodicamente como cópia de segurança, além do que já fica no Supabase.
🏷️ Marca & Documentos
Esses dados aparecem no cabeçalho dos recibos, comprovantes de pedido e relatórios exportados. Ficam salvos neste navegador.
🖼️
Cole o link direto da imagem do Imgur, ou envie um arquivo do seu computador abaixo — o que for preenchido por último vale.
🔐 E-mail do Administrador
Somente este e-mail terá acesso a este painel. Qualquer outro usuário cadastrado no Supabase será bloqueado.
⚠️ Importante: O e-mail é salvo na tabela sistema_config do Supabase. Se ainda não rodou o SQL dos expositores, faça isso primeiro para que essa tabela exista.
🗄️ Criar Tabelas no Supabase
No painel do Supabase, vá em SQL Editor → New query e cole o SQL abaixo. Execute uma vez e as tabelas estarão prontas.
-- 1. Filamentos
CREATE TABLE filamentos (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
marca text NOT NULL,
cor text NOT NULL,
cor_hex text DEFAULT '#ffffff',
tipo text NOT NULL DEFAULT 'PLA',
peso_total integer NOT NULL DEFAULT 1000,
peso_restante integer NOT NULL DEFAULT 1000,
preco_kg numeric(10,2) NOT NULL DEFAULT 0,
preco_total numeric(10,2) DEFAULT 0,
pago_status text DEFAULT 'pendente',
alerta_g integer NOT NULL DEFAULT 200,
ativo boolean DEFAULT true,
created_at timestamptz DEFAULT now()
);
-- 2. Catálogo de produtos
CREATE TABLE catalogo (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
nome text NOT NULL,
descricao text,
foto_url text,
fotos jsonb DEFAULT '[]',
tempo_horas numeric(6,2) DEFAULT 0,
peso_g numeric(8,2) DEFAULT 0,
custo numeric(10,2) DEFAULT 0,
preco_venda numeric(10,2) DEFAULT 0,
tipo text DEFAULT 'PLA',
categoria text,
largura numeric(8,2) DEFAULT 0,
altura numeric(8,2) DEFAULT 0,
profundidade numeric(8,2) DEFAULT 0,
filamentos_ids jsonb DEFAULT '[]',
ativo boolean DEFAULT true,
qtd_unidade integer DEFAULT 1,
created_at timestamptz DEFAULT now()
);
-- 3. Clientes
CREATE TABLE clientes (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
nome text NOT NULL,
telefone text,
email text,
endereco text,
cidade text,
estado text DEFAULT 'RS',
total_gasto numeric(10,2) DEFAULT 0,
ativo boolean DEFAULT true,
created_at timestamptz DEFAULT now()
);
-- 4. Pedidos
CREATE TABLE pedidos (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
numero serial,
cliente_id uuid REFERENCES clientes(id),
cliente_nome text,
produto_nome text,
catalogo_id uuid REFERENCES catalogo(id),
filamento_id uuid REFERENCES filamentos(id),
filamento_nome text,
filamentos_usados jsonb DEFAULT '[]',
quantidade integer DEFAULT 1,
peso_total_g numeric(8,2) DEFAULT 0,
valor numeric(10,2) DEFAULT 0,
desconto numeric(10,2) DEFAULT 0,
status text DEFAULT 'feito',
pago text DEFAULT 'nao',
rastreio text,
observacoes text,
largura numeric(8,2) DEFAULT 0,
altura numeric(8,2) DEFAULT 0,
profundidade numeric(8,2) DEFAULT 0,
created_at timestamptz DEFAULT now(),
updated_at timestamptz DEFAULT now()
);
-- 5. RLS: habilitar e liberar acesso total para usuários autenticados
ALTER TABLE filamentos ENABLE ROW LEVEL SECURITY;
ALTER TABLE catalogo ENABLE ROW LEVEL SECURITY;
ALTER TABLE clientes ENABLE ROW LEVEL SECURITY;
ALTER TABLE pedidos ENABLE ROW LEVEL SECURITY;
-- Policies: qualquer usuário autenticado pode ler e escrever
CREATE POLICY "acesso_autenticado" ON filamentos FOR ALL TO authenticated USING (true) WITH CHECK (true);
CREATE POLICY "acesso_autenticado" ON catalogo FOR ALL TO authenticated USING (true) WITH CHECK (true);
CREATE POLICY "acesso_autenticado" ON clientes FOR ALL TO authenticated USING (true) WITH CHECK (true);
CREATE POLICY "acesso_autenticado" ON pedidos FOR ALL TO authenticated USING (true) WITH CHECK (true);
🔧 Migração / Correção de Erros
Se você já criou as tabelas e está recebendo erros como "violates row-level security policy" ou "column not found in schema cache", execute este SQL no Supabase → SQL Editor para corrigir tudo de uma vez:
-- ══ MIGRAÇÃO COMPLETA ══
-- Execute no Supabase → SQL Editor
-- Seguro para rodar mesmo se as colunas já existirem
-- 1. Adicionar colunas que possam estar faltando em filamentos
ALTER TABLE filamentos ADD COLUMN IF NOT EXISTS pago_status text DEFAULT 'pendente';
ALTER TABLE filamentos ADD COLUMN IF NOT EXISTS preco_total numeric(10,2) DEFAULT 0;
ALTER TABLE filamentos ADD COLUMN IF NOT EXISTS cor_hex text DEFAULT '#ffffff';
ALTER TABLE filamentos ADD COLUMN IF NOT EXISTS alerta_g integer NOT NULL DEFAULT 200;
ALTER TABLE filamentos ADD COLUMN IF NOT EXISTS ativo boolean DEFAULT true;
-- 2. Adicionar colunas que possam estar faltando em catalogo
ALTER TABLE catalogo ADD COLUMN IF NOT EXISTS filamentos_ids jsonb DEFAULT '[]';
ALTER TABLE catalogo ADD COLUMN IF NOT EXISTS foto_url text;
ALTER TABLE catalogo ADD COLUMN IF NOT EXISTS fotos jsonb DEFAULT '[]';
ALTER TABLE catalogo ADD COLUMN IF NOT EXISTS largura numeric(8,2) DEFAULT 0;
ALTER TABLE catalogo ADD COLUMN IF NOT EXISTS altura numeric(8,2) DEFAULT 0;
ALTER TABLE catalogo ADD COLUMN IF NOT EXISTS profundidade numeric(8,2) DEFAULT 0;
ALTER TABLE catalogo ADD COLUMN IF NOT EXISTS ativo boolean DEFAULT true;
ALTER TABLE catalogo ADD COLUMN IF NOT EXISTS categoria text;
ALTER TABLE catalogo ADD COLUMN IF NOT EXISTS qtd_unidade integer DEFAULT 1;
-- 3. Adicionar colunas que possam estar faltando em pedidos
ALTER TABLE pedidos ADD COLUMN IF NOT EXISTS catalogo_id uuid REFERENCES catalogo(id);
ALTER TABLE pedidos ADD COLUMN IF NOT EXISTS filamento_id uuid REFERENCES filamentos(id);
ALTER TABLE pedidos ADD COLUMN IF NOT EXISTS filamento_nome text;
ALTER TABLE pedidos ADD COLUMN IF NOT EXISTS filamentos_usados jsonb DEFAULT '[]';
ALTER TABLE pedidos ADD COLUMN IF NOT EXISTS rastreio text;
ALTER TABLE pedidos ADD COLUMN IF NOT EXISTS observacoes text;
ALTER TABLE pedidos ADD COLUMN IF NOT EXISTS largura numeric(8,2) DEFAULT 0;
ALTER TABLE pedidos ADD COLUMN IF NOT EXISTS altura numeric(8,2) DEFAULT 0;
ALTER TABLE pedidos ADD COLUMN IF NOT EXISTS profundidade numeric(8,2) DEFAULT 0;
ALTER TABLE pedidos ADD COLUMN IF NOT EXISTS updated_at timestamptz DEFAULT now();
-- 4. Adicionar colunas que possam estar faltando em clientes
ALTER TABLE clientes ADD COLUMN IF NOT EXISTS total_gasto numeric(10,2) DEFAULT 0;
ALTER TABLE clientes ADD COLUMN IF NOT EXISTS ativo boolean DEFAULT true;
-- 4b. Desconto por pedido
ALTER TABLE pedidos ADD COLUMN IF NOT EXISTS desconto numeric(10,2) DEFAULT 0;
ALTER TABLE pedidos ADD COLUMN IF NOT EXISTS custo_material numeric(10,2);
-- 4c. Termos de recebimento em consignação (faltava esta tabela)
CREATE TABLE IF NOT EXISTS expositor_recebimentos (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
expositor_id UUID REFERENCES expositores(id) ON DELETE CASCADE,
itens JSONB DEFAULT '[]',
status TEXT DEFAULT 'pendente',
criado_em TIMESTAMPTZ DEFAULT now(),
aceito_por_nome TEXT,
aceito_em TIMESTAMPTZ
);
ALTER TABLE expositor_recebimentos ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS "acesso_autenticado" ON expositor_recebimentos;
CREATE POLICY "acesso_autenticado" ON expositor_recebimentos FOR ALL TO authenticated USING (true) WITH CHECK (true);
-- 5. Corrigir RLS — habilitar e criar policies para usuários autenticados
ALTER TABLE filamentos ENABLE ROW LEVEL SECURITY;
ALTER TABLE catalogo ENABLE ROW LEVEL SECURITY;
ALTER TABLE clientes ENABLE ROW LEVEL SECURITY;
ALTER TABLE pedidos ENABLE ROW LEVEL SECURITY;
-- Remover policies antigas se existirem (evita erro de duplicata)
DROP POLICY IF EXISTS "acesso_autenticado" ON filamentos;
DROP POLICY IF EXISTS "acesso_autenticado" ON catalogo;
DROP POLICY IF EXISTS "acesso_autenticado" ON clientes;
DROP POLICY IF EXISTS "acesso_autenticado" ON pedidos;
-- Criar policies novas
CREATE POLICY "acesso_autenticado" ON filamentos FOR ALL TO authenticated USING (true) WITH CHECK (true);
CREATE POLICY "acesso_autenticado" ON catalogo FOR ALL TO authenticated USING (true) WITH CHECK (true);
CREATE POLICY "acesso_autenticado" ON clientes FOR ALL TO authenticated USING (true) WITH CHECK (true);
CREATE POLICY "acesso_autenticado" ON pedidos FOR ALL TO authenticated USING (true) WITH CHECK (true);
🏪 SQL — Módulo Expositores
Se você ainda não criou as tabelas de expositores, rode este SQL no Supabase → SQL Editor. Substitua SEU_EMAIL@AQUI.COM pelo seu e-mail antes de executar.
-- 1. Tabela de expositores (lojas parceiras)
CREATE TABLE IF NOT EXISTS expositores (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
nome_loja TEXT NOT NULL,
responsavel TEXT,
telefone TEXT,
endereco TEXT,
email_acesso TEXT,
ativo BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT now()
);
-- 2. Estoque vinculado a cada expositor
CREATE TABLE IF NOT EXISTS expositor_estoque (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
expositor_id UUID REFERENCES expositores(id) ON DELETE CASCADE,
catalogo_id UUID REFERENCES catalogo(id) ON DELETE CASCADE,
quantidade_inicial INTEGER DEFAULT 0,
quantidade_atual INTEGER DEFAULT 0,
preco_venda NUMERIC(10,2) DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT now(),
updated_at TIMESTAMPTZ DEFAULT now()
);
-- 3. Histórico de movimentações (com campos extras para venda)
CREATE TABLE IF NOT EXISTS expositor_movimentacoes (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
expositor_id UUID REFERENCES expositores(id) ON DELETE CASCADE,
estoque_id UUID REFERENCES expositor_estoque(id) ON DELETE CASCADE,
tipo TEXT CHECK (tipo IN ('saida','entrada','ajuste','venda','cancelado')) NOT NULL,
quantidade INTEGER NOT NULL,
observacao TEXT,
cliente_nome TEXT,
status_pagamento TEXT,
valor_total NUMERIC(10,2) DEFAULT 0,
desconto_aplicado NUMERIC(10,2) DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT now(),
updated_at TIMESTAMPTZ DEFAULT now()
);
-- 4. Configurações do sistema (admin_email e outras)
CREATE TABLE IF NOT EXISTS sistema_config (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
chave TEXT UNIQUE NOT NULL,
valor TEXT,
updated_at TIMESTAMPTZ DEFAULT now()
);
-- Inserir registro do e-mail admin (substitua pelo seu e-mail real)
INSERT INTO sistema_config (chave, valor)
VALUES ('admin_email', 'SEU_EMAIL@AQUI.COM')
ON CONFLICT (chave) DO NOTHING;
-- 5. RLS — acesso total para usuários autenticados (admin gerencia tudo)
ALTER TABLE expositores ENABLE ROW LEVEL SECURITY;
ALTER TABLE expositor_estoque ENABLE ROW LEVEL SECURITY;
ALTER TABLE expositor_movimentacoes ENABLE ROW LEVEL SECURITY;
ALTER TABLE sistema_config ENABLE ROW LEVEL SECURITY;
-- Remover policies antigas se existirem (evita erro de duplicata)
DROP POLICY IF EXISTS "expositor_own" ON expositores;
DROP POLICY IF EXISTS "estoque_own" ON expositor_estoque;
DROP POLICY IF EXISTS "movimentacao_own" ON expositor_movimentacoes;
DROP POLICY IF EXISTS "admin_expositores" ON expositores;
DROP POLICY IF EXISTS "admin_estoque" ON expositor_estoque;
DROP POLICY IF EXISTS "admin_movimentacoes" ON expositor_movimentacoes;
DROP POLICY IF EXISTS "acesso_autenticado" ON expositores;
DROP POLICY IF EXISTS "acesso_autenticado" ON expositor_estoque;
DROP POLICY IF EXISTS "acesso_autenticado" ON expositor_movimentacoes;
DROP POLICY IF EXISTS "acesso_autenticado" ON sistema_config;
-- Policies: qualquer usuário autenticado pode ler e escrever
CREATE POLICY "acesso_autenticado" ON expositores
FOR ALL TO authenticated USING (true) WITH CHECK (true);
CREATE POLICY "acesso_autenticado" ON expositor_estoque
FOR ALL TO authenticated USING (true) WITH CHECK (true);
CREATE POLICY "acesso_autenticado" ON expositor_movimentacoes
FOR ALL TO authenticated USING (true) WITH CHECK (true);
-- sistema_config: qualquer autenticado lê, mas só o admin (verificado no app) escreve
CREATE POLICY "acesso_autenticado" ON sistema_config
FOR ALL TO authenticated USING (true) WITH CHECK (true);
💰 SQL Financeiro Extra (sincroniza entre dispositivos)
Execute no Supabase → SQL Editor para criar as tabelas de Retiradas Pessoais, Pagamentos Avulsos e Despesas de Equipamento. Sem isso, esses registros ficam salvos só neste navegador.
-- 1. Retiradas para conta pessoal (Nubank)
CREATE TABLE IF NOT EXISTS retiradas_pessoais (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
valor numeric(10,2) NOT NULL DEFAULT 0,
data date DEFAULT CURRENT_DATE,
observacao text,
created_at timestamptz DEFAULT now()
);
-- 2. Pagamentos avulsos de dívidas (filamento ou geral)
CREATE TABLE IF NOT EXISTS pagamentos_avulsos (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
filamento_id uuid REFERENCES filamentos(id),
filamento_nome text,
descricao text,
valor numeric(10,2) NOT NULL DEFAULT 0,
data date DEFAULT CURRENT_DATE,
created_at timestamptz DEFAULT now()
);
-- 3. Despesas de equipamento (impressora, ferramentas, manutenção)
CREATE TABLE IF NOT EXISTS despesas_equipamento (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
descricao text NOT NULL,
valor numeric(10,2) NOT NULL DEFAULT 0,
data date DEFAULT CURRENT_DATE,
created_at timestamptz DEFAULT now()
);
-- 4. RLS: habilitar e liberar acesso total para usuários autenticados
ALTER TABLE retiradas_pessoais ENABLE ROW LEVEL SECURITY;
ALTER TABLE pagamentos_avulsos ENABLE ROW LEVEL SECURITY;
ALTER TABLE despesas_equipamento ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS "acesso_autenticado" ON retiradas_pessoais;
DROP POLICY IF EXISTS "acesso_autenticado" ON pagamentos_avulsos;
DROP POLICY IF EXISTS "acesso_autenticado" ON despesas_equipamento;
CREATE POLICY "acesso_autenticado" ON retiradas_pessoais FOR ALL TO authenticated USING (true) WITH CHECK (true);
CREATE POLICY "acesso_autenticado" ON pagamentos_avulsos FOR ALL TO authenticated USING (true) WITH CHECK (true);
CREATE POLICY "acesso_autenticado" ON despesas_equipamento FOR ALL TO authenticated USING (true) WITH CHECK (true);
🔎 SQL Análise de Mercado
Execute no Supabase → SQL Editor para criar a tabela do histórico de análises e das taxas de marketplace (Shopee/Mercado Livre).
-- 1. Histórico de análises de mercado
CREATE TABLE IF NOT EXISTS analises_mercado (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
catalogo_id uuid REFERENCES catalogo(id),
nome_produto text NOT NULL,
link text,
marketplace text DEFAULT 'nenhum',
ml_modalidade text DEFAULT 'classico',
preco_concorrente numeric(10,2) NOT NULL DEFAULT 0,
meu_custo numeric(10,2) NOT NULL DEFAULT 0,
meu_preco_venda numeric(10,2) DEFAULT 0,
data date DEFAULT CURRENT_DATE,
observacao text,
created_at timestamptz DEFAULT now()
);
-- 2. Taxas de marketplace (linha única, configurável) — faixas Shopee/ML vigentes desde mar/2026
CREATE TABLE IF NOT EXISTS taxas_marketplace (
id int PRIMARY KEY DEFAULT 1,
-- Shopee: comissão escalonada por faixa de preço
shopee_pct_f1 numeric(5,2) DEFAULT 50, -- < R$8 (sem taxa fixa)
shopee_pct_f2 numeric(5,2) DEFAULT 20, -- R$8 – R$79,99
shopee_fixa_f2 numeric(10,2) DEFAULT 4,
shopee_pct_f3 numeric(5,2) DEFAULT 14, -- R$80 – R$99,99
shopee_fixa_f3 numeric(10,2) DEFAULT 16,
shopee_pct_f4 numeric(5,2) DEFAULT 14, -- R$100 – R$199,99
shopee_fixa_f4 numeric(10,2) DEFAULT 20,
shopee_pct_f5 numeric(5,2) DEFAULT 14, -- >= R$200
shopee_fixa_f5 numeric(10,2) DEFAULT 26,
shopee_taxa_campanha_pct numeric(5,2) DEFAULT 2.5, -- cobrada de todo vendedor
shopee_cpf_alto_volume boolean DEFAULT false, -- CPF com +450 pedidos/90 dias
shopee_taxa_cpf_extra numeric(10,2) DEFAULT 3,
shopee_frete numeric(10,2) DEFAULT 0,
-- Mercado Livre: comissão por modalidade + custo fixo estimado até R$79,99
ml_comissao_classico_pct numeric(5,2) DEFAULT 12,
ml_comissao_premium_pct numeric(5,2) DEFAULT 17,
ml_custo_fixo_baixo numeric(10,2) DEFAULT 5.5, -- até R$20
ml_custo_fixo_alto numeric(10,2) DEFAULT 6.75, -- R$20 – R$79,99
ml_frete numeric(10,2) DEFAULT 0,
-- colunas antigas (modelo simples), mantidas por compatibilidade, não são mais usadas
shopee_comissao_pct numeric(5,2) DEFAULT 20,
shopee_taxa_fixa numeric(10,2) DEFAULT 4,
ml_comissao_pct numeric(5,2) DEFAULT 16,
ml_taxa_fixa numeric(10,2) DEFAULT 6,
updated_at timestamptz DEFAULT now()
);
INSERT INTO taxas_marketplace (id) VALUES (1) ON CONFLICT (id) DO NOTHING;
-- 2b. Migração: se a tabela já existia com o modelo antigo, isso adiciona as colunas novas sem apagar nada
ALTER TABLE taxas_marketplace ADD COLUMN IF NOT EXISTS shopee_pct_f1 numeric(5,2) DEFAULT 50;
ALTER TABLE taxas_marketplace ADD COLUMN IF NOT EXISTS shopee_pct_f2 numeric(5,2) DEFAULT 20;
ALTER TABLE taxas_marketplace ADD COLUMN IF NOT EXISTS shopee_fixa_f2 numeric(10,2) DEFAULT 4;
ALTER TABLE taxas_marketplace ADD COLUMN IF NOT EXISTS shopee_pct_f3 numeric(5,2) DEFAULT 14;
ALTER TABLE taxas_marketplace ADD COLUMN IF NOT EXISTS shopee_fixa_f3 numeric(10,2) DEFAULT 16;
ALTER TABLE taxas_marketplace ADD COLUMN IF NOT EXISTS shopee_pct_f4 numeric(5,2) DEFAULT 14;
ALTER TABLE taxas_marketplace ADD COLUMN IF NOT EXISTS shopee_fixa_f4 numeric(10,2) DEFAULT 20;
ALTER TABLE taxas_marketplace ADD COLUMN IF NOT EXISTS shopee_pct_f5 numeric(5,2) DEFAULT 14;
ALTER TABLE taxas_marketplace ADD COLUMN IF NOT EXISTS shopee_fixa_f5 numeric(10,2) DEFAULT 26;
ALTER TABLE taxas_marketplace ADD COLUMN IF NOT EXISTS shopee_taxa_campanha_pct numeric(5,2) DEFAULT 2.5;
ALTER TABLE taxas_marketplace ADD COLUMN IF NOT EXISTS shopee_cpf_alto_volume boolean DEFAULT false;
ALTER TABLE taxas_marketplace ADD COLUMN IF NOT EXISTS shopee_taxa_cpf_extra numeric(10,2) DEFAULT 3;
ALTER TABLE taxas_marketplace ADD COLUMN IF NOT EXISTS ml_comissao_classico_pct numeric(5,2) DEFAULT 12;
ALTER TABLE taxas_marketplace ADD COLUMN IF NOT EXISTS ml_comissao_premium_pct numeric(5,2) DEFAULT 17;
ALTER TABLE taxas_marketplace ADD COLUMN IF NOT EXISTS ml_custo_fixo_baixo numeric(10,2) DEFAULT 5.5;
ALTER TABLE taxas_marketplace ADD COLUMN IF NOT EXISTS ml_custo_fixo_alto numeric(10,2) DEFAULT 6.75;
-- 2c. Migração: análises de mercado precisam saber a modalidade do ML (Clássico/Premium) usada
ALTER TABLE analises_mercado ADD COLUMN IF NOT EXISTS ml_modalidade text DEFAULT 'classico';
-- 3. RLS
ALTER TABLE analises_mercado ENABLE ROW LEVEL SECURITY;
ALTER TABLE taxas_marketplace ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS "acesso_autenticado" ON analises_mercado;
DROP POLICY IF EXISTS "acesso_autenticado" ON taxas_marketplace;
CREATE POLICY "acesso_autenticado" ON analises_mercado FOR ALL TO authenticated USING (true) WITH CHECK (true);
CREATE POLICY "acesso_autenticado" ON taxas_marketplace FOR ALL TO authenticated USING (true) WITH CHECK (true);
🔗 Edge Function: Buscar Dados do Link
Opcional. Ativa o botão "🔗 Buscar dados" na Análise de Mercado, que tenta preencher nome e preço automaticamente a partir do link colado. Funciona bem no Mercado Livre; na Shopee normalmente não encontra nada (a página carrega os dados via JavaScript) — nesse caso você continua preenchendo à mão, sem problema.
1
No painel do Supabase, vá em Edge Functions (menu lateral) → Deploy a new function
2
Nome da função: extrair-produto (exatamente assim, com hífen)
3
Cole o código abaixo no editor e clique em Deploy (se já existir uma versão antiga, é só colar por cima e fazer deploy de novo — essa versão traz diagnóstico de erro)
4
Em Edge Functions → extrair-produto → Settings, marque a opção que permite chamadas sem JWT ("Enforce JWT verification" desligado) — ou, se preferir manter ligado, o app já envia sua sessão autenticada automaticamente
// supabase/functions/extrair-produto/index.ts
// Edge Function: recebe { url } e tenta extrair nome + preço da página.
// Se não conseguir achar nada, devolve informação de diagnóstico (status
// HTTP recebido + um trecho do HTML) pra entender se o site bloqueou o
// acesso (comum em Shopee/Mercado Livre quando o pedido não vem de um
// navegador de pessoa real).
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
};
function extrairMeta(html, propriedade) {
const re1 = new RegExp('<meta[^>]+property=["\']' + propriedade + '["\'][^>]+content=["\']([^"\']+)["\']', "i");
const re2 = new RegExp('<meta[^>]+content=["\']([^"\']+)["\'][^>]+property=["\']' + propriedade + '["\']', "i");
const m = html.match(re1) || html.match(re2);
return m ? m[1] : null;
}
function extrairMetaName(html, nome) {
const re1 = new RegExp('<meta[^>]+name=["\']' + nome + '["\'][^>]+content=["\']([^"\']+)["\']', "i");
const re2 = new RegExp('<meta[^>]+content=["\']([^"\']+)["\'][^>]+name=["\']' + nome + '["\']', "i");
const m = html.match(re1) || html.match(re2);
return m ? m[1] : null;
}
serve(async (req) => {
if (req.method === "OPTIONS") {
return new Response("ok", { headers: corsHeaders });
}
try {
const { url } = await req.json();
if (!url) throw new Error("URL não informada");
const resposta = await fetch(url, {
redirect: "follow",
headers: {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Language": "pt-BR,pt;q=0.9,en;q=0.8",
},
});
const html = await resposta.text();
const statusRecebido = resposta.status;
const urlFinal = resposta.url;
let nome = extrairMeta(html, "og:title") || extrairMetaName(html, "twitter:title");
let imagem = extrairMeta(html, "og:image");
let preco = extrairMeta(html, "product:price:amount") || extrairMeta(html, "og:price:amount");
// Tenta achar preço/nome em blocos JSON-LD (schema.org Product/Offer),
// comum no Mercado Livre.
if (!preco || !nome) {
const blocosLd = [...html.matchAll(/<script[^>]+type=["']application\/ld\+json["'][^>]*>([\s\S]*?)<\/script>/gi)];
for (const bloco of blocosLd) {
try {
const parsed = JSON.parse(bloco[1]);
const itens = Array.isArray(parsed) ? parsed : [parsed];
for (const item of itens) {
const offers = item.offers || (item["@graph"] && item["@graph"].find((g) => g.offers)?.offers);
if (offers) {
preco = preco || offers.price || offers.lowPrice;
nome = nome || item.name;
const img = item.image;
imagem = imagem || (Array.isArray(img) ? img[0] : img);
}
}
} catch (_erro) {
// ignora bloco JSON-LD malformado e segue tentando os próximos
}
}
}
const achouAlgo = Boolean(nome || preco);
// Log no painel (Edge Functions → extrair-produto → Logs) pra facilitar diagnóstico
console.log("URL pedida:", url, "| status recebido:", statusRecebido, "| url final:", urlFinal, "| achou nome:", Boolean(nome), "| achou preço:", Boolean(preco));
const resultado = { nome, preco, imagem, ok: achouAlgo };
// Se não achou nada, devolve pistas de diagnóstico (sem quebrar o app —
// o front-end só usa isso pra mostrar uma mensagem melhor)
if (!achouAlgo) {
resultado.debugStatus = statusRecebido;
resultado.debugUrlFinal = urlFinal;
resultado.debugSnippet = html.slice(0, 300).replace(/\s+/g, " ");
}
return new Response(JSON.stringify(resultado), {
headers: { ...corsHeaders, "Content-Type": "application/json" },
});
} catch (erro) {
return new Response(JSON.stringify({ error: erro.message }), {
status: 400,
headers: { ...corsHeaders, "Content-Type": "application/json" },
});
}
});
Vá em Project Settings → API e copie a Project URL e a anon public key
4
Cole as credenciais acima e clique em Salvar e Conectar
5
Vá em SQL Editor, cole o SQL acima e clique em Run
6
Pronto! Volte ao Dashboard e comece a usar.
Pedidos (mês)
—
por data de criação
Faturamento (mês)
—
por data de criação
Faturamento Total
—
todos os pedidos já realizados
Clientes
—
cadastrados
Filamentos
—
bobinas ativas
💸 A Pagar
—
investimentos pendentes
⚠️ Alertas de Estoque
Carregando...
🛒 Pedidos Recentes
#
Cliente
Produto
Valor
Status
Carregando...
🧵 Estoque de Filamentos
🔍
🧵
Nenhum filamento cadastrado ainda.
🗂️ Catálogo de Produtos
🔍
🗂️
Nenhum produto no catálogo.
🛒 Pedidos
🔍
#
Data
Cliente
Produto
Qtd
Valor
Lucro
Andamento
Pago
Rastreio
Carregando...
👤 Clientes
🔍
Nome
Telefone
Cidade/UF
Pedidos
TotalGasto
Carregando...
Total a Pagar
R$ 0,00
filamento + equipamentos pendentes
Filamentos (custo)
R$ 0,00
valor total investido
🛠️ Equipamentos (custo)
R$ 0,00
impressora, ferramentas etc.
Recuperado via Vendas
R$ 0,00
descontado por pedidos
Pago Avulso
R$ 0,00
pagamentos diretos
Saldo Restante
R$ 0,00
ainda a recuperar
🧵 Dívida Já Recuperada
R$ 0,00
custo já coberto pelas vendas
💰 Saldo em Caixa Disponível
R$ 0,00
livre pra retirar, após dívida quitada
💸 Total Retirado
R$ 0,00
já repassado pra conta pessoal
🧵 Investimentos em Filamentos
Filamento
Tipo
PesoTotal
Preço/kg
CustoTotal
Usado(g)
Status
Carregando...
🛠️ Despesas de Equipamento
💡 Registre aqui compras de impressora, ferramentas, manutenção etc. Esse valor entra na mesma dívida geral do filamento (soma no "Total a Pagar") e é recuperado junto com as vendas, até cobrir tudo que foi investido.
Data
Descrição
Valor
Nenhuma despesa de equipamento registrada.
🛍️ Sugestão de Recompra
Carregando...
🏆 Produtos Mais Vendidos
por quantidade vendida (exclui cancelados)
#
Produto
Unid. vendidas
Faturamento
Ticket médio
Carregando...
🔄 Giro de Estoque — quanto ainda dá pra produzir
com o filamento disponível hoje
💡 Calculado apenas para produtos com 1 filamento vinculado, onde a conta é exata (peso do filamento em estoque ÷ peso do produto). Produtos com múltiplos filamentos não entram aqui pois o consumo por filamento não é individualizado.
Produto
Filamento
Estoque do filamento
Unidades possíveis
Carregando...
🏦 Retiradas para Conta Pessoal (Nubank)
💡 Registre aqui quando você transfere dinheiro da conta da empresa pra sua conta pessoal. Cada retirada desconta do "Saldo em Caixa Disponível" acima.
Data
Observação / Motivo
Valor
Nenhuma retirada registrada.
💳 Pagamentos Avulsos de Dívidas
💡 Registre aqui pagamentos em dinheiro feitos para abater dívidas de filamentos. O saldo devedor geral é quitado pela soma de: pedidos marcados como "Pago" + estes pagamentos avulsos, até cobrir o custo total investido em filamento.
Data
Filamento
Descrição / Conta
Valor
Nenhum pagamento avulso registrado.
Total Faturado
R$ 0,00
todos os pedidos ativos
Total Recebido
R$ 0,00
pedidos marcados como pagos
A Receber
R$ 0,00
pedidos ainda não pagos
Mês Atual
R$ 0,00
faturado este mês
💎 Lucro Real (total)
R$ 0,00
vendas − custo de produção
💎 Lucro Real (mês atual)
R$ 0,00
apenas pedidos deste mês
🏭 Custo de Produção (total)
R$ 0,00
estimado via catálogo/filamentos
📈 Margem Média
0%
lucro ÷ faturamento
📊 Faturamento por Mês
Mês/Ano
Pedidos
Faturado
Recebido
Lucro
Pendente
% Recebido
Carregando...
📦 Pedidos e Pagamentos
#
Data
Cliente
Produto
Qtd
Valor
Lucro
Andamento
Pago?
Ações
Carregando...
⚡ Predefinições salvas
🧵
Filamento
Dados do rolo e do fatiador
R$/kg
g
g
Impressão multicolor (AMS / troca de filamento)
Insira cada cor separada. O peso aparece no Bambu Handy como PLA | Xg.
Cor/Filamento
Peso(g)
PreçoR$/kg
g
⏱
Impressão
Tempo e consumo de energia
h
min
W
R$/kWh
⚙️
Máquina e Consumíveis
Depreciação e desgaste — salvo automaticamente
R$
h
R$
h
Incluir desgaste da cama (PEI)
R$
h
📦
Embalagem e Envio
Custos de materiais de embalagem por pedido
Incluir custos de embalagem no cálculo
Informe o custo unitário de cada material usado por pedido. Deixe 0 nos que não usa.
R$
R$
R$
R$
R$
R$
Total embalagem:R$ 0,00
🗂️
Objetos na Mesa
Múltiplos modelos diferentes na mesma impressão
Impressão com múltiplos objetos diferentes
Modo atual: peça única ou lote idêntico. Use os campos de Filamento acima e Quantidade abaixo.
Modo múltiplos objetos: o tempo total é dividido proporcionalmente pelo peso.
Objeto
Modelo(g)
Suporte(g)
Qtd
📊
Falhas e Preço de Venda
%
un
%
🏪
Taxas de Plataforma e Frete
Descontadas do preço de venda — salvo automaticamente
%
Categoria selecionada
—
0%
Incluir custo de frete no cálculo
Informe o custo de frete que você paga. Pode ser valor fixo (R$) ou percentual sobre a venda.
R$
%
💡 Frete grátis ao cliente? O custo ainda existe. Inclua aqui para não comer sua margem.
Custo por peça
—
custo real total
Preço de venda
—
com margem aplicada
🔍
Detalhamento dos Custos
📦
Resumo do Lote
🗂️ Resultado por Objeto
📐 Dimensões do Objeto (mm) — opcional
mm
mm
mm
🏪 Lojas Parceiras
🔍
Loja
Responsável
Telefone
Endereço
Status
Termos
Criado em
Carregando...
📦 Estoque nos Expositores
Loja
Produto
Preço Venda
Inicial
Atual
Vendido
% Vendido
Valor Vendido
Carregando...
Total Saídas
—
unidades vendidas
Valor Vendido
—
receita nos expositores
Entradas
—
reposições registradas
📋 Histórico de Movimentações
Data
Loja
Produto
Tipo
Qtd
Observação
Carregando...
📜 Termos de Recebimento em Consignação
📜
Nenhum termo ainda.
🔎 Compare o preço de um produto no Shopee/Mercado Livre com o seu custo e preço de venda. O cálculo já desconta as taxas reais do marketplace (comissão escalonada por faixa de preço + taxa fixa + campanha/frete), configuráveis em Configuração → Taxas de Marketplace.
Análises Feitas
0
no histórico
🟢 Valem a Pena
0
margem real positiva
🔴 Não Valem
0
prejuízo após taxas
🔎 Histórico de Análises
Data
Produto
Marketplace
Preço Concorrente
Líquido (após taxas)
Meu Custo
Margem Real
Meu Preço
Competitividade
Nenhuma análise registrada ainda.
🛍️ Publicar no Catálogo Externo
✅ Este produto será salvo diretamente no Supabase e aparecerá no seu catálogo.html público.
R$
R$
g
h
📐 Dimensões (mm) — aparecem no catálogo
mm
mm
mm
📷 Clique para adicionar uma foto JPG, PNG ou WebP
A foto é salva como base64. Para fotos grandes, use URL externa no campo abaixo.
👁️ Visível no catálogo público
✅ O produto aparecerá no catalogo.html para os clientes verem.
🧵 Novo Filamento
🗂️ Novo Produto
Adicione quantas fotos quiser. A primeira da lista é a capa (usada nas tabelas e recibos) — use ↑ ↓ para reordenar. Na loja, todas aparecem em um carrossel.
🧮 Calculadora de Custo Integrada
R$/kg
g
h
min
%
%
Custo calculado:—Preço sugerido:—
un
Ex: se o preço acima é de um kit com 2 suportes, coloque 2. Isso aparece na loja como "Kit com 2 unidades".
📐 Dimensões do Produto (mm)
mm
mm
mm
🧵 Filamentos deste Produto
Selecione os filamentos que compõem este produto. Isso ajuda no controle financeiro.
👁️ Visível no catálogo público
✅ O produto aparecerá no catalogo.html para os clientes verem.
👤 Novo Cliente
📜 Histórico de Pedidos
#
Data
Produto
Qtd
Valor
Status
Pago
—
🛒 Novo Pedido
🧵 Filamentos Utilizados
Adicione cada filamento com o peso gasto. Suporta multicolor / AMS.
Filamento
Peso(g)
Peso total: 0g
Preço cheio:
mm
mm
mm
⚠️ Após salvar, o peso de cada filamento será descontado do estoque automaticamente.
📋 Cadastro em Massa — Produtos
Preencha uma linha por produto. Nome e Preço de venda são obrigatórios — o resto é opcional e pode ser completado depois no catálogo.
📋 Cadastro em Massa — Pedidos
Cole uma linha por pedido. Colunas separadas por ; (ponto e vírgula): Cliente ; Produto ; Valor ; Quantidade ; Status ; Pago ; Rastreio ; Observações Cliente, Produto e Valor são obrigatórios.
Status: feito / andamento / pronto / entregue / cancelado | Pago: sim / nao / parcial
Exemplo: João Silva ; Chaveiro Gato ; 25 ; 2 ; feito ; nao ; ; Cor verde
#
Cliente
Produto
Valor
Qtd
Status
Pago
Rastreio
Obs
Status
🏪 Nova Loja Parceira
⚠️ O e-mail precisa ser criado antes no Supabase → Authentication → Invite user. Cole o mesmo e-mail aqui para vinculação automática.
📦 Vincular Produto ao Expositor
💡 O custo definido aqui será visível (mas não editável) pelo expositor na loja, para calcular a comissão.
📦 Registrar Movimentação
✍️ Confirmar Recebimento
"Declaro que recebi os produtos acima listados em consignação, comprometendo-me a zelar pela guarda e a prestar contas das vendas conforme acordado."