# Environment Variables Guide

This document describes all environment variables used by the 4Runr Gateway.

## Quick Start

For local development, copy the configuration below to `infra/.env`:

```bash
# Minimal development configuration
NODE_ENV=development
GATEWAY_PERSISTENCE=persistent
DATABASE_URL=postgresql://4runr:4runr_password@postgres:5432/4runr_gateway
AUTH_ENABLED=true
AUTH_MODE=api_key
API_KEY=test-key
RATE_LIMIT_ENABLED=true
```

## Server Configuration

| Variable | Default | Description |
|----------|---------|-------------|
| `NODE_ENV` | `development` | Environment: `development`, `production`, or `test` |
| `PORT` | `3000` | Server port |
| `HOST` | `127.0.0.1` | Server host (use `0.0.0.0` for Docker) |

## Persistence Configuration

| Variable | Default | Description |
|----------|---------|-------------|
| `GATEWAY_PERSISTENCE` | `persistent` | Options: `memory`, `persistent`, `postgres` |
| `DATABASE_URL` | - | PostgreSQL connection string (required unless `memory` mode) |

**Persistence Modes:**
- `memory`: No database/filesystem persistence (for testing)
- `persistent` or `postgres`: Use PostgreSQL database

## Authentication Configuration

| Variable | Default | Description |
|----------|---------|-------------|
| `AUTH_ENABLED` | `true` | Enable/disable authentication |
| `AUTH_MODE` | `api_key` | Authentication mode: `api_key`, `jwt`, or `mixed` |
| `API_KEY` | - | API key(s) for memory mode (comma-separated) |
| `JWT_SECRET` | - | JWT signing secret (min 32 chars, required for jwt/mixed mode) |
| `JWT_ALG` | `HS256` | JWT algorithm: `HS256`, `HS384`, or `HS512` |

**Authentication Modes:**

1. **`api_key`** (Default): Only API key authentication
   - Clients must provide `x-api-key` header
   - Keys validated against database (postgres mode) or env var (memory mode)

2. **`jwt`**: Only JWT authentication
   - Clients must provide `Authorization: Bearer <token>` header
   - Requires `JWT_SECRET` to be set

3. **`mixed`**: Accept either API key OR JWT
   - Clients can use either authentication method
   - Useful for migration scenarios or supporting multiple client types

**API Key Format:**
```bash
# Single key
API_KEY=your-api-key-here

# Multiple keys (memory mode only)
API_KEY=key1,key2,key3
```

**JWT Token Format:**
```
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```

**JWT Payload Structure:**
```json
{
  "sub": "user-id",
  "tenantId": "tenant-id",
  "roles": ["admin", "user"],
  "exp": 1234567890,
  "iat": 1234567890
}
```

## Rate Limiting Configuration

| Variable | Default | Description |
|----------|---------|-------------|
| `RATE_LIMIT_ENABLED` | `true` | Enable/disable rate limiting |
| `RATE_LIMIT_MAX` | `60` | Maximum requests per time window |
| `RATE_LIMIT_WINDOW_MS` | `60000` | Time window in milliseconds (60000 = 1 minute) |

**Rate Limiting Behavior:**
- Limits are applied per identity (API key, JWT sub, or IP address)
- Different endpoints may have different limits:
  - **Read operations**: Full limit (e.g., 60/min)
  - **Write operations**: 75% of limit (e.g., 45/min)
  - **Expensive operations**: 50% of limit (e.g., 30/min)
- When limit is exceeded, returns `429 Too Many Requests` with retry information

**Example Error Response:**
```json
{
  "error": "rate_limited",
  "message": "Too many requests, please try again later",
  "retry_after_ms": 45000,
  "limit": 60,
  "window_ms": 60000
}
```

## Security Configuration

| Variable | Default | Description |
|----------|---------|-------------|
| `ENCRYPTION_KEY` | - | Encryption key for sensitive data (min 32 chars) |

**Security Features:**
- **Security Headers**: Automatically set (CSP, HSTS, X-Frame-Options, etc.)
- **Secrets Validation**: Automatic validation on startup
- **Error Masking**: 500 errors masked in production
- **Correlation IDs**: Included in all error responses

**Security Headers Set:**
- `Content-Security-Policy`
- `Strict-Transport-Security` (HTTPS only)
- `X-Content-Type-Options: nosniff`
- `X-Frame-Options: DENY`
- `X-XSS-Protection: 1; mode=block`
- `Referrer-Policy: strict-origin-when-cross-origin`
- `Permissions-Policy`
- `Cross-Origin-Embedder-Policy`
- `Cross-Origin-Opener-Policy`
- `Cross-Origin-Resource-Policy`

**Secrets Validation:**
On startup, the gateway validates:
- JWT_SECRET length (min 32 chars)
- No insecure default values
- Required secrets for production mode

## Redis Configuration

| Variable | Default | Description |
|----------|---------|-------------|
| `REDIS_URL` | - | Redis connection URL (required for queue, rate limiting, idempotency) |

**Redis Usage:**
- **Queue System**: BullMQ uses Redis for job queue management
- **Rate Limiting**: Per-tenant rate limiting with Redis backing
- **Idempotency**: Idempotency key storage and caching
- **Caching**: General caching (future use)

**Redis Connection:**
```bash
# Local development
REDIS_URL=redis://localhost:6379

# Docker Compose
REDIS_URL=redis://redis:6379

# Production with password
REDIS_URL=redis://:password@redis-host:6379
```

**Note**: Gateway will fall back to synchronous execution if Redis is unavailable, but queue, rate limiting, and idempotency features will be disabled.

## Logging Configuration

| Variable | Default | Description |
|----------|---------|-------------|
| `LOG_LEVEL` | `info` | Log level: `error`, `warn`, `info`, or `debug` |

## Development Settings

| Variable | Default | Description |
|----------|---------|-------------|
| `DEV_MODE` | `false` | Enable development mode features |
| `ALLOW_LOCALHOST_ONLY` | `true` | Restrict to localhost connections only |

## Queue Configuration

| Variable | Default | Description |
|----------|---------|-------------|
| `REDIS_URL` | - | Redis URL (required for queue system) |

**Queue Features:**
- **Priority Support**: High, normal, and low priority queues
- **Retry Logic**: Automatic retries with exponential backoff (3 attempts)
- **Job Retention**: Completed jobs retained for 24 hours, failed for 7 days
- **Graceful Shutdown**: Jobs properly handled during shutdown

**Queue Behavior:**
- Automatically enabled when Redis is available
- Falls back to synchronous execution if Redis unavailable
- Jobs processed with priority ordering (high → normal → low)

## Idempotency Configuration

| Variable | Default | Description |
|----------|---------|-------------|
| `REDIS_URL` | - | Redis URL (required for idempotency) |

**Idempotency Features:**
- **Duplicate Prevention**: Same request with same idempotency key returns cached response
- **Key Expiration**: Idempotency keys expire after TTL
- **Route Scoping**: Keys are scoped per route

**Usage:**
```bash
curl -X POST http://localhost:3000/api/runs \
  -H "x-api-key: your-key" \
  -H "Idempotency-Key: unique-key-123" \
  -H "Content-Type: application/json" \
  -d '{"name": "My Run", "input": {}}'
```

## Health Check Configuration

Health checks are automatically available at:
- `/health` - Liveness probe (server is running)
- `/ready` - Readiness probe (server and dependencies ready)
- `/startup` - Startup probe (server has completed startup)

**Dependencies Checked:**
- PostgreSQL connection (if in postgres mode)
- Redis connection (if REDIS_URL is set)
- Queue system initialization

## Sentinel Configuration (AI Safety)

| Variable | Default | Description |
|----------|---------|-------------|
| `SENTINEL_ENABLED` | `true` | Enable/disable Sentinel integration |
| `SENTINEL_MODE` | `live` | Options: `live` or `mock` |
| `SENTINEL_SHIELD_MODE` | `enforce` | Options: `enforce`, `monitor`, or `off` |
| `SENTINEL_STORE_PLAIN` | `true` | Store plain data (not recommended for production) |

**Sentinel Features:**
- **Policy Enforcement**: Max duration, token limits, custom policies
- **Kill Switch**: Emergency run termination
- **Event Streaming**: Real-time events via SSE
- **Audit Trails**: Complete audit logging

## Production Configuration

For production, ensure:

1. **Required variables are set:**
   - `DATABASE_URL` (strong password, secure connection)
   - `JWT_SECRET` (if using JWT auth)
   - `ENCRYPTION_KEY`

2. **Security settings:**
   - `AUTH_ENABLED=true`
   - `SENTINEL_STORE_PLAIN=false`
   - Strong secrets (use `openssl rand -base64 32` to generate)

3. **Rate limiting:**
   - Adjust `RATE_LIMIT_MAX` based on expected traffic
   - Consider using Redis for distributed rate limiting

**Example Production Configuration:**
```bash
NODE_ENV=production
GATEWAY_PERSISTENCE=postgres
DATABASE_URL=postgresql://user:strong-password@db-host:5432/4runr_gateway
REDIS_URL=redis://redis-host:6379

AUTH_ENABLED=true
AUTH_MODE=mixed
JWT_SECRET=<generated-with-openssl-rand>
JWT_ALG=HS256

RATE_LIMIT_ENABLED=true
RATE_LIMIT_MAX=100
RATE_LIMIT_WINDOW_MS=60000

SENTINEL_ENABLED=true
SENTINEL_MODE=live
SENTINEL_SHIELD_MODE=enforce
SENTINEL_STORE_PLAIN=false

LOG_LEVEL=warn
ENCRYPTION_KEY=<generated-with-openssl-rand>
```

## Testing Different Auth Modes

### API Key Only
```bash
AUTH_ENABLED=true
AUTH_MODE=api_key
API_KEY=test-key

# Test
curl -H "x-api-key: test-key" http://localhost:3000/api/runs
```

### JWT Only
```bash
AUTH_ENABLED=true
AUTH_MODE=jwt
JWT_SECRET=development_jwt_secret_key_min_32_chars_long_12345

# Test (you'll need to generate a valid JWT token)
curl -H "Authorization: Bearer <your-jwt-token>" http://localhost:3000/api/runs
```

### Mixed Mode
```bash
AUTH_ENABLED=true
AUTH_MODE=mixed
API_KEY=test-key
JWT_SECRET=development_jwt_secret_key_min_32_chars_long_12345

# Test with API key
curl -H "x-api-key: test-key" http://localhost:3000/api/runs

# Test with JWT
curl -H "Authorization: Bearer <your-jwt-token>" http://localhost:3000/api/runs
```

### No Authentication (Dev Only)
```bash
AUTH_ENABLED=false

# Test (no credentials needed)
curl http://localhost:3000/api/runs
```

## Validation Errors

All API endpoints now validate input. Invalid requests return `400 Bad Request`:

```json
{
  "error": "invalid_request",
  "message": "Request body validation failed",
  "details": {
    "fieldErrors": {
      "name": ["Name is required"],
      "input": ["Expected object, received string"]
    },
    "formErrors": []
  }
}
```

## Environment Variable Loading

The gateway loads environment variables in this order:

1. System environment variables
2. `infra/.env` file (if it exists)
3. Docker Compose environment section
4. Default values

To override, set variables in this priority order (highest to lowest):
1. Docker Compose `environment` section
2. `infra/.env` file
3. System environment

