Synaplan
開源 AI 平台,供企業使用:自行託管的 AI 代理、符合 GDPR 的聊天機器人小工具、RAG 知識庫、WhatsApp 與 Outlook AI、MCP、多模型路由。Docker、Kubernetes 或託管於 Germ
AI 翻譯
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
Controle de saída, entrada e saldo de caixas retornáveis por cliente, filial e galpão. Site estático + função serverless na Vercel, com Postgres no Supabase como banco. Modelo de referência: crate ledger — o mesmo desenho usado por SpireStock, TrackOnline e Mercaflux: Manual completo, por perfil (motorista, promotor, galpão, escritório): https://qdelicia-caixas.vercel.app/manual.html Fonte em manual.html — página estática, sem dependência, publicada junto com o app.檢視完整 README ↗
Controle de saída, entrada e saldo de caixas retornáveis por cliente, filial e galpão. Site estático + função serverless na Vercel, com Postgres no Supabase como banco.
Modelo de referência: crate ledger — o mesmo desenho usado por SpireStock, TrackOnline e Mercaflux:
saldo do cliente = saídas − devoluções confirmadas − perdas baixadas
Vai continuar o projeto em outra ferramenta? PARA-O-CLAUDE-DESKTOP.md é o mapa de entrega:
o que levar, o que fica de fora por segurança, e o que roda — ou não roda — de cada lado.
Manual completo, por perfil (motorista, promotor, galpão, escritório): https://qdelicia-caixas.vercel.app/manual.html
Fonte em manual.html — página estática, sem dependência, publicada junto com o app.
GALPÃO ──carrega──► ROTA ──entrega──► CLIENTE ──coleta──► ROTA ──volta──► GALPÃO
└──transferência──► FILIAL ──saída──► CLIENTE ──devolução──► FILIAL ──► GALPÃO
A rota é o caminhão e guarda caixa como qualquer outro local. É o que impede o que subiu no caminhão e não foi entregue de aparecer na conta do cliente.
Cada local (galpão, filial, cliente) tem saldo próprio, então a caixa nunca "some no meio do caminho": se saiu do galpão e não chegou ao cliente, o saldo fica com quem estiver com ela.
A regra que resolve a dor principal: todo retorno baixa o saldo assim que é lançado,
não importa quem lançou. Até setembro/2026 a devolução contada na rua nascia AGUARDANDO e
esperava conferência no galpão; a aba de Conferência saiu do app de campo — e era o único lugar
onde um retorno era confirmado —, então manter o estado de espera prenderia a caixa na conta do
cliente para sempre. A divergência entre o contado e o que chegou continua registrada; o que ela
deixou de ser é portão.
O perfil quase não decide nada. Só ADMIN tem poder próprio — cadastros e correções; o resto é
chave por usuário, no cadastro de cada pessoa:
| Chave | O que controla | Vazio quer dizer |
|---|---|---|
saidas / destinos | De onde e para onde aquela pessoa pode lançar | todos |
operacoes | Se ela lança Saída, Retorno ou os dois — recusado no servidor, não só escondido | todas |
acesso_painel | Se abre o admin.html | (booleano; ADMIN entra sempre) |
abas | Quais das seis abas do painel ela enxerga | todas as permitidas |
Perfis de fábrica: Admin, Gestor, Gerente, Conferente, Motorista, Promotor — e o campo
é texto livre, para o escritório escrever o cargo que precisar. Perfil escrito nasce sem poder
nenhum: permissão por digitação seria permissão por engano de digitação. A única exceção que ainda
mora no perfil é PROMOTOR, que não vê a aba de Saída.
| Onde | Abas |
|---|---|
index.html (campo) | Saída · Retorno · Lançamentos |
admin.html (escritório) | Painel de Ativos · Painel · Extratos · Ajustes · Movimentos · Cadastros |
extrato.html?t=TOKEN | Só leitura: o cliente vê o próprio saldo e extrato |
A entrada é uma só para os dois primeiros: a mesma tela, com um campo de segredo que
aceita o PIN de 6 números ou a senha do painel. Quem decide o destino é o papel, e não o
endereço digitado: só o perfil ADMIN, entrando por senha, abre o admin.html; todo o resto
cai no index.html, na aba Saída, que é onde se lança. Abrir o admin.html direto mostra
essa mesma tela de entrada.
Ter a chave acesso_painel dá a porta — o botão ▦ Painel no alto da tela —, não o ponto
de partida.
navegador ──fetch──► /api (função na Vercel) ──service_role──► Postgres (Supabase)
│
└──► Storage (canhotos e fotos)
O navegador nunca fala com o banco. A chave que abre o Postgres vive só na variável de
ambiente da Vercel; a página conhece apenas o caminho /api. É isso que permite manter o PIN
curto e o link anônimo do cliente sem deixar o banco exposto.
| Arquivo | Papel |
|---|---|
api/index.js | Roteador das 16 ações, o mesmo contrato de sempre |
api/_logica.js | Regras de negócio, funções puras, zero acesso a banco |
api/_supabase.js | PostgREST via fetch e tradução snake_case ↔ formato interno |
supabase/schema.sql | Tabelas, índices, RLS e bucket |
supabase/seed.sql | Dados de exemplo |
Arquivos em api/ que começam com _ não viram endpoint — a Vercel os trata como auxiliares.
Duas peças: o banco no Supabase e o site + API na Vercel. Nenhuma precisa de CLI.
supabase/schema.sql → Run.supabase/seed.sql para os dados de exemplo.
Depois, rode supabase/bootstrap.sql uma vez: a partir dele o
app aplica sozinho toda migração futura, sem ninguém abrir o SQL Editor de novo.O RLS fica ligado e sem política em todas as tabelas: a chave pública não acessa nada.
Quem entra é a função, com a service_role — que nunca vai para o repositório.
https://vercel.com/new → importe sinerggia-dev/qdelicia-caixas.
Framework Preset: Other. Não há build: os arquivos da raiz são servidos como estão
e a pasta api/ vira função sozinha.
Environment Variables, marcando os três ambientes:
| Nome | Valor |
|---|---|
SUPABASE_URL | https://xxxxx.supabase.co |
SUPABASE_SERVICE_KEY | a chave service_role |
Deploy. Confira em SEU-DOMINIO/api?acao=ping, que deve responder
{"ok":true,"versao":3,"motor":"supabase"}.
Alterou código? git push na main e a Vercel publica sozinha.
Mudou variável de ambiente? Precisa de redeploy para valer.
| Tabela | Para quê |
|---|---|
locais | Galpões, filiais, clientes e rotas — todos são "nós" que guardam caixas. token é o código do link do cliente; rota_id liga o cliente à rota; motorista_id liga a rota ao motorista. |
tipos_caixa | Tipos de caixa, com o peso (kg) de cada um. |
usuarios | Nome, perfil, senha, PIN, local padrão e as chaves de permissão. |
motoristas | Quem dirige, com CNH e as rotas que atende. Não faz login. |
locais_padrao | Postos de trabalho. Não guardam caixa. |
movimentos | Livro-razão, só acrescenta. Nada é apagado — movimento errado se cancela. |
config | Nome da empresa, prazo padrão. |
Tipos de movimento: SAIDA, DEVOLUCAO, TRANSFERENCIA, PERDA, AJUSTE.
O status da coluna de Movimentos é o ponto do ciclo, não o de valer no saldo: Enviada,
Transferida, Parcial, Devolvida, Perda, Ajuste. AGUARDANDO não existe mais, e as
linhas antigas que ficaram nele passaram a contar.
localStorage) e sobe sozinho quando a internet volta. O chip no topo mostra o tamanho da fila.client_key, e a coluna tem UNIQUE.
Quem recusa a repetição é o banco, não o código — reenvio da fila nunca lança duas vezes.canhotos no Supabase Storage e o link aparece
no extrato. É reduzida no celular antes de subir — o corpo da requisição na Vercel tem limite de
4,5 MB. Lançamentos antigos podem ter assinatura anexada; o campo saiu da tela em setembro/2026.teste no perfil produz lançamento de teste. Ele conta no
saldo como qualquer outro — as telas só separam a leitura, com um seletor Só reais / Só de
teste, e nunca misturam os dois.fetch comum, mesma origem. Sem JSONP e sem CORS, que só existiam por
causa das limitações do Apps Script.node teste/teste_api.js # 520 verificações das regras
node teste/teste_tela.js # 746 verificações das telas
node teste/teste_permissoes.js # 87 verificações das permissões, ponta a ponta
A primeira roda o roteador, as regras e os tradutores de verdade, trocando apenas o acesso ao Postgres por um banco falso em memória — sem rede e sem chave: saldo por cliente, divergência, perda, caminho galpão→rota→cliente, aging FIFO, extrato, token do cliente, idempotência da fila offline, cancelamento, login, primeiro acesso, permissões e o fluxo do Painel de Ativos.
A segunda lê o HTML e o JavaScript das páginas e confere que cada filtro, coluna e botão está ligado dos dois lados: um campo que aparece na barra mas não viaja no pedido, ou uma coluna com cabeçalho e sem célula, falha ali em vez de falhar na tela de quem usa.
Rode as duas depois de qualquer alteração. Mexeu em app.js ou styles.css? Rode também
python scripts/versionar.py antes de commitar — sem isso o navegador serve o arquivo do cache.
O backend antigo do Google continua no repositório, com o próprio teste
(node teste/teste_backend.js, 38 verificações), como referência e rota de volta enquanto a
migração não estiver validada em produção.
Alterou o esquema do banco? Rode o SQL novo no SQL Editor do Supabase. Como o
schema.sql usa create table if not exists, ele não recria o que já existe — para mudar
coluna, escreva o alter table correspondente.
Atenção ao plano gratuito: o projeto do Supabase pausa após ~7 dias sem acesso. Despausar é um clique no painel, mas o primeiro acesso depois disso falha.