Files
tiagoandClaude Sonnet 5 f9738e54da Etapa 8 — Personalização whitelabel e ajustes finais
Adiciona upload/remoção de logo e cor primária por tenant (módulo
tenant-profile, armazenamento local atrás de uma interface StorageService
trocável por object storage depois) e um endpoint público de tema para a
tela de login carregar antes da autenticação.

Revisão de segurança: Helmet e CORS explícito (extraídos para
security.util.ts, reutilizado pelos testes e2e que verificam os
cabeçalhos), Swagger em /docs cobrindo todos os módulos via o plugin
oficial, paginação em alert_templates. Corrige um achado real: o reset de
senha logava o token em texto puro desde a Etapa 2 — agora envia por
e-mail de verdade.

Build de produção do Docker validado (imagem sem devDependencies, app e
worker rodando contra Postgres/Redis reais) e README consolidado com o
processo de deploy. Fecha o backlog com um teste e2e do fluxo completo:
master cria tenant → login → customer/produto → venda com parcelas →
parcela paga → dashboard financeiro reflete o pagamento.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 23:38:37 -03:00

93 lines
4.5 KiB
Bash

# ============================================================
# SeConectai Vendas — variáveis de ambiente
# Copie este arquivo para `.env` e ajuste os valores.
# ============================================================
# Ambiente da aplicação: development | production | test
NODE_ENV=development
# Porta HTTP exposta pela API (também usada pelo docker-compose para o mapeamento de porta)
PORT=3000
# --- Postgres --------------------------------------------------
# Credenciais usadas pelo container do Postgres (docker-compose.yml)
POSTGRES_USER=seconectai
POSTGRES_PASSWORD=seconectai
POSTGRES_DB=seconectai_vendas
POSTGRES_PORT=5432
# String de conexão usada pelo Prisma. Dentro do docker-compose, o host é o
# nome do serviço (`postgres`); rodando a API fora do compose, use `localhost`.
DATABASE_URL=postgresql://seconectai:seconectai@postgres:5432/seconectai_vendas?schema=public
# Connection string da role `app_master` (LOGIN + BYPASSRLS, criada na
# migration `20260813120000_auth_app_roles`), usada pelo painel master para
# enxergar dados de todos os tenants sem passar pelas policies de RLS.
DATABASE_URL_MASTER=postgresql://app_master:app_master_changeme@postgres:5432/seconectai_vendas?schema=public
# Connection string da role `app_tenant` (LOGIN comum, sem BYPASSRLS),
# usada para toda query autenticada como tenant_user, dentro da transação
# que executa `SET LOCAL app.current_tenant_id` — é essa role que faz as
# policies de RLS valerem de fato (a role de DATABASE_URL é dona das
# tabelas e, por ser a superuser bootstrap do Postgres, sempre ignora RLS).
DATABASE_URL_TENANT=postgresql://app_tenant:app_tenant_changeme@postgres:5432/seconectai_vendas?schema=public
# Em produção, troque as senhas acima com `ALTER ROLE app_master/app_tenant
# WITH PASSWORD '...'` e atualize as URLs de acordo — mesma lógica de
# POSTGRES_PASSWORD/JWT_SECRET: os valores default aqui são só para dev.
# --- Redis -------------------------------------------------------
REDIS_HOST=redis
REDIS_PORT=6379
# --- Autenticação --------------------------------------------------
# Segredo usado para assinar os JWTs de acesso/refresh (mínimo 32 caracteres)
JWT_SECRET=troque-este-valor-por-um-segredo-forte-com-32-caracteres-ou-mais
# Expiração do access token (formato aceito pela lib `ms`, ex: 15m, 1h)
JWT_ACCESS_EXPIRES_IN=15m
# Expiração do refresh token e do token de reset de senha, em dias/horas
REFRESH_TOKEN_EXPIRES_IN_DAYS=30
PASSWORD_RESET_EXPIRES_IN_HOURS=1
# Bloqueio de força bruta: nº de tentativas falhas e janela (minutos) até bloquear
LOGIN_MAX_ATTEMPTS=5
LOGIN_LOCKOUT_WINDOW_MINUTES=15
# --- Painel Master ------------------------------------------------
# Dias de trial concedidos a um tenant recém-criado (tenants.trial_expira_em)
TENANT_TRIAL_DIAS=14
# --- Integrações (Evolution API / SMTP) ----------------------------
# Chave usada para cifrar segredos em repouso (AES-256-GCM): api_key da
# Evolution API (evolution_api_config.api_key_cripto) e senha SMTP
# (master_email_config.smtp_senha_cripto / tenant_email_config.smtp_senha_cripto).
# Mínimo 32 caracteres; internamente é reduzida a 32 bytes via SHA-256 antes
# de virar a chave AES-256, então qualquer string longa o suficiente serve.
# Nunca reutilize o valor de exemplo em produção — trocar invalida todos os
# segredos já cifrados no banco (seria necessário recriá-los).
ENCRYPTION_KEY=troque-este-valor-por-um-segredo-forte-com-32-caracteres-ou-mais
# --- Motor de Alertas (BullMQ) — só lido pelo processo worker (src/worker.ts) ----
# Horário dos jobs diários, em formato cron (padrão node-cron/crontab: min hora dia mes dia-semana)
ALERT_CRON_MENSALIDADE=0 8 * * *
ALERT_CRON_COBRANCA=0 8 * * *
# Quantos dias antes do vencimento o alerta já é disparado (além de toda fatura/parcela
# já vencida e ainda sem alerta hoje)
ALERT_DIAS_ANTECEDENCIA_MENSALIDADE=3
ALERT_DIAS_ANTECEDENCIA_COBRANCA=3
# Retry do BullMQ para falha transitória de envio: nº de tentativas e atraso-base (ms)
# do backoff exponencial (tentativa N espera ALERT_JOB_BACKOFF_MS * 2^(N-1))
ALERT_JOB_MAX_ATTEMPTS=3
ALERT_JOB_BACKOFF_MS=5000
# --- CORS -----------------------------------------------------------
# Origens (frontend) autorizadas a chamar a API via browser, separadas por
# vírgula (sem espaço) — nunca "*". Vazio/ausente = nenhuma origem cross-site
# autorizada (chamadas server-to-server e ferramentas como curl/Postman não
# passam pelo CORS do browser, então não são afetadas).
CORS_ORIGINS=http://localhost:5173,http://localhost:3001