Voltar para a documentação
Guia 03

Configuração

Simmetric Chat tem dois níveis de configuração: variáveis de ambiente validadas com Zod na inicialização do processo, e uma camada de configuração runtime armazenada no banco de dados que administradores podem editar pela interface sem reiniciar nenhum s…

4 min de leitura

Simmetric Chat tem dois níveis de configuração: variáveis de ambiente validadas com Zod na inicialização do processo, e uma camada de configuração runtime armazenada no banco de dados que administradores podem editar pela interface sem reiniciar nenhum serviço.

  1. Variáveis de ambiente (inicialização do processo) - validadas com Zod em packages/<pkg>/src/config/env.ts; process.exit(1) quando inválidas.
  2. Configuração runtime (DB `SystemConfig`) - editável pela UI de admin sem reinício.

Resolução:

  • Chaves ALWAYS_READONLY (JWT_SECRET, DATABASE_URL, SERVER_PORT, COLLECTOR_PORT, SERVER_URL, COLLECTOR_URL, LICENSE_SECRET): ENV > Default, não editáveis pela UI.
  • Todas as outras: DB > ENV > Default, editáveis via PUT /api/system/settings.

Os três pacotes leem .env via path.resolve(__dirname, "../../.env") (independente do diretório de trabalho). O documento de referência é .env.example na raiz do repositório.

Variáveis de ambiente - server

Schema: packages/server/src/config/env.ts. Defaults exibidos; OBR = obrigatório.

Core / infra

VariávelDefaultObr.Descrição
NODE_ENVdevelopmentoptdevelopment/production/test
SERVER_PORT3000optPorta da API do servidor
COLLECTOR_PORT3210optPorta do collector (para a URL padrão)
SERVER_URLhttp://localhost:3000optURL pública do servidor
COLLECTOR_URLhttp://localhost:3210optURL do collector
WIDGET_SERVICE_URLhttp://localhost:3211optURL do serviço widget (push cache-bust)
WIDGET_API_KEY—optSegredo compartilhado do push widget; ausente → cache-bust no-op (TTL 5 min)
DATABASE_URLpostgresql://simmetricchat:[email protected]:5432/simmetricchatoptURL do PostgreSQL
JWT_SECRET—OBRSegredo JWT
ENCRYPTION_KEY—optBase64 de 32 bytes para AES-256-GCM (data-at-rest). Sem valor → fallback scryptSync(JWT_SECRET, salt)
SESSION_EXPIRY86400000 (24h ms)optExpiração do JWT
ALLOWED_ORIGINShttp://localhost:5173,127.0.0.1:5173,localhost:3000optAllowlist CORS global (CSV). /api/internal/widget excluído
LOG_LEVELinfooptdebug/info/warn/error
ALLOW_REGISTRATIONfalseoptInterruptor de auto-registro
DISABLE_TELEMETRYtrueoptDesativa telemetria

Bootstrap admin (seed)

VariávelDefaultDescrição
SEED_BOOTSTRAP_ADMINtrueAuto-seed do admin no primeiro boot (transform custom: false/0/no/off/"" = desativado)
SEED_ADMIN_USERNAMEadminUsername do admin bootstrap
SEED_ADMIN_PASSWORDadmin123Senha (min 8); conta mustChangePassword=true
SEED_ADMIN_EMAIL[email protected]Email do admin bootstrap

LLM

VariávelDefaultDescrição
LLM_PROVIDERollamaopenai/anthropic/ollama/openrouter
LLM_MODELgemma4:latestModelo padrão
LLM_TEMPERATURE0.70–2
LLM_MAX_TOKENS4096Teto de tokens de conclusão
LLM_TIMEOUT0Timeout do Axios em ms (0 = nenhum, para LLMs locais lentos)
LLM_API_KEY / LLM_API_BASE_URL—Overrides genéricos
OPENAI_API_KEY / OPENAI_MODEL—OpenAI
ANTHROPIC_API_KEY / ANTHROPIC_MODEL—Anthropic
OLLAMA_BASE_URLhttp://ollama:11434Endpoint do Ollama
OLLAMA_MODEL / OLLAMA_API_KEY—Override do Ollama
OPENROUTER_API_KEY / OPENROUTER_BASE_URL / OPENROUTER_MODELhttps://openrouter.ai/api / —OpenRouter

Watchdog de agente (prevenção de loops/stalls)

VariávelDefaultDescrição
AGENT_WALLCLOCK_TIMEOUT_MS600000 (10 min)Limite superior absoluto para uma requisição ReAct
AGENT_MAX_TOTAL_TOKENS200000Total prompt+completion por requisição
AGENT_MAX_CONTEXT_BYTES500000 (500 KB)Teto do tamanho do array de contexto
AGENT_MAX_TOOL_OUTPUT_LENGTH5000Truncamento da saída por skill
AGENT_MAX_SKILL_EXECUTION_MS60000Timeout por skill
AGENT_LOOP_DETECTION_WINDOW3Abortar após N tool+input idênticos consecutivos
CHAT_MAX_CONCURRENT_PER_USER5Limite de concorrência de chats por usuário

Embedding / Vector DB / OCR / Synthesis

VariávelDefaultDescrição
EMBEDDING_PROVIDERlocallocal/openai/ollama
EMBEDDING_MODELXenova/all-MiniLM-L6-v2Modelo de embedding
EMBEDDING_API_KEY—API key de embedding
VECTOR_DB_PROVIDERlancedblancedb/qdrant
VECTOR_DB_URL / VECTOR_DB_API_KEY—Para Qdrant remoto
OCR_MODELglm-ocr:latestModelo de visão OCR (formato model:version)
OCR_TIMEOUT600000Timeout de visão OCR
SYNTHESIS_LLM_MODELgemma4:latestModelo do pipeline de síntese
PUPPETEER_EXECUTABLE_PATH—Chromium para export PDF de arquivos

Licença, push, email, collector

VariávelDefaultDescrição
LICENSE_KEY—JWT de licença Enterprise (HS256). Ausente → Community
LICENSE_SECRET—Segredo de verificação JWT (recomendado); fallback a LICENSE_KEY
COLLECTOR_SECRET—OBR — segredo compartilhado server↔collector
VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY / VAPID_SUBJECT—Web Push; sem valor → chaves efêmeras geradas em dev
SMTP_HOST / SMTP_PORT / SMTP_USER / SMTP_PASS / SMTP_FROM—SMTP para reset de senha + notificações de falha de backup
LEGACY_PREVIOUS_ENCRYPTION_KEYS—CSV base64 32 bytes para rotação de chaves
Variáveis em .env.example mas gerenciadas como settings DB (não em envSchema): OCR_ENABLED, OCR_PRECHECK_CHARS, STORAGE_PATH (collector), RESET_PASSWORD_STRATEGY.

Variáveis de ambiente - collector

Schema: packages/collector/src/config/env.ts.

VariávelDefaultObr.Descrição
COLLECTOR_PORT3210optPorta HTTP
COLLECTOR_URLhttp://localhost:3210optURL própria
SERVER_URLhttp://localhost:3000optURL do servidor (callback)
EMBEDDING_PROVIDERlocaloptlocal/openai/ollama
EMBEDDING_MODEL—optModelo de embedding
EMBEDDING_API_KEY—optAPI key
VECTOR_DB_PROVIDERlancedboptlancedb/qdrant
VECTOR_DB_URL / VECTOR_DB_API_KEY—optQdrant
OLLAMA_BASE_URLhttp://ollama:11434optOllama
STORAGE_PATH./storageoptArmazenamento filesystem
COLLECTOR_SECRET—OBRDeve corresponder ao servidor

Variáveis de ambiente - widget

Schema: packages/widget/src/config/env.ts.

VariávelDefaultObr.Descrição
NODE_ENVdevelopmentoptAmbiente
WIDGET_PORT3211optPorta HTTP
SERVER_URLhttp://localhost:3000optURL do servidor
WIDGET_API_KEY—OBRSegredo compartilhado widget↔server (deve corresponder)
LOG_LEVELinfooptNível de log
Frontend: sem variáveis VITE_* e sem arquivo .env. O frontend lê branding/config do servidor (GET /api/system/settings, GET /api/license/info).

Feature flags e licença

Definidos em packages/shared/src/constants/license.ts (FEATURE_FLAGS + defaults). Verificados em packages/server/src/services/licenseService.ts.

Como passar de Community para Enterprise

  1. Defina LICENSE_KEY (JWT HS256) e, recomendado, LICENSE_SECRET.
  2. jwt.verify → payload validado contra licensePayloadSchema (tier, iss, sub, iat, exp, features).
  3. tier=enterprise → parte de ENTERPRISE_FEATURE_DEFAULTS + os overrides features do JWT.
  4. Expirada/inválida → fallback Community com aviso.

Graceful degradation: getLicenseInfo() verifica a expiração em runtime; se Enterprise expirar durante o uso, degrada para Community sem reinício. requireFeature(flag) → HTTP 402 quando desabilitado; requireFeatureLimit(flag, model) → 402 quando count >= limit (Enterprise = Infinity).

Flags commodity sempre ativos: desde a remoção EPA-02, os 8 flags commodity não existem mais em FEATURE_FLAGS - webhooks, push_notifications, web search, memory, lead_export, widget_analytics, auto_title, synthesis_rate_limit estão sempre ativos em Community (rotas commodity rodam sem gating). priority_support não é um flag: é um contrato comercial/SLA (EPA-08). Restam 11 flags enterprise, incluindo widget_credits_editing (edição de créditos do widget, Community false / Enterprise true) e custom_agents como limite numérico (Community 3, Enterprise Infinity).

Tabela de flags (11)

FlagTipoCommunityEnterpriseO que gateia
sso_enabledboolfalsetrueSSO Enterprise
audit_log_immutableboolfalsetrueImutabilidade do audit log
white_labelboolfalsetrueBranding BRANDING_*
max_workspacesnum3InfinityCriação de workspaces
max_projectsnum3InfinityCriação de projetos
custom_agentsnum3InfinityAgentes custom (limite)
widget_enabledboolfalsetrueWidget incorporável
max_widgetsnum1InfinityCriação de widgets
backup_enabledboolfalsetrueSistema de backup
max_backup_destinationsnum1InfinityDestinos de backup
widget_credits_editingboolfalsetrueEdição de créditos do widget

Runtime config (DB SystemConfig)

Editável via GET/PUT /api/system/settings (bulk) e PUT /api/system/chat-retention (específica, auditada). Defaults vivem em CONFIG_DEFAULTS (packages/shared/src/constants/permissions.ts).

Grupos de chaves: LLM (LLM_PROVIDER, LLM_MODEL, LLM_TEMPERATURE, ...), Embedding/Vector, Portas/URLs do servidor, Auth (SESSION_EXPIRY), Branding (BRANDING_APP_NAME, BRANDING_PRIMARY_COLOR, BRANDING_APP_SUBTITLE, BRANDING_APP_ICON_URL - gated white_label), Feature (DISABLE_TELEMETRY, ALLOW_REGISTRATION, DLP_ENABLED), OCR (OCR_DEFAULT_MODEL, OCR_DEFAULT_MODE, OCR_DEFAULT_CUSTOM_INSTRUCTIONS, OCR_ENABLED, OCR_PRECHECK_CHARS), Synthesis (SYNTHESIS_LLM_PROVIDER_ID, SYNTHESIS_LLM_MODEL), Retention (upload_draft_retention_days, ALLOW_NON_ADMIN_UPLOAD, chat_message_retention_days).

PUT /api/system/settings sempre retorna 200 com { updated: [...], rejected: [...] } (chaves readonly são rejeitadas enquanto as demais são aplicadas).

Retenção de mensagens de chat (reaper)

Serviço: packages/server/src/services/chatMessageReaperJob.ts. Knob DB: chat_message_retention_days.

  • Pass 1 (soft-delete): tombstones mensagens de chats ATIVOS além de retentionDays. No-op quando o valor é null/""/<=0.
  • Pass 2 (hard-purge): exclui linhas tombstonadas além de uma graça de 7 dias (hardcoded). Sempre roda, independentemente da config de retenção (anti-vazamento de PII).
  • Cadência: setInterval de 24h, primeiro run às 03:00 hora local. Mutex isRunning.
  • Apenas PUT /api/system/chat-retention (auditada, confirmDataLoss: true, retentionDays: integer|null, min 1); o endpoint bulk rejeita essa chave.

Retenção de backups

Por job (o campo retentionDays em BackupJob, default 30). backupRetentionService.ts limpa logs/arquivos além de cutoffDate. Não é global.

Rotação de chaves de criptografia

packages/server/src/services/encryptionService.ts (AES-256-GCM, chave de 32 bytes, IV de 16 bytes, salt simmetric-chat-encryption-salt).

  • Chave atual: ENCRYPTION_KEY (base64 32 bytes) quando definida; senão scryptSync(JWT_SECRET, salt, 32).
  • LEGACY_PREVIOUS_ENCRYPTION_KEYS (CSV base64 32 bytes) → cadeia de chaves de descriptografia [current, ...previous, scryptLegacy?].
  • encrypt() usa chain[0]. Não há job automático de re-criptografia: o procedimento é manual descriptografar-com-antiga → re-criptografar-com-nova.