Torna alla documentazione
Guida 03

Configurazione

Simmetric Chat ha due livelli di configurazione: variabili d'ambiente validate con Zod all'avvio del processo, e un layer di runtime config su DB che gli admin modificano da UI senza riavviare alcun servizio.

4 min di lettura

Simmetric Chat ha due livelli di configurazione: variabili d'ambiente validate con Zod all'avvio del processo, e un layer di runtime config su DB che gli admin modificano da UI senza riavviare alcun servizio.

  1. Environment variables (avvio del processo) - validate con Zod in packages/<pkg>/src/config/env.ts; process.exit(1) se invalide.
  2. Runtime config (DB `SystemConfig`) - modificabile da UI admin senza restart.

Risoluzione:

  • Chiavi ALWAYS_READONLY (JWT_SECRET, DATABASE_URL, SERVER_PORT, COLLECTOR_PORT, SERVER_URL, COLLECTOR_URL): ENV > Default, non modificabili da UI.
  • Tutte le altre: DB > ENV > Default, modificabili via PUT /api/system/settings.

I tre package leggono .env via path.resolve(__dirname, "../../.env") (indipendente dalla cwd). Il riferimento documentale è .env.example alla radice del repo.

Variabili d'ambiente - server

Schema: packages/server/src/config/env.ts. Default mostrati; OBBL = obbligatorio.

Core / infra

VariabileDefaultObbl.Descrizione
NODE_ENVdevelopmentoptdevelopment/production/test
SERVER_PORT3000optPorta API server
COLLECTOR_PORT3210optPorta collector (per default URL)
SERVER_URLhttp://localhost:3000optURL pubblico server
COLLECTOR_URLhttp://localhost:3210optURL collector
WIDGET_SERVICE_URLhttp://localhost:3211optURL widget service (push cache-bust)
WIDGET_API_KEY-optShared secret widget push; se assente, cache-bust no-op (TTL 5 min)
DATABASE_URLpostgresql://simmetricchat:[email protected]:5432/simmetricchatoptURL PostgreSQL
JWT_SECRET-OBBLSegreto JWT
ENCRYPTION_KEY-optBase64 di 32 byte per AES-256-GCM (data-at-rest). Se unset → fallback scryptSync(JWT_SECRET, salt)
SESSION_EXPIRY86400000 (24h ms)optScadenza JWT
ALLOWED_ORIGINShttp://localhost:5173,127.0.0.1:5173,localhost:3000optAllowlist CORS globale (CSV). /api/internal/widget escluso
LOG_LEVELinfooptdebug/info/warn/error
ALLOW_REGISTRATIONfalseoptSelf-registration toggle
DISABLE_TELEMETRYtrueoptDisabilita telemetria

Bootstrap admin (seed)

VariabileDefaultDescrizione
SEED_BOOTSTRAP_ADMINtrueAuto-seed admin al primo avvio (transform custom: false/0/no/off/"" = disabilitato)
SEED_ADMIN_USERNAMEadminUsername admin bootstrap
SEED_ADMIN_PASSWORDadmin123Password (min 8); account mustChangePassword=true
SEED_ADMIN_EMAIL[email protected]Email admin bootstrap

LLM

VariabileDefaultDescrizione
LLM_PROVIDERollamaopenai/anthropic/ollama/openrouter
LLM_MODELgemma4:latestModello default
LLM_TEMPERATURE0.70–2
LLM_MAX_TOKENS4096Cap token completamento
LLM_TIMEOUT0Timeout Axios ms (0 = nessuno, per LLM locali lenti)
LLM_API_KEY / LLM_API_BASE_URL-Override generici
OPENAI_API_KEY / OPENAI_MODEL-OpenAI
ANTHROPIC_API_KEY / ANTHROPIC_MODEL-Anthropic
OLLAMA_BASE_URLhttp://ollama:11434Endpoint Ollama
OLLAMA_MODEL / OLLAMA_API_KEY-Ollama override
OPENROUTER_API_KEY / OPENROUTER_BASE_URL / OPENROUTER_MODELhttps://openrouter.ai/api / -OpenRouter

Agent watchdog (prevenzione loop/stall)

VariabileDefaultDescrizione
AGENT_WALLCLOCK_TIMEOUT_MS600000 (10 min)Upper bound assoluto per request ReAct
AGENT_MAX_TOTAL_TOKENS200000Totale prompt+completion per request
AGENT_MAX_CONTEXT_BYTES500000 (500 KB)Cap dimensione context array
AGENT_MAX_TOOL_OUTPUT_LENGTH5000Truncation per-skill output
AGENT_MAX_SKILL_EXECUTION_MS60000Timeout per-skill
AGENT_LOOP_DETECTION_WINDOW3Abort dopo N tool+input identici consecutivi
CHAT_MAX_CONCURRENT_PER_USER5Limite concorrenza chat per utente

Embedding / Vector DB / OCR / Synthesis

VariabileDefaultDescrizione
EMBEDDING_PROVIDERlocallocal/openai/ollama
EMBEDDING_MODELXenova/all-MiniLM-L6-v2Modello embedding
EMBEDDING_API_KEY-API key embedding
VECTOR_DB_PROVIDERlancedblancedb/qdrant
VECTOR_DB_URL / VECTOR_DB_API_KEY-Per Qdrant remoto
OCR_MODELglm-ocr:latestModello vision OCR (formato model:version)
OCR_TIMEOUT600000Timeout OCR vision
SYNTHESIS_LLM_MODELgemma4:latestModello pipeline synthesis
PUPPETEER_EXECUTABLE_PATH-Chromium per export PDF archivi
WIKI_EMBED_TIMEOUT_MS1800000 (30 min)Cap attesa server→collector POST /api/ingest/wiki-pages per il reindex orario consistency-wiki; alza per pagine wiki molto grandi su host lenti; 0 disabilita il cap (ENV-only)

Licenza, push, email, collector

VariabileDefaultDescrizione
LICENSE_KEY-JWT Enterprise license RS256 (vendor-issued; chiave pubblica embedded nel sorgente). Assente → Community; alternativa no-.env = la paste in admin UI / PUT /api/license/instance (F-LIC-1)
COLLECTOR_SECRET-OBBL - shared secret server↔collector
VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY / VAPID_SUBJECT-Web Push; se unset, generate effimere in dev
SMTP_HOST / SMTP_PORT / SMTP_USER / SMTP_PASS / SMTP_FROM-SMTP per password-reset + notifiche fail backup
LEGACY_PREVIOUS_ENCRYPTION_KEYS-CSV base64 32-byte per rotazione chiavi
Variabili in .env.example ma gestite come settings DB (non in envSchema): OCR_ENABLED, OCR_PRECHECK_CHARS, STORAGE_PATH (collector), RESET_PASSWORD_STRATEGY.

Variabili d'ambiente - collector

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

VariabileDefaultObbl.Descrizione
COLLECTOR_PORT3210optPorta HTTP
COLLECTOR_URLhttp://localhost:3210optURL proprio
SERVER_URLhttp://localhost:3000optURL server (callback)
EMBEDDING_PROVIDERlocaloptlocal/openai/ollama
EMBEDDING_MODEL-optModello 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./storageoptFilesystem storage
COLLECTOR_SECRET-OBBLDeve matchare il server

Variabili d'ambiente - widget

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

VariabileDefaultObbl.Descrizione
NODE_ENVdevelopmentoptAmbiente
WIDGET_PORT3211optPorta HTTP
SERVER_URLhttp://localhost:3000optURL server
WIDGET_API_KEY-OBBLShared secret widget↔server (deve matchare)
LOG_LEVELinfooptLivello log
Frontend: nessuna variabile VITE_* né file .env. Il frontend legge branding/config dal server (GET /api/system/settings, GET /api/license/info).

Feature flag & licenza

Definiti in packages/shared/src/constants/license.ts (FEATURE_FLAGS + defaults). Verifica in packages/server/src/services/licenseService.ts.

Come si passa Community → Enterprise

  1. Imposta LICENSE_KEY (JWT RS256 vendor-issued; la chiave pubblica è embedded nel sorgente server - packages/server/src/services/license-public-key.ts) - oppure, senza toccare il .env e senza restart, incolla la key in Settings → Security → License o PUT /api/license/instance (F-LIC-1).
  2. Il payload viene validato contro licensePayloadSchema (tier, iss, sub, iat, exp, features); verifica probe-first: una key rifiutata non viene mai salvata.
  3. tier=enterprise → parte da ENTERPRISE_FEATURE_DEFAULTS + override features del JWT.
  4. Precedenza sorgenti (identica a boot e runtime): slot INSTANCE_LICENSE (AES-256-GCM cifrato) → riga plugin verificata → ENV LICENSE_KEY → Community.
  5. Scaduto/invalido → fallback Community con warn.

Graceful degradation: getLicenseInfo() controlla la scadenza a runtime; se Enterprise scade durante l'attività, degrada a Community senza restart. requireFeature(flag) → HTTP 402 se disabilitato; requireFeatureLimit(flag, model) → 402 se count >= limit (Enterprise = Infinity).

Flag commodity sempre attivi: dalla rimozione EPA-02 gli 8 flag commodity non esistono più in FEATURE_FLAGS - webhooks, push_notifications, web search, memory, lead_export, widget_analytics, auto_title, synthesis_rate_limit sono sempre attivi in Community (le route commodity girano senza gating). priority_support non è un flag: è un contratto commerciale/SLA (EPA-08). Restano 14 flag, tra cui widget_credits_editing (modifica crediti widget, Community false / Enterprise true), custom_agents come limite numerico (Community 3, Enterprise Infinity), max_skills (Community 3, Enterprise Infinity, F-SKILL-1), max_users (Community 5, Enterprise Infinity - enforced alla creazione utente, F-RBAC-1-class) e connectors_enabled (Community false, F-CONN-1).

Tabella flag (14)

FlagTipoCommunityEnterpriseCosa gatea
sso_enabledboolfalsetrueSSO enterprise
audit_log_immutableboolfalsetrueImmutabilità audit log
white_labelboolfalsetrueBranding BRANDING_*
max_workspacesnum3InfinityCreazione workspace
max_projectsnum3InfinityCreazione progetto
custom_agentsnum3InfinityAgent custom (limite)
widget_enabledboolfalsetrueWidget embeddabile
max_widgetsnum1InfinityCreazione widget
backup_enabledboolfalsetrueSistema backup
max_backup_destinationsnum1InfinityDestinazioni backup
max_usersnum5InfinityUtenti (seat per licenza)
connectors_enabledboolfalsetrueConnettori chat (F-CONN-1)
max_skillsnum3InfinitySkill custom (F-SKILL-1)
widget_credits_editingboolfalsetrueModifica crediti widget

Runtime config (DB SystemConfig)

Modificabile via GET/PUT /api/system/settings (bulk) e PUT /api/system/chat-retention (specifica, audited). Default in CONFIG_DEFAULTS (packages/shared/src/constants/permissions.ts).

Gruppi di chiavi: LLM (LLM_PROVIDER, LLM_MODEL, LLM_TEMPERATURE, ...), Embedding/Vector, Server porte/URL, 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 ritorna sempre 200 con { updated: [...], rejected: [...] } (le chiavi readonly sono rifiutate ma le altre applicate).

Chat message retention (reaper)

Servizio: packages/server/src/services/chatMessageReaperJob.ts. Knob DB: chat_message_retention_days.

  • Pass 1 (soft-delete): tombstone messaggi di chat ATTIVE oltre retentionDays. No-op se valore null/""/<=0.
  • Pass 2 (hard-purge): elimina righe tombstonate oltre grace di 7 giorni (hardcoded). Runna sempre, indipendentemente dalla config retention (anti-PII leak).
  • Cadenza setInterval 24h, primo run alle 03:00 locali. Mutex isRunning.
  • Solo PUT /api/system/chat-retention (audited, confirmDataLoss: true, retentionDays: integer|null, min 1); la bulk settings rifiuta questa chiave.

Backup retention

Per-job (campo retentionDays su BackupJob, default 30). backupRetentionService.ts pulisce log/file oltre cutoffDate. Non è globale.

Encryption key rotation

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

  • Chiave corrente: ENCRYPTION_KEY (base64 32 byte) se set; else scryptSync(JWT_SECRET, salt, 32).
  • LEGACY_PREVIOUS_ENCRYPTION_KEYS (CSV base64 32-byte) → key chain decrypt [current, ...previous, scryptLegacy?].
  • encrypt() usa chain[0]. Non esiste job automatico di re-encryption: procedura manuale decrypt-con-old → re-encrypt-con-new.

Provenienza v0.28.1

AffermazioneFonte
LICENSE_KEY RS256 (no LICENSE_SECRET - la chiave pubblica è embedded)docs/CONFIGURATION.md (riga LICENSE_KEY, row-time) + docs/ADMIN.md (§ Licenza Enterprise) - F-LIC-1
ALWAYS_READONLY = 6 chiavi infra (LICENSE_SECRET non è più readonly - non esiste)docs/CONFIGURATION.md:42 (row-time)
Feature flags = 14 (+max_users 5/∞, connectors_enabled false/true, max_skills 3/∞)packages/shared/src/constants/license.ts (row-time: FEATURE_FLAGS ×14 + COMMUNITY/ENTERPRISE defaults) - F-SKILL-1, F-CONN-1
WIKI_EMBED_TIMEOUT_MS 1800000 (ENV-only)docs/CONFIGURATION.md:107 (row-time)

Riferimento operativo - Simmetric Chat v0.28.1 (docs aggiornate 2026-10-02, census SHA `aca5b8ff`).