Synaplan
Open-source AI platform for companies: self-hosted AI agents, GDPR-compliant chatbot widget, RAG knowledge base, WhatsApp and Outlook AI, MCP, multi-model routing. Docker, Kubernetes or hosted in Germ
翻訳待ち
No updates detected yet. GitHub releases will appear here.
Loading the full README. The saved excerpt is shown below.
Web app (PWA) de agendamento e CRM para clínicas de estética, multi-tenant. Regras do projeto em CLAUDE.md; plano de entregas em ROADMAP.md. Pré-requisitos: Node 24, pnpm e Docker. O app usa o driver @neondatabase/serverless em todos os ambientes. Em dev, ele fala com o local-neon-http-proxy do Docker pelo host db.localtest.me, que resolve para 127.0.0.1. Esse host depende de DNS público, então em dev é preciso estar online.Read the full README ↗
Web app (PWA) de agendamento e CRM para clínicas de estética, multi-tenant. Regras do projeto em CLAUDE.md; plano de entregas em ROADMAP.md.
Pré-requisitos: Node 24, pnpm e Docker.
cp .env.example .env.local
pnpm install
pnpm db:up # Postgres 17 + proxy do Neon (docker-compose.yml)
pnpm db:migrate
pnpm db:seed # clínica de exemplo "EasyGlowCare"
pnpm dev # http://localhost:3000/easyglowcare
O app usa o driver @neondatabase/serverless em todos os ambientes. Em dev, ele fala com o
local-neon-http-proxy do Docker pelo host db.localtest.me, que resolve para 127.0.0.1.
Esse host depende de DNS público, então em dev é preciso estar online.
pnpm test # Vitest; usa o banco easyglowcare_test (precisa do pnpm db:up)
pnpm test:e2e # Playwright; veja "Equipe e login"
pnpm test:e2e:prod # build + Playwright em modo produção (igual ao CI)
pnpm typecheck
pnpm lint
pnpm build
O painel da equipe fica em /admin (login em /admin/login). A tela /admin/equipe, onde o dono
cadastra e gerencia a equipe, só abre para o papel dono. A área do cliente (/minha-conta) ainda é
um espaço reservado.
O pnpm db:seed cria estes usuários de exemplo (só para desenvolvimento e staging):
| Nome | Papel | |
|---|---|---|
[email protected] | Marina Alves | dono |
[email protected] | Paulo Reis | recepção |
[email protected] | Ana Souza | profissional |
[email protected] | Beatriz Lima | profissional |
[email protected] | Dra. Carla Mendes | profissional |
A senha de todos é a variável SEED_STAFF_PASSWORD do .env.local, quando definida (de 10 a 128
caracteres). Sem ela, o seed gera uma senha e a imprime no terminal; anote-a, porque ela não é
mostrada de novo. Em produção o seed só pode ser usado uma vez, em banco vazio, com --force (veja
"Neon + Vercel"); depois que houver dados reais, nunca o rode em produção.
A variável SESSION_SECRET (mínimo de 32 caracteres) é obrigatória para o app e para o build: sem
ela o login e as sessões não funcionam. O script pnpm staff:create não a usa (verificado: com ela
vazia ele roda normalmente). Para gerar uma: node -e "console.log(require('crypto').randomBytes(32).toString('base64'))".
pnpm test:e2e roda o Playwright com o Google Chrome instalado e precisa do pnpm db:up. Antes dos
testes, ele refaz o seed no banco local de desenvolvimento com uma senha fixa de teste e limpa a
tabela login_attempts; por isso, depois dele, a senha do seed deixa de ser a do seu .env.local
(rode pnpm db:seed de novo para voltar a ela). Ele se recusa a rodar se DATABASE_URL ou
DATABASE_URL_UNPOOLED não apontarem para o banco local.
O app pode ser instalado no celular, como se fosse um aplicativo. A cliente instala pelo link
"Instalar app" da página da clínica (/<slug>/instalar). A equipe instala pelo link "Instalar o
painel no celular" na tela inicial do painel (/admin/instalar).
pnpm build && pnpm start), não no pnpm dev.A cada PR para staging ou main, e a cada push em staging e main, o GitHub roda o workflow .github/workflows/ci.yml: lint,
checagem de tipos, testes, build e os testes de navegador em modo produção. Ele não usa nenhum
segredo: sobe um Postgres próprio e dados de teste.
Para exigir o CI antes do merge, no GitHub vá em Settings > Branches > Add branch ruleset (ou "Add
rule") e crie a regra para staging e para main. Marque "Require status checks to pass" e escolha
"Lint, tipos, testes, build e navegador". Em repositório privado, exigir o CI antes do merge pode
precisar de plano pago do GitHub.
Se o CI falhar nos testes de navegador, o relatório do Playwright fica em "Artifacts" na página da execução, por 7 dias.
Nenhuma mensagem é enviada na hora: o código grava em message_outbox e um cron envia. Em
desenvolvimento, o provedor console só imprime no terminal o canal, o modelo e o destinatário
mascarado. As ações de acesso e de equipe ficam registradas em audit_log (ainda sem tela;
consulte pelo pnpm db:studio).
| Rota | O que faz | Agendamento (vercel.json) |
|---|---|---|
/api/cron/outbox | Envia as mensagens vencidas (até 50 por execução, 5 tentativas) | por volta das 06:00 de Brasília, todo dia |
/api/cron/cleanup | Apaga tentativas de login e sessões com mais de 30 dias e mensagens enviadas há mais de 90 | por volta das 06:30 de Brasília, todo dia |
As duas rotas exigem o cabeçalho Authorization: Bearer <CRON_SECRET>; sem a variável
CRON_SECRET definida, respondem 401 e nada é processado. Para chamar localmente (com
pnpm dev rodando e CRON_SECRET no .env.local), no PowerShell:
$env:CRON_SECRET = 'o mesmo valor do .env.local'
Invoke-RestMethod http://localhost:3000/api/cron/outbox -Headers @{ Authorization = "Bearer $env:CRON_SECRET" }
Remove-Item Env:CRON_SECRET
Na Vercel: cadastre CRON_SECRET em Production e em Preview, com valores diferentes (gere
com node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"), antes do
merge e do deploy. A Vercel só entrega uma variável nova aos deploys feitos depois que ela foi
cadastrada. Se cadastrar depois, faça um redeploy; senão os crons respondem 401 todo dia, sem
nenhum aviso além do log. A Vercel envia o cabeçalho sozinha nas chamadas de cron.
Os crons da Vercel só rodam no deploy de produção (main). Em staging (Preview) eles não
disparam. Para testar lá, chame as rotas à mão, com o CRON_SECRET de Preview, como no exemplo
local (trocando a URL).
This is the beginning of the README. Read the rest at the original. Read the full README ↗