Configuración
Simmetric Chat tiene dos niveles de configuración: variables de entorno validadas con Zod en el arranque del proceso, y una capa de configuración runtime almacenada en la base de datos que los administradores pueden editar desde la interfaz sin reiniciar…
Simmetric Chat tiene dos niveles de configuración: variables de entorno validadas con Zod en el arranque del proceso, y una capa de configuración runtime almacenada en la base de datos que los administradores pueden editar desde la interfaz sin reiniciar ningún servicio.
- Variables de entorno (arranque del proceso) - validadas con Zod en
packages/<pkg>/src/config/env.ts;process.exit(1)si son inválidas. - Configuración runtime (DB `SystemConfig`) - editable desde la UI de administración sin reiniciar.
Resolución:
- Claves
ALWAYS_READONLY(JWT_SECRET,DATABASE_URL,SERVER_PORT,COLLECTOR_PORT,SERVER_URL,COLLECTOR_URL,LICENSE_SECRET):ENV > Default, no editables desde la UI. - Todas las demás:
DB > ENV > Default, editables viaPUT /api/system/settings.
Los tres paquetes leen .env via path.resolve(__dirname, "../../.env") (independiente del directorio de trabajo). El documento de referencia es .env.example en la raíz del repo.
Variables de entorno - server
Schema: packages/server/src/config/env.ts. Se muestran los valores por defecto; OBL = obligatorio.
Core / infra
| Variable | Default | Obl. | Descripción |
|---|---|---|---|
NODE_ENV | development | opt | development/production/test |
SERVER_PORT | 3000 | opt | Puerto de la API del servidor |
COLLECTOR_PORT | 3210 | opt | Puerto del collector (para la URL por defecto) |
SERVER_URL | http://localhost:3000 | opt | URL pública del servidor |
COLLECTOR_URL | http://localhost:3210 | opt | URL del collector |
WIDGET_SERVICE_URL | http://localhost:3211 | opt | URL del servicio widget (push cache-bust) |
WIDGET_API_KEY | — | opt | Secreto compartido del push widget; ausente → cache-bust no-op (TTL 5 min) |
DATABASE_URL | postgresql://simmetricchat:[email protected]:5432/simmetricchat | opt | URL de PostgreSQL |
JWT_SECRET | — | OBL | Secreto JWT |
ENCRYPTION_KEY | — | opt | Base64 de 32 bytes para AES-256-GCM (data-at-rest). Sin definir → fallback scryptSync(JWT_SECRET, salt) |
SESSION_EXPIRY | 86400000 (24h ms) | opt | Caducidad JWT |
ALLOWED_ORIGINS | http://localhost:5173,127.0.0.1:5173,localhost:3000 | opt | Allowlist CORS global (CSV). /api/internal/widget excluido |
LOG_LEVEL | info | opt | debug/info/warn/error |
ALLOW_REGISTRATION | false | opt | Interruptor de auto-registro |
DISABLE_TELEMETRY | true | opt | Desactiva la telemetría |
Bootstrap admin (seed)
| Variable | Default | Descripción |
|---|---|---|
SEED_BOOTSTRAP_ADMIN | true | Auto-seed del admin en el primer arranque (transform custom: false/0/no/off/"" = deshabilitado) |
SEED_ADMIN_USERNAME | admin | Username del admin bootstrap |
SEED_ADMIN_PASSWORD | admin123 | Contraseña (min 8); cuenta mustChangePassword=true |
SEED_ADMIN_EMAIL | [email protected] | Email del admin bootstrap |
LLM
| Variable | Default | Descripción |
|---|---|---|
LLM_PROVIDER | ollama | openai/anthropic/ollama/openrouter |
LLM_MODEL | gemma4:latest | Modelo por defecto |
LLM_TEMPERATURE | 0.7 | 0–2 |
LLM_MAX_TOKENS | 4096 | Tope de tokens de completación |
LLM_TIMEOUT | 0 | Timeout de Axios en ms (0 = ninguno, para LLM locales 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_URL | http://ollama:11434 | Endpoint de Ollama |
OLLAMA_MODEL / OLLAMA_API_KEY | — | Override de Ollama |
OPENROUTER_API_KEY / OPENROUTER_BASE_URL / OPENROUTER_MODEL | https://openrouter.ai/api / — | OpenRouter |
Watchdog de agente (prevención de loops/stalls)
| Variable | Default | Descripción |
|---|---|---|
AGENT_WALLCLOCK_TIMEOUT_MS | 600000 (10 min) | Límite superior absoluto para una petición ReAct |
AGENT_MAX_TOTAL_TOKENS | 200000 | Total prompt+completion por petición |
AGENT_MAX_CONTEXT_BYTES | 500000 (500 KB) | Tope del tamaño del array de contexto |
AGENT_MAX_TOOL_OUTPUT_LENGTH | 5000 | Truncado de la salida por skill |
AGENT_MAX_SKILL_EXECUTION_MS | 60000 | Timeout por skill |
AGENT_LOOP_DETECTION_WINDOW | 3 | Abortar tras N tool+input idénticos consecutivos |
CHAT_MAX_CONCURRENT_PER_USER | 5 | Límite de concurrencia de chats por usuario |
Embedding / Vector DB / OCR / Synthesis
| Variable | Default | Descripción |
|---|---|---|
EMBEDDING_PROVIDER | local | local/openai/ollama |
EMBEDDING_MODEL | Xenova/all-MiniLM-L6-v2 | Modelo de embedding |
EMBEDDING_API_KEY | — | API key de embedding |
VECTOR_DB_PROVIDER | lancedb | lancedb/qdrant |
VECTOR_DB_URL / VECTOR_DB_API_KEY | — | Para Qdrant remoto |
OCR_MODEL | glm-ocr:latest | Modelo de visión OCR (formato model:version) |
OCR_TIMEOUT | 600000 | Timeout de visión OCR |
SYNTHESIS_LLM_MODEL | gemma4:latest | Modelo del pipeline de síntesis |
PUPPETEER_EXECUTABLE_PATH | — | Chromium para export PDF de archivos |
Licencia, push, email, collector
| Variable | Default | Descripción |
|---|---|---|
LICENSE_KEY | — | JWT de licencia Enterprise (HS256). Ausente → Community |
LICENSE_SECRET | — | Secreto de verificación JWT (recomendado); fallback a LICENSE_KEY |
COLLECTOR_SECRET | — | OBL — secreto compartido server↔collector |
VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY / VAPID_SUBJECT | — | Web Push; sin definir → claves efímeras generadas en dev |
SMTP_HOST / SMTP_PORT / SMTP_USER / SMTP_PASS / SMTP_FROM | — | SMTP para reset de contraseña + notificaciones de fallo de backup |
LEGACY_PREVIOUS_ENCRYPTION_KEYS | — | CSV base64 32-byte para rotación de claves |
Variables en.env.examplepero gestionadas como settings DB (no enenvSchema):OCR_ENABLED,OCR_PRECHECK_CHARS,STORAGE_PATH(collector),RESET_PASSWORD_STRATEGY.
Variables de entorno - collector
Schema: packages/collector/src/config/env.ts.
| Variable | Default | Obl. | Descripción |
|---|---|---|---|
COLLECTOR_PORT | 3210 | opt | Puerto HTTP |
COLLECTOR_URL | http://localhost:3210 | opt | URL propia |
SERVER_URL | http://localhost:3000 | opt | URL del servidor (callback) |
EMBEDDING_PROVIDER | local | opt | local/openai/ollama |
EMBEDDING_MODEL | — | opt | Modelo de 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 | Almacenamiento filesystem |
COLLECTOR_SECRET | — | OBL | Debe coincidir con el servidor |
Variables de entorno - widget
Schema: packages/widget/src/config/env.ts.
| Variable | Default | Obl. | Descripción |
|---|---|---|---|
NODE_ENV | development | opt | Entorno |
WIDGET_PORT | 3211 | opt | Puerto HTTP |
SERVER_URL | http://localhost:3000 | opt | URL del servidor |
WIDGET_API_KEY | — | OBL | Secreto compartido widget↔server (debe coincidir) |
LOG_LEVEL | info | opt | Nivel de log |
Frontend: sin variablesVITE_*ni archivo.env. El frontend lee branding/config desde el servidor (GET /api/system/settings,GET /api/license/info).
Feature flags y licencia
Definidos en packages/shared/src/constants/license.ts (FEATURE_FLAGS + defaults). Verificados en packages/server/src/services/licenseService.ts.
Cómo pasar de Community a Enterprise
- Define
LICENSE_KEY(JWT HS256) y, recomendado,LICENSE_SECRET. jwt.verify→ payload validado contralicensePayloadSchema(tier,iss,sub,iat,exp,features).tier=enterprise→ arranca desdeENTERPRISE_FEATURE_DEFAULTS+ los overridesfeaturesdel JWT.- Caducado/inválido → fallback Community con warning.
Graceful degradation: getLicenseInfo() comprueba la caducidad en runtime; si Enterprise caduca durante su uso, degrada a Community sin reiniciar. requireFeature(flag) → HTTP 402 si está deshabilitado; requireFeatureLimit(flag, model) → 402 si count >= limit (Enterprise = Infinity).
Flags commodity siempre activos: desde la eliminación EPA-02, los 8 flags commodity ya no existen en FEATURE_FLAGS - webhooks, push_notifications, web search, memory, lead_export, widget_analytics, auto_title, synthesis_rate_limit están siempre activos en Community (las rutas commodity corren sin gating). priority_support no es un flag: es un contrato comercial/SLA (EPA-08). Quedan 11 flags enterprise, incluidos widget_credits_editing (edición de créditos widget, Community false / Enterprise true) y custom_agents como límite numérico (Community 3, Enterprise Infinity).
Tabla de flags (11)
| Flag | Tipo | Community | Enterprise | Qué gatea |
|---|---|---|---|---|
sso_enabled | bool | false | true | SSO Enterprise |
audit_log_immutable | bool | false | true | Inmutabilidad del audit log |
white_label | bool | false | true | Branding BRANDING_* |
max_workspaces | num | 3 | Infinity | Creación de workspaces |
max_projects | num | 3 | Infinity | Creación de proyectos |
custom_agents | num | 3 | Infinity | Agentes custom (límite) |
widget_enabled | bool | false | true | Widget embebible |
max_widgets | num | 1 | Infinity | Creación de widgets |
backup_enabled | bool | false | true | Sistema de backup |
max_backup_destinations | num | 1 | Infinity | Destinos de backup |
widget_credits_editing | bool | false | true | Edición de créditos widget |
Runtime config (DB SystemConfig)
Editable via GET/PUT /api/system/settings (bulk) y PUT /api/system/chat-retention (específica, auditada). Los defaults viven en CONFIG_DEFAULTS (packages/shared/src/constants/permissions.ts).
Grupos de claves: LLM (LLM_PROVIDER, LLM_MODEL, LLM_TEMPERATURE, ...), Embedding/Vector, Puertos/URLs del 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 siempre devuelve 200 con { updated: [...], rejected: [...] } (las claves readonly son rechazadas mientras las demás se aplican).
Retención de mensajes de chat (reaper)
Servicio: packages/server/src/services/chatMessageReaperJob.ts. Knob DB: chat_message_retention_days.
- Pass 1 (soft-delete): tombstones mensajes de chats ACTIVOS más allá de
retentionDays. No-op cuando el valor esnull/""/<=0. - Pass 2 (hard-purge): elimina filas tombstonadas más allá de una gracia de 7 días (hardcoded). Siempre corre, independientemente de la config de retención (anti-PII leak).
- Cadencia:
setIntervalde 24h, primer run a las 03:00 hora local. MutexisRunning. - Solo
PUT /api/system/chat-retention(auditada,confirmDataLoss: true,retentionDays: integer|null, min 1); el endpoint bulk rechaza esta clave.
Retención de backups
Por job (el campo retentionDays en BackupJob, default 30). backupRetentionService.ts limpia logs/archivos más allá de cutoffDate. No es global.
Rotación de claves de cifrado
packages/server/src/services/encryptionService.ts (AES-256-GCM, clave de 32 bytes, IV de 16 bytes, salt simmetric-chat-encryption-salt).
- Clave actual:
ENCRYPTION_KEY(base64 32 bytes) si está definida; si noscryptSync(JWT_SECRET, salt, 32). LEGACY_PREVIOUS_ENCRYPTION_KEYS(CSV base64 32 bytes) → cadena de claves de descifrado[current, ...previous, scryptLegacy?].encrypt()usachain[0]. No existe job automático de re-encriptación: el procedimiento es manual decrypt-con-old → re-encrypt-con-new.
Cross-link
- Endpoints de settings: 04 - API Reference
- Funciones internas: 05 - Feature Guide
- Env vars de deploy: 09 - Deployment