> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ferrum.thalamiq.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration

> Configure Ferrum with config.yaml and environment variables.

## Overview

Configuration is loaded in this order (later overrides earlier):

1. Built-in defaults
2. `config.yaml` (optional)
3. Environment variables with `FHIR__` prefix (e.g. `FHIR__SERVER__PORT`)
4. `DATABASE_URL` fallback for `database.url` when `FHIR__DATABASE__URL` is unset
5. Runtime overrides in PostgreSQL (Admin UI / Admin API)

Nested keys map to env vars via `__`: `FHIR__DATABASE__URL` → `database.url`. Arrays use comma: `FHIR__SERVER__CORS_ORIGINS=https://a.com,https://b.com`.

## Config Reference

### `server`

| Option                   | Default            | Description                            |
| ------------------------ | ------------------ | -------------------------------------- |
| `host`                   | `"0.0.0.0"`        | Bind address                           |
| `port`                   | `8080`             | Listen port                            |
| `cors_origins`           | `[]`               | Allowed CORS origins (empty = no CORS) |
| `max_request_body_size`  | `10485760` (10 MB) | Max request body bytes                 |
| `max_response_body_size` | `52428800` (50 MB) | Max response body bytes                |

### `database`

| Option                        | Default                                   | Description                        |
| ----------------------------- | ----------------------------------------- | ---------------------------------- |
| `url`                         | `"postgresql://fhir:fhir@localhost/fhir"` | Connection string                  |
| `test_database_url`           | `null`                                    | Override for test environments     |
| `pool_min_size`               | `2`                                       | API server pool min connections    |
| `pool_max_size`               | `20`                                      | API server pool max connections    |
| `pool_timeout_seconds`        | `60`                                      | API server pool timeout            |
| `worker_pool_min_size`        | `1`                                       | Worker pool min connections        |
| `worker_pool_max_size`        | `5`                                       | Worker pool max connections        |
| `worker_pool_timeout_seconds` | `60`                                      | Worker pool timeout                |
| `indexing_batch_size`         | `50`                                      | Resources per indexing batch       |
| `indexing_bulk_threshold`     | `200`                                     | Min resources to use bulk indexing |
| `statement_timeout_seconds`   | `300`                                     | Max query execution time           |
| `lock_timeout_seconds`        | `30`                                      | Max lock wait time                 |

### `fhir`

| Option                      | Default            | Description                                                       |
| --------------------------- | ------------------ | ----------------------------------------------------------------- |
| `version`                   | `"R4"`             | FHIR version (R4, R4B, R5)                                        |
| `default_format`            | `"json"`           | Default format (json, xml)                                        |
| `default_prefer_return`     | `"representation"` | Prefer header default (minimal, representation, operationoutcome) |
| `allow_update_create`       | `true`             | Allow PUT to create resources                                     |
| `hard_delete`               | `false`            | Physical delete vs soft-delete                                    |
| `install_internal_packages` | `true`             | Install bundled packages from `fhir_packages/`                    |
| `internal_packages_dir`     | `null`             | Override path for internal packages                               |
| `registry_url`              | `null`             | Custom package registry URL                                       |

**`fhir.interactions`** — Toggle FHIR operations. All default to `true`.

* `system`: capabilities, search, history, delete, batch, transaction, history\_bundle
* `type_level`: create, conditional\_create, search, history, conditional\_update, conditional\_patch, conditional\_delete
* `instance`: read, vread, update, patch, delete, history, delete\_history, delete\_history\_version
* `compartment`: search
* `operations`: system, type\_level, instance

**`fhir.search`**

| Option                             | Default              | Description                                                         |
| ---------------------------------- | -------------------- | ------------------------------------------------------------------- |
| `inline_indexing`                  | `true`               | Index synchronously during CRUD; set `false` for large bulk ingests |
| `enable_text`                      | `true`               | Enable `_text` search                                               |
| `enable_content`                   | `true`               | Enable `_content` search                                            |
| `default_count`                    | `20`                 | Default page size                                                   |
| `max_count`                        | `1000`               | Max `_count` value                                                  |
| `max_total_results`                | `10000`              | Max total results across pages                                      |
| `max_include_depth`                | `3`                  | Max `_include`/`_revinclude` depth                                  |
| `max_includes`                     | `10`                 | Max `_include` parameters                                           |
| `search_parameter_active_statuses` | `["draft","active"]` | Active SearchParameter statuses                                     |

**`fhir.fhirpath`**

| Option                 | Default | Description                                 |
| ---------------------- | ------- | ------------------------------------------- |
| `enable_resolve`       | `true`  | Allow `resolve()` for references            |
| `enable_external_http` | `false` | Allow external HTTP fetches (security risk) |
| `resolve_cache_size`   | `100`   | LRU cache size for resolved resources       |
| `http_timeout_seconds` | `5`     | Timeout for external HTTP                   |

**`fhir.referential_integrity`**

| Option | Default     | Description                                                                         |
| ------ | ----------- | ----------------------------------------------------------------------------------- |
| `mode` | `"lenient"` | `lenient` (no checks) or `strict` (reject broken refs, block deletes of referenced) |

**`fhir.default_packages`** — core, extensions, terminology. Each: `install`, `install_examples`, `include_resource_types`, `exclude_resource_types` (mutually exclusive).

**`fhir.packages`** — Additional packages: `name`, `version`, `install_examples`, `include_resource_types`, `exclude_resource_types`.

**`fhir.capability_statement`** — Metadata for GET /metadata: `id`, `name`, `title`, `publisher`, `description`, `software_name`, `software_version`, `contact_email`, `supported_resources`.

### `workers`

| Option                      | Default | Description                                                            |
| --------------------------- | ------- | ---------------------------------------------------------------------- |
| `enabled`                   | `true`  | Enable background workers                                              |
| `embedded`                  | `true`  | Run workers in server process; `false` = separate `fhir-worker` binary |
| `poll_interval_seconds`     | `5`     | Poll interval (plus LISTEN/NOTIFY)                                     |
| `max_concurrent_jobs`       | `1`     | Max concurrent jobs                                                    |
| `reconnect_initial_seconds` | `1`     | Initial reconnect backoff                                              |
| `reconnect_max_seconds`     | `30`    | Max reconnect backoff                                                  |
| `reconnect_jitter_ratio`    | `0.2`   | Jitter for reconnect (0–1)                                             |

### `logging`

| Option                   | Default                   | Description                     |
| ------------------------ | ------------------------- | ------------------------------- |
| `level`                  | `"info"`                  | trace, debug, info, warn, error |
| `json`                   | `false`                   | JSON log format                 |
| `file_enabled`           | `false`                   | Enable file logging             |
| `file_directory`         | `"./logs"`                | Log file directory              |
| `file_prefix`            | `"fhir-server"`           | Log file prefix                 |
| `file_rotation`          | `"daily"`                 | daily, hourly, minutely, never  |
| `opentelemetry_enabled`  | `false`                   | OpenTelemetry integration       |
| `otlp_endpoint`          | `"http://localhost:4317"` | OTLP endpoint                   |
| `trace_sample_ratio`     | `1.0`                     | Trace sampling (0–1)            |
| `service_name`           | `"fhir-server"`           | Service name                    |
| `deployment_environment` | `"development"`           | dev, staging, prod              |
| `service_version`        | `null`                    | Override version                |
| `otlp_timeout_seconds`   | `10`                      | OTLP export timeout             |

**`logging.audit`** — Audit logging for FHIR operations.

| Option                          | Default | Description                           |
| ------------------------------- | ------- | ------------------------------------- |
| `enabled`                       | `true`  | Master switch                         |
| `include_success`               | `true`  | Record successful interactions        |
| `include_authz_failure`         | `true`  | Record 401/403                        |
| `include_processing_failure`    | `true`  | Record other failures                 |
| `capture_search_query`          | `true`  | Capture search request in AuditEvent  |
| `capture_operation_outcome`     | `true`  | Capture OperationOutcome on failure   |
| `per_patient_events_for_search` | `true`  | One AuditEvent per patient for search |

**`logging.audit.interactions`** — Per-interaction audit toggles: read, vread, history, search, create, update, patch, delete, capabilities (default: false), operation, batch, transaction, export.

### `ui`

| Option                | Default        | Description                                           |
| --------------------- | -------------- | ----------------------------------------------------- |
| `enabled`             | `true`         | Enable admin UI                                       |
| `title`               | `"FHIR Admin"` | Browser tab title                                     |
| `password`            | `null`         | Admin password (use `FHIR__UI__PASSWORD` for secrets) |
| `session_secret`      | `null`         | Session signing key (recommended in production)       |
| `session_ttl_seconds` | `43200` (12h)  | Session lifetime                                      |

### `auth`

| Option         | Default                                    | Description                     |
| -------------- | ------------------------------------------ | ------------------------------- |
| `enabled`      | `false`                                    | Enable OIDC authentication      |
| `required`     | `true`                                     | Reject unauthenticated requests |
| `public_paths` | health, /, favicon, metadata, smart-config | Paths that skip auth            |

**`auth.oidc`** — Required when `auth.enabled=true`: `issuer_url`, `audience`. Optional: `jwks_url`, `jwks_cache_ttl_seconds` (300), `http_timeout_seconds` (5).

## Example

```yaml theme={null}
server:
  host: "0.0.0.0"
  port: 8080

database:
  url: "postgresql://fhir:fhir@db:5432/fhir"

fhir:
  version: "R4"
  allow_update_create: true
  hard_delete: false
  search:
    max_count: 1000

workers:
  embedded: true

ui:
  password: null  # Use FHIR__UI__PASSWORD in production

auth:
  enabled: false
```

## Runtime Configuration

A subset of settings can be changed at runtime via Admin UI (Settings) or Admin API (`GET/PUT /admin/config/{key}`). Stored in PostgreSQL; multi-instance sync via LISTEN/NOTIFY. See `apps/server/src/runtime_config/keys.rs` for supported keys.
