Skip to main content

Configuration Reference

DVARA is configured through application.yml with environment variable overrides. Configuration is partitioned across three namespace families:

  • Cross-cutting (dvara.*) — license, audit, encryption, region, credentials, vault, actuator. Every DVARA app reads them.
  • LLM Gateway (dvara.llm-gateway.*) — providers, routes, resilience, rate-limit, cache, PII, guardrails, webhooks, IP access, FinOps, routing strategies.
  • Flightdeck / MCP-only (dvara.flightdeck.* and dvara.mcp-gateway.*) — admin UI, OIDC/SAML, compliance, agentic governance, MCP-proxy timeouts. Bound only by the apps that need them.

Spring relaxed binding maps every property to an env var by uppercasing and replacing dots/hyphens with underscores — dvara.llm-gateway.providers.openai.api-key is settable as DVARA_LLM_GATEWAY_PROVIDERS_OPENAI_API_KEY or, more commonly, via the explicit env-var aliases like OPENAI_API_KEY declared in application.yml (see below).

SaaS-mode property surface

The dvara.flightdeck.saas.* properties (Stripe price IDs, webhook signing secret, checkout URLs) plus the SaaS-funnel dvara.flightdeck.email.* configuration are for the dvarahq.com managed install only. They are intentionally not documented here. Self-hosted and managed-hosting customers do not need them — leave dvara.flightdeck.saas.enabled=false (the default) and the surface stays dark even if the JAR is on the classpath.

Configuration Hierarchy

Configuration is resolved in this order (later sources override earlier ones):

  1. Defaults — hardcoded in application.yml
  2. application.yml — file-based configuration
  3. Environment variables — override any property (e.g., OPENAI_API_KEY)
  4. System properties — JVM -D flags
  5. bootstrap.yaml — when DVARA_BOOTSTRAP_FILE is set, seeds tenants, API keys, and routes into the database on first startup (idempotent; re-runs skip rows whose id already exists)
  6. Database (Admin API / Flightdeck writes) — once seeded, ongoing changes to routes, policies, credentials, tenants, budgets, etc. are made through /v1/admin/* REST endpoints or the Flightdeck UI. These writes hot-reload across the fleet via PostgreSQL NOTIFY config_change; the data plane's DataPlaneConfigRefresher picks up the notification and either rebuilds the routing engine (routes), republishes the PolicyMutationEvent (policies), or evicts the relevant cache (credentials, plugins, semantic cache configs). No restart required for any persisted-config change.

Steps 1–4 govern boot-time configuration. Steps 5–6 govern persisted state and shadow the file-based config for the entities they own — once a route exists in the database, the YAML's dvara.llm-gateway.routes: entries no longer apply for that route id.

Full Application Configuration

dvara:
# ── Cross-cutting (every DVARA app reads these) ──
license:
key: ${DVARA_LICENSE_KEY:} # signed DVARA- envelope; required at startup
encryption:
master-password: ${DVARA_ENCRYPTION_MASTER_PASSWORD:}
actuator:
api-key: ${DVARA_ACTUATOR_API_KEY:} # Bearer for /actuator/gateway-status + authenticated actuator paths
metrics-api-key: ${DVARA_ACTUATOR_METRICS_API_KEY:} # Distinct Bearer for /actuator/prometheus
audit:
hmac-secret: ${DVARA_AUDIT_HMAC_SECRET:default-dev-secret-change-in-production}
max-events: ${DVARA_AUDIT_MAX_EVENTS:100000}
store-prompts-by-default: ${DVARA_AUDIT_STORE_PROMPTS:false}
prompt-retention-days: ${DVARA_AUDIT_PROMPT_RETENTION_DAYS:90}
region:
id: ${DVARA_REGION_ID:} # region identity (blank = region-unaware)
name: ${DVARA_REGION_NAME:} # human-readable region name
credentials:
require-tenant-credential: ${DVARA_CREDENTIALS_REQUIRE_TENANT_CREDENTIAL:false}

# ── LLM Gateway ──
llm-gateway:
data-plane:
require-api-key: ${DVARA_LLM_GATEWAY_REQUIRE_API_KEY:false} # set true in production

# ── Provider Configuration ──
providers:
openai:
api-key: ${OPENAI_API_KEY:} # blank = provider disabled
# base-url: https://api.openai.com/v1 # override for Azure / proxy / long-tail OpenAI-compatible upstreams

anthropic:
api-key: ${ANTHROPIC_API_KEY:}

gemini:
api-key: ${GEMINI_API_KEY:}

azure-openai:
api-key: ${AZURE_OPENAI_API_KEY:}
base-url: ${AZURE_OPENAI_BASE_URL:} # required, e.g. https://{resource}.openai.azure.com/openai

mistral:
api-key: ${MISTRAL_API_KEY:}

cohere:
api-key: ${COHERE_API_KEY:}

groq:
api-key: ${GROQ_API_KEY:}

# ── First-class Chinese-region providers ──
qwen:
api-key: ${QWEN_API_KEY:} # Alibaba Dashscope
# base-url defaults to https://dashscope.aliyuncs.com/compatible-mode/v1

deepseek:
api-key: ${DEEPSEEK_API_KEY:}
# base-url defaults to https://api.deepseek.com/v1

moonshot:
api-key: ${MOONSHOT_API_KEY:} # Kimi
# base-url defaults to https://api.moonshot.cn/v1

chatglm:
api-key: ${ZHIPU_API_KEY:} # note: env var is ZHIPU_*, not CHATGLM_*
# base-url defaults to https://open.bigmodel.cn/api/paas/v4

grok:
api-key: ${XAI_API_KEY:} # note: env var is XAI_*, not GROK_*
# base-url defaults to https://api.x.ai/v1

ollama:
enabled: ${OLLAMA_ENABLED:false}
base-url: ${OLLAMA_BASE_URL:http://localhost:11434}

bedrock:
enabled: ${BEDROCK_ENABLED:false}
access-key: ${AWS_ACCESS_KEY_ID:}
secret-key: ${AWS_SECRET_ACCESS_KEY:}
region: ${AWS_REGION:us-east-1}

mock:
enabled: ${MOCK_PROVIDER_ENABLED:false} # dev / CI only — bundles Groovy for scripted matchers
response: "This is a mock response" # static text or `groovy:`-prefixed script
latency-ms: 100 # simulated delay
stream-token-delay-ms: 20 # inter-token SSE delay
error-rate: 0.0 # 0.0–1.0 failure fraction

# ── Route Configuration ──
routes:
- id: load-balance-gpt
model-pattern: "gpt*"
strategy: round-robin
providers:
- provider: openai
- provider: bedrock

- id: weighted-claude
model-pattern: "claude*"
strategy: weighted
providers:
- provider: anthropic
weight: 70
- provider: bedrock
weight: 30

# ── Resilience ──
resilience:
retry:
max-attempts: 3
initial-backoff-ms: 500
backoff-multiplier: 2.0
max-backoff-ms: 10000
circuit-breaker:
failure-rate-threshold: 50
sliding-window-size: 10
minimum-number-of-calls: 5
wait-duration-in-open-state-ms: 30000
permitted-calls-in-half-open: 3
timeout:
chat-timeout-ms: 30000
streaming-timeout-ms: 120000
fallback:
enabled: true

# ── Rate Limiting (always backed by embedded Hazelcast) ──
rate-limit:
enabled: false
per-key:
requests-per-minute: 100 # max requests per API key per 60-second sliding window
tokens-per-minute: 100000 # max tokens per API key per 60-second sliding window

# ── Response Caching (exact-match) ──
cache:
enabled: false
ttl-seconds: 3600
max-size: 10000

# ── Observability ──
management:
endpoints:
web:
exposure:
include: health,prometheus,gateway-status,info # exposed actuator endpoints
exclude: env,heapdump,threaddump,beans,mappings,configprops,loggers,scheduledtasks,caches,sessions,quartz # dangerous endpoints — return 404 regardless of auth
endpoint:
health:
show-details: when-authorized # `always` is rejected at boot; use `when-authorized` or `never`
prometheus:
metrics:
export:
enabled: true # enable Prometheus scrape endpoint
tracing:
sampling:
probability: ${TRACING_SAMPLING_PROBABILITY:1.0} # 0.0–1.0
otlp:
tracing:
endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:http://localhost:4318/v1/traces}

# ── JVM and logging ──
spring:
threads:
virtual:
enabled: true # Project Loom virtual threads
# profiles:
# active: log-plain # switch from JSON to plain-text logging

server:
port: 8080

Environment Variable Reference

Environment VariablePropertyDescription
OPENAI_API_KEYdvara.llm-gateway.providers.openai.api-keyOpenAI API key
ANTHROPIC_API_KEYdvara.llm-gateway.providers.anthropic.api-keyAnthropic API key
GEMINI_API_KEYdvara.llm-gateway.providers.gemini.api-keyGoogle Gemini API key
OLLAMA_ENABLEDdvara.llm-gateway.providers.ollama.enabledEnable Ollama provider
OLLAMA_BASE_URLdvara.llm-gateway.providers.ollama.base-urlOllama server URL
BEDROCK_ENABLEDdvara.llm-gateway.providers.bedrock.enabledEnable AWS Bedrock provider
AWS_ACCESS_KEY_IDdvara.llm-gateway.providers.bedrock.access-keyAWS access key for Bedrock
AWS_SECRET_ACCESS_KEYdvara.llm-gateway.providers.bedrock.secret-keyAWS secret key for Bedrock
AWS_REGIONdvara.llm-gateway.providers.bedrock.regionAWS region for Bedrock
AZURE_OPENAI_API_KEYdvara.llm-gateway.providers.azure-openai.api-keyAzure OpenAI API key
AZURE_OPENAI_BASE_URLdvara.llm-gateway.providers.azure-openai.base-urlAzure OpenAI deployment URL (required)
MISTRAL_API_KEYdvara.llm-gateway.providers.mistral.api-keyMistral API key
COHERE_API_KEYdvara.llm-gateway.providers.cohere.api-keyCohere API key
GROQ_API_KEYdvara.llm-gateway.providers.groq.api-keyGroq API key
QWEN_API_KEYdvara.llm-gateway.providers.qwen.api-keyAlibaba Qwen / Dashscope API key. Default base URL https://dashscope.aliyuncs.com/compatible-mode/v1.
DEEPSEEK_API_KEYdvara.llm-gateway.providers.deepseek.api-keyDeepSeek API key. Default base URL https://api.deepseek.com/v1.
MOONSHOT_API_KEYdvara.llm-gateway.providers.moonshot.api-keyMoonshot / Kimi API key. Default base URL https://api.moonshot.cn/v1.
ZHIPU_API_KEYdvara.llm-gateway.providers.chatglm.api-keyChatGLM / Zhipu API key — note the env-var name is ZHIPU_*, not CHATGLM_* (matches the brand's API auth header). Default base URL https://open.bigmodel.cn/api/paas/v4.
XAI_API_KEYdvara.llm-gateway.providers.grok.api-keyxAI Grok API key — note the env-var name is XAI_*, not GROK_* (matches xAI's auth convention). Default base URL https://api.x.ai/v1.
MOCK_PROVIDER_ENABLEDdvara.llm-gateway.providers.mock.enabledEnable mock provider for testing. Dev / CI only — the Mock provider bundles Groovy for scenario scripting, which means arbitrary code execution inside the gateway JVM. A startup WARN fires whenever Mock is enabled outside the dev / test / ci / local / default Spring profile allow-list.
DVARA_LLM_GATEWAY_PROVIDERS_MOCK_RESPONSEdvara.llm-gateway.providers.mock.responseDefault mock response text (or groovy:-prefixed script)
DVARA_LLM_GATEWAY_PROVIDERS_MOCK_LATENCY_MSdvara.llm-gateway.providers.mock.latency-msSimulated latency per call in ms (default: 100)
DVARA_LLM_GATEWAY_PROVIDERS_MOCK_STREAM_TOKEN_DELAY_MSdvara.llm-gateway.providers.mock.stream-token-delay-msInter-token delay for streaming (default: 20)
DVARA_LLM_GATEWAY_PROVIDERS_MOCK_ERROR_RATEdvara.llm-gateway.providers.mock.error-rateProbability [0.0, 1.0] of injected PROVIDER_ERROR
dvara.llm-gateway.providers.mock.matchersWiremock-style conditional matchers (YAML list — see Provider Setup → Mock)
dvara.llm-gateway.providers.mock.scenarios-dirDirectory of *.groovy scenario files with hot reload
dvara.llm-gateway.providers.mock.console-authoringOpt in to the DVARA Flightdeck authoring UI + REST API at /v1/admin/mock/scenarios/** (default: false)
dvara.llm-gateway.providers.mock.audit-sample-rateFraction of MOCK_MATCHER_FIRED events to audit (default: 1.0)
DVARA_REGION_IDdvara.region.idRegion identity for this gateway instance
DVARA_REGION_NAMEdvara.region.nameHuman-readable region name
TRACING_SAMPLING_PROBABILITYmanagement.tracing.sampling.probabilityTrace sampling rate (0.0–1.0, default: 1.0)
OTEL_EXPORTER_OTLP_ENDPOINTmanagement.otlp.tracing.endpointOTLP HTTP endpoint for trace export
DVARA_FLIGHTDECK_COMPLIANCE_SOC2_SCHEDULEdvara.flightdeck.compliance.soc2-scheduleCron expression for scheduled SOC2 reports
DVARA_FLIGHTDECK_COMPLIANCE_HIPAA_SCHEDULEdvara.flightdeck.compliance.hipaa-scheduleCron expression for scheduled HIPAA reports
DVARA_FLIGHTDECK_COMPLIANCE_GDPR_SCHEDULEdvara.flightdeck.compliance.gdpr-scheduleCron expression for scheduled GDPR reports
DVARA_FLIGHTDECK_COMPLIANCE_DEFAULT_TENANTdvara.flightdeck.compliance.default-tenant-idTenant for scheduled reports (blank = all)
DVARA_FLIGHTDECK_COMPLIANCE_RETENTION_DAYSdvara.flightdeck.compliance.retention-daysReport retention period (default: 365)
DVARA_LLM_GATEWAY_PII_ENABLEDdvara.llm-gateway.pii.enabledEnable PII detection (default: true)
DVARA_LLM_GATEWAY_PII_DEFAULT_ACTIONdvara.llm-gateway.pii.default-actionDefault PII action: LOG, BLOCK, REDACT
DVARA_LLM_GATEWAY_PII_SCAN_RESPONSESdvara.llm-gateway.pii.scan-responsesScan LLM responses for PII (default: true)
DVARA_LLM_GATEWAY_PII_STRIP_BEFORE_CACHEdvara.llm-gateway.pii.strip-before-cacheRedact PII before caching (default: true)
DVARA_LLM_GATEWAY_PII_TOKEN_ENCRYPTION_PASSWORDdvara.llm-gateway.pii.token-encryption-passwordAES-256-GCM key for PII token encryption
DVARA_LLM_GATEWAY_PII_MAX_TOKENS_PER_TENANTdvara.llm-gateway.pii.max-tokens-per-tenantMax PII tokens per tenant (default: 50000)
DVARA_LLM_GATEWAY_PII_TOKEN_RETENTION_DAYSdvara.llm-gateway.pii.token-retention-daysPII token retention period (default: 30)
DVARA_LICENSE_KEYdvara.license.keySigned DVARA license key for enterprise features
DVARA_ACTUATOR_API_KEYdvara.actuator.api-keyShared-secret Bearer required on /actuator/gateway-status and every authenticated actuator path except /actuator/prometheus. Generate with openssl rand -base64 32. Set the same value on the DVARA Flightdeck so it can fetch the rich status payload that powers the License page. The legacy property name gateway.control-plane.api-key (env: GATEWAY_CONTROL_PLANE_API_KEY) is accepted as a one-release fallback with a deprecation WARN; the legacy property name is removed in 1.1.0-GA. The current DVARA_ACTUATOR_API_KEY env var is the canonical name and not subject to removal.
DVARA_ACTUATOR_METRICS_API_KEYdvara.actuator.metrics-api-keyDistinct Bearer required only on /actuator/prometheus. Generate independently — a leaked metrics-scrape token must not unlock the license envelope. Configure your Prometheus scrape job's bearer_token_file to point at this value.
DVARA_LLM_GATEWAY_REQUIRE_API_KEYdvara.llm-gateway.data-plane.require-api-keyRequire a valid API key on every /v1/* request (default: false). When true, requests without a valid Authorization: Bearer header are rejected with 401.
DVARA_CREDENTIALS_REQUIRE_TENANT_CREDENTIALdvara.credentials.require-tenant-credentialStrict-BYOK enforcement (default: false). When true, tenants without their own active provider credential are rejected with TENANT_CREDENTIAL_REQUIRED (HTTP 403) instead of borrowing the platform-default credential. Per-tenant override via Tenant.metadata["credentials.require-tenant-credential"].
dvara.llm-gateway.credentials.grace-expiry-initial-delay-msInitial delay before the first credential grace-expiry sweep runs after startup (default: 60000).
dvara.llm-gateway.credentials.grace-expiry-interval-msInterval between credential grace-expiry sweeps (default: 60000). Each sweep transitions expired GRACE credentials to SUPERSEDED and emits a CREDENTIAL_GRACE_EXPIRED audit event.
DVARA_FLIGHTDECK_PLAYGROUND_ENABLEDdvara.flightdeck.playground.enabledEnable the Flightdeck Playground (Console /playground for owner + Portal /portal/playground for tenant admin / developer; default: true). Set false in production to prevent ad-hoc LLM calls from the Console + Portal.
DVARA_ENCRYPTION_MASTER_PASSWORDdvara.encryption.master-passwordAES-256-GCM master password for ENC: decryption and database credential storage. Required for credentials created in ENCRYPTED storage mode (the default). Optional for REFERENCE-only deployments — REFERENCE credentials store only a vault pointer and never hit the AES path, so a zero-trust deployment that creates all credentials with storageMode=REFERENCE can omit this property entirely.
DVARA_FLIGHTDECK_SECURITY_ENABLEDdvara.flightdeck.security.enabledEnable authentication for admin endpoints (default: true). When true with no OIDC issuer-uri, built-in email/password auth activates.
DVARA_FLIGHTDECK_OIDC_ISSUER_URIdvara.flightdeck.security.oidc.issuer-uriOIDC issuer for JWT validation
DVARA_FLIGHTDECK_OIDC_AUDIENCEdvara.flightdeck.security.oidc.audienceExpected JWT audience
DVARA_FLIGHTDECK_OIDC_ROLE_CLAIMdvara.flightdeck.security.oidc.role-claimJWT claim for roles (default: roles)
DVARA_FLIGHTDECK_RBAC_ENABLEDdvara.flightdeck.security.rbac.enabledEnable URL-pattern RBAC (default: true)
DVARA_AUDIT_HMAC_SECRETdvara.audit.hmac-secretHMAC-SHA256 key for signing audit events
DVARA_AUDIT_MAX_EVENTSdvara.audit.max-eventsAudit store capacity (default: 100000)
DVARA_VAULT_BACKENDdvara.vault.backendVault backend: hashicorp, aws-secrets-manager, azure-key-vault
DVARA_LLM_GATEWAY_IP_ACCESS_ENABLEDdvara.llm-gateway.ip-access.enabledEnable IP allowlist/denylist (default: false)
DVARA_LLM_GATEWAY_WEBHOOKS_ENABLEDdvara.llm-gateway.webhooks.enabledEnable webhook delivery (default: true)
DVARA_DB_POOL_SIZEspring.datasource.hikari.maximum-pool-sizeJDBC connection pool size (default: 2 for data plane)
DVARA_CONFIG_FILEPath to gateway.yaml (default: ./gateway.yaml)
DVARA_API_KEYStatic API key for standalone mode
DVARA_BOOTSTRAP_FILEPath to bootstrap.yaml for first-startup seeding

Provider Credential Management

Provider API keys (OpenAI, Anthropic, Gemini, etc.) can be configured through three methods. The gateway checks them in priority order — the first match wins:

1. Database credential (DVARA Flightdeck / API) → highest priority
2. Vault (HashiCorp, AWS SM, Azure KV) → middle priority
3. Environment variable / property → lowest priority (fallback)

Method 1: Environment Variables (simplest)

Set the API key as an environment variable. This is the quickest way to get started:

export OPENAI_API_KEY=sk-your-key
export ANTHROPIC_API_KEY=sk-ant-your-key

The gateway reads these at startup. To change a key, you must restart the gateway.

Store credentials in the database through the DVARA Flightdeck or REST API. Keys are encrypted with AES-256-GCM before storage and decrypted at request time. No restart needed for rotation.

Prerequisites: Set DVARA_ENCRYPTION_MASTER_PASSWORD for AES encryption.

Via the DVARA Flightdeck:

  1. Navigate to CredentialsAdd Credential
  2. Select the provider and enter the API key
  3. The key is encrypted and stored — it takes effect immediately

Via the API:

# Create a credential
curl -X POST http://localhost:8090/v1/admin/credentials \
-H "Content-Type: application/json" \
-d '{
"name": "openai-prod",
"provider": "openai",
"secretKey": "provider.openai.api-key",
"apiKey": "sk-your-actual-key"
}'

# Rotate (new key takes effect immediately)
curl -X POST http://localhost:8090/v1/admin/credentials/{id}/rotate \
-H "Content-Type: application/json" \
-d '{"apiKey": "sk-new-key"}'

# Revoke (falls back to vault or env var)
curl -X POST http://localhost:8090/v1/admin/credentials/{id}/revoke

Delegate credential storage to an external secrets manager. See Vault Configuration below.

How Priority Works — Examples

Example 1: Database overrides env var

# Env var set at startup
OPENAI_API_KEY=sk-old-key

# Later, admin adds a credential via UI for provider.openai.api-key
# → Gateway immediately uses the database credential, not the env var

Example 2: Revoke falls back to env var

# Database credential for OpenAI: ACTIVE
# Env var: OPENAI_API_KEY=sk-fallback-key

# Admin revokes the database credential
# → Gateway falls back to sk-fallback-key from the env var

Example 3: Database + vault coexistence

# Vault has provider.openai.api-key = sk-from-vault
# Database has ACTIVE credential for provider.openai.api-key = sk-from-db

# → Gateway uses sk-from-db (database wins over vault)
# If database credential is revoked → sk-from-vault is used
# If vault entry is also removed → falls back to OPENAI_API_KEY env var

:::tip When to use which method

  • Environment variables — local development, CI/CD, single-operator setups
  • DVARA Flightdeck / API — team environments where multiple people manage credentials, or when you need rotation without restarts
  • Vault — production environments with strict secret management policies :::

Authentication Configuration

DVARA uses a two-domain authentication model: the data plane and the admin API are secured independently.

  • Data plane (/v1/chat/completions, /v1/embeddings, etc.) is always protected by API keys. Every request must include a valid Authorization: Bearer <api-key> header. This is active regardless of the dvara.flightdeck.security.enabled setting.

  • Admin API (/v1/admin/*) authentication is enabled by default (dvara.flightdeck.security.enabled=true). Three authentication modes are available:

    1. Built-in email/password (default) — activates when security.enabled=true and no OIDC issuer-uri or SAML metadata-url is set. On first visit, /setup creates the initial admin account. No external IdP required.
    2. OIDC/JWT — activates when dvara.flightdeck.security.oidc.issuer-uri is set. Requires an external IdP (Keycloak, Okta, Azure AD, Auth0).
    3. SAML 2.0 SSO — activates when dvara.flightdeck.security.saml.metadata-url is set (mutually exclusive with OIDC).
dvara:
flightdeck:
security:
enabled: true # Default: admin API requires authentication
# Built-in auth activates automatically when no OIDC/SAML is configured.
# To use OIDC instead, set the issuer-uri:
oidc:
issuer-uri: ${DVARA_FLIGHTDECK_OIDC_ISSUER_URI:}
audience: ${DVARA_FLIGHTDECK_OIDC_AUDIENCE:}
role-claim: ${DVARA_FLIGHTDECK_OIDC_ROLE_CLAIM:roles}
name-claim: ${DVARA_FLIGHTDECK_OIDC_NAME_CLAIM:name}
tenant-claim: ${DVARA_FLIGHTDECK_OIDC_TENANT_CLAIM:tenant_id}
rbac:
enabled: true # URL-pattern RBAC when security is enabled
session:
timeout-seconds: 3600
warning

Setting dvara.flightdeck.security.enabled=false disables all admin authentication. Anyone with network access to port 8090 can modify gateway configuration. Only use this for local development.

When dvara.flightdeck.security.enabled=true:

  • Without OIDC or SAML configured, built-in email/password authentication activates automatically. The first user is created via the /setup page. Additional users are invited by existing admins.
  • With issuer-uri configured, JWT tokens are validated against the configured issuer via OIDC discovery.
  • Roles are extracted from the JWT claim specified by role-claim and mapped to DVARA's six built-in roles: owner, policy-admin, billing-admin (platform), plus admin, developer, viewer (tenant).
  • When rbac.enabled=true (the default when security is on), URL-pattern RBAC rules enforce fine-grained access to each admin endpoint.
  • When rbac.enabled=false, any authenticated user can access all admin endpoints.

Tenant Configuration

Per-tenant configuration is not set via YAML files. Instead, tenant settings are managed through the Admin API (POST /PUT /v1/admin/tenants) as metadata key-value pairs on each tenant object.

This means tenant-level customization (PII policy, guardrail behavior, cost controls, IP access, approval gates, etc.) is dynamic and does not require a gateway restart.

# Per-tenant config is set via Tenant.metadata (not YAML)
# Managed through Admin API: POST/PUT /v1/admin/tenants
# Example metadata keys:
# priority-tier: premium|standard|bulk
# pii.enabled: true
# pii.action: BLOCK|REDACT|LOG
# pii.custom-patterns: {"label": "regex"}
# pii.scan-responses: true
# guardrail.enabled: true
# guardrail.action: BLOCK|FLAG|LOG
# guardrail.risk-score-threshold: 0.7
# cost.downgrade-threshold-pct: 80
# cost.downgrade-rules: "gpt-4o:gpt-4o-mini,claude-3-opus:claude-3-sonnet"
# cost.anomaly-threshold-pct: 200
# ip-access.allowlist: "10.0.0.0/8,172.16.0.0/12"
# ip-access.denylist: "192.168.1.100/32"
# approval.required-tools: "database_*,filesystem_*"
# approval.required-servers: "server-a,server-b"
# approval.timeout-seconds: 300
# audit.store-prompts: true
# agentic.loop-detection.enabled: true
# agentic.loop-detection.repetition-threshold: 5
# agentic.loop-detection.auto-kill: false

Example API call to set tenant metadata:

curl -X PUT http://localhost:8090/v1/admin/tenants/acme-corp \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Corp",
"metadata": {
"priority-tier": "premium",
"pii.enabled": "true",
"pii.action": "REDACT",
"guardrail.enabled": "true",
"guardrail.action": "BLOCK",
"cost.downgrade-rules": "gpt-4o:gpt-4o-mini",
"ip-access.allowlist": "10.0.0.0/8",
"audit.store-prompts": "true"
}
}'

Global defaults for PII, guardrails, budgets, and other enterprise features are configured in application.yml under their respective namespaces (e.g., dvara.llm-gateway.pii.*, dvara.llm-gateway.guardrail.*, dvara.llm-gateway.finops.*). Tenant metadata overrides these global defaults on a per-tenant basis.

Per-Tenant Metadata Key Reference

Every per-tenant override key the gateway recognises. Values are strings unless noted; booleans accept true/false/yes/no/on/off/1/0 (case-insensitive) per Spring's relaxed binding.

KeyTypeSubsystemBehaviour
priority-tierpremium / standard / bulkRoutingTenant's priority class for concurrency-based admission control. See Priority routing.
credentials.require-tenant-credentialbooleanBYOKNarrows or relaxes the global strict-BYOK policy (dvara.credentials.require-tenant-credential) for this tenant. Useful for tiered plans where free-tier tenants share the platform-default credential and paid tiers must BYOK.
pat.max-ttl-daysint (≤ 365)AuthNarrows the platform PAT TTL ceiling for this tenant. Hard cap of 365 always applies.
pii.enabledbooleanPIIOverride PII detection enable/disable for this tenant.
pii.actionBLOCK / REDACT / LOGPIIOverride default PII action.
pii.scan-responsesbooleanPIIOverride response scanning.
pii.scan-streaming-responsesbooleanPIIOverride streaming-response scanning.
pii.custom-patternsJSON mapPIICustom regex patterns: {"label": "regex", ...}
phileas.enabled-filtersCSV of FilterType namesPIIRestrict the embedded Phileas scanner to a subset of its 17 filter types for this tenant.
guardrail.enabledbooleanGuardrailsOverride guardrail detection.
guardrail.actionBLOCK / FLAG / LOGGuardrailsOverride default action.
guardrail.risk-score-thresholddouble (0.0–1.0)GuardrailsOverride risk-score threshold.
guardrail.scan-streaming-responsesbooleanGuardrailsOverride streaming-response scanning.
guardrail.max-input-tokensintGuardrailsOverride OWASP LLM10 input-token cap.
guardrail.max-messages-per-requestintGuardrailsOverride message count cap.
guardrail.max-message-lengthintGuardrailsOverride per-message char cap.
guardrail.default-max-response-tokensintGuardrailsOverride applied when client omits max_tokens.
guardrail.injection.custom-patternsJSON mapGuardrailsCustom injection patterns.
guardrail.content.profanity.actionBLOCK / FLAG / LOGGuardrailsPer-category action override.
guardrail.content.violence.actionBLOCK / FLAG / LOGGuardrailsPer-category action override.
guardrail.content.sexual.actionBLOCK / FLAG / LOGGuardrailsPer-category action override.
guardrail.content.competitor.keywordsCSVGuardrailsCompetitor brand keywords.
guardrail.content.topic-restrictionsCSVGuardrailsRestricted topic keywords.
guardrail.content.custom-denylistJSON mapGuardrailsCustom deny-list patterns.
guardrail.mcp-injection.enabledbooleanGuardrailsEnable MCP injection scanning.
guardrail.mcp-injection.actionBLOCK / FLAG / SANITIZEGuardrailsMCP injection action.
guardrail.context.warning-threshold-pctint (0–100)GuardrailsContext-window warning threshold (default 70).
guardrail.context.hard-threshold-pctint (0–100)GuardrailsContext-window hard threshold (default 90).
guardrail.context.pruning-strategyNONE / TRUNCATE_OLDEST / TRUNCATE_MIDDLEGuardrailsPruning strategy on context overflow.
guardrail.pluginsJSON mapGuardrailsPer-plugin config: {"pluginName": {"enabled": false, ...}}
grounding.enabledbooleanGroundingOverride embedding-based hallucination detection.
grounding.actionBLOCK / FLAG / LOGGroundingOverride action on ungrounded claims.
grounding.max-sourcesintGroundingOverride source-document cap.
grounding.max-source-lengthintGroundingOverride per-source char cap.
cost.downgrade-threshold-pctint (0–100)FinOpsBudget utilization % at which model downgrade triggers (default: 80).
cost.downgrade-rulesCSV from:to pairsFinOpsModel downgrade rules, e.g. gpt-4o:gpt-4o-mini,claude-3-opus:claude-3-sonnet.
cost.anomaly-threshold-pctintFinOpsPer-tenant override of dvara.llm-gateway.finops.anomaly-threshold-pct (default: 200 = 2× baseline).
ip-access.allowlistCSV CIDRsNetworkPer-tenant IP allowlist.
ip-access.denylistCSV CIDRsNetworkPer-tenant IP denylist.
approval.required-toolsCSV glob patternsAgenticTools that require human-in-the-loop approval (e.g. database_*,filesystem_*).
approval.required-serversCSV server IDsAgenticMCP servers whose every tool call requires approval.
approval.timeout-secondsintAgenticPer-tenant approval timeout override.
approval.default-actionapprove / denyAgenticAction on timeout.
agentic.loop-detection.enabledbooleanAgenticOverride loop detection.
agentic.loop-detection.repetition-thresholdintAgenticOverride consecutive same-tool threshold.
agentic.loop-detection.max-calls-per-minuteintAgenticOverride rate-limit threshold.
agentic.loop-detection.auto-killbooleanAgenticAuto-kill session on loop detection.
audit.store-promptsbooleanAuditOpt-in prompt storage for compliance.
audit.archive.retention-daysintAuditPer-tenant override for the archive job's PG retention window.

Use PUT /v1/admin/tenants/{id} with a metadata JSON object on the request body to set any of these keys; unsetting is null (the global default takes over).

Bootstrap File Seeding

Set DVARA_BOOTSTRAP_FILE to a YAML file path to seed tenants, API keys, and routes on first startup. This is designed for first-time tenant seeding before the Flightdeck UI is in use; entries are idempotently upserted on every boot, so re-running with the same file is safe.

docker run -d --name dvara-gateway \
-p 8080:8080 \
-v $(pwd)/bootstrap.yaml:/etc/dvara/bootstrap.yaml \
-e DVARA_BOOTSTRAP_FILE=/etc/dvara/bootstrap.yaml \
ghcr.io/dvarahq/dvara/dvara-llm-gateway:latest

The bootstrap loader is idempotent: it checks the config version and skips seeding if any configuration has already been applied (from a previous startup or from gateway.yaml).

tenants:
- id: acme-corp
name: Acme Corp
status: active

api_keys:
- tenant: acme-corp
name: production-key
key: ${ACME_API_KEY} # env var reference
- tenant: acme-corp
name: dev-key
generate: true # auto-generated, printed at startup

routes:
- id: gpt-route
model: "gpt*"
provider: openai

Notes on the bootstrap flow:

  • The file performs idempotent first-startup seeding of tenants, API keys, and routes. Re-running with the same file is safe — entries are upserted, never duplicated. BootstrapLoader runs after the gateway has booted with a valid license envelope (DVARA_LICENSE_KEY is always required at startup; there is no "unlicensed mode").
  • It supports ${ENV_VAR} and ${ENV_VAR:-default} substitution; resolution is performed by the gateway's YAML loader before parsing, so any Spring Environment source — env vars, JVM -D props, Kubernetes ConfigMaps — feeds back in.
  • The legacy GATEWAY_BOOTSTRAP_FILE env var is accepted for one release with a deprecation WARN (removed in 1.1.0-GA). Switch to DVARA_BOOTSTRAP_FILE for new deployments.
  • After first startup, ongoing config changes are made through the Flightdeck UI or /v1/admin/* REST API; subsequent boots skip rows whose id already exists in the database.

Provider Activation

A provider bean is only registered when its activation condition is met:

ProviderActivation Condition
OpenAIOPENAI_API_KEY is set and non-blank
AnthropicANTHROPIC_API_KEY is set and non-blank
GeminiGEMINI_API_KEY is set and non-blank
OllamaOLLAMA_ENABLED=true
BedrockBEDROCK_ENABLED=true
Azure OpenAIAZURE_OPENAI_API_KEY + AZURE_OPENAI_BASE_URL both set
MistralMISTRAL_API_KEY is set and non-blank
CohereCOHERE_API_KEY is set and non-blank
GroqGROQ_API_KEY is set and non-blank
QwenQWEN_API_KEY is set and non-blank
DeepSeekDEEPSEEK_API_KEY is set and non-blank
MoonshotMOONSHOT_API_KEY is set and non-blank
ChatGLMZHIPU_API_KEY is set and non-blank
GrokXAI_API_KEY is set and non-blank
MockMOCK_PROVIDER_ENABLED=true

If no provider is configured for a requested model, the gateway returns HTTP 400 with error code no_provider.

Property Reference

dvara.llm-gateway.providers.*

See Provider Setup for per-provider configuration details.

gateway.routes[]

PropertyTypeRequiredDefaultDescription
idstringyesUnique route identifier
model-patternstringyesGlob pattern to match model names
strategystringnomodel-prefixmodel-prefix, round-robin, weighted, latency-aware, cost-aware, canary, geo-aware, intelligent
cost-tolerance-pctintno0Cost tolerance band (0–100) for cost-aware routing — providers within this % above the cheapest may be preferred by the latency tiebreak. Not read by other strategies.
latency-sla-mslongno0Latency SLA in ms for cost-aware routing (0 = no SLA)
model-tiersmapnoComplexity→model mapping for intelligent routing (keys: SIMPLE, MODERATE, COMPLEX)
providers[].providerstringyesProvider name
providers[].weightintno1Weight for weighted strategy
providers[].regionstringnoRegion affinity for this provider entry
pinned-model-versionstringnoOverride model name sent to provider

dvara.llm-gateway.resilience.*

PropertyTypeDefaultDescription
resilience.retry.max-attemptsint3Max retry attempts on failure
resilience.retry.wait-duration-msint500Wait between retries (ms)
resilience.circuit-breaker.failure-rate-thresholdint50Failure % to open circuit
resilience.circuit-breaker.sliding-window-sizeint20Calls in sliding window
resilience.circuit-breaker.wait-duration-in-open-state-msint30000Time before half-open (ms)
resilience.timeout.chat-timeout-msint30000Non-streaming request timeout
resilience.timeout.streaming-timeout-msint120000Streaming request timeout

dvara.llm-gateway.rate-limit.*

PropertyTypeDefaultDescription
rate-limit.enabledbooleanfalseEnable rate limiting
rate-limit.per-key.requests-per-minuteint100Max requests per API key per 60-second window
rate-limit.per-key.tokens-per-minuteint100000Max tokens per API key per 60-second window

dvara.llm-gateway.cache.*

PropertyTypeDefaultDescription
cache.enabledbooleanfalseEnable response caching
cache.ttl-secondsint3600Cache entry time-to-live
cache.max-sizeint10000Max entries (Caffeine only)

dvara.llm-gateway.pii.* (Enterprise — PII Detection)

PropertyTypeDefaultDescription
pii.enabledbooleantrueEnable PII detection and enforcement
pii.providerstringregexDetection provider: regex or presidio
pii.default-actionstringLOGDefault action: LOG, BLOCK, REDACT
pii.scan-responsesbooleantrueScan LLM responses for PII output leaks
pii.strip-before-cachebooleantrueAlways redact PII before writing to cache
pii.token-encryption-passwordstringAES-256-GCM password for PII token encryption
pii.max-tokens-per-tenantint50000Maximum PII tokens stored per tenant
pii.token-retention-daysint30Days to retain PII tokens before expiry
pii.presidio.endpointstringPresidio analyzer endpoint URL
pii.presidio.languagestringenPresidio analysis language
pii.presidio.score-thresholddouble0.5Minimum Presidio confidence score
pii.presidio.timeout-secondsint5Presidio HTTP timeout
pii.presidio.cache-max-sizeint1000LRU cache max entries (0 = disabled)
pii.presidio.cache-ttl-secondsint300Cache entry TTL
pii.scan-streaming-responsesbooleantrueScan SSE streaming responses for PII. Buffers a rolling window across chunk boundaries so spans split across two SSE events are still caught.
pii.streaming-scan-window-sizeint256Characters buffered before a PII scan triggers during streaming.
pii.streaming-overlap-marginint64Characters retained between scan windows so PII spanning chunk boundaries is not missed.

Per-tenant PII configuration is set via tenant metadata keys:

Metadata KeyValuesDescription
pii.enabledtrue / falseOverride PII detection for this tenant
pii.actionBLOCK / REDACT / LOGOverride default PII action for this tenant
pii.scan-responsestrue / falseOverride response scanning for this tenant
pii.scan-streaming-responsestrue / falseOverride streaming-response scanning for this tenant
pii.custom-patternsJSON stringCustom regex patterns ({"label": "regex", ...})
cost.downgrade-threshold-pctint (0–100)Budget utilization % at which model downgrade triggers (default: 80)
cost.downgrade-rulesstringComma-separated model downgrade rules (format: "from:to,from:to", e.g. "gpt-4o:gpt-4o-mini,claude-3-opus:claude-3-sonnet")
cost.anomaly-threshold-pctintPer-tenant anomaly detection threshold (default: 200 = 2x baseline)

See PII Detection for full configuration details.

dvara.llm-gateway.guardrail.* (Enterprise — Guardrails & Safety)

PropertyTypeDefaultDescription
guardrail.enabledbooleantrueEnable guardrail detection and enforcement
guardrail.default-actionstringLOGDefault action: LOG, BLOCK, FLAG
guardrail.scan-responsesbooleantrueScan LLM responses for violations
guardrail.risk-score-thresholddouble0.7Detections below this score are ignored
guardrail.max-input-tokensint32000Max estimated input tokens (OWASP LLM10)
guardrail.max-messages-per-requestint100Max messages per request (OWASP LLM10)
guardrail.max-message-lengthint50000Max character length per message (OWASP LLM10)
guardrail.default-max-response-tokensint4096Applied when client doesn't specify max_tokens
guardrail.scan-streaming-responsesbooleantrueEnable guardrail scanning on streaming responses
guardrail.streaming-scan-window-sizeint256Chars buffered before scan trigger during streaming
guardrail.streaming-overlap-marginint64Chars retained between windows for boundary detection
guardrail.ml-classifier.enabledbooleanfalseEnable ML classifier for injection detection
guardrail.ml-classifier.providerstringgenericProvider: generic, lakera, shield-gemini
guardrail.ml-classifier.endpointstringURL (auto-defaulted per provider if blank)
guardrail.ml-classifier.api-keystringAPI key for the ML provider
guardrail.ml-classifier.project-idstringGoogle Cloud project ID (shield-gemini only)
guardrail.ml-classifier.locationstringus-central1Google Cloud region (shield-gemini only)
guardrail.ml-classifier.confidence-thresholddouble0.8Detections below this are ignored
guardrail.ml-classifier.timeout-secondsint5HTTP call timeout
guardrail.ml-classifier.cache-max-sizeint1000LRU cache max entries. 0 = disabled
guardrail.ml-classifier.cache-ttl-secondsint300Cache entry TTL
guardrail.plugins.enabledbooleanfalseEnable external guardrail plugin system
guardrail.plugins.definitions[].namestringUnique plugin identifier
guardrail.plugins.definitions[].urlstringHTTP endpoint URL
guardrail.plugins.definitions[].secretstringHMAC-SHA256 signing secret
guardrail.plugins.definitions[].timeout-msint5000HTTP call timeout
guardrail.plugins.definitions[].fail-modestringOPENOPEN or CLOSED
guardrail.grounding.enabledbooleanfalseEnable hallucination/grounding detection
guardrail.grounding.similarity-thresholddouble0.7Cosine similarity threshold for claims
guardrail.grounding.actionstringLOGAction: LOG, FLAG, BLOCK

Per-tenant guardrail configuration is set via tenant metadata keys:

Metadata KeyValuesDescription
guardrail.enabledtrue / falseOverride guardrail detection for this tenant
guardrail.actionBLOCK / FLAG / LOGOverride default action for this tenant
guardrail.risk-score-thresholddouble (0.0–1.0)Override risk score threshold
guardrail.max-input-tokensintOverride max estimated input tokens
guardrail.max-messages-per-requestintOverride max messages per request
guardrail.max-message-lengthintOverride max message character length
guardrail.default-max-response-tokensintOverride default response token cap
guardrail.content.profanity.actionBLOCK / FLAG / LOGPer-category action override
guardrail.content.violence.actionBLOCK / FLAG / LOGPer-category action override
guardrail.content.sexual.actionBLOCK / FLAG / LOGPer-category action override
guardrail.content.competitor.keywordscomma-separatedCompetitor brand keywords
guardrail.content.topic-restrictionscomma-separatedRestricted topic keywords
guardrail.content.custom-denylistJSON stringCustom deny-list patterns
guardrail.injection.custom-patternsJSON stringCustom injection patterns
guardrail.mcp-injection.enabledtrue / falseEnable MCP injection scanning
guardrail.mcp-injection.actionBLOCK / FLAG / SANITIZEMCP injection action
guardrail.context.warning-threshold-pctint (0–100)Context window warning threshold (default: 70)
guardrail.context.hard-threshold-pctint (0–100)Context window hard threshold (default: 90)
guardrail.context.pruning-strategyNONE / TRUNCATE_OLDEST / TRUNCATE_MIDDLEContext pruning strategy
guardrail.scan-streaming-responsestrue / falseOverride streaming-response scanning for this tenant
guardrail.max-input-tokensintPer-tenant override (OWASP LLM10)
guardrail.max-messages-per-requestintPer-tenant override (OWASP LLM10)
guardrail.max-message-lengthintPer-tenant override (OWASP LLM10)
guardrail.default-max-response-tokensintPer-tenant override applied when client omits max_tokens
guardrail.pluginsJSON mapPer-plugin config: {"pluginName": {"enabled": false}}

See Guardrails & Safety for full configuration details.

dvara.llm-gateway.guardrail.phileas.* (Enterprise — Embedded PII Scanner)

In-process PII detection via the embedded Phileas library — runs entirely in-process, no external service required, no network calls, no vendor API keys, sub-millisecond per-call latency. Pairs with the always-on RegexPiiDetector; for production credit-card detection, rely on the regex path's Luhn validation since Phileas matching is best-effort.

PropertyTypeDefaultDescription
guardrail.phileas.enabledbooleanfalseEnable the Phileas PII scanner. The default policy enables 17 filter types: SSN, credit card, phone, email, IP, passport, drivers license, IBAN, MAC, URL, ZIP, bank routing number, VIN, bitcoin address, tracking number, currency, age.

Per-tenant restriction via Tenant.metadata["phileas.enabled-filters"] (comma-separated FilterType names) — editable from the DVARA Console tenant form (Phileas Filters tab) or via the Automation API (PUT /v1/admin/tenants/{id}).

dvara.llm-gateway.guardrail.grounding.* (Enterprise — Hallucination / Grounding Detection)

Embedding-based grounding detection. When source documents are provided on the request via request.metadata["grounding.sources"] (List<String>), the detector splits the response into sentence claims, embeds each claim and source via EmbeddingService, and flags claims with max cosine similarity below the threshold.

PropertyTypeDefaultDescription
guardrail.grounding.enabledbooleanfalseEnable embedding-based grounding detection
guardrail.grounding.similarity-thresholddouble0.7Cosine similarity threshold — claims below this are flagged ungrounded
guardrail.grounding.actionstringLOGLOG, FLAG, or BLOCK when a hallucination is detected
guardrail.grounding.max-sourcesint50Maximum source documents per request; excess silently dropped
guardrail.grounding.max-source-lengthint10000Maximum chars per source document; oversized sources silently dropped

Per-tenant overrides via Tenant.metadata: grounding.enabled, grounding.action, grounding.max-sources, grounding.max-source-length. Streaming requests run the same detector at stream-end against the accumulated response text.

dvara.llm-gateway.finops.* (Enterprise — Cost Calculation)

PropertyTypeDefaultDescription
finops.enabledbooleantrueEnable enterprise cost calculation
finops.pricing-cache-ttl-secondsint60TTL for pricing lookup cache (0 = disabled)
finops.spend-cache-ttl-secondsint30TTL for budget spend cache (avoids per-request DB queries)
finops.soft-alert-cooldown-minutesint60Per-budget-cap dedup window for soft-limit alerts. The first soft breach on a cap writes BUDGET_CAP_SOFT (which fans out to webhook subscribers and the audit log); subsequent soft breaches on the same cap within this window are skipped — no audit event, no webhook delivery. The Prometheus counter gateway_budget_soft_alert_total is incremented on every breach regardless.

Operational caveat: a tenant whose spend straddles the soft threshold over many requests will not generate a per-call alert — operators wiring on-call paging that expects per-call notifications should lower this to seconds (e.g. 1) or zero. The cooldown is per budget id, not per tenant, so a tenant with three caps (global / tenant / API-key) can still see up to three soft alerts within the window. Model downgrade (ModelDowngradeFilter) is not subject to the cooldown — it runs on every request whose BudgetCheckResult.softLimitBreached() is true, so downgrade continues to apply silently between alert fires.
finops.downgrade-cache-ttl-secondsint5TTL for per-tenant downgrade policy cache (0 = disabled)
finops.chargeback-schedulestring""Cron expression for monthly chargeback report auto-generation (empty = disabled)
finops.anomaly-threshold-pctint200Default anomaly threshold: current daily rate vs 30d baseline (200 = 2x)
finops.budget-warning-threshold-pctint75Default utilization % threshold at which WARN_AGENT policy rules fire. When a tenant's spend on a budget cap crosses this fraction of the cap's limit, any policy with a WARN_AGENT action sees the warning state and can inject a soft-cap notice into the response without blocking the call. Per-budget override via the budget cap's softLimitPct field; per-tenant override via the policy YAML's threshold expression.

Cost calculation uses ModelPricing entries managed via the /v1/admin/pricing API. Pricing supports glob patterns (e.g. gpt-4o* matches gpt-4o, gpt-4o-mini). Costs are calculated per-request using BigDecimal precision and persisted as CostRecord entries, queryable via /v1/admin/costs.

Budget caps enforce soft and hard spending limits at three scopes — global, tenant, and API-key. The data plane evaluates all applicable caps for each request in most-specific-first order (API-key → tenant → global) and short-circuits on the first hard or soft breach; for non-breach cases the tightest-remaining-percent cap is surfaced via BudgetCheckResult.allowedWithBudget and rendered into response headers. Configure budgets via /v1/admin/budgets. Budget periods (DAILY, WEEKLY, MONTHLY) reset automatically at UTC boundaries.

Hard breachBudgetEnforcementFilter rejects the request with HTTP 402 Payment Required and writes a BUDGET_CAP_HARD audit event. No retries, no downgrade — the request never reaches the provider.

Soft breach → the request is allowed through with the breach state stamped onto the FilterContext. Two side-effects fire from the soft state:

  1. A BUDGET_CAP_SOFT audit event is written (subject to the soft-alert-cooldown-minutes dedup window above). Webhook subscribers with the BUDGET_CAP_SOFT event type get the payload via the audit→webhook bridge.
  2. ModelDowngradeFilter reads the soft-breach signal and, if Tenant.metadata["cost.downgrade-rules"] defines a rule for the requested model, swaps the model in-flight (e.g. gpt-4ogpt-4o-mini) before dispatch. Downgrade fires on every soft-breach request — it is not subject to the soft-alert cooldown, so spend continues to bend toward the cheaper variant even when alerts are paused.

The downgrade threshold (default 80% of the cap) and downgrade rules are per-tenant via cost.downgrade-threshold-pct and cost.downgrade-rules metadata keys.

Chargeback reports aggregate costs by tenant, API key, model, provider, and time period. Reports are exportable as CSV and PDF. Monthly auto-generation is available via chargeback-schedule cron. Cost forecasting uses trailing 7-day and 30-day spend trends with linear projection. Cost anomaly detection compares current daily spend rate against the 30-day baseline; alerts fire when the deviation exceeds the configured threshold (per-tenant override via cost.anomaly-threshold-pct metadata key).

Enterprise License

A valid DVARA license key is required for all apps to start. Set DVARA_LICENSE_KEY as an environment variable.

PropertyEnvironment VariableDefaultDescription
dvara.license.keyDVARA_LICENSE_KEYSigned DVARA license key (trial or production)
dvara.license-monitor.interval-msDVARA_LICENSE_MONITOR_INTERVAL_MS3600000 (1 hour)Interval for runtime license re-validation. Each sweep re-checks the envelope's signature and expiry, updates LicenseStatusHolder, and writes a LICENSE_* audit event on status transitions.

Runtime license lifecycle:

  • Within 30 days of expiryEXPIRING_SOON: X-License-Warning response header added, LICENSE_EXPIRY_WARNING audit event
  • Expired (within 14-day grace)GRACE_PERIOD: X-License-Warning header, LICENSE_EXPIRED audit event, service fully operational
  • Expired (beyond the 14-day grace)DEGRADED: data-plane /v1/* returns 402 Payment Required, admin/internal endpoints remain accessible, LICENSE_DEGRADED audit event

dvara.flightdeck.license-alert.* (License-Expiry Email Alerts)

Operator-friendly email notifications on license status transitions. The alerting itself is driven by Spring events published by LicenseExpiryMonitor in enterprise-core — no schedule config needed. Off by default so existing deploys don't start sending alerts on a license-key rotation just because the rc23+ images landed.

PropertyDefaultDescription
dvara.flightdeck.license-alert.enabledfalseMaster switch. Opt-in.
dvara.flightdeck.license-alert.recipients[]Email addresses to notify on LICENSE_EXPIRY_WARNING / LICENSE_EXPIRED / LICENSE_DEGRADED transitions. Comma-separated in env vars, list in YAML. At least one address is required when enabled=true — misconfigured state logs a WARN at boot but doesn't refuse to start (alerting is non-critical to data-plane uptime).
dvara.flightdeck.license-alert.subject-prefix[DVARA license alert]Override for the email subject line prefix. Useful when a single ops mailbox receives alerts from multiple DVARA installs (e.g. [DVARA license alert — prod], [DVARA license alert — staging]).

Enterprise Latency-Aware Routing Configuration

Tunes the latency-aware routing strategy (see Routing → Latency-aware) — EWMA per-(provider, model) latency tracking with a configurable freshness window and decay penalty for stale samples. Requires a valid DVARA license key.

PropertyEnvironment VariableDefaultDescription
dvara.llm-gateway.routing.latency.alpha0.2EWMA smoothing factor (0.0–1.0). Higher values give more weight to recent samples
dvara.llm-gateway.routing.latency.decay-threshold-ms60000Staleness threshold in milliseconds. Entries older than this receive a decay penalty
dvara.llm-gateway.routing.latency.decay-multiplier0.5Stale EWMA is divided by this value (lower = harsher penalty)
dvara.llm-gateway.routing.latency.min-samples5Minimum latency samples before EWMA is used for routing decisions
dvara.llm-gateway.routing.latency.snapshot-interval100Persist latency snapshot to repository every N samples

Enterprise Priority Routing Configuration

Requires a valid DVARA license key.

PropertyEnvironment VariableDefaultDescription
dvara.llm-gateway.routing.priority.enabledfalseEnable concurrency-based priority admission control
dvara.llm-gateway.routing.priority.max-concurrent-requests1000Maximum concurrent requests across all tiers
dvara.llm-gateway.routing.priority.tiers.premium.throttle-threshold-pct100Load % at which premium requests are throttled
dvara.llm-gateway.routing.priority.tiers.standard.throttle-threshold-pct80Load % at which standard requests are throttled
dvara.llm-gateway.routing.priority.tiers.bulk.throttle-threshold-pct50Load % at which bulk requests are throttled
dvara.llm-gateway.routing.priority.resolver-cache-ttl-seconds5TTL for tenant → priority tier cache

Enterprise Webhook Configuration

Requires a valid DVARA license key.

PropertyEnvironment VariableDefaultDescription
dvara.llm-gateway.webhooks.enabledDVARA_LLM_GATEWAY_WEBHOOKS_ENABLEDtrueEnable webhook delivery of governance events
dvara.llm-gateway.webhooks.max-retriesDVARA_LLM_GATEWAY_WEBHOOKS_MAX_RETRIES3Maximum retry attempts for failed deliveries
dvara.llm-gateway.webhooks.base-retry-delay-msDVARA_LLM_GATEWAY_WEBHOOKS_BASE_RETRY_DELAY_MS1000Base delay in milliseconds for exponential backoff
dvara.llm-gateway.webhooks.retry-multiplierDVARA_LLM_GATEWAY_WEBHOOKS_RETRY_MULTIPLIER4Multiplier for exponential backoff (delay = base x multiplier^attempt)
dvara.llm-gateway.webhooks.delivery-timeout-msDVARA_LLM_GATEWAY_WEBHOOKS_DELIVERY_TIMEOUT_MS5000HTTP connect+read timeout for webhook delivery
dvara.llm-gateway.webhooks.approval-base-urlDVARA_LLM_GATEWAY_WEBHOOKS_APPROVAL_BASE_URL"" (empty)Base URL for approve/deny links in MCP approval webhooks
dvara.llm-gateway.webhooks.approval-ttl-minutesDVARA_LLM_GATEWAY_WEBHOOKS_APPROVAL_TTL15TTL in minutes for approval token validity
dvara.llm-gateway.webhooks.max-delivery-log-entriesDVARA_LLM_GATEWAY_WEBHOOKS_MAX_DELIVERY_LOG_ENTRIES50000Capacity of the delivery log (rolling). Older entries are dropped when capacity is reached.

dvara.persistence.* (Enterprise — Database Persistence)

Requires a valid DVARA license key.

PropertyEnvironment VariableDefaultDescription
spring.datasource.urlSPRING_DATASOURCE_URLJDBC connection URL (e.g. jdbc:postgresql://localhost:5432/dvara). When set with a valid license, PostgreSQL persistence activates automatically.
dvara.persistence.batch-sizeDVARA_PERSISTENCE_BATCH_SIZE100Batch size for bulk write operations
spring.datasource.usernameSPRING_DATASOURCE_USERNAMEDatabase username
spring.datasource.passwordSPRING_DATASOURCE_PASSWORDDatabase password
spring.flyway.enabledSPRING_FLYWAY_ENABLEDtrueAuto-run database migrations on startup
spring.datasource.hikari.maximum-pool-sizeDVARA_DB_POOL_SIZE2JDBC connection pool size. Data plane (gateway-server, mcp-proxy-server) defaults to 2 (one connection reserved for config reads via the PG NOTIFY listener, one for audit writes) — the data plane is read-mostly and persists asynchronously, so a small pool is correct. Flightdeck (admin server, flightdeck) should be sized to its real concurrency — set DVARA_DB_POOL_SIZE=10 or higher in production for the UI's read-heavy dashboard endpoints + the Admin API. Do not raise the data-plane pool unless you have evidence of contention; raising it just to "be safe" wastes connections that are scarce behind PgBouncer / DigitalOcean Managed Connection Pool.
# Enterprise persistence (PostgreSQL-backed state)
dvara:
persistence:
batch-size: 100 # default: 100

spring:
datasource:
url: jdbc:postgresql://localhost:5432/dvara
username: dvara
password: ${DB_PASSWORD}
flyway:
enabled: true # auto-runs migrations on startup

Distributed Caching and Rate Limiting

DVARA ships with an embedded distributed cache for API key lookups and rate-limit counters. No external cache infrastructure is required — the cache runs in-process and auto-clusters across pods.

  • Local / Docker Compose: pods discover each other via multicast (works out of the box).
  • Kubernetes: pods discover each other via DNS lookup against a headless Service (not a regular ClusterIP Service — the Hazelcast Kubernetes discovery SPI needs EndpointSlice records returned by the Service). Create the headless Service with clusterIP: None and a label selector matching your data-plane pods, then set the CACHE_SERVICE_NAME env var on every pod to the Service name. The Service must live in the same namespace as the pods; cross-namespace discovery requires CACHE_SERVICE_NAMESPACE as well. Without CACHE_SERVICE_NAME, pods boot in single-node mode and rate-limit / cache state is per-pod, not fleet-wide — silently breaking horizontal correctness. The Hazelcast autoconfig logs a clear WARN at startup when this happens.

The distributed cache currently wraps the API key repository with a 30-second TTL for sub-millisecond auth lookups across the fleet. Write-through eviction ensures revoked keys are never served from cache.

Rate limiting uses the same in-process distributed maps for per-key request and token counts shared across all pods. See Rate Limiting for configuration.

MCP Proxy Configuration

Configuration for the standalone DVARA MCP Proxy (port 8070). Requires enterprise license.

PropertyEnvironment VariableDefaultDescription
dvara.mcp-gateway.timeout-default30Default timeout in seconds for upstream MCP server requests
dvara.mcp-gateway.timeout-max120Maximum allowed timeout in seconds (caps any per-server override)
dvara.mcp-gateway.registry-cache-ttl-seconds30TTL for the MCP server registry cache

dvara.mcp-gateway.pii.* (MCP Proxy PII Detection)

The MCP Proxy runs its own PII scanner independent of the LLM gateway's dvara.llm-gateway.pii.* settings — MCP tool inputs and outputs are not LLM completions and need their own enable/action knobs.

PropertyDefaultDescription
dvara.mcp-gateway.pii.enabledtrueEnable PII scanning on MCP tool arguments and responses.
dvara.mcp-gateway.pii.default-actionLOGDefault PiiAction on detection: LOG, BLOCK, or REDACT.
dvara.mcp-gateway.pii.scan-responsestrueScan MCP tool responses (in addition to request arguments) for PII output leaks.

Per-tenant overrides are managed identically to the LLM-gateway side via tenant metadata.

management.* (Observability)

PropertyTypeDefaultDescription
management.endpoints.web.exposure.includestringhealth,prometheus,gateway-status,infoActuator endpoints to expose. The probe paths (/actuator/health, /actuator/health/liveness, /actuator/health/readiness, /actuator/info) stay anonymous. /actuator/gateway-status requires DVARA_ACTUATOR_API_KEY; /actuator/prometheus requires DVARA_ACTUATOR_METRICS_API_KEY.
management.endpoints.web.exposure.excludestringenv,heapdump,threaddump,beans,mappings,configprops,loggers,scheduledtasks,caches,sessions,quartzDangerous endpoints — return 404 regardless of authentication. Do not remove from this list without a security review.
management.endpoint.health.show-detailsstringwhen-authorizedHealth detail visibility. Setting this to always is rejected at boot — the readiness probe stays DOWN and a rolling deploy halts on the first replica. Use when-authorized (default) or never.
management.prometheus.metrics.export.enabledbooleantrueEnable Prometheus scrape endpoint

Logging

ConfigurationValueDescription
Default formatStructured JSONEvery log line is valid JSON
Plain-text modespring.profiles.active=log-plainHuman-readable output for local dev
Log config filelogback-spring.xmlLogging configuration, supports Spring profile overrides

dvara.flightdeck.security.* (Enterprise — OIDC/JWT Authentication)

Requires a valid DVARA license key.

PropertyDefaultDescription
dvara.flightdeck.security.enabledtrueEnable authentication for admin endpoints. When true with no OIDC issuer-uri or SAML metadata-url, built-in email/password auth activates. Set to false for local development only.
dvara.flightdeck.security.oidc.issuer-uriOIDC issuer URL for JWT validation (e.g. Keycloak, Auth0)
dvara.flightdeck.security.oidc.audience""Expected JWT audience claim (blank = skip audience validation)
dvara.flightdeck.security.oidc.role-claimrolesJWT claim containing roles (supports dot-notation, e.g. realm_access.roles)
dvara.flightdeck.security.oidc.name-claimnameJWT claim for user display name
dvara.flightdeck.security.oidc.tenant-claimtenant_idJWT claim for tenant association
dvara.flightdeck.security.rbac.enabledtrueEnable URL-pattern RBAC enforcement (false = authenticated() only)
dvara.flightdeck.security.session.timeout-seconds3600Session timeout in seconds

dvara.vault.* (Enterprise — Secrets Management)

Requires a valid DVARA license key.

PropertyDefaultDescription
dvara.vault.backend"" (disabled)hashicorp, aws-secrets-manager, or azure-key-vault
dvara.vault.cache-ttl-seconds300Secret cache TTL
dvara.vault.hashicorp.addressHashiCorp Vault address
dvara.vault.hashicorp.tokenStatic Vault token
dvara.vault.hashicorp.auth-methodtokentoken or approle
dvara.vault.hashicorp.secret-pathsecret/data/meridianKV v2 secret path
dvara.vault.aws.regionus-east-1AWS region
dvara.vault.aws.secret-namemeridian/provider-credentialsAWS Secrets Manager secret name
dvara.vault.azure.vault-urlAzure Key Vault URL

dvara.llm-gateway.tls.* (Enterprise — mTLS Per Provider)

Requires a valid DVARA license key.

PropertyDefaultDescription
dvara.llm-gateway.tls.enforce-tls13trueEnforce TLS 1.3 on all outbound provider connections
dvara.llm-gateway.tls.providers.<name>.mtls-enabledfalseEnable mTLS client cert for this provider
dvara.llm-gateway.tls.providers.<name>.client-cert-pathPath to client certificate (PEM or PKCS12)
dvara.llm-gateway.tls.providers.<name>.client-key-pathPath to client private key (PEM)
dvara.llm-gateway.tls.providers.<name>.trust-store-pathPath to trust store

dvara.llm-gateway.ip-access.* (Enterprise — IP Access Control)

Requires a valid DVARA license key.

PropertyDefaultDescription
dvara.llm-gateway.ip-access.enabledfalseEnable IP allowlist/denylist
dvara.llm-gateway.ip-access.scopeallall or data-plane (only /v1/*)
dvara.llm-gateway.ip-access.global-allowlist[]CIDR ranges to allow (e.g. 10.0.0.0/8)
dvara.llm-gateway.ip-access.global-denylist[]CIDR ranges to deny

Per-tenant: ip-access.allowlist and ip-access.denylist in tenant metadata (comma-separated CIDRs).

dvara.audit.* (Enterprise — Audit Trail)

Requires a valid DVARA license key.

PropertyDefaultDescription
dvara.audit.hmac-secretdefault-dev-secret-change-in-productionHMAC-SHA256 key for signing audit events
dvara.audit.max-events100000Capacity of append-only audit store
dvara.audit.store-prompts-by-defaultfalseStore prompt/response text in audit events
dvara.audit.prompt-retention-days90Retention period for stored prompts

dvara.flightdeck.audit-archive.* (Audit Archive Job)

Off-by-default scheduled job that archives older audit events out of PostgreSQL into object storage. Per-tenant overrides live in Tenant.metadata.

PropertyDefaultDescription
dvara.flightdeck.audit-archive.enabledfalseMaster switch. When false, the scheduled job is registered but no-ops.
dvara.flightdeck.audit-archive.schedule0 0 2 * * ?Spring cron — daily 02:00 UTC by default.
dvara.flightdeck.audit-archive.retention-days180Events older than this in PostgreSQL are eligible for archive. Per-tenant override via Tenant.metadata["audit.archive.retention-days"].
dvara.flightdeck.audit-archive.grace-period-days7Extra days after a partition is VERIFIED in object storage before the corresponding PG rows are deleted. Safety window for restoring from PG if an object-storage issue surfaces post-upload.
dvara.flightdeck.audit-archive.bucket""Object-storage bucket name. Read from SPACES_BUCKET env var by the install scripts.
dvara.flightdeck.audit-archive.endpoint""S3-compatible endpoint (DigitalOcean Spaces, MinIO, AWS S3). Env: SPACES_ENDPOINT.
dvara.flightdeck.audit-archive.region""Object-storage region. Env: SPACES_REGION.
dvara.flightdeck.audit-archive.access-key-id""Object-storage access key. Env: SPACES_ACCESS_KEY_ID.
dvara.flightdeck.audit-archive.secret-access-key""Object-storage secret. Env: SPACES_SECRET_ACCESS_KEY.
dvara.flightdeck.audit-archive.max-rows-per-archive1000000Safety cap on rows per single (tenant, date) partition. If a partition exceeds this, the job logs a warning and skips it — operator must split it manually before the next run. Raise if a tenant generates more than 1M audit events/day.

dvara.llm-gateway.siem.* (Enterprise — SIEM Export)

PropertyDefaultDescription
dvara.llm-gateway.siem.splunk.enabledfalseEnable Splunk HEC SIEM export
dvara.llm-gateway.siem.splunk.hec-urlSplunk HEC endpoint URL
dvara.llm-gateway.siem.splunk.tokenHEC authentication token
dvara.llm-gateway.siem.splunk.index""Splunk index (blank = default)
dvara.llm-gateway.siem.splunk.sourcedvara-gatewaySplunk event source
dvara.llm-gateway.siem.splunk.source-type_jsonSplunk source type
dvara.llm-gateway.siem.splunk.timeout-seconds10HTTP timeout for the HEC POST. Failed posts are retried via the Kafka DLQ if Kafka is also configured; otherwise the audit event still lands in PostgreSQL (HEC export is best-effort).
dvara.llm-gateway.siem.cloudwatch.enabledfalseEnable CloudWatch Logs SIEM export
dvara.llm-gateway.siem.cloudwatch.log-groupCloudWatch log group name
dvara.llm-gateway.siem.cloudwatch.log-streamdvara-auditCloudWatch log stream name
dvara.llm-gateway.siem.cloudwatch.regionus-east-1AWS region
dvara.llm-gateway.siem.cloudwatch.endpointCustom endpoint (blank = regional default https://logs.{region}.amazonaws.com)
dvara.llm-gateway.siem.cloudwatch.batch-size25Flush events to CloudWatch in batches of this size — bounded by the CloudWatch PutLogEvents API limit of 10,000 events per call.
dvara.llm-gateway.siem.cloudwatch.timeout-seconds10HTTP timeout for PutLogEvents calls.
dvara.llm-gateway.siem.kafka.enabledfalseEnable Kafka SIEM export
dvara.llm-gateway.siem.kafka.bootstrap-serversKafka broker addresses (e.g. localhost:9092)
dvara.llm-gateway.siem.kafka.topicdvara-auditKafka topic for audit events
dvara.llm-gateway.siem.kafka.dead-letter-topic""Dead-letter topic for failed publishes (blank = disabled)
dvara.llm-gateway.siem.kafka.acksallProducer acknowledgment (all = survives broker failures)
dvara.llm-gateway.siem.kafka.security-protocolSecurity protocol (e.g. SASL_SSL)
dvara.llm-gateway.siem.kafka.sasl-mechanismSASL mechanism (e.g. PLAIN, SCRAM-SHA-256)
dvara.llm-gateway.siem.kafka.sasl-jaas-configJAAS config string for SASL auth

dvara.mcp-gateway.agentic.* (Enterprise — Agentic Governance)

Requires a valid DVARA license key.

PropertyDefaultDescription
dvara.mcp-gateway.agentic.enabledtrueEnable agentic governance features
dvara.mcp-gateway.agentic.session-ttl-minutes60Active session TTL
dvara.mcp-gateway.agentic.session-max-capacity10000Max tracked sessions
dvara.mcp-gateway.agentic.loop-detection.enabledtrueEnable loop detection
dvara.mcp-gateway.agentic.loop-detection.repetition-threshold5Consecutive same-tool calls to trigger
dvara.mcp-gateway.agentic.loop-detection.max-calls-per-minute60Rate limit threshold
dvara.mcp-gateway.agentic.loop-detection.auto-killfalseAuto-kill session on loop detection
dvara.mcp-gateway.agentic.approval.enabledtrueEnable human-in-the-loop approval gates
dvara.mcp-gateway.agentic.approval.timeout-seconds300Approval wait timeout
dvara.mcp-gateway.agentic.approval.default-actiondenyAction on approval timeout: deny or approve
dvara.mcp-gateway.agentic.approval.max-pending-approvals1000Max concurrent pending approvals
dvara.mcp-gateway.agentic.loop-detection.cycle-max-length4Max cycle pattern length
dvara.mcp-gateway.agentic.loop-detection.cycle-repetitions3Required cycle repetitions to trigger
dvara.mcp-gateway.agentic.loop-detection.history-size100Per-session tool-call history buffer size

dvara.flightdeck.security.builtin.* (Built-in Email/Password Auth)

Active when dvara.flightdeck.security.enabled=true and no OIDC issuer-uri or SAML metadata-url is set. Provides form login, invite-only user creation, password reset, and personal access tokens.

PropertyDefaultDescription
dvara.flightdeck.security.builtin.session-timeout-minutes60Form-login session timeout
dvara.flightdeck.security.builtin.max-failed-attempts5Consecutive failed logins before lockout
dvara.flightdeck.security.builtin.lockout-duration-minutes15Lockout duration after max failed attempts
dvara.flightdeck.security.builtin.base-urlhttp://localhost:8090Base URL for invitation and password-reset email links
dvara.flightdeck.security.builtin.pat.default-max-ttl-days365Platform-wide ceiling on PAT (personal access token) TTL. A per-tenant override lives in Tenant.metadata["pat.max-ttl-days"] and narrows below this ceiling. The absolute hard cap is 365 regardless of configuration — higher values are clamped at PAT creation time. PAT expiry is required (non-expiring PATs are not allowed).

Email delivery configuration has been consolidated under the new dvara.flightdeck.email.* namespace — see Email Configuration below.

dvara.flightdeck.email.* (Consolidated Email Configuration)

The Flightdeck pod is the only one that ships actual sends. Producers in any module publish an EmailRequestedEvent; the EmailDeliveryListener in Flightdeck renders the template and dispatches via the configured transport. URL fields live in the cross-cutting EmailProperties; transport + durability fields live in FlightdeckEmailProperties — both bind to the same dvara.flightdeck.email.* prefix.

URL + transport fields (consumed by producers and the transport tier):

PropertyEnv VarDefaultDescription
dvara.flightdeck.email.fromDVARA_FLIGHTDECK_EMAIL_FROMnoreply@dvarahq.comSender address — From: header on every outbound email
dvara.flightdeck.email.transportDVARA_FLIGHTDECK_EMAIL_TRANSPORTloglog prints to console (dev / CI); smtp uses Spring's JavaMailSender; resend POSTs to the Resend transactional API
dvara.flightdeck.email.public-endpoint-urlDVARA_FLIGHTDECK_EMAIL_PUBLIC_ENDPOINT_URLhttps://api.dvarahq.com/v1Data-plane URL shown in the welcome email and /signup/check-email
dvara.flightdeck.email.flightdeck-urlDVARA_FLIGHTDECK_EMAIL_FLIGHTDECK_URLhttps://flightdeck.dvarahq.comConsole base URL for welcome / password-reset CTAs
dvara.flightdeck.email.docs-urlDVARA_FLIGHTDECK_EMAIL_DOCS_URLhttps://dvarahq.com/docsDocs link in the welcome email
dvara.flightdeck.email.resend-api-keyDVARA_FLIGHTDECK_EMAIL_RESEND_API_KEYResend API key (re_…); only used when transport=resend. The sender domain in email.from must be verified in Resend (or use the sandbox sender onboarding@resend.dev).
dvara.flightdeck.email.resend.verify-domain-at-startuptrueWhen transport=resend, the boot probe calls GET /domains and refuses to start on a production-class profile if the sender domain isn't verified. Skipped automatically for the sandbox sender. Disable on air-gapped / no-egress environments.

Durability + retry + DLQ + idempotency knobs (dvara.flightdeck.email.delivery.*):

PropertyDefaultDescription
delivery.enabledtrueMaster switch for the durability layer. false → listener falls back to fire-and-forget — no email_delivery_log row, no idempotency dedup, no retry, no DLQ. Useful for tests that don't want a Postgres dep.
delivery.max-attempts5Sync attempt 1 + 4 async retries before the row is marked DEAD_LETTERED
delivery.initial-backoff-ms30000Backoff before attempt 2
delivery.max-backoff-ms120000Ceiling on any single retry's backoff
delivery.backoff-multiplier2.0Exponential factor — delay(n) = min(initial × multiplier^(n-2), max) for n ≥ 2. With defaults: 0 / +30s / +60s / +120s / +120s → cumulative ~5m 30s before DLQ.
delivery.retry-sweep-interval-ms30000How often the EmailRetrySweeper polls the DB for due retries
delivery.retry-sweep-batch-size100Max rows the sweeper processes per tick
delivery.idempotency-ttl-minutes60Dedup window. A second publish of the same EmailRequestedEvent.idempotencyKey within this window is a no-op. Producers reusing deterministic UUIDs across dlq-retention-days should regenerate to avoid losing the audit row on PK collision.
delivery.dlq-retention-days30How long SENT + DEAD_LETTERED rows are kept for operator review
delivery.cleanup-cron0 0 3 * * *Daily 03:00 UTC sweep that drops terminal rows past dlq-retention-days. PENDING_RETRY rows are never touched.

The legacy dvara.flightdeck.email.resend.retry-max-attempts / .retry-initial-backoff-ms / .retry-max-backoff-ms properties on the Resend transport are now defunct (retry lives at the listener level since PR 4 of #835) and kept for one release with @Deprecated. Operators should migrate to the dvara.flightdeck.email.delivery.* namespace.

dvara.flightdeck.security.saml.* (SAML 2.0 SSO)

Active when dvara.flightdeck.security.saml.metadata-url is set. Mutually exclusive with OIDC — configuring both fails at startup.

PropertyEnv VarDefaultDescription
dvara.flightdeck.security.saml.metadata-urlDVARA_FLIGHTDECK_SAML_METADATA_URLIdP metadata XML URL (activates SAML mode)
dvara.flightdeck.security.saml.entity-idDVARA_FLIGHTDECK_SAML_ENTITY_IDdvaraSP entity ID
dvara.flightdeck.security.saml.registration-idDVARA_FLIGHTDECK_SAML_REGISTRATION_IDdvaraSAML registration ID used in the ACS and metadata URLs (/login/saml2/sso/{registrationId})
dvara.flightdeck.security.saml.role-attributeDVARA_FLIGHTDECK_SAML_ROLE_ATTRIBUTErolesSAML attribute containing roles
dvara.flightdeck.security.saml.email-attributeDVARA_FLIGHTDECK_SAML_EMAIL_ATTRIBUTENameIDSAML attribute for email (NameID uses the SAML NameID element)
dvara.flightdeck.security.saml.tenant-attributeDVARA_FLIGHTDECK_SAML_TENANT_ATTRIBUTEtenant_idSAML attribute for tenant ID
dvara.flightdeck.security.saml.name-attributeDVARA_FLIGHTDECK_SAML_NAME_ATTRIBUTEdisplayNameSAML attribute for display name
dvara.flightdeck.security.saml.auto-provisionDVARA_FLIGHTDECK_SAML_AUTO_PROVISIONfalseAuto-create users on first SAML login
dvara.flightdeck.security.saml.default-rolesDVARA_FLIGHTDECK_SAML_DEFAULT_ROLESviewerComma-separated roles for auto-provisioned users
dvara.flightdeck.security.saml.default-tenant-idDVARA_FLIGHTDECK_SAML_DEFAULT_TENANT_IDTenant ID for auto-provisioned users (required when auto-provisioning is on)

dvara.vault.hashicorp.* / .aws.* / .azure.* (Full Vault Config)

The basic dvara.vault.backend selector and cache TTL are in the earlier Vault section. Backend-specific sub-fields:

PropertyEnv VarDefaultDescription
dvara.vault.hashicorp.namespaceVAULT_NAMESPACEVault Enterprise namespace (optional)
dvara.vault.hashicorp.role-idVAULT_ROLE_IDAppRole role ID
dvara.vault.hashicorp.secret-idVAULT_SECRET_IDAppRole secret ID
dvara.vault.aws.access-keyAWS_VAULT_ACCESS_KEYOptional. When blank, the AWS SDK's default credential provider chain resolves credentials in order: env vars (AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY), Java system props, the EC2 instance profile, the ECS task role, the EKS IRSA web-identity token (AWS_WEB_IDENTITY_TOKEN_FILE), and the ~/.aws/credentials file. For Kubernetes deployments, prefer IRSA over static keys — leave both fields blank and attach the IAM role to the pod's ServiceAccount.
dvara.vault.aws.secret-keyAWS_VAULT_SECRET_KEYOptional. Same fallback chain as access-key — leave blank to use instance / IRSA / SDK-default credentials.
dvara.vault.azure.client-idAZURE_CLIENT_IDAzure AD application client ID
dvara.vault.azure.client-secretAZURE_CLIENT_SECRETAzure AD application client secret
dvara.vault.azure.tenant-idAZURE_TENANT_IDAzure AD tenant ID

dvara.llm-gateway.tls.providers.<name>.* (Full mTLS Config)

PropertyDefaultDescription
client-key-passwordPassword for client key or PKCS12 bundle
trust-store-passwordTrust store password (if encrypted)
store-typeautoAuto-detected from extension: .p12→PKCS12, .jks→JKS, .pem→PEM

dvara.flightdeck.compliance.* (Scheduled Compliance Reports)

Requires a valid DVARA license key.

PropertyEnv VarDefaultDescription
dvara.flightdeck.compliance.soc2-scheduleDVARA_FLIGHTDECK_COMPLIANCE_SOC2_SCHEDULE""Cron expression for SOC2 auto-generation (blank = disabled)
dvara.flightdeck.compliance.hipaa-scheduleDVARA_FLIGHTDECK_COMPLIANCE_HIPAA_SCHEDULE""Cron expression for HIPAA auto-generation
dvara.flightdeck.compliance.gdpr-scheduleDVARA_FLIGHTDECK_COMPLIANCE_GDPR_SCHEDULE""Cron expression for GDPR auto-generation
dvara.flightdeck.compliance.default-tenant-idDVARA_FLIGHTDECK_COMPLIANCE_DEFAULT_TENANTTenant ID for scheduled reports (blank = all tenants)
dvara.flightdeck.compliance.retention-daysDVARA_FLIGHTDECK_COMPLIANCE_RETENTION_DAYS365Retention for generated reports

dvara.flightdeck.portal.* (Tenant Self-Service Portal)

PropertyDefaultDescription
dvara.flightdeck.portal.enabledtrueEnable /portal/* routes for tenant users
dvara.flightdeck.portal.self-servicetrueAllow tenants to create API keys via the portal

Flightdeck GitOps Config Import — Upload Cap

The Flightdeck Config Import surface (POST /config/import/preview) is protected by two layered byte caps. Sized for fleet snapshots — a 10K-tenant export is well under 5 MB — and small enough that a single tampered upload can't OOM the JVM.

PropertyDefaultDescription
spring.servlet.multipart.max-file-size25MBTomcat-level cap on the uploaded .json snapshot. A MaxUploadSizeExceededException handler turns Tomcat's bare 413 into a friendly redirect-with-flash on /config/import.
spring.servlet.multipart.max-request-size25MBMirrors max-file-size so a multipart envelope with extra form fields can't sneak past.

ConfigUiController re-checks the same byte cap in-process for both file uploads and pasted JSON, so the cap applies uniformly regardless of input method.

dvara.region.* (Multi-Region Identity)

PropertyEnv VarDescription
dvara.region.idDVARA_REGION_IDRegion identifier used in data-residency routing
dvara.region.nameDVARA_REGION_NAMEHuman-readable region name

dvara.encryption.* (AES-256-GCM Master Password)

PropertyEnv VarDescription
dvara.encryption.master-passwordDVARA_ENCRYPTION_MASTER_PASSWORDMaster password used to derive AES-256-GCM keys for provider credentials and the PII token store. Required when storing credentials through /v1/admin/credentials.

See Credentials & BYOK for rotation guidance.

MCP Proxy Observability Config

For the standalone DVARA MCP Proxy (port 8070), in addition to the existing MCP timeout properties:

PropertyDefaultDescription
management.endpoints.web.exposure.includehealth,prometheusActuator endpoints to expose
management.prometheus.metrics.export.enabledtrueEnable Prometheus scrape endpoint
management.tracing.sampling.probability1.0OTel sampling probability (env: TRACING_SAMPLING_PROBABILITY)
management.otlp.tracing.endpointhttp://localhost:4318/v1/tracesOTLP trace exporter endpoint (env: OTEL_EXPORTER_OTLP_ENDPOINT)
dvara.mcp-gateway.agentic.approval.default-actiondenyAction on timeout: deny or approve