systemRuntime.projectName=eddi
# Custom startup banner (replaces default Quarkus ASCII art)
quarkus.banner.path=banner.txt
systemRuntime.projectDomain=eddi.labs.ai
systemRuntime.projectVersion=6.1.0
systemRuntime.agentTimeoutInSeconds=60
%dev.systemRuntime.agentTimeoutInSeconds=600
%dev.eddi.conversations.maximumLifeTimeOfIdleConversationsInDays=10
eddi.conversations.maximumLifeTimeOfIdleConversationsInDays=90
%dev.eddi.conversations.deleteEndedConversationsOnceOlderThanDays=90
eddi.conversations.deleteEndedConversationsOnceOlderThanDays=365
# Per-category retention — set to -1 to disable automatic cleanup
# User memories (persistent facts, preferences, context)
eddi.usermemories.deleteOlderThanDays=-1
%dev.eddi.usermemories.deleteOlderThanDays=-1
# Audit ledger entries (disabled by default — EU AI Act requires retention)
eddi.audit.retentionDays=-1
%dev.eddi.audit.retentionDays=-1
eddi.migration.skipConversationMemories=false
eddi.migration.v6-qute.enabled=false

# Qute — template engine (replaces Thymeleaf for native image support)
quarkus.qute.strict-rendering=false

# Datastore — database backend for configuration and conversation storage
# Options: mongodb (default), postgres
eddi.datastore.type=mongodb

# PostgreSQL — only used when eddi.datastore.type=postgres
# Activate via Quarkus profile: -Dquarkus.profile=postgres (or env QUARKUS_PROFILE=postgres)
# DataStoreProducers selects the correct store implementation at runtime.
quarkus.datasource.db-kind=postgresql
quarkus.datasource.active=false
quarkus.datasource.devservices.enabled=false
%postgres.quarkus.datasource.active=true
# jdbc.url, username, password are provided by DevServices for tests.
# For production, set all three explicitly:
# %postgres.quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/eddi
# %postgres.quarkus.datasource.username=eddi
# %postgres.quarkus.datasource.password=eddi
%postgres.eddi.datastore.type=postgres

# Messaging — event bus for conversation ordering
# Options: in-memory (default, zero-dependency) or nats (JetStream, durable)
eddi.messaging.type=in-memory
# NATS configuration (only used when eddi.messaging.type=nats)
eddi.nats.url=nats://localhost:4222
eddi.nats.stream-name=EDDI_CONVERSATIONS
eddi.nats.max-retries=3
eddi.nats.ack-wait-seconds=60
eddi.nats.dead-letter-stream-name=EDDI_DEAD_LETTERS

# Logging — in-memory ring buffer + optional DB persistence
# Ring buffer size (in-memory, for SSE live tail)
eddi.logs.buffer-size=10000
# DB persistence (set to false to disable — ring buffer + SSE only)
eddi.logs.db-enabled=true
# Flush interval for async batch DB writer (seconds)
eddi.logs.db-flush-interval-seconds=5
# Minimum log level to persist to DB (TRACE, DEBUG, INFO, WARN, ERROR)
eddi.logs.db-persist-min-level=WARN
# Attach log capture filter to console handler (captures every record into ring buffer)
quarkus.log.console.filter=eddi-log-capture

# Secrets Vault — envelope-encrypted secret storage
# Master key (KEK) — REQUIRED to enable vault. Set via env var:
#   EDDI_VAULT_MASTER_KEY=<your-32-char-passphrase>
# If not set, vault is DISABLED and plaintext configs pass through unchanged.
eddi.vault.master-key=
eddi.vault.cache-ttl-minutes=5
eddi.vault.cache-max-size=1000

# Tenant Quotas — SaaS foundation (per-tenant rate limits + usage metering)
# Set to -1 for unlimited. Disabled by default — zero impact on existing deployments.
eddi.tenant.default-id=default
eddi.tenant.quota.enabled=false
eddi.tenant.quota.max-conversations-per-day=-1
eddi.tenant.quota.max-agents-per-tenant=-1
eddi.tenant.quota.max-api-calls-per-minute=-1
eddi.tenant.quota.max-monthly-cost-usd=-1

# Scheduled Triggers — heartbeat / cron job configuration
# Master switch (set to false to disable all schedule polling)
eddi.schedule.enabled=true
# How often to check for due schedules (default: 15s)
eddi.schedule.poll-interval=15s
# How long until a claimed schedule is considered abandoned (crash recovery)
eddi.schedule.lease-timeout=5m
# Maximum retry attempts before dead-lettering
eddi.schedule.max-retries=5
# Exponential backoff: delay = base * multiplier^(attempt-1) seconds
eddi.schedule.backoff-base-seconds=15
eddi.schedule.backoff-multiplier=4
# Minimum allowed cron interval (prevents schedule bombing)
eddi.schedule.min-interval-seconds=60
# Instance ID for cluster claim tracking (auto-detected from hostname if empty)
eddi.schedule.instance-id=
# Default time zone for schedules (IANA format)
eddi.schedule.default-timezone=UTC

# Http Client
httpClient.maxConnectionPerRoute=200
httpClient.connectTimeoutInMillis=10000
httpClient.idleTimeoutInMillis=60000
httpClient.maxRedirects=5


# MongoDB
mongodb.database=eddi
%dev.mongodb.connectionString=mongodb://localhost:27017/eddi?retryWrites=true&w=majority&connectTimeoutMS=10000&socketTimeoutMS=30000
mongodb.connectionString=mongodb://mongodb:27017/eddi?retryWrites=true&w=majority&connectTimeoutMS=10000&socketTimeoutMS=30000

quarkus.mongodb.devservices.enabled=true
quarkus.mongodb.devservices.port=27017
# Http
quarkus.http.port=7070
# Immutable caching for hashed UI bundles (filename contains content hash)
quarkus.http.filter.ui-assets-immutable.header.Cache-Control=public, max-age=31536000, immutable
quarkus.http.filter.ui-assets-immutable.matches=/(scripts|assets)/.*
quarkus.http.filter.ui-assets-immutable.methods=GET
quarkus.http.ssl-port=7443
quarkus.http.cors.enabled=true
quarkus.http.cors.origins=http://localhost:3000,http://localhost:7070,https://localhost:7443
quarkus.http.cors.headers=accept, origin, authorization, content-type, x-requested-with
quarkus.http.cors.exposed-headers=Location
quarkus.http.cors.methods=OPTIONS,HEAD,GET,PUT,POST,DELETE,PATCH
# Jackson JSON
json.prettyPrint=false
quarkus.jackson.write-dates-as-timestamps=true
# Qute Templating — strict in production (fail on missing template variables)
%prod.quarkus.qute.strict-rendering=true
# Security response headers — defense-in-depth for SPA and API responses
quarkus.http.header.X-Content-Type-Options.value=nosniff
quarkus.http.header.X-Frame-Options.value=DENY
quarkus.http.header.Referrer-Policy.value=strict-origin-when-cross-origin
quarkus.http.header.X-XSS-Protection.value=0
quarkus.http.header.Permissions-Policy.value=camera=(), microphone=(), geolocation=()
# CSP: Allow self + inline styles + connect to same-origin API and to Keycloak.
# eddi.keycloak.public.url is set via EDDI_KEYCLOAK_PUBLIC_URL env var when auth is enabled.
# When auth is disabled (no env var) the placeholder expands to empty string — harmless.
quarkus.http.header.Content-Security-Policy.value=default-src 'self'; script-src 'self'; \
  style-src 'self' 'unsafe-inline'; img-src 'self' data:; \
  connect-src 'self' ${eddi.keycloak.public.url:}; \
  font-src 'self'; frame-ancestors 'none';
# OIDC Configuration
# quarkus.oidc.enabled is BUILD-TIME — extension must be active for token validation
quarkus.oidc.enabled=true
# quarkus.oidc.tenant-enabled is RUNTIME — controls whether auth is enforced
# Override at container start: QUARKUS_OIDC_TENANT_ENABLED=true
quarkus.oidc.tenant-enabled=false
quarkus.oidc.auth-server-url=http://localhost:8180/realms/eddi
quarkus.oidc.client-id=eddi-backend
quarkus.oidc.credentials.secret=
quarkus.oidc.authentication.user-info-required=true
# Bearer-only: backend validates tokens, never initiates browser login.
# The Manager SPA handles login via JavaScript using the eddi-frontend client.
quarkus.oidc.application-type=service
# quarkus.oidc.token.lifespan-grace=3000

# Note: No callback permission needed — service mode returns 401 (no redirect).
# SPA entry points (/manage, /chat) and static assets (/scripts, /fonts, /img)
# are permitted so the Manager SPA can load and handle Keycloak login via keycloak-js.
# All API endpoints remain behind the authenticated policy.
# Auth Permissions
# authorization.enabled tracks tenant-enabled — when OIDC is on, @RolesAllowed is enforced
authorization.enabled=${quarkus.oidc.tenant-enabled}
# Security escape hatch — MUST be explicitly set to true to allow unauthenticated access in prod
eddi.security.allow-unauthenticated=false
# Static assets + SPA entry points — GET/HEAD only (no mutation allowed)
# Root-level icons/images must be listed explicitly because /* is caught by the authenticated policy
quarkus.http.auth.permission.static-assets.paths=/manage,/manage/*,/chat,/chat/*,/scripts/*,/fonts/*,/css/*,/js/*,/img/*,/assets/*,/eddi-icon.svg,/eddi-icon.ico,/logo_eddi.png,/favicon.ico,/robots.txt,/mockServiceWorker.js
quarkus.http.auth.permission.static-assets.policy=permit
quarkus.http.auth.permission.static-assets.methods=GET,HEAD
# Health endpoints — publicly readable (required for k8s probes)
quarkus.http.auth.permission.health.paths=/q/health/*
quarkus.http.auth.permission.health.policy=permit
quarkus.http.auth.permission.health.methods=GET
# Metrics — require authentication (leaks deployment shape)
# Removed from permit rules — falls through to authenticated policy
# Slack webhooks — POST only (signature verified in handler)
quarkus.http.auth.permission.slack.paths=/integrations/slack/*
quarkus.http.auth.permission.slack.policy=permit
quarkus.http.auth.permission.slack.methods=POST
# Catch-all — everything else requires authentication
quarkus.http.auth.permission.authenticated.paths=/,/*
quarkus.http.auth.permission.authenticated.policy=authenticated
quarkus.http.auth.permission.authenticated.methods=GET,HEAD,POST,PUT,DELETE,OPTIONS,PATCH
# Logging
quarkus.log.console.enabled=true
quarkus.log.console.format=%d{yyyy-MM-dd HH:mm:ss} %-5p [%c{3.}]] (%t) %s%e%n
quarkus.log.console.level=DEBUG
# Live Reload
quarkus.live-reload.instrumentation=true
# Micrometer
quarkus.micrometer.binder.http-server.max-uri-tags=200
# OpenAPI / Swagger
quarkus.swagger-ui.title=EDDI API
quarkus.swagger-ui.footer=&#169; LABS.AI 2026
quarkus.swagger-ui.always-include=true
quarkus.swagger-ui.doc-expansion=none
quarkus.smallrye-openapi.info-title=EDDI API
%dev.quarkus.smallrye-openapi.info-title=EDDI API (development)
quarkus.smallrye-openapi.info-version=6.1.0
quarkus.smallrye-openapi.info-description=Enterprise-grade conversational AI platform. \
  Configure agents, orchestrate multi-agent group discussions, \
  and integrate with LLM providers via a unified REST API.
quarkus.smallrye-openapi.info-terms-of-service=
quarkus.smallrye-openapi.info-contact-email=contact@labs.ai
quarkus.smallrye-openapi.info-contact-name=LABS.AI
quarkus.smallrye-openapi.info-contact-url=https://eddi.labs.ai
quarkus.smallrye-openapi.info-license-name=Apache 2.0
quarkus.smallrye-openapi.info-license-url=https://www.apache.org/licenses/LICENSE-2.0.html
quarkus.smallrye-openapi.path=/openapi
# Auto-generate operationId from method name (SDK codegen friendly)
quarkus.smallrye-openapi.operation-id-strategy=METHOD
# OpenAPI Security Scheme (Keycloak OIDC)
# SmallRye auto-generates securityScheme + global securityRequirement.
# Swagger UI will show "Authorize" button.
# Only enforced at runtime when QUARKUS_OIDC_TENANT_ENABLED=true.
quarkus.smallrye-openapi.security-scheme=oidc
quarkus.smallrye-openapi.security-scheme-name=Keycloak OIDC
quarkus.smallrye-openapi.security-scheme-description=OAuth2 / OpenID Connect via Keycloak. \
  Only enforced when QUARKUS_OIDC_TENANT_ENABLED=true.
quarkus.smallrye-openapi.oidc-open-id-connect-url=\
  ${quarkus.oidc.auth-server-url}/.well-known/openid-configuration
quarkus.swagger-ui.oauth2-redirect-url=http://localhost:7070/q/swagger-ui/oauth2-redirect.html
# Docker
quarkus.container-image.group=labsai
quarkus.container-image.name=eddi
quarkus.container-image.tag=latest
quarkus.container-image.additional-tags=6.1.0

# ╔══════════════════════════════════════════════════════════════════════════════╗
# ║ SECURITY: MCP Server Authentication                                        ║
# ║                                                                            ║
# ║ By default, EDDI's MCP endpoint (/mcp) is UNAUTHENTICATED.                ║
# ║ All 33 MCP tools (agent CRUD, conversations, user memories, audit trails)  ║
# ║ are accessible to any MCP client that can reach this endpoint.             ║
# ║                                                                            ║
# ║ FOR PRODUCTION DEPLOYMENTS:                                                ║
# ║   1. Set QUARKUS_OIDC_TENANT_ENABLED=true                                 ║
# ║   2. Configure quarkus.oidc.auth-server-url to your Keycloak realm         ║
# ║   3. MCP clients must present valid Bearer tokens                          ║
# ║   4. Read-only tools require role 'eddi-viewer'                            ║
# ║   5. Write/delete tools require role 'eddi-admin'                          ║
# ║                                                                            ║
# ║ Without OIDC enabled, authorization.enabled=false and role checks          ║
# ║ in McpConversationTools / McpMemoryTools are no-ops.                       ║
# ╚══════════════════════════════════════════════════════════════════════════════╝
# MCP Server — Model Context Protocol (Phase 8a)
# Expose EDDI agents and admin API as MCP tools for AI assistants
# Streamable HTTP transport at /mcp endpoint
quarkus.mcp-server.http.root-path=/mcp

# ╔══════════════════════════════════════════════════════════════════════════════╗
# ║ OBSERVABILITY: OpenTelemetry Distributed Tracing                           ║
# ║                                                                            ║
# ║ EDDI emits traces via OTLP protocol (backend-agnostic).                   ║
# ║ Works with Jaeger, Grafana Tempo, Datadog, Honeycomb, etc.                ║
# ║                                                                            ║
# ║ Traces include:                                                            ║
# ║   - JAX-RS REST endpoints (auto-instrumented by Quarkus)                  ║
# ║   - Vert.x outbound HTTP calls (auto-instrumented by Quarkus)            ║
# ║   - MongoDB operations (auto-instrumented by Quarkus)                     ║
# ║   - Pipeline task execution (manual spans in LifecycleManager)            ║
# ║                                                                            ║
# ║ FOR PRODUCTION: set quarkus.otel.exporter.otlp.endpoint to your           ║
# ║ collector (e.g. Jaeger at http://jaeger:4317).                            ║
# ╚══════════════════════════════════════════════════════════════════════════════╝
quarkus.otel.service.name=eddi
quarkus.otel.exporter.otlp.endpoint=http://localhost:4317
# Disabled by default — enable via env var when a collector is present
# (docker-compose.monitoring.yml sets QUARKUS_OTEL_SDK_DISABLED=false)
quarkus.otel.sdk.disabled=true

# ╔══════════════════════════════════════════════════════════════════════════════╗
# ║ COORDINATOR: Conversation Queue Limits                                     ║
# ║                                                                            ║
# ║ Maximum number of concurrent active conversation queues.                   ║
# ║ Prevents OOM from runaway conversation creation.                           ║
# ║ Follow-up messages to existing conversations are always accepted.          ║
# ╚══════════════════════════════════════════════════════════════════════════════╝
eddi.coordinator.max-active-conversations=10000

