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.
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.
- Environment variables (avvio del processo) - validate con Zod in
packages/<pkg>/src/config/env.ts;process.exit(1)se invalide. - 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 viaPUT /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
| Variabile | Default | Obbl. | Descrizione |
|---|---|---|---|
NODE_ENV | development | opt | development/production/test |
SERVER_PORT | 3000 | opt | Porta API server |
COLLECTOR_PORT | 3210 | opt | Porta collector (per default URL) |
SERVER_URL | http://localhost:3000 | opt | URL pubblico server |
COLLECTOR_URL | http://localhost:3210 | opt | URL collector |
WIDGET_SERVICE_URL | http://localhost:3211 | opt | URL widget service (push cache-bust) |
WIDGET_API_KEY | - | opt | Shared secret widget push; se assente, cache-bust no-op (TTL 5 min) |
DATABASE_URL | postgresql://simmetricchat:[email protected]:5432/simmetricchat | opt | URL PostgreSQL |
JWT_SECRET | - | OBBL | Segreto JWT |
ENCRYPTION_KEY | - | opt | Base64 di 32 byte per AES-256-GCM (data-at-rest). Se unset → fallback scryptSync(JWT_SECRET, salt) |
SESSION_EXPIRY | 86400000 (24h ms) | opt | Scadenza JWT |
ALLOWED_ORIGINS | http://localhost:5173,127.0.0.1:5173,localhost:3000 | opt | Allowlist CORS globale (CSV). /api/internal/widget escluso |
LOG_LEVEL | info | opt | debug/info/warn/error |
ALLOW_REGISTRATION | false | opt | Self-registration toggle |
DISABLE_TELEMETRY | true | opt | Disabilita telemetria |
Bootstrap admin (seed)
| Variabile | Default | Descrizione |
|---|---|---|
SEED_BOOTSTRAP_ADMIN | true | Auto-seed admin al primo avvio (transform custom: false/0/no/off/"" = disabilitato) |
SEED_ADMIN_USERNAME | admin | Username admin bootstrap |
SEED_ADMIN_PASSWORD | admin123 | Password (min 8); account mustChangePassword=true |
SEED_ADMIN_EMAIL | [email protected] | Email admin bootstrap |
LLM
| Variabile | Default | Descrizione |
|---|---|---|
LLM_PROVIDER | ollama | openai/anthropic/ollama/openrouter |
LLM_MODEL | gemma4:latest | Modello default |
LLM_TEMPERATURE | 0.7 | 0–2 |
LLM_MAX_TOKENS | 4096 | Cap token completamento |
LLM_TIMEOUT | 0 | Timeout 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_URL | http://ollama:11434 | Endpoint Ollama |
OLLAMA_MODEL / OLLAMA_API_KEY | - | Ollama override |
OPENROUTER_API_KEY / OPENROUTER_BASE_URL / OPENROUTER_MODEL | https://openrouter.ai/api / - | OpenRouter |
Agent watchdog (prevenzione loop/stall)
| Variabile | Default | Descrizione |
|---|---|---|
AGENT_WALLCLOCK_TIMEOUT_MS | 600000 (10 min) | Upper bound assoluto per request ReAct |
AGENT_MAX_TOTAL_TOKENS | 200000 | Totale prompt+completion per request |
AGENT_MAX_CONTEXT_BYTES | 500000 (500 KB) | Cap dimensione context array |
AGENT_MAX_TOOL_OUTPUT_LENGTH | 5000 | Truncation per-skill output |
AGENT_MAX_SKILL_EXECUTION_MS | 60000 | Timeout per-skill |
AGENT_LOOP_DETECTION_WINDOW | 3 | Abort dopo N tool+input identici consecutivi |
CHAT_MAX_CONCURRENT_PER_USER | 5 | Limite concorrenza chat per utente |
Embedding / Vector DB / OCR / Synthesis
| Variabile | Default | Descrizione |
|---|---|---|
EMBEDDING_PROVIDER | local | local/openai/ollama |
EMBEDDING_MODEL | Xenova/all-MiniLM-L6-v2 | Modello embedding |
EMBEDDING_API_KEY | - | API key embedding |
VECTOR_DB_PROVIDER | lancedb | lancedb/qdrant |
VECTOR_DB_URL / VECTOR_DB_API_KEY | - | Per Qdrant remoto |
OCR_MODEL | glm-ocr:latest | Modello vision OCR (formato model:version) |
OCR_TIMEOUT | 600000 | Timeout OCR vision |
SYNTHESIS_LLM_MODEL | gemma4:latest | Modello pipeline synthesis |
PUPPETEER_EXECUTABLE_PATH | - | Chromium per export PDF archivi |
WIKI_EMBED_TIMEOUT_MS | 1800000 (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
| Variabile | Default | Descrizione |
|---|---|---|
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.examplema gestite come settings DB (non inenvSchema):OCR_ENABLED,OCR_PRECHECK_CHARS,STORAGE_PATH(collector),RESET_PASSWORD_STRATEGY.
Variabili d'ambiente - collector
Schema: packages/collector/src/config/env.ts.
| Variabile | Default | Obbl. | Descrizione |
|---|---|---|---|
COLLECTOR_PORT | 3210 | opt | Porta HTTP |
COLLECTOR_URL | http://localhost:3210 | opt | URL proprio |
SERVER_URL | http://localhost:3000 | opt | URL server (callback) |
EMBEDDING_PROVIDER | local | opt | local/openai/ollama |
EMBEDDING_MODEL | - | opt | Modello embedding |
EMBEDDING_API_KEY | - | opt | API key |
VECTOR_DB_PROVIDER | lancedb | opt | lancedb/qdrant |
VECTOR_DB_URL / VECTOR_DB_API_KEY | - | opt | Qdrant |
OLLAMA_BASE_URL | http://ollama:11434 | opt | Ollama |
STORAGE_PATH | ./storage | opt | Filesystem storage |
COLLECTOR_SECRET | - | OBBL | Deve matchare il server |
Variabili d'ambiente - widget
Schema: packages/widget/src/config/env.ts.
| Variabile | Default | Obbl. | Descrizione |
|---|---|---|---|
NODE_ENV | development | opt | Ambiente |
WIDGET_PORT | 3211 | opt | Porta HTTP |
SERVER_URL | http://localhost:3000 | opt | URL server |
WIDGET_API_KEY | - | OBBL | Shared secret widget↔server (deve matchare) |
LOG_LEVEL | info | opt | Livello log |
Frontend: nessuna variabileVITE_*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
- 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.enve senza restart, incolla la key in Settings → Security → License oPUT /api/license/instance(F-LIC-1). - Il payload viene validato contro
licensePayloadSchema(tier,iss,sub,iat,exp,features); verifica probe-first: una key rifiutata non viene mai salvata. tier=enterprise→ parte daENTERPRISE_FEATURE_DEFAULTS+ overridefeaturesdel JWT.- Precedenza sorgenti (identica a boot e runtime): slot
INSTANCE_LICENSE(AES-256-GCM cifrato) → riga plugin verificata → ENVLICENSE_KEY→ Community. - 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)
| Flag | Tipo | Community | Enterprise | Cosa gatea |
|---|---|---|---|---|
sso_enabled | bool | false | true | SSO enterprise |
audit_log_immutable | bool | false | true | Immutabilità audit log |
white_label | bool | false | true | Branding BRANDING_* |
max_workspaces | num | 3 | Infinity | Creazione workspace |
max_projects | num | 3 | Infinity | Creazione progetto |
custom_agents | num | 3 | Infinity | Agent custom (limite) |
widget_enabled | bool | false | true | Widget embeddabile |
max_widgets | num | 1 | Infinity | Creazione widget |
backup_enabled | bool | false | true | Sistema backup |
max_backup_destinations | num | 1 | Infinity | Destinazioni backup |
max_users | num | 5 | Infinity | Utenti (seat per licenza) |
connectors_enabled | bool | false | true | Connettori chat (F-CONN-1) |
max_skills | num | 3 | Infinity | Skill custom (F-SKILL-1) |
widget_credits_editing | bool | false | true | Modifica 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 valorenull/""/<=0. - Pass 2 (hard-purge): elimina righe tombstonate oltre grace di 7 giorni (hardcoded). Runna sempre, indipendentemente dalla config retention (anti-PII leak).
- Cadenza
setInterval24h, primo run alle 03:00 locali. MutexisRunning. - 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; elsescryptSync(JWT_SECRET, salt, 32). LEGACY_PREVIOUS_ENCRYPTION_KEYS(CSV base64 32-byte) → key chain decrypt[current, ...previous, scryptLegacy?].encrypt()usachain[0]. Non esiste job automatico di re-encryption: procedura manuale decrypt-con-old → re-encrypt-con-new.
Provenienza v0.28.1
| Affermazione | Fonte |
|---|---|
| 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`).
Cross-link
- Endpoint settings: 04 - API Reference
- Internals feature: 05 - Feature Guide
- Deploy env vars: 09 - Deployment