fraiseql_server/server_config/mod.rs
1//! Server configuration (`*Config` types).
2//!
3//! These are developer-facing configuration types loaded from `fraiseql.toml`,
4//! environment variables, or CLI flags. They are mutable between deployments.
5//!
6//! For the distinction between `*Config` (developer-facing, mutable) and
7//! `*Settings` (compiled into `schema.compiled.json`, immutable at runtime),
8//! see `docs/architecture/config-vs-settings.md`.
9
10pub(crate) mod defaults;
11pub mod hs256;
12mod methods;
13pub mod observers;
14pub mod tls;
15
16#[cfg(test)]
17mod tests;
18
19use std::{net::SocketAddr, path::PathBuf};
20
21use defaults::{
22 default_bind_addr, default_database_url, default_graphql_path, default_health_path,
23 default_introspection_path, default_max_header_bytes, default_max_header_count,
24 default_max_request_body_bytes, default_metrics_json_path, default_metrics_path,
25 default_playground_path, default_pool_max_size, default_pool_min_size, default_pool_timeout,
26 default_readiness_path, default_schema_path, default_shutdown_timeout_secs,
27 default_subscription_path,
28};
29use fraiseql_core::security::OidcConfig;
30pub use hs256::Hs256Config;
31pub use observers::AdmissionConfig;
32#[cfg(feature = "observers")]
33pub use observers::{ObserverConfig, ObserverPoolConfig};
34use serde::{Deserialize, Serialize};
35pub use tls::{DatabaseTlsConfig, PlaygroundTool, TlsServerConfig};
36
37use crate::middleware::RateLimitConfig;
38
39/// Server configuration.
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct ServerConfig {
42 /// Path to compiled schema JSON file.
43 #[serde(default = "defaults::default_schema_path")]
44 pub schema_path: PathBuf,
45
46 /// Database connection URL (PostgreSQL, MySQL, SQLite, SQL Server).
47 #[serde(default = "defaults::default_database_url")]
48 pub database_url: String,
49
50 /// Server bind address.
51 #[serde(default = "defaults::default_bind_addr")]
52 pub bind_addr: SocketAddr,
53
54 /// Arrow Flight gRPC bind address (requires `arrow` feature).
55 ///
56 /// Defaults to `0.0.0.0:50051`. Override with `FRAISEQL_FLIGHT_BIND_ADDR`
57 /// environment variable or this field in the config file.
58 #[cfg(feature = "arrow")]
59 #[serde(default = "defaults::default_flight_bind_addr")]
60 pub flight_bind_addr: SocketAddr,
61
62 /// Enable CORS.
63 #[serde(default = "defaults::default_true")]
64 pub cors_enabled: bool,
65
66 /// CORS allowed origins (if empty, allows all).
67 #[serde(default)]
68 pub cors_origins: Vec<String>,
69
70 /// Enable framework-level response compression.
71 ///
72 /// Defaults to `false`. In production FraiseQL is typically deployed
73 /// behind a reverse proxy (Nginx, Caddy, cloud load balancer) that
74 /// handles compression more efficiently (brotli, shared across upstreams,
75 /// cacheable). Enable this only for single-binary / no-proxy deployments.
76 #[serde(default = "defaults::default_false")]
77 pub compression_enabled: bool,
78
79 /// Enable request tracing.
80 #[serde(default = "defaults::default_true")]
81 pub tracing_enabled: bool,
82
83 /// OTLP exporter endpoint for distributed tracing.
84 ///
85 /// When set (e.g. `"http://otel-collector:4317"`), the server initializes an
86 /// `OpenTelemetry` OTLP exporter. When `None`, the `OTEL_EXPORTER_OTLP_ENDPOINT`
87 /// environment variable is checked as a fallback. If neither is set, no OTLP
88 /// export occurs (zero overhead).
89 #[serde(default)]
90 pub otlp_endpoint: Option<String>,
91
92 /// OTLP exporter timeout in seconds (default: 10).
93 #[serde(default = "defaults::default_otlp_timeout_secs")]
94 pub otlp_export_timeout_secs: u64,
95
96 /// Service name for distributed tracing (default: `"fraiseql"`).
97 #[serde(default = "defaults::default_service_name")]
98 pub tracing_service_name: String,
99
100 /// Enable APQ (Automatic Persisted Queries).
101 #[serde(default = "defaults::default_true")]
102 pub apq_enabled: bool,
103
104 /// Enable query caching.
105 #[serde(default = "defaults::default_true")]
106 pub cache_enabled: bool,
107
108 /// GraphQL endpoint path.
109 #[serde(default = "defaults::default_graphql_path")]
110 pub graphql_path: String,
111
112 /// Health check endpoint path (liveness probe).
113 ///
114 /// Returns 200 as long as the process is alive, 503 if the database is down.
115 #[serde(default = "defaults::default_health_path")]
116 pub health_path: String,
117
118 /// Readiness probe endpoint path.
119 ///
120 /// Returns 200 when the server is ready to serve traffic (database reachable),
121 /// 503 otherwise. Kubernetes `readinessProbe` should point here.
122 #[serde(default = "defaults::default_readiness_path")]
123 pub readiness_path: String,
124
125 /// Introspection endpoint path.
126 #[serde(default = "defaults::default_introspection_path")]
127 pub introspection_path: String,
128
129 /// Metrics endpoint path (Prometheus format).
130 #[serde(default = "defaults::default_metrics_path")]
131 pub metrics_path: String,
132
133 /// Metrics JSON endpoint path.
134 #[serde(default = "defaults::default_metrics_json_path")]
135 pub metrics_json_path: String,
136
137 /// Playground (GraphQL IDE) endpoint path.
138 #[serde(default = "defaults::default_playground_path")]
139 pub playground_path: String,
140
141 /// Enable GraphQL playground/IDE (default: false for production safety).
142 ///
143 /// When enabled, serves a GraphQL IDE (`GraphiQL` or Apollo Sandbox)
144 /// at the configured `playground_path`.
145 ///
146 /// **Security**: Disabled by default for production safety. Set to true for development
147 /// environments only. The playground exposes schema information and can be a
148 /// reconnaissance vector for attackers.
149 #[serde(default)]
150 pub playground_enabled: bool,
151
152 /// Which GraphQL IDE to use.
153 ///
154 /// - `graphiql`: The classic GraphQL IDE (default)
155 /// - `apollo-sandbox`: Apollo's embeddable sandbox
156 #[serde(default)]
157 pub playground_tool: PlaygroundTool,
158
159 /// `WebSocket` endpoint path for GraphQL subscriptions.
160 #[serde(default = "defaults::default_subscription_path")]
161 pub subscription_path: String,
162
163 /// Enable GraphQL subscriptions over `WebSocket`.
164 ///
165 /// When enabled, provides graphql-ws (graphql-transport-ws) protocol
166 /// support for real-time subscription events.
167 #[serde(default = "defaults::default_true")]
168 pub subscriptions_enabled: bool,
169
170 /// Enable metrics endpoints.
171 ///
172 /// **Security**: Disabled by default for production safety.
173 /// When enabled, requires `metrics_token` to be set for authentication.
174 #[serde(default)]
175 pub metrics_enabled: bool,
176
177 /// Bearer token for metrics endpoint authentication.
178 ///
179 /// Required when `metrics_enabled` is true. Requests must include:
180 /// `Authorization: Bearer <token>`
181 ///
182 /// **Security**: Use a strong, random token (e.g., 32+ characters).
183 #[serde(default)]
184 pub metrics_token: Option<String>,
185
186 /// Enable admin API endpoints (default: false for production safety).
187 ///
188 /// **Security**: Disabled by default. When enabled, requires `admin_token` to be set.
189 /// Admin endpoints allow schema reloading, cache management, and config inspection.
190 #[serde(default)]
191 pub admin_api_enabled: bool,
192
193 /// Bearer token for admin API authentication.
194 ///
195 /// Required when `admin_api_enabled` is true. Requests must include:
196 /// `Authorization: Bearer <token>`
197 ///
198 /// **Security**: Use a strong, random token (minimum 32 characters).
199 /// This token grants access to **destructive** admin operations:
200 /// `reload-schema`, `cache/clear`.
201 ///
202 /// If `admin_readonly_token` is set, this token is restricted to write
203 /// operations only. If `admin_readonly_token` is not set, this token
204 /// also grants access to read-only endpoints (backwards-compatible).
205 #[serde(default)]
206 pub admin_token: Option<String>,
207
208 /// Optional separate bearer token for read-only admin operations.
209 ///
210 /// When set, restricts `admin_token` to destructive operations only
211 /// (`reload-schema`, `cache/clear`) and uses this token for read-only
212 /// endpoints (`config`, `cache/stats`, `explain`, `grafana-dashboard`).
213 ///
214 /// Operators and monitoring tools can use this token without gaining
215 /// the ability to modify server state or reload the schema.
216 ///
217 /// **Security**: Must be different from `admin_token` and at least 32
218 /// characters. Requires `admin_api_enabled = true` and `admin_token` set.
219 #[serde(default)]
220 pub admin_readonly_token: Option<String>,
221
222 /// Enable introspection endpoint (default: false for production safety).
223 ///
224 /// **Security**: Disabled by default. When enabled, the introspection endpoint
225 /// exposes the complete GraphQL schema structure. Combined with `introspection_require_auth`,
226 /// you can optionally protect it with OIDC authentication.
227 #[serde(default)]
228 pub introspection_enabled: bool,
229
230 /// Require authentication for introspection endpoint (default: true).
231 ///
232 /// When true and OIDC is configured, introspection requires same auth as GraphQL endpoint.
233 /// When false, introspection is publicly accessible (use only in development).
234 #[serde(default = "defaults::default_true")]
235 pub introspection_require_auth: bool,
236
237 /// Require authentication for the schema metadata endpoint (default: None).
238 ///
239 /// When `Some(true)`, the `/api/v1/schema/metadata` endpoint requires OIDC auth
240 /// independently of introspection. When `Some(false)`, metadata is publicly
241 /// accessible regardless of introspection auth. When `None` (default), falls
242 /// back to `introspection_require_auth` for backwards compatibility.
243 #[serde(default, skip_serializing_if = "Option::is_none")]
244 pub metadata_require_auth: Option<bool>,
245
246 /// Require authentication for schema export endpoints (default: None).
247 ///
248 /// Controls `/api/v1/schema.graphql` and `/api/v1/schema.json` independently of
249 /// introspection auth. When `Some(true)`, schema export requires OIDC auth. When
250 /// `Some(false)`, schema export is publicly accessible. When `None` (default),
251 /// falls back to `introspection_require_auth` for backwards compatibility.
252 #[serde(default, skip_serializing_if = "Option::is_none")]
253 pub schema_export_require_auth: Option<bool>,
254
255 /// Require authentication for the GraphQL Playground endpoint (default: None).
256 ///
257 /// Controls the playground independently of introspection auth. When `Some(true)`,
258 /// the playground requires OIDC auth. When `Some(false)`, the playground is publicly
259 /// accessible. When `None` (default), falls back to `introspection_require_auth`
260 /// for backwards compatibility.
261 #[serde(default, skip_serializing_if = "Option::is_none")]
262 pub playground_require_auth: Option<bool>,
263
264 /// Require authentication for the `WebSocket` subscription endpoint (default: None).
265 ///
266 /// Controls the `/subscriptions` endpoint independently of introspection auth.
267 /// When `Some(true)`, the subscription endpoint requires OIDC auth. When `Some(false)`,
268 /// subscriptions are publicly accessible. When `None` (default), falls back to
269 /// `introspection_require_auth` for backwards compatibility.
270 #[serde(default, skip_serializing_if = "Option::is_none")]
271 pub subscription_require_auth: Option<bool>,
272
273 /// Require authentication for design audit API endpoints (default: true).
274 ///
275 /// Design audit endpoints expose system architecture and optimization opportunities.
276 /// When true and OIDC is configured, design endpoints require same auth as GraphQL endpoint.
277 /// When false, design endpoints are publicly accessible (use only in development).
278 #[serde(default = "defaults::default_true")]
279 pub design_api_require_auth: bool,
280
281 /// Database connection pool minimum size.
282 #[serde(default = "defaults::default_pool_min_size")]
283 pub pool_min_size: usize,
284
285 /// Database connection pool maximum size.
286 #[serde(default = "defaults::default_pool_max_size")]
287 pub pool_max_size: usize,
288
289 /// Database connection pool timeout in seconds.
290 #[serde(default = "defaults::default_pool_timeout")]
291 pub pool_timeout_secs: u64,
292
293 /// OIDC authentication configuration (optional).
294 ///
295 /// When set, enables JWT authentication using OIDC discovery.
296 /// Supports Auth0, Keycloak, Okta, Cognito, Azure AD, and any
297 /// OIDC-compliant provider.
298 ///
299 /// # Example (TOML)
300 ///
301 /// ```toml
302 /// [auth]
303 /// issuer = "https://your-tenant.auth0.com/"
304 /// audience = "your-api-identifier"
305 /// ```
306 #[serde(default)]
307 pub auth: Option<OidcConfig>,
308
309 /// HS256 symmetric-key authentication (optional).
310 ///
311 /// Alternative to `auth` (OIDC) for integration testing and internal
312 /// service-to-service scenarios. Mutually exclusive with `auth`.
313 ///
314 /// Validation is fully local — no discovery endpoint, no JWKS fetch.
315 /// Not recommended for public-facing production.
316 ///
317 /// # Example (TOML)
318 ///
319 /// ```toml
320 /// [auth_hs256]
321 /// secret_env = "FRAISEQL_HS256_SECRET"
322 /// issuer = "my-test-suite"
323 /// audience = "my-api"
324 /// ```
325 #[serde(default)]
326 pub auth_hs256: Option<Hs256Config>,
327
328 /// TLS/SSL configuration for HTTPS and encrypted connections.
329 ///
330 /// When set, enables TLS enforcement for HTTP/gRPC endpoints and
331 /// optionally requires mutual TLS (mTLS) for client certificates.
332 ///
333 /// # Example (TOML)
334 ///
335 /// ```toml
336 /// [tls]
337 /// enabled = true
338 /// cert_path = "/etc/fraiseql/cert.pem"
339 /// key_path = "/etc/fraiseql/key.pem"
340 /// require_client_cert = false
341 /// min_version = "1.2" # "1.2" or "1.3"
342 /// ```
343 #[serde(default)]
344 pub tls: Option<TlsServerConfig>,
345
346 /// Database TLS configuration.
347 ///
348 /// Enables TLS for database connections and configures
349 /// per-database TLS settings (PostgreSQL, Redis, `ClickHouse`, etc.).
350 ///
351 /// # Example (TOML)
352 ///
353 /// ```toml
354 /// [database_tls]
355 /// postgres_ssl_mode = "require" # disable, allow, prefer, require, verify-ca, verify-full
356 /// redis_ssl = true # Use rediss:// protocol
357 /// clickhouse_https = true # Use HTTPS
358 /// elasticsearch_https = true # Use HTTPS
359 /// verify_certificates = true # Verify server certificates
360 /// ```
361 #[serde(default)]
362 pub database_tls: Option<DatabaseTlsConfig>,
363
364 /// Require `Content-Type: application/json` on POST requests (default: true).
365 ///
366 /// CSRF protection: rejects POST requests with non-JSON Content-Type
367 /// (e.g. `text/plain`, `application/x-www-form-urlencoded`) with 415.
368 #[serde(default = "defaults::default_true")]
369 pub require_json_content_type: bool,
370
371 /// Maximum request body size in bytes (default: 1 MB).
372 ///
373 /// Requests exceeding this limit receive 413 Payload Too Large.
374 /// Set to 0 to use axum's default (no limit).
375 #[serde(default = "defaults::default_max_request_body_bytes")]
376 pub max_request_body_bytes: usize,
377
378 /// Maximum number of HTTP headers per request (default: 100).
379 ///
380 /// Requests with more headers than this limit receive 431 Request Header Fields Too Large.
381 /// Prevents header-flooding `DoS` attacks that exhaust memory.
382 #[serde(default = "defaults::default_max_header_count")]
383 pub max_header_count: usize,
384
385 /// Maximum total size of all HTTP headers in bytes (default: 32 `KiB`).
386 ///
387 /// Requests whose combined header name+value bytes exceed this limit receive
388 /// 431 Request Header Fields Too Large. Prevents memory exhaustion from
389 /// oversized header values.
390 #[serde(default = "defaults::default_max_header_bytes")]
391 pub max_header_bytes: usize,
392
393 /// Per-request processing timeout in seconds (default: `None` — no timeout).
394 ///
395 /// When set, each HTTP request must complete within this many seconds or
396 /// the server returns **408 Request Timeout**. This is a defence-in-depth
397 /// measure against slow or runaway database queries.
398 ///
399 /// **Recommendation**: set to `60` for production deployments.
400 ///
401 /// # Example (TOML)
402 ///
403 /// ```toml
404 /// request_timeout_secs = 60
405 /// ```
406 #[serde(default)]
407 pub request_timeout_secs: Option<u64>,
408
409 /// Maximum byte length for a query string delivered via HTTP GET.
410 ///
411 /// GET queries are URL-encoded and passed as a query parameter. Very long
412 /// strings are either a `DoS` attempt or a sign that the caller should use
413 /// POST instead. Default: `100_000` (100 `KiB`).
414 ///
415 /// # Example (TOML)
416 ///
417 /// ```toml
418 /// max_get_query_bytes = 50000
419 /// ```
420 #[serde(default = "defaults::default_max_get_query_bytes")]
421 pub max_get_query_bytes: usize,
422
423 /// Rate limiting configuration for GraphQL requests.
424 ///
425 /// When configured, enables per-IP and per-user rate limiting with token bucket algorithm.
426 /// Defaults to enabled with sensible per-IP limits for security-by-default.
427 ///
428 /// # Example (TOML)
429 ///
430 /// ```toml
431 /// [rate_limiting]
432 /// enabled = true
433 /// rps_per_ip = 100 # 100 requests/second per IP
434 /// rps_per_user = 1000 # 1000 requests/second per authenticated user
435 /// burst_size = 500 # Allow bursts up to 500 requests
436 /// ```
437 #[serde(default)]
438 pub rate_limiting: Option<RateLimitConfig>,
439
440 /// Observer runtime configuration (optional, requires `observers` feature).
441 #[cfg(feature = "observers")]
442 #[serde(default)]
443 pub observers: Option<ObserverConfig>,
444
445 /// Connection pool pressure monitoring configuration.
446 ///
447 /// When `enabled = true`, the server spawns a background task that monitors
448 /// pool metrics and emits scaling recommendations via Prometheus metrics and
449 /// log lines. **The pool is not resized at runtime** — act on
450 /// `fraiseql_pool_tuning_*` events by adjusting `max_connections` and restarting.
451 ///
452 /// # Example (TOML)
453 ///
454 /// ```toml
455 /// [pool_tuning]
456 /// enabled = true
457 /// min_pool_size = 5
458 /// max_pool_size = 50
459 /// tuning_interval_ms = 30000
460 /// ```
461 #[serde(default)]
462 pub pool_tuning: Option<crate::config::pool_tuning::PoolPressureMonitorConfig>,
463
464 /// Admission control configuration.
465 ///
466 /// When set, enforces a maximum number of concurrent in-flight requests and
467 /// a maximum queue depth. Requests that exceed either limit receive
468 /// `503 Service Unavailable` immediately instead of stalling under load.
469 ///
470 /// # Example (TOML)
471 ///
472 /// ```toml
473 /// [admission_control]
474 /// max_concurrent = 500
475 /// max_queue_depth = 1000
476 /// ```
477 #[serde(default)]
478 pub admission_control: Option<AdmissionConfig>,
479
480 /// Security contact email for `/.well-known/security.txt` (RFC 9116).
481 ///
482 /// When set, the server exposes a `/.well-known/security.txt` endpoint
483 /// with this email address as the security contact. This helps security
484 /// researchers report vulnerabilities responsibly.
485 ///
486 /// # Example (TOML)
487 ///
488 /// ```toml
489 /// security_contact = "security@example.com"
490 /// ```
491 #[serde(default)]
492 pub security_contact: Option<String>,
493
494 /// Query validation overrides (depth and complexity limits).
495 ///
496 /// When present, these values take precedence over the limits baked into
497 /// the compiled schema, allowing operators to tune validation without
498 /// recompiling.
499 ///
500 /// # Example (TOML)
501 ///
502 /// ```toml
503 /// [validation]
504 /// max_query_depth = 15
505 /// max_query_complexity = 200
506 /// ```
507 #[serde(default)]
508 pub validation: Option<fraiseql_core::schema::ValidationConfig>,
509
510 /// Maximum failed admin bearer auth attempts per IP within a 60-second
511 /// window before the IP is blocked with 429 Too Many Requests (default: 10).
512 ///
513 /// Set to `0` to disable brute-force protection entirely (not recommended).
514 ///
515 /// # Example (TOML)
516 ///
517 /// ```toml
518 /// admin_auth_max_failures = 5
519 /// ```
520 #[serde(default = "defaults::default_admin_auth_max_failures")]
521 pub admin_auth_max_failures: u32,
522
523 /// Bearer token protecting the storage REST API (`/storage/v1/`).
524 ///
525 /// When set, all requests to storage endpoints must include an
526 /// `Authorization: Bearer <token>` header that matches this value. Requests
527 /// without a valid token receive **401 Unauthorized**.
528 ///
529 /// **Security**: This token protects *all* storage operations (upload, download,
530 /// delete, presigned URL). Use a strong random string (minimum 32 characters).
531 /// Omit the field (or set `None`) to leave storage endpoints open — appropriate
532 /// only in development or when the storage API is behind a trusted network boundary.
533 ///
534 /// # Example (TOML)
535 ///
536 /// ```toml
537 /// storage_token = "your-strong-random-token-here"
538 /// ```
539 #[serde(default)]
540 pub storage_token: Option<String>,
541
542 /// Graceful shutdown drain timeout in seconds (default: 30).
543 ///
544 /// After a SIGTERM or Ctrl+C signal, the server stops accepting new connections and
545 /// waits for in-flight requests and background runtimes (observers) to finish.
546 /// If the drain takes longer than this value, the process logs a warning and exits
547 /// immediately instead of hanging indefinitely.
548 ///
549 /// Set this to match `terminationGracePeriodSeconds` in your Kubernetes pod spec
550 /// minus a small buffer (e.g., 25s when `terminationGracePeriodSeconds = 30`).
551 ///
552 /// Override with `FRAISEQL_SHUTDOWN_TIMEOUT_SECS`.
553 #[serde(default = "defaults::default_shutdown_timeout_secs")]
554 pub shutdown_timeout_secs: u64,
555
556 /// Usage counter persistence configuration (optional).
557 ///
558 /// When set, mutation usage counters are periodically flushed to PostgreSQL
559 /// and restored on server startup. Requires a PostgreSQL database URL.
560 ///
561 /// ```toml
562 /// [usage]
563 /// flush_interval_secs = 60
564 /// ```
565 ///
566 /// When absent (default), counters are in-memory only and reset on restart.
567 #[serde(default)]
568 pub usage: Option<crate::config::UsagePersistenceConfig>,
569}
570
571impl Default for ServerConfig {
572 fn default() -> Self {
573 Self {
574 schema_path: default_schema_path(),
575 database_url: default_database_url(),
576 bind_addr: default_bind_addr(),
577 #[cfg(feature = "arrow")]
578 flight_bind_addr: defaults::default_flight_bind_addr(),
579 cors_enabled: true,
580 cors_origins: Vec::new(),
581 compression_enabled: false,
582 tracing_enabled: true,
583 otlp_endpoint: None,
584 otlp_export_timeout_secs: defaults::default_otlp_timeout_secs(),
585 tracing_service_name: defaults::default_service_name(),
586 apq_enabled: true,
587 cache_enabled: true,
588 graphql_path: default_graphql_path(),
589 health_path: default_health_path(),
590 readiness_path: default_readiness_path(),
591 introspection_path: default_introspection_path(),
592 metrics_path: default_metrics_path(),
593 metrics_json_path: default_metrics_json_path(),
594 playground_path: default_playground_path(),
595 playground_enabled: false, // Disabled by default for security
596 playground_tool: PlaygroundTool::default(),
597 subscription_path: default_subscription_path(),
598 subscriptions_enabled: true,
599 metrics_enabled: false, // Disabled by default for security
600 metrics_token: None,
601 admin_api_enabled: false, // Disabled by default for security
602 admin_token: None,
603 admin_readonly_token: None,
604 introspection_enabled: false, // Disabled by default for security
605 introspection_require_auth: true, // Require auth when enabled
606 metadata_require_auth: None, // Falls back to introspection_require_auth
607 schema_export_require_auth: None, // Falls back to introspection_require_auth
608 playground_require_auth: None, // Falls back to introspection_require_auth
609 subscription_require_auth: None, // Falls back to introspection_require_auth
610 design_api_require_auth: true, // Require auth for design endpoints
611 pool_min_size: default_pool_min_size(),
612 pool_max_size: default_pool_max_size(),
613 pool_timeout_secs: default_pool_timeout(),
614 auth: None, // No auth by default
615 auth_hs256: None, // No HS256 auth by default
616 tls: None, // TLS disabled by default
617 database_tls: None, /* Database TLS disabled
618 * by default */
619 require_json_content_type: true, // CSRF protection
620 max_request_body_bytes: default_max_request_body_bytes(), // 1 MB
621 max_header_count: default_max_header_count(), // 100 headers
622 max_header_bytes: default_max_header_bytes(), // 32 KiB
623 rate_limiting: None, // Rate limiting uses defaults
624 #[cfg(feature = "observers")]
625 observers: None, // Observers disabled by default
626 pool_tuning: None, // Pool pressure monitoring disabled by default
627 admission_control: None, // Admission control disabled by default
628 security_contact: None, // No security.txt by default
629 validation: None, // Use compiled schema defaults
630 shutdown_timeout_secs: default_shutdown_timeout_secs(),
631 request_timeout_secs: None,
632 max_get_query_bytes: defaults::default_max_get_query_bytes(),
633 admin_auth_max_failures: defaults::default_admin_auth_max_failures(),
634 storage_token: None,
635 usage: None, // Usage persistence disabled by default
636 }
637 }
638}