# Configuration

All application configuration is managed through the central `getConfig()` function in `src/lib/core/config.ts`. Environment variables are the default source, but the abstraction supports swapping to database-backed configuration.

> **Rule**: Never read `process.env` directly in application code. Always use `getConfig()`.

## Environment Variables Reference

### Required

| Variable | Description | Default |
|----------|-------------|---------|
| `JWT_SECRET` | Secret for JWT signing (min 32 chars) | — |

### Database

| Variable | Description | Default |
|----------|-------------|----------|
| `DB_PROVIDER` | Database backend: `sqlite` or `mongodb` | `sqlite` |
| `SQLITE_DATA_DIR` | Data directory for SQLite files | `./data` |
| `MONGODB_URI` | MongoDB connection string (required when `DB_PROVIDER=mongodb`) | — |
| `MAIN_DB_NAME` | Main database name | `console_main` |
| `MONGODB_MIN_POOL_SIZE` | Min connection pool size | `2` |
| `MONGODB_MAX_POOL_SIZE` | Max connection pool size | `10` |
| `MONGODB_CONNECT_TIMEOUT_MS` | Connection timeout | `10000` |
| `MONGODB_SOCKET_TIMEOUT_MS` | Socket timeout | `45000` |
| `MONGODB_SERVER_SELECTION_TIMEOUT_MS` | Server selection timeout | `30000` |

### Authentication

| Variable | Description | Default |
|----------|-------------|---------|
| `JWT_EXPIRES_IN` | JWT token expiry | `7d` |
| `PROVIDER_ENCRYPTION_SECRET` | Encryption key for provider credentials | Falls back to `JWT_SECRET` |

### Gateway (Resilience)

| Variable | Description | Default |
|----------|-------------|---------|
| `GATEWAY_REQUEST_TIMEOUT_MS` | Request timeout for provider calls | `120000` |
| `GATEWAY_RETRY_ENABLED` | Enable automatic retries | `true` |
| `GATEWAY_RETRY_MAX_ATTEMPTS` | Maximum retry attempts | `3` |
| `GATEWAY_RETRY_INITIAL_DELAY_MS` | Initial retry delay (exponential) | `200` |
| `GATEWAY_CIRCUIT_BREAKER_ENABLED` | Enable circuit breaker | `true` |
| `GATEWAY_CIRCUIT_BREAKER_THRESHOLD` | Failures before opening circuit | `5` |
| `GATEWAY_CIRCUIT_BREAKER_RESET_MS` | Time before half-open test | `30000` |

### Cache

| Variable | Description | Default |
|----------|-------------|---------|
| `CACHE_PROVIDER` | Cache backend: `none`, `memory`, `redis` | `memory` |
| `CACHE_TTL_SECONDS` | Default cache TTL | `300` |
| `REDIS_URL` | Redis connection URL (required when provider=redis) | — |
| `REDIS_KEY_PREFIX` | Key prefix for Redis cache | `console:` |

### Rate Limiting

| Variable | Description | Default |
|----------|-------------|---------|
| `RATE_LIMIT_PROVIDER` | Provider: `mongodb`, `memory`, `redis`. `memory` and `redis` require the same `CACHE_PROVIDER`. | `mongodb` |
| `RATE_LIMIT_SYNC_INTERVAL_MS` | Sync interval for distributed counters | `5000` |

### Browser Runtime

| Variable | Description | Default |
|----------|-------------|---------|
| `BROWSER_BLOCK_PRIVATE_NETWORK` | Blocks localhost, link-local, private, and reserved network egress from managed browser sessions. | `true` |

### JS Sandbox Runtime

| Variable | Description | Default |
|----------|-------------|---------|
| `JS_SANDBOX_DEFAULT_MAX_CONCURRENT` | Concurrent JS executions per tenant | `5` |
| `JS_SANDBOX_DEFAULT_TIMEOUT_MS` | Default execution timeout | `5000` |
| `JS_SANDBOX_MAX_TIMEOUT_MS` | Maximum execution timeout | `30000` |
| `JS_SANDBOX_MEMORY_LIMIT_MB` | V8 isolate memory limit | `64` |
| `JS_SANDBOX_MAX_CODE_SIZE_BYTES` | Maximum submitted code size | `65536` |
| `JS_SANDBOX_MAX_RESULT_SIZE_BYTES` | Maximum serialized result size | `524288` |
| `JS_SANDBOX_MAX_LOG_ENTRIES` | Maximum captured console log entries | `100` |

### Cluster & Queue

| Variable | Description | Default |
|----------|-------------|---------|
| `NODE_ROLE` | Node role: `main`, `worker`, or `all` | `all` |
| `NODE_NAME` | Unique node name (used in the cluster registry) | `<hostname>-<pid>` |
| `CLUSTER_DEFAULT_NODE_NAME` | Default node for new instance assignments | First online node |
| `QUEUE_PROVIDER` | Queue backend: `auto`, `memory`, `bullmq` | `auto` (bullmq when Redis is configured) |
| `QUEUE_REDIS_URL` | Redis URL for BullMQ | Falls back to `REDIS_URL` |
| `QUEUE_PREFIX` | BullMQ key prefix | `console:q:` |
| `QUEUE_DEFAULT_ATTEMPTS` | Default retry attempts per job | `3` |
| `QUEUE_DEFAULT_BACKOFF_MS` | Default backoff between retries | `1000` |

See [Cluster](/guide/cluster) for the full topology / assignment model.

### Logging

| Variable | Description | Default |
|----------|-------------|---------|
| `LOG_LEVEL` | Log level: `error`, `warn`, `info`, `debug` | `debug` (dev) / `info` (prod) |
| `LOG_FORMAT` | Output format: `json`, `pretty` | `pretty` (dev) / `json` (prod) |
| `LOG_REQUEST_BODY` | Log request bodies | `false` |
| `LOG_RESPONSE_BODY` | Log response bodies | `false` |

### CORS

| Variable | Description | Default |
|----------|-------------|---------|
| `CORS_ENABLED` | Enable CORS for client API | `false` |
| `CORS_ALLOWED_ORIGINS` | Comma-separated allowed origins | — |
| `CORS_MAX_AGE` | Preflight cache duration (seconds) | `86400` |

### SMTP (Email)

| Variable | Description | Default |
|----------|-------------|---------|
| `SMTP_HOST` | SMTP server host | `smtp.gmail.com` |
| `SMTP_PORT` | SMTP server port | `587` |
| `SMTP_SECURE` | Use TLS | `false` |
| `SMTP_USER` | SMTP username | — |
| `SMTP_PASS` | SMTP password | — |
| `SMTP_FROM` | From address | Falls back to `SMTP_USER` |

### Application

| Variable | Description | Default |
|----------|-------------|---------|
| `NEXT_PUBLIC_APP_URL` | Public application URL | `http://localhost:3000` |
| `SHUTDOWN_TIMEOUT_MS` | Graceful shutdown timeout | `15000` |
| `TRACING_MAX_BODY_SIZE_MB` | Max tracing payload size | `10` |
| `HEALTH_ENDPOINT_ENABLED` | Enable health endpoints | `true` |
| `PROVIDER_RUNTIME_CACHE_TTL_SECONDS` | Runtime pool entry TTL | `300` |

## Config Source Abstraction

The config module uses a `ConfigSource` interface, making it easy to swap between ENV-based and database-backed configuration:

```typescript
interface ConfigSource {
  readonly name: string;
  get(key: string): string | undefined;
}
```

The default `EnvConfigSource` reads from `process.env`. You can replace it:

```typescript
import { setConfigSource } from '@/lib/core/config';

setConfigSource(myDatabaseConfigSource);
```

## Validation

At startup, critical configuration is validated:

```typescript
const cfg = getConfig();
const errors = validateConfig(cfg);
// Checks: MONGODB_URI required, JWT_SECRET required,
// REDIS_URL required when CACHE_PROVIDER=redis, etc.
```

Validation errors are logged but do not crash the server — this allows K8s secrets to be injected after initial startup.

## Example `.env.local`

### SQLite mode (default, zero dependencies)

```bash
# Required
JWT_SECRET=your-secret-key-must-be-at-least-32-chars

# Database (SQLite is the default — no MongoDB needed)
# DB_PROVIDER=sqlite
# SQLITE_DATA_DIR=./data

# Cache
CACHE_PROVIDER=memory

# Logging
LOG_LEVEL=debug
LOG_FORMAT=pretty

# CORS (for client SDKs)
CORS_ENABLED=true
CORS_ALLOWED_ORIGINS=http://localhost:3001,http://localhost:5173
```

### MongoDB mode

```bash
# Required
JWT_SECRET=your-secret-key-must-be-at-least-32-chars

# Database
DB_PROVIDER=mongodb
MONGODB_URI=mongodb://localhost:27017

# Cache
CACHE_PROVIDER=memory
# REDIS_URL=redis://localhost:6379

# Logging
LOG_LEVEL=debug
LOG_FORMAT=pretty

# CORS (for client SDKs)
CORS_ENABLED=true
CORS_ALLOWED_ORIGINS=http://localhost:3001,http://localhost:5173

# SMTP (optional)
# SMTP_HOST=smtp.gmail.com
# SMTP_USER=your@email.com
# SMTP_PASS=your-app-password
```
