Files
DeskcommCRM/.env.hostgator.example
T

350 lines
18 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# =============================================================================
# DeskcommCRM — template de ambiente para self-host na HostGator (VPS + Docker).
# Copie para `.env` e preencha. O install.sh gera os segredos automaticamente.
#
# Regra de ouro:
# - NEXT_PUBLIC_* = embutidas no BUILD (baked na imagem). Trocar = REBUILD.
# - as demais = injetadas em RUNTIME pelo docker-compose (trocar = restart).
# =============================================================================
# -----------------------------------------------------------------------------
# 0) AS TRÊS IMAGENS (genéricas e pré-buildadas — o leigo só puxa, não builda)
# -----------------------------------------------------------------------------
# O install.sh preenche isto com a ÚLTIMA VERSÃO PUBLICADA, não com um canal
# móvel, e as três sempre na MESMA versão. Regra em docs/doctrine/packaging.md.
#
# Sobre as tags:
# 1.2.1 → uma release, para sempre. É o que uma instalação de verdade usa.
# stable → a última release publicada (move a cada release)
# latest → o TOPO DA MAIN. Apesar do nome, NÃO é a última release: é código
# ainda não lançado. Use só para avaliar o projeto — nunca num
# servidor que atende cliente.
#
# pull_policy acompanha a tag: imutável usa `missing`, móvel usa `always`.
# Não é preferência — foi medido que, com `always` e o registro sem responder
# para aquela referência, o `up -d` FALHA e o contêiner não sobe, mesmo com a
# imagem já no disco. Numa tag imutável isso só amarra a subida do seu CRM à
# disponibilidade do GHCR.
# Os valores abaixo são o PISO seguro para quem preenche à mão (stable = a
# última release). O install.sh sobrescreve com o NÚMERO da versão, que é o que
# uma instalação de verdade usa — ver a regra de ouro na doutrina.
# troque pelo seu fork se publicar o seu
APP_IMAGE=ghcr.io/melgarafael/deskcommcrm:stable
APP_PULL_POLICY=always
# O worker (agente de IA 24/7) e o scheduler (crons) acompanham a versão do app.
# Até 2026-08-13 eles não tinham imagem: eram compilados na sua VPS no install e
# nenhum update.sh jamais os reconstruía — o agente ficava congelado no código
# do dia da instalação. Deixe-os na mesma versão do APP_IMAGE acima.
WORKER_IMAGE=ghcr.io/melgarafael/deskcomm-worker:stable
WORKER_PULL_POLICY=always
SCHEDULER_IMAGE=ghcr.io/melgarafael/deskcomm-scheduler:stable
SCHEDULER_PULL_POLICY=always
# ── Chamada de voz WhatsApp (spec 18) — DESLIGADA, e é assim que ela nasce ────
#
# Ligá-la vincula um SEGUNDO APARELHO ao mesmo número que já atende, por um
# caminho que não é o oficial: o risco é a CONTA ser bloqueada pelo WhatsApp, e
# com ela o canal onde você vende. Nenhuma atualização liga isto sozinha.
#
# COMO LIGAR, se você aceitar esse risco:
# 1. troque a linha abaixo por COMPOSE_PROFILES=voz
# 2. troque a de baixo por WACALLS_API_BASE_URL=http://wacalls:8080
# 3. rode ./update.sh
# 4. na tela, em Configurações › Segurança, ligue e aceite o aviso.
#
# COMO DESLIGAR: faça o contrário do passo 4 (a tela desconecta o aparelho de
# verdade), depois esvazie as duas linhas e rode ./update.sh.
#
# Esta chave é lida pelo próprio `docker compose`: vazia, o serviço `wacalls`
# nem é criado.
COMPOSE_PROFILES=
WACALLS_API_BASE_URL=
# Gerados pelo instalador. O serviço de voz NÃO SOBE sem usuário e senha de
# administrador, e o app só fala com ele pelo token. Não precisa mexer.
WACALLS_ADMIN_USER=
WACALLS_ADMIN_PASSWORD=
WACALLS_API_TOKEN=
# -----------------------------------------------------------------------------
# 1) DOMÍNIO / HTTPS (você define; aponte o A-record deste domínio pro IP do VPS)
# -----------------------------------------------------------------------------
DOMAIN=crm.seudominio.com.br
# e-mail do Let's Encrypt (avisos de cert)
ACME_EMAIL=voce@seudominio.com.br
# Quem responde nas portas 80/443:
# caddy → o kit sobe o próprio Caddy (padrão; VPS "cru")
# traefik → o VPS JÁ tem um Traefik nessas portas (Hostinger, Coolify,
# Dokploy...). O install.sh detecta isso sozinho e preenche aqui.
# Em modo traefik é preciso subir com o override:
# docker compose -f docker-compose.prod.yml -f docker-compose.traefik.yml up -d
# (os scripts do kit já fazem isso sozinhos ao ler esta variável).
#
# DEIXE COMENTADO. O install.sh só detecta quando a variável está VAZIA — se você
# copiar este arquivo com `REVERSE_PROXY=caddy` preenchido, a detecção não roda e a
# instalação numa VPS com proxy próprio volta a morrer no bind da porta.
# Descomente apenas para forçar um modo à mão.
#REVERSE_PROXY=caddy
# Só lidas quando REVERSE_PROXY=traefik, e o install.sh preenche sozinho.
# TRAEFIK_NETWORK é a bridge onde o Traefik encontra o app — o app é anexado a ela.
# Se o Traefik da hospedagem tem rede própria, é a rede DELE (o nome varia por
# painel: `coolify`, `dokploy-network`, `traefik`). Se ele roda em `--network host`
# (Hostinger), ele não tem rede no Docker e o install.sh cria uma bridge do projeto:
# `<nome do projeto no compose>_proxy` — que NÃO é o nome cru da pasta, e sim o que
# o compose faz com ele (minúsculas, só [a-z0-9_-], `_`/`-` iniciais aparados). Numa
# pasta `CRM.Host_Teste` a rede é `crmhost_teste_proxy`. Nos dois casos o install.sh
# descobre e preenche sozinho.
# DEIXE COMENTADO: valor preenchido aqui PULA a detecção. O instalador recusa o
# que não é bridge ou não existe, mas uma bridge que existe e não é a do proxy ele
# não tem como desmentir — e aí o site sobe sem responder.
#TRAEFIK_NETWORK=traefik
#TRAEFIK_ENTRYPOINT=websecure
#TRAEFIK_ENTRYPOINT_HTTP=web
#TRAEFIK_CERTRESOLVER=letsencrypt
# -----------------------------------------------------------------------------
# 2) SUPABASE (crie um projeto grátis em supabase.com → Settings → API/Database)
# -----------------------------------------------------------------------------
# BUILD-TIME (baked na imagem):
NEXT_PUBLIC_SUPABASE_URL=https://SEU-PROJETO.supabase.co
# anon key (Settings → API)
NEXT_PUBLIC_SUPABASE_ANON_KEY=
# RUNTIME:
# service_role key — BYPASSA RLS, só server
SUPABASE_SERVICE_ROLE_KEY=
# connection string (Settings → Database) — a do APP (vai para os contêineres)
SUPABASE_DB_URL=
# Só para Supabase PRÓPRIO: a conexão do DONO do banco, que roda o schema
# (create extension, baseline.sql, promoção do dono, pg_dump do backup). Na
# nuvem não preencha — a de cima já é privilegiada. O install.sh NÃO grava esta
# chave; descomentar aqui é uma escolha sua, e vale a pena para que o update.sh
# (que roda sozinho pelo cron) continue conseguindo aplicar migration nova.
# Atenção: o compose entrega o .env inteiro ao app e ao worker (env_file), então
# declará-la aqui a expõe aos contêineres — se preferir não expor, passe-a só no
# comando: SUPABASE_DB_ADMIN_URL='...' bash hostgator-setup-kit/update.sh
#SUPABASE_DB_ADMIN_URL=
# -----------------------------------------------------------------------------
# 3) APP URLs (BUILD-TIME — precisam bater com o DOMAIN acima; trocar = rebuild)
# -----------------------------------------------------------------------------
NEXT_PUBLIC_APP_URL=https://crm.seudominio.com.br
NEXT_PUBLIC_ADMIN_URL=https://crm.seudominio.com.br
# -----------------------------------------------------------------------------
# 4) IA (Anthropic via AI Gateway) — paga por uso, chave sua
# -----------------------------------------------------------------------------
# ou ANTHROPIC_API_KEY abaixo. As chaves de IA são OPCIONAIS: o CRM sobe sem
# nenhuma delas e você cadastra a sua depois pela tela, em IA › Credenciais
# (fica cifrada no banco). Sem chave, o agente de IA não responde.
AI_GATEWAY_API_KEY=
ANTHROPIC_API_KEY=
# OpenRouter (OPCIONAL) — alternativa ao gateway da Vercel, compatível com a API
# da OpenAI, com catálogo grande de modelos num único faturamento.
# Ordem de resolução do chat: AI_GATEWAY_API_KEY > OPENROUTER_API_KEY > provider
# direto (ANTHROPIC_API_KEY / OPENAI_API_KEY). Vazio = nada muda.
#
# ALCANCE — leia antes de trocar. Esta chave roteia a classificação de
# sentimento, o bot de resposta E o AGENTE do CRM quando a organização está em
# OpenRouter sem credencial cadastrada na tela — que é exatamente o estado de
# quem instalou pelo kit escolhendo a opção [1] e nunca abriu Agente de IA →
# Provedores. O agente aceita os quatro provedores (Anthropic, OpenAI, Google,
# OpenRouter); a credencial cadastrada por organização vence esta chave.
# Ela NÃO escolhe o provedor: quem escolhe é o instalador (AI_PROVIDER) ou a
# tela. Preencher aqui com a organização em Anthropic não migra o agente.
# Isso importa porque o agente opera por FERRAMENTAS (contatos, leads, funil,
# catálogo, transferência para humano), e modelo sem tool calling sólido não dá
# erro: responde texto plausível e nunca cria o lead nem move o card. Por isso o
# painel RECUSA salvar modelo sem ferramentas nos pontos "Responder o cliente" e
# "Trabalhar o funil", pelo que o fabricante declara no catálogo.
OPENROUTER_API_KEY=
# vazio = https://openrouter.ai/api/v1
OPENROUTER_BASE_URL=
# opcional — transcrição de áudio; embeddings do RAG também aceitam OpenRouter
OPENAI_API_KEY=
# -----------------------------------------------------------------------------
# 5) SEGREDOS GERADOS PELO install.sh (openssl). NÃO precisa preencher à mão.
# (comando de cada um ao lado, se quiser gerar manualmente)
# -----------------------------------------------------------------------------
# openssl rand -hex 32
INTERNAL_SECRET=
# opcional; vazio = usa INTERNAL_SECRET
INTERNAL_CRON_SECRET=
# Provisionamento de organizações por um sistema externo
# (POST /api/v1/tenants/provision). DESLIGADO por padrão: vazio, a rota
# responde 404. Para ligar, gere um segredo de 32+ caracteres
# (`openssl rand -hex 32`) e entregue-o só ao sistema que vai criar empresas —
# com ele, esse sistema cria organizações nesta instalação sem passar pela tela.
TENANT_PROVISIONING_SECRET=
# openssl rand -base64 32
CPF_ENCRYPTION_KEY=
# openssl rand -base64 32 (32 bytes)
AI_CRED_AES_KEY=
# openssl rand -base64 32
WAHA_BYO_ENCRYPTION_KEY=
# openssl rand -hex 32 (>=32 chars)
IMPERSONATE_COOKIE_SECRET=
# openssl rand -hex 32
LGPD_SIGNING_KEY=
# -----------------------------------------------------------------------------
# 6) WhatsApp / WAHA (Core grátis por padrão; ver docker-compose.prod.yml)
# -----------------------------------------------------------------------------
# nome do serviço na rede docker (não mexer)
WAHA_API_BASE_URL=http://waha:3000
# WAHA→app interno; sem domínio público (não mexer)
WAHA_WEBHOOK_BASE_URL=http://app:3000
# retoma sessão pareada quando o contêiner do transporte reinicia
WHATSAPP_RESTART_ALL_SESSIONS=True
# gerado pelo install.sh (ver Task 6: hash vs plaintext)
WAHA_API_KEY=
# hash SHA512 hex de WAHA_API_KEY (o container usa este)
WAHA_API_KEY_SHA512=
# openssl rand -hex 32 (assinatura do webhook)
WAHA_HMAC_SECRET=
# -----------------------------------------------------------------------------
# 7) Redis (roda no VPS via serverless-redis-http; sem conta Upstash)
# -----------------------------------------------------------------------------
# container srh (não mexer)
UPSTASH_REDIS_REST_URL=http://srh:80
# = SRH_TOKEN abaixo (mesmo valor)
UPSTASH_REDIS_REST_TOKEN=
# openssl rand -hex 32 (igual ao de cima)
SRH_TOKEN=
# -----------------------------------------------------------------------------
# 8) FLAGS
# -----------------------------------------------------------------------------
NODE_ENV=production
# template genérico; true p/ ligar e-commerce
NUVEMSHOP_ENABLED=false
# false = IA real (true devolveria trace fake!)
INTERNAL_AGENT_RUN_STUB=false
# -----------------------------------------------------------------------------
# 9) Nuvemshop (só preencher se NUVEMSHOP_ENABLED=true — partners.tiendanube.com)
# -----------------------------------------------------------------------------
NUVEMSHOP_APP_ID=
NUVEMSHOP_CLIENT_ID=
NUVEMSHOP_CLIENT_SECRET=
NUVEMSHOP_OAUTH_ENCRYPTION_KEY=
# -----------------------------------------------------------------------------
# 10) E-mail transacional (Resend — opcional; sem ele, convites mostram link na UI)
# -----------------------------------------------------------------------------
# RESEND_FROM_EMAIL tem de ser um endereço de domínio VERIFICADO na SUA conta
# Resend. Vazio = e-mail desligado, e é melhor assim: um domínio que não é seu
# faz todo envio ser recusado pela Resend com uma mensagem que não diz que o
# problema é configuração.
RESEND_API_KEY=
RESEND_FROM_EMAIL=
# -----------------------------------------------------------------------------
# 10-b) E-mail transacional (SMTP — a alternativa à Resend acima)
# -----------------------------------------------------------------------------
# Os dois caminhos convivem: preenchido, o envio sai pelo SEU servidor de
# e-mail; vazio, continua pela Resend. Quem já roda com Resend não mexe em nada.
# É o caminho de quem não quer depender de serviço externo para mandar convite.
#
# A tela /admin/email grava os mesmos campos no banco, e o BANCO PREVALECE
# sobre estas variáveis — elas existem para provisionar a VPS sem abrir a
# interface, e são o piso de rollback.
#
# Use somente o hostname, sem smtp:// e sem :porta.
# SSL/TLS implícito: 465 + tls. STARTTLS: 587 + starttls.
# Host ou remetente vazio mantém o envio desligado sem falhar.
SMTP_HOST=
SMTP_PORT=587
SMTP_SECURITY=starttls
SMTP_USERNAME=
SMTP_PASSWORD=
SMTP_FROM_EMAIL=
SMTP_FROM_NAME=
# -----------------------------------------------------------------------------
# 11) Observabilidade (Sentry) — relatórios de erro
# -----------------------------------------------------------------------------
# O install.sh pergunta na primeira instalação. A ausência desta chave no
# template é intencional: `SENTRY_DSN=""` passa a existir só DEPOIS que a pessoa
# aceita o Sentry da comunidade, e assim uma reexecução preserva essa escolha.
# Para pré-configurar sem pergunta, descomente UMA opção:
# SENTRY_DSN=off → desliga TODA a telemetria (nada é enviado)
# SENTRY_DSN= → aceita o Sentry da comunidade (erros anonimizados)
# SENTRY_DSN=<seu-dsn> → envia os erros pro SEU próprio Sentry
# SENTRY_DSN=
# -----------------------------------------------------------------------------
# 12) Bootstrap do 1º dono (usado só uma vez pelo install.sh)
# -----------------------------------------------------------------------------
OWNER_EMAIL=voce@seudominio.com.br
# senha forte do primeiro admin
OWNER_PASSWORD=
# -----------------------------------------------------------------------------
# AGENT ENGINE (fusão Vendaval) — worker 24/7 do agente SDR (serviço `worker`)
# -----------------------------------------------------------------------------
# O worker usa o SUPABASE_DB_URL acima (recomendado: role dedicada agent_worker
# — ver docs/deploy-selfhost/README.md §2). Defaults seguros; descomente p/ mudar.
# dono único do despacho: engine (worker) | native (sem worker)
AGENT_DISPATCH_CONSUMER=engine
# Teto de gasto de IA — a alavanca de emergência da INSTALAÇÃO. Quem escolhe o
# teto é cada organização, na tela Uso de IA › Orçamento; esta chave só AFROUXA.
# on (default) respeita a escolha de cada organização
# avisar rebaixa "parar a IA" para só avisar
# off desliga a proteção nesta instalação inteira (também: false, 0, nao)
# A IA parou e você precisa dela de volta agora? ponha off aqui e reinicie o app
# e o worker — sem psql, sem SQL. Valor não reconhecido cai em `on`: uma alavanca
# de emergência não pode derrubar o app por um typo. Deixe comentado para o padrão.
#AI_BUDGET_ENFORCEMENT=on
#WATCHDOG_INTERVAL_MS=60000 # reconciliador de sessão + redrive de mensagens presas
#FLYWHEEL_INTERVAL_MS=21600000 # auto-melhoria (propostas; aplicar é sempre manual). 0=off
#FLYWHEEL_BATCH_LIMIT=10
# ── Marca da instalação (white-label) ───────────────────────────────────────
# Quem instala o CRM para clientes (agência, revendedor) troca a marca aqui, sem
# editar código — patch em código se perde no próximo update. Vazio = padrão.
# APP_LOGO_URL aceita qualquer URL pública de imagem; sem ela, o nome aparece
# como texto. Ver lib/branding.ts.
APP_NAME=
APP_LOGO_URL=
# Cor da marca: cerquilha + 6 dígitos hex (`#7a5cd6`). O install.sh pergunta e
# valida essa forma; formas que o app aceita mas o e-mail não (`#abc`, `7a5cd6`)
# pintariam a tela e deixariam o verde do produto no e-mail de acesso.
# Depois da primeira leitura o banco manda (platform_branding, tela /admin/marca)
# — esta chave é a SEMENTE e o piso de rollback, e a única fonte dos e-mails de
# acesso, que o hostgator-setup-kit/marca-emails.sh empurra para o GoTrue.
APP_ACCENT_HEX=
# Endereço de suporte que o CLIENTE FINAL vê (conta suspensa, cobrança). Ponha o
# SEU — quem suspende a conta de um cliente é quem hospeda, não o produto.
# Vazio = a tela não mostra endereço nenhum.
SUPPORT_EMAIL=
# ─── Agenda · Google Calendar (BYO) — OPCIONAL ────────────────────────────────
# Sem as duas, a Agenda funciona inteira: some o botão "Conectar Google" e a tela
# explica que falta configuração — sem culpar quem está usando.
#
# Onde obter: console.cloud.google.com > APIs e Serviços > Credenciais >
# ID do cliente OAuth, tipo "Aplicativo da Web".
#
# ⚠️ E REGISTRE O ENDEREÇO DE RETORNO, que é onde todo mundo tropeça. No console,
# em "URIs de redirecionamento autorizados", ponha a URL do seu app MAIS o
# caminho do callback — o Google compara BYTE A BYTE:
#
# https://SEU-DOMINIO/api/v1/agenda/google/callback
#
# Registrar só `https://SEU-DOMINIO` é o palpite natural e o Google recusa com
# `redirect_uri_mismatch`, um erro que aponta para ele e não para a divergência.
# A própria tela da Agenda mostra o endereço exato, pronto para copiar, enquanto
# a instalação estiver sem as chaves.
GOOGLE_CALENDAR_CLIENT_ID=
GOOGLE_CALENDAR_CLIENT_SECRET=
# Web Push — bandeja do SO com a aba fechada. Sem o par, alertas só com o site aberto.
# Gerar: npx web-push generate-vapid-keys
VAPID_PUBLIC_KEY=
VAPID_PRIVATE_KEY=